<!--
* @Author: wh
* @Date: 2025-09-03 10:16:22
* @LastEditors: wh
* @LastEditTime: 2025-09-05 11:21:37
-->
<template>
<view v-if="template">
<s-layout title="首页" navbar="custom" tabbar="/pages/index/index">
<scroll-view
class="home-scroll"
scroll-y="true"
:style="{ height: scrollHeight + 'px' }"
>
<view class="home">
<view class="banner">
<view
class="banner-container"
@touchstart="handleTouchStart"
@touchend="handleTouchEnd"
>
<view
class="banner-scroll"
:style="{
transform: `translateX(-${currentIndex * 100}%)`,
transition: isAutoScroll ? 'transform 0.5s ease' : 'none',
}"
>
<view
class="banner-item"
v-for="(item, index) in swiperData.items"
:key="index"
@click="handleBannerClick(item)"
>
<image
:src="item.imgUrl"
mode="aspectFill"
class="banner-img"
></image>
</view>
</view>
<view class="banner-indicator">
<view
class="indicator-dot"
v-for="(item, index) in swiperData.items"
:key="index"
:class="{ 'indicator-dot--active': index === currentIndex }"
></view>
</view>
</view>
</view>
<view class="computing">
<view class="computing_con">
<view class="title">
<span>算力中心</span>
<span class="more" @click="computingMore">更多</span>
</view>
<s-menu-grid
:data="computingData"
:styles="computingData.style"
@item-click="handleComputingItemClick"
/>
</view>
</view>
<view class="special">
<view class="special_con">
<view class="title">
<span>专区</span>
<span class="more" @click="zoneMore">更多</span>
</view>
<view class="special-content">
<view
v-for="(item, index) in specialData"
:key="index"
class="special-card"
@click="handleZoneClick()"
>
<view class="special-img-container">
<image
:src="item.logoFilePath"
mode="aspectFill"
class="special-img"
></image>
</view>
<view class="special-text">
<text class="special-title">{{ item.name }}</text>
<text class="special-subtitle" v-if="item.subtitle">{{
item.subtitle
}}</text>
</view>
</view>
</view>
</view>
</view>
<view class="product">
<view class="product_con">
<view class="title">
<span>推荐商品</span>
</view>
<view class="content">
<view
v-for="(item, index) in productList"
:key="index"
class="product-card"
:class="{ 'reverse-layout': index % 2 === 1 }"
@click="handleProductClick(item.id)"
>
<view class="product-img">
<image
:src="item.image"
mode="aspectFill"
class="product-img__inner"
></image>
</view>
<view class="product-info">
<view class="product-title">{{ item.productName }}</view>
<view class="product-price">
<text class="product-01">{{ item.productTypeName }}</text>
<text class="product-02">{{ item.price || "面议" }}</text>
</view>
<text class="product-name">{{ item.storeName }}</text>
<text class="product-subtitle">{{ item.productDesc }}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
</s-layout>
</view>
</template>
<script setup>
import { ref, computed, onMounted, onUnmounted } from "vue";
import { onLoad, onPageScroll, onPullDownRefresh } from "@dcloudio/uni-app";
import sheep from "@/sheep";
import CommonApi from "@/sheep/api/common/index";
import ProductApi from "@/sheep/api/product/index";
import ZoneApi from "@/sheep/api/zone/index";
// 隐藏原生tabBar
uni.hideTabBar({ fail: () => {} });
const currentIndex = ref(0); // 当前显示的Banner索引
const touchStartX = ref(0); // 触摸起始X坐标
const touchEndX = ref(0); // 触摸结束X坐标
const autoScrollTimer = ref(null); // 自动轮播定时器
const isAutoScroll = ref(true); // 是否开启自动滚动(用于控制过渡动画)
const swiperData = ref({
autoplay: true, // 是否自动轮播
interval: 5000, // 轮播间隔(毫秒)
items: [
{
imgUrl:
"https://sanxiamy-oss.oss-cn-hangzhou.aliyuncs.com/xianxingqu/mini/static_resource/banner-01.png",
link: "", // 点击跳转链接
},
{
imgUrl:
"https://sanxiamy-oss.oss-cn-hangzhou.aliyuncs.com/xianxingqu/mini/static_resource/banner-02.png",
link: "",
},
{
imgUrl:
"https://sanxiamy-oss.oss-cn-hangzhou.aliyuncs.com/xianxingqu/mini/static_resource/banner-03.png",
link: "",
},
{
imgUrl:
"https://sanxiamy-oss.oss-cn-hangzhou.aliyuncs.com/xianxingqu/mini/static_resource/banner-04.png",
link: "",
},
],
});
const handleTouchStart = (e) => {
touchStartX.value = e.touches[0].clientX;
isAutoScroll.value = false;
clearInterval(autoScrollTimer.value);
};
const handleTouchEnd = (e) => {
touchEndX.value = e.changedTouches[0].clientX;
const diffX = touchEndX.value - touchStartX.value;
if (diffX > 50) {
currentIndex.value =
currentIndex.value === 0
? swiperData.value.items.length - 1
: currentIndex.value - 1;
} else if (diffX < -50) {
currentIndex.value =
currentIndex.value === swiperData.value.items.length - 1
? 0
: currentIndex.value + 1;
}
if (swiperData.value.autoplay) {
startAutoScroll();
}
isAutoScroll.value = true; // 恢复动画
};
// 点击Banner转链接
const handleBannerClick = (item) => {
// if (item.link) {
// if (item.link.includes("pages/index/category")) {
// uni.reLaunch({ url: item.link });
// } else if (item.link.includes("pages/special")) {
// uni.navigateTo({ url: item.link });
// } else {
// uni.navigateTo({ url: item.link });
// }
// }
};
// 开启自动轮播
const startAutoScroll = () => {
if (!swiperData.value.autoplay) return;
clearInterval(autoScrollTimer.value);
autoScrollTimer.value = setInterval(() => {
currentIndex.value =
currentIndex.value === swiperData.value.items.length - 1
? 0
: currentIndex.value + 1;
}, swiperData.value.interval);
};
onUnmounted(() => {
clearInterval(autoScrollTimer.value);
});
const scrollHeight = ref(1000);
const navigationBarData = ref({
title: "",
description: "",
navBarHeight: 55,
backgroundColor: "#415EE8",
backgroundImage: "",
styleType: "normal",
alwaysShow: true,
showGoBack: true,
bgType: "color",
bgColor: "#415EE8",
});
const productList = ref([]);
const computingData = ref({
column: 3,
list: [
{
title: "卡时售卖",
titleColor: "#333",
subtitle: "",
subtitleColor: "#bbb",
badge: { show: false, textColor: "#fff", bgColor: "#FF6000", text: "1" },
iconUrl:
"https://sanxiamy-oss.oss-cn-hangzhou.aliyuncs.com/xianxingqu/mini/static_resource/kssm.png",
url: "/pages/index/category?tab=computing&category=gpu",
},
{
title: "节点售卖",
titleColor: "#333",
subtitle: "",
subtitleColor: "#bbb",
badge: { show: false, textColor: "#fff", bgColor: "#FF6000" },
iconUrl:
"https://sanxiamy-oss.oss-cn-hangzhou.aliyuncs.com/xianxingqu/mini/static_resource/jdian.png",
url: "/pages/index/category?tab=computing&category=cpu",
},
{
title: "token售卖",
titleColor: "#333",
subtitle: "",
subtitleColor: "#bbb",
badge: { show: false, textColor: "#fff", bgColor: "#FF6000" },
iconUrl:
"https://sanxiamy-oss.oss-cn-hangzhou.aliyuncs.com/xianxingqu/mini/static_resource/token.png",
url: "/pages/index/category?tab=computing&category=memory",
},
],
});
const isZoneLoading = ref(false);
const isProductLoading = ref(false);
const specialData = ref([]);
const template = computed(() => sheep.$store("app").template?.user);
const handleComputingItemClick = (item, index) => {
if (item.clickHandler) {
item.clickHandler();
} else {
const categories = ["gpu", "cpu", "memory"];
const category = categories[index] || "gpu";
goToComputingWithCategory(category);
}
};
const goToComputingWithCategory = (category = "gpu") => {
uni.reLaunch({
url: `/pages/index/category?tab=computing&category=${category}`,
});
};
const computingMore = () => {
uni.reLaunch({ url: "/pages/index/category?tab=computing" });
};
const handleZoneClick = () => {
uni.switchTab({ url: "/pages/index/category?tab=product" });
};
const zoneMore = () => {
uni.navigateTo({ url: "/pages/special/special-zone" });
};
const handleProductClick = (id) => {
uni.navigateTo({ url: `/pages/product/details?id=${id}` });
};
const ZoneList = async (reset = false) => {
if (isZoneLoading.value) return;
isZoneLoading.value = true;
try {
const res = await ZoneApi.getZoneList("1", "4");
if (res && res.success && res.data?.records) {
specialData.value = res.data.records;
}
} catch (error) {
console.error("专区接口请求失败:", error);
} finally {
isZoneLoading.value = false;
}
};
const loadDemandList = async (reset = false) => {
if (isProductLoading.value) return;
isProductLoading.value = true;
try {
const res = await ProductApi.getRecommendList("", "HOT", "PRODUCT");
if (res && res.success && res.data) {
productList.value = res.data.map((item) => ({
id: item.id,
productName: item.productName,
productDesc: item.productDesc,
image:
item.displayFiles?.length > 0
? item.displayFiles[0].thumbnailUrl || item.displayFiles[0].fileUrl
: "/static/img/default-product.png",
productTypeName: item.productTypeName,
storeName: item.storeName,
price: item.price,
}));
}
} catch (error) {
console.error("推荐商品接口请求失败:", error);
} finally {
isProductLoading.value = false;
}
};
onMounted(() => {
if (swiperData.value.autoplay) {
startAutoScroll();
}
});
onLoad((options) => {
uni.hideTabBar({ fail: () => {} });
ZoneList(true);
loadDemandList(true);
// 小程序识别二维码
if (options.scene) {
const sceneParams = decodeURIComponent(options.scene).split("=");
options[sceneParams[0]] = sceneParams[1];
}
// 预览模板
if (options.templateId) {
sheep.$store("app").init(options.templateId);
}
// 进入指定页面
if (options.page) {
sheep.$router.go(decodeURIComponent(options.page));
}
});
onPullDownRefresh(() => {
sheep.$store("app").init();
setTimeout(() => {
uni.stopPullDownRefresh();
}, 800);
});
onPageScroll(() => {});
</script>
<style lang="scss" scoped>
@import "@/sheep/scss/style/_index.scss";
</style>这个是首页的代码,<template>
<s-layout
title="商城"
tabbar="/pages/index/category"
navbar="normal"
:bgStyle="{}"
>
<view class="demand-hall">
<!-- 顶部搜索栏 -->
<view class="search-bar">
<view class="search-input full-width">
<uni-icons type="search" size="18" color="#999"></uni-icons>
<input
type="text"
:placeholder="activeTab === 'product' ? '搜索产品' : '搜索算力服务'"
v-model="searchKeyword"
@confirm="handleSearch"
/>
</view>
</view>
<!-- Tab分类 -->
<view class="tab-bar">
<view
class="tab-item"
:class="{ active: activeTab === 'product' }"
@click="switchTab('product')"
>
产品广场
</view>
<view
class="tab-item"
:class="{ active: activeTab === 'computing' }"
@click="switchTab('computing')"
>
算力中心
</view>
</view>
<!-- 产品广场内容 -->
<view v-if="activeTab === 'product'">
<!-- 分类筛选栏 -->
<scroll-view class="category-bar">
<view class="category-con">
<view
class="category-item cp-item"
v-for="item in categories"
:key="item.id"
:class="{ active: activeCategory === item.id }"
@click="openFilterDrawer(item)"
>
{{ item.name }}
</view>
</view>
</scroll-view>
<!-- 排序栏 -->
<view class="sort-bar">
<view
class="sort-item"
:class="{ active: !currentSort.active }"
@click="handleDefaultSort"
>
<text>综合排序</text>
</view>
<view
class="sort-item"
v-for="item in sortOptions"
:key="item.key"
:class="{
active: currentSort.active && currentSort.key === item.key,
}"
@click="handleSort(item)"
>
<text>{{ item.name }}</text>
<view class="sort-icons">
<uni-icons
:type="getSortIconType(item.key, 'asc')"
size="14"
:color="getSortIconColor(item.key, 'asc')"
></uni-icons>
<uni-icons
:type="getSortIconType(item.key, 'desc')"
size="14"
:color="getSortIconColor(item.key, 'desc')"
></uni-icons>
</view>
</view>
</view>
<!-- 产品列表 -->
<scroll-view class="demand-list" scroll-y @scrolltolower="loadMore">
<!-- 筛选标签 -->
<view class="filter-tags" v-if="selectedFilters.length > 0">
<view
class="filter-tag"
v-for="(tag, index) in selectedFilters"
:key="index"
>
<text>{{ tag }}</text>
<uni-icons
type="close"
size="20"
color="#999"
class="delete-icon"
@click.stop="handleTagDelete(index)"
></uni-icons>
</view>
</view>
<!-- 产品内容 -->
<view class="demand-grid">
<view
v-if="demandList.length === 0 && !isLoading"
class="empty-state"
>
<!-- <text>暂无产品数据</text> -->
</view>
<view
class="demand-item"
v-for="item in sortedDemandList"
:key="item.id"
@click="navigateToDetail(item.id)"
>
<view class="category-img">
<image
class="demand-image"
:src="item.thumbnailUrl"
mode="aspectFill"
></image>
</view>
<view class="demand-info">
<text class="demand-title">{{ item.productName }}</text>
<view class="demand-meta">
<text class="unit">{{ item.productTypeName }}</text>
</view>
<text class="demand-sort">{{ item.storeName }}</text>
<text class="demand-price">{{ item.price || "面议" }}</text>
<view class="demand-stats">
<text>{{ item.productDesc }}</text>
</view>
</view>
</view>
</view>
<!-- 加载状态 -->
<view class="load-status">
<uni-load-more
:status="isLoading ? 'loading' : noMoreData ? 'noMore' : 'more'"
></uni-load-more>
</view>
</scroll-view>
</view>
<!-- 算力中心内容 -->
<view v-if="activeTab === 'computing'">
<!-- 算力分类 -->
<view class="category-bar">
<view class="category-con sl-con">
<view
class="category-item sl-item"
v-for="item in computingCategories"
:key="item.id"
:class="{ active: activeComputingCategory === item.id }"
@click="selectComputingCategory(item.id)"
>
{{ item.name }}
</view>
</view>
</view>
<!-- 算力服务列表 -->
<scroll-view
class="computing-list"
scroll-y
@scrolltolower="loadMoreComputing"
>
<view class="computing-grid">
<!-- 无数据状态 -->
<view
v-if="computingList.length === 0 && !isComputingLoading"
class="empty-state"
>
<text>暂无算力服务数据</text>
</view>
<!-- 算力服务项 -->
<view
class="computing-item"
v-for="item in computingList"
:key="item.id"
@click="navigateToComputingDetail(item.id)"
>
<view class="computing-info">
<view class="computing-top">
<text class="computing-title">{{ item.packageName }}</text>
<view class="computing-price">{{
item.price || "面议"
}}</view>
</view>
<view
class="computing-specs"
v-for="(spec, idx) in item.specs"
:key="idx"
>
<view class="spec-row">
<text class="spec-name">{{ spec.name }}</text>
<text class="spec-type">{{ spec.type }}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 加载状态 -->
<view class="load-status">
<uni-load-more
:status="computingNoMoreData ? 'noMore' : 'more'"
></uni-load-more>
</view>
</scroll-view>
</view>
<!-- 筛选侧边栏 (仅产品广场) -->
<filter-drawer
ref="filterDrawerRef"
:filter-options="currentFilterOptions"
:selected-options="selectedOptions"
@update:selectedOptions="updateSelectedOptions"
@confirm="onFilterConfirm"
@close="onFilterClose"
v-if="activeTab === 'product' && currentFilterOptions.length > 0"
/>
</view>
</s-layout>
</template>
<script setup>
import { ref, reactive, computed, onMounted, nextTick } from "vue";
import {
onShow,
onPageScroll,
onPullDownRefresh,
onReachBottom,
onLoad,
onReady,
} from "@dcloudio/uni-app";
import sheep from "@/sheep";
import FilterDrawer from "./components/filter-drawer.vue";
import CommonApi from "@/sheep/api/common/index";
import ProductApi from "@/sheep/api/product/index";
import { handleAuthAndOrgCheck } from "@/sheep/utils/authHandler";
// 隐藏原生tabBar
uni.hideTabBar({
fail: () => {},
});
// 当前激活的Tab
const activeTab = ref("product");
// 切换Tab
const switchTab = (tab) => {
activeTab.value = tab;
// 切换Tab时重置搜索关键词
searchKeyword.value = "";
};
// 搜索关键词
const searchKeyword = ref("");
// 数据配置
const config = {
categories: [
{ id: "DIC000003", name: "场景" },
{ id: "DIC000001", name: "类型" },
{ id: "DIC000004", name: "专区" },
],
};
// 分类数据
const categories = ref(config.categories);
// 当前选中的分类
const activeCategory = ref("");
// 排序选项
const sortOptions = ref([
{ key: "sales", name: "销量" },
{ key: "price", name: "价格" },
{ key: "views", name: "浏览量" },
]);
// 当前排序方式
const currentSort = ref({
key: "",
order: "", // asc 或 desc
active: false, //是否激活排序
});
// 筛选选项数据
const filterOptions = ref([
{
id: "DIC000003",
name: "场景",
options: [],
},
{
id: "DIC000001",
name: "类型",
options: [],
},
{
id: "DIC000004",
name: "专区",
options: [],
},
]);
//默认综合排序
const handleDefaultSort = () => {
currentSort.value = {
key: "",
order: "",
active: false,
};
queryParams.orderColumn = ""; // 清空排序维度
queryParams.isAsc = undefined; // 清空排序方向
loadDemandList(true);
};
// 当前显示的筛选选项
const currentFilterOptions = computed(() => {
if (!activeCategory.value) return [];
// 返回对应分类的筛选选项
const category = filterOptions.value.find(
(cat) => cat.id === activeCategory.value
);
return category ? [category] : [];
});
// 选中的筛选条件
const selectedFilters = ref([]);
const selectedOptions = reactive({
DIC000003: [], // 场景
DIC000001: [], // 类型
DIC000004: [], // 专区
});
// 产品列表数据
const demandList = ref([]);
const page = ref(1);
const pageSize = ref(10);
const isLoading = ref(false);
const noMoreData = ref(false);
const queryParams = reactive({
current: 1,
size: 10,
queryType: "PRODUCT",
belongDomain: "",
sceneCatalog: "",
productType: "",
orderColumn: "",
isAsc: undefined,
});
// 排序后的产品列表
const sortedDemandList = computed(() => {
// 未激活排序:返回原始列表
if (!currentSort.value.active) {
return demandList.value;
}
// 激活排序:按当前维度和方向排序
return [...demandList.value].sort((a, b) => {
const valueA = a[currentSort.value.key] || 0;
const valueB = b[currentSort.value.key] || 0;
return currentSort.value.order === "asc"
? valueA - valueB
: valueB - valueA;
});
});
// 算力中心相关数据
const computingCategories = ref([
{ id: "gpu", name: "卡时售卖" },
{ id: "cpu", name: "节点/集群售卖" },
{ id: "memory", name: "token售卖" },
]);
const activeComputingCategory = ref("gpu");
//算力中心内容
const computingStaticData = {
// 卡时售卖数据
gpu: [
{
id: "gpu-package1",
packageName: "套餐一",
specs: [
{
name: "NV H800",
type: "GPU",
},
{
name: "8468处理器,24核",
type: "CPU",
},
],
price: "面议",
},
{
id: "gpu-package2",
packageName: "套餐二",
specs: [
{
name: "NV H800",
type: "GPU",
},
{
name: "8468处理器,48核",
type: "CPU",
},
],
price: "面议",
},
{
id: "gpu-package3",
packageName: "套餐三",
specs: [
{
name: "NV H800",
type: "GPU",
},
{
name: "8468处理器,72核",
type: "CPU",
},
],
type: "CPU",
price: "面议",
},
],
// 节点/集群售卖数据
cpu: [
{
id: "cpu-package1",
packageName: "套餐一",
specs: [
{
name: "8*NV H800",
type: "GPU",
},
{
name: "8468处理器,48C/96T,16GT/s,105M Cache",
type: "CPU",
},
{
name: "2T DDR5-4800 ECC RDIMM",
type: "内存",
},
{
name: "INTEL P5530,3.84T NVME*8",
type: "数据盘",
},
{
name: "NV ConnectX-7 400Gb/s NDR IB*8",
type: "算力网络",
},
{
name: "NV Connectx-7 IB NDR 200G单口",
type: "存储网络",
},
],
price: "面议",
},
{
id: "cpu-package2",
packageName: "套餐二",
specs: [
{
name: "8*NV H800 *N",
type: "GPU",
},
{
name: "8468处理器,48C/96T,16GT/s,105M Cache",
type: "CPU",
},
{
name: "2T DDR5-4800 ECC RDIMM",
type: "内存",
},
{
name: "INTEL P5530,3.84T NVME*8",
type: "数据盘",
},
{
name: "NV ConnectX-7 400Gb/s NDR IB*8",
type: "算力网络",
},
{
name: "NV Connectx-7 IB NDR 200G单口",
type: "存储网络",
},
],
price: "面议",
},
{
id: "cpu-package3",
packageName: "套餐三",
specs: [
{
name: "8*NV H800 *128/256",
type: "GPU",
},
{
name: "8468处理器,48C/96T,16GT/s,105M Cache",
type: "CPU",
},
{
name: "2T DDR5-4800 ECC RDIMM",
type: "内存",
},
{
name: "INTEL P5530,3.84T NVME*8",
type: "数据盘",
},
{
name: "NV ConnectX-7 400Gb/s NDR IB*8",
type: "算力网络",
},
{
name: "NV Connectx-7 IB NDR 200G单口",
type: "存储网络",
},
],
price: "面议",
},
],
// token售卖数据
memory: [
{
id: "memory-package1",
packageName: "SFT训练",
specs: [
{
name: "qwen1.5-7b-chat",
type: "模型规格",
},
{
name: "SFT训练",
type: "训练方式",
},
],
price: "面议",
},
{
id: "memory-package2",
packageName: "LoRA更新",
specs: [
{
name: "llama2-7b-base",
type: "模型规格",
},
{
name: "LoRA更新",
type: "训练方式",
},
],
price: "面议",
},
{
id: "memory-package3",
packageName: "模型评测",
specs: [
{
name: "llama2-7b-base",
type: "模型规格",
},
{
name: "模型评测",
type: "训练方式",
},
],
price: "面议",
},
],
};
const computingList = ref([]);
const computingPage = ref(1);
const isComputingLoading = ref(false);
const computingNoMoreData = ref(false);
// 筛选组件引用
const filterDrawerRef = ref(null);
//场景 类型 领域
const state = reactive({
loadStatus: "",
pageNum: 1,
pageSize: 99,
});
// 初始化数据
onMounted(() => {
loadDemandList();
loadComputingList(true);
});
// 加载产品列表
const loadDemandList = async (reset = false) => {
if (isLoading.value) return;
if (reset) {
queryParams.current = 1;
noMoreData.value = false;
demandList.value = [];
}
isLoading.value = true;
try {
let res = await ProductApi.getProductList(
queryParams.current,
queryParams.size,
queryParams.queryType,
queryParams.belongDomain,
queryParams.sceneCatalog,
queryParams.productType,
queryParams.orderColumn,
queryParams.isAsc,
searchKeyword.value
);
let records = [];
let hasNext = false;
if (res.data && Array.isArray(res.data)) {
records = res.data;
hasNext = records.length >= queryParams.size;
} else if (
res.data &&
res.data.data &&
Array.isArray(res.data.data.records)
) {
records = res.data.data.records;
hasNext = res.data.data.hasNext || false;
} else if (
res.data &&
res.data.records &&
Array.isArray(res.data.records)
) {
records = res.data.records;
hasNext = res.data.hasNext || false;
} else {
hasNext = false;
}
//处理数据
const processedRecords = records.map((item) => ({
id: item.id || item.productId || Math.random().toString(),
productName: item.productName || "-",
thumbnailUrl:
(item.displayFiles &&
item.displayFiles.length > 0 &&
item.displayFiles[0].thumbnailUrl) ||
item.imageUrl ||
"/static/images/default-product.png",
storeName: item.storeName || "-",
publishTime: item.publishTime || "-",
productDesc: item.productDesc || "-",
productTypeName: item.productTypeName || "-",
price: item.price || null,
sales: item.saleCount || item.sales || 0,
views: item.viewCount || item.views || 0,
}));
if (reset) {
demandList.value = processedRecords;
} else {
demandList.value = [...demandList.value, ...processedRecords];
}
noMoreData.value = !hasNext;
queryParams.current++;
} catch (error) {
} finally {
isLoading.value = false;
}
};
// 加载算力服务列表
const loadComputingList = async (reset = false) => {
if (reset) {
computingList.value =
computingStaticData[activeComputingCategory.value] || [];
}
};
// 获取排序图标类型
const getSortIconType = (key, direction) => {
// 无论是否激活,方向匹配时直接返回对应箭头图标
return direction === "asc" ? "arrowup" : "arrowdown";
};
// 获取排序图标颜色
const getSortIconColor = (key, direction) => {
const { active, key: currentKey, order: currentOrder } = currentSort.value;
if (active && currentKey === key && currentOrder === direction) {
return "#007aff";
}
return "#999";
};
// 处理排序
const handleSort = (sortItem) => {
const { key } = sortItem;
const currentKey = currentSort.value.key;
const currentOrder = currentSort.value.order;
if (!currentSort.value.active) {
currentSort.value = { key, order: "asc", active: true };
} else if (currentKey === key && currentOrder === "asc") {
currentSort.value.order = "desc";
} else if (currentKey === key && currentOrder === "desc") {
currentSort.value = { key: "", order: "", active: false };
} else {
currentSort.value = { key, order: "asc", active: true };
}
queryParams.orderColumn = currentSort.value.active
? currentSort.value.key
: "";
queryParams.isAsc = currentSort.value.active
? currentSort.value.order === "asc"
? "true"
: "false"
: undefined;
loadDemandList(true);
};
// 处理筛选标签删除
const handleTagDelete = async (tagIndex) => {
const deletedTag = selectedFilters.value[tagIndex];
let targetCategoryId = "";
let targetOptionIndex = -1;
for (const categoryId of Object.keys(selectedOptions)) {
const optionIndex = selectedOptions[categoryId].findIndex(
(option) => option.name === deletedTag && option.subOptionId !== "all"
);
if (optionIndex > -1) {
targetCategoryId = categoryId;
targetOptionIndex = optionIndex;
break;
}
}
if (targetCategoryId && targetOptionIndex > -1) {
selectedOptions[targetCategoryId].splice(targetOptionIndex, 1);
}
selectedFilters.value.splice(tagIndex, 1);
// 场景筛选
queryParams.sceneCatalog = selectedOptions.DIC000003.filter(
(option) => option.subOptionId !== "all"
)
.map((option) => option.subOptionId)
.join(",");
// 类型筛选
queryParams.productType = selectedOptions.DIC000001.filter(
(option) => option.subOptionId !== "all"
)
.map((option) => option.subOptionId)
.join(",");
// 专区筛选
queryParams.belongDomain = selectedOptions.DIC000004.filter(
(option) => option.subOptionId !== "all"
)
.map((option) => option.subOptionId)
.join(",");
queryParams.current = 1;
await loadDemandList(true);
};
// 选择算力分类
const selectComputingCategory = (categoryId) => {
activeComputingCategory.value = categoryId;
loadComputingList(true);
};
// 加载更多
const loadMore = () => {
if (!noMoreData.value && !isLoading.value) {
loadDemandList();
}
};
// 加载更多算力服务
const loadMoreComputing = () => {
computingNoMoreData.value = true;
};
// 打开筛选抽屉
const openFilterDrawer = async (category) => {
activeCategory.value = category.id;
await nextTick();
// 获取场景 类型 领域
await getTypeData(activeCategory.value);
await nextTick();
filterDrawerRef.value.open();
};
// 更新选中的选项
const updateSelectedOptions = (newOptions) => {
Object.keys(newOptions).forEach((key) => {
selectedOptions[key] = newOptions[key];
});
updateSelectedFilters();
};
// 筛选确认
const onFilterConfirm = (selectedOptions) => {
updateSelectedFilters();
queryParams.sceneCatalog = "";
queryParams.productType = "";
queryParams.belongDomain = "";
queryParams.sceneCatalog = selectedOptions.DIC000003.filter(
(item) => item.subOptionId !== "all"
)
.map((item) => item.subOptionId)
.join(",");
queryParams.productType = selectedOptions.DIC000001.filter(
(item) => item.subOptionId !== "all"
)
.map((item) => item.subOptionId)
.join(",");
queryParams.belongDomain = selectedOptions.DIC000004.filter(
(item) => item.subOptionId !== "all"
)
.map((item) => item.subOptionId)
.join(",");
queryParams.current = 1;
loadDemandList(true);
};
// 筛选关闭
const onFilterClose = () => {
activeCategory.value = "";
};
// 更新选中的筛选标签
const updateSelectedFilters = () => {
selectedFilters.value = [];
for (const section in selectedOptions) {
selectedOptions[section].forEach((option) => {
if (option.subOptionId !== "all") {
selectedFilters.value.push(option.name);
}
});
}
};
// 搜索处理
const handleSearch = () => {
if (activeTab.value === "product") {
loadDemandList(true);
} else {
loadComputingList(true);
}
};
// 跳转到产品详情
const navigateToDetail = (id) => {
uni.navigateTo({
url: `/pages/product/details?id=${id}`,
});
};
// 跳转到算力申请
const navigateToComputingDetail = (id) => {
handleAuthAndOrgCheck(`/pages/computing/apply`);
};
// 监听页面滚动到底部
onReachBottom(() => {
if (activeTab.value === "product") {
loadMore();
} else {
loadMoreComputing();
}
});
// 获取码值数据
async function getTypeData(id) {
state.loadStatus = "loading";
try {
let res = await CommonApi.getCommonList(state.pageNum, state.pageSize, id);
if (res.data && Array.isArray(res.data)) {
const currentCategory = categories.value.find((cat) => cat.id === id);
if (currentCategory) {
const mainCategoryOption = {
id: currentCategory.id,
name: currentCategory.name,
children: [],
};
mainCategoryOption.children.push({
id: "all",
name: "全部",
});
res.data.forEach((item) => {
mainCategoryOption.children.push({
id: item.value,
name: item.label,
});
});
const filterCategory = filterOptions.value.find((cat) => cat.id === id);
if (filterCategory) {
filterCategory.options = [mainCategoryOption];
}
}
}
} catch (error) {
} finally {
state.loadStatus = "";
}
}
const handlePageParams = (options) => {
if (options && options.tab) {
const newTab = options.tab;
if (activeTab.value !== newTab) {
activeTab.value = newTab;
if (newTab === "computing") {
if (
options.category &&
computingCategories.value.some((cat) => cat.id === options.category)
) {
activeComputingCategory.value = options.category;
} else {
activeComputingCategory.value =
computingCategories.value[0]?.id || "gpu";
}
loadComputingList(true);
} else {
loadDemandList(true);
}
return true;
}
}
return false;
};
onLoad(async (options) => {
// 处理参数
handlePageParams(options);
// 预先加载所有分类数据
for (const category of categories.value) {
await getTypeData(category.id);
}
// 如果参数没有导致Tab变化,加载默认数据
if (!handlePageParams(options)) {
if (activeTab.value === "product") {
loadDemandList();
} else {
loadComputingList(true);
}
}
});
onShow(() => {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
if (currentPage && currentPage.options) {
handlePageParams(currentPage.options);
}
});
</script>
<style lang="scss" scoped>
@import "@/sheep/scss/style/_category.scss";
</style>这个是商城页面的代码,我想在首页的算力中心跳转到商城的算力中心对应的tab栏,这两个页面都是tab底部跳转页面
最新发布