feat: 调整接口

This commit is contained in:
liulujian 2026-04-03 23:03:58 +08:00
parent 4f2a8c4aac
commit b933da492c
13 changed files with 2060 additions and 524 deletions

View File

@ -0,0 +1,83 @@
import { fetchSso } from '@/core/request';
const basurl = '';
export default {
// 获取用户信息(含入驻状态 gxdtRzbz
init(params) {
return fetchSso({
url: `${basurl}/mhzc/user/init`,
method: 'post',
loading: true,
data: JSON.stringify(params),
});
},
// 企业入驻申请
register(params) {
return fetchSso({
url: `${basurl}/gxzx/qyrz/qyrzsq`,
method: 'post',
loading: true,
data: JSON.stringify(params),
});
},
// 获取供需信息列表ywlxDm: '01'=供给, '02'=需求)
gxxxList(params) {
return fetchSso({
url: `${basurl}/gxzx/gxdt/gxxxList`,
method: 'post',
loading: true,
data: JSON.stringify(params),
});
},
// 发布供需信息ywlxDm: '01'=供给, '02'=需求)
gxfb(params) {
return fetchSso({
url: `${basurl}/gxzx/gxdt/gxfb`,
method: 'post',
loading: true,
data: JSON.stringify(params),
});
},
// 收藏/取消收藏供需信息type: 'add'/'remove'
gxsc(params) {
return fetchSso({
url: `${basurl}/gxzx/gxdt/gxsc`,
method: 'post',
data: JSON.stringify(params),
});
},
// 代码表查询tableName: fwlx/xqlx/sshy/ysfw/XZQH/bq/dw
dms2mc(tableName, params) {
return fetchSso({
url: `${basurl}/yygl/cache/v1/list/${tableName}`,
method: 'post',
loading: true,
data: JSON.stringify(params),
});
},
// 获取已入驻企业列表
getQyxxListByYwlx() {
return fetchSso({
url: `${basurl}/mhzc/company/getQyxxListByYwlx?ywlx=gxdtrzbz`,
method: 'get',
loading: true,
});
},
// 根据标签获取企业 UUID 列表
getQyuuidsByBq(params) {
return fetchSso({
url: `${basurl}/gxzx/gxdt/getQyuuidsByBq`,
method: 'post',
loading: true,
data: JSON.stringify(params),
});
},
};

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="28px" height="28px" viewBox="0 0 28 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>未收藏</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="绿碳供需大厅-碳服务供给" transform="translate(-1622, -910)">
<g id="编组-13" transform="translate(225, 616)">
<g id="编组-8备份-5" transform="translate(985, 270)">
<g id="未收藏" transform="translate(412, 24)">
<rect id="close-circle-(Background)" opacity="0" x="0" y="0" width="28" height="28"></rect>
<g id="编组" transform="translate(4, 4)" fill="#060001" fill-rule="nonzero">
<path d="M15.5834977,20.1658413 C15.2303411,20.1658413 14.8711988,20.0820414 14.541985,19.908456 L10.6033909,17.8374019 C10.5255767,17.795502 10.4298054,17.795502 10.3519913,17.8374019 L6.41339716,19.908456 C5.65919829,20.3035125 4.75535678,20.2436555 4.06700067,19.7408562 C3.37265885,19.238057 3.03745935,18.4000582 3.18111628,17.5620595 L3.93531515,13.1745375 C3.95327227,13.0847519 3.92334374,12.9949663 3.85750098,12.9351092 L0.673105741,9.82852817 C0.0625637965,9.22995764 -0.152921596,8.35604466 0.110449439,7.54198873 C0.373820474,6.7279328 1.06217659,6.14731938 1.91214675,6.02760528 L6.31762588,5.38713481 C6.40741146,5.3751634 6.48522563,5.32129205 6.52113986,5.23749217 L8.49043692,1.24502671 C8.86753635,0.478856427 9.63370664,0 10.4896625,0 C11.3456184,0 12.1117886,0.478856427 12.4888881,1.24502671 L14.4581851,5.23749217 C14.5000851,5.31530634 14.5719135,5.3751634 14.6616991,5.38713481 L19.0671783,6.02760528 C19.9111627,6.15330509 20.6055045,6.73391851 20.8688756,7.54198873 C21.1322466,8.35604466 20.9167612,9.22995764 20.3062193,9.82852817 L17.1038669,12.9351092 C17.0380241,12.9949663 17.0080956,13.0847519 17.0260527,13.1745375 L17.7802516,17.5620595 C17.9239085,18.4060439 17.5827233,19.238057 16.8943672,19.7408562 C16.4993107,20.0221844 16.0443971,20.1658413 15.5834977,20.1658413 Z M10.4776911,1.44255499 C10.1664344,1.44255499 9.90306338,1.61015474 9.76539215,1.88549718 L7.7960951,5.87796264 C7.54469547,6.38076189 7.06583905,6.73391851 6.50916845,6.81173268 L2.10368932,7.45220315 C1.79841835,7.49410309 1.55899013,7.69761707 1.46321885,7.99091663 C1.36744756,8.28421619 1.44526173,8.58948716 1.66673283,8.80497256 L4.85112807,11.9115536 C5.25217033,12.3066102 5.43772719,12.8692665 5.34195591,13.4259371 L4.59374274,17.8014877 C4.53987139,18.1067587 4.6595855,18.3940725 4.91098512,18.5796294 C5.16238475,18.7592005 5.47364142,18.7831434 5.74299816,18.6394864 L9.68159228,16.5684324 C10.1784058,16.3050613 10.7709907,16.3050613 11.2737899,16.5684324 L15.212384,18.6394864 C15.4877265,18.7831434 15.7989831,18.7592005 16.0443971,18.5796294 C16.2957967,18.4000582 16.4095251,18.1067587 16.3616394,17.8014877 L15.6074406,13.4139657 C15.5116693,12.8572951 15.6972261,12.2946388 16.0982684,11.8995822 L19.2826636,8.79300115 C19.5041347,8.57751575 19.5759632,8.27224478 19.4861776,7.97894522 C19.3904063,7.68564566 19.1509781,7.48213168 18.8457072,7.44023174 L14.4462137,6.80574697 C13.8895431,6.7219471 13.4106867,6.37477619 13.1592871,5.87197694 L11.18999,1.87951148 C11.0523188,1.60416903 10.7889478,1.44255499 10.4776911,1.44255499 Z" id="形状"></path>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="28px" height="28px" viewBox="0 0 28 28" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>已收藏</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="绿碳供需大厅-碳服务供给" transform="translate(-638, -640)">
<g id="编组-13" transform="translate(225, 616)">
<g id="编组-8" transform="translate(1, 0)">
<g id="已收藏" transform="translate(412, 24)">
<rect id="close-circle-(Background)" opacity="0" x="0" y="0" width="28" height="28"></rect>
<g id="编组" transform="translate(4, 4)" fill="#FFBE4F" fill-rule="nonzero">
<path d="M15.5834977,20.1658413 C15.2303411,20.1658413 14.8711988,20.0820414 14.541985,19.908456 L10.6033909,17.8374019 C10.5255767,17.795502 10.4298054,17.795502 10.3519913,17.8374019 L6.41339716,19.908456 C5.65919829,20.3035125 4.75535678,20.2436555 4.06700067,19.7408562 C3.37265885,19.238057 3.03745935,18.4000582 3.18111628,17.5620595 L3.93531515,13.1745375 C3.95327227,13.0847519 3.92334374,12.9949663 3.85750098,12.9351092 L0.673105741,9.82852817 C0.0625637965,9.22995764 -0.152921596,8.35604466 0.110449439,7.54198873 C0.373820474,6.7279328 1.06217659,6.14731938 1.91214675,6.02760528 L6.31762588,5.38713481 C6.40741146,5.3751634 6.48522563,5.32129205 6.52113986,5.23749217 L8.49043692,1.24502671 C8.86753635,0.478856427 9.63370664,0 10.4896625,0 C11.3456184,0 12.1117886,0.478856427 12.4888881,1.24502671 L14.4581851,5.23749217 C14.5000851,5.31530634 14.5719135,5.3751634 14.6616991,5.38713481 L19.0671783,6.02760528 C19.9111627,6.15330509 20.6055045,6.73391851 20.8688756,7.54198873 C21.1322466,8.35604466 20.9167612,9.22995764 20.3062193,9.82852817 L17.1038669,12.9351092 C17.0380241,12.9949663 17.0080956,13.0847519 17.0260527,13.1745375 L17.7802516,17.5620595 C17.9239085,18.4060439 17.5827233,19.238057 16.8943672,19.7408562 C16.4993107,20.0221844 16.0443971,20.1658413 15.5834977,20.1658413 Z" id="路径"></path>
<path d="M10.4776911,1.44255499 C10.1664344,1.44255499 9.90306338,1.61015474 9.76539215,1.88549718 L7.7960951,5.87796264 C7.54469547,6.38076189 7.06583905,6.73391851 6.50916845,6.81173268 L2.10368932,7.45220315 C1.79841835,7.49410309 1.55899013,7.69761707 1.46321885,7.99091663 C1.36744756,8.28421619 1.44526173,8.58948716 1.66673283,8.80497256 L4.85112807,11.9115536 C5.25217033,12.3066102 5.43772719,12.8692665 5.34195591,13.4259371 L4.59374274,17.8014877 C4.53987139,18.1067587 4.6595855,18.3940725 4.91098512,18.5796294 C5.16238475,18.7592005 5.47364142,18.7831434 5.74299816,18.6394864 L9.68159228,16.5684324 C10.1784058,16.3050613 10.7709907,16.3050613 11.2737899,16.5684324 L15.212384,18.6394864 C15.4877265,18.7831434 15.7989831,18.7592005 16.0443971,18.5796294 C16.2957967,18.4000582 16.4095251,18.1067587 16.3616394,17.8014877 L15.6074406,13.4139657 C15.5116693,12.8572951 15.6972261,12.2946388 16.0982684,11.8995822 L19.2826636,8.79300115 C19.5041347,8.57751575 19.5759632,8.27224478 19.4861776,7.97894522 C19.3904063,7.68564566 19.1509781,7.48213168 18.8457072,7.44023174 L14.4462137,6.80574697 C13.8895431,6.7219471 13.4106867,6.37477619 13.1592871,5.87197694 L11.18999,1.87951148 C11.0523188,1.60416903 10.7889478,1.44255499 10.4776911,1.44255499 Z" id="路径"></path>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1,288 @@
<template>
<!-- 发布服务抽屉 -->
<t-drawer
:visible.sync="drawerVisible"
header="发布碳服务供给"
size="600px"
:closeOnOverlayClick="false"
:onClose="onClose"
class="global-drawer"
>
<div class="publish-form">
<t-form
:rules="rules"
:data="formData"
ref="form"
labelAlign="top"
@submit="submitForm"
>
<t-row :gutter="16">
<t-col :span="12">
<t-form-item label="服务标题" name="bt1">
<t-input v-model="formData.bt1" placeholder="请输入服务标题" clearable />
</t-form-item>
</t-col>
<t-col :span="12">
<t-form-item label="服务类型" name="fwlxjh">
<t-select
v-model="formData.fwlxjh"
:max="4"
:options="fwlxOptions"
placeholder="请选择服务类型"
multiple
clearable
/>
</t-form-item>
</t-col>
</t-row>
<t-row :gutter="16">
<t-col :span="12">
<t-form-item label="所属行业" name="sshy">
<t-select v-model="formData.sshy" :options="sshyDmOptions" placeholder="请选择所属行业" clearable />
</t-form-item>
</t-col>
<t-col :span="12">
<t-form-item label="服务地区" name="fwfw">
<t-select v-model="formData.fwfw" :options="fwfwOptions" placeholder="请选择服务地区" clearable />
</t-form-item>
</t-col>
</t-row>
<t-row :gutter="16">
<t-col :span="12">
<t-form-item label="价格" name="gjjg">
<t-input v-model="formData.gjjg" :disabled="ismy" placeholder="请输入价格" clearable />
<t-radio style="width: 80px; margin-left: 8px" allowUncheck v-model="ismy" @click="ismyChange">面议</t-radio>
</t-form-item>
</t-col>
<t-col :span="12">
<t-form-item label="单位" name="gjdwDm">
<t-select v-model="formData.gjdwDm" :disabled="ismy" :options="gjdwdmOptions" placeholder="请选择单位" clearable />
</t-form-item>
</t-col>
</t-row>
<t-form-item label="服务详细描述" name="fwnr">
<t-textarea v-model="formData.fwnr" placeholder="请填写服务详细描述" :maxlength="100" />
</t-form-item>
<t-form-item label="标签" name="bqjh">
<t-select
v-model="formData.bqjh"
:max="4"
:options="bqOptions"
placeholder="请选择标签"
multiple
clearable
/>
</t-form-item>
<t-row :gutter="16">
<t-col :span="8">
<t-form-item label="联系人" name="lxr">
<t-input v-model="formData.lxr" placeholder="请输入联系人" />
</t-form-item>
</t-col>
<t-col :span="8">
<t-form-item label="联系电话" name="lxdh">
<t-input v-model="formData.lxdh" placeholder="请输入联系电话" />
</t-form-item>
</t-col>
<t-col :span="8">
<t-form-item label="电子邮箱" name="email">
<t-input v-model="formData.email" placeholder="请输入电子邮箱" />
</t-form-item>
</t-col>
</t-row>
</t-form>
<div class="form-actions">
<t-button theme="primary" type="submit" @click="handleSubmit">提交发布</t-button>
</div>
</div>
</t-drawer>
</template>
<script>
import api from '@/pages/index/api/fwsc/index.js';
export default {
name: 'FwscPublish',
props: {
visible: {
type: Boolean,
default: false,
},
},
data() {
return {
drawerVisible: false,
ismy: false,
formData: {
bt1: '',
fwlxjh: '',
sshy: '',
gjjg: '',
gjdwDm: '',
fwfw: '',
fwnr: '',
bqjh: [],
lxr: '',
lxdh: '',
email: '',
},
rules: {
bt1: [{ required: true, message: '必填', type: 'error' }],
fwlxjh: [{ required: true, message: '必填', type: 'error' }],
sshy: [{ required: true, message: '必填', type: 'error' }],
fwfw: [{ required: true, message: '必填', type: 'error' }],
fwnr: [{ required: true, message: '必填', type: 'error' }],
lxr: [{ required: true, message: '必填', type: 'error' }],
lxdh: [{ required: true, message: '必填', type: 'error' }],
},
fwlxOptions: [],
sshyDmOptions: [],
fwfwOptions: [],
bqOptions: [],
gjdwdmOptions: [],
};
},
watch: {
visible(val) {
this.drawerVisible = val;
if (val) {
this.loadDmList();
}
},
drawerVisible(val) {
this.$emit('update:visible', val);
},
},
methods: {
loadDmList() {
this.fwlxoptionsSearch();
this.sshyoptionsSearch();
this.fwfwoptionsSearch();
this.bqoptionsSearch();
this.gjdwdmoptionsSearch();
},
async fwlxoptionsSearch() {
try {
const res = await api.dms2mc('fwlx', {});
this.fwlxOptions = res.data || [];
} catch (error) {
this.fwlxOptions = [];
}
},
async sshyoptionsSearch() {
try {
const res = await api.dms2mc('sshy', {});
this.sshyDmOptions = res.data || [];
} catch (error) {
this.sshyDmOptions = [];
}
},
async fwfwoptionsSearch() {
try {
const res = await api.dms2mc('XZQH', {});
this.fwfwOptions = res.data || [];
} catch (error) {
this.fwfwOptions = [];
}
},
async bqoptionsSearch() {
try {
const res = await api.dms2mc('bq', {});
this.bqOptions = res.data || [];
} catch (error) {
this.bqOptions = [];
}
},
async gjdwdmoptionsSearch() {
try {
const res = await api.dms2mc('dw', {});
this.gjdwdmOptions = res.data || [];
} catch (error) {
this.gjdwdmOptions = [];
}
},
ismyChange() {
this.ismy = !this.ismy;
if (this.ismy) {
this.formData.gjjg = '';
this.formData.gjdwDm = '';
}
},
handleSubmit() {
this.$refs.form.validate().then((result) => {
if (result === true) {
this.gxfb();
} else {
this.$message.warning('请填写全部必填信息');
}
});
},
async gxfb() {
try {
let prame = {
ywlxDm: '01',
...this.formData,
};
if (prame.bqjh && prame.bqjh.length) {
prame.bqjh = prame.bqjh.toString();
}
if (prame.fwlxjh && prame.fwlxjh.length) {
prame.fwlxjh = prame.fwlxjh.toString();
}
await api.gxfb(prame);
this.$message.success('发布成功,请等待审核');
this.drawerVisible = false;
this.resetForm();
this.$emit('success');
} catch (error) {
console.error('发布失败', error);
}
},
resetForm() {
this.formData = {
bt1: '',
fwlxjh: '',
sshy: '',
gjjg: '',
gjdwDm: '',
fwfw: '',
fwnr: '',
bqjh: [],
lxr: '',
lxdh: '',
email: '',
};
this.ismy = false;
},
onClose() {
this.drawerVisible = false;
this.resetForm();
},
submitForm() {
// handled by handleSubmit
},
},
};
</script>
<style lang="less" scoped>
.publish-form {
padding: 0 8px;
}
.form-actions {
display: flex;
justify-content: center;
margin-top: 30px;
.t-button {
width: 200px;
}
}
</style>

View File

@ -0,0 +1,275 @@
<template>
<!-- 发布需求抽屉 -->
<t-drawer
:visible.sync="drawerVisible"
header="发布碳服务需求"
size="600px"
:closeOnOverlayClick="false"
:onClose="onClose"
class="global-drawer"
>
<div class="publish-form">
<t-form
:rules="rules"
:data="formData"
ref="form"
labelAlign="top"
@submit="submitForm"
>
<t-row :gutter="16">
<t-col :span="12">
<t-form-item label="需求标题" name="bt1">
<t-input v-model="formData.bt1" placeholder="请输入需求标题" clearable />
</t-form-item>
</t-col>
<t-col :span="12">
<t-form-item label="需求类型" name="fwlxjh">
<t-select v-model="formData.fwlxjh" :options="xqlxOptions" placeholder="请选择需求类型" clearable />
</t-form-item>
</t-col>
</t-row>
<t-row :gutter="16">
<t-col :span="12">
<t-form-item label="所属行业" name="sshy">
<t-select v-model="formData.sshy" :options="sshyDmOptions" placeholder="请选择所属行业" clearable />
</t-form-item>
</t-col>
<t-col :span="12">
<t-form-item label="预算范围" name="ysfwDm1">
<t-select v-model="formData.ysfwDm1" :options="ysfwDm1Options" placeholder="请选择预算范围" clearable />
</t-form-item>
</t-col>
</t-row>
<t-row :gutter="16">
<t-col :span="12">
<t-form-item label="期望完成时间" name="qwwcsj">
<t-date-picker
v-model="formData.qwwcsj"
placeholder="请选择期望完成时间"
style="width: 100%"
clearable
/>
</t-form-item>
</t-col>
<t-col :span="12">
<t-form-item label="服务地区" name="fwfw">
<t-select v-model="formData.fwfw" :options="fwfwOptions" placeholder="请选择服务地区" clearable />
</t-form-item>
</t-col>
</t-row>
<t-form-item label="需求详细描述" name="fwnr">
<t-textarea v-model="formData.fwnr" placeholder="请填写需求详细描述" :maxlength="100" />
</t-form-item>
<t-form-item label="标签" name="bqjh">
<t-select
v-model="formData.bqjh"
:max="4"
:options="bqOptions"
placeholder="请选择标签"
multiple
clearable
/>
</t-form-item>
<t-row :gutter="16">
<t-col :span="8">
<t-form-item label="联系人" name="lxr">
<t-input v-model="formData.lxr" placeholder="请输入联系人" />
</t-form-item>
</t-col>
<t-col :span="8">
<t-form-item label="联系电话" name="lxdh">
<t-input v-model="formData.lxdh" placeholder="请输入联系电话" />
</t-form-item>
</t-col>
<t-col :span="8">
<t-form-item label="电子邮箱" name="email">
<t-input v-model="formData.email" placeholder="请输入电子邮箱" />
</t-form-item>
</t-col>
</t-row>
</t-form>
<div class="form-actions">
<t-button theme="primary" type="submit" @click="handleSubmit">提交发布</t-button>
</div>
</div>
</t-drawer>
</template>
<script>
import api from '@/pages/index/api/fwsc/index.js';
export default {
name: 'XqscPublish',
props: {
visible: {
type: Boolean,
default: false,
},
},
data() {
return {
drawerVisible: false,
formData: {
bt1: '',
fwlxjh: '',
sshy: '',
ysfwDm1: '',
qwwcsj: '',
fwfw: '',
fwnr: '',
bqjh: [],
lxr: '',
lxdh: '',
email: '',
},
rules: {
bt1: [{ required: true, message: '必填', type: 'error' }],
fwlxjh: [{ required: true, message: '必填', type: 'error' }],
sshy: [{ required: true, message: '必填', type: 'error' }],
ysfwDm1: [{ required: true, message: '必填', type: 'error' }],
qwwcsj: [{ required: true, message: '必填', type: 'error' }],
fwfw: [{ required: true, message: '必填', type: 'error' }],
fwnr: [{ required: true, message: '必填', type: 'error' }],
lxr: [{ required: true, message: '必填', type: 'error' }],
lxdh: [{ required: true, message: '必填', type: 'error' }],
},
xqlxOptions: [],
sshyDmOptions: [],
ysfwDm1Options: [],
fwfwOptions: [],
bqOptions: [],
};
},
watch: {
visible(val) {
this.drawerVisible = val;
if (val) {
this.loadDmList();
}
},
drawerVisible(val) {
this.$emit('update:visible', val);
},
},
methods: {
loadDmList() {
this.xqlxoptionsSearch();
this.sshyoptionsSearch();
this.ysfwoptionsSearch();
this.fwfwoptionsSearch();
this.bqoptionsSearch();
},
async xqlxoptionsSearch() {
try {
const res = await api.dms2mc('xqlx', {});
this.xqlxOptions = res.data || [];
} catch (error) {
this.xqlxOptions = [];
}
},
async sshyoptionsSearch() {
try {
const res = await api.dms2mc('sshy', {});
this.sshyDmOptions = res.data || [];
} catch (error) {
this.sshyDmOptions = [];
}
},
async ysfwoptionsSearch() {
try {
const res = await api.dms2mc('ysfw', {});
this.ysfwDm1Options = res.data || [];
} catch (error) {
this.ysfwDm1Options = [];
}
},
async fwfwoptionsSearch() {
try {
const res = await api.dms2mc('XZQH', {});
this.fwfwOptions = res.data || [];
} catch (error) {
this.fwfwOptions = [];
}
},
async bqoptionsSearch() {
try {
const res = await api.dms2mc('bq', {});
this.bqOptions = res.data || [];
} catch (error) {
this.bqOptions = [];
}
},
handleSubmit() {
this.$refs.form.validate().then((result) => {
if (result === true) {
this.gxfb();
} else {
this.$message.warning('请填写全部必填信息');
}
});
},
async gxfb() {
try {
let prame = {
ywlxDm: '02',
...this.formData,
};
if (prame.bqjh && prame.bqjh.length) {
prame.bqjh = prame.bqjh.toString();
}
await api.gxfb(prame);
this.$message.success('发布成功,请等待审核');
this.drawerVisible = false;
this.resetForm();
this.$emit('success');
} catch (error) {
console.error('发布失败', error);
}
},
resetForm() {
this.formData = {
bt1: '',
fwlxjh: '',
sshy: '',
ysfwDm1: '',
qwwcsj: '',
fwfw: '',
fwnr: '',
bqjh: [],
lxr: '',
lxdh: '',
email: '',
};
},
onClose() {
this.drawerVisible = false;
this.resetForm();
},
submitForm() {
// handled by handleSubmit
},
},
};
</script>
<style lang="less" scoped>
.publish-form {
padding: 0 8px;
}
.form-actions {
display: flex;
justify-content: center;
margin-top: 30px;
.t-button {
width: 200px;
}
}
</style>

View File

@ -5,78 +5,195 @@
<!-- 面包屑导航 -->
<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.path)"
>
{{ tab.label }}
</button>
</div>
<button class="publish-btn" @click="handlePublish">免费发布服务</button>
</div>
</div>
<main class="fwsc-main">
<div class="内容区域">
<div class="content-area">
<!-- 左侧筛选栏 -->
<aside class="筛选栏">
<div class="筛选栏内容">
<aside class="filter-sidebar">
<div class="filter-sidebar-content">
<!-- 服务类型 -->
<div class="筛选项">
<div class="筛选标签">服务类型</div>
<t-select v-model="筛选.服务类型" :options="服务类型选项" placeholder="请选择服务类型" clearable />
<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="筛选项">
<div class="筛选标签">服务企业</div>
<t-select v-model="筛选.服务企业" :options="服务企业选项" placeholder="请选择服务企业" clearable />
<div class="filter-section">
<div class="filter-title">服务企业</div>
<div class="filter-options">
<t-checkbox-group v-model="filter.qyuuids" :options="qyOptions" @change="onSearch" />
</div>
</div>
<!-- 关键词搜索 -->
<div class="筛选项">
<div class="筛选标签">关键词</div>
<t-input v-model="筛选.关键词" placeholder="请输入关键词" />
<!-- 只展示收藏项 -->
<div class="filter-section">
<t-checkbox v-model="filter.zzsscx" @change="onSearch">只展示收藏项</t-checkbox>
</div>
<t-button theme="primary" class="搜索按钮" @click="搜索">搜索</t-button>
<!-- 内容搜索 -->
<div class="filter-section">
<div class="filter-title">内容搜索</div>
<t-input v-model="filter.nr" placeholder="请输入关键词" @enter="onSearch" />
</div>
<div class="filter-buttons">
<t-button theme="primary" @click="onSearch">查询</t-button>
<t-button theme="default" @click="onReset">重置</t-button>
</div>
</div>
</aside>
<!-- 右侧服务卡片列表 -->
<div class="卡片列表">
<div class="card-list">
<div
v-for="(card, index) in 卡片数据"
:key="index"
class="服务卡片"
v-for="(card, index) in cardList"
:key="card.gxUuid"
class="service-card"
>
<!-- 卡片头部 -->
<div class="card-header">
<div class="card-title-box">
<div class="card-title-text">
<div class="card-title-main">{{ card.bt1 }}</div>
<div class="card-title-sub">
<span class="company-name">{{ card.qymc }}</span>
<span class="location" v-if="card.fwfw">
<LocationIcon style="transform: translateY(-1px)" />{{ card.fwfw }}
</span>
</div>
</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>
<!-- 卡片内容 -->
<div class="卡片头部">
<h3 class="卡片标题">{{ card.标题 }}</h3>
<p class="卡片企业">{{ card.企业 }}</p>
<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="卡片标签">
<span v-for="(tag, tagIndex) in card.标签" :key="tagIndex" class="标签">
{{ tag }}
</span>
<!-- 卡片底部 -->
<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">
<t-button theme="primary" size="small" @click="handleContact(card)">联系服务商</t-button>
</div>
</div>
</div>
<div class="卡片价格" :style="{ color: '#D25F00' }">
{{ card.价格 }}
</div>
<p class="卡片描述">{{ card.描述 }}</p>
<div class="卡片操作">
<t-button theme="primary" class="操作按钮">联系服务商</t-button>
<t-button variant="outline" class="操作按钮">收藏</t-button>
</div>
<!-- 分隔线 -->
<div v-if="index < 卡片数据.length - 1" class="卡片分隔线"></div>
<!-- 空状态 -->
<div v-if="cardList.length === 0 && !loading" class="empty-state">
<p>暂无服务信息</p>
</div>
</div>
</div>
<!-- 分页 -->
<div class="pagination-box" v-if="page.total > 0">
<t-pagination
v-model="page.pageNo"
:total="page.total"
:page-size.sync="page.pageSize"
:page-size-options="[3, 9, 27, 45]"
@change="onPageChange"
/>
</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 } 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',
@ -84,71 +201,248 @@ export default {
NewNav,
Footer,
BreadcrumbNav,
FwscPublish,
LocationIcon,
},
data() {
return {
筛选: {
服务类型: '',
服务企业: '',
关键词: '',
navTabs: [
{ label: '碳服务市场', path: '/fwsc/fwsc' },
{ label: '碳需求市场', path: '/fwsc/xqsc' },
{ label: '碳金融市场', path: '/fwsc/jrsc' },
{ label: '碳数据市场', path: '/fwsc/sjsc' },
],
//
filter: {
fwlxjh: [],
qyuuids: [],
nr: '',
zzsscx: false,
},
服务类型选项: [
{ label: '全部', value: '' },
{ label: '碳核查服务', value: '碳核查服务' },
{ label: '碳足迹核算', value: '碳足迹核算' },
{ label: '碳减排技术服务', value: '碳减排技术服务' },
{ label: '碳资产管理服务', value: '碳资产管理服务' },
{ label: 'ESG报告编制', value: 'ESG报告编制' },
{ label: '碳交易咨询', value: '碳交易咨询' },
],
服务企业选项: [
{ label: '全部', value: '' },
{ label: '欧冶云商', value: '欧冶云商' },
{ label: '上海企源科技', value: '上海企源科技' },
{ label: '上海零数科技', value: '上海零数科技' },
{ label: '上海链坤数字科技', value: '上海链坤数字科技' },
],
卡片数据: [
{
标题: '本司提供碳相关服务寻找有需求的企业客户',
企业: '上海链坤数字科技有限公司 · 辽宁省',
标签: ['ESG报告编制', '碳减排技术服务'],
价格: '¥ 10,000.00 /次',
描述: '我们为参与碳市场的企业提供全方位的交易策略与风险管理咨询。服务内容包括解读碳市场政策规则、分析碳价走势、制定交易策略助…',
},
{
标题: '为碳超标企业提供中和方案',
企业: '上海零数科技有限公司 · 全国',
标签: ['碳核查服务', '碳足迹核算'],
价格: '¥ 5,000,000.00 /年',
描述: '本服务依据国际国内标准如ISO 14064-1对企业的温室气体排放报告进行独立的第三方审定与核查。我们通过文件评审、现场访…',
},
{
标题: '',
企业: '欧冶云商 · 北京市',
标签: ['ESG报告编制'],
价格: '¥ 1,500.00 /年',
描述: '我们协助企业系统梳理其在环境、社会和治理ESG领域的表现并按照GRI、SASB、TCFD等主流框架编制专业的ESG报告。服…',
},
{
标题: '碳足迹核算、碳减排技术供给',
企业: '上海企源科技股份有限公司 · 全国',
标签: ['碳减排技术服务', '碳足迹核算'],
价格: '面议',
描述: '本服务依据国际国内标准如ISO 14064-1对企业的温室气体排放报告进行独立的第三方审定与核查。我们通过文件评审、现场访…',
},
],
//
fwlxOptions: [],
//
qyOptions: [],
//
allQyOptions: [],
//
cardList: [],
//
page: {
pageNo: 1,
pageSize: 9,
total: 0,
},
//
loading: false,
//
yhxx: {},
//
publishVisible: false,
//
contactVisible: false,
contactData: {},
//
rzVisible: false,
//
publishSuccessVisible: false,
};
},
mounted() {
this.initUser();
this.loadDmList();
this.searchList();
//
if (this.$route.query.publish === '1') {
this.handlePublish();
}
},
methods: {
搜索() {
console.log('搜索条件:', this.筛选);
//
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 || [];
} catch (error) {
this.allQyOptions = [];
this.qyOptions = [];
}
},
//
async onFwlxChange() {
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));
} catch (error) {
this.qyOptions = this.allQyOptions;
}
} else {
this.qyOptions = this.allQyOptions;
}
this.onSearch();
},
//
async searchList() {
this.loading = true;
this.cardList = [];
try {
const prame = {
ywlxDm: '01',
...this.filter,
...this.page,
};
if (prame.scbz !== undefined) {
prame.scbz = this.filter.zzsscx ? 'Y' : '';
}
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 = data.total || 0;
} catch (error) {
this.cardList = [];
this.page.total = 0;
console.error('获取服务列表失败', error);
} finally {
this.loading = false;
}
},
//
onReset() {
this.filter = {
fwlxjh: [],
qyuuids: [],
nr: '',
zzsscx: false,
};
this.qyOptions = this.allQyOptions;
this.page.pageNo = 1;
this.searchList();
},
//
onSearch() {
this.page.pageNo = 1;
this.searchList();
},
//
onPageChange(pageInfo) {
this.page.pageNo = pageInfo.current;
this.page.pageSize = pageInfo.pageSize;
this.searchList();
},
//
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) {
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('/fwsc/fwsc');
},
onPublishSuccessClose() {
this.publishSuccessVisible = false;
},
},
};
</script>
<style scoped>
<style lang="less" scoped>
.fwsc-container {
min-height: 100vh;
background: #f5f5f5;
@ -161,13 +455,68 @@ export default {
margin: 0 auto;
}
.内容区域 {
//
.secondary-nav {
background: #fff;
border-bottom: 1px solid #eee;
}
.secondary-nav-content {
display: flex;
align-items: center;
justify-content: space-between;
max-width: 1400px;
padding: 0 20px;
margin: 0 auto;
}
.nav-tabs {
display: flex;
gap: 8px;
}
.nav-tab {
padding: 12px 20px;
font-size: 14px;
color: #666;
cursor: pointer;
background: transparent;
border: none;
border-bottom: 2px solid transparent;
transition: all 0.3s;
&:hover {
color: #009a29;
}
&.active {
color: #009a29;
border-bottom-color: #009a29;
}
}
.publish-btn {
padding: 8px 20px;
font-size: 14px;
color: #fff;
cursor: pointer;
background: #009a29;
border: none;
border-radius: 4px;
transition: background 0.3s;
&:hover {
background: #007a1f;
}
}
.content-area {
display: flex;
gap: 20px;
}
/* 左侧筛选栏 */
.筛选栏 {
//
.filter-sidebar {
position: sticky;
top: 104px;
width: 220px;
@ -175,115 +524,224 @@ export default {
flex-shrink: 0;
}
.筛选栏内容 {
.filter-sidebar-content {
padding: 20px;
background: #fff;
border-radius: 8px;
}
.筛选项 {
.filter-section {
margin-bottom: 20px;
&:last-child {
margin-bottom: 0;
}
}
.筛选标签 {
.filter-title {
margin-bottom: 8px;
font-size: 14px;
font-weight: 500;
color: #333;
}
.搜索按钮 {
width: 100%;
margin-top: 10px;
.filter-options {
/deep/.t-checkbox__label {
font-size: 14px;
color: #666;
}
}
/* 右侧卡片列表 */
.卡片列表 {
.filter-buttons {
display: flex;
gap: 8px;
margin-top: 16px;
.t-button {
flex: 1;
}
}
//
.card-list {
flex: 1;
display: grid;
grid-template-columns: repeat(2, 1fr);
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.服务卡片 {
position: relative;
padding: 20px;
.service-card {
display: flex;
flex-direction: column;
width: calc((100% - 40px) / 3);
overflow: hidden;
background: #fff;
border-radius: 8px;
transition: transform 0.2s;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
transition: transform 0.3s, box-shadow 0.3s;
&:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
}
.服务卡片:hover {
transform: scale(1.02);
.card-header {
padding: 16px;
border-bottom: 1px solid #eee;
}
.卡片头部 {
margin-bottom: 12px;
.card-title-box {
display: flex;
justify-content: space-between;
}
.卡片标题 {
margin: 0 0 8px;
.card-title-text {
flex: 1;
min-width: 0;
}
.card-title-main {
margin-bottom: 4px;
overflow: hidden;
font-size: 16px;
font-weight: 600;
line-height: 1.4;
line-height: 24px;
color: #333;
}
.卡片企业 {
margin: 0;
font-size: 13px;
color: #666;
}
.卡片标签 {
display: flex;
gap: 8px;
margin-bottom: 12px;
flex-wrap: wrap;
}
.标签 {
display: inline-block;
padding: 4px 12px;
font-size: 12px;
color: #0052d9;
background: #f0f5ff;
border-radius: 4px;
}
.卡片价格 {
margin-bottom: 12px;
font-size: 20px;
font-weight: 700;
}
.卡片描述 {
display: box;
margin-bottom: 16px;
overflow: hidden;
font-size: 13px;
line-height: 1.6;
color: #666;
text-overflow: ellipsis;
box-orient: vertical;
-webkit-line-clamp: 2;
white-space: nowrap;
}
.卡片操作 {
.card-title-sub {
display: flex;
font-size: 14px;
color: #666;
gap: 12px;
}
.操作按钮 {
flex: 1;
.company-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.卡片分隔线 {
position: absolute;
right: 20px;
bottom: 0;
left: 20px;
height: 1px;
background: #eee;
.location {
display: flex;
align-items: center;
gap: 2px;
flex-shrink: 0;
}
.card-collect {
flex-shrink: 0;
margin-left: 8px;
cursor: pointer;
img {
width: 20px;
height: 20px;
}
}
.card-content {
flex: 1;
padding: 16px;
}
.card-desc {
display: box;
margin-bottom: 12px;
overflow: hidden;
font-size: 14px;
line-height: 1.6;
color: #666;
text-overflow: ellipsis;
-webkit-line-clamp: 3;
box-orient: vertical;
}
.card-tags {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.tag {
padding: 2px 8px;
font-size: 12px;
color: #2e7d32;
background: #dcf9e2;
border-radius: 4px;
}
.card-footer {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 16px;
border-top: 1px dashed #979797;
}
.card-price-info {
display: flex;
align-items: baseline;
}
.price-value {
font-size: 20px;
font-weight: 600;
color: #d25f00;
}
.price-unit {
margin-left: 2px;
font-size: 14px;
color: #666;
}
//
.empty-state {
display: flex;
width: 100%;
min-height: 300px;
font-size: 14px;
color: #999;
align-items: center;
justify-content: center;
}
//
.pagination-box {
display: flex;
justify-content: center;
padding-top: 32px;
}
//
.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) {
.service-card {
width: 100%;
}
}
</style>

View File

@ -29,8 +29,8 @@
<h3 class="service-card-title">碳服务市场</h3>
<p class="service-card-desc">汇聚全国优质第三方服务机构提供从核算到认证的全链条专业服务</p>
<div class="service-card-buttons">
<t-button theme="primary" variant="outline" @click.stop="goToPage('/fwsc/fwsc')">浏览供给信息</t-button>
<t-button theme="primary" @click.stop="goToPage('/fwsc/fwsc')">我要入驻</t-button>
<t-button theme="primary" variant="outline" @click.stop="goToPage('/fwsc/fwsc')">浏览服务信息</t-button>
<t-button theme="primary" @click.stop="goToPage('/fwsc/fwsc?publish=1')">我要发布服务</t-button>
</div>
</div>
@ -43,7 +43,7 @@
<p class="service-card-desc">企业发布真实服务采购需求智能匹配靠谱服务商杜绝中间商差价</p>
<div class="service-card-buttons">
<t-button theme="primary" variant="outline" @click.stop="goToPage('/fwsc/xqsc')">浏览求购信息</t-button>
<t-button theme="primary" @click.stop="goToPage('/fwsc/xqsc')">我要发布需求</t-button>
<t-button theme="primary" @click.stop="goToPage('/fwsc/xqsc?publish=1')">我要发布需求</t-button>
</div>
</div>
@ -56,7 +56,7 @@
<p class="service-card-desc">打通"碳""钱"的通道提供碳质押碳回购绿色信贷及碳基金对接服务</p>
<div class="service-card-buttons">
<t-button theme="primary" variant="outline" @click.stop="goToPage('/fwsc/jrsc')">查看金融产品</t-button>
<t-button theme="primary" @click.stop="goToPage('/fwsc/jrsc')">金融机构入驻</t-button>
<t-button theme="primary" @click.stop="goToPage('/view/mhzc/yhzx')">金融机构入驻</t-button>
</div>
</div>
@ -69,7 +69,7 @@
<p class="service-card-desc">合规高效的碳数据流转平台包括公共数据社会性数据因子库等多类数据库</p>
<div class="service-card-buttons">
<t-button theme="primary" variant="outline" @click.stop="goToPage('/fwsc/sjsc')">进入交易大厅</t-button>
<t-button theme="primary" @click.stop="goToPage('/fwsc/sjsc')">我要卖碳</t-button>
<t-button theme="primary" @click.stop="goToPage('/view/mhzc/yhzx')">我要出售</t-button>
</div>
</div>
</div>
@ -108,7 +108,6 @@ export default {
}
.main-content {
// padding-top: 64px;
}
//

View File

@ -1,11 +1,28 @@
<template>
<div class="jrsc-page">
<!-- 顶部导航 -->
<new-nav />
<NewNav />
<!-- 面包屑导航 -->
<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.path)"
>
{{ tab.label }}
</button>
</div>
<button class="publish-btn" @click="handlePublish">免费发布金融产品</button>
</div>
</div>
<!-- 页面主体 -->
<div class="jrsc-main">
<!-- 内容区域 -->
@ -120,24 +137,30 @@
</div>
<!-- 底部 -->
<footer-component />
<Footer />
</div>
</template>
<script>
import NewNav from '@/pages/index/components/new-nav/index.vue';
import FooterComponent from '@/pages/index/components/footer/index.vue';
import Footer from '@/pages/index/components/footer/index.vue';
import BreadcrumbNav from '@/pages/index/components/breadcrumb/index.vue';
export default {
name: 'JrscPage',
components: {
NewNav,
FooterComponent,
Footer,
BreadcrumbNav,
},
data() {
return {
navTabs: [
{ label: '碳服务市场', path: '/fwsc/fwsc' },
{ label: '碳需求市场', path: '/fwsc/xqsc' },
{ label: '碳金融市场', path: '/fwsc/jrsc' },
{ label: '碳数据市场', path: '/fwsc/sjsc' },
],
//
selectedServiceType: '全部',
//
@ -256,8 +279,16 @@ export default {
},
methods: {
handleSearch() {
//
console.log('搜索关键词:', this.searchKeyword);
//
},
isActiveTab(path) {
return this.$route.path === path;
},
goToTab(path) {
this.$router.push(path);
},
handlePublish() {
//
},
},
};
@ -275,6 +306,61 @@ export default {
margin: 0 auto;
}
//
.secondary-nav {
background: #fff;
border-bottom: 1px solid #eee;
}
.secondary-nav-content {
display: flex;
align-items: center;
justify-content: space-between;
max-width: 1400px;
padding: 0 20px;
margin: 0 auto;
}
.nav-tabs {
display: flex;
gap: 8px;
}
.nav-tab {
padding: 12px 20px;
font-size: 14px;
color: #666;
cursor: pointer;
background: transparent;
border: none;
border-bottom: 2px solid transparent;
transition: all 0.3s;
&:hover {
color: #009a29;
}
&.active {
color: #009a29;
border-bottom-color: #009a29;
}
}
.publish-btn {
padding: 8px 20px;
font-size: 14px;
color: #fff;
cursor: pointer;
background: #009a29;
border: none;
border-radius: 4px;
transition: background 0.3s;
&:hover {
background: #007a1f;
}
}
//
.content-wrapper {
display: flex;

View File

@ -142,7 +142,6 @@ export default {
data() {
return {
currentPageName: '数据列表',
marketId: '',
filterParams: {
priceMin: '',
priceMax: '',
@ -226,9 +225,6 @@ export default {
],
};
},
created() {
this.marketId = this.$route.query.id || '';
},
computed: {
sortedDataList() {
if (!this.sortField) {
@ -277,7 +273,7 @@ export default {
};
},
confirmFilter() {
console.log('筛选条件:', this.filterParams);
//
},
},
};

View File

@ -5,6 +5,23 @@
<!-- 面包屑导航 -->
<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.path)"
>
{{ tab.label }}
</button>
</div>
<button class="publish-btn" @click="handlePublish">免费发布数据</button>
</div>
</div>
<!-- 页面主体 -->
<div class="page-body">
<!-- 左侧筛选栏 -->
@ -76,6 +93,12 @@ export default {
},
data() {
return {
navTabs: [
{ label: '碳服务市场', path: '/fwsc/fwsc' },
{ label: '碳需求市场', path: '/fwsc/xqsc' },
{ label: '碳金融市场', path: '/fwsc/jrsc' },
{ label: '碳数据市场', path: '/fwsc/sjsc' },
],
selectedType: 'all',
dataTypeList: [
{ label: '全部', value: 'all' },
@ -147,6 +170,15 @@ export default {
handleTypeChange(value) {
this.selectedType = value;
},
isActiveTab(path) {
return this.$route.path === path;
},
goToTab(path) {
this.$router.push(path);
},
handlePublish() {
//
},
goToDataList(id) {
this.$router.push({ path: '/fwsc/sjlbc', query: { id } });
},
@ -178,6 +210,61 @@ export default {
gap: 20px;
}
//
.secondary-nav {
background: #fff;
border-bottom: 1px solid #eee;
}
.secondary-nav-content {
display: flex;
align-items: center;
justify-content: space-between;
max-width: 1400px;
padding: 0 20px;
margin: 0 auto;
}
.nav-tabs {
display: flex;
gap: 8px;
}
.nav-tab {
padding: 12px 20px;
font-size: 14px;
color: #666;
cursor: pointer;
background: transparent;
border: none;
border-bottom: 2px solid transparent;
transition: all 0.3s;
&:hover {
color: #009a29;
}
&.active {
color: #009a29;
border-bottom-color: #009a29;
}
}
.publish-btn {
padding: 8px 20px;
font-size: 14px;
color: #fff;
cursor: pointer;
background: #009a29;
border: none;
border-radius: 4px;
transition: background 0.3s;
&:hover {
background: #007a1f;
}
}
//
.sidebar {
position: sticky;

View File

@ -1,148 +1,184 @@
<!--
* @Descripttion: 碳需求市场页面
* @Version: 1.0
* @Author: cby
* @Date: 2026-04-03
-->
<template>
<div>
<div class="xqsc-container">
<NewNav />
<div class="xqsc-page">
<!-- 面包屑导航 -->
<BreadcrumbNav currentPage="碳需求市场" />
<!-- 主内容区 -->
<div class="content-wrapper">
<!-- 左侧筛选栏 -->
<div class="filter-sidebar">
<!-- 搜索框 -->
<div class="filter-search">
<t-input v-model="searchKeyword" placeholder="请输入关键词" @enter="handleSearch"></t-input>
<t-button theme="primary" @click="handleSearch">搜索</t-button>
</div>
<!-- 服务类型 -->
<div class="filter-section">
<div class="filter-title">服务类型</div>
<div class="filter-options">
<div
v-for="item in serviceTypeList"
:key="item.value"
:class="['filter-option', { active: selectedServiceType === item.value }]"
@click="handleServiceTypeSelect(item.value)"
>
{{ item.label }}
</div>
</div>
</div>
<!-- 服务企业 -->
<div class="filter-section">
<div class="filter-title">服务企业</div>
<div class="filter-options">
<div
v-for="item in companyList"
:key="item.value"
:class="['filter-option', { active: selectedCompany === item.value }]"
@click="handleCompanySelect(item.value)"
>
{{ item.label }}
</div>
</div>
</div>
</div>
<!-- 右侧需求卡片列表 -->
<div class="demand-list">
<div class="list-header">
<span class="list-title">碳需求市场</span>
<span class="list-count"> {{ demandList.length }} 条需求</span>
</div>
<div class="demand-grid">
<div
v-for="(item, index) in demandList"
:key="index"
class="demand-card"
>
<!-- 卡片头部 - 标题 -->
<div :class="['demand-title', { 'urgent': item.urgent }]">
{{ item.title }}
</div>
<!-- 发布企业 -->
<div class="demand-company">
{{ item.company }}
</div>
<!-- 标签 -->
<div class="demand-tags">
<span v-for="(tag, tagIndex) in item.tags" :key="tagIndex" class="demand-tag">
{{ tag }}
</span>
</div>
<!-- 预算 -->
<div class="demand-budget">
<span class="budget-label">预算</span>
<span class="budget-value">{{ item.budget }}</span>
</div>
<!-- 描述 -->
<div class="demand-desc">
{{ item.desc }}
</div>
<!-- 有效期 -->
<div class="demand-validity" v-if="item.validity">
<svg class="calendar-icon" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5V3.5C13.5 3.22386 13.2761 3 13 3H12.5V1.5C12.5 1.22386 12.2761 1 12 1C11.7239 1 11.5 1.22386 11.5 1.5V3H4.5V1.5C4.5 1.22386 4.27614 1 4 1C3.72386 1 3.5 1.22386 3.5 1.5V3H3C2.72386 3 2.5 3.22386 2.5 3.5V13.5C2.5 13.7761 2.72386 14 3 14H13C13.2761 14 13.5 13.7761 13.5 13.5V13.5" stroke="#666" stroke-width="1.2"/>
<path d="M5.5 6H10.5M5.5 8.5H10.5M5.5 11H8.5" stroke="#666" stroke-width="1.2" stroke-linecap="round"/>
</svg>
<span>有效期至{{ item.validity }}</span>
</div>
<!-- 操作按钮 -->
<div class="demand-action">
<t-button theme="primary" @click="handleContact(item)">联系服务</t-button>
</div>
</div>
</div>
</div>
<!-- 面包屑导航 -->
<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.path)"
>
{{ tab.label }}
</button>
</div>
<!-- 联系服务弹窗 -->
<t-dialog
:closeOnOverlayClick="false"
header="联系服务"
:visible.sync="contactDialogVisible"
@confirm="handleConfirm"
@cancel="handleCancel"
:onClose="handleClose"
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>
<div class="dialog-line">
<div class="dialog-line-title" style="width:95px">留言内容</div>
<t-textarea v-model="messageContent" :autosize="{ minRows: 3 }"></t-textarea>
</div>
</t-dialog>
<Footer />
<button class="publish-btn" @click="handlePublish">免费发布需求</button>
</div>
</div>
<main class="xqsc-main">
<div class="content-area">
<!-- 左侧筛选栏 -->
<aside class="filter-sidebar">
<div class="filter-sidebar-content">
<!-- 需求类型 -->
<div class="filter-section">
<div class="filter-title">需求类型</div>
<div class="filter-options">
<t-checkbox-group v-model="filter.fwlxjh" :options="xqlxOptions" @change="onSearch" />
</div>
</div>
<!-- 所属行业 -->
<div class="filter-section">
<div class="filter-title">所属行业</div>
<div class="filter-options">
<t-checkbox-group v-model="filter.sshy" :options="sshyDmOptions" @change="onSearch" />
</div>
</div>
<!-- 服务地区 -->
<div class="filter-section">
<div class="filter-title">服务地区</div>
<t-select v-model="filter.dq" :options="fwfwOptions" placeholder="请选择" clearable style="width: 100%" @change="onSearch" />
</div>
<!-- 内容搜索 -->
<div class="filter-section">
<div class="filter-title">内容搜索</div>
<t-input v-model="filter.nr" placeholder="请输入关键词" @enter="onSearch" />
</div>
<div class="filter-buttons">
<t-button theme="primary" @click="onSearch">查询</t-button>
<t-button theme="default" @click="onReset">重置</t-button>
</div>
</div>
</aside>
<!-- 右侧需求卡片列表 -->
<div class="demand-list">
<div class="list-header">
<span class="list-title">碳需求市场</span>
<span class="list-count"> {{ page.total }} 条需求</span>
</div>
<div class="demand-grid">
<div
v-for="card in cardList"
:key="card.gxUuid"
class="demand-card"
>
<!-- 卡片头部 -->
<div class="card-header">
<div :class="['demand-title', { urgent: card.urgent }]">
{{ card.bt1 }}
</div>
<div class="demand-company">{{ card.qymc }}</div>
</div>
<!-- 卡片内容 -->
<div class="card-content">
<div class="card-tags">
<span v-for="(tag, i) in card.fwlxbqList" :key="i" class="tag">{{ tag }}</span>
</div>
<p class="card-desc">{{ card.fwnr }}</p>
</div>
<!-- 卡片底部 -->
<div class="card-footer">
<div class="card-budget">
<span class="budget-label">预算</span>
<span class="budget-value">{{ card.ysfwDm1 }}</span>
</div>
<div class="card-actions">
<t-button theme="primary" size="small" @click="handleContact(card)">联系服务</t-button>
</div>
</div>
</div>
</div>
<!-- 空状态 -->
<div v-if="cardList.length === 0 && !loading" class="empty-state">
<p>暂无需求信息</p>
</div>
</div>
</div>
<!-- 分页 -->
<div class="pagination-box" v-if="page.total > 0">
<t-pagination
v-model="page.pageNo"
:total="page.total"
:page-size.sync="page.pageSize"
:page-size-options="[3, 9, 27, 45]"
@change="onPageChange"
/>
</div>
</main>
<Footer />
<!-- 发布需求抽屉 -->
<XqscPublish
: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>
@ -150,123 +186,286 @@
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 XqscPublish from './components/XqscPublish.vue';
import api from '@/pages/index/api/fwsc/index.js';
export default {
name: 'Xqsc',
name: 'XqscPage',
components: {
NewNav,
Footer,
BreadcrumbNav,
XqscPublish,
},
data() {
return {
searchKeyword: '',
selectedServiceType: '',
selectedCompany: '',
contactDialogVisible: false,
contactData: {
lxr: '张经理',
lxdh: '021-12345678',
email: 'service@example.com'
navTabs: [
{ label: '碳服务市场', path: '/fwsc/fwsc' },
{ label: '碳需求市场', path: '/fwsc/xqsc' },
{ label: '碳金融市场', path: '/fwsc/jrsc' },
{ label: '碳数据市场', path: '/fwsc/sjsc' },
],
//
filter: {
fwlxjh: [],
sshy: [],
dq: '',
nr: '',
},
messageContent: '',
serviceTypeList: [
{ label: '全部', value: '' },
{ label: '碳核查服务', value: 'carbon_check' },
{ label: '碳足迹核算', value: 'carbon_footprint' },
{ label: '碳减排技术服务', value: 'carbon_reduction' },
{ label: '碳资产管理服务', value: 'carbon_asset' },
{ label: 'ESG报告编制', value: 'esg_report' },
{ label: '碳交易咨询', value: 'carbon_trade' }
],
companyList: [
{ label: '全部', value: '' },
{ label: '欧冶云商', value: 'ouye' },
{ label: '上海企源科技股份有限公司', value: 'qiyuan' },
{ label: '上海零数科技有限公司', value: 'lingshu' },
{ label: '上海链坤数字科技有限公司', value: 'linkun' }
],
demandList: [
{
title: '碳核查服务需求',
company: '上海链坤数字科技有限公司',
tags: ['ESG报告编制', '碳减排技术服务'],
budget: '¥ 50-100 万元',
desc: '我们为参与碳市场的企业提供全方位的交易策略与风险管理咨询。服务内容包括解读碳市场政策规则、分析碳价走势、制定交易策略...',
validity: '2026-04-24',
urgent: false
},
{
title: '【碳服务需求!急急急!】',
company: '上海零数科技有限公司',
tags: ['碳核查服务', '碳足迹核算'],
budget: '¥ 50-100 万元',
desc: '本服务依据国际国内标准如ISO 14064-1对企业的温室气体排放报告进行独立的第三方审定与核查。我们通过文件评审、现场访...',
validity: '2026-04-24',
urgent: true
},
{
title: '减碳中和需求',
company: '上海链坤数字科技有限公司',
tags: ['ESG报告编制', '碳减排技术服务'],
budget: '¥ 50-100 万元',
desc: '我们为参与碳市场的企业提供全方位的交易策略与风险管理咨询。服务内容包括解读碳市场政策规则、分析碳价走势、制定交易策略...',
validity: '',
urgent: false
},
{
title: '碳足迹核算需求',
company: '欧冶云商',
tags: ['碳核查服务', '碳足迹核算'],
budget: '¥ 50-100 万元',
desc: '本服务依据国际国内标准如ISO 14064-1对企业的温室气体排放报告进行独立的第三方审定与核查。我们通过文件评审、现场访...',
validity: '',
urgent: false
}
]
//
xqlxOptions: [],
sshyDmOptions: [],
fwfwOptions: [],
//
cardList: [],
//
page: {
pageNo: 1,
pageSize: 9,
total: 0,
},
//
loading: false,
//
publishVisible: false,
//
contactVisible: false,
contactData: {},
//
rzVisible: false,
//
publishSuccessVisible: false,
};
},
methods: {
handleSearch() {
console.log('搜索关键词:', this.searchKeyword);
},
handleServiceTypeSelect(value) {
this.selectedServiceType = value;
},
handleCompanySelect(value) {
this.selectedCompany = value;
},
handleContact(item) {
this.contactDialogVisible = true;
this.messageContent = '';
},
handleConfirm() {
console.log('提交留言:', this.messageContent);
this.$message.success('留言发布成功!');
this.contactDialogVisible = false;
},
handleCancel() {
this.contactDialogVisible = false;
},
handleClose() {
this.contactDialogVisible = false;
mounted() {
this.loadDmList();
this.searchList();
//
if (this.$route.query.publish === '1') {
this.handlePublish();
}
}
},
methods: {
//
loadDmList() {
this.xqlxoptionsSearch();
this.sshyoptionsSearch();
this.fwfwoptionsSearch();
},
async xqlxoptionsSearch() {
try {
const res = await api.dms2mc('xqlx', {});
this.xqlxOptions = res.data || [];
} catch (error) {
this.xqlxOptions = [];
}
},
async sshyoptionsSearch() {
try {
const res = await api.dms2mc('sshy', {});
this.sshyDmOptions = res.data || [];
} catch (error) {
this.sshyDmOptions = [];
}
},
async fwfwoptionsSearch() {
try {
const res = await api.dms2mc('XZQH', {});
this.fwfwOptions = res.data || [];
} catch (error) {
this.fwfwOptions = [];
}
},
//
async searchList() {
this.loading = true;
this.cardList = [];
try {
const prame = {
ywlxDm: '02',
...this.filter,
...this.page,
};
if (prame.dq === '000000') {
prame.dq = '';
}
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 = data.total || 0;
} catch (error) {
this.cardList = [];
this.page.total = 0;
console.error('获取需求列表失败', error);
} finally {
this.loading = false;
}
},
//
onReset() {
this.filter = {
fwlxjh: [],
sshy: [],
dq: '',
nr: '',
};
this.page.pageNo = 1;
this.searchList();
},
//
onSearch() {
this.page.pageNo = 1;
this.searchList();
},
//
onPageChange(pageInfo) {
this.page.pageNo = pageInfo.current;
this.page.pageSize = pageInfo.pageSize;
this.searchList();
},
//
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;
}
},
//
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) {
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('/fwsc/xqsc');
},
onPublishSuccessClose() {
this.publishSuccessVisible = false;
},
},
};
</script>
<style lang="less" scoped>
.xqsc-page {
.xqsc-container {
min-height: 100vh;
background: #efefef;
background: #f5f5f5;
}
//
.content-wrapper {
display: flex;
.xqsc-main {
width: 100%;
max-width: 1400px;
padding: 20px;
margin: 0 auto;
}
//
.secondary-nav {
background: #fff;
border-bottom: 1px solid #eee;
}
.secondary-nav-content {
display: flex;
align-items: center;
justify-content: space-between;
max-width: 1400px;
padding: 0 20px;
margin: 0 auto;
}
.nav-tabs {
display: flex;
gap: 8px;
}
.nav-tab {
padding: 12px 20px;
font-size: 14px;
color: #666;
cursor: pointer;
background: transparent;
border: none;
border-bottom: 2px solid transparent;
transition: all 0.3s;
&:hover {
color: #009a29;
}
&.active {
color: #009a29;
border-bottom-color: #009a29;
}
}
.publish-btn {
padding: 8px 20px;
font-size: 14px;
color: #fff;
cursor: pointer;
background: #009a29;
border: none;
border-radius: 4px;
transition: background 0.3s;
&:hover {
background: #007a1f;
}
}
.content-area {
display: flex;
gap: 20px;
}
@ -275,53 +474,45 @@ export default {
position: sticky;
top: 104px;
width: 220px;
flex-shrink: 0;
height: fit-content;
flex-shrink: 0;
}
.filter-sidebar-content {
padding: 20px;
background: #fff;
border-radius: 8px;
}
.filter-search {
display: flex;
gap: 8px;
margin-bottom: 24px;
}
.filter-section {
margin-bottom: 20px;
&:last-child {
margin-bottom: 0;
}
}
.filter-title {
margin-bottom: 12px;
font-size: 16px;
font-weight: 600;
margin-bottom: 8px;
font-size: 14px;
font-weight: 500;
color: #333;
}
.filter-options {
display: flex;
flex-direction: column;
gap: 8px;
/deep/.t-checkbox__label {
font-size: 14px;
color: #666;
}
}
.filter-option {
padding: 8px 12px;
font-size: 14px;
color: #666;
cursor: pointer;
background: #f5f5f5;
border-radius: 4px;
transition: all 0.3s;
.filter-buttons {
display: flex;
gap: 8px;
margin-top: 16px;
&:hover {
color: #009a29;
background: #e8f5e9;
}
&.active {
color: #fff;
background: #009a29;
.t-button {
flex: 1;
}
}
@ -364,6 +555,16 @@ export default {
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
transition: transform 0.3s, box-shadow 0.3s;
&:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
}
.card-header {
margin-bottom: 12px;
}
.demand-title {
@ -379,30 +580,53 @@ export default {
}
.demand-company {
margin-bottom: 12px;
font-size: 14px;
color: #666;
}
.demand-tags {
.card-content {
flex: 1;
margin-bottom: 12px;
}
.card-tags {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 12px;
}
.demand-tag {
padding: 4px 8px;
.tag {
padding: 2px 8px;
font-size: 12px;
color: #2e7d32;
background: #e4f4e6;
border-radius: 2px;
background: #dcf9e2;
border-radius: 4px;
}
.demand-budget {
.card-desc {
display: box;
margin-bottom: 16px;
overflow: hidden;
font-size: 14px;
line-height: 1.6;
color: #666;
text-overflow: ellipsis;
-webkit-line-clamp: 3;
box-orient: vertical;
}
.card-footer {
display: flex;
align-items: center;
justify-content: space-between;
padding-top: 14px;
border-top: 1px dashed #979797;
}
.card-budget {
display: flex;
align-items: center;
margin-bottom: 12px;
}
.budget-label {
@ -417,32 +641,21 @@ export default {
color: #D25F00;
}
.demand-desc {
margin-bottom: 16px;
font-size: 14px;
line-height: 1.6;
color: #666;
flex-grow: 1;
}
.demand-validity {
//
.empty-state {
display: flex;
margin-bottom: 16px;
min-height: 300px;
font-size: 14px;
color: #999;
align-items: center;
gap: 6px;
justify-content: center;
}
.calendar-icon {
width: 16px;
height: 16px;
}
.demand-action {
.t-button {
width: 100%;
}
//
.pagination-box {
display: flex;
justify-content: center;
padding-top: 32px;
}
//
@ -452,11 +665,18 @@ export default {
}
.dialog-line-title {
margin-right: 8px;
flex-shrink: 0;
width: 80px;
color: #333;
}
.dialog-line-text {
color: #666;
}
@media (max-width: 1200px) {
.demand-grid {
grid-template-columns: 1fr;
}
}
</style>

View File

@ -5,7 +5,6 @@
<!-- 主页面 -->
<div class="container">
<div>asdf</div>
<!-- 顶部风力发电机图片 -->
<div class="top-box">
<div class="top-title">

View File

@ -95,54 +95,54 @@ const configureWebpackPlugin = [];
/**
* 本地开发启用hard-source-webpack-plugin
*/
// if (LOCAL_DEV) {
// console.log('====>> 启动本地开发缓存');
// configureWebpackPlugin.push(
// new HardSourceWebpackPlugin({
// // 缓存目录,支持相对目录或绝对目录
// // 如果有设置VUE_APP_HARD_SOURCE_FOLDER目录则使用设置值
// // 一般在coding流水线编译使用把缓存设置到`/data/npm/`中,不会丢失
// cacheDirectory: `${
// (process.env.VUE_APP_HARD_SOURCE_FOLDER && path.join(process.env.VUE_APP_HARD_SOURCE_FOLDER, '/')) ||
// path.join(process.cwd(), 'node_modules', '/')
// }.cache/hard-source/[confighash]`,
// // 基于package.json中的name来生成不同的hash串用于cacheDirectory的目录
// // @param webpackConfig
// configHash(webpackConfig) {
// return require('node-object-hash')({ sort: false }).hash({ packageName, ...webpackConfig });
// },
// // 根据目录中的lock文件来决定是否重设缓存如果设置false则需要手动删除
// environmentHash: {
// root: process.cwd(),
// directories: [],
// files: ['package-lock.json', 'yarn.lock'],
// },
// info: {
// // 'none' or 'test'.
// mode: 'none',
// // 'debug', 'log', 'info', 'warn', or 'error'.
// level: 'debug',
// },
// // 自动清除过期、过大缓存
// cachePrune: {
// // 缓存时间默认7天
// maxAge: 7 * 24 * 60 * 60 * 1000,
// // 超过该处设置的阈值默认500MB则自动删除缓存
// sizeThreshold: 500 * 1024 * 1024,
// },
// }),
// new HardSourceWebpackPlugin.ExcludeModulePlugin([
// {
// // HardSource works with mini-css-extract-plugin but due to how
// // mini-css emits assets, assets are not emitted on repeated builds with
// // mini-css and hard-source together. Ignoring the mini-css loader
// // modules, but not the other css loader modules, excludes the modules
// // that mini-css needs rebuilt to output assets every time.
// test: /mini-css-extract-plugin[\\/]dist[\\/]loader/,
// },
// ]),
// );
// }
if (LOCAL_DEV) {
console.log('====>> 启动本地开发缓存');
configureWebpackPlugin.push(
new HardSourceWebpackPlugin({
// 缓存目录,支持相对目录或绝对目录
// 如果有设置VUE_APP_HARD_SOURCE_FOLDER目录则使用设置值
// 一般在coding流水线编译使用把缓存设置到`/data/npm/`中,不会丢失
cacheDirectory: `${
(process.env.VUE_APP_HARD_SOURCE_FOLDER && path.join(process.env.VUE_APP_HARD_SOURCE_FOLDER, '/')) ||
path.join(process.cwd(), 'node_modules', '/')
}.cache/hard-source/[confighash]`,
// 基于package.json中的name来生成不同的hash串用于cacheDirectory的目录
// @param webpackConfig
configHash(webpackConfig) {
return require('node-object-hash')({ sort: false }).hash({ packageName, ...webpackConfig });
},
// 根据目录中的lock文件来决定是否重设缓存如果设置false则需要手动删除
environmentHash: {
root: process.cwd(),
directories: [],
files: ['package-lock.json', 'yarn.lock'],
},
info: {
// 'none' or 'test'.
mode: 'none',
// 'debug', 'log', 'info', 'warn', or 'error'.
level: 'debug',
},
// 自动清除过期、过大缓存
cachePrune: {
// 缓存时间默认7天
maxAge: 7 * 24 * 60 * 60 * 1000,
// 超过该处设置的阈值默认500MB则自动删除缓存
sizeThreshold: 500 * 1024 * 1024,
},
}),
new HardSourceWebpackPlugin.ExcludeModulePlugin([
{
// HardSource works with mini-css-extract-plugin but due to how
// mini-css emits assets, assets are not emitted on repeated builds with
// mini-css and hard-source together. Ignoring the mini-css loader
// modules, but not the other css loader modules, excludes the modules
// that mini-css needs rebuilt to output assets every time.
test: /mini-css-extract-plugin[\\/]dist[\\/]loader/,
},
]),
);
}
if (isExtract) {
configureWebpackPlugin.push(
@ -290,6 +290,14 @@ module.exports = {
target: 'http://carbon.liantu.tech',
changeOrigin: true,
},
'^/gxzx': {
target: 'http://carbon.liantu.tech',
changeOrigin: true,
},
'^/yygl': {
target: 'http://carbon.liantu.tech',
changeOrigin: true,
},
},
before(app) {
if (process.env.VUE_APP_MOCK === 'true') {