feat: 搜索页开发
This commit is contained in:
parent
78a531f7d1
commit
f584a9fec2
@ -26,7 +26,8 @@
|
|||||||
"Bash(sed -i 's/com\\\\.css\\\\.txw\\\\.gxzx\\\\.pojo\\\\.vo\\\\.lsjr/com.css.txw.mhzc.pojo.vo.gxzx.lsjr/g' \"E:/00项目/T_碳信网/code/txw/txw-mhzc/txw-mhzc-service-biz/src/main/java/com/css/txw/mhzc/pojo/vo/gxzx/lsjr/ProductApplyVO.java\")",
|
"Bash(sed -i 's/com\\\\.css\\\\.txw\\\\.gxzx\\\\.pojo\\\\.vo\\\\.lsjr/com.css.txw.mhzc.pojo.vo.gxzx.lsjr/g' \"E:/00项目/T_碳信网/code/txw/txw-mhzc/txw-mhzc-service-biz/src/main/java/com/css/txw/mhzc/pojo/vo/gxzx/lsjr/ProductApplyVO.java\")",
|
||||||
"Bash(\"/d/Program Files/apache-maven/apache-maven-3.6.3/bin/mvn\" compile -pl txw-mhzc-service-biz -am)",
|
"Bash(\"/d/Program Files/apache-maven/apache-maven-3.6.3/bin/mvn\" compile -pl txw-mhzc-service-biz -am)",
|
||||||
"Bash(\"/d/Program Files/apache-maven/apache-maven-3.6.3/bin/mvn\" clean package -pl txw-mhzc-service-biz -am -DskipTests)",
|
"Bash(\"/d/Program Files/apache-maven/apache-maven-3.6.3/bin/mvn\" clean package -pl txw-mhzc-service-biz -am -DskipTests)",
|
||||||
"Bash(\"/d/Program Files/jdk8/bin/java\" -Xms256m -Xmx512m -Duser.timezone=Asia/Shanghai -jar target/txw-mhzc-service-biz.jar --spring.profiles.active=local)"
|
"Bash(\"/d/Program Files/jdk8/bin/java\" -Xms256m -Xmx512m -Duser.timezone=Asia/Shanghai -jar target/txw-mhzc-service-biz.jar --spring.profiles.active=local)",
|
||||||
|
"Bash(mvn compile *)"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,6 +43,7 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
handleClick() {
|
handleClick() {
|
||||||
if (this.result.url) {
|
if (this.result.url) {
|
||||||
|
// 后端返回的URL已包含id参数,直接跳转
|
||||||
window.location.href = this.result.url;
|
window.location.href = this.result.url;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -94,6 +94,7 @@
|
|||||||
<div
|
<div
|
||||||
v-for="(card, index) in cardList"
|
v-for="(card, index) in cardList"
|
||||||
:key="card.gxUuid"
|
:key="card.gxUuid"
|
||||||
|
:data-gx-uuid="card.gxUuid"
|
||||||
class="service-card"
|
class="service-card"
|
||||||
>
|
>
|
||||||
<!-- 卡片头部 -->
|
<!-- 卡片头部 -->
|
||||||
@ -292,6 +293,12 @@ export default {
|
|||||||
if (this.$route.query.publish === '1') {
|
if (this.$route.query.publish === '1') {
|
||||||
this.handlePublish();
|
this.handlePublish();
|
||||||
}
|
}
|
||||||
|
// 如果URL有id参数,等待数据加载后定位到对应项
|
||||||
|
if (this.$route.query.id) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.scrollToItem(this.$route.query.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 初始化用户信息
|
// 初始化用户信息
|
||||||
@ -419,11 +426,24 @@ export default {
|
|||||||
this.page.pageNo = 1;
|
this.page.pageNo = 1;
|
||||||
this.searchList();
|
this.searchList();
|
||||||
},
|
},
|
||||||
// 分页变化
|
// 滚动到指定项并高亮
|
||||||
onPageChange(pageInfo) {
|
scrollToItem(gxUuid) {
|
||||||
this.page.pageNo = pageInfo.current;
|
this.$nextTick(() => {
|
||||||
this.page.pageSize = pageInfo.pageSize;
|
const targetCard = this.cardList.find(card => card.gxUuid === gxUuid);
|
||||||
this.searchList();
|
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() {
|
handlePublish() {
|
||||||
@ -804,6 +824,10 @@ export default {
|
|||||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&.highlight-card {
|
||||||
|
animation: highlight-pulse 3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
@ -1124,4 +1148,16 @@ export default {
|
|||||||
font-size: 18px;
|
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>
|
</style>
|
||||||
|
|||||||
@ -86,6 +86,7 @@
|
|||||||
<div
|
<div
|
||||||
v-for="card in cardList"
|
v-for="card in cardList"
|
||||||
:key="card.gxUuid"
|
:key="card.gxUuid"
|
||||||
|
:data-gx-uuid="card.gxUuid"
|
||||||
class="demand-card"
|
class="demand-card"
|
||||||
>
|
>
|
||||||
<!-- 卡片头部 -->
|
<!-- 卡片头部 -->
|
||||||
@ -261,6 +262,12 @@ export default {
|
|||||||
if (this.$route.query.publish === '1') {
|
if (this.$route.query.publish === '1') {
|
||||||
this.handlePublish();
|
this.handlePublish();
|
||||||
}
|
}
|
||||||
|
// 如果URL有id参数,等待数据加载后定位到对应项
|
||||||
|
if (this.$route.query.id) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.scrollToItem(this.$route.query.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 加载代码表
|
// 加载代码表
|
||||||
@ -345,11 +352,21 @@ export default {
|
|||||||
this.page.pageNo = 1;
|
this.page.pageNo = 1;
|
||||||
this.searchList();
|
this.searchList();
|
||||||
},
|
},
|
||||||
// 分页变化
|
// 滚动到指定项并高亮
|
||||||
onPageChange(pageInfo) {
|
scrollToItem(gxUuid) {
|
||||||
this.page.pageNo = pageInfo.current;
|
this.$nextTick(() => {
|
||||||
this.page.pageSize = pageInfo.pageSize;
|
const targetCard = this.cardList.find(card => card.gxUuid === gxUuid);
|
||||||
this.searchList();
|
if (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() {
|
handlePublish() {
|
||||||
@ -705,6 +722,10 @@ export default {
|
|||||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&.highlight-card {
|
||||||
|
animation: highlight-pulse 3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
@ -1028,4 +1049,16 @@ export default {
|
|||||||
font-size: 18px;
|
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>
|
</style>
|
||||||
|
|||||||
@ -48,16 +48,12 @@
|
|||||||
<div class="top-search-box">
|
<div class="top-search-box">
|
||||||
<div class="search-box">
|
<div class="search-box">
|
||||||
<input type="text" v-model="inputValue" placeholder="搜索碳资产、企业、服务" />
|
<input type="text" v-model="inputValue" placeholder="搜索碳资产、企业、服务" />
|
||||||
<div class="search-btn">
|
<div class="search-btn" @click="handleSearch">
|
||||||
搜索
|
搜索
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="top-search-hot">
|
<div class="top-search-hot">
|
||||||
<div class="hot-tag">电厂配额</div>
|
<div class="hot-tag" v-for="(tag, index) in hotSearchTags" :key="index" @click="handleHotSearch(tag)">{{ tag }}</div>
|
||||||
<div class="hot-tag">林业碳汇开发</div>
|
|
||||||
<div class="hot-tag">CBAM 报告</div>
|
|
||||||
<div class="hot-tag">2025年度碳报告</div>
|
|
||||||
<div class="hot-tag">光伏发展</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -359,7 +355,7 @@ export default {
|
|||||||
icon: require('@/pages/index/views/home2/assets/closed-loop@2x.png')
|
icon: require('@/pages/index/views/home2/assets/closed-loop@2x.png')
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
inputValue: "",
|
hotSearchTags: ["碳核查", "ESG", "碳资产管理", "ISO 14067"],
|
||||||
// 企业出海数据
|
// 企业出海数据
|
||||||
overseas2List: [
|
overseas2List: [
|
||||||
{ name: '电池法案', btnName: "申请服务", desc: "欧盟电池法案管控电池全生命周期,涉及回收、碳足迹等要求。", icon: require('@/pages/index/assets/home-dcfa-icon.png') },
|
{ name: '电池法案', btnName: "申请服务", desc: "欧盟电池法案管控电池全生命周期,涉及回收、碳足迹等要求。", icon: require('@/pages/index/assets/home-dcfa-icon.png') },
|
||||||
@ -514,14 +510,12 @@ export default {
|
|||||||
// 快捷搜索
|
// 快捷搜索
|
||||||
handleSearch() {
|
handleSearch() {
|
||||||
if (this.inputValue) {
|
if (this.inputValue) {
|
||||||
console.log('搜索:', this.inputValue);
|
this.$router.push({ path: '/search', query: { keyword: this.inputValue } });
|
||||||
// TODO: 实现搜索功能
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 处理热门搜索点击
|
// 处理热门搜索点击
|
||||||
handleHotSearch(keyword) {
|
handleHotSearch(keyword) {
|
||||||
this.inputValue = keyword;
|
this.$router.push({ path: '/search', query: { keyword: keyword } });
|
||||||
this.handleSearch();
|
|
||||||
},
|
},
|
||||||
// 企业出海点击
|
// 企业出海点击
|
||||||
handleOverseasClick(item) {
|
handleOverseasClick(item) {
|
||||||
@ -799,6 +793,14 @@ export default {
|
|||||||
padding: 4px 12px;
|
padding: 4px 12px;
|
||||||
color: #333;
|
color: #333;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(0, 185, 107, 0.4);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-box-bottom-over {
|
.top-box-bottom-over {
|
||||||
|
|||||||
@ -228,6 +228,7 @@ export default {
|
|||||||
}
|
}
|
||||||
let params={
|
let params={
|
||||||
captchaVerification:this.loginForm.captchaVerification,
|
captchaVerification:this.loginForm.captchaVerification,
|
||||||
|
captchaCode:this.loginForm.captchaCode,
|
||||||
sjhm1:this.loginForm.dlzh,
|
sjhm1:this.loginForm.dlzh,
|
||||||
}
|
}
|
||||||
sendMsg(params).then((res) => {
|
sendMsg(params).then((res) => {
|
||||||
|
|||||||
@ -20,20 +20,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</t-input>
|
</t-input>
|
||||||
</t-form-item>
|
</t-form-item>
|
||||||
<t-form-item class="verification-code" name="sms">
|
|
||||||
<t-input v-model="loginForm.sms" size="large" placeholder="请输入短信验证码" key="verifyCode" />
|
|
||||||
<t-button :disabled="countDown > 0" @click="handleCounter">
|
|
||||||
{{ countDown === 0 ? '发送验证码' : `${countDown}秒后可重发` }}
|
|
||||||
</t-button>
|
|
||||||
</t-form-item>
|
|
||||||
<!-- 滑块验证区域(已注释,保留以便回滚) -->
|
|
||||||
<!--
|
|
||||||
<t-form-item name="captchaVerification" user-select:none>
|
|
||||||
<div class="drag" ref="dragDiv" v-if="iscxhk">...</div>
|
|
||||||
<div class="drag" ref="dragDiv" v-else>...</div>
|
|
||||||
</t-form-item>
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!-- 新增:图形验证码 -->
|
<!-- 新增:图形验证码 -->
|
||||||
<t-form-item name="captchaCode">
|
<t-form-item name="captchaCode">
|
||||||
<div class="captcha-wrapper">
|
<div class="captcha-wrapper">
|
||||||
@ -52,6 +39,20 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</t-form-item>
|
</t-form-item>
|
||||||
|
<t-form-item class="verification-code" name="sms">
|
||||||
|
<t-input v-model="loginForm.sms" size="large" placeholder="请输入短信验证码" key="verifyCode" />
|
||||||
|
<t-button :disabled="countDown > 0" @click="handleCounter">
|
||||||
|
{{ countDown === 0 ? '发送验证码' : `${countDown}秒后可重发` }}
|
||||||
|
</t-button>
|
||||||
|
</t-form-item>
|
||||||
|
<!-- 滑块验证区域(已注释,保留以便回滚) -->
|
||||||
|
<!--
|
||||||
|
<t-form-item name="captchaVerification" user-select:none>
|
||||||
|
<div class="drag" ref="dragDiv" v-if="iscxhk">...</div>
|
||||||
|
<div class="drag" ref="dragDiv" v-else>...</div>
|
||||||
|
</t-form-item>
|
||||||
|
-->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<t-form-item class="btn-container">
|
<t-form-item class="btn-container">
|
||||||
<t-button class="btn-container" block size="large" type="submit"> 登录</t-button>
|
<t-button class="btn-container" block size="large" type="submit"> 登录</t-button>
|
||||||
@ -176,6 +177,7 @@ handleCounter() {
|
|||||||
this.startCountDown();
|
this.startCountDown();
|
||||||
let params = {
|
let params = {
|
||||||
captchaVerification: this.loginForm.captchaVerification,
|
captchaVerification: this.loginForm.captchaVerification,
|
||||||
|
captchaCode: this.loginForm.captchaCode,
|
||||||
sjhm1: this.loginForm.sjhm,
|
sjhm1: this.loginForm.sjhm,
|
||||||
}
|
}
|
||||||
sendMsg(params).then((res) => {
|
sendMsg(params).then((res) => {
|
||||||
|
|||||||
@ -1,63 +1,191 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="search-page">
|
<div class="search-page">
|
||||||
<!-- 顶部导航 (复用现有组件) -->
|
<!-- 搜索区域背景 -->
|
||||||
<Nav :isyhxx="false" />
|
<div class="search-hero">
|
||||||
|
<div class="hero-bg-overlay"></div>
|
||||||
|
<div class="hero-content">
|
||||||
|
<h1 class="hero-title">搜索碳资产、企业、服务</h1>
|
||||||
|
<p class="hero-subtitle">一站式碳信息搜索平台,快速定位所需内容</p>
|
||||||
|
|
||||||
<!-- 搜索区域 -->
|
<!-- 搜索框 -->
|
||||||
<SearchArea @search="handleSearch" />
|
<div class="search-box">
|
||||||
|
<div class="search-input-wrapper">
|
||||||
|
<t-select
|
||||||
|
v-model="selectedCategory"
|
||||||
|
:options="categoryOptions"
|
||||||
|
placeholder="全部分类"
|
||||||
|
@change="handleCategoryChange"
|
||||||
|
class="category-select"
|
||||||
|
/>
|
||||||
|
<t-input
|
||||||
|
v-model="keyword"
|
||||||
|
placeholder="输入关键词搜索..."
|
||||||
|
@enter="handleSearch"
|
||||||
|
@input="handleInput"
|
||||||
|
class="keyword-input"
|
||||||
|
>
|
||||||
|
<template #suffix-icon>
|
||||||
|
<t-icon name="search" class="search-icon" />
|
||||||
|
</template>
|
||||||
|
</t-input>
|
||||||
|
</div>
|
||||||
|
<t-button theme="primary" class="search-btn" @click="handleSearch">
|
||||||
|
搜索
|
||||||
|
</t-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 搜索历史 -->
|
<!-- 热门搜索 -->
|
||||||
<SearchHistoryBar
|
<div class="hot-search" v-if="hotSearchList.length > 0">
|
||||||
:historyList="searchHistory"
|
<span class="hot-label">热门:</span>
|
||||||
@select="handleHistorySelect"
|
<t-tag
|
||||||
@clear="handleClearHistory"
|
v-for="(item, index) in hotSearchList"
|
||||||
/>
|
:key="index"
|
||||||
|
class="hot-item"
|
||||||
|
@click="handleHotClick(item)"
|
||||||
|
>
|
||||||
|
{{ item }}
|
||||||
|
</t-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 分类 Tab -->
|
<!-- 搜索结果区域 -->
|
||||||
<SearchCategoryTabs
|
<div class="search-results-wrapper">
|
||||||
:currentTab="currentCategory"
|
<!-- 搜索历史 -->
|
||||||
:categoryCount="categoryCount"
|
<div class="history-section" v-if="searchHistory.length > 0 && !keyword">
|
||||||
@change="handleCategoryChange"
|
<div class="section-header">
|
||||||
/>
|
<span class="section-title">
|
||||||
|
<i class="title-icon"></i>
|
||||||
|
搜索历史
|
||||||
|
</span>
|
||||||
|
<span class="clear-btn" @click="handleClearHistory">清空</span>
|
||||||
|
</div>
|
||||||
|
<div class="history-tags">
|
||||||
|
<t-tag
|
||||||
|
v-for="(item, index) in searchHistory"
|
||||||
|
:key="index"
|
||||||
|
class="history-tag"
|
||||||
|
variant="light"
|
||||||
|
@click="handleHistorySelect(item)"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<t-icon name="history" class="tag-icon" />
|
||||||
|
</template>
|
||||||
|
{{ item }}
|
||||||
|
</t-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 搜索结果列表 -->
|
<!-- 分类 Tab -->
|
||||||
<SearchResultList
|
<div class="category-tabs" v-if="keyword || resultList.length > 0">
|
||||||
:list="resultList"
|
<div class="tabs-header">
|
||||||
:total="total"
|
<span class="tabs-title">
|
||||||
:pageSize="pageSize"
|
<i class="title-icon"></i>
|
||||||
:loading="loading"
|
搜索结果
|
||||||
:keyword="keyword"
|
<span class="result-count" v-if="total > 0">约 {{ total }} 条</span>
|
||||||
@page-change="handlePageChange"
|
</span>
|
||||||
/>
|
<div class="tabs-wrapper">
|
||||||
|
<div
|
||||||
|
v-for="tab in categoryTabs"
|
||||||
|
:key="tab.value"
|
||||||
|
:class="['tab-item', { active: currentCategory === tab.value }]"
|
||||||
|
@click="handleCategoryChange(tab.value)"
|
||||||
|
>
|
||||||
|
<span class="tab-name">{{ tab.label }}</span>
|
||||||
|
<span class="tab-count" v-if="categoryCount[tab.value]">{{ categoryCount[tab.value] }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 搜索结果列表 -->
|
||||||
|
<div class="results-container" v-if="keyword">
|
||||||
|
<!-- 加载状态 -->
|
||||||
|
<div v-if="loading" class="loading-state">
|
||||||
|
<t-loading size="large" text="搜索中..." />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 空状态 -->
|
||||||
|
<div v-else-if="resultList.length === 0" class="empty-state">
|
||||||
|
<div class="empty-icon">
|
||||||
|
<t-icon name="search" />
|
||||||
|
</div>
|
||||||
|
<p class="empty-text">未找到相关结果</p>
|
||||||
|
<p class="empty-hint">换个关键词试试,或浏览热门内容</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 结果列表 -->
|
||||||
|
<div v-else class="result-list">
|
||||||
|
<div
|
||||||
|
v-for="item in resultList"
|
||||||
|
:key="item.id"
|
||||||
|
class="result-item"
|
||||||
|
@click="handleResultClick(item)"
|
||||||
|
>
|
||||||
|
<div class="result-header">
|
||||||
|
<t-tag :style="getCategoryStyle(item.categoryType)" size="small">
|
||||||
|
{{ item.category }}
|
||||||
|
</t-tag>
|
||||||
|
<span class="result-date" v-if="item.publishTime">{{ formatDate(item.publishTime) }}</span>
|
||||||
|
</div>
|
||||||
|
<h3 class="result-title" v-html="item.title"></h3>
|
||||||
|
<p class="result-summary" v-html="item.summary"></p>
|
||||||
|
<div class="result-footer">
|
||||||
|
<span class="result-source" v-if="item.source">
|
||||||
|
<t-icon name="enterprise" class="source-icon" />
|
||||||
|
{{ item.source }}
|
||||||
|
</span>
|
||||||
|
<t-link theme="primary" class="result-link" @click="handleResultClick(item)">
|
||||||
|
查看详情
|
||||||
|
<template #suffixIcon>
|
||||||
|
<t-icon name="arrow-right" class="link-icon" />
|
||||||
|
</template>
|
||||||
|
</t-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分页 -->
|
||||||
|
<div class="pagination-wrapper" v-if="total > pageSize">
|
||||||
|
<t-pagination
|
||||||
|
v-model="currentPage"
|
||||||
|
:total="total"
|
||||||
|
:page-size="pageSize"
|
||||||
|
@change="handlePageChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 底部版权 -->
|
<!-- 底部版权 -->
|
||||||
<div class="footer">
|
<Footer />
|
||||||
<p>版权信息等</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Nav from '@/pages/index/components/nav/index.vue';
|
import Footer from '@/pages/index/components/footer/index.vue';
|
||||||
import SearchArea from '@/pages/index/components/search/SearchArea.vue';
|
|
||||||
import SearchHistoryBar from '@/pages/index/components/search/SearchHistoryBar.vue';
|
|
||||||
import SearchCategoryTabs from '@/pages/index/components/search/SearchCategoryTabs.vue';
|
|
||||||
import SearchResultList from '@/pages/index/components/search/SearchResultList.vue';
|
|
||||||
import searchApi from '@/pages/index/api/search.js';
|
import searchApi from '@/pages/index/api/search.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SearchPage',
|
name: 'SearchPage',
|
||||||
components: {
|
components: {
|
||||||
Nav,
|
Footer,
|
||||||
SearchArea,
|
|
||||||
SearchHistoryBar,
|
|
||||||
SearchCategoryTabs,
|
|
||||||
SearchResultList,
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
keyword: '',
|
keyword: '',
|
||||||
currentCategory: 'all',
|
selectedCategory: 'all',
|
||||||
|
categoryOptions: [
|
||||||
|
{ label: '全部分类', value: 'all' },
|
||||||
|
{ label: '碳证中心', value: 'carbon_cert' },
|
||||||
|
{ label: '服务中心', value: 'service' },
|
||||||
|
{ label: '行业专题', value: 'news' },
|
||||||
|
],
|
||||||
|
categoryTabs: [
|
||||||
|
{ label: '全部', value: 'all' },
|
||||||
|
{ label: '行业专题', value: 'news' },
|
||||||
|
{ label: '服务中心', value: 'service' },
|
||||||
|
],
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
resultList: [],
|
resultList: [],
|
||||||
@ -65,35 +193,67 @@ export default {
|
|||||||
categoryCount: {},
|
categoryCount: {},
|
||||||
loading: false,
|
loading: false,
|
||||||
searchHistory: [],
|
searchHistory: [],
|
||||||
|
hotSearchList: [],
|
||||||
|
suggestions: [],
|
||||||
|
showSuggestion: false,
|
||||||
|
inputTimer: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.keyword = this.$route.query.keyword || '';
|
this.keyword = this.$route.query.keyword || '';
|
||||||
this.currentCategory = this.$route.query.category || 'all';
|
this.currentCategory = this.$route.query.category || 'all';
|
||||||
|
|
||||||
this.loadSearchHistory();
|
this.loadSearchHistory();
|
||||||
|
this.loadHotSearch();
|
||||||
if (this.keyword) {
|
if (this.keyword) {
|
||||||
this.doSearch();
|
this.doSearch();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleSearch(params) {
|
handleSearch() {
|
||||||
this.keyword = params.keyword;
|
if (!this.keyword.trim()) {
|
||||||
this.currentCategory = params.categoryType;
|
this.$message.warning('请输入搜索关键词');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.showSuggestion = false;
|
||||||
|
this.currentCategory = this.selectedCategory;
|
||||||
this.currentPage = 1;
|
this.currentPage = 1;
|
||||||
|
|
||||||
this.$router.push({
|
this.$router.push({
|
||||||
query: {
|
query: {
|
||||||
keyword: this.keyword,
|
keyword: this.keyword,
|
||||||
category: this.currentCategory,
|
category: this.currentCategory,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
this.saveSearchHistory(this.keyword);
|
this.saveSearchHistory(this.keyword);
|
||||||
|
|
||||||
this.doSearch();
|
this.doSearch();
|
||||||
},
|
},
|
||||||
|
handleInput(value) {
|
||||||
|
if (this.inputTimer) {
|
||||||
|
clearTimeout(this.inputTimer);
|
||||||
|
}
|
||||||
|
if (!value.trim()) {
|
||||||
|
this.showSuggestion = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.inputTimer = setTimeout(() => {
|
||||||
|
this.loadSuggestions(value);
|
||||||
|
}, 300);
|
||||||
|
},
|
||||||
|
handleCategoryChange(value) {
|
||||||
|
this.currentCategory = value || this.selectedCategory;
|
||||||
|
this.currentPage = 1;
|
||||||
|
this.$router.push({
|
||||||
|
query: {
|
||||||
|
keyword: this.keyword,
|
||||||
|
category: this.currentCategory,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.doSearch();
|
||||||
|
},
|
||||||
|
handlePageChange(pageInfo) {
|
||||||
|
this.currentPage = pageInfo.current;
|
||||||
|
this.doSearch();
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
},
|
||||||
handleHistorySelect(keyword) {
|
handleHistorySelect(keyword) {
|
||||||
this.keyword = keyword;
|
this.keyword = keyword;
|
||||||
this.doSearch();
|
this.doSearch();
|
||||||
@ -102,23 +262,14 @@ export default {
|
|||||||
this.searchHistory = [];
|
this.searchHistory = [];
|
||||||
searchApi.clearSearchHistory();
|
searchApi.clearSearchHistory();
|
||||||
},
|
},
|
||||||
handleCategoryChange(category) {
|
handleHotClick(keyword) {
|
||||||
this.currentCategory = category;
|
this.keyword = keyword;
|
||||||
this.currentPage = 1;
|
this.handleSearch();
|
||||||
|
|
||||||
this.$router.push({
|
|
||||||
query: {
|
|
||||||
keyword: this.keyword,
|
|
||||||
category: this.currentCategory,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
this.doSearch();
|
|
||||||
},
|
},
|
||||||
handlePageChange(page) {
|
handleResultClick(item) {
|
||||||
this.currentPage = page;
|
if (item.url) {
|
||||||
this.doSearch();
|
window.location.href = item.url;
|
||||||
window.scrollTo(0, 0);
|
}
|
||||||
},
|
},
|
||||||
async doSearch() {
|
async doSearch() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
@ -129,7 +280,6 @@ export default {
|
|||||||
page: this.currentPage,
|
page: this.currentPage,
|
||||||
pageSize: this.pageSize,
|
pageSize: this.pageSize,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res && res.data) {
|
if (res && res.data) {
|
||||||
this.resultList = res.data.list || [];
|
this.resultList = res.data.list || [];
|
||||||
this.total = res.data.total || 0;
|
this.total = res.data.total || 0;
|
||||||
@ -155,21 +305,55 @@ export default {
|
|||||||
},
|
},
|
||||||
saveSearchHistory(keyword) {
|
saveSearchHistory(keyword) {
|
||||||
if (!keyword) return;
|
if (!keyword) return;
|
||||||
|
|
||||||
this.searchHistory = this.searchHistory.filter((k) => k !== keyword);
|
this.searchHistory = this.searchHistory.filter((k) => k !== keyword);
|
||||||
|
|
||||||
this.searchHistory.unshift(keyword);
|
this.searchHistory.unshift(keyword);
|
||||||
|
|
||||||
if (this.searchHistory.length > 10) {
|
if (this.searchHistory.length > 10) {
|
||||||
this.searchHistory = this.searchHistory.slice(0, 10);
|
this.searchHistory = this.searchHistory.slice(0, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
localStorage.setItem('searchHistory', JSON.stringify(this.searchHistory));
|
localStorage.setItem('searchHistory', JSON.stringify(this.searchHistory));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('保存搜索历史失败', e);
|
console.error('保存搜索历史失败', e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async loadHotSearch() {
|
||||||
|
try {
|
||||||
|
const res = await searchApi.getHotSearch();
|
||||||
|
if (res && res.data) {
|
||||||
|
this.hotSearchList = res.data;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载热门搜索失败', error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async loadSuggestions(keyword) {
|
||||||
|
try {
|
||||||
|
const res = await searchApi.getSuggest(keyword);
|
||||||
|
if (res && res.data && res.data.suggestions) {
|
||||||
|
this.suggestions = res.data.suggestions;
|
||||||
|
this.showSuggestion = this.suggestions.length > 0;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载搜索建议失败', error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getCategoryStyle(type) {
|
||||||
|
if (type === 'news') {
|
||||||
|
return { theme: 'primary', variant: 'light' };
|
||||||
|
} else if (type === 'service') {
|
||||||
|
return { theme: 'success', variant: 'light' };
|
||||||
|
}
|
||||||
|
return { theme: 'default', variant: 'light' };
|
||||||
|
},
|
||||||
|
formatDate(dateStr) {
|
||||||
|
if (!dateStr) return '';
|
||||||
|
try {
|
||||||
|
const date = new Date(dateStr);
|
||||||
|
return date.toLocaleDateString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit' });
|
||||||
|
} catch {
|
||||||
|
return dateStr;
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@ -177,19 +361,515 @@ export default {
|
|||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.search-page {
|
.search-page {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background-color: #fff;
|
background-color: #f5f7fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
// 搜索英雄区域
|
||||||
background-color: #f5f5f5;
|
.search-hero {
|
||||||
padding: 24px 0;
|
position: relative;
|
||||||
text-align: center;
|
background: linear-gradient(135deg, #007242 0%, #009a29 50%, #00b96b 100%);
|
||||||
margin-top: 40px;
|
padding: 80px 20px 60px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
p {
|
&::before {
|
||||||
margin: 0;
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: url('~@/pages/index/assets/home-top-bg1.jpg') center/cover no-repeat;
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-bg-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: linear-gradient(180deg, rgba(0, 114, 66, 0.9) 0%, rgba(0, 154, 41, 0.85) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-content {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-title {
|
||||||
|
font-size: 36px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #ffffff;
|
||||||
|
margin: 0 0 12px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-subtitle {
|
||||||
|
font-size: 16px;
|
||||||
|
color: rgba(255, 255, 255, 0.85);
|
||||||
|
margin: 0 0 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索框
|
||||||
|
.search-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
gap: 0;
|
||||||
|
background: rgba(255, 255, 255, 0.95);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 6px;
|
||||||
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
gap: 0;
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-select {
|
||||||
|
width: 130px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border: none !important;
|
||||||
|
border-radius: 6px 0 0 6px !important;
|
||||||
|
background: #f5f7fa !important;
|
||||||
|
|
||||||
|
::v-deep .t-input__inner {
|
||||||
|
text-align: center !important;
|
||||||
|
background-color: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .t-select__wrap {
|
||||||
|
border: none !important;
|
||||||
|
border-radius: 6px 0 0 6px !important;
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .t-input {
|
||||||
|
border: none !important;
|
||||||
|
border-radius: 6px 0 0 6px !important;
|
||||||
|
background: #f5f7fa !important;
|
||||||
|
text-align: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .t-input__value {
|
||||||
|
text-align: center !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.keyword-input {
|
||||||
|
flex: 1;
|
||||||
|
border: none !important;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
background: #fff !important;
|
||||||
|
|
||||||
|
::v-deep .t-input {
|
||||||
|
border: none !important;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
background: transparent !important;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn {
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-radius: 6px !important;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 热门搜索
|
||||||
|
.hot-search {
|
||||||
|
margin-top: 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
.hot-label {
|
||||||
|
margin-right: 4px;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-item {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
background: rgba(255, 255, 255, 0.15) !important;
|
||||||
|
border-color: rgba(255, 255, 255, 0.3) !important;
|
||||||
|
color: #fff !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(0, 185, 107, 0.4) !important;
|
||||||
|
border-color: rgba(0, 185, 107, 0.6) !important;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索结果区域
|
||||||
|
.search-results-wrapper {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索历史
|
||||||
|
.history-section {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px 24px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
|
||||||
|
.title-icon {
|
||||||
|
width: 4px;
|
||||||
|
height: 16px;
|
||||||
|
background: linear-gradient(180deg, #00b42a, #00d468);
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.clear-btn {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #999;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-tag {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #e8f5e9 !important;
|
||||||
|
color: #009a29 !important;
|
||||||
|
border-color: #009a29 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-icon {
|
||||||
|
font-size: 14px;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分类标签
|
||||||
|
.category-tabs {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px 24px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
|
||||||
|
.title-icon {
|
||||||
|
width: 4px;
|
||||||
|
height: 16px;
|
||||||
|
background: linear-gradient(180deg, #00b42a, #00d468);
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-count {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #999;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs-wrapper {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 20px;
|
||||||
|
background: #f5f7fa;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #e8f5e9;
|
||||||
|
color: #009a29;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: linear-gradient(135deg, #009a29, #00b96b);
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 154, 41, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-count {
|
||||||
|
padding: 2px 8px;
|
||||||
|
background: rgba(255, 255, 255, 0.3);
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active .tab-count {
|
||||||
|
background: rgba(255, 255, 255, 0.25);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 结果列表
|
||||||
|
.results-container {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 24px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-state {
|
||||||
|
padding: 60px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
padding: 60px 0;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.empty-icon {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
margin: 0 auto 16px;
|
||||||
|
background: #f5f7fa;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.t-icon {
|
||||||
|
font-size: 36px;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-text {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
margin: 0 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-hint {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #999;
|
color: #999;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-item {
|
||||||
|
padding: 20px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #f0f0f0;
|
||||||
|
border-radius: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: #00b42a;
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 154, 41, 0.12);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-category {
|
||||||
|
padding: 4px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-date {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #222;
|
||||||
|
margin: 0 0 12px;
|
||||||
|
line-height: 1.5;
|
||||||
|
|
||||||
|
::v-deep em {
|
||||||
|
color: #00b42a;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-summary {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
line-height: 1.8;
|
||||||
|
margin: 0 0 16px;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
::v-deep em {
|
||||||
|
color: #00b42a;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-source {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #999;
|
||||||
|
|
||||||
|
.source-icon {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
font-size: 13px;
|
||||||
|
|
||||||
|
.link-icon {
|
||||||
|
font-size: 12px;
|
||||||
|
transition: transform 0.3s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-item:hover .result-link .link-icon {
|
||||||
|
transform: translateX(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
.pagination-wrapper {
|
||||||
|
margin-top: 32px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 响应式
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.search-hero {
|
||||||
|
padding: 60px 16px 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-title {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-subtitle {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input-wrapper {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs-wrapper {
|
||||||
|
overflow-x: auto;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-item {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-item {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-title {
|
||||||
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -30,16 +30,11 @@ public class SearchController {
|
|||||||
@Operation(summary = "搜索", description = "全站搜索")
|
@Operation(summary = "搜索", description = "全站搜索")
|
||||||
public CommonResult<Map<String, Object>> search(@Valid SearchReqVO reqVO) {
|
public CommonResult<Map<String, Object>> search(@Valid SearchReqVO reqVO) {
|
||||||
List<SearchResultVO> list = searchService.search(reqVO);
|
List<SearchResultVO> list = searchService.search(reqVO);
|
||||||
|
Map<String, Integer> categoryCount = searchService.getCategoryCount(reqVO.getKeyword());
|
||||||
|
|
||||||
Map<String, Object> result = new HashMap<>();
|
Map<String, Object> result = new HashMap<>();
|
||||||
result.put("total", list.size());
|
result.put("total", list.size());
|
||||||
result.put("list", list);
|
result.put("list", list);
|
||||||
|
|
||||||
Map<String, Integer> categoryCount = new HashMap<>();
|
|
||||||
categoryCount.put("all", list.size());
|
|
||||||
categoryCount.put("carbon_cert", 0);
|
|
||||||
categoryCount.put("service", 0);
|
|
||||||
categoryCount.put("news", list.size());
|
|
||||||
result.put("categoryCount", categoryCount);
|
result.put("categoryCount", categoryCount);
|
||||||
|
|
||||||
return CommonResult.success(result);
|
return CommonResult.success(result);
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package com.css.txw.mhzc.service;
|
|||||||
import com.css.txw.mhzc.pojo.req.SearchReqVO;
|
import com.css.txw.mhzc.pojo.req.SearchReqVO;
|
||||||
import com.css.txw.mhzc.pojo.vo.SearchResultVO;
|
import com.css.txw.mhzc.pojo.vo.SearchResultVO;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public interface SearchService {
|
public interface SearchService {
|
||||||
|
|
||||||
@ -11,6 +12,11 @@ public interface SearchService {
|
|||||||
*/
|
*/
|
||||||
List<SearchResultVO> search(SearchReqVO reqVO);
|
List<SearchResultVO> search(SearchReqVO reqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取搜索结果分类统计
|
||||||
|
*/
|
||||||
|
Map<String, Integer> getCategoryCount(String keyword);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取热门搜索词
|
* 获取热门搜索词
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
package com.css.txw.mhzc.service.impl;
|
package com.css.txw.mhzc.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.css.txw.mhzc.mapper.TxwGxzxGxxxbMapper;
|
||||||
|
import com.css.txw.mhzc.pojo.domain.TxwGxzxGxxxbDO;
|
||||||
import com.css.txw.mhzc.pojo.req.SearchReqVO;
|
import com.css.txw.mhzc.pojo.req.SearchReqVO;
|
||||||
|
import com.css.txw.mhzc.pojo.vo.GxxxVO;
|
||||||
import com.css.txw.mhzc.pojo.vo.SearchResultVO;
|
import com.css.txw.mhzc.pojo.vo.SearchResultVO;
|
||||||
import com.css.txw.mhzc.pojo.vo.SyzxxxVO;
|
import com.css.txw.mhzc.pojo.vo.SyzxxxVO;
|
||||||
import com.css.txw.mhzc.service.SearchService;
|
import com.css.txw.mhzc.service.SearchService;
|
||||||
@ -12,6 +16,7 @@ import org.springframework.util.StringUtils;
|
|||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -23,43 +28,63 @@ public class SearchServiceImpl implements SearchService {
|
|||||||
@Resource
|
@Resource
|
||||||
private TxwMhzcZxxxbService zxxxbService;
|
private TxwMhzcZxxxbService zxxxbService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TxwGxzxGxxxbMapper gxxxbMapper;
|
||||||
|
|
||||||
private static final String HIGHLIGHT_START = "<em>";
|
private static final String HIGHLIGHT_START = "<em>";
|
||||||
private static final String HIGHLIGHT_END = "</em>";
|
private static final String HIGHLIGHT_END = "</em>";
|
||||||
|
private static final String VIEW_MHZC_PREFIX = "/view/mhzc";
|
||||||
|
private static final String URL_PARAM_KEYWORD = "keyword";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<SearchResultVO> search(SearchReqVO reqVO) {
|
public List<SearchResultVO> search(SearchReqVO reqVO) {
|
||||||
Map<String, List<SyzxxxVO>> data = zxxxbService.zxxx();
|
|
||||||
List<SearchResultVO> resultList = new ArrayList<>();
|
List<SearchResultVO> resultList = new ArrayList<>();
|
||||||
String categoryType = reqVO.getCategoryType();
|
String categoryType = reqVO.getCategoryType();
|
||||||
|
String keyword = reqVO.getKeyword();
|
||||||
|
|
||||||
if (data != null) {
|
// 搜索资讯信息
|
||||||
data.forEach((category, list) -> {
|
if (!"service".equals(categoryType)) {
|
||||||
String currentCategoryType = getCategoryType(category);
|
Map<String, List<SyzxxxVO>> data = zxxxbService.zxxx();
|
||||||
if (!"all".equals(categoryType) && !categoryType.equals(currentCategoryType)) {
|
if (data != null) {
|
||||||
return;
|
data.forEach((category, list) -> {
|
||||||
}
|
String currentCategoryType = getCategoryType(category);
|
||||||
|
if (!"all".equals(categoryType) && !categoryType.equals(currentCategoryType)) {
|
||||||
list.forEach(zxxx -> {
|
return;
|
||||||
if (matchKeyword(zxxx.getBt1(), reqVO.getKeyword()) ||
|
|
||||||
matchKeyword(zxxx.getZxNr(), reqVO.getKeyword())) {
|
|
||||||
|
|
||||||
SearchResultVO vo = new SearchResultVO();
|
|
||||||
vo.setId(zxxx.getUuid());
|
|
||||||
vo.setTitle(highlightKeyword(zxxx.getBt1(), reqVO.getKeyword()));
|
|
||||||
vo.setSummary(highlightKeyword(truncate(zxxx.getZxNr(), 200), reqVO.getKeyword()));
|
|
||||||
vo.setCategory(category);
|
|
||||||
vo.setCategoryType(currentCategoryType);
|
|
||||||
vo.setSource("碳信网");
|
|
||||||
vo.setSourceType("news");
|
|
||||||
vo.setPublishTime(zxxx.getFbsj() != null ? zxxx.getFbsj().toString() : null);
|
|
||||||
vo.setUrl("/mhzc/news/" + zxxx.getUuid());
|
|
||||||
|
|
||||||
resultList.add(vo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list.forEach(zxxx -> {
|
||||||
|
if (matchKeyword(zxxx.getBt1(), keyword) ||
|
||||||
|
matchKeyword(zxxx.getZxNr(), keyword)) {
|
||||||
|
|
||||||
|
SearchResultVO vo = new SearchResultVO();
|
||||||
|
vo.setId(zxxx.getUuid());
|
||||||
|
vo.setTitle(highlightKeyword(zxxx.getBt1(), keyword));
|
||||||
|
vo.setSummary(highlightKeyword(truncate(zxxx.getZxNr(), 200), keyword));
|
||||||
|
vo.setCategory(category);
|
||||||
|
vo.setCategoryType(currentCategoryType);
|
||||||
|
vo.setSource("碳信网");
|
||||||
|
vo.setSourceType("news");
|
||||||
|
vo.setPublishTime(zxxx.getFbsj() != null ? zxxx.getFbsj().toString() : null);
|
||||||
|
vo.setUrl(VIEW_MHZC_PREFIX + "/zx?id=" + zxxx.getUuid());
|
||||||
|
|
||||||
|
resultList.add(vo);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 搜索服务中心(供需信息)
|
||||||
|
if (!"news".equals(categoryType) && !"carbon_cert".equals(categoryType)) {
|
||||||
|
List<SearchResultVO> serviceResults = searchServiceInfo(keyword);
|
||||||
|
if (!"all".equals(categoryType)) {
|
||||||
|
resultList.addAll(serviceResults);
|
||||||
|
} else {
|
||||||
|
resultList.addAll(serviceResults);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页处理
|
||||||
int start = (reqVO.getPage() - 1) * reqVO.getPageSize();
|
int start = (reqVO.getPage() - 1) * reqVO.getPageSize();
|
||||||
int end = Math.min(start + reqVO.getPageSize(), resultList.size());
|
int end = Math.min(start + reqVO.getPageSize(), resultList.size());
|
||||||
|
|
||||||
@ -72,7 +97,47 @@ public class SearchServiceImpl implements SearchService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getHotSearchKeywords() {
|
public List<String> getHotSearchKeywords() {
|
||||||
return Arrays.asList("江苏电厂配额", "林业碳汇开发", "CBAM 报告", "零碳展会");
|
return Arrays.asList("碳核查", "ESG", "碳资产管理", "ISO 14067");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Integer> getCategoryCount(String keyword) {
|
||||||
|
Map<String, Integer> countMap = new HashMap<>();
|
||||||
|
countMap.put("all", 0);
|
||||||
|
countMap.put("news", 0);
|
||||||
|
countMap.put("service", 0);
|
||||||
|
countMap.put("carbon_cert", 0);
|
||||||
|
|
||||||
|
// 统计资讯数量
|
||||||
|
Map<String, List<SyzxxxVO>> data = zxxxbService.zxxx();
|
||||||
|
if (data != null) {
|
||||||
|
data.forEach((category, list) -> {
|
||||||
|
String categoryType = getCategoryType(category);
|
||||||
|
long count = list.stream()
|
||||||
|
.filter(zxxx -> matchKeyword(zxxx.getBt1(), keyword) || matchKeyword(zxxx.getZxNr(), keyword))
|
||||||
|
.count();
|
||||||
|
countMap.put(categoryType, (int) count);
|
||||||
|
if (!"carbon_cert".equals(categoryType)) {
|
||||||
|
countMap.put("all", countMap.get("all") + (int) count);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统计供需信息数量
|
||||||
|
if (StringUtils.hasText(keyword)) {
|
||||||
|
QueryWrapper<TxwGxzxGxxxbDO> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.lambda()
|
||||||
|
.and(w -> w.like(TxwGxzxGxxxbDO::getBt1, keyword)
|
||||||
|
.or().like(TxwGxzxGxxxbDO::getFwnr, keyword)
|
||||||
|
.or().like(TxwGxzxGxxxbDO::getQymc, keyword))
|
||||||
|
.eq(TxwGxzxGxxxbDO::getSjzt, "Y")
|
||||||
|
.eq(TxwGxzxGxxxbDO::getZt, "3");
|
||||||
|
Long serviceCount = gxxxbMapper.selectCount(wrapper);
|
||||||
|
countMap.put("service", serviceCount.intValue());
|
||||||
|
countMap.put("all", countMap.get("all") + serviceCount.intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return countMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -84,10 +149,42 @@ public class SearchServiceImpl implements SearchService {
|
|||||||
List<String> suggestions = new ArrayList<>();
|
List<String> suggestions = new ArrayList<>();
|
||||||
String lowerKeyword = keyword.toLowerCase();
|
String lowerKeyword = keyword.toLowerCase();
|
||||||
|
|
||||||
suggestions.add(keyword);
|
// 从资讯中提取建议
|
||||||
|
Map<String, List<SyzxxxVO>> data = zxxxbService.zxxx();
|
||||||
|
if (data != null) {
|
||||||
|
data.forEach((category, list) -> {
|
||||||
|
list.forEach(zxxx -> {
|
||||||
|
if (matchKeyword(zxxx.getBt1(), keyword)) {
|
||||||
|
suggestions.add(zxxx.getBt1());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从供需信息中提取建议
|
||||||
|
QueryWrapper<TxwGxzxGxxxbDO> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.lambda()
|
||||||
|
.and(w -> w.like(TxwGxzxGxxxbDO::getBt1, keyword)
|
||||||
|
.or().like(TxwGxzxGxxxbDO::getFwnr, keyword)
|
||||||
|
.or().like(TxwGxzxGxxxbDO::getQymc, keyword))
|
||||||
|
.eq(TxwGxzxGxxxbDO::getSjzt, "Y")
|
||||||
|
.eq(TxwGxzxGxxxbDO::getZt, "3")
|
||||||
|
.select(TxwGxzxGxxxbDO::getBt1, TxwGxzxGxxxbDO::getQymc)
|
||||||
|
.last("LIMIT 20");
|
||||||
|
|
||||||
|
List<TxwGxzxGxxxbDO> gxxxList = gxxxbMapper.selectList(wrapper);
|
||||||
|
if (gxxxList != null) {
|
||||||
|
gxxxList.forEach(gxxx -> {
|
||||||
|
if (StringUtils.hasText(gxxx.getBt1())) {
|
||||||
|
suggestions.add(gxxx.getBt1());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 去重并返回包含关键词的建议
|
||||||
return suggestions.stream()
|
return suggestions.stream()
|
||||||
.filter(s -> s.toLowerCase().contains(lowerKeyword))
|
.filter(s -> s != null && s.toLowerCase().contains(lowerKeyword))
|
||||||
|
.distinct()
|
||||||
.limit(10)
|
.limit(10)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
@ -124,6 +221,69 @@ public class SearchServiceImpl implements SearchService {
|
|||||||
return "all";
|
return "all";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<SearchResultVO> searchServiceInfo(String keyword) {
|
||||||
|
List<SearchResultVO> resultList = new ArrayList<>();
|
||||||
|
if (!StringUtils.hasText(keyword)) {
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryWrapper<TxwGxzxGxxxbDO> wrapper = new QueryWrapper<>();
|
||||||
|
wrapper.lambda()
|
||||||
|
.and(w -> w.like(TxwGxzxGxxxbDO::getBt1, keyword)
|
||||||
|
.or().like(TxwGxzxGxxxbDO::getFwnr, keyword)
|
||||||
|
.or().like(TxwGxzxGxxxbDO::getQymc, keyword))
|
||||||
|
.eq(TxwGxzxGxxxbDO::getSjzt, "Y")
|
||||||
|
.eq(TxwGxzxGxxxbDO::getZt, "3")
|
||||||
|
.orderByDesc(TxwGxzxGxxxbDO::getLrrq);
|
||||||
|
|
||||||
|
List<TxwGxzxGxxxbDO> list = gxxxbMapper.selectList(wrapper);
|
||||||
|
|
||||||
|
if (list != null) {
|
||||||
|
for (TxwGxzxGxxxbDO gxxx : list) {
|
||||||
|
String ywlxMc = getYwlxMc(gxxx.getYwlxDm());
|
||||||
|
String ywlxPath = getYwlxPath(gxxx.getYwlxDm());
|
||||||
|
SearchResultVO vo = new SearchResultVO();
|
||||||
|
vo.setId(gxxx.getGxUuid());
|
||||||
|
vo.setTitle(highlightKeyword(gxxx.getBt1(), keyword));
|
||||||
|
vo.setSummary(highlightKeyword(truncate(gxxx.getFwnr(), 200), keyword));
|
||||||
|
vo.setCategory(ywlxMc);
|
||||||
|
vo.setCategoryType("service");
|
||||||
|
vo.setSource(gxxx.getQymc());
|
||||||
|
vo.setSourceType("service");
|
||||||
|
vo.setPublishTime(gxxx.getLrrq() != null ? gxxx.getLrrq().toString() : null);
|
||||||
|
vo.setUrl(VIEW_MHZC_PREFIX + ywlxPath + "?id=" + gxxx.getGxUuid());
|
||||||
|
resultList.add(vo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resultList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getYwlxMc(String ywlxDm) {
|
||||||
|
if ("01".equals(ywlxDm)) {
|
||||||
|
return "碳服务市场";
|
||||||
|
} else if ("02".equals(ywlxDm)) {
|
||||||
|
return "碳需求市场";
|
||||||
|
} else if ("03".equals(ywlxDm)) {
|
||||||
|
return "碳金融市场";
|
||||||
|
} else if ("04".equals(ywlxDm)) {
|
||||||
|
return "碳数据市场";
|
||||||
|
}
|
||||||
|
return "服务中心";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getYwlxPath(String ywlxDm) {
|
||||||
|
if ("01".equals(ywlxDm)) {
|
||||||
|
return "/tfwsc";
|
||||||
|
} else if ("02".equals(ywlxDm)) {
|
||||||
|
return "/txqsc";
|
||||||
|
} else if ("03".equals(ywlxDm)) {
|
||||||
|
return "/tjrsc";
|
||||||
|
} else if ("04".equals(ywlxDm)) {
|
||||||
|
return "/tsjsc";
|
||||||
|
}
|
||||||
|
return "/tfwsc";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getSearchHistory() {
|
public List<String> getSearchHistory() {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
|
|||||||
@ -17,8 +17,12 @@ public class SendMsgReqVO {
|
|||||||
@NotEmpty(message = "手机号码不能为空")
|
@NotEmpty(message = "手机号码不能为空")
|
||||||
private String sjhm1;
|
private String sjhm1;
|
||||||
|
|
||||||
@Schema(description = "验证码,验证码开启时,需要传递", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "图形验证码uuid", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
@NotEmpty(message = "验证码不能为空", groups = AuthLoginReqVO.CodeEnableGroup.class)
|
@NotEmpty(message = "验证码不能为空", groups = AuthLoginReqVO.CodeEnableGroup.class)
|
||||||
private String captchaVerification;
|
private String captchaVerification;
|
||||||
|
|
||||||
|
@Schema(description = "图形验证码", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotEmpty(message = "验证码不能为空", groups = AuthLoginReqVO.CodeEnableGroup.class)
|
||||||
|
private String captchaCode;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -158,7 +158,7 @@ public class AuthServiceImpl implements AuthService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer sendMsg(SendMsgReqVO reqVO) throws Exception{
|
public Integer sendMsg(SendMsgReqVO reqVO) throws Exception{
|
||||||
final Boolean checked = verifyService.checkVerifyToken(reqVO.getCaptchaVerification());
|
final Boolean checked = verifyService.checkCaptcha(reqVO.getCaptchaVerification(), reqVO.getCaptchaCode());
|
||||||
if (!checked) {
|
if (!checked) {
|
||||||
throw exception(AUTH_LOGIN_CAPTCHA_CODE_ERROR);
|
throw exception(AUTH_LOGIN_CAPTCHA_CODE_ERROR);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user