1570 lines
43 KiB
Vue
1570 lines
43 KiB
Vue
<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)">
|
||
<span>{{ category.firTitle }}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 产品内容区域 -->
|
||
<div class="product-content">
|
||
<!-- 左侧菜单区域(只有有二级或三级菜单时才显示) -->
|
||
<div v-if="hasMenuSidebar" class="menu-sidebar">
|
||
|
||
<template v-if="isTokenMarketActive">
|
||
<div class="input">
|
||
<el-input
|
||
v-model="searchKeyword"
|
||
class="product-search"
|
||
clearable
|
||
prefix-icon="el-icon-search"
|
||
placeholder="输入关键词 搜索模型"
|
||
></el-input>
|
||
</div>
|
||
<div class="token-filter-section">
|
||
<h4>模型筛选</h4>
|
||
<div class="token-filter-grid">
|
||
<button
|
||
v-for="item in tokenModelTypeList"
|
||
:key="item"
|
||
class="token-filter-item"
|
||
:class="{ active: tokenActiveModelType === item }"
|
||
@click="toggleTokenModelType(item)"
|
||
>
|
||
{{ item }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="token-filter-section">
|
||
<h4>提供方</h4>
|
||
<div class="token-filter-grid">
|
||
<button
|
||
v-for="item in tokenProviderList"
|
||
:key="item"
|
||
class="token-filter-item"
|
||
:class="{ active: tokenActiveProvider === item }"
|
||
@click="toggleTokenProvider(item)"
|
||
>
|
||
{{ item }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<template v-else>
|
||
<div class="input">
|
||
<el-input
|
||
v-model="searchKeyword"
|
||
class="product-search"
|
||
clearable
|
||
prefix-icon="el-icon-search"
|
||
placeholder="搜索产品名称、类型或描述"
|
||
></el-input>
|
||
</div>
|
||
<!-- 二级菜单 -->
|
||
|
||
<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>
|
||
</template>
|
||
</div>
|
||
|
||
<!-- 主内容区 -->
|
||
<div class="main-content" :class="{ 'full-width': !hasMenuSidebar }">
|
||
<template v-if="isTokenMarketActive">
|
||
<!-- <div class="token-market-toolbar">
|
||
<span>排序:</span>
|
||
<button class="token-sort-btn active">综合排序</button>
|
||
<button class="token-sort-btn">体验</button>
|
||
</div> -->
|
||
<div class="token-market-grid">
|
||
<div
|
||
v-for="product in displayedTokenProducts"
|
||
:key="product.id"
|
||
class="token-market-card"
|
||
@click="goModelDetail(product)"
|
||
>
|
||
<div class="token-card-top">
|
||
<h3>{{ product.display_name || product.model_name }}</h3>
|
||
<!-- <span v-if="product.sort_order <= 10" class="token-new-badge">NEW</span> -->
|
||
<!-- <i class="el-icon-more token-more"></i> -->
|
||
</div>
|
||
<div class="token-tags">
|
||
<span>{{ product.model_type || '-' }}</span>
|
||
<span>{{ product.billing_method || '-' }}</span>
|
||
<span>{{ product.provider || '-' }}</span>
|
||
<span v-if="product.llmid">{{ product.llmid }}</span>
|
||
</div>
|
||
<div class="token-price-line">
|
||
<span>输入 ¥{{ formatTokenPrice(product.input_token_price) }}/千Token</span>
|
||
<span>输出 ¥{{ formatTokenPrice(product.output_token_price) }}/千Token</span>
|
||
</div>
|
||
<div class="token-meta">
|
||
<span class="token-provider-avatar">{{ getProviderInitial(product.provider) }}</span>
|
||
<span>{{ product.provider || '-' }}</span>
|
||
</div>
|
||
<div class="token-actions">
|
||
<button @click.stop="goModelApiDocument(product)">
|
||
<i class="el-icon-document"></i>
|
||
API文档
|
||
</button>
|
||
<button class="experience" @click.stop="goModelExperience(product)">
|
||
<i class="el-icon-video-play"></i>
|
||
体验
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<!-- 产品网格 -->
|
||
<div v-else class="product-grid">
|
||
<div v-for="product in displayedProducts"
|
||
:key="product.id"
|
||
class="product-card"
|
||
@click="handleProductClick(product)">
|
||
<div class="product-header">
|
||
<div class="product-icon">
|
||
<i :class="getProductIcon(product)"></i>
|
||
</div>
|
||
<div class="product-title">
|
||
<h3 class="product-name">{{ product.name }}</h3>
|
||
<span class="product-type">{{ product.type }}</span>
|
||
</div>
|
||
<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-status">稳定服务</span>
|
||
<button class="detail-btn" @click.stop="handleProductClick(product)">
|
||
查看详情
|
||
<i class="el-icon-arrow-right"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 空状态 -->
|
||
<div v-if="isTokenMarketActive ? !displayedTokenProducts.length : !hasDisplayProducts" class="empty-state">
|
||
<div class="empty-icon">
|
||
<i class="el-icon-box"></i>
|
||
</div>
|
||
<p class="empty-text">{{ searchKeyword ? '没有匹配的产品' : '暂无产品数据' }}</p>
|
||
<span>可以切换分类或调整搜索关键词后再试。</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { reqNavList, reqNewHomeSync, reqNewHomeFestival } from "@/api/newHome";
|
||
import { gotoYuanJingAPI } from '@/api/gotoYuanJing'
|
||
|
||
export default {
|
||
name: "ProductServicePage",
|
||
data() {
|
||
return {
|
||
panelData: [],
|
||
activeCategory: '',
|
||
activeSubId: null,
|
||
activeThirdId: null,
|
||
searchKeyword: '',
|
||
currentProducts: [],
|
||
tokenList: [],
|
||
tokenModelTypeList: [],
|
||
tokenProviderList: [],
|
||
tokenActiveModelType: '',
|
||
tokenActiveProvider: ''
|
||
};
|
||
},
|
||
computed: {
|
||
isTokenMarketActive() {
|
||
return this.isTokenMarketCategory(this.activeCategory);
|
||
},
|
||
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;
|
||
},
|
||
displayedProducts() {
|
||
const keyword = this.searchKeyword.trim().toLowerCase();
|
||
|
||
if (!keyword) {
|
||
return this.currentProducts;
|
||
}
|
||
|
||
return this.currentProducts.filter(product => {
|
||
const productText = [
|
||
product.name,
|
||
product.type,
|
||
this.getProductDescription(product)
|
||
].join(' ').toLowerCase();
|
||
|
||
return productText.includes(keyword);
|
||
});
|
||
},
|
||
hasDisplayProducts() {
|
||
return this.displayedProducts && this.displayedProducts.length > 0;
|
||
},
|
||
totalProductCount() {
|
||
return this.panelData.reduce((total, category) => {
|
||
return total + this.getAllProductsFromCategory(category).length;
|
||
}, 0);
|
||
},
|
||
activeCategorySummary() {
|
||
if (!this.activeCategory) {
|
||
return '选择分类后查看对应产品能力';
|
||
}
|
||
|
||
const productCount = this.currentProducts.length;
|
||
const subCount = this.currentSubcategories.length;
|
||
return `当前分类包含 ${subCount} 个子类,${productCount} 个可选产品`;
|
||
},
|
||
hasMenuSidebar() {
|
||
if (this.isTokenMarketActive) return true;
|
||
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 !== '';
|
||
},
|
||
displayedTokenProducts() {
|
||
const keyword = this.searchKeyword.trim().toLowerCase();
|
||
return this.tokenList.filter(item => {
|
||
const matchKeyword = !keyword || [
|
||
item.display_name,
|
||
item.model_name,
|
||
item.model_type,
|
||
item.provider,
|
||
item.description
|
||
].join(' ').toLowerCase().includes(keyword);
|
||
const matchType = !this.tokenActiveModelType || item.model_type === this.tokenActiveModelType;
|
||
const matchProvider = !this.tokenActiveProvider || item.provider === this.tokenActiveProvider;
|
||
return matchKeyword && matchType && matchProvider;
|
||
});
|
||
}
|
||
},
|
||
async mounted() {
|
||
await this.loadNavData();
|
||
this.initializeDefaultData();
|
||
},
|
||
methods: {
|
||
// 判断当前一级分类是否为 TOKEN 市集,后续用于切换独立渲染逻辑。
|
||
isTokenMarketCategory(title) {
|
||
return ['TOKEN市集', 'Token市集', 'token市集', 'Token Market'].includes(title);
|
||
},
|
||
|
||
// 从导航接口内嵌的 token_market 中取出模型列表和筛选项。
|
||
setTokenMarketData(category) {
|
||
const marketData = category && category.token_market && category.token_market.data
|
||
? category.token_market.data
|
||
: {};
|
||
this.tokenList = Array.isArray(marketData.model_list) ? marketData.model_list : [];
|
||
this.tokenModelTypeList = Array.isArray(marketData.model_type_list) ? marketData.model_type_list : [];
|
||
this.tokenProviderList = Array.isArray(marketData.provider_list) ? marketData.provider_list : [];
|
||
},
|
||
|
||
// 点击同一个模型类型时取消筛选,再点其他类型则切换筛选项。
|
||
toggleTokenModelType(type) {
|
||
this.tokenActiveModelType = this.tokenActiveModelType === type ? '' : type;
|
||
},
|
||
|
||
// 点击同一个供应商时取消筛选,再点其他供应商则切换筛选项。
|
||
toggleTokenProvider(provider) {
|
||
this.tokenActiveProvider = this.tokenActiveProvider === provider ? '' : provider;
|
||
},
|
||
|
||
// TOKEN 市集价格展示,去掉无意义的尾部 0。
|
||
formatTokenPrice(value) {
|
||
if (value === undefined || value === null || value === '') return '-';
|
||
const num = Number(value);
|
||
if (Number.isNaN(num)) return value;
|
||
return num.toFixed(4).replace(/\.?0+$/, '');
|
||
},
|
||
|
||
// 供应商头像取首字,避免没有 logo 时卡片显得空。
|
||
getProviderInitial(provider) {
|
||
return provider ? provider.slice(0, 1) : 'M';
|
||
},
|
||
|
||
// TOKEN 市集卡片点击:进入模型详情页。
|
||
goModelDetail(model) {
|
||
this.cacheTokenMarketModel(model);
|
||
this.$router.push({
|
||
name: 'modelDetail',
|
||
query: {
|
||
id: model.id,
|
||
model_id: model.id,
|
||
llmid: model.llmid || model.model_name || model.id,
|
||
from: 'tokenMarket',
|
||
category: 'TOKEN市集'
|
||
}
|
||
});
|
||
},
|
||
|
||
// TOKEN 市集 API 文档按钮:进入模型 API 文档页。
|
||
goModelApiDocument(model) {
|
||
this.cacheTokenMarketModel(model);
|
||
this.$router.push({
|
||
name: 'modelApiDocument',
|
||
query: {
|
||
id: model.id,
|
||
model_id: model.id,
|
||
from: 'tokenMarket',
|
||
category: 'TOKEN市集'
|
||
}
|
||
});
|
||
},
|
||
|
||
// TOKEN 市集体验按钮:进入模型体验页。
|
||
goModelExperience(model) {
|
||
this.cacheTokenMarketModel(model);
|
||
this.$router.push({
|
||
name: 'modelExperience',
|
||
query: {
|
||
id: model.id,
|
||
model_id: model.id,
|
||
from: 'tokenMarket',
|
||
category: 'TOKEN市集'
|
||
}
|
||
});
|
||
},
|
||
|
||
// 详情页需要完整模型字段,这里点击时缓存当前卡片数据,避免只带 id 过去后页面无法渲染。
|
||
cacheTokenMarketModel(model) {
|
||
if (!model) return;
|
||
sessionStorage.setItem('tokenMarketSelectedModel', JSON.stringify(model));
|
||
},
|
||
|
||
// 生成唯一的二级菜单项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 (this.isTokenMarketCategory(category.firTitle)) {
|
||
this.setTokenMarketData(category);
|
||
}
|
||
// 确保一级分类有唯一标识
|
||
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 defaultCategory = this.getDefaultCategory();
|
||
this.activeCategory = defaultCategory.firTitle;
|
||
this.setDefaultSubcategory(defaultCategory);
|
||
}
|
||
},
|
||
|
||
// 进入 /product 时优先根据路由 query 打开指定分类;没有 query 时默认打开 TOKEN 市集。
|
||
getDefaultCategory() {
|
||
const queryCategory = this.$route.query.category || this.$route.query.tab;
|
||
const categoryFromQuery = queryCategory
|
||
? this.panelData.find(item => item.firTitle === queryCategory || this.isTokenMarketCategory(queryCategory) && this.isTokenMarketCategory(item.firTitle))
|
||
: null;
|
||
const tokenCategory = this.panelData.find(item => this.isTokenMarketCategory(item.firTitle));
|
||
return categoryFromQuery || tokenCategory || this.panelData[0];
|
||
},
|
||
|
||
// 根据分类设置默认二级菜单
|
||
setDefaultSubcategory(category) {
|
||
if (this.isTokenMarketCategory(category.firTitle)) {
|
||
this.activeSubId = null;
|
||
this.activeThirdId = null;
|
||
this.currentProducts = [];
|
||
return;
|
||
}
|
||
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) {
|
||
if (category && category.firTitle === '元境') {
|
||
this.goYuanjing()
|
||
return;
|
||
}
|
||
|
||
this.activeCategory = category.firTitle;
|
||
this.activeSubId = null;
|
||
this.activeThirdId = null;
|
||
if (this.isTokenMarketCategory(category.firTitle)) {
|
||
this.setTokenMarketData(category);
|
||
this.currentProducts = [];
|
||
return;
|
||
}
|
||
this.setDefaultSubcategory(category);
|
||
},
|
||
async goYuanjing() {
|
||
const userId = sessionStorage.getItem('userId')
|
||
if (!userId || userId === 'null' || userId === '') {
|
||
this.$message.warning('请先登录哦~')
|
||
return
|
||
}
|
||
|
||
const yuanJingWindow = window.open('', '_blank')
|
||
|
||
try {
|
||
const res = await gotoYuanJingAPI({ user_id: userId })
|
||
const deerer = this.getYuanJingAuthorization(res)
|
||
|
||
if (!deerer) {
|
||
if (yuanJingWindow) {
|
||
yuanJingWindow.close()
|
||
}
|
||
this.$message.error((res && res.msg) || '获取元境授权参数失败')
|
||
return
|
||
}
|
||
|
||
const loginUrl = `https://ai.opencomputing.cn/#/getCookie?deerer=${encodeURIComponent(deerer)}`
|
||
if (yuanJingWindow) {
|
||
yuanJingWindow.location.href = loginUrl
|
||
} else {
|
||
window.location.href = loginUrl
|
||
}
|
||
} catch (error) {
|
||
if (yuanJingWindow) {
|
||
yuanJingWindow.close()
|
||
}
|
||
this.$message.error('跳转元境失败,请稍后重试')
|
||
}
|
||
},
|
||
getYuanJingAuthorization(res) {
|
||
if (!res) {
|
||
return ''
|
||
}
|
||
|
||
if (typeof res === 'string') {
|
||
return res
|
||
}
|
||
|
||
const data = res.data || res
|
||
if (typeof data === 'string') {
|
||
return data
|
||
}
|
||
|
||
return data.Authorization || data.authorization || data.token || data.header || data.value || ''
|
||
},
|
||
|
||
// 切换二级分类
|
||
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] || '专业的云服务产品,提供稳定可靠的服务';
|
||
},
|
||
|
||
// 根据产品类型展示不同图标,让卡片更容易区分。
|
||
getProductIcon(product) {
|
||
const iconMap = {
|
||
'百度云': 'el-icon-cloudy',
|
||
'阿里云': 'el-icon-cloudy-and-sunny',
|
||
'智算': 'el-icon-cpu',
|
||
'算力网络': 'el-icon-connection'
|
||
};
|
||
|
||
return iconMap[product.type] || 'el-icon-coin';
|
||
},
|
||
|
||
// 修复阿里云跳转逻辑
|
||
async handleAliyunProductClick(useid) {
|
||
// 第一步:同步请求
|
||
const syncResponse = await reqNewHomeSync();
|
||
|
||
if (!syncResponse.status) {
|
||
this.$message.warning(syncResponse.msg || '同步失败,请稍后重试');
|
||
return;
|
||
}
|
||
// 第二步:获取跳转链接
|
||
const festivalResponse = await reqNewHomeFestival();
|
||
console.log(festivalResponse);
|
||
|
||
if (festivalResponse.status && festivalResponse.data) {
|
||
window.open(festivalResponse.data);
|
||
} else {
|
||
this.$message.warning(festivalResponse.msg || '获取跳转链接失败');
|
||
}
|
||
|
||
},
|
||
|
||
// 点击产品
|
||
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;
|
||
height: calc(100vh - 100px);
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
.product-service-page {
|
||
background: linear-gradient(180deg, #f3f7ff 0%, #f7f9fc 38%, #ffffff 100%);
|
||
|
||
.page-hero {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: stretch;
|
||
gap: 24px;
|
||
margin-bottom: 20px;
|
||
padding: 28px;
|
||
color: #ffffff;
|
||
background:
|
||
radial-gradient(circle at 88% 12%, rgba(255, 255, 255, 0.28) 0, rgba(255, 255, 255, 0) 32%),
|
||
linear-gradient(135deg, #1e6fff 0%, #5d8dff 52%, #7fb0ff 100%);
|
||
border-radius: 22px;
|
||
box-shadow: 0 18px 42px rgba(30, 111, 255, 0.18);
|
||
|
||
.hero-content {
|
||
max-width: 560px;
|
||
|
||
.hero-tag {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
height: 26px;
|
||
padding: 0 12px;
|
||
margin-bottom: 14px;
|
||
font-size: 12px;
|
||
color: rgba(255, 255, 255, 0.92);
|
||
background: rgba(255, 255, 255, 0.16);
|
||
border: 1px solid rgba(255, 255, 255, 0.22);
|
||
border-radius: 999px;
|
||
}
|
||
|
||
h2 {
|
||
margin: 0 0 10px;
|
||
font-size: 30px;
|
||
font-weight: 700;
|
||
letter-spacing: 1px;
|
||
}
|
||
|
||
p {
|
||
margin: 0;
|
||
color: rgba(255, 255, 255, 0.86);
|
||
font-size: 14px;
|
||
line-height: 1.8;
|
||
}
|
||
}
|
||
|
||
.hero-stats {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 116px);
|
||
gap: 12px;
|
||
align-items: center;
|
||
|
||
.stat-card {
|
||
padding: 16px 14px;
|
||
text-align: center;
|
||
background: rgba(255, 255, 255, 0.14);
|
||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||
border-radius: 16px;
|
||
|
||
span {
|
||
display: block;
|
||
margin-bottom: 8px;
|
||
color: rgba(255, 255, 255, 0.78);
|
||
font-size: 12px;
|
||
}
|
||
|
||
strong {
|
||
font-size: 26px;
|
||
line-height: 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.product-search {
|
||
margin: 10px 0;
|
||
/deep/ .el-input__inner {
|
||
height: 40px;
|
||
line-height: 40px;
|
||
border-radius: 12px;
|
||
}
|
||
}
|
||
.page-toolbar {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
gap: 20px;
|
||
margin-bottom: 16px;
|
||
padding: 18px 20px;
|
||
background: rgba(255, 255, 255, 0.92);
|
||
border: 1px solid #edf1f7;
|
||
border-radius: 18px;
|
||
box-shadow: 0 10px 28px rgba(31, 45, 61, 0.06);
|
||
|
||
h3 {
|
||
margin: 0 0 6px;
|
||
color: #1f2d3d;
|
||
font-size: 18px;
|
||
}
|
||
|
||
p {
|
||
margin: 0;
|
||
color: #8a94a6;
|
||
font-size: 13px;
|
||
}
|
||
|
||
|
||
}
|
||
|
||
.category-nav {
|
||
gap: 10px;
|
||
padding: 10px;
|
||
overflow-x: auto;
|
||
background: #ffffff;
|
||
border: 1px solid #edf1f7;
|
||
border-radius: 18px;
|
||
box-shadow: 0 10px 28px rgba(31, 45, 61, 0.05);
|
||
|
||
.nav-item {
|
||
flex: 1;
|
||
min-width: 96px;
|
||
padding: 12px 18px;
|
||
text-align: center;
|
||
border: 0;
|
||
border-radius: 12px;
|
||
|
||
&:hover {
|
||
background: #f4f8ff;
|
||
}
|
||
|
||
&.active {
|
||
color: #ffffff;
|
||
background: linear-gradient(135deg, #1e6fff, #5d8dff);
|
||
box-shadow: 0 10px 22px rgba(30, 111, 255, 0.18);
|
||
}
|
||
}
|
||
}
|
||
|
||
.product-content {
|
||
align-items: flex-start;
|
||
|
||
.menu-sidebar {
|
||
position: sticky;
|
||
top: 16px;
|
||
padding: 16px;
|
||
background: #ffffff;
|
||
border: 1px solid #edf1f7;
|
||
border-radius: 18px;
|
||
box-shadow: 0 12px 30px rgba(31, 45, 61, 0.06);
|
||
}
|
||
|
||
.token-filter-section {
|
||
margin-top: 18px;
|
||
|
||
h4 {
|
||
margin: 0 0 10px;
|
||
color: #98a2b3;
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
|
||
.token-filter-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 8px 12px;
|
||
}
|
||
|
||
.token-filter-item {
|
||
padding: 4px 0;
|
||
color: #344054;
|
||
text-align: left;
|
||
background: transparent;
|
||
border: 0;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
|
||
&.active {
|
||
color: #1e6fff;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
}
|
||
|
||
.product-content .subcategory-list,
|
||
.product-content .third-level-list {
|
||
.subcategory-item,
|
||
.third-level-item {
|
||
padding: 12px 14px;
|
||
border-radius: 12px;
|
||
|
||
&.active {
|
||
background: linear-gradient(135deg, rgba(30, 111, 255, 0.12), rgba(93, 141, 255, 0.08));
|
||
box-shadow: inset 3px 0 0 #1e6fff;
|
||
}
|
||
}
|
||
}
|
||
|
||
.product-content .main-content {
|
||
min-width: 0;
|
||
|
||
.token-market-toolbar {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
margin-bottom: 14px;
|
||
color: #667085;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.token-sort-btn {
|
||
height: 28px;
|
||
padding: 0 12px;
|
||
color: #667085;
|
||
background: #ffffff;
|
||
border: 1px solid #e5e7eb;
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
|
||
&.active {
|
||
color: #7c3aed;
|
||
background: #f5f3ff;
|
||
border-color: #c4b5fd;
|
||
}
|
||
}
|
||
|
||
.token-market-grid {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 14px;
|
||
}
|
||
|
||
.token-market-card {
|
||
flex: 0 0 calc((100% - 28px) / 3);
|
||
min-width: 0;
|
||
padding: 14px;
|
||
background: #ffffff;
|
||
border: 1px solid #edf1f7;
|
||
border-radius: 12px;
|
||
box-shadow: 0 10px 24px rgba(31, 45, 61, 0.05);
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
|
||
&:hover {
|
||
border-color: #d7e4f5;
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 16px 32px rgba(31, 45, 61, 0.08);
|
||
}
|
||
}
|
||
|
||
.token-card-top {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
margin-bottom: 8px;
|
||
|
||
h3 {
|
||
flex: 1;
|
||
margin: 0;
|
||
color: #1f2d3d;
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
line-height: 1.35;
|
||
}
|
||
}
|
||
|
||
.token-new-badge {
|
||
padding: 1px 6px;
|
||
color: #ffffff;
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
background: #3b82f6;
|
||
border-radius: 5px;
|
||
}
|
||
|
||
.token-more {
|
||
color: #98a2b3;
|
||
transform: rotate(90deg);
|
||
}
|
||
|
||
.token-tags {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 6px;
|
||
padding-bottom: 10px;
|
||
margin-bottom: 10px;
|
||
border-bottom: 1px dashed #d8e0ee;
|
||
|
||
span {
|
||
padding: 2px 6px;
|
||
color: #667085;
|
||
font-size: 11px;
|
||
background: #f8fafc;
|
||
border: 1px solid #edf1f7;
|
||
border-radius: 6px;
|
||
}
|
||
}
|
||
|
||
.token-price-line {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 10px;
|
||
margin-bottom: 8px;
|
||
color: #1f2937;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.token-meta {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
margin-bottom: 10px;
|
||
color: #667085;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.token-provider-avatar {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 16px;
|
||
height: 16px;
|
||
color: #ffffff;
|
||
font-size: 10px;
|
||
background: #1e6fff;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.token-actions {
|
||
display: flex;
|
||
gap: 6px;
|
||
|
||
button {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
height: 28px;
|
||
padding: 0 10px;
|
||
color: #475467;
|
||
font-size: 12px;
|
||
background: #ffffff;
|
||
border: 1px solid #d8e0ee;
|
||
border-radius: 7px;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
|
||
&:hover {
|
||
color: #1e6fff;
|
||
border-color: #9ec5ff;
|
||
background: #f4f8ff;
|
||
}
|
||
}
|
||
|
||
.experience {
|
||
color: #4f46e5;
|
||
border-color: #c7d2fe;
|
||
|
||
&:hover {
|
||
color: #4338ca;
|
||
border-color: #a5b4fc;
|
||
background: #eef2ff;
|
||
}
|
||
}
|
||
}
|
||
|
||
.product-grid {
|
||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||
|
||
.product-card {
|
||
position: relative;
|
||
min-height: 178px;
|
||
overflow: hidden;
|
||
border-color: #edf1f7;
|
||
border-radius: 18px;
|
||
box-shadow: 0 10px 26px rgba(31, 45, 61, 0.06);
|
||
|
||
&::after {
|
||
content: "";
|
||
position: absolute;
|
||
right: -36px;
|
||
top: -36px;
|
||
width: 96px;
|
||
height: 96px;
|
||
background: rgba(30, 111, 255, 0.08);
|
||
border-radius: 50%;
|
||
pointer-events: none;
|
||
}
|
||
|
||
&:hover {
|
||
box-shadow: 0 18px 38px rgba(30, 111, 255, 0.14);
|
||
}
|
||
|
||
.product-header {
|
||
position: relative;
|
||
z-index: 1;
|
||
align-items: flex-start;
|
||
gap: 12px;
|
||
|
||
.product-icon {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex: 0 0 42px;
|
||
width: 42px;
|
||
height: 42px;
|
||
color: #1e6fff;
|
||
font-size: 22px;
|
||
background: #eef5ff;
|
||
border-radius: 14px;
|
||
}
|
||
|
||
.product-title {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.product-name {
|
||
margin: 0 0 7px;
|
||
color: #1f2d3d;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.product-type {
|
||
display: inline-flex;
|
||
color: #7a8699;
|
||
font-size: 12px;
|
||
background: #f4f6fa;
|
||
padding: 4px 8px;
|
||
border-radius: 999px;
|
||
}
|
||
|
||
.discount-badge {
|
||
position: relative;
|
||
z-index: 1;
|
||
border-radius: 999px;
|
||
white-space: nowrap;
|
||
}
|
||
}
|
||
|
||
.product-desc {
|
||
position: relative;
|
||
z-index: 1;
|
||
min-height: 44px;
|
||
color: #667085;
|
||
line-height: 1.6;
|
||
line-clamp: 2;
|
||
-webkit-line-clamp: 2;
|
||
}
|
||
|
||
.product-footer {
|
||
position: relative;
|
||
z-index: 1;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
|
||
.product-status {
|
||
color: #12b76a;
|
||
font-size: 12px;
|
||
background: #ecfdf3;
|
||
padding: 5px 10px;
|
||
border-radius: 999px;
|
||
}
|
||
|
||
.detail-btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
color: #ffffff;
|
||
background: #1E6FFF;
|
||
border: none;
|
||
padding: 8px 13px;
|
||
border-radius: 999px;
|
||
cursor: pointer;
|
||
transition: background 0.25s ease, transform 0.25s ease;
|
||
|
||
&:hover {
|
||
background: #0d5ae0;
|
||
transform: translateX(2px);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.empty-state {
|
||
padding: 76px 20px;
|
||
text-align: center;
|
||
background: #ffffff;
|
||
border: 1px dashed #d8e0ee;
|
||
border-radius: 18px;
|
||
|
||
.empty-icon {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 64px;
|
||
height: 64px;
|
||
margin-bottom: 16px;
|
||
color: #98a2b3;
|
||
font-size: 32px;
|
||
background: #f4f6fa;
|
||
border-radius: 18px;
|
||
}
|
||
|
||
.empty-text {
|
||
margin: 0 0 8px;
|
||
color: #475467;
|
||
font-size: 15px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
span {
|
||
color: #98a2b3;
|
||
font-size: 13px;
|
||
}
|
||
}
|
||
}
|
||
|
||
@media (max-width: 1080px) {
|
||
.page-hero {
|
||
flex-direction: column;
|
||
|
||
.hero-stats {
|
||
grid-template-columns: repeat(3, 1fr);
|
||
}
|
||
}
|
||
|
||
.page-toolbar {
|
||
align-items: flex-start;
|
||
flex-direction: column;
|
||
|
||
.product-search {
|
||
width: 100%;
|
||
}
|
||
}
|
||
|
||
.product-content .main-content .token-market-card {
|
||
flex-basis: calc((100% - 14px) / 2);
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.product-content .main-content .token-market-card {
|
||
flex-basis: 100%;
|
||
}
|
||
}
|
||
}
|
||
</style>
|