mirror of
http://112.124.100.131/ebiz-ai/ebiz-base-ai.git
synced 2025-12-09 19:06:50 +08:00
feat(product): 添加产品推荐功能并优化相关页面
- 新增产品推荐页面,提供个性化的产品推荐服务 - 优化首页布局,增加产品推荐入口 - 调整聊天组件,支持产品推荐功能 - 优化样式文件,统一主题颜色和样式 - 更新路由配置,添加产品推荐路由
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
@import './utils.scss';
|
||||
@import './transition.scss';
|
||||
@import './public.scss';
|
||||
@import "./loading.scss";
|
||||
@import './loading.scss';
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
@@ -33,7 +33,7 @@ a:hover {
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
::-webkit-scrollbar{
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
// 宽度设置
|
||||
|
||||
@@ -1,61 +1,62 @@
|
||||
body{
|
||||
background-color: #EEEEEE!important;
|
||||
body {
|
||||
background-color: #eeeeee !important;
|
||||
}
|
||||
.van-cell-group--inset{
|
||||
margin:0 10px!important;
|
||||
.van-cell-group--inset {
|
||||
margin: 0 10px !important;
|
||||
}
|
||||
.van-cell-group__title--inset{
|
||||
padding:15px 15px 5px 15px!important;
|
||||
.van-cell-group__title--inset {
|
||||
padding: 15px 15px 5px 15px !important;
|
||||
}
|
||||
.van-toast--text {
|
||||
.van-toast--text {
|
||||
max-width: 70vw !important;
|
||||
min-width: 60vw !important;
|
||||
}
|
||||
.button-group-container{
|
||||
.button-group-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
#app .van-col{
|
||||
#app .van-col {
|
||||
margin: 5px 0;
|
||||
}
|
||||
#app .button-group-container{
|
||||
margin: 5px!important;
|
||||
.van-button{
|
||||
#app .button-group-container {
|
||||
margin: 5px !important;
|
||||
.van-button {
|
||||
margin: unset;
|
||||
}
|
||||
}
|
||||
#app .van-button + .van-button{
|
||||
#app .van-button + .van-button {
|
||||
margin-left: 5px;
|
||||
}
|
||||
#app .van-cell__title{
|
||||
#app .van-cell__title {
|
||||
color: #646566;
|
||||
}
|
||||
|
||||
|
||||
.flexPrice{
|
||||
display: flex; justify-content: space-between; justify-items: center; align-items: center; width: 100%
|
||||
.flexPrice {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
.van-tag+.van-tag{margin-left: 5px;}
|
||||
.speakLoadingToast{
|
||||
z-index: 2100!important;
|
||||
.van-tag + .van-tag {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.speakLoadingToast {
|
||||
z-index: 2100 !important;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.gs-color-g{
|
||||
.gs-color-g {
|
||||
color: #009960;
|
||||
}
|
||||
.gs-bg-color-g{
|
||||
.gs-bg-color-g {
|
||||
background: #009960;
|
||||
}
|
||||
|
||||
|
||||
.chat-icon{
|
||||
.chat-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-left: 0!important;
|
||||
margin-right: 2px!important;
|
||||
|
||||
margin-left: 0 !important;
|
||||
margin-right: 2px !important;
|
||||
}
|
||||
|
||||
@@ -23,4 +23,12 @@ export default [
|
||||
title: '产品对比',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/recommend',
|
||||
name: 'recommend',
|
||||
component: () => import('@/views/recommend/index.vue'),
|
||||
meta: {
|
||||
title: '产品推荐',
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
@@ -90,6 +90,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
chatData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -220,6 +224,12 @@ export default {
|
||||
conversationId: this.conversationId,
|
||||
productName: this.productName,
|
||||
}
|
||||
// 如果有自定义参数
|
||||
if (this.chatData) {
|
||||
for (let k in this.chatData) {
|
||||
params[k] = this.chatData[k]
|
||||
}
|
||||
}
|
||||
if (this.$route.query.compareId) {
|
||||
params.compareResult = JSON.parse(sessionStorage.getItem('results'))
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="home-container">
|
||||
<van-swipe class="my-swipe">
|
||||
<van-swipe-item class="item">
|
||||
<div v-for="item in navigationItems" @click="jumpPage(item)">
|
||||
<van-swipe-item class="item" v-for="swiper in swiper">
|
||||
<div v-for="item in swiper" @click="jumpPage(item)">
|
||||
<div class="icon-contact mt20">
|
||||
<svg-icon :icon-class="item.icon" class-name="icon "></svg-icon>
|
||||
</div>
|
||||
@@ -39,10 +39,14 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
navigationItems: [
|
||||
{ title: 'AI智能助手', icon: 'product', path: '/chatPage' },
|
||||
{ title: 'AI客服助手', icon: 'sale', path: '/customer' },
|
||||
{ title: '产品对比', icon: 'earth', path: '/comparison' },
|
||||
swiper: [
|
||||
[
|
||||
{ title: 'AI智能助手', icon: 'product', path: '/chatPage' },
|
||||
{ title: '产品对比', icon: 'earth', path: '/comparison' },
|
||||
{ title: '产品推荐', icon: 'product', path: '/recommend' },
|
||||
],
|
||||
|
||||
[{ title: 'AI客服助手', icon: 'sale', path: '/customer' }],
|
||||
],
|
||||
list: [
|
||||
{
|
||||
@@ -63,6 +67,17 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
// 主题颜色定义
|
||||
$primary-color: #2e5ca9;
|
||||
$primary-text-color: #f6aa21;
|
||||
$primary-trans-color: #87a2d0;
|
||||
.van-nav-bar__text,
|
||||
.van-nav-bar .van-icon {
|
||||
color: $primary-color !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped lang="scss">
|
||||
// 主题颜色定义
|
||||
$primary-color: #2e5ca9;
|
||||
|
||||
157
src/views/recommend/index.vue
Normal file
157
src/views/recommend/index.vue
Normal file
@@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<div class="chat-page">
|
||||
<van-nav-bar title="产品推荐" left-text="返回" left-arrow @click-left="$router.history.go(-1)" />
|
||||
<main class="chat-main">
|
||||
<div class="chat-content">
|
||||
<div class="message-area" ref="messageArea" @scroll="handleScroll">
|
||||
<!-- -->
|
||||
<messageComponent
|
||||
:messagesList="messages"
|
||||
:is-deep="isDeep"
|
||||
:is-search="isSearching"
|
||||
:think-ok="isThink"
|
||||
@setProductName="setProductName"
|
||||
></messageComponent>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 滚动到顶部按钮 -->
|
||||
<div class="button-container" style="background: #fff">
|
||||
<van-icon name="upgrade" size="2em" @click="scrollToTop" />
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<chatMessage
|
||||
:messages.sync="messages"
|
||||
:messageStatus.sync="messageStatus"
|
||||
:is-deep.sync="isDeep"
|
||||
:conversation-id.sync="conversationId"
|
||||
:is-searching.sync="isSearching"
|
||||
:product-name.sync="productName"
|
||||
:autoScrollEnabled.sync="autoScrollEnabled"
|
||||
:chatData="{ action: 'product_recommand' }"
|
||||
@getIsThink="getIsThink"
|
||||
></chatMessage>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Icon, NavBar } from 'vant'
|
||||
import SvgIcon from '@/components/svg-icon/index.vue'
|
||||
import HotProducts from '@/views/AI/components/HotProducts.vue'
|
||||
import chatMessage from '@/views/AI/components/chat.vue'
|
||||
import messageComponent from '@/views/AI/components/message.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SvgIcon,
|
||||
messageComponent,
|
||||
[Icon.name]: Icon,
|
||||
[NavBar.name]: NavBar,
|
||||
HotProducts,
|
||||
chatMessage,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hotList: [],
|
||||
productName: '',
|
||||
conversationId: '',
|
||||
messageStatus: 'stop',
|
||||
isThink: null,
|
||||
messages: [
|
||||
{
|
||||
type: 'bot',
|
||||
text: '欢迎使用产品推荐智能助手,我将推荐符合您的产品',
|
||||
},
|
||||
],
|
||||
isSearching: false,
|
||||
isDeep: false,
|
||||
autoScrollEnabled: true,
|
||||
scrollPosition: 0,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getIsThink(e) {
|
||||
this.isThink = e
|
||||
},
|
||||
getHotProducts(e) {
|
||||
console.log(e)
|
||||
this.hotList = e
|
||||
},
|
||||
|
||||
scrollToTop() {
|
||||
const messageArea = this.$refs.messageArea
|
||||
if (messageArea) {
|
||||
messageArea.scrollTop = 0
|
||||
}
|
||||
},
|
||||
scrollToBottom() {
|
||||
if (!this.autoScrollEnabled) return
|
||||
this.$nextTick(() => {
|
||||
const messageArea = this.$refs.messageArea
|
||||
if (messageArea) {
|
||||
messageArea.scrollTop = messageArea.scrollHeight
|
||||
}
|
||||
})
|
||||
},
|
||||
setProductName(e) {
|
||||
this.productName = e
|
||||
},
|
||||
handleScroll() {
|
||||
const messageArea = this.$refs.messageArea
|
||||
if (!messageArea) return
|
||||
const threshold = 10
|
||||
const isAtBottom = messageArea.scrollHeight - messageArea.clientHeight <= messageArea.scrollTop + threshold
|
||||
this.autoScrollEnabled = isAtBottom
|
||||
this.scrollPosition = messageArea.scrollTop
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
messages: {
|
||||
handler() {
|
||||
this.$nextTick(() => this.scrollToBottom())
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$primary-color: #2e5ca9;
|
||||
$primary-text-color: #f6aa21;
|
||||
$primary-trans-color: rgba(135, 162, 208, 0.5);
|
||||
|
||||
.chat-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
//-webkit-user-select: none;
|
||||
//-moz-user-select: none;
|
||||
//-ms-user-select: none;
|
||||
//user-select: none;
|
||||
|
||||
.chat-main {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
background: #f7f8fa;
|
||||
position: relative;
|
||||
|
||||
.button-container {
|
||||
position: fixed;
|
||||
bottom: 150px;
|
||||
right: 10px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.chat-content {
|
||||
height: 100%;
|
||||
.message-area {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,9 +1,9 @@
|
||||
const autoprefixer = require('autoprefixer');
|
||||
const pxtoviewport = require('postcss-px-to-viewport');
|
||||
const path = require('path');
|
||||
const autoprefixer = require('autoprefixer')
|
||||
const pxtoviewport = require('postcss-px-to-viewport')
|
||||
const path = require('path')
|
||||
|
||||
function resolve(dir) {
|
||||
return path.join(__dirname, dir);
|
||||
return path.join(__dirname, dir)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
@@ -12,37 +12,36 @@ module.exports = {
|
||||
outputDir: 'dist',
|
||||
productionSourceMap: false,
|
||||
devServer: {
|
||||
https: false,
|
||||
https: true,
|
||||
host: '0.0.0.0',
|
||||
disableHostCheck: true,
|
||||
},
|
||||
css: {
|
||||
sourceMap: true,
|
||||
loaderOptions: {
|
||||
loaderOptions: {
|
||||
postcss: {
|
||||
postcssOptions: {
|
||||
plugins: [
|
||||
autoprefixer(), // 自动加浏览器前缀
|
||||
pxtoviewport({ // px 转 viewport
|
||||
pxtoviewport({
|
||||
// px 转 viewport
|
||||
viewportWidth: 375,
|
||||
selectorBlackList: ['van-circle__layer'] // 排除vant circle组件样式转换
|
||||
})
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
selectorBlackList: ['van-circle__layer'], // 排除vant circle组件样式转换
|
||||
}),
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
chainWebpack: (config) => {
|
||||
// 设置路径别名
|
||||
config.resolve.alias
|
||||
.set('@', resolve('src'))
|
||||
.set('@utils', resolve('src/assets/js/utils'));
|
||||
config.resolve.alias.set('@', resolve('src')).set('@utils', resolve('src/assets/js/utils'))
|
||||
|
||||
// 移除 prefetch 插件(减少初始加载体积)
|
||||
config.plugins.delete('prefetch');
|
||||
config.plugins.delete('prefetch')
|
||||
|
||||
// SVG 图标配置
|
||||
config.module.rule('svg').exclude.add(resolve('src/icons')).end();
|
||||
config.module.rule('svg').exclude.add(resolve('src/icons')).end()
|
||||
config.module
|
||||
.rule('icons')
|
||||
.test(/\.svg$/)
|
||||
@@ -52,7 +51,7 @@ module.exports = {
|
||||
.loader('svg-sprite-loader')
|
||||
.options({
|
||||
symbolId: 'icon-[name]',
|
||||
});
|
||||
})
|
||||
|
||||
// 处理 .mjs 文件(用于 mermaid 等模块)
|
||||
config.module
|
||||
@@ -61,7 +60,7 @@ module.exports = {
|
||||
.include.add(/node_modules/)
|
||||
.end()
|
||||
.use('babel-loader')
|
||||
.loader('babel-loader');
|
||||
.loader('babel-loader')
|
||||
|
||||
// 添加对现代 JS 的支持(如 ?? 和 ?.)
|
||||
config.module
|
||||
@@ -71,19 +70,19 @@ module.exports = {
|
||||
.loader('babel-loader')
|
||||
.options({
|
||||
presets: ['@babel/preset-env'],
|
||||
});
|
||||
})
|
||||
},
|
||||
configureWebpack: (config) => {
|
||||
// 强制使用 CommonJS 模块加载 mermaid
|
||||
config.resolve = config.resolve || {};
|
||||
config.resolve.alias = config.resolve.alias || {};
|
||||
config.resolve = config.resolve || {}
|
||||
config.resolve.alias = config.resolve.alias || {}
|
||||
// config.resolve.alias.mermaid$ = path.resolve(
|
||||
// __dirname,
|
||||
// './node_modules/mermaid/dist/mermaid.common.js'
|
||||
// );
|
||||
|
||||
// Webpack devtool 设置
|
||||
config.devtool = 'source-map';
|
||||
config.devtool = 'source-map'
|
||||
|
||||
// 打包性能提示设置
|
||||
config.performance = {
|
||||
@@ -91,8 +90,8 @@ module.exports = {
|
||||
maxEntrypointSize: 7168000, // 7MB
|
||||
maxAssetSize: 7168000, // 7MB
|
||||
assetFilter: function (assetFilename) {
|
||||
return assetFilename.endsWith('.js');
|
||||
return assetFilename.endsWith('.js')
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user