YYD-YY 9 months ago
commit 07efe8e04b
  1. 23
      ALOps_sys_fe/alops-ui/src/api/QandA/knowledge.js
  2. 123
      ALOps_sys_fe/alops-ui/src/api/inMonitoring/assessment.js
  3. 248
      ALOps_sys_fe/alops-ui/src/views/QandA/Aiassistant/index copy.vue
  4. 36
      ALOps_sys_fe/alops-ui/src/views/QandA/Aiassistant/index.vue
  5. 272
      ALOps_sys_fe/alops-ui/src/views/QandA/Aiassistant/index2.vue
  6. 4
      ALOps_sys_fe/alops-ui/src/views/QandA/knowledge/index.vue
  7. 17
      ALOps_sys_fe/alops-ui/src/views/inMonitoring/inMonitor/message/index.vue
  8. 1
      ALOps_sys_fe/alops-ui/src/views/inMonitoring/inMonitor/rules/index.vue

@ -1,5 +1,5 @@
import request from '@/utils/request'
const api = '/knowledge/'
const api = '/QandA/knowledge/'
// 查询详细
export function getDict() {
@ -9,10 +9,19 @@ export function getDict() {
})
}
// 查询列表
export function list(query) {
// 获取所有正式条目
export function permanentKnowledgeList(query) {
return request({
url: '/knowBase/query',
url: api + '/knowBase/permanent-knowledge',
method: 'get',
params: query
})
}
// 获取所有上传文件信息
export function uploadedFilesList(query) {
return request({
url: api + '/knowBase/uploaded-files',
method: 'get',
params: query
})
@ -21,7 +30,7 @@ export function list(query) {
// 新增
export function add(data) {
return request({
url: '/knowledge/add',
url: api + 'upload',
method: 'post',
data: data
})
@ -30,7 +39,7 @@ export function add(data) {
// 修改
export function update(data) {
return request({
url: '/knowBasemodify',
url: api + 'upload',
method: 'put',
data: data
})
@ -39,7 +48,7 @@ export function update(data) {
// 删除
export function del(id) {
return request({
url: '/knowBase/delete/' + id,
url: api + '/uploaded-files/' + id,
method: 'delete'
})
}

@ -1,130 +1,11 @@
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/ruoyi";
// 查询用户列表
export function listUser(query) {
return request({
url: '/system/user/list',
method: 'get',
params: query
})
}
// 查询用户详细
export function getUser(userId) {
return request({
url: '/system/user/' + parseStrEmpty(userId),
method: 'get'
})
}
// 新增用户
export function addUser(data) {
export function knowledgeAsk(data) {
return request({
url: '/system/user',
url: '/QandA/knowledge/ask',
method: 'post',
data: data
})
}
// 修改用户
export function updateUser(data) {
return request({
url: '/system/user',
method: 'put',
data: data
})
}
// 删除用户
export function delUser(userId) {
return request({
url: '/system/user/' + userId,
method: 'delete'
})
}
// 用户密码重置
export function resetUserPwd(userId, password) {
const data = {
userId,
password
}
return request({
url: '/system/user/resetPwd',
method: 'put',
data: data
})
}
// 用户状态修改
export function changeUserStatus(userId, status) {
const data = {
userId,
status
}
return request({
url: '/system/user/changeStatus',
method: 'put',
data: data
})
}
// 查询用户个人信息
export function getUserProfile() {
return request({
url: '/system/user/profile',
method: 'get'
})
}
// 修改用户个人信息
export function updateUserProfile(data) {
return request({
url: '/system/user/profile',
method: 'put',
data: data
})
}
// 用户密码重置
export function updateUserPwd(oldPassword, newPassword) {
const data = {
oldPassword,
newPassword
}
return request({
url: '/system/user/profile/updatePwd',
method: 'put',
data: data
})
}
// 用户头像上传
export function uploadAvatar(data) {
return request({
url: '/system/user/profile/avatar',
method: 'post',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data: data
})
}
// 查询授权角色
export function getAuthRole(userId) {
return request({
url: '/system/user/authRole/' + userId,
method: 'get'
})
}
// 保存授权角色
export function updateAuthRole(data) {
return request({
url: '/system/user/authRole',
method: 'put',
params: data
})
}

@ -0,0 +1,248 @@
<template>
<div id="app">
<el-card class="customer-service">
<!-- 客服头部 -->
<div class="service-header">
<h2>AI智能助手</h2>
<p>您好我是智能助手很高兴为您服务</p>
</div>
<div class="service-container">
<!-- 右侧聊天区域 -->
<div class="chat-section">
<div class="chat-messages" ref="messagesContainer">
<div
v-for="(message, index) in messages"
:key="index"
:class="['message', message.sender]"
>
<div class="message-content">
<div>{{ message.text }}</div>
<div class="timestamp">{{ message.time }}</div>
</div>
</div>
</div>
<div class="chat-input">
<el-input
v-model="newMessage"
placeholder="请输入您的问题..."
@keyup.enter.native="sendMessage"
></el-input>
<el-button
type="primary"
@click="sendMessage"
:disabled="!newMessage.trim()"
>发送</el-button>
</div>
</div>
</div>
</el-card>
</div>
</template>
<script>
import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus, deptTreeSelect } from "@/api/inMonitoring/assessment"
import { getToken } from "@/utils/auth"
import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
import { Splitpanes, Pane } from "splitpanes"
import "splitpanes/dist/splitpanes.css"
export default {
name: "User",
dicts: ['sys_normal_disable', 'sys_user_sex'],
components: { Treeselect, Splitpanes, Pane },
data() {
return {
newMessage: '',
messages: [
{
text: '您好!我是AI智能助手,请问有什么可以帮您?',
sender: 'service',
time: this.formatTime(new Date())
}
],
faqs: [
{ question: '如何查询订单状态?', answer: '您可以在"我的订单"页面查看订单的当前状态和物流信息。' },
{ question: '如何办理退货?', answer: '请在订单详情页点击"申请退货",填写相关信息后提交申请。' },
{ question: '支付方式有哪些?', answer: '我们支持支付宝、微信支付、银联等多种支付方式。' },
{ question: '会员有哪些优惠?', answer: '会员可享受购物折扣、专属优惠券、生日特权等多重优惠。' },
{ question: '商品何时发货?', answer: '一般情况下,我们会在订单支付成功后24小时内安排发货。' }
]
};
},mounted() {
//
this.scrollToBottom();
},
methods: {
sendMessage() {
if (!this.newMessage.trim()) return;
//
this.messages.push({
text: this.newMessage,
sender: 'customer',
time: this.formatTime(new Date())
});
//
setTimeout(() => {
this.autoReply(this.newMessage);
}, 1000);
this.newMessage = '';
},
autoReply(userMessage) {
let replyText = '';
//
if (userMessage.includes('订单') || userMessage.includes('物流')) {
replyText = '您可以在"我的订单"页面查看订单详情和物流信息。';
} else if (userMessage.includes('支付') || userMessage.includes('付款')) {
replyText = '我们支持支付宝、微信支付、银联等多种支付方式。';
} else if (userMessage.includes('退货') || userMessage.includes('退款')) {
replyText = '如需退货退款,请在订单详情页提交申请,客服会尽快处理。';
} else if (userMessage.includes('会员') || userMessage.includes('优惠')) {
replyText = '会员可享受专属折扣和优惠券,详情请查看会员中心。';
} else if (userMessage.includes('发票')) {
replyText = '您可以在下单时选择开具发票,我们提供电子发票和纸质发票两种方式。';
} else {
replyText = '抱歉,我没有完全理解您的问题。您可以尝试联系人工客服获得更详细的帮助。';
}
//
this.messages.push({
text: replyText,
sender: 'service',
time: this.formatTime(new Date())
});
//
this.scrollToBottom();
},
selectFaq(faq) {
//
this.messages.push({
text: faq.question,
sender: 'customer',
time: this.formatTime(new Date())
});
//
setTimeout(() => {
this.messages.push({
text: faq.answer,
sender: 'service',
time: this.formatTime(new Date())
});
this.scrollToBottom();
}, 1000);
},
scrollToBottom() {
this.$nextTick(() => {
const container = this.$refs.messagesContainer;
container.scrollTop = container.scrollHeight;
});
},
formatTime(date) {
const hours = date.getHours().toString().padStart(2, '0');
const minutes = date.getMinutes().toString().padStart(2, '0');
return `${hours}:${minutes}`;
}
},
watch: {
messages: {
handler() {
this.scrollToBottom();
},
deep: true
}
}
}
</script>
<style scoped>
#app {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
margin: 20px;
}
.customer-service {
/* max-width: 1000px; */
margin: 0 auto;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
border-radius: 4px;
}
.service-header {
background-color: #409EFF;
color: white;
padding: 15px 20px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.service-container {
display: flex;
min-height: 400px;
}
.faq-section {
width: 30%;
border-right: 1px solid #e6e6e6;
overflow-y: auto;
padding: 15px;
}
.chat-section {
width: 100%;
display: flex;
flex-direction: column;
}
.chat-messages {
flex: 1;
overflow-y: auto;
padding: 15px;
}
.message {
margin-bottom: 15px;
display: flex;
}
.message.customer {
justify-content: flex-end;
}
.message-content {
max-width: 70%;
padding: 10px 15px;
border-radius: 4px;
}
.message.customer .message-content {
background-color: #ecf5ff;
border: 1px solid #d9ecff;
}
.message.service .message-content {
background-color: #f4f4f5;
border: 1px solid #e9e9eb;
}
.chat-input {
padding: 15px;
border-top: 1px solid #e6e6e6;
display: flex;
}
.chat-input .el-input {
margin-right: 10px;
}
.faq-item {
padding: 10px;
margin-bottom: 10px;
border-radius: 4px;
cursor: pointer;
border: 1px solid #ebeef5;
}
.faq-item:hover {
background-color: #f5f7fa;
}
.timestamp {
font-size: 12px;
color: #909399;
margin-top: 5px;
text-align: right;
}
</style>

@ -9,19 +9,6 @@
</div>
<div class="service-container">
<!-- 左侧常见问题 -->
<!-- <div class="faq-section">
<h3>常见问题</h3>
<div
v-for="(faq, index) in faqs"
:key="index"
class="faq-item"
@click="selectFaq(faq)"
>
{{ faq.question }}
</div>
</div> -->
<!-- 右侧聊天区域 -->
<div class="chat-section">
<div class="chat-messages" ref="messagesContainer">
@ -56,7 +43,7 @@
</template>
<script>
import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus, deptTreeSelect } from "@/api/inMonitoring/assessment"
import { knowledgeAsk } from "@/api/inMonitoring/assessment"
import { getToken } from "@/utils/auth"
import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
@ -92,7 +79,6 @@ export default {
methods: {
sendMessage() {
if (!this.newMessage.trim()) return;
//
this.messages.push({
text: this.newMessage,
@ -107,22 +93,13 @@ export default {
this.newMessage = '';
},
autoReply(userMessage) {
async autoReply(userMessage) {
let replyText = '';
//
if (userMessage.includes('订单') || userMessage.includes('物流')) {
replyText = '您可以在"我的订单"页面查看订单详情和物流信息。';
} else if (userMessage.includes('支付') || userMessage.includes('付款')) {
replyText = '我们支持支付宝、微信支付、银联等多种支付方式。';
} else if (userMessage.includes('退货') || userMessage.includes('退款')) {
replyText = '如需退货退款,请在订单详情页提交申请,客服会尽快处理。';
} else if (userMessage.includes('会员') || userMessage.includes('优惠')) {
replyText = '会员可享受专属折扣和优惠券,详情请查看会员中心。';
} else if (userMessage.includes('发票')) {
replyText = '您可以在下单时选择开具发票,我们提供电子发票和纸质发票两种方式。';
let res = await knowledgeAsk({question: userMessage });
if (res.code == 200) {
replyText = res.data.answer;
}else {
replyText = '抱歉,我没有完全理解您的问题。您可以尝试联系人工客服获得更详细的帮助。';
replyText = '很抱歉,暂时无法回答您的问题。您可以尝试其他常见问题或联系客服人员。';
}
//
@ -213,6 +190,7 @@ export default {
flex: 1;
overflow-y: auto;
padding: 15px;
max-height: 350px;
}
.message {
margin-bottom: 15px;

@ -1,272 +0,0 @@
<template>
<div class="chat-container">
<!-- 消息列表区域 -->
<el-scrollbar
ref="messageScroll"
class="message-area"
@scroll.native="handleScroll">
<div
v-for="(msg, index) in messages"
:key="index"
:class="['message', msg.sender === 'user' ? 'user-msg' : 'customer-msg']">
<el-avatar :size="40" :src="msg.avatar"></el-avatar>
<div class="message-content">
<div class="sender">{{ msg.sender === 'user' ? '我' : '客服' }}</div>
<div class="content">{{ msg.content }}</div>
<div class="time">{{ formatTime(msg.timestamp) }}</div>
</div>
</div>
<!-- 加载中提示 -->
<div
v-if="loading"
class="loading-indicator">
<i class="el-icon-loading"></i> 加载中...
</div>
</el-scrollbar>
<!-- 输入区域 -->
<div class="input-area">
<el-input
v-model="inputMessage"
type="textarea"
placeholder="请输入消息..."
@keyup.enter.native="sendMessage"
:disabled="!connected">
</el-input>
<div class="action-buttons">
<el-button
type="primary"
@click="sendMessage"
:disabled="!connected || !inputMessage.trim()"
:loading="sending">
发送
</el-button>
<el-button @click="toggleConnection">
{{ connected ? '断开' : '连接' }}
</el-button>
</div>
</div>
</div>
</template>
<script>
import { Loading } from 'element-ui';
export default {
data() {
return {
messages: [],
inputMessage: '',
connected: false,
loading: false,
sending: false,
page: 1,
pageSize: 20
};
},
mounted() {
this.connect();
this.scrollToBottom();
},
methods: {
//
connect() {
this.connected = true;
this.loadMessages();
},
//
toggleConnection() {
this.connected = !this.connected;
if (this.connected) {
this.loadMessages();
}
},
//
async loadMessages() {
this.loading = true;
try {
// API
const response = await this.mockApiCall();
this.messages = response.data;
this.page++;
} catch (error) {
console.error('加载消息失败:', error);
} finally {
this.loading = false;
this.$nextTick(this.scrollToBottom);
}
},
//
sendMessage() {
if (!this.inputMessage.trim()) return;
this.sending = true;
//
setTimeout(() => {
this.messages.push({
sender: 'user',
content: this.inputMessage,
timestamp: Date.now(),
avatar: 'https://via.placeholder.com/40?text=U'
});
this.inputMessage = '';
this.sending = false;
this.scrollToBottom();
//
this.simulateCustomerReply();
}, 500);
},
//
simulateCustomerReply() {
setTimeout(() => {
this.messages.push({
sender: 'customer',
content: '您好,已收到您的消息,我们会尽快处理',
timestamp: Date.now(),
avatar: 'https://via.placeholder.com/40?text=C'
});
this.scrollToBottom();
}, 1000);
},
//
scrollToBottom() {
const scrollContainer = this.$refs.messageScroll.$el.querySelector('.el-scrollbar__wrap');
if (scrollContainer) {
scrollContainer.scrollTop = scrollContainer.scrollHeight;
}
},
//
handleScroll(e) {
const { scrollTop, scrollHeight, clientHeight } = e.target;
const scrollBottom = scrollHeight - scrollTop - clientHeight;
//
if (scrollBottom < 50 && !this.loading) {
this.loadMoreMessages();
}
},
//
async loadMoreMessages() {
this.loading = true;
try {
// API
const response = await this.mockApiCall(this.page);
this.messages = [...response.data, ...this.messages];
this.page++;
} catch (error) {
console.error('加载更多消息失败:', error);
} finally {
this.loading = false;
}
},
//
formatTime(timestamp) {
return new Date(timestamp).toLocaleTimeString();
},
// API
mockApiCall(page = 1) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
data: Array(this.pageSize).fill().map((_, i) => ({
sender: Math.random() > 0.5 ? 'user' : 'customer',
content: `消息 ${(page-1)*this.pageSize + i + 1}`,
timestamp: Date.now() - i * 1000,
avatar: Math.random() > 0.5
? 'https://via.placeholder.com/40?text=U'
: 'https://via.placeholder.com/40?text=C'
}))
});
}, 800);
});
}
}
};
</script>
<style>
.chat-container {
display: flex;
flex-direction: column;
height: 100vh;
border: 1px solid #ebeef5;
border-radius: 4px;
}
.message-area {
flex: 1;
padding: 20px;
overflow-y: auto;
}
.message {
display: flex;
margin-bottom: 20px;
}
.user-msg {
flex-direction: row-reverse;
}
.customer-msg {
flex-direction: row;
}
.message-content {
margin-left: 15px;
background: #f0f0f0;
padding: 12px;
border-radius: 8px;
max-width: 80%;
}
.user-msg .message-content {
background: #e1f0ff;
}
.sender {
font-weight: bold;
margin-bottom: 5px;
}
.content {
white-space: pre-wrap;
}
.time {
font-size: 0.8em;
color: #999;
text-align: right;
margin-top: 5px;
}
.input-area {
padding: 15px;
border-top: 1px solid #ebeef5;
background: #fff;
}
.action-buttons {
display: flex;
justify-content: flex-end;
margin-top: 10px;
}
.loading-indicator {
text-align: center;
padding: 15px;
color: #999;
}
</style>

@ -70,7 +70,7 @@
</template>
<script>
import { list, del, add, update } from "@/api/QandA/knowledge"
import { list, del, add, update, permanentKnowledgeList, uploadedFilesList } from "@/api/QandA/knowledge"
import { getToken } from "@/utils/auth"
import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
@ -169,7 +169,7 @@ export default {
/** 查询类型列表 */
getList() {
this.loading = true
list(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
uploadedFilesList(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
this.userList = response.rows
this.total = response.total
this.loading = false

@ -46,19 +46,28 @@
></el-table-column>
<el-table-column label="预警时间" align="center" key="occurTime" prop="occurTime" />
<el-table-column label="预警等级" align="center" key="level" prop="level" :show-overflow-tooltip="true" />
<el-table-column label="预警信息" align="center" key="version" prop="version" :show-overflow-tooltip="true" />
<el-table-column label="预警信息" align="center" key="message" prop="message" width="200" />
<el-table-column label="预警状态" align="center" key="status">
<template slot-scope="scope">
<dict-tag :options="dict.type.alert_message_status" :value="scope.row.status"/>
</template>
</el-table-column>
<el-table-column label="处理人" align="center" key="handler" prop="handler" width="120" />
<el-table-column label="处理人" align="center" key="handler" prop="handler" width="120" >
<template slot-scope="scope">
<span>{{ scope.row.handler || '--' }}</span>
</template>
</el-table-column>
<el-table-column label="处理时间" align="center" prop="handleTime" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.handleTime) }}</span>
<span>{{ parseTime(scope.row.handleTime) || '--' }}</span>
</template>
</el-table-column>
<el-table-column label="解决方案" align="center" key="solution" prop="solution" :show-overflow-tooltip="true" />
<el-table-column label="解决方案" align="center" key="solution" prop="solution" :show-overflow-tooltip="true" >
<template slot-scope="scope">
<span>{{ scope.row.solution || '--'}}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" v-if="scope.row.status == 'UNHANDLED'" type="text" @click="handleUpdate(scope.row)" v-hasPermi="['device:files:edit']">去处理</el-button>

@ -338,6 +338,7 @@ export default {
/** 重置按钮操作 */
resetQuery() {
this.dateRange = []
this.queryParams.severity = undefined
this.resetForm("queryForm")
this.handleQuery()
},

Loading…
Cancel
Save