1688 lines
42 KiB
Vue
1688 lines
42 KiB
Vue
<template>
|
||
<div class="plaza-page">
|
||
<div class="floating-orb orb-1"></div>
|
||
<div class="floating-orb orb-2"></div>
|
||
<div class="floating-orb orb-3"></div>
|
||
<div class="floating-orb orb-4"></div>
|
||
|
||
<section class="hero-section">
|
||
<div class="hero-glow glow-blue"></div>
|
||
<div class="hero-glow glow-cyan"></div>
|
||
<div class="hero-glow glow-warm"></div>
|
||
<div class="particle-layer">
|
||
<span v-for="item in 30" :key="item" :style="getParticleStyle(item)"></span>
|
||
</div>
|
||
|
||
<div class="hero-inner">
|
||
<h1>供需<span>广场</span></h1>
|
||
<p>
|
||
围绕云资源、算力、网络服务、模型及应用,企业可灵活发布资源供给或业务需求,
|
||
通过精准匹配打破信息壁垒,助力企业降本增效
|
||
</p>
|
||
<div class="hero-actions">
|
||
<button type="button" class="primary-btn" @click="sendInfo('2')">
|
||
<i class="el-icon-plus"></i>
|
||
发布需求
|
||
</button>
|
||
<button type="button" class="secondary-btn" @click="scrollToList">
|
||
<i class="el-icon-search"></i>
|
||
浏览产品
|
||
</button>
|
||
<!-- <button type="button" class="secondary-btn" @click="sendInfo('1')">
|
||
<i class="el-icon-s-goods"></i>
|
||
发布商品
|
||
</button> -->
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
|
||
|
||
<section id="demand-list" class="list-section">
|
||
<div class="section-head">
|
||
<h2>热门<span>产品</span></h2>
|
||
<p>AI 行业应用领域,开元云为您提供完善的产品服务</p>
|
||
</div>
|
||
|
||
<div class="toolbar">
|
||
<div class="search-box">
|
||
<i class="el-icon-search"></i>
|
||
<input v-model.trim="keyword" type="text" placeholder="搜索产品..." @input="handleSearch">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="tab-row">
|
||
<button
|
||
v-for="tab in plazaTabs"
|
||
:key="tab.value"
|
||
type="button"
|
||
:class="['tab-btn', { active: currentPlazaTab === tab.value }]"
|
||
:data-color="tab.color"
|
||
@click="switchPlazaTab(tab.value)"
|
||
>
|
||
{{ tab.label }}
|
||
</button>
|
||
</div>
|
||
|
||
<div v-if="filteredPlazaDemandList.length" class="card-grid">
|
||
<article v-for="item in filteredPlazaDemandList" :key="item.title" class="demand-card">
|
||
<div class="card-top">
|
||
<span class="type-tag" :style="getTypeStyle(item)">{{ item.type }}</span>
|
||
</div>
|
||
<h4>{{ item.title }}</h4>
|
||
<p>{{ item.desc }}</p>
|
||
<div class="tag-list">
|
||
<span v-for="tag in item.tags" :key="tag" :style="getTypeStyle(item)">{{ tag }}</span>
|
||
</div>
|
||
<div class="card-foot static-card-foot">
|
||
<button type="button">
|
||
查看详情
|
||
<span>→</span>
|
||
</button>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
|
||
<div v-else class="empty-box">
|
||
<img src="./img/empty.svg" alt="暂无数据">
|
||
<p>暂无匹配的需求信息</p>
|
||
</div>
|
||
|
||
<!-- 原接口返回产品区域先保留,按需求隐藏不删除 -->
|
||
<div class="interface-product-block is-hidden">
|
||
<div class="tab-row">
|
||
<button
|
||
type="button"
|
||
:class="['tab-btn', { active: !activeFirstId }]"
|
||
data-color="blue"
|
||
@click="selectFirstCategory('')"
|
||
>
|
||
全部
|
||
</button>
|
||
<button
|
||
v-for="category in firstCategories"
|
||
:key="category.id"
|
||
type="button"
|
||
:class="['tab-btn', { active: activeFirstId === category.id }]"
|
||
:data-color="getTabColor(category)"
|
||
@click="selectFirstCategory(category.id)"
|
||
>
|
||
{{ getCategoryName(category) }}
|
||
</button>
|
||
</div>
|
||
|
||
<div v-if="secondCategories.length" class="sub-tab-row">
|
||
<button
|
||
type="button"
|
||
:class="['sub-tab-btn', { active: !activeSecondId }]"
|
||
@click="selectSecondCategory('')"
|
||
>
|
||
全部品类
|
||
</button>
|
||
<button
|
||
v-for="category in secondCategories"
|
||
:key="category.id"
|
||
type="button"
|
||
:class="['sub-tab-btn', { active: activeSecondId === category.id }]"
|
||
@click="selectSecondCategory(category.id)"
|
||
>
|
||
{{ getCategoryName(category) }}
|
||
</button>
|
||
</div>
|
||
|
||
<div class="publish-type-row">
|
||
<button type="button" :class="{ active: publish_type === '1' }" @click="changePublishType('1')">企业商品</button>
|
||
<button type="button" :class="{ active: publish_type === '2' }" @click="changePublishType('2')">企业需求</button>
|
||
</div>
|
||
|
||
<div v-if="filteredProductList.length" class="card-grid">
|
||
<article v-for="item in filteredProductList" :key="item.id" class="demand-card">
|
||
<div class="card-top">
|
||
<span class="type-tag" :style="getTypeStyle(item)">{{ getItemType(item) }}</span>
|
||
<span v-if="item.favorite === '1'" class="favorite-tag">已收藏</span>
|
||
</div>
|
||
<h4>{{ item.product_name || item.name || '未命名产品' }}</h4>
|
||
<p>{{ item.requirement_summary || item.description || '暂无描述' }}</p>
|
||
<div v-if="item.company_name || item.company_type" class="meta-line">
|
||
<span v-if="item.company_name">{{ item.company_name }}</span>
|
||
<span v-if="item.company_type">{{ item.company_type }}</span>
|
||
</div>
|
||
<div class="tag-list">
|
||
<span v-for="tag in getItemTags(item)" :key="tag" :style="getTypeStyle(item)">{{ tag }}</span>
|
||
</div>
|
||
<div class="card-foot">
|
||
<span class="price">{{ getPriceText(item) }}</span>
|
||
<button type="button" @click="openDetail(item)">
|
||
查看详情
|
||
<i v-if="loadingStates[item.id]" class="el-icon-loading"></i>
|
||
<span v-else>→</span>
|
||
</button>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
|
||
<div v-else class="empty-box">
|
||
<img src="./img/empty.svg" alt="暂无数据">
|
||
<p>暂无匹配的需求信息</p>
|
||
</div>
|
||
|
||
<el-pagination
|
||
v-if="total > page_size"
|
||
class="plaza-pagination"
|
||
:current-page.sync="current_page"
|
||
:page-size="page_size"
|
||
layout="total, prev, pager, next"
|
||
:total="total"
|
||
@current-change="handleCurrentChange"
|
||
/>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="cta-section">
|
||
<div class="cta-card">
|
||
<div class="cta-bg"></div>
|
||
<div class="cta-content">
|
||
<h2>打破信息壁垒,助力降本增效</h2>
|
||
<p>发布需求,精准匹配,与行业伙伴共建云服务生态</p>
|
||
<div>
|
||
<button type="button" class="primary-btn" @click="sendInfo('2')">
|
||
<i class="el-icon-plus"></i>
|
||
发布需求
|
||
</button>
|
||
<button type="button" class="secondary-btn" @click="sendInfo('1')">
|
||
<i class="el-icon-office-building"></i>
|
||
企业入驻
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<div v-if="publishDemandVisible" class="modal-overlay active" @click.self="closePublishDemand">
|
||
<div class="modal-content" @click.stop>
|
||
<div class="modal-header">
|
||
<h3>发布需求</h3>
|
||
<button type="button" class="modal-close" @click="closePublishDemand">
|
||
<i class="el-icon-close"></i>
|
||
</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="form-item">
|
||
<label>所属类别 <span>*</span></label>
|
||
<el-cascader
|
||
v-model="demandForm.product_category"
|
||
class="demand-category-cascader"
|
||
:options="demandCategoryOptions"
|
||
placeholder="请选择所属类别"
|
||
@change="handleDemandCategoryChange"
|
||
></el-cascader>
|
||
</div>
|
||
<div class="form-item">
|
||
<label>应用场景</label>
|
||
<input v-model.trim="demandForm.scenario" class="form-input" type="text" placeholder="请描述应用场景,如:智能客服、金融风控、医疗影像等">
|
||
</div>
|
||
<div class="form-item">
|
||
<label>需求标题 <span>*</span></label>
|
||
<input v-model.trim="demandForm.title" class="form-input" type="text" placeholder="请输入需求标题">
|
||
</div>
|
||
<div class="form-item">
|
||
<label>需求描述 <span>*</span></label>
|
||
<textarea v-model.trim="demandForm.desc" class="form-input" placeholder="请详细描述您的需求,包括场景、规模、期望交付方式等"></textarea>
|
||
</div>
|
||
<div class="form-item">
|
||
<label>企业名称 <span>*</span></label>
|
||
<input v-model.trim="demandForm.company" class="form-input" type="text" placeholder="请输入企业名称">
|
||
</div>
|
||
<div class="form-item">
|
||
<label>联系人</label>
|
||
<input v-model.trim="demandForm.contact" class="form-input" type="text" placeholder="请输入联系人姓名">
|
||
</div>
|
||
<div class="form-item">
|
||
<label>联系方式</label>
|
||
<input v-model.trim="demandForm.phone" class="form-input" type="text" placeholder="手机号或邮箱">
|
||
</div>
|
||
<div class="modal-actions">
|
||
<button type="button" class="submit-demand-btn" @click="submitDemand">提交需求</button>
|
||
<button type="button" class="cancel-demand-btn" @click="closePublishDemand">取消</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<el-dialog
|
||
:title="publish_type === '2' ? '发布需求' : '发布商品'"
|
||
width="60vw"
|
||
top="5vh"
|
||
custom-class="publish-dialog"
|
||
:visible.sync="sendProductVisible"
|
||
>
|
||
<sendProduct v-if="publish_type" :isEdit="false" :publish_type="publish_type" @success="sendProductSuccess"></sendProduct>
|
||
</el-dialog>
|
||
|
||
<el-dialog title="温馨提示" :visible.sync="showTip" width="30%">
|
||
<span>您还没有完善企业信息,完善企业信息审核通过后您可以发布需求与商品。</span>
|
||
<span slot="footer" class="dialog-footer">
|
||
<span>
|
||
<span class="tip-text">跳转到</span>
|
||
<el-button size="small" type="primary" @click="goInfo">信息完善</el-button>
|
||
</span>
|
||
</span>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import {
|
||
reqCompanyCategorySearch,
|
||
reqEnterpriseAuditInfoSearch,
|
||
reqGetProductCategorySearch,
|
||
reqGetProductDetail,
|
||
reqGetSupplyAndDemandSquareList,
|
||
reqPublishProductAdd,
|
||
reqSupplyAndDemandFirstCategory
|
||
} from '@/api/ncmatch'
|
||
import { buildCaTree } from '@/views/homePage/ncmatch/mainPage/sendProduct/buildCaTree'
|
||
import { mapGetters, mapState } from 'vuex'
|
||
|
||
export default {
|
||
name: 'supplyAndDemandSquare',
|
||
components: {
|
||
sendProduct: () => import('@/views/homePage/ncmatch/mainPage/sendProduct/index.vue')
|
||
},
|
||
data() {
|
||
return {
|
||
page_size: 9,
|
||
current_page: 1,
|
||
publish_type: '1',
|
||
selectedCategory: '',
|
||
selectedCompanies: [],
|
||
companies: [],
|
||
productList: [],
|
||
total: 0,
|
||
firstCategories: [],
|
||
secondCategories: [],
|
||
demandCategoryOptions: [],
|
||
activeFirstId: '',
|
||
activeSecondId: '',
|
||
showTip: false,
|
||
sendProductVisible: false,
|
||
publishDemandVisible: false,
|
||
useStaticPlaza: true,
|
||
keyword: '',
|
||
currentPlazaTab: '全部',
|
||
loadingStates: {},
|
||
demandForm: this.createDemandForm(),
|
||
plazaTabs: [
|
||
{ label: '全部', value: '全部', color: 'blue' },
|
||
{ label: '大模型', value: '大模型', color: 'orange' },
|
||
{ label: '智能体', value: '智能体', color: 'purple' },
|
||
{ label: 'AI解决方案', value: '行业解决方案', color: 'green' }
|
||
],
|
||
plazaDemandData: [
|
||
{
|
||
title: 'AI Ops能源电力监测模型',
|
||
company: '星河能源科技',
|
||
type: '大模型',
|
||
tags: ['能源', '电力监测'],
|
||
desc: '面向能源电力场景的AI运维监测模型,实现设备状态智能预警与故障诊断'
|
||
},
|
||
{
|
||
title: '投资决策分析大模型',
|
||
company: '银河金融科技',
|
||
type: '大模型',
|
||
tags: ['投资', '决策分析'],
|
||
desc: '面向投资场景的决策分析大模型,实现市场趋势预测与风险评估'
|
||
},
|
||
{
|
||
title: '投标智能体',
|
||
company: '鼎盛集团',
|
||
type: '智能体',
|
||
tags: ['投标', '智能分析'],
|
||
desc: '面向投标场景的智能助手,实现投标文件智能生成与合规审查'
|
||
},
|
||
{
|
||
title: '招投标大模型引擎',
|
||
company: '仁济医疗科技',
|
||
type: '大模型',
|
||
tags: ['招投标', '智能引擎'],
|
||
desc: '面向招投标场景的大模型智能引擎,实现标书智能分析与生成'
|
||
},
|
||
{
|
||
title: '教学助手智能体',
|
||
company: '超算数据中心',
|
||
type: '智能体',
|
||
tags: ['教育', '智能体'],
|
||
desc: '面向教育场景的智能教学助手,实现个性化学习辅导与答疑'
|
||
},
|
||
{
|
||
title: '招标评标智能体',
|
||
company: '灵犀AI科技',
|
||
type: '智能体',
|
||
tags: ['招标', '评标'],
|
||
desc: '面向招投标场景的智能评标助手,实现标书智能解析与评分推荐'
|
||
},
|
||
{
|
||
title: 'AI智慧农业',
|
||
company: '精工制造集团',
|
||
type: '行业解决方案',
|
||
tags: ['智慧农业', 'AI'],
|
||
desc: '面向农业场景的AI智慧解决方案,实现农作物监测与精准灌溉'
|
||
}
|
||
],
|
||
steps: [
|
||
{ title: '企业入驻', desc: '完成企业认证,入驻供需广场', icon: 'el-icon-office-building', theme: 'blue' },
|
||
{ title: '发布供需', desc: '发布资源供给或业务需求信息', icon: 'el-icon-edit-outline', theme: 'cyan' },
|
||
{ title: '精准匹配', desc: 'AI 引擎智能推荐最优合作方', icon: 'el-icon-lightning', theme: 'green' },
|
||
{ title: '签约合作', desc: '线上签约,安全高效达成合作', icon: 'el-icon-finished', theme: 'teal' }
|
||
]
|
||
}
|
||
},
|
||
computed: {
|
||
filteredPlazaDemandList() {
|
||
const keyword = this.keyword.toLowerCase()
|
||
return this.plazaDemandData.filter(item => {
|
||
const matchTab = this.currentPlazaTab === '全部' || item.type === this.currentPlazaTab
|
||
const matchSearch = !keyword || [
|
||
item.title,
|
||
item.company,
|
||
item.type,
|
||
item.desc,
|
||
...(item.tags || [])
|
||
].some(value => String(value || '').toLowerCase().includes(keyword))
|
||
return matchTab && matchSearch
|
||
})
|
||
},
|
||
filteredProductList() {
|
||
if (!this.keyword) return this.productList
|
||
const keyword = this.keyword.toLowerCase()
|
||
return this.productList.filter(item => {
|
||
return [
|
||
item.product_name,
|
||
item.name,
|
||
item.company_name,
|
||
item.company_type,
|
||
item.requirement_summary,
|
||
item.description
|
||
].some(value => String(value || '').toLowerCase().includes(keyword))
|
||
})
|
||
},
|
||
isNcmatchHome() {
|
||
return window.location.href.includes('ncmatchHome')
|
||
},
|
||
...mapGetters(['sidebar', 'avatar', 'device']),
|
||
...mapState({
|
||
isShowPanel: state => state.product.showHomeNav,
|
||
navIndex: state => state.product.navIndex,
|
||
gridObj: state => state.operationAnalysis.gridObj,
|
||
mybalance: state => state.user.mybalance,
|
||
logoutUrl: state => state.login.logoutUrl,
|
||
loginStateVuex: state => state.login.loginState,
|
||
logoInfoNew: state => state.product.logoInfoNew
|
||
}),
|
||
loginState() {
|
||
const userId = sessionStorage.getItem('userId')
|
||
return this.loginStateVuex || (userId !== null && userId !== 'null' && userId !== '')
|
||
}
|
||
},
|
||
created() {
|
||
this.initDemandCategories()
|
||
if (!this.useStaticPlaza) {
|
||
this.initAllData()
|
||
}
|
||
},
|
||
methods: {
|
||
createDemandForm() {
|
||
return {
|
||
type: '',
|
||
product_category: [],
|
||
scenario: '',
|
||
title: '',
|
||
desc: '',
|
||
company: '',
|
||
contact: '',
|
||
phone: ''
|
||
}
|
||
},
|
||
initDemandCategories() {
|
||
return reqGetProductCategorySearch({ url_link: window.location.href, to_page: 'publish' }).then(res => {
|
||
if (res.status) {
|
||
this.demandCategoryOptions = buildCaTree(res.data || [])
|
||
}
|
||
return res
|
||
})
|
||
},
|
||
sendInfo(type) {
|
||
if (!this.loginState) {
|
||
this.$router.push('/login')
|
||
return
|
||
}
|
||
|
||
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.openPublishByType(type)
|
||
}
|
||
} else if (!isCustomer) {
|
||
this.openPublishByType(type)
|
||
} else {
|
||
this.showTip = true
|
||
}
|
||
})
|
||
},
|
||
openPublishByType(type) {
|
||
this.publish_type = type
|
||
if (type === '2') {
|
||
this.publishDemandVisible = true
|
||
} else {
|
||
this.sendProductVisible = true
|
||
}
|
||
},
|
||
closePublishDemand() {
|
||
this.publishDemandVisible = false
|
||
this.resetDemandForm()
|
||
},
|
||
resetDemandForm() {
|
||
this.demandForm = this.createDemandForm()
|
||
},
|
||
submitDemand() {
|
||
if (!this.demandForm.product_category || !this.demandForm.product_category.length) {
|
||
this.$message.warning('请选择所属类别')
|
||
return
|
||
}
|
||
if (!this.demandForm.title) {
|
||
this.$message.warning('请输入需求标题')
|
||
return
|
||
}
|
||
if (!this.demandForm.desc) {
|
||
this.$message.warning('请输入需求描述')
|
||
return
|
||
}
|
||
if (!this.demandForm.company) {
|
||
this.$message.warning('请输入企业名称')
|
||
return
|
||
}
|
||
|
||
const formData = new FormData()
|
||
formData.append('url_link', window.location.href)
|
||
formData.append('publish_type', '2')
|
||
formData.append('product_category', this.demandForm.product_category)
|
||
formData.append('product_name', this.demandForm.title)
|
||
formData.append('requirement_summary', this.demandForm.desc)
|
||
formData.append('company_name', this.demandForm.company)
|
||
formData.append('contact_person', this.demandForm.contact)
|
||
formData.append('phone_number', this.demandForm.phone)
|
||
formData.append('application_scenario', this.demandForm.scenario)
|
||
const submittedDemand = {
|
||
title: this.demandForm.title,
|
||
company: this.demandForm.company,
|
||
type: this.demandForm.type,
|
||
scenario: this.demandForm.scenario,
|
||
tags: [this.demandForm.type].filter(Boolean),
|
||
desc: this.demandForm.desc
|
||
}
|
||
|
||
reqPublishProductAdd(formData).then(res => {
|
||
if (res.status) {
|
||
this.plazaDemandData.unshift(submittedDemand)
|
||
this.currentPlazaTab = '全部'
|
||
this.publishDemandVisible = false
|
||
this.resetDemandForm()
|
||
this.$message.success(res.msg || '需求发布成功!')
|
||
} else {
|
||
this.$message.error(res.msg || '需求发布失败')
|
||
}
|
||
}).catch(() => {
|
||
this.$message.error('需求发布失败,请稍后重试')
|
||
})
|
||
},
|
||
handleDemandCategoryChange(value) {
|
||
const lastValue = Array.isArray(value) ? value[value.length - 1] : value
|
||
const node = this.findCategoryNode(this.demandCategoryOptions, lastValue)
|
||
this.demandForm.type = node ? node.label : ''
|
||
},
|
||
findCategoryNode(options, value) {
|
||
for (const item of options || []) {
|
||
if (item.value === value) return item
|
||
const child = this.findCategoryNode(item.children || [], value)
|
||
if (child) return child
|
||
}
|
||
return null
|
||
},
|
||
sendProductSuccess() {
|
||
this.sendProductVisible = false
|
||
this.initData()
|
||
},
|
||
goInfo() {
|
||
this.showTip = false
|
||
this.$router.push('/customer/approve')
|
||
},
|
||
scrollToList() {
|
||
const target = document.getElementById('demand-list')
|
||
if (target) target.scrollIntoView({ behavior: 'smooth' })
|
||
},
|
||
handleSearch() {
|
||
this.current_page = 1
|
||
},
|
||
switchPlazaTab(tab) {
|
||
this.currentPlazaTab = tab
|
||
},
|
||
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) {
|
||
this.companies = (res.data || []).map(item => ({
|
||
label: item.company_category,
|
||
value: item.company_category
|
||
}))
|
||
}
|
||
return res
|
||
})
|
||
},
|
||
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 : []
|
||
this.activeFirstId = ''
|
||
this.activeSecondId = ''
|
||
this.selectedCategory = ''
|
||
this.secondCategories = []
|
||
}
|
||
return res
|
||
})
|
||
},
|
||
loadSecondCategories(firstId) {
|
||
if (!firstId) {
|
||
this.secondCategories = []
|
||
return Promise.resolve()
|
||
}
|
||
return reqSupplyAndDemandFirstCategory({ to_page: 'show', url_link: window.location.href, first_level_id: firstId }).then(res => {
|
||
this.secondCategories = res.status && Array.isArray(res.data) ? res.data : []
|
||
return res
|
||
})
|
||
},
|
||
selectFirstCategory(id) {
|
||
if (id === this.activeFirstId) return
|
||
this.current_page = 1
|
||
this.activeFirstId = id
|
||
this.activeSecondId = ''
|
||
this.selectedCategory = id || ''
|
||
this.loadSecondCategories(id).then(() => {
|
||
this.initData()
|
||
})
|
||
},
|
||
selectSecondCategory(id) {
|
||
if (id === this.activeSecondId) return
|
||
this.current_page = 1
|
||
this.activeSecondId = id
|
||
this.selectedCategory = id || this.activeFirstId || ''
|
||
this.initData()
|
||
},
|
||
changePublishType(type) {
|
||
if (this.publish_type === type) return
|
||
this.publish_type = type
|
||
this.current_page = 1
|
||
this.initData()
|
||
},
|
||
initData() {
|
||
const payload = {
|
||
product_category: this.selectedCategory,
|
||
to_page: 'square',
|
||
url_link: window.location.href,
|
||
page_size: this.page_size,
|
||
current_page: this.current_page,
|
||
company_type: this.selectedCompanies.length > 0 ? this.selectedCompanies.join(',') : '',
|
||
publish_type: this.publish_type
|
||
}
|
||
reqGetSupplyAndDemandSquareList(payload).then(res => {
|
||
if (res.status) {
|
||
const data = Array.isArray(res.data) ? res.data : []
|
||
const first = data[0] || {}
|
||
this.productList = first.product_list || []
|
||
this.total = Number(first.total_count || 0)
|
||
}
|
||
})
|
||
},
|
||
selectCompany(companyId) {
|
||
const index = this.selectedCompanies.indexOf(companyId)
|
||
if (index > -1) {
|
||
this.selectedCompanies.splice(index, 1)
|
||
} else {
|
||
this.selectedCompanies.push(companyId)
|
||
}
|
||
this.initData()
|
||
},
|
||
openDetail(item) {
|
||
this.$set(this.loadingStates, item.id, true)
|
||
reqGetProductDetail({
|
||
id: item.productid ? item.productid : item.id,
|
||
from: 'f'
|
||
}).then(res => {
|
||
if (res.status) {
|
||
this.$store.commit('SETPRODUCTDETAIL', res.data)
|
||
this.$store.commit('SHOWPRODUCTDETAIL', true)
|
||
} else {
|
||
this.$message.error(res.msg)
|
||
}
|
||
}).finally(() => {
|
||
this.$set(this.loadingStates, item.id, false)
|
||
})
|
||
},
|
||
getCategoryName(category) {
|
||
return category.product_category || category.label || category.name || '未分类'
|
||
},
|
||
getTabColor(category) {
|
||
const name = this.getCategoryName(category)
|
||
if (name.includes('模型')) return 'orange'
|
||
if (name.includes('智能体')) return 'purple'
|
||
if (name.includes('方案') || name.includes('解决')) return 'green'
|
||
return 'blue'
|
||
},
|
||
getItemType(item) {
|
||
return item.type || item.company_type || item.product_category || (this.publish_type === '1' ? '企业商品' : '企业需求')
|
||
},
|
||
getTypeStyle(item) {
|
||
const type = this.getItemType(item)
|
||
const colors = type.includes('模型')
|
||
? { bg: 'rgba(245,158,11,0.08)', text: '#d97706', border: 'rgba(245,158,11,0.15)' }
|
||
: type.includes('智能体')
|
||
? { bg: 'rgba(139,92,246,0.08)', text: '#7c3aed', border: 'rgba(139,92,246,0.15)' }
|
||
: type.includes('方案') || type.includes('解决')
|
||
? { bg: 'rgba(16,185,129,0.08)', text: '#059669', border: 'rgba(16,185,129,0.15)' }
|
||
: { bg: 'rgba(45,91,255,0.08)', text: '#2d5bff', border: 'rgba(45,91,255,0.15)' }
|
||
return {
|
||
background: colors.bg,
|
||
color: colors.text,
|
||
borderColor: colors.border
|
||
}
|
||
},
|
||
getItemTags(item) {
|
||
if (Array.isArray(item.tags)) return item.tags
|
||
const tags = [
|
||
item.company_type,
|
||
item.product_category,
|
||
item.unit,
|
||
item.short_term === '1' ? '可短租' : ''
|
||
].filter(Boolean)
|
||
return Array.from(new Set(tags)).slice(0, 3)
|
||
},
|
||
getPriceText(item) {
|
||
if (!item.discount_price && item.discount_price !== 0) return '面议'
|
||
return `¥${item.discount_price}${item.unit ? ` / ${item.unit}` : ''}`
|
||
},
|
||
getParticleStyle(index) {
|
||
const size = 2 + (index % 4)
|
||
return {
|
||
width: `${size}px`,
|
||
height: `${size}px`,
|
||
left: `${(index * 23) % 100}%`,
|
||
top: `${(index * 37) % 100}%`,
|
||
animationDelay: `${(index % 8) * 0.4}s`,
|
||
animationDuration: `${6 + (index % 5)}s`
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.plaza-page {
|
||
position: relative;
|
||
min-height: 100vh;
|
||
overflow-x: hidden;
|
||
background: linear-gradient(180deg, #f0f7ff 0%, #ffffff 60%, #f5f8ff 100%);
|
||
color: #1a1a1a;
|
||
font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||
}
|
||
|
||
.floating-orb {
|
||
position: fixed;
|
||
z-index: 0;
|
||
border-radius: 50%;
|
||
filter: blur(80px);
|
||
opacity: 0.08;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.orb-1 {
|
||
top: -100px;
|
||
left: -100px;
|
||
width: 400px;
|
||
height: 400px;
|
||
background: #3b82f6;
|
||
animation: float1 20s ease-in-out infinite;
|
||
}
|
||
|
||
.orb-2 {
|
||
right: -150px;
|
||
bottom: -150px;
|
||
width: 500px;
|
||
height: 500px;
|
||
background: #3b82f6;
|
||
animation: float2 25s ease-in-out infinite;
|
||
}
|
||
|
||
.orb-3 {
|
||
top: 50%;
|
||
left: 50%;
|
||
width: 300px;
|
||
height: 300px;
|
||
background: #ec4899;
|
||
animation: float3 18s ease-in-out infinite;
|
||
}
|
||
|
||
.orb-4 {
|
||
right: 20%;
|
||
bottom: 30%;
|
||
width: 350px;
|
||
height: 350px;
|
||
background: #f59e0b;
|
||
animation: float1 22s ease-in-out infinite reverse;
|
||
}
|
||
|
||
.hero-section {
|
||
position: relative;
|
||
z-index: 1;
|
||
overflow: hidden;
|
||
padding: 96px 24px 64px;
|
||
}
|
||
|
||
.hero-glow {
|
||
position: absolute;
|
||
border-radius: 999px;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.glow-blue {
|
||
top: 80px;
|
||
left: 80px;
|
||
width: 384px;
|
||
height: 384px;
|
||
background: rgba(59, 130, 246, 0.2);
|
||
filter: blur(120px);
|
||
}
|
||
|
||
.glow-cyan {
|
||
right: 80px;
|
||
bottom: 80px;
|
||
width: 500px;
|
||
height: 500px;
|
||
background: rgba(59, 130, 246, 0.2);
|
||
filter: blur(150px);
|
||
}
|
||
|
||
.glow-warm {
|
||
top: 50%;
|
||
left: 50%;
|
||
width: 600px;
|
||
height: 600px;
|
||
background: rgba(245, 158, 11, 0.1);
|
||
filter: blur(180px);
|
||
transform: translate(-50%, -50%);
|
||
}
|
||
|
||
.particle-layer {
|
||
position: absolute;
|
||
inset: 0;
|
||
overflow: hidden;
|
||
pointer-events: none;
|
||
|
||
span {
|
||
position: absolute;
|
||
border-radius: 50%;
|
||
background: rgba(45, 91, 255, 0.08);
|
||
animation: particleFloat 8s linear infinite;
|
||
}
|
||
}
|
||
|
||
.hero-inner {
|
||
position: relative;
|
||
z-index: 2;
|
||
max-width: 960px;
|
||
margin: 0 auto;
|
||
text-align: center;
|
||
|
||
h1 {
|
||
margin: 0 0 24px;
|
||
color: #111827;
|
||
font-size: 72px;
|
||
font-weight: 800;
|
||
line-height: 1;
|
||
|
||
span {
|
||
background: linear-gradient(135deg, #2d5bff 0%, #3b82f6 100%);
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
}
|
||
}
|
||
|
||
p {
|
||
max-width: 780px;
|
||
margin: 0 auto;
|
||
color: #6b7280;
|
||
font-size: 20px;
|
||
line-height: 1.8;
|
||
}
|
||
}
|
||
|
||
.hero-actions,
|
||
.cta-content > div {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 16px;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-top: 40px;
|
||
}
|
||
|
||
.primary-btn,
|
||
.secondary-btn {
|
||
display: inline-flex;
|
||
gap: 8px;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 14px 32px;
|
||
border: 0;
|
||
border-radius: 12px;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.primary-btn {
|
||
position: relative;
|
||
overflow: hidden;
|
||
color: #fff;
|
||
background: linear-gradient(90deg, #2563eb, #1d4ed8);
|
||
box-shadow: 0 10px 20px rgba(59, 130, 246, 0.2);
|
||
|
||
&:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 12px 28px rgba(45, 91, 255, 0.3);
|
||
}
|
||
}
|
||
|
||
.secondary-btn {
|
||
color: #374151;
|
||
background: #fff;
|
||
border: 1px solid #e5e7eb;
|
||
|
||
&:hover {
|
||
color: #2563eb;
|
||
background: #eff6ff;
|
||
border-color: #93c5fd;
|
||
transform: translateY(-2px);
|
||
}
|
||
}
|
||
|
||
.process-section,
|
||
.list-section,
|
||
.cta-section {
|
||
position: relative;
|
||
z-index: 1;
|
||
max-width: 1280px;
|
||
margin: 0 auto;
|
||
padding: 0 24px 80px;
|
||
}
|
||
|
||
.section-subtitle {
|
||
margin: 0 0 48px;
|
||
color: #6b7280;
|
||
font-size: 18px;
|
||
text-align: center;
|
||
}
|
||
|
||
.step-list {
|
||
display: flex;
|
||
align-items: stretch;
|
||
justify-content: center;
|
||
}
|
||
|
||
.step-wrap {
|
||
display: flex;
|
||
flex: 1;
|
||
align-items: center;
|
||
}
|
||
|
||
.step-card {
|
||
flex: 1;
|
||
min-height: 178px;
|
||
padding: 24px;
|
||
text-align: center;
|
||
border: 1px solid rgba(59, 130, 246, 0.12);
|
||
border-radius: 16px;
|
||
background: linear-gradient(135deg, rgba(59, 130, 246, 0.08), rgba(147, 197, 253, 0.12));
|
||
box-shadow: 0 4px 20px rgba(59, 130, 246, 0.06);
|
||
transition: all 0.3s ease;
|
||
|
||
&:hover {
|
||
border-color: rgba(59, 130, 246, 0.3);
|
||
box-shadow: 0 12px 32px rgba(59, 130, 246, 0.15);
|
||
transform: translateY(-6px);
|
||
}
|
||
|
||
&.cyan {
|
||
background: linear-gradient(135deg, rgba(6, 182, 212, 0.08), rgba(103, 232, 249, 0.12));
|
||
}
|
||
|
||
&.green {
|
||
background: linear-gradient(135deg, rgba(16, 185, 129, 0.08), rgba(110, 231, 183, 0.12));
|
||
}
|
||
|
||
&.teal {
|
||
background: linear-gradient(135deg, rgba(20, 184, 166, 0.08), rgba(94, 234, 212, 0.12));
|
||
}
|
||
|
||
h4 {
|
||
margin: 0 0 8px;
|
||
color: #111827;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
p {
|
||
margin: 0;
|
||
color: #6b7280;
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
|
||
.step-icon {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 56px;
|
||
height: 56px;
|
||
margin: 0 auto 16px;
|
||
color: #3b82f6;
|
||
font-size: 28px;
|
||
border: 1px solid rgba(59, 130, 246, 0.3);
|
||
border-radius: 16px;
|
||
background: rgba(59, 130, 246, 0.1);
|
||
}
|
||
|
||
.step-arrow {
|
||
flex: 0 0 40px;
|
||
color: #60a5fa;
|
||
font-size: 24px;
|
||
text-align: center;
|
||
}
|
||
|
||
.section-head {
|
||
margin-bottom: 40px;
|
||
text-align: center;
|
||
|
||
h2 {
|
||
margin: 0 0 16px;
|
||
color: #111827;
|
||
font-size: 40px;
|
||
font-weight: 700;
|
||
|
||
span {
|
||
background: linear-gradient(135deg, #2d5bff 0%, #3b82f6 100%);
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
}
|
||
}
|
||
|
||
p {
|
||
margin: 0;
|
||
color: #6b7280;
|
||
font-size: 18px;
|
||
}
|
||
}
|
||
|
||
.toolbar {
|
||
display: flex;
|
||
justify-content: center;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.search-box {
|
||
display: flex;
|
||
gap: 12px;
|
||
align-items: center;
|
||
width: 100%;
|
||
max-width: 672px;
|
||
padding: 12px 20px;
|
||
border: 1px solid rgba(0, 0, 0, 0.06);
|
||
border-radius: 16px;
|
||
background: rgba(255, 255, 255, 0.85);
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
|
||
backdrop-filter: blur(20px);
|
||
|
||
i {
|
||
color: #64748b;
|
||
font-size: 18px;
|
||
}
|
||
|
||
input {
|
||
flex: 1;
|
||
color: #333;
|
||
font-size: 14px;
|
||
background: transparent;
|
||
border: none;
|
||
outline: none;
|
||
|
||
&::placeholder {
|
||
color: #94a3b8;
|
||
}
|
||
}
|
||
}
|
||
|
||
.tab-row,
|
||
.sub-tab-row,
|
||
.publish-type-row {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 12px;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.tab-btn,
|
||
.sub-tab-btn,
|
||
.publish-type-row button {
|
||
padding: 8px 20px;
|
||
color: #64748b;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||
border-radius: 999px;
|
||
background: rgba(255, 255, 255, 0.8);
|
||
transition: all 0.2s ease;
|
||
|
||
&:hover {
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
&.active {
|
||
color: #fff;
|
||
background: #2d5bff;
|
||
border-color: #2d5bff;
|
||
box-shadow: 0 2px 8px rgba(45, 91, 255, 0.25);
|
||
}
|
||
}
|
||
|
||
.tab-btn.active[data-color='orange'] {
|
||
background: #f59e0b;
|
||
border-color: #f59e0b;
|
||
}
|
||
|
||
.tab-btn.active[data-color='purple'] {
|
||
background: #8b5cf6;
|
||
border-color: #8b5cf6;
|
||
}
|
||
|
||
.tab-btn.active[data-color='green'] {
|
||
background: #10b981;
|
||
border-color: #10b981;
|
||
}
|
||
|
||
.interface-product-block.is-hidden {
|
||
display: none;
|
||
}
|
||
|
||
.sub-tab-row {
|
||
margin-top: -8px;
|
||
}
|
||
|
||
.sub-tab-btn {
|
||
padding: 6px 16px;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.publish-type-row {
|
||
margin-top: -8px;
|
||
|
||
button.active {
|
||
background: #111827;
|
||
border-color: #111827;
|
||
}
|
||
}
|
||
|
||
.card-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
gap: 20px;
|
||
}
|
||
|
||
.demand-card {
|
||
padding: 24px;
|
||
cursor: pointer;
|
||
background: rgba(255, 255, 255, 0.85);
|
||
border: 1px solid rgba(0, 0, 0, 0.06);
|
||
border-radius: 16px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
|
||
transition: all 0.3s ease;
|
||
|
||
&:hover {
|
||
border-color: rgba(45, 91, 255, 0.15);
|
||
box-shadow: 0 8px 24px rgba(45, 91, 255, 0.08);
|
||
transform: translateY(-3px);
|
||
}
|
||
|
||
h4 {
|
||
margin: 0 0 8px;
|
||
color: #1a1a1a;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
p {
|
||
display: -webkit-box;
|
||
min-height: 66px;
|
||
margin: 0 0 12px;
|
||
overflow: hidden;
|
||
color: #666;
|
||
font-size: 14px;
|
||
line-height: 1.6;
|
||
text-overflow: ellipsis;
|
||
word-break: break-all;
|
||
-webkit-box-orient: vertical;
|
||
-webkit-line-clamp: 3;
|
||
line-clamp: 3;
|
||
}
|
||
}
|
||
|
||
.card-top,
|
||
.card-foot,
|
||
.meta-line {
|
||
display: flex;
|
||
gap: 10px;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.card-top {
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.type-tag,
|
||
.favorite-tag,
|
||
.tag-list span {
|
||
display: inline-block;
|
||
padding: 3px 10px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
border: 1px solid;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.favorite-tag {
|
||
color: #059669;
|
||
background: rgba(16, 185, 129, 0.08);
|
||
border-color: rgba(16, 185, 129, 0.15);
|
||
}
|
||
|
||
.meta-line {
|
||
justify-content: flex-start;
|
||
margin-bottom: 12px;
|
||
color: #6b7280;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.tag-list {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 6px;
|
||
min-height: 26px;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.card-foot {
|
||
.price {
|
||
color: #ef4444;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
button {
|
||
display: inline-flex;
|
||
gap: 4px;
|
||
align-items: center;
|
||
padding: 0;
|
||
color: #2d5bff;
|
||
font-size: 13px;
|
||
background: transparent;
|
||
border: none;
|
||
}
|
||
}
|
||
|
||
.static-card-foot {
|
||
justify-content: flex-end;
|
||
}
|
||
|
||
.empty-box {
|
||
display: flex;
|
||
min-height: 360px;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: #7a82a0;
|
||
font-size: 16px;
|
||
|
||
img {
|
||
width: 150px;
|
||
height: 150px;
|
||
margin-bottom: 12px;
|
||
}
|
||
}
|
||
|
||
.plaza-pagination {
|
||
display: flex;
|
||
justify-content: center;
|
||
margin-top: 32px;
|
||
}
|
||
|
||
.cta-card {
|
||
position: relative;
|
||
max-width: 1000px;
|
||
padding: 56px;
|
||
margin: 0 auto;
|
||
overflow: hidden;
|
||
text-align: center;
|
||
background: rgba(255, 255, 255, 0.85);
|
||
border: 1px solid rgba(0, 0, 0, 0.06);
|
||
border-radius: 24px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
|
||
backdrop-filter: blur(20px);
|
||
|
||
&::before,
|
||
&::after {
|
||
position: absolute;
|
||
width: 100%;
|
||
height: 2px;
|
||
content: '';
|
||
background: linear-gradient(90deg, transparent, #2d5bff, transparent);
|
||
animation: borderMove 3s linear infinite;
|
||
}
|
||
|
||
&::before {
|
||
top: 0;
|
||
left: -100%;
|
||
}
|
||
|
||
&::after {
|
||
right: -100%;
|
||
bottom: 0;
|
||
animation-direction: reverse;
|
||
}
|
||
}
|
||
|
||
.cta-bg {
|
||
position: absolute;
|
||
inset: 0;
|
||
background: linear-gradient(135deg, rgba(37, 99, 235, 0.1), transparent, rgba(8, 145, 178, 0.1));
|
||
}
|
||
|
||
.cta-content {
|
||
position: relative;
|
||
z-index: 1;
|
||
|
||
h2 {
|
||
margin: 0 0 16px;
|
||
color: #111827;
|
||
font-size: 36px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
p {
|
||
max-width: 576px;
|
||
margin: 0 auto 32px;
|
||
color: #6b7280;
|
||
font-size: 18px;
|
||
}
|
||
}
|
||
|
||
.tip-text {
|
||
margin-right: 10px;
|
||
}
|
||
|
||
::v-deep .publish-dialog {
|
||
overflow: hidden;
|
||
background: linear-gradient(135deg, #ffffff, #f8faff);
|
||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||
border-radius: 20px;
|
||
box-shadow: 0 24px 80px rgba(15, 23, 42, 0.24);
|
||
|
||
.el-dialog__header {
|
||
padding: 24px;
|
||
border-bottom: 1px solid #f3f4f6;
|
||
}
|
||
|
||
.el-dialog__title {
|
||
color: #111827;
|
||
font-size: 20px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.el-dialog__headerbtn {
|
||
top: 24px;
|
||
right: 24px;
|
||
width: 32px;
|
||
height: 32px;
|
||
background: #f3f4f6;
|
||
border-radius: 8px;
|
||
transition: all 0.2s ease;
|
||
|
||
&:hover {
|
||
background: #e5e7eb;
|
||
}
|
||
}
|
||
|
||
.el-dialog__body {
|
||
max-height: 72vh;
|
||
padding: 24px;
|
||
overflow-y: auto;
|
||
}
|
||
}
|
||
|
||
.modal-overlay {
|
||
position: fixed;
|
||
inset: 0;
|
||
z-index: 1000;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
visibility: hidden;
|
||
background: rgba(0, 0, 0, 0.7);
|
||
opacity: 0;
|
||
backdrop-filter: blur(8px);
|
||
transition: all 0.3s ease;
|
||
|
||
&.active {
|
||
visibility: visible;
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
.modal-content {
|
||
width: 90%;
|
||
max-width: 600px;
|
||
max-height: 85vh;
|
||
overflow-y: auto;
|
||
background: linear-gradient(135deg, #ffffff, #f8faff);
|
||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||
border-radius: 20px;
|
||
box-shadow: 0 24px 80px rgba(15, 23, 42, 0.24);
|
||
}
|
||
|
||
.modal-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 24px;
|
||
border-bottom: 1px solid #f3f4f6;
|
||
|
||
h3 {
|
||
margin: 0;
|
||
color: #111827;
|
||
font-size: 20px;
|
||
font-weight: 700;
|
||
}
|
||
}
|
||
|
||
.modal-close {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 32px;
|
||
height: 32px;
|
||
color: #9ca3af;
|
||
background: #f3f4f6;
|
||
border: none;
|
||
border-radius: 8px;
|
||
transition: all 0.2s ease;
|
||
|
||
&:hover {
|
||
color: #4b5563;
|
||
background: #e5e7eb;
|
||
}
|
||
}
|
||
|
||
.modal-body {
|
||
padding: 24px;
|
||
}
|
||
|
||
.form-item {
|
||
margin-bottom: 20px;
|
||
|
||
label {
|
||
display: block;
|
||
margin-bottom: 8px;
|
||
color: #4b5563;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
|
||
span {
|
||
color: #ef4444;
|
||
}
|
||
}
|
||
}
|
||
|
||
.form-input,
|
||
.form-select {
|
||
width: 100%;
|
||
padding: 10px 14px;
|
||
color: #333;
|
||
font-size: 14px;
|
||
background: #f5f7fa;
|
||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||
border-radius: 10px;
|
||
outline: none;
|
||
transition: border-color 0.2s ease;
|
||
|
||
&:focus {
|
||
border-color: rgba(45, 91, 255, 0.4);
|
||
}
|
||
|
||
&::placeholder {
|
||
color: #999;
|
||
}
|
||
}
|
||
|
||
.form-select {
|
||
appearance: none;
|
||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='%23666' viewBox='0 0 16 16'%3E%3Cpath d='M8 11L3 6h10l-5 5z'/%3E%3C/svg%3E");
|
||
background-repeat: no-repeat;
|
||
background-position: right 12px center;
|
||
}
|
||
|
||
.demand-category-cascader {
|
||
width: 100%;
|
||
|
||
::v-deep .el-input__inner {
|
||
height: 42px;
|
||
color: #333;
|
||
background: #f5f7fa;
|
||
border-color: rgba(0, 0, 0, 0.1);
|
||
border-radius: 10px;
|
||
|
||
&:focus {
|
||
border-color: rgba(45, 91, 255, 0.4);
|
||
}
|
||
}
|
||
}
|
||
|
||
textarea.form-input {
|
||
min-height: 100px;
|
||
resize: vertical;
|
||
}
|
||
|
||
.modal-actions {
|
||
display: flex;
|
||
gap: 12px;
|
||
align-items: center;
|
||
}
|
||
|
||
.submit-demand-btn,
|
||
.cancel-demand-btn {
|
||
padding: 12px 24px;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
border: none;
|
||
border-radius: 12px;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.submit-demand-btn {
|
||
flex: 1;
|
||
color: #fff;
|
||
background: linear-gradient(90deg, #2563eb, #1d4ed8);
|
||
box-shadow: 0 10px 15px rgba(59, 130, 246, 0.2);
|
||
|
||
&:hover {
|
||
background: linear-gradient(90deg, #3b82f6, #2563eb);
|
||
}
|
||
}
|
||
|
||
.cancel-demand-btn {
|
||
color: #4b5563;
|
||
background: #f3f4f6;
|
||
border: 1px solid #e5e7eb;
|
||
|
||
&:hover {
|
||
background: #e5e7eb;
|
||
}
|
||
}
|
||
|
||
@keyframes float1 {
|
||
0%,
|
||
100% {
|
||
transform: translate(0, 0);
|
||
}
|
||
33% {
|
||
transform: translate(50px, -50px);
|
||
}
|
||
66% {
|
||
transform: translate(-30px, 30px);
|
||
}
|
||
}
|
||
|
||
@keyframes float2 {
|
||
0%,
|
||
100% {
|
||
transform: translate(0, 0);
|
||
}
|
||
33% {
|
||
transform: translate(-40px, 40px);
|
||
}
|
||
66% {
|
||
transform: translate(60px, -30px);
|
||
}
|
||
}
|
||
|
||
@keyframes float3 {
|
||
0%,
|
||
100% {
|
||
transform: translate(-50%, -50%);
|
||
}
|
||
33% {
|
||
transform: translate(calc(-50% + 40px), calc(-50% - 40px));
|
||
}
|
||
66% {
|
||
transform: translate(calc(-50% - 30px), calc(-50% + 30px));
|
||
}
|
||
}
|
||
|
||
@keyframes particleFloat {
|
||
0% {
|
||
opacity: 0;
|
||
transform: translateY(0) scale(0);
|
||
}
|
||
10% {
|
||
opacity: 1;
|
||
transform: translateY(-20px) scale(1);
|
||
}
|
||
90% {
|
||
opacity: 1;
|
||
transform: translateY(-200px) scale(1);
|
||
}
|
||
100% {
|
||
opacity: 0;
|
||
transform: translateY(-240px) scale(0.5);
|
||
}
|
||
}
|
||
|
||
@keyframes borderMove {
|
||
0% {
|
||
left: -100%;
|
||
}
|
||
100% {
|
||
left: 100%;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 1024px) {
|
||
.card-grid {
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
}
|
||
|
||
.step-list {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 16px;
|
||
}
|
||
|
||
.step-wrap {
|
||
display: block;
|
||
}
|
||
|
||
.step-arrow {
|
||
display: none;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.hero-inner h1 {
|
||
font-size: 48px;
|
||
}
|
||
|
||
.hero-inner p {
|
||
font-size: 16px;
|
||
}
|
||
|
||
.process-section,
|
||
.list-section,
|
||
.cta-section {
|
||
padding-right: 16px;
|
||
padding-left: 16px;
|
||
}
|
||
|
||
.card-grid,
|
||
.step-list {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.cta-card {
|
||
padding: 36px 20px;
|
||
}
|
||
}
|
||
</style>
|