1137 lines
25 KiB
Vue
1137 lines
25 KiB
Vue
<template>
|
||
<div class="fwsc-container">
|
||
<!-- 面包屑导航 -->
|
||
<!-- <BreadcrumbNav currentPage="碳服务市场" /> -->
|
||
|
||
<!-- 二级菜单 -->
|
||
<div class="secondary-nav">
|
||
<div class="secondary-nav-content">
|
||
<div class="nav-tabs">
|
||
<button v-for="tab in navTabs" :key="tab.path" :class="['nav-tab', { active: isActiveTab(tab.path) }]"
|
||
@click="goToTab(tab)">
|
||
{{ tab.label }}
|
||
</button>
|
||
</div>
|
||
<div class="nav-right">
|
||
<span class="list-count">共 {{ page.total }} 条服务</span>
|
||
<button class="publish-btn" @click="handlePublish">免费发布服务</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<main class="fwsc-main">
|
||
<div class="content-area">
|
||
<!-- 左侧服务卡片列表 -->
|
||
<div class="card-list">
|
||
<div class="service-grid">
|
||
<div v-for="(card, index) in cardList" :key="card.gxUuid" :data-gx-uuid="card.gxUuid" class="service-card">
|
||
<!-- 卡片头部 -->
|
||
<div class="card-header">
|
||
<div class="card-title-box">
|
||
<div class="card-title-text">
|
||
<div class="card-title-row">
|
||
<div class="card-title-main">{{ card.bt1 }}</div>
|
||
<!-- 收藏按钮 -->
|
||
<div class="card-collect" @click="handleCollect(card)">
|
||
<img v-if="card.scbz === 'Y'" src="../../assets/fwsc/ysc.svg" />
|
||
<img v-else src="../../assets/fwsc/wsc.svg" />
|
||
</div>
|
||
</div>
|
||
<div class="card-title-sub">
|
||
<div class="card-company">
|
||
<img src="../../assets/fwsc/city.svg" />
|
||
<span class="company-name">{{ card.qymc }}</span>
|
||
</div>
|
||
<div class="location" v-if="card.fwfw">
|
||
<img src="../../assets/fwsc/map.svg" />
|
||
<span class="company-name">{{ card.fwfw }}</span>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 卡片内容 -->
|
||
<div class="card-content">
|
||
<p class="card-desc">{{ card.fwnr }}</p>
|
||
<div class="card-tags">
|
||
<span v-for="(tag, i) in card.fwlxbqList" :key="i" class="tag">{{ tag }}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 卡片底部 -->
|
||
<div class="card-footer">
|
||
<div class="card-price-info">
|
||
<span class="price-value" v-if="card.gjjg">¥{{ card.gjjg }}</span>
|
||
<span class="price-value" v-else>面议</span>
|
||
<!-- <span class="price-unit" v-if="card.gjdwDm">/{{ card.gjdwDm }}</span> -->
|
||
</div>
|
||
<div class="card-actions">
|
||
<span @click="handleContact(card)">立即咨询</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 空状态 -->
|
||
<div v-if="cardList.length === 0 && !loading" class="empty-state">
|
||
<p>暂无服务信息</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 右侧筛选栏 -->
|
||
<aside class="filter-sidebar">
|
||
<div class="filter-toggle" @click="filterCollapsed = !filterCollapsed">
|
||
<span class="toggle-text">筛选</span>
|
||
<span class="toggle-icon">{{ filterCollapsed ? '▼' : '▲' }}</span>
|
||
</div>
|
||
<div :class="['filter-sidebar-content', { collapsed: filterCollapsed }]">
|
||
<!-- 内容搜索 -->
|
||
<div class="filter-section">
|
||
<div class="filter-title">内容搜索</div>
|
||
<t-input v-model="filter.nr" placeholder="请输入关键词" @enter="onSearch">
|
||
<template #suffix-icon>
|
||
<SearchIcon />
|
||
</template>
|
||
</t-input>
|
||
|
||
<!-- 只展示收藏项 -->
|
||
<div class="filter-section">
|
||
<t-checkbox v-model="filter.zzsscx" @change="() => onSearch()">只展示收藏项</t-checkbox>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- 服务类型 -->
|
||
<div class="filter-section">
|
||
<div class="filter-title">服务类型</div>
|
||
<div class="filter-options">
|
||
<t-checkbox-group v-model="filter.fwlxjh" :options="fwlxOptions" @change="onFwlxChange" />
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 服务企业 -->
|
||
<div class="filter-section">
|
||
<div class="filter-title">服务企业</div>
|
||
<t-input v-model="qySearchKeyword" placeholder="搜索企业名称" clearable class="qy-search-input"
|
||
@change="filterQyOptions">
|
||
<template #prefix-icon>
|
||
<SearchIcon />
|
||
</template>
|
||
</t-input>
|
||
<div class="filter-options enterprise-options" v-if="qyFilteredOptions.length > 0">
|
||
<t-checkbox-group v-model="filter.qyuuids" :options="qyFilteredOptions" @change="onSearch" />
|
||
</div>
|
||
<div class="Qy-options-empty" v-else>
|
||
<span>未找到匹配企业</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</aside>
|
||
</div>
|
||
|
||
<!-- 分页 -->
|
||
<div class="pagination-box" v-if="page.total > 0">
|
||
<div class="pagination-total">共 {{ page.total }} 条数据</div>
|
||
<t-pagination v-model="page.pageNo" :total="page.total" :page-size.sync="page.pageSize" :totalContent='false'
|
||
:page-size-options="[10, 20, 30, 50]" @change="onPageChange" align="center" />
|
||
</div>
|
||
</main>
|
||
|
||
<Footer />
|
||
|
||
<!-- 发布服务抽屉 -->
|
||
<FwscPublish :visible.sync="publishVisible" @success="onPublishSuccess" />
|
||
|
||
<!-- 联系服务弹窗 -->
|
||
<t-dialog :closeOnOverlayClick="false" header="联系服务" :visible.sync="contactVisible" @confirm="onContactConfirm"
|
||
:onClose="onContactClose" class="global-dialog" attach="body">
|
||
<div class="dialog-line">
|
||
<div class="dialog-line-title">联系人:</div>
|
||
<div class="dialog-line-text">{{ contactData.lxr }}</div>
|
||
</div>
|
||
<div class="dialog-line">
|
||
<div class="dialog-line-title">联系电话:</div>
|
||
<div class="dialog-line-text">{{ contactData.lxdh }}</div>
|
||
</div>
|
||
<div class="dialog-line">
|
||
<div class="dialog-line-title">电子邮箱:</div>
|
||
<div class="dialog-line-text">{{ contactData.email }}</div>
|
||
</div>
|
||
</t-dialog>
|
||
|
||
<!-- 提示弹窗 -->
|
||
<t-dialog :closeOnOverlayClick="false" header="提示" body="请先进行企业入驻" :visible.sync="rzVisible" @confirm="onRzConfirm"
|
||
:onClose="onRzClose" :cancelBtn="null" class="global-dialog" />
|
||
|
||
<!-- 发布成功弹窗 -->
|
||
<t-dialog :closeOnOverlayClick="false" body="发布申请成功,请等待审核,是否继续发布?" :visible.sync="publishSuccessVisible"
|
||
@confirm="onPublishSuccessConfirm" @cancel="onPublishSuccessCancel" :onClose="onPublishSuccessClose"
|
||
cancelBtn="返回" confirmBtn="继续发布" class="global-dialog" />
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { LocationIcon, SearchIcon } from 'tdesign-icons-vue';
|
||
import NewNav from '@/pages/index/components/new-nav/index.vue';
|
||
import Footer from '@/pages/index/components/footer/index.vue';
|
||
import BreadcrumbNav from '@/pages/index/components/breadcrumb/index.vue';
|
||
import FwscPublish from './components/FwscPublish.vue';
|
||
import api from '@/pages/index/api/fwsc/index.js';
|
||
|
||
export default {
|
||
name: 'FwscPage',
|
||
components: {
|
||
NewNav,
|
||
Footer,
|
||
BreadcrumbNav,
|
||
FwscPublish,
|
||
LocationIcon,
|
||
SearchIcon,
|
||
},
|
||
data() {
|
||
return {
|
||
navTabs: [
|
||
{ label: '碳服务市场', path: '/tfwsc' },
|
||
{ label: '碳需求市场', path: '/txqsc' },
|
||
{ label: '碳数据市场', path: '/tsjsc' },
|
||
{ label: '碳金融市场', path: '/tjrsc', disable: true },
|
||
],
|
||
// 筛选条件
|
||
filter: {
|
||
fwlxjh: [],
|
||
qyuuids: [],
|
||
nr: '',
|
||
zzsscx: false,
|
||
},
|
||
// 服务类型选项
|
||
fwlxOptions: [],
|
||
// 企业选项(根据服务类型动态过滤)
|
||
qyOptions: [],
|
||
// 全部企业列表
|
||
allQyOptions: [],
|
||
// 企业搜索关键词
|
||
qySearchKeyword: '',
|
||
// 过滤后的企业选项
|
||
qyFilteredOptions: [],
|
||
// 卡片列表
|
||
cardList: [],
|
||
// 分页
|
||
page: {
|
||
pageNo: 1,
|
||
pageSize: 10,
|
||
total: 0,
|
||
},
|
||
// 加载状态
|
||
loading: false,
|
||
// 用户信息
|
||
yhxx: {},
|
||
// 发布抽屉
|
||
publishVisible: false,
|
||
// 联系弹窗
|
||
contactVisible: false,
|
||
contactData: {},
|
||
// 入驻提示弹窗
|
||
rzVisible: false,
|
||
// 发布成功弹窗
|
||
publishSuccessVisible: false,
|
||
// 移动端筛选折叠状态
|
||
filterCollapsed: true,
|
||
};
|
||
},
|
||
mounted() {
|
||
this.initUser();
|
||
this.loadDmList();
|
||
this.searchList();
|
||
// 检查是否需要直接打开发布面板
|
||
if (this.$route.query.publish === '1') {
|
||
this.handlePublish();
|
||
}
|
||
},
|
||
methods: {
|
||
// 初始化用户信息
|
||
async initUser() {
|
||
try {
|
||
const { data } = await api.init();
|
||
this.yhxx = data || {};
|
||
window.sessionStorage.setItem('yhxx', JSON.stringify(data));
|
||
} catch (error) {
|
||
console.error('获取用户信息失败', error);
|
||
}
|
||
},
|
||
// 加载代码表
|
||
loadDmList() {
|
||
this.fwlxoptionsSearch();
|
||
this.hqqylist();
|
||
},
|
||
async fwlxoptionsSearch() {
|
||
try {
|
||
const res = await api.dms2mc('fwlx', {});
|
||
this.fwlxOptions = res.data || [];
|
||
} catch (error) {
|
||
this.fwlxOptions = [];
|
||
}
|
||
},
|
||
// 获取已入驻企业列表
|
||
async hqqylist() {
|
||
try {
|
||
const res = await api.getQyxxListByYwlx();
|
||
const options = [];
|
||
(res.data || []).map((item) => {
|
||
options.push({ value: item.qyuuid, label: item.qymc });
|
||
});
|
||
this.allQyOptions = options || [];
|
||
this.qyOptions = options || [];
|
||
this.qyFilteredOptions = options || [];
|
||
} catch (error) {
|
||
this.allQyOptions = [];
|
||
this.qyOptions = [];
|
||
this.qyFilteredOptions = [];
|
||
}
|
||
},
|
||
// 服务类型变化时,动态过滤企业
|
||
async onFwlxChange() {
|
||
this.qySearchKeyword = '';
|
||
if (this.filter.fwlxjh.length > 0) {
|
||
try {
|
||
const res = await api.getQyuuidsByBq({ fwlxjh: this.filter.fwlxjh });
|
||
const selectedCodes = res.data || [];
|
||
this.qyOptions = this.allQyOptions.filter((q) => selectedCodes.includes(q.value));
|
||
this.qyFilteredOptions = this.qyOptions;
|
||
} catch (error) {
|
||
this.qyOptions = this.allQyOptions;
|
||
this.qyFilteredOptions = this.allQyOptions;
|
||
}
|
||
} else {
|
||
this.qyOptions = this.allQyOptions;
|
||
this.qyFilteredOptions = this.allQyOptions;
|
||
}
|
||
this.onSearch();
|
||
},
|
||
// 过滤企业选项
|
||
filterQyOptions() {
|
||
console.log('this.qySearchKeyword', this.qySearchKeyword);
|
||
if (!this.qySearchKeyword) {
|
||
this.qyFilteredOptions = this.qyOptions;
|
||
} else {
|
||
const keyword = this.qySearchKeyword.toLowerCase();
|
||
this.qyFilteredOptions = this.qyOptions.filter((q) =>
|
||
q.label.toLowerCase().includes(keyword)
|
||
);
|
||
}
|
||
},
|
||
// 搜索列表
|
||
async searchList() {
|
||
this.loading = true;
|
||
this.cardList = [];
|
||
const targetId = this.$route.query.id || '';
|
||
try {
|
||
const prame = {
|
||
ywlxDm: '01',
|
||
...this.filter,
|
||
...this.page,
|
||
};
|
||
// 只展示收藏项:Y=是, N=否
|
||
prame.scbz = this.filter.zzsscx ? 'Y' : 'N';
|
||
// URL携带id:按id精确查询单条
|
||
if (targetId) {
|
||
prame.gxUuid = targetId;
|
||
}
|
||
const { data } = await api.gxxxList(prame);
|
||
if (data.records) {
|
||
data.records.map((item) => {
|
||
if (item.bqjh) {
|
||
item.bqjh = item.bqjh.split(',');
|
||
}
|
||
if (item.fwlxjh) {
|
||
item.fwlxbqList = item.fwlxjh.split(',');
|
||
} else {
|
||
item.fwlxbqList = [];
|
||
}
|
||
});
|
||
}
|
||
this.cardList = data.records || [];
|
||
this.page.total = Number(data.total || 0);
|
||
// 数据渲染后定位到对应项
|
||
if (targetId) {
|
||
this.scrollToItem(targetId);
|
||
}
|
||
} catch (error) {
|
||
this.cardList = [];
|
||
this.page.total = 0;
|
||
console.error('获取服务列表失败', error);
|
||
} finally {
|
||
this.loading = false;
|
||
}
|
||
},
|
||
// 重置筛选
|
||
onReset() {
|
||
this.filter = {
|
||
fwlxjh: [],
|
||
qyuuids: [],
|
||
nr: '',
|
||
zzsscx: false,
|
||
};
|
||
this.qySearchKeyword = '';
|
||
this.qyOptions = this.allQyOptions;
|
||
this.qyFilteredOptions = this.allQyOptions;
|
||
this.page.pageNo = 1;
|
||
this.searchList();
|
||
},
|
||
// 搜索
|
||
onSearch() {
|
||
this.page.pageNo = 1;
|
||
this.searchList();
|
||
},
|
||
// 滚动到指定项并高亮
|
||
scrollToItem(gxUuid) {
|
||
this.$nextTick(() => {
|
||
const targetCard = this.cardList.find(card => card.gxUuid === gxUuid);
|
||
if (targetCard) {
|
||
// 找到对应卡片并滚动到视图中心
|
||
const cardIndex = this.cardList.indexOf(targetCard);
|
||
const cardElement = document.querySelector(`[data-gx-uuid="${gxUuid}"]`);
|
||
if (cardElement) {
|
||
cardElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||
// 添加高亮效果
|
||
cardElement.classList.add('highlight-card');
|
||
setTimeout(() => {
|
||
cardElement.classList.remove('highlight-card');
|
||
}, 3000);
|
||
}
|
||
}
|
||
});
|
||
},
|
||
// 处理发布
|
||
handlePublish() {
|
||
const yhxx = window.sessionStorage.getItem('yhxx');
|
||
if (yhxx) {
|
||
const yhxxData = JSON.parse(yhxx);
|
||
if (yhxxData.gxdtRzbz === 'Y') {
|
||
this.publishVisible = true;
|
||
} else {
|
||
this.rzVisible = true;
|
||
}
|
||
} else {
|
||
this.rzVisible = true;
|
||
}
|
||
},
|
||
// 收藏/取消收藏
|
||
async handleCollect(card) {
|
||
try {
|
||
const type = card.scbz === 'Y' ? 'remove' : 'add';
|
||
await api.gxsc({ gxUuid: card.gxUuid, type });
|
||
card.scbz = card.scbz === 'Y' ? 'N' : 'Y';
|
||
} catch (error) {
|
||
console.error('收藏失败', error);
|
||
}
|
||
},
|
||
// 联系服务
|
||
handleContact(card) {
|
||
this.contactData = {
|
||
lxr: card.lxr || '',
|
||
lxdh: card.lxdh || '',
|
||
email: card.email || '',
|
||
};
|
||
this.contactVisible = true;
|
||
},
|
||
// 发布成功回调
|
||
onPublishSuccess() {
|
||
this.publishSuccessVisible = true;
|
||
},
|
||
// 导航相关
|
||
isActiveTab(path) {
|
||
return this.$route.path === path;
|
||
},
|
||
goToTab({path, disable}) {
|
||
if (disable) {
|
||
this.$message.info('敬请期待');
|
||
return
|
||
}
|
||
this.$router.push(path);
|
||
},
|
||
// 弹窗回调
|
||
onContactConfirm() {
|
||
this.contactVisible = false;
|
||
},
|
||
onContactClose() {
|
||
this.contactVisible = false;
|
||
},
|
||
onRzConfirm() {
|
||
this.rzVisible = false;
|
||
},
|
||
onRzClose() {
|
||
this.rzVisible = false;
|
||
},
|
||
onPublishSuccessConfirm() {
|
||
this.publishSuccessVisible = false;
|
||
this.publishVisible = true;
|
||
},
|
||
onPublishSuccessCancel() {
|
||
this.publishSuccessVisible = false;
|
||
this.$router.push('/tfwsc');
|
||
},
|
||
onPublishSuccessClose() {
|
||
this.publishSuccessVisible = false;
|
||
},
|
||
// 分页变化
|
||
onPageChange() {
|
||
this.searchList();
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
.fwsc-container {
|
||
min-height: 100vh;
|
||
background: #f5f5f5;
|
||
}
|
||
|
||
.fwsc-main {
|
||
width: 100%;
|
||
max-width: 1400px;
|
||
padding: 20px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
// 二级菜单
|
||
.secondary-nav {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.secondary-nav-content {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
max-width: 1400px;
|
||
padding: 20px 20px 0;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.nav-tabs {
|
||
display: flex;
|
||
gap: 40px;
|
||
width: 596px;
|
||
height: 42px;
|
||
}
|
||
|
||
.nav-right {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 20px;
|
||
}
|
||
|
||
.nav-tab {
|
||
position: relative;
|
||
min-width: max-content;
|
||
height: 42px;
|
||
padding: 8px 16px;
|
||
font-size: 18px;
|
||
font-weight: 500;
|
||
color: #003B1A;
|
||
cursor: pointer;
|
||
background: transparent;
|
||
border-radius: 32px;
|
||
transition: all 0.3s;
|
||
|
||
&:hover {
|
||
color: #009a29;
|
||
}
|
||
|
||
&.active {
|
||
background: #8CFFCE;
|
||
box-shadow: inset 0 0 0 1px #00B96B;
|
||
}
|
||
}
|
||
|
||
.publish-btn {
|
||
width: 220px;
|
||
height: 42px;
|
||
line-height: 26px;
|
||
padding: 8px 16px;
|
||
font-size: 18px;
|
||
font-weight: 400;
|
||
color: #fff;
|
||
cursor: pointer;
|
||
background: linear-gradient(135deg, #009a29 0%, #48C666 100%);
|
||
border: none;
|
||
border-radius: 6px;
|
||
box-shadow: 0 4px 12px rgba(0, 154, 41, 0.25);
|
||
transition: all 0.3s ease;
|
||
|
||
&:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 6px 16px rgba(0, 154, 41, 0.35);
|
||
}
|
||
|
||
&:active {
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
.content-area {
|
||
display: flex;
|
||
gap: 20px;
|
||
align-items: stretch;
|
||
}
|
||
|
||
// 左侧筛选栏
|
||
.filter-sidebar {
|
||
position: sticky;
|
||
top: 104px;
|
||
width: 220px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
// 移动端筛选栏折叠
|
||
.filter-toggle {
|
||
display: none;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.filter-toggle {
|
||
display: flex;
|
||
padding: 12px;
|
||
margin-bottom: 8px;
|
||
cursor: pointer;
|
||
background: #fff;
|
||
border-radius: 8px;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
|
||
.toggle-text {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
}
|
||
|
||
.toggle-icon {
|
||
font-size: 18px;
|
||
color: #666;
|
||
transition: transform 0.3s;
|
||
}
|
||
|
||
&.collapsed .toggle-icon {
|
||
transform: rotate(-90deg);
|
||
}
|
||
}
|
||
|
||
.filter-sidebar-content {
|
||
max-height: 1000px;
|
||
padding: 20px;
|
||
overflow: hidden;
|
||
transition: max-height 0.3s ease, padding 0.3s ease;
|
||
}
|
||
|
||
.filter-sidebar-content.collapsed {
|
||
max-height: 0;
|
||
padding-top: 0;
|
||
padding-bottom: 0;
|
||
}
|
||
}
|
||
|
||
.filter-sidebar-content {
|
||
padding: 20px;
|
||
background: #fff;
|
||
border-radius: 12px;
|
||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
.filter-section {
|
||
// padding-bottom: 20px;
|
||
margin-bottom: 20px;
|
||
border-bottom: 1px dashed #e0e0e0;
|
||
|
||
&:last-child {
|
||
padding: 10px 0;
|
||
margin-bottom: 0;
|
||
border-bottom: none;
|
||
}
|
||
}
|
||
|
||
.filter-title {
|
||
display: flex;
|
||
margin-bottom: 12px;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
align-items: center;
|
||
gap: 6px;
|
||
|
||
&::before {
|
||
width: 4px;
|
||
height: 14px;
|
||
background: linear-gradient(180deg, #009a29, #48C666);
|
||
border-radius: 2px;
|
||
content: '';
|
||
}
|
||
}
|
||
|
||
.filter-options {
|
||
/deep/.t-checkbox__label {
|
||
font-size: 14px;
|
||
color: #666;
|
||
}
|
||
|
||
&.enterprise-options {
|
||
max-height: 200px;
|
||
overflow-y: auto;
|
||
}
|
||
}
|
||
|
||
.qy-search-input {
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.Qy-options-empty {
|
||
padding: 16px 0;
|
||
font-size: 14px;
|
||
color: #999;
|
||
text-align: center;
|
||
}
|
||
|
||
|
||
// 右侧卡片列表
|
||
.card-list {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.list-count {
|
||
font-size: 14px;
|
||
font-weight: 400;
|
||
color: #6B8575;
|
||
}
|
||
|
||
.service-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 24px;
|
||
}
|
||
|
||
.service-card {
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
background: #fff;
|
||
border-radius: 12px;
|
||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||
transition: all 0.3s ease;
|
||
|
||
&.highlight-card {
|
||
animation: highlight-pulse 3s ease-out;
|
||
}
|
||
|
||
// &::before {
|
||
// position: absolute;
|
||
// top: 0;
|
||
// left: 0;
|
||
// width: 100%;
|
||
// height: 3px;
|
||
// background: linear-gradient(90deg, #009a29, #48C666);
|
||
// content: '';
|
||
// transform: scaleX(0);
|
||
// transform-origin: left;
|
||
// transition: transform 0.3s ease;
|
||
// }
|
||
|
||
// &:hover {
|
||
// transform: translateY(-4px);
|
||
// box-shadow: 0 8px 24px rgba(0, 154, 41, 0.15);
|
||
|
||
// &::before {
|
||
// transform: scaleX(1);
|
||
// }
|
||
// }
|
||
}
|
||
|
||
.card-header {
|
||
position: relative;
|
||
padding: 16px;
|
||
height: 70px;
|
||
|
||
&::after {
|
||
position: absolute;
|
||
right: 16px;
|
||
bottom: -6px;
|
||
left: 16px;
|
||
height: 1px;
|
||
background: #E8F0EC;
|
||
content: '';
|
||
}
|
||
}
|
||
|
||
.card-title-box {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.card-title-text {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.card-title-main {
|
||
flex: 1;
|
||
overflow: hidden;
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
line-height: 24px;
|
||
color: #003B1A;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.card-title-row {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.card-company {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.card-title-sub {
|
||
display: flex;
|
||
gap: 12px;
|
||
justify-content: space-between;
|
||
|
||
}
|
||
|
||
.company-name {
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
font-size: 14px;
|
||
color: #6B8575;
|
||
font-weight: 400;
|
||
}
|
||
|
||
.location {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.card-collect {
|
||
flex-shrink: 0;
|
||
margin-left: 8px;
|
||
cursor: pointer;
|
||
|
||
img {
|
||
width: 20px;
|
||
height: 20px;
|
||
}
|
||
}
|
||
|
||
.card-content {
|
||
padding: 16px;
|
||
}
|
||
|
||
.card-desc {
|
||
display: block;
|
||
height: 70px;
|
||
overflow: hidden;
|
||
font-size: 14px;
|
||
line-height: 1.6;
|
||
color: #666;
|
||
text-overflow: ellipsis;
|
||
-webkit-line-clamp: 3;
|
||
}
|
||
|
||
.card-tags {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
}
|
||
|
||
.tag {
|
||
padding: 2px 8px;
|
||
font-size: 13px;
|
||
font-weight: 400;
|
||
color: #00B96B;
|
||
background: #EEFAE2;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.card-footer {
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 14px 16px;
|
||
height: 64px;
|
||
|
||
&::before {
|
||
position: absolute;
|
||
top: 0;
|
||
right: 16px;
|
||
left: 16px;
|
||
height: 1px;
|
||
background: #E8F0EC;
|
||
content: '';
|
||
}
|
||
}
|
||
|
||
.card-price-info {
|
||
display: flex;
|
||
align-items: baseline;
|
||
}
|
||
|
||
.card-actions {
|
||
display: flex;
|
||
height: 32px;
|
||
padding: 6px 12px;
|
||
border-radius: 4px;
|
||
border: 1px solid #00b96b;
|
||
color: #00b96b;
|
||
font-size: 14px;
|
||
font-weight: 400;
|
||
|
||
&:hover {
|
||
background: rgba(0, 154, 41, 0.1);
|
||
cursor: pointer;
|
||
}
|
||
}
|
||
|
||
.price-value {
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
color: #FF4D4F;
|
||
}
|
||
|
||
.price-unit {
|
||
margin-left: 2px;
|
||
font-size: 14px;
|
||
color: #666;
|
||
}
|
||
|
||
// 空状态
|
||
.empty-state {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 100%;
|
||
min-height: 300px;
|
||
padding: 40px;
|
||
background: #fff;
|
||
border-radius: 12px;
|
||
animation: fadeIn 0.5s ease;
|
||
|
||
.empty-icon {
|
||
margin-bottom: 16px;
|
||
font-size: 48px;
|
||
color: #d0d0d0;
|
||
}
|
||
|
||
p {
|
||
font-size: 14px;
|
||
color: #999;
|
||
}
|
||
}
|
||
|
||
@keyframes fadeIn {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(10px);
|
||
}
|
||
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
// 分页
|
||
.pagination-total {
|
||
font-size: 16px;
|
||
color: #666;
|
||
}
|
||
|
||
.pagination-box {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding-top: 32px;
|
||
gap: 10px;
|
||
|
||
::v-deep .t-pagination {
|
||
display: flex !important;
|
||
justify-content: center;
|
||
flex-wrap: wrap;
|
||
width: initial;
|
||
|
||
.t-input.t-is-readonly {
|
||
width: 110px;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 弹窗样式
|
||
.dialog-line {
|
||
display: flex;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.dialog-line-title {
|
||
flex-shrink: 0;
|
||
width: 80px;
|
||
color: #333;
|
||
}
|
||
|
||
.dialog-line-text {
|
||
color: #666;
|
||
}
|
||
|
||
@media (max-width: 1200px) {
|
||
.service-card {
|
||
width: calc((100% - 20px) / 2);
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.fwsc-main {
|
||
padding: 12px;
|
||
}
|
||
|
||
.secondary-nav-content {
|
||
flex-direction: column;
|
||
padding: 12px 16px;
|
||
gap: 12px;
|
||
}
|
||
|
||
.nav-tabs {
|
||
width: 100%;
|
||
padding-bottom: 4px;
|
||
overflow-x: auto;
|
||
gap: 4px;
|
||
}
|
||
|
||
.nav-tab {
|
||
padding: 10px 12px;
|
||
font-size: 13px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.publish-btn {
|
||
width: 100%;
|
||
padding: 10px;
|
||
}
|
||
|
||
.content-area {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.filter-sidebar {
|
||
position: relative;
|
||
top: 0;
|
||
width: 100%;
|
||
}
|
||
|
||
.card-list {
|
||
width: 100%;
|
||
}
|
||
|
||
.list-header {
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.service-grid {
|
||
grid-template-columns: 1fr;
|
||
gap: 12px;
|
||
}
|
||
|
||
.service-card {
|
||
width: 100%;
|
||
}
|
||
|
||
.card-header {
|
||
padding: 12px;
|
||
}
|
||
|
||
.card-content {
|
||
padding: 12px;
|
||
}
|
||
|
||
.card-footer {
|
||
padding: 12px;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
}
|
||
|
||
.card-actions {
|
||
width: 100%
|
||
}
|
||
|
||
.pagination-box {
|
||
padding-top: 20px;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 480px) {
|
||
.fwsc-main {
|
||
padding: 8px;
|
||
}
|
||
|
||
.secondary-nav-content {
|
||
padding: 8px 12px;
|
||
}
|
||
|
||
.nav-tab {
|
||
padding: 8px 10px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.publish-btn {
|
||
padding: 8px;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.filter-sidebar-content {
|
||
padding: 12px;
|
||
}
|
||
|
||
.list-title-box .list-title {
|
||
font-size: 18px;
|
||
}
|
||
|
||
.card-title-main {
|
||
font-size: 14px;
|
||
}
|
||
|
||
.card-desc {
|
||
height: 60px;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.price-value {
|
||
font-size: 18px;
|
||
}
|
||
}
|
||
|
||
@keyframes highlight-pulse {
|
||
0% {
|
||
box-shadow: 0 0 0 0 rgba(0, 154, 41, 0.4);
|
||
}
|
||
|
||
50% {
|
||
box-shadow: 0 0 20px 10px rgba(0, 154, 41, 0.2);
|
||
}
|
||
|
||
100% {
|
||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||
}
|
||
}
|
||
</style>
|