Commit 2223a16f authored by 姜耀祖's avatar 姜耀祖

前端代码修改

parent 89e233a0
Pipeline #21044 passed with stages
in 3 minutes and 6 seconds
......@@ -50,14 +50,15 @@
</div>
</div>
</div>
<!-- 中间聊天区域 -->
<div class="chat-wrapper">
<div class="chat-container">
<!-- 消息历史区域 -->
<!-- 右侧聊天区域 -->
<div class="chat-area">
<!-- 消息历史区域 -->
<div id="scrollContainer" class="scrollContainer">
<div id="chat-messages" class="chat-messages">
<div v-for="(message, index) in messages"
:key="index"
class="message"
<div v-for="(message, index) in messages"
:key="index"
class="message"
:class="message.role + '-message'">
<div class="avatar">{{ message.role === 'user' ? '我' : 'AI' }}</div>
<div class="content">
......@@ -66,23 +67,44 @@
</div>
</div>
</div>
<!-- 输入区域 -->
<div class="input-area">
<textarea id="user-input" v-model="userInput" placeholder="请输入您的问题..." rows="2"></textarea>
<button id="send-btn" class="send-btn" @click="sendMessage" v-show="!isResponding">
<svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2" fill="none"
stroke-linecap="round" stroke-linejoin="round" class="send-icon">
<line x1="22" y1="2" x2="11" y2="13"></line>
<polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
</svg>
</button>
<button id="stop-btn" class="stop-btn" @click="stopResponse" v-show="isResponding">
<svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2" fill="none"
stroke-linecap="round" stroke-linejoin="round" class="stop-icon">
<rect x="6" y="6" width="12" height="12" rx="2" ry="2"></rect>
</svg>
</button>
</div>
<!-- 输入区域 -->
<div class="input-area">
<textarea id="user-input" v-model="userInput" placeholder="请输入您的问题 shift+enter换行" rows="3"></textarea>
<div class="input-area-content">
<div>
<div class="custom-select" v-click-outside="closeExpertDropdown">
<div class="selected-option" @click.stop="toggleExpertDropdown">
<span>{{ selectedExpert }}</span>
<svg class="dropdown-icon" :class="{ 'rotated': showExpertDropdown }" viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none">
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</div>
<div class="dropdown-menu" v-show="showExpertDropdown">
<div class="dropdown-item" @click.stop="selectExpert('内部专家')" :class="{ 'active': selectedExpert === '内部专家' }">
<span>内部专家</span>
</div>
<div class="dropdown-item" @click.stop="selectExpert('外部专家')" :class="{ 'active': selectedExpert === '外部专家' }">
<span>外部专家</span>
</div>
</div>
</div>
</div>
<div>
<button id="send-btn" class="send-btn" @click="sendMessage" v-show="!isResponding">
<svg class="send-icon" viewBox="0 0 24 24" width="18" height="18" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round">
<line x1="12" y1="19" x2="12" y2="5"></line>
<polyline points="5 12 12 5 19 12"></polyline>
</svg>
</button>
<button id="stop-btn" class="stop-btn" @click="stopResponse" v-show="isResponding">
<svg viewBox="0 0 24 24" width="18" height="18" stroke="currentColor" stroke-width="2" fill="none"
stroke-linecap="round" stroke-linejoin="round" class="stop-icon">
<rect x="6" y="6" width="12" height="12" rx="2" ry="2"></rect>
</svg>
</button>
</div>
</div>
</div>
</div>
......
......@@ -2,6 +2,21 @@
* AI聊天页面Vue应用
*/
require(['jquery', 'vue', 'utils', 'echarts', 'global'], function ($, Vue, utils, echarts) {
// 添加点击外部关闭指令
Vue.directive('click-outside', {
bind: function (el, binding, vnode) {
el.clickOutsideEvent = function (event) {
if (!(el == event.target || el.contains(event.target))) {
vnode.context[binding.expression](event);
}
};
document.body.addEventListener('click', el.clickOutsideEvent);
},
unbind: function (el) {
document.body.removeEventListener('click', el.clickOutsideEvent);
}
});
const app = new Vue({
el: '#app',
data: {
......@@ -18,6 +33,10 @@ require(['jquery', 'vue', 'utils', 'echarts', 'global'], function ($, Vue, utils
isResponding: false,
userInput: "",
// 专家选择相关数据
selectedExpert: '内部专家',
showExpertDropdown: false,
// 历史对话分类
historySections: [
{
......@@ -68,6 +87,7 @@ require(['jquery', 'vue', 'utils', 'echarts', 'global'], function ($, Vue, utils
this.getSessionId();
},
mounted: function () {
this.pageEvent();
// 监听输入框的键盘事件
this.$nextTick(() => {
const textarea = document.getElementById('user-input');
......@@ -82,9 +102,37 @@ require(['jquery', 'vue', 'utils', 'echarts', 'global'], function ($, Vue, utils
this.closeAllMenus();
}
});
// // 获取滚动容器和消息容器
// const scrollContainer = document.getElementById('chat-messages').parentElement;
// const chatMessages = document.getElementById('chat-messages');
// // 创建MutationObserver监听消息变化
// const observer = new MutationObserver(function(mutations) {
// mutations.forEach(mutation => {
// if (mutation.addedNodes.length) {
// // 使用延时确保内容已渲染
// setTimeout(() => {
// scrollContainer.scrollTo({
// top: scrollContainer.scrollHeight,
// behavior: 'smooth' // 可选平滑滚动
// });
// }, 50);
// }
// });
// });
//
// // 开始观察子元素变化
// observer.observe(chatMessages, {
// childList: true
// });
});
},
methods: {
pageEvent:function(){
// 确保在DOM加载完成后执行
document.addEventListener('DOMContentLoaded', function() {
});
},
// 用户相关方法
currentUser: function () {
const that = this;
......@@ -130,7 +178,8 @@ require(['jquery', 'vue', 'utils', 'echarts', 'global'], function ($, Vue, utils
sendMessage() {
const message = this.userInput.trim();
if (!message) return;
this.stopResponse();
// 添加用户消息
this.addMessage('user', message);
this.userInput = '';
......@@ -146,7 +195,7 @@ require(['jquery', 'vue', 'utils', 'echarts', 'global'], function ($, Vue, utils
if (this.currentEventSource) {
this.currentEventSource.close();
this.currentEventSource = null;
// 切换回发送按钮
this.isResponding = false;
......@@ -154,8 +203,9 @@ require(['jquery', 'vue', 'utils', 'echarts', 'global'], function ($, Vue, utils
const aiMessages = this.messages.filter(msg => msg.role === 'ai');
if (aiMessages.length > 0) {
const lastAIMessage = aiMessages[aiMessages.length - 1];
if (!lastAIMessage.content.includes('(已终止)')) {
lastAIMessage.content += ' (已终止)';
lastAIMessage.typing = false;
if (!lastAIMessage.content.includes('(已手动结束回答)')) {
lastAIMessage.content += ' (已手动结束回答)';
}
}
}
......@@ -167,7 +217,7 @@ require(['jquery', 'vue', 'utils', 'echarts', 'global'], function ($, Vue, utils
// 自动滚动到底部
this.$nextTick(() => {
const messagesDiv = document.getElementById('chat-messages');
const messagesDiv = document.getElementById('scrollContainer');
if (messagesDiv) {
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
......@@ -181,7 +231,7 @@ require(['jquery', 'vue', 'utils', 'echarts', 'global'], function ($, Vue, utils
// 自动滚动到底部
this.$nextTick(() => {
const messagesDiv = document.getElementById('chat-messages');
const messagesDiv = document.getElementById('scrollContainer');
if (messagesDiv) {
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
......@@ -212,7 +262,7 @@ require(['jquery', 'vue', 'utils', 'echarts', 'global'], function ($, Vue, utils
// 自动滚动到底部
this.$nextTick(() => {
const messagesDiv = document.getElementById('chat-messages');
const messagesDiv = document.getElementById('scrollContainer');
if (messagesDiv) {
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
......@@ -348,6 +398,18 @@ require(['jquery', 'vue', 'utils', 'echarts', 'global'], function ($, Vue, utils
if (isActiveChat) {
this.clearChat();
}
},
// 专家选择相关方法
toggleExpertDropdown() {
this.showExpertDropdown = !this.showExpertDropdown;
},
closeExpertDropdown() {
this.showExpertDropdown = false;
},
selectExpert(expert) {
this.selectedExpert = expert;
// 立即关闭下拉框
this.showExpertDropdown = false;
}
}
});
......
......@@ -65,6 +65,7 @@ body {
display: flex;
height: 100vh;
width: 100%;
overflow: hidden;
}
/* 左侧边栏样式 */
......@@ -212,101 +213,54 @@ body {
color: var(--text-secondary);
}
/* 聊天包装器样式 - 新增 */
.chat-wrapper {
/* 右侧聊天区域 */
.chat-area {
flex: 1;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
background-color: var(--bg-color);
padding: 0;
position: relative;
height: 100vh;
overflow: hidden;
}
/* 聊天容器样式 */
.chat-container {
width: 900px;
max-width: 95%;
height: 100%;
display: flex;
flex-direction: column;
overflow-y: auto; /* 使整个聊天区域可滚动,滚动条显示在最右边 */
overflow-x: hidden;
background-color: var(--bg-color);
overflow: hidden;
position: relative;
padding-bottom: 80px; /* 为底部输入框留出空间 */
}
/* 聊天头部样式 */
.chat-header {
padding: 15px 20px;
background-color: #fff;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #e8e8e8;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
.current-chat-info {
display: flex;
align-items: center;
.scrollContainer{
width: 100%;
overflow-y: auto; /* 让内容继续流动 */
height: calc(100vh - 150px); /* 确保占据足够高度 */
}
.current-chat-title {
font-size: 1rem;
font-weight: 600;
color: #333;
/* 聊天消息区域 */
.chat-messages {
width: 900px;
max-width: 95%;
margin: 0 auto;
padding: 20px;
margin-bottom: 10px;
}
.chat-info {
/* 输入区域 */
.input-area {
width: 900px;
max-width: 95%;
margin: 0 auto 30px auto;
padding: 8px 10px;
display: flex;
align-items: center;
gap: 15px;
background-color: var(--input-area-bg);
border-radius: 15px;
box-shadow: 0 1px 8px var(--box-shadow);
position: sticky;
bottom: 30px;
flex-shrink: 0; /* 防止被压缩 */
flex-direction: column;
justify-content: flex-start;
}
.status {
.input-area-content{
display: flex;
align-items: center;
font-size: 0.9rem;
}
.status::before {
content: '';
display: inline-block;
width: 8px;
height: 8px;
margin-right: 5px;
border-radius: 50%;
}
.status.online::before {
background-color: #52c41a;
}
.clear-btn {
padding: 6px 12px;
background-color: #f0f0f0;
color: #595959;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
.clear-btn:hover {
background-color: #e0e0e0;
}
/* 消息区域样式 */
.chat-messages {
flex: 1;
padding: 20px;
overflow-y: auto;
background-color: var(--bg-color);
height: calc(100vh - 80px);
justify-content: space-between;
padding-left: 10px;
}
/* 单条消息样式 */
......@@ -363,23 +317,6 @@ body {
word-break: break-word;
}
/* 输入区域样式 */
.input-area {
display: flex;
padding: 8px 10px;
background-color: var(--input-area-bg);
align-items: center;
position: absolute;
bottom: 30px;
left: 20px;
right: 20px;
width: calc(100% - 40px);
z-index: 10;
box-shadow: 0 1px 8px var(--box-shadow);
border-radius: 15px;
border-top: none;
}
#user-input {
flex: 1;
padding: 8px 10px;
......@@ -387,7 +324,7 @@ body {
border-radius: 0;
resize: none;
outline: none;
height: 70px;
height: 100px;
max-height: 150px;
background-color: transparent;
transition: all 0.3s;
......@@ -407,13 +344,13 @@ body {
}
.send-btn, .stop-btn {
width: 44px;
height: 44px;
min-height: 44px;
width: 36px;
height: 36px;
min-height: 36px;
background-color: var(--primary-color);
color: white;
border: none;
border-radius: 12px;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
......@@ -434,9 +371,9 @@ body {
background-color: #ff7875;
}
.stop-icon {
width: 20px;
height: 20px;
.stop-icon, .send-icon {
width: 18px;
height: 18px;
stroke: white;
}
......@@ -473,15 +410,10 @@ body {
left: 0;
}
.chat-wrapper {
padding: 10px;
}
.chat-container {
.chat-messages,
.input-area {
width: 100%;
max-width: 100%;
height: 100vh;
border-radius: 0;
}
.message .content {
......@@ -521,4 +453,98 @@ body {
opacity: 1;
transform: translateY(0);
}
}
/* 自定义选择器样式 */
.custom-select {
position: relative;
width: auto;
min-width: 70px;
cursor: pointer;
user-select: none;
margin-right: 10px;
margin-left: 0;
}
.selected-option {
display: flex;
align-items: center;
justify-content: center;
padding: 2px 5px;
border-radius: 8px;
background-color: rgba(230, 220, 250, 0.5);
color: #6633ff;
font-size: 14px;
transition: all 0.2s;
}
.selected-option span {
margin-right: 2px;
text-align: center;
display: inline-block;
width: 100%;
}
.dark-theme .selected-option {
background-color: rgba(130, 100, 200, 0.2);
color: #9980ff;
}
.selected-option:hover {
background-color: rgba(210, 200, 250, 0.7);
}
.dark-theme .selected-option:hover {
background-color: rgba(150, 120, 220, 0.3);
}
.dropdown-icon {
transition: transform 0.2s;
margin-left: 2px;
flex-shrink: 0;
stroke: #6633ff;
}
.dark-theme .dropdown-icon {
stroke: #9980ff;
}
.dropdown-icon.rotated {
transform: rotate(180deg);
}
.dropdown-menu {
position: absolute;
bottom: 100%;
left: 0;
width: 100%;
margin-bottom: 5px;
background-color: var(--message-bg);
border-radius: 8px;
box-shadow: 0 2px 10px var(--box-shadow);
z-index: 100;
overflow: hidden;
}
.dropdown-item {
padding: 6px 8px;
transition: background-color 0.2s;
font-size: 13px;
color: var(--text-color);
text-align: center;
}
.dropdown-item:hover {
background-color: var(--hover-bg);
}
.dropdown-item.active {
background-color: var(--active-bg);
font-weight: 500;
}
/* 输入区域内容样式 */
.input-area-content {
display: flex;
align-items: center;
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment