This commit is contained in:
hrx 2025-11-12 14:38:09 +08:00
parent 0acedc3543
commit 1a5e57a603
5 changed files with 449 additions and 454 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 873 KiB

View File

@ -1,97 +1,114 @@
<template>
<div id="homeOut" class="homeOut">
<TopBox id="topBox"></TopBox>
<div class="banner-box">
<div class="conter">
<div class="title">
供需广场
</div>
<div class="banner-title">
开元算力供需对接平台精准攻克算力资源错配利用低效的行业痛点依托技术整合与生态共建双引擎
构建灵活适配高效协同的一站式算力服务体系支持供需信息发布与精准对接致力于成为链接算力资源赋能产业升级推动人工智能技术规模化落地的核心载体与关键桥梁
</div>
<div class="btn">
<div class="btn-box" @click="sendInfo('2')">发布需求</div>
<div class="btn-box" @click="sendInfo('1')">发布商品</div>
</div>
</div>
</div>
<div class="search-box">
<search></search>
</div>
<div style="width: 90%;max-width: 1600px;">
<router-view></router-view>
</div>
<el-dialog :title="productDetailInfo.publish_type==='1'? '商品详情' :'需求详情'" top="5vh" :visible.sync="showProductDetail" width="80%" @open="scrollToTop">
<!-- 发布商品/需求弹窗 -->
<el-dialog :title="publish_type === '2' ? '发布需求' : '发布商品'" width="60vw" top="5vh"
:visible.sync="sendProductVisible">
<sendProduct :isEdit="false" v-if="sendProductVisible" @success="sendProductSuccess" :publish_type="publish_type">
</sendProduct>
</el-dialog>
<!-- 审核提示弹窗 -->
<el-dialog title="温馨提示" :visible.sync="showTip" width="30%">
<span>您还没有完善企业信息完善企业信息审核通过后您可以发布需求与商品</span>
<span slot="footer" class="dialog-footer">
<span> <span style="margin-right: 10px;"> 跳转到</span> <el-button size="small" type="primary"
@click="goInfo">信息完善</el-button></span>
</span>
</el-dialog>
<el-dialog :title="productDetailInfo.publish_type === '1' ? '商品详情' : '需求详情'" top="5vh" :visible.sync="showProductDetail"
width="80%" @open="scrollToTop">
<ProductDetail></ProductDetail>
<span slot="footer" class="dialog-footer">
<!-- <el-button @click="closeProductDetail"> </el-button> -->
<el-button type="primary" @click="closeProductDetail"> </el-button>
</span>
</el-dialog>
<!-- footer-->
<!-- Footer -->
<div class="footer">
<div class="left-box" style="border-bottom: 1px solid #7A82A0">
<div style="display: flex;flex-direction: column">
<img v-if="JSON.stringify(logoInfoNew) !== '{}'" style="width: 148px;height: 48px;"
:src="logoInfoNew.home.logoImg" alt="" class="img">
<div class="content-main">
<ul class="info">
<li>地址<span v-if="JSON.stringify(logoInfoNew) !== '{}'">{{ logoInfoNew.home.adress }}</span>
</li>
<li>地址<span v-if="JSON.stringify(logoInfoNew) !== '{}'">{{ logoInfoNew.home.adress }}</span></li>
<li v-if="JSON.stringify(logoInfoNew) !== '{}'"> 邮箱{{ logoInfoNew.home.email }}</li>
<li v-if="JSON.stringify(logoInfoNew) !== '{}'">电话: <span class="tel">{{ logoInfoNew.home.mobile }}</span>
</li>
<li>
<!-- <a href="" rel="noreferrer" target="_blank"></a> -->
</li>
<li v-if="JSON.stringify(logoInfoNew) !== '{}'">电话: <span class="tel">{{ logoInfoNew.home.mobile }}</span></li>
</ul>
</div>
</div>
<ul class="bigUl">
</ul>
<ul class="bigUl"></ul>
<div v-if="JSON.stringify(logoInfoNew) !== '{}' && logoInfoNew.home.bannerTitle !== '开元数智'" class="right-box">
<div class="qr-box">
<div class="qr-code">
<img src="../img/kefu.jpg" style="padding: 0.08rem" alt="">
</div>
<img src="../img/kefu.jpg" style="padding: 0.08rem" alt="">
<span class="qr-content">微信客服</span>
</div>
<div class="qr-box" style="margin-left: 0.667rem">
<div class="qr-code">
<img src="../img/img.png" alt="">
</div>
<img src="../img/img.png" alt="">
<span class="qr-content">关注公众号</span>
</div>
</div>
</div>
<div style="display: flex;justify-content: center;align-items: center;width: 100%; ">
<span v-if="JSON.stringify(logoInfoNew) !== '{}'"
style="margin:15px 0 ;width: 1400px;display:flex;justify-content:center;align-items:center;color: #7A82A0;"><span
class="goStyle" @click="goOut('https://beian.miit.gov.cn/#/Integrated/index')">
京ICP备{{
logoInfoNew.home.license
}}&nbsp;
</span> &nbsp;&nbsp;{{
logoInfoNew.home.footerTitle
}}&nbsp;{{
logoInfoNew.home.copyright
}}&nbsp; </span>
<!-- IPC备案号:{{ ICP }} <span style="margin-left: 0.267rem">版权所有 @kaiyuanyun 2023</span>-->
<!-- <img src="../../image/login/policeInsignia/policeInsignia.png" alt=""-->
<!-- style="width:0.227rem;height:0.227rem;margin-right: 0.027rem;">-->
<!-- <a href="https://beian.mps.gov.cn/#/query/webSearch?code=11010502054007" rel="noreferrer"-->
<!-- target="_blank"-->
<!-- style="margin-right:0.4rem;">京公网安备11010502054007</a>-->
<!-- <span>-->
<!-- <router-link tag="a" target="_blank"-->
<!-- :to="{ name: 'homePageImage' }">经营许可证:京B2-20232313</router-link>-->
<!-- </span>-->
style="margin:15px 0 ;width: 1400px;display:flex;justify-content:center;align-items:center;color: #7A82A0;">
<span class="goStyle" @click="goOut('https://beian.miit.gov.cn/#/Integrated/index')">
京ICP备{{ logoInfoNew.home.license }}&nbsp;
</span>
&nbsp;&nbsp;{{ logoInfoNew.home.footerTitle }}&nbsp;{{ logoInfoNew.home.copyright }}&nbsp;
</span>
</div>
</div>
</div>
</template>
<script>
import Vue from 'vue'
import TopBox from "@/views/homePage/components/topBox/index.vue";
import { mapGetters, mapState } from "vuex";
import search from "./search/index.vue";
import { reqEnterpriseAuditInfoSearch } from '@/api/ncmatch'
import productDetail from "./proDetail/index.vue";
export default Vue.extend({
name: "indexLast",
components: { TopBox, search, ProductDetail: productDetail },
components: {
TopBox,
search,
ProductDetail: productDetail,
sendProduct: () => import('@/views/homePage/ncmatch/mainPage/sendProduct/index.vue')
},
data() {
return {
currentBaseMenu: "hot", //
currentBaseMenu: "hot",
//
sendProductVisible: false,
showTip: false,
publish_type: "",
}
},
computed: {
@ -114,23 +131,12 @@ export default Vue.extend({
this.$store.commit('SHOWPRODUCTDETAIL', value);
}
},
showRegisterButton() {
const orgType = window.sessionStorage.getItem('org_type');
const userId = window.sessionStorage.getItem('userId');
console.log("此时是:", orgType !== '2' && orgType !== '3' && userId !== null)
return orgType !== '2' && orgType !== '3' && userId === null;
},
username() {
return sessionStorage.getItem('username') || '';
},
},
methods: {
closeProductDetail() {
this.$store.commit('SHOWPRODUCTDETAIL', false)
},
scrollToTop() {
// 使nextTickDOM
this.$nextTick(() => {
const dialogBody = document.querySelector('.el-dialog__body');
if (dialogBody) {
@ -145,13 +151,12 @@ export default Vue.extend({
const element = document.getElementById(id);
if (element) {
element.scrollIntoView({
behavior: 'smooth', //
block: 'start', // 'start', 'center', 'end', 'nearest'
behavior: 'smooth',
block: 'start',
});
}
},
clickBaseMenu(menu) {
console.log("emnu", menu)
this.currentBaseMenu = menu.id;
},
async goBaidu() {
@ -160,22 +165,122 @@ export default Vue.extend({
await this.$store.commit('setNavIndex', 0)
},
async goAliyun() {
this.scrollToElement('topBox')
await this.$store.commit('setShowHomeNav', true)
await this.$store.commit('setNavIndex', 1)
},
// /
sendInfo(type) {
console.log("发布类型:", type);
if (this.loginState) {
reqEnterpriseAuditInfoSearch({
url_link: window.location.href,
}).then(res => {
const dataList = res && res.data && res.data.data
const hasAuditInfo = Array.isArray(dataList) && dataList.length !== 0
const roles = sessionStorage.getItem('jueseNew')
const isCustomer = roles ? roles.includes('客户') : true
if (hasAuditInfo && dataList[0]) {
const auditStatus = dataList[0].audit_status
if (auditStatus === 'pending') {
this.$message.warning('您的审核状态为待审核,请等待审核通过后发布~')
} else if (auditStatus === 'rejected') {
this.$message.warning('您的审核状态为驳回,请重新提交~')
} else {
//
this.publish_type = type
this.sendProductVisible = true
}
} else if (!isCustomer) {
//
this.publish_type = type
this.sendProductVisible = true
} else {
//
this.showTip = true
}
})
} else {
this.$router.push('/login')
}
},
//
sendProductSuccess() {
this.sendProductVisible = false;
this.$message.success(this.publish_type === '1' ? '商品发布成功' : '需求发布成功');
// 广
if (this.$route.path === '/supplyAndDemandSquare') {
// 广
this.$bus.$emit('refreshSupplyDemandList');
}
},
//
goInfo() {
this.showTip = false
this.$router.push('/customer/approve')
},
}
})
</script>
<style scoped lang="less">
/deep/.banner-box {
height: 700px!important;
background: url('./img/tt-banner.png') no-repeat ;
width: 100%;
padding-bottom: 200px;
.conter {
width: 700px;
position: relative;
display: flex;
flex-direction: column;
align-items: flex-start;
margin: 140px 240px 0px;
}
.title {
font-size: 30px;
font-weight: 600;
}
.banner-title {
width: 500px;
font-size: 16px;
color: #8890ab;
line-height: 2 !important;
}
.btn{
display: flex;
}
.btn-box{
padding: 10px 20px;
background: linear-gradient(90deg, rgb(39, 90, 255), rgb(46, 189, 250));
border-radius: 14px;
color: #fff;
margin-right: 20px;
margin-top: 20px;
cursor: pointer;
transition: all 0.3s ease;
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(39, 90, 255, 0.3);
}
}
}
<style scoped lang="scss">
.search-box {
width: 100%;
margin-top: 15px;
margin: 45px 0;
margin-bottom: 25px;
// margin: 45px 0 25px 0;
margin-bottom: 20px;
display: flex;
flex-direction: column;
align-items: center;
@ -183,7 +288,6 @@ export default Vue.extend({
}
.homeOut {
//padding-top: 60px;
height: 100%;
overflow: auto !important;
min-width: 1500px;
@ -192,12 +296,9 @@ export default Vue.extend({
align-items: center;
justify-content: flex-start;
background-color: #f6f8fd;
}
.footer {
padding: 35px 0;
width: 100%;
display: flex;
@ -227,13 +328,11 @@ export default Vue.extend({
font-size: 0.187rem;
}
.qr-code {
img {
width: 100%;
height: 100%;
}
width: 1.853rem;
height: 1.853rem;
}
@ -253,19 +352,9 @@ export default Vue.extend({
align-items: center;
}
.logo {
background-color: #32abfc;
img {
width: 100%;
height: 100%;
}
}
.bigUl {
margin: 0 15px;
margin-left: -250px;
//padding-top: 15px;
width: fit-content;
display: flex;
justify-content: flex-start;
@ -273,7 +362,6 @@ export default Vue.extend({
.bigLi {
margin: 0 25px;
}
height: 100%;
.title {
@ -283,7 +371,6 @@ export default Vue.extend({
}
.smallUl {
font-size: 16px;
color: #7A82A0;
@ -323,4 +410,7 @@ export default Vue.extend({
color: #1b5bff;
}
}
/deep/.el-pagination{
text-align: center !important;
}
</style>

View File

@ -1,25 +1,11 @@
<template>
<div class="main-box">
<div class="class">
<div class="class-box" @mouseenter="hoverClassBox = 1" @mouseleave="hoverClassBox = 0" :class="{ active: hoverClassBox === 1 }">
<div class="class-title" @click="sendInfo('2')">
发布需求
</div>
</div>
<div class="class-box" @mouseenter="hoverClassBox = 2" @mouseleave="hoverClassBox = 0" :class="{ active: hoverClassBox === 2 }">
<div class="class-title" @click="sendInfo('1')">
发布商品
</div>
</div>
</div>
<div style="margin-top: 25px;">
<span style="margin-top: 100px;" class="title">
<span class="leftText">
算力供需
</span>
<span class="rightText"> 广场</span></span>
</div>
<!-- 发布商品/需求弹窗 -->
@ -38,80 +24,88 @@
</span>
</el-dialog>
<!-- <div style="width: 100%;max-width: 1600px;"> -->
<div class="category-filter">
<!-- 新增的需求和商品radio按钮组 -->
<div class="radio-group-container">
<div class="radio-group">
<label class="radio-item" style="margin-right: 25px;" :class="{ active: publish_type === '1' }">
<input type="radio" v-model="publish_type" value="1" @change="handleTypeChange">
<span class="radio-text">企业商品</span>
</label>
<label class="radio-item" :class="{ active: publish_type === '2' }">
<input type="radio" v-model="publish_type" value="2" @change="handleTypeChange">
<span class="radio-text">企业需求</span>
</label>
<!-- 筛选条件区域 - 整合到一个卡片中 -->
<div class="filter-card">
<!-- <div class="filter-header">
<span class="filter-title">筛选条件</span>
</div> -->
<div class="filter-content">
<!-- 发布类型 -->
<div class="filter-section">
<div class="filter-label">发布类型</div>
<div class="filter-options">
<label class="filter-option" :class="{ active: publish_type === '1' }">
<input type="radio" v-model="publish_type" value="1" @change="handleTypeChange">
<span class="option-text">企业商品</span>
</label>
<label class="filter-option" :class="{ active: publish_type === '2' }">
<input type="radio" v-model="publish_type" value="2" @change="handleTypeChange">
<span class="option-text">企业需求</span>
</label>
</div>
</div>
<!-- 所属类别 -->
<div class="category-section">
<div class="category-title">所属类别</div>
<div class="category-tags">
<div class="filter-section">
<div class="filter-label">所属类别</div>
<div class="filter-options">
<span v-for="category in firstCategories" :key="category.id"
:class="['category-tag', { active: activeFirstId === category.id }]"
:class="['filter-option', { active: activeFirstId === category.id }]"
@click="selectFirstCategory(category.id)">
{{ category.product_category || category.label }}
</span>
</div>
</div>
<div class="category-section" v-if="secondCategories.length > 0">
<div class="category-title">所属品类</div>
<div class="category-tags">
<!-- 所属品类 -->
<div class="filter-section" v-if="secondCategories.length > 0">
<div class="filter-label">所属品类</div>
<div class="filter-options">
<span v-for="category in secondCategories" :key="category.id"
:class="['category-tag', { active: activeSecondId === category.id }]"
:class="['filter-option', { active: activeSecondId === category.id }]"
@click="selectSecondCategory(category.id)">
{{ category.product_category || category.label }}
</span>
</div>
</div>
<!-- 公司类别 -->
<div class="category-section">
<div class="category-title">公司类别</div>
<div class="category-tags">
<div class="filter-section">
<div class="filter-label">公司类别</div>
<div class="filter-options">
<span v-for="company in companies" :key="company.id"
:class="['category-tag', { active: selectedCompanies.includes(company.value) }]"
:class="['filter-option', { active: selectedCompanies.includes(company.value) }]"
@click="selectCompany(company.value)">
{{ company.label }}
</span>
</div>
</div>
<!-- 产品 -->
<div class="product-card-container">
<div v-if="productList.length > 0">
<productCard type="supplyAndDemandSquare" :publish_type="publish_type"
:productList="productList">
</productCard>
<el-pagination @current-change="handleCurrentChange" :page-size="page_size"
layout="total, prev, pager, next" :total="total">
</el-pagination>
</div>
<div v-else class="no-data">
<img style="width: 150px;height: 10px;" src="./img/empty.svg" alt="">
暂无数据
</div>
</div>
</div>
<!-- </div> -->
</div>
<!-- 产品列表 -->
<div class="product-card-container">
<div v-if="productList.length > 0">
<productCard type="supplyAndDemandSquare" :publish_type="publish_type"
:productList="productList">
</productCard>
<el-pagination @current-change="handleCurrentChange" :page-size="page_size"
layout="total, prev, pager, next" :total="total" style="width: 100%; text-align: center;">
</el-pagination>
</div>
<div v-else class="no-data">
<img style="width: 150px;height: 150px;" src="./img/empty.svg" alt="">
暂无数据
</div>
</div>
</div>
</template>
<script>
import { reqGetSupplyAndDemandSquareList, reqCompanyCategorySearch, reqSupplyAndDemandFirstCategory, reqEnterpriseAuditInfoSearch } from '@/api/ncmatch'
import { mapGetters, mapState } from 'vuex'
export default {
name: 'supplyAndDemandSquare',
components: {
@ -120,26 +114,20 @@ export default {
},
data() {
return {
// hover
hoverClassBox: 0, // 0: , 1: , 2:
page_size: 8,
current_page: 1,
typeList: [],
publish_type: '1', //
selectedCategory: '', //
selectedCompanies: [], //
publish_type: '1',
selectedCategory: '',
selectedCompanies: [],
categories: [],
companies: [],
productList: [],
detailVisible: false,
oneLevelCategory:[],
twoLevelCategory:[],
//
total: 0,
firstCategories: [],
secondCategories: [],
activeFirstId: null,
activeSecondId: null,
//
showTip: false,
sendProductVisible: false,
}
@ -178,7 +166,6 @@ export default {
const roles = sessionStorage.getItem('jueseNew')
const isCustomer = roles ? roles.includes('客户') : true
// data[0]
if (hasAuditInfo && dataList[0]) {
const auditStatus = dataList[0].audit_status
@ -187,16 +174,13 @@ export default {
} else if (auditStatus === 'rejected') {
this.$message.warning('您的审核状态为驳回,请重新提交~')
} else {
//
this.publish_type = type
this.sendProductVisible = true
}
} else if (!isCustomer) {
//
this.publish_type = type
this.sendProductVisible = true
} else {
//
this.showTip = true
}
})
@ -207,8 +191,8 @@ export default {
//
sendProductSuccess() {
this.sendProductVisible = false; //
this.initData() //
this.sendProductVisible = false;
this.initData()
},
//
@ -217,32 +201,19 @@ export default {
this.$router.push('/customer/approve')
},
getOneLevelCategory(){
// reqSupplyAndDemandFirstCategory({url_link:window.location.href}).then(res=>{
// if(res.status){
// this.oneLevelCategory=res.data
// }
// })
},
getTwoLevelCategory(){
// reqSupplyAndDemandSecondCategory({url_link:window.location.href}).then(res=>{
// if(res.status){
// this.twoLevelCategory=res.data
// }
// })
},
handleCurrentChange(val) {
this.current_page = val
this.initData()
},
initAllData() {
//
this.init_product_category().then(() => {
this.init_company_category().then(() => {
this.initData()
})
})
},
init_company_category() {
return reqCompanyCategorySearch({ url_link: window.location.href }).then(res => {
if (res.status) {
@ -253,23 +224,22 @@ export default {
value: item.company_category
})
}
this.companies = this.company_category_list
}
return res
})
},
//
selectFirstCategory(id) {
if (id === this.activeFirstId) return
this.activeFirstId = id
//
this.activeSecondId = null
this.selectedCategory = id
//
this.loadSecondCategories(id)
this.initData()
},
//
selectSecondCategory(id) {
if (id === this.activeSecondId) return
@ -277,8 +247,8 @@ export default {
this.selectedCategory = id
this.initData()
},
init_product_category() {
//
return reqSupplyAndDemandFirstCategory({to_page: 'show', url_link: window.location.href }).then(res => {
if (res.status) {
this.firstCategories = Array.isArray(res.data) ? res.data : []
@ -286,7 +256,6 @@ export default {
this.activeFirstId = this.firstCategories[0].id
this.selectedCategory = this.activeFirstId
this.activeSecondId = null
//
return this.loadSecondCategories(this.activeFirstId)
} else {
this.activeFirstId = null
@ -298,8 +267,8 @@ export default {
return res
})
},
loadSecondCategories(firstId) {
// first_level_id /
return reqSupplyAndDemandFirstCategory({ to_page: 'show',url_link: window.location.href, first_level_id: firstId }).then(res => {
if (res.status) {
this.secondCategories = Array.isArray(res.data) ? res.data : []
@ -309,12 +278,12 @@ export default {
return res
})
},
handleTypeChange() {
//
console.log('切换到:', this.publish_type)
//
this.initData()
},
initData() {
let ploay = {
product_category: this.selectedCategory,
@ -335,197 +304,22 @@ export default {
this.total = res.data[0].total_count
}
})
},
selectCompany(companyId) {
const index = this.selectedCompanies.indexOf(companyId)
if (index > -1) {
//
this.selectedCompanies.splice(index, 1)
} else {
//
this.selectedCompanies.push(companyId)
}
console.log("this.selectedCompanies", this.selectedCompanies);
this.initData()
},
getProductList() {
this.productList = [
{
id: 1,
name: 'NVIDIA-4090',
image: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjE1MCIgdmlld0JveD0iMCAwIDIwMCAxNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyMDAiIGhlaWdodD0iMTUwIiBmaWxsPSIjMjIyMjIyIi8+Cjx0ZXh0IHg9IjEwMCIgeT0iNzUiIGZvbnQtZmFtaWx5PSJBcmlhbCIgZm9udC1zaXplPSIxNCIgZmlsbD0id2hpdGUiIHRleHQtYW5jaG9yPSJtaWRkbGUiPk5WSUQpQSBSVFggNDA5MDwvdGV4dD4KPC9zdmc+Cg==',
price: 6000,
cpu: 'AMD EPYC 7542 32 C * 2',
memory: '64G DDR4-3200 * 8',
gpu: 'NVIDIA-4090-24GB * 8',
sys_disk: '960G SATA SSD * 2 (Raid)',
data_disk: '3.84T U.2 NVMe SSD * 1',
net_card: 'Mellanox Connect4 25G SFP28 2-port * 1'
},
{
id: 2,
name: 'NVIDIA-A100',
image: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjE1MCIgdmlld0JveD0iMCAwIDIwMCAxNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyMDAiIGhlaWdodD0iMTUwIiBmaWxsPSIjMjIyMjIyIi8+Cjx0ZXh0IHg9IjEwMCIgeT0iNzUiIGZvbnQtZmFtaWx5PSJBcmlhbCIgZm9udC1zaXplPSIxNCIgZmlsbD0id2hpdGUiIHRleHQtYW5jaG9yPSJtaWRkbGUiPk5WSUQpQSBSVFggNDA5MDwvdGV4dD4KPC9zdmc+Cg==',
price: 8000,
cpu: 'AMD EPYC 7542 32 C * 2',
memory: '128G DDR4-3200 * 8',
gpu: 'NVIDIA-A100-80GB * 8',
sys_disk: '1.92T SATA SSD * 2 (Raid)',
data_disk: '7.68T U.2 NVMe SSD * 1',
net_card: 'Mellanox Connect4 25G SFP28 2-port * 1'
},
{
id: 3,
name: '昇腾910B',
image: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjE1MCIgdmlld0JveD0iMCAwIDIwMCAxNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyMDAiIGhlaWdodD0iMTUwIiBmaWxsPSIjMjIyMjIyIi8+Cjx0ZXh0IHg9IjEwMCIgeT0iNzUiIGZvbnQtZmFtaWx5PSJBcmlhbCIgZm9udC1zaXplPSIxNCIgZmlsbD0id2hpdGUiIHRleHQtYW5jaG9yPSJtaWRkbGUiPk5WSUQpQSBSVFggNDA5MDwvdGV4dD4KPC9zdmc+Cg==',
price: 5000,
cpu: 'Kunpeng 920 64 C * 2',
memory: '64G DDR4-3200 * 8',
gpu: '昇腾910B-32GB * 8',
sys_disk: '960G SATA SSD * 2 (Raid)',
data_disk: '3.84T U.2 NVMe SSD * 1',
net_card: 'Mellanox Connect4 25G SFP28 2-port * 1'
},
{
id: 4,
name: '昆仑芯P800',
image: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjE1MCIgdmlld0JveD0iMCAwIDIwMCAxNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyMDAiIGhlaWdodD0iMTUwIiBmaWxsPSIjMjIyMjIyIi8+Cjx0ZXh0IHg9IjEwMCIgeT0iNzUiIGZvbnQtZmFtaWx5PSJBcmlhbCIgZm9udC1zaXplPSIxNCIgZmlsbD0id2hpdGUiIHRleHQtYW5jaG9yPSJtaWRkbGUiPk5WSUQpQSBSVFggNDA5MDwvdGV4dD4KPC9zdmc+Cg==',
price: 4000,
cpu: 'Kunpeng 920 64 C * 2',
memory: '64G DDR4-3200 * 8',
gpu: '昆仑芯P800-16GB * 8',
sys_disk: '960G SATA SSD * 2 (Raid)',
data_disk: '3.84T U.2 NVMe SSD * 1',
net_card: 'Mellanox Connect4 25G SFP28 2-port * 1'
}
]
}
},
mounted() {
// this.getProductList()
}
}
</script>
<style scoped lang="scss">
.class{
margin: 40px 0;
min-width: 1200px;
display: flex;
background-color: #fff;
padding:8px 10px;
.class-box{
width: 50%;
padding: 10px 20px;
// border-radius: 8px;
transition: all 0.3s ease;
cursor: pointer;
border: 1px solid transparent;
text-align: center;
/* 悬停时的渐变背景 */
&:hover,
&.active {
background: linear-gradient(to right, #2979fe, #2eb8fa);
border-color: #2979fe;
color: #fff;
box-shadow: 0 4px 12px rgba(41, 121, 254, 0.3);
.class-title {
color: #fff;
}
}
}
.class-title{
font-size: 16px;
color: #333;
transition: color 0.3s ease;
}
}
.back-btn {
width: 100%;
height: 40px;
line-height: 40px;
display: flex;
justify-content: flex-start;
align-items: center;
margin-top: 20px;
font-size: 16px;
color: #666;
&:hover {
cursor: pointer;
color: #275AFF;
}
}
/* 新增的radio按钮组样式 */
.radio-group-container {
width: 100% !important;
display: flex;
justify-content: flex-start;
// margin: 20px 0;
align-items: center;
max-width: 1400px;
}
.radio-group {
display: flex;
//background: #fff;
border-radius: 8px;
margin-bottom: 15px;
// box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.radio-item {
position: relative;
display: flex;
align-items: center;
justify-content: center;
padding: 8px 16px;
border-radius: 6px;
cursor: pointer;
transition: all 0.3s ease;
background: #fff;
border: 1px solid #e8e8e8;
margin-right: 4px;
font-size: 16px !important;
&:last-child {
margin-right: 0;
}
input[type="radio"] {
position: absolute;
opacity: 0;
width: 0;
height: 0;
}
.radio-text {
font-size: 16px;
color: #275AFF;
font-weight: 500;
transition: all 0.3s ease;
}
&:hover {
border-color: #275AFF;
}
&.active {
background: linear-gradient(to right, #275AFF, #2EBDFA);
border-color: #275AFF;
box-shadow: 0 2px 8px rgba(39, 90, 255, 0.3);
.radio-text {
color: #fff;
}
}
}
.title {
color: #666 !important;
font-size: 36px;
@ -533,52 +327,15 @@ export default {
.leftText {
background: linear-gradient(to right, #275AFF, #2EBDFA);
/* 渐变方向颜色 */
-webkit-background-clip: text;
/* 关键属性:裁剪背景到文字 */
background-clip: text;
color: transparent;
/* 文字颜色透明 */
display: inline-block;
/* 确保渐变生效 */
}
}
.itemTitle {
display: flex;
justify-content: flex-start;
align-items: center;
flex-direction: column;
.topText {
color: #222F60;
font-size: 48px;
font-weight: bold;
}
.bottomText {
font-size: 24px;
color: #7A82A0;
margin-top: 15px;
}
}
.product-list {
width: 100%;
// display: grid;
// grid-template-columns: repeat(4, 1fr);
// gap: 20px;
.no-data {
text-align: center;
font-size: 16px;
}
}
/* 产品卡片容器样式 */
.product-card-container {
margin-top: 20px;
margin-top: 30px;
width: 100%;
}
@ -591,66 +348,119 @@ export default {
max-width: 1600px;
}
.category-filter {
// padding: 20px;
bottom: 1rem;
// background-color: #;
/* 筛选卡片样式 */
.filter-card {
width: 100%;
max-width: 1400px;
background: white;
border-radius: 16px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
margin: 20px 0;
transition: all 0.3s ease;
overflow: hidden;
&:hover {
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.12);
}
}
.filter-header {
padding: 20px 25px;
border-bottom: 1px solid #f0f0f0;
background: linear-gradient(135deg, #f8faff 0%, #f0f4ff 100%);
}
.filter-title {
font-size: 18px;
font-weight: 600;
color: #111e52;
display: flex;
align-items: center;
&::before {
content: '';
display: inline-block;
width: 4px;
height: 16px;
background: linear-gradient(135deg, #275AFF, #2EBDFA);
border-radius: 2px;
margin-right: 10px;
}
}
.filter-content {
padding: 25px;
}
.filter-section {
display: flex;
align-items: flex-start;
margin-bottom: 25px;
&:last-child {
margin-bottom: 0;
}
}
.filter-label {
font-size: 14px;
color: #333;
font-weight: 500;
white-space: nowrap;
flex-shrink: 0;
line-height: 32px;
width: 80px;
margin-right: 20px;
}
.filter-options {
display: flex;
flex-wrap: wrap;
gap: 12px;
flex: 1;
}
.filter-option {
position: relative;
padding: 8px 20px;
border: 1px solid #e0e0e0;
border-radius: 8px;
margin: 20px;
margin-left: 0;
margin-right: 0;
font-size: 14px;
color: #666;
cursor: pointer;
transition: all 0.3s ease;
background: white;
display: flex;
align-items: center;
justify-content: center;
min-width: 80px;
text-align: center;
.category-section {
display: flex;
justify-content: flex-start;
align-items: center;
margin-bottom: 20px;
&:hover {
border-color: #275AFF;
color: #275AFF;
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(39, 90, 255, 0.2);
}
&:last-child {
margin-bottom: 0;
}
&.active {
background: linear-gradient(135deg, #275AFF, #2EBDFA);
color: white;
border-color: #275AFF;
box-shadow: 0 2px 8px rgba(39, 90, 255, 0.3);
}
.category-title {
font-size: 16px;
color: #333;
// margin-bottom: 12px;
font-weight: 500;
display: flex;
justify-content: flex-end;
align-items: center;
height: 100%;
margin-right: 15px;
}
/* 隐藏原生radio */
input[type="radio"] {
position: absolute;
opacity: 0;
width: 0;
height: 0;
}
.category-tags {
display: flex;
flex-wrap: wrap;
gap: 8px;
.category-tag {
padding: 3px 6px;
background-color: #fff;
border: 1px solid #e8e8e8;
border-radius: 2px;
color: #666;
cursor: pointer;
transition: all 0.3s ease;
font-size: 14px;
&:hover {
border-color: #1890ff;
color: #1890ff;
}
&.active {
background-color: #e6f7ff;
border-color: #1890ff; /* 激活状态下的边框颜色 */
color: #1890ff;
}
}
}
.option-text {
font-weight: 500;
pointer-events: none;
}
}
@ -662,11 +472,50 @@ export default {
font-size: 16px;
color: #7A82A0;
flex-direction: column;
}
.el-pagination{
text-align: center;
.el-pagination {
text-align: center;
margin-top: 30px;
}
/* 响应式调整 */
@media (max-width: 768px) {
.filter-card {
margin: 15px 10px;
}
.filter-content {
padding: 15px;
}
.filter-section {
flex-direction: column;
margin-bottom: 20px;
}
.filter-label {
width: 100%;
margin-bottom: 10px;
margin-right: 0;
}
.filter-options {
width: 100%;
gap: 8px;
}
.filter-option {
padding: 6px 12px;
font-size: 12px;
min-width: 60px;
}
}
@media (max-width: 1200px) {
.filter-card {
max-width: calc(100% - 40px);
margin: 20px;
}
}
</style>

View File

@ -99,9 +99,9 @@
<el-input ref="vcode" v-model="loginForm.vcode" placeholder="请输入验证码" name="vcode" type="text" />
</div>
</el-form-item>
<!-- 获取验证码按钮 -->
<span :disabled="isDisabled" class="getCodeStyleNew" style="height:40px;margin-left:10px"
@click="getCode">
<!-- 获取验证码按钮 - 添加防抖功能 -->
<span :disabled="isDisabled || isGettingCode" class="getCodeStyleNew" style="height:40px;margin-left:10px"
@click="debouncedGetCode">
{{ SendCode_text }}
</span>
</div>
@ -155,7 +155,7 @@
<el-input style="border:1px solid #d9d9d9;border-radius: 3px" ref="vcode" v-model="form.vcode"
placeholder="请输入验证码" name="vcode" type="text" />
<el-button type="primary" size="mini" style="height: 40px; margin-left: 10px"
:disabled="isDisabled1" @click="getCode1">
:disabled="isDisabled1 || isGettingCode1" @click="debouncedGetCode1">
{{ SendCode_text1 }}
</el-button>
</div>
@ -246,6 +246,12 @@ export default {
timer: null, //
timer1: null, //
//
isGettingCode: false, //
isGettingCode1: false, //
debounceTimer: null, //
debounceTimer1: null, //
//
dialogVisible: false, //
loading: false, //
@ -347,6 +353,50 @@ export default {
},
methods: {
//
debounce(func, wait) {
return function() {
const context = this;
const args = arguments;
clearTimeout(this.debounceTimer);
this.debounceTimer = setTimeout(() => {
func.apply(context, args);
}, wait);
};
},
//
debouncedGetCode: function() {
if (this.isDisabled || this.isGettingCode) return;
this.isGettingCode = true;
//
clearTimeout(this.debounceTimer);
// 300ms
this.debounceTimer = setTimeout(() => {
this.getCode();
this.isGettingCode = false;
}, 300);
},
//
debouncedGetCode1: function() {
if (this.isDisabled1 || this.isGettingCode1) return;
this.isGettingCode1 = true;
//
clearTimeout(this.debounceTimer1);
// 300ms
this.debounceTimer1 = setTimeout(() => {
this.getCode1();
this.isGettingCode1 = false;
}, 300);
},
//
goBaidu(listUrl, url) {
this.$store.commit('setRedirectUrl', url)
@ -695,6 +745,9 @@ export default {
});
}
}
}).catch(error => {
this.isGettingCode = false;
this.$message.error('验证码获取失败');
});
},
@ -743,6 +796,9 @@ export default {
type: "error",
});
}
}).catch(error => {
this.isGettingCode1 = false;
this.$message.error('验证码获取失败');
});
},