607 lines
18 KiB
Vue
607 lines
18 KiB
Vue
<template>
|
||
<div class="group-container">
|
||
<div class="infinite-list" v-infinite-scroll="listLoad" style="overflow: auto"
|
||
:infinite-scroll-immediate="false" infinite-scroll-distance="10">
|
||
<el-card class="add-robot">
|
||
<div class="add-box" @click="handleAdd">
|
||
<el-icon>
|
||
<Plus></Plus>
|
||
</el-icon>
|
||
添加机器人
|
||
</div>
|
||
</el-card>
|
||
|
||
<el-card v-for="(item, index) in robotCards" :key="item.index"
|
||
:class="{ 'active-robot': newRobotId == item.id }" @click="handleRobot(item)">
|
||
<div class="robot-title">
|
||
|
||
<el-image class="robot-head" :src="item.head_url"></el-image>
|
||
<p class="robot-name-box">
|
||
<label class="name">{{ item.name }}</label>
|
||
<label class="wx_name"> 微信:{{ item.wx_name
|
||
}}</label>
|
||
<label class="wx_name"> 服务:{{ item.server_ip }}</label>
|
||
</p>
|
||
</div>
|
||
|
||
|
||
<p class="description">描述:{{ item.description }}</p>
|
||
<span v-if="item.status == 1" class="success"> 运行中 </span>
|
||
<span v-if="item.status == 2" class="danger"> 异常 </span>
|
||
<el-popover @click.stop placement="bottom" width="120px" trigger="hover">
|
||
<template #reference>
|
||
<span class="edit-icon" @click.stop>
|
||
<el-icon>
|
||
<MoreFilled />
|
||
</el-icon>
|
||
</span>
|
||
</template>
|
||
<template #default>
|
||
<ul class="popover-list" @click.stop>
|
||
<li class="edit-icon" @click.stop="setMonitor(item)">
|
||
<el-icon>
|
||
<svg class="icon" aria-hidden="true">
|
||
<use xlink:href="#icon-jiance"></use>
|
||
</svg>
|
||
|
||
</el-icon> 巡检
|
||
<el-icon v-if="xjLoading" class="mht-loading" style="margin-left: 4px;">
|
||
<Loading />
|
||
</el-icon>
|
||
</li>
|
||
<li class="rizhi-icon" @click.stop="openLog(item)">
|
||
<el-icon>
|
||
<ChatLineSquare />
|
||
</el-icon> 日志
|
||
</li>
|
||
<li class="edit-icon" @click.stop="handleEdit(item, index)">
|
||
<el-icon>
|
||
<Edit></Edit>
|
||
</el-icon> 编辑
|
||
</li>
|
||
|
||
|
||
<li class="delete-icon" @click.stop="handleDelete(item, index)">
|
||
<el-icon>
|
||
<Delete />
|
||
</el-icon> 删除
|
||
</li>
|
||
</ul>
|
||
</template>
|
||
|
||
</el-popover>
|
||
<!-- <span class="act-icon">
|
||
<el-icon>
|
||
<svg class="icon" aria-hidden="true">
|
||
<use xlink:href="#icon-duigou3"></use>
|
||
</svg>
|
||
</el-icon>
|
||
</span> -->
|
||
</el-card>
|
||
</div>
|
||
<el-dialog v-model="dialogVisible" :title="isEdit ? '编辑机器人' : '添加机器人'" width="600px" align-center
|
||
:before-close="handleClose">
|
||
<div class="dialog-box">
|
||
|
||
<el-form ref="ruleFormRef" :model="ruleForm" :rules="rules">
|
||
<el-form-item label="机器人名称" prop="name">
|
||
<el-input v-model="ruleForm.name" placeholder="请输入机器人名称" size="large" />
|
||
</el-form-item>
|
||
<el-form-item label="机器人描述" prop="description">
|
||
<el-input type="textarea" row="3" v-model="ruleForm.description" placeholder="请输入机器人描述"
|
||
size="large" />
|
||
</el-form-item>
|
||
<el-form-item label="机器人地址" prop="server_ip" v-if="!isEdit">
|
||
<el-input v-model="ruleForm.server_ip" :readonly="isEdit" placeholder="请输入机器人地址" size="large" />
|
||
<p>示例:http://210.198.123.58</p>
|
||
</el-form-item>
|
||
|
||
|
||
</el-form>
|
||
</div>
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<el-button type="primary" @click="submitRobot" :class="{ 'no-click': mhtLoading }">
|
||
<el-icon v-if="mhtLoading" class="mht-loading" style="margin-right: 4px;">
|
||
<Loading />
|
||
</el-icon>
|
||
<el-icon v-else style="margin-right: 4px;">
|
||
<svg class="icon" aria-hidden="true">
|
||
<use xlink:href="#icon-baocun"></use>
|
||
</svg></el-icon>
|
||
{{ isEdit ? '保 存' : '添 加' }}
|
||
</el-button>
|
||
</div>
|
||
</template>
|
||
</el-dialog>
|
||
<el-dialog v-model="dialogLog" title="机器人日志" width="1000px" align-center :before-close="handleClose">
|
||
<div class="dialog-box">
|
||
|
||
<el-table :data="logList" style="width: 100%" max-height="500px" :row-class-name="rowClassname">
|
||
<template #empty>
|
||
<span v-if="tableLoading">加载中...</span>
|
||
<span v-if="!tableLoading">暂无数据</span>
|
||
</template>
|
||
<el-table-column prop="created_at" label="监听时间" align="center" width="160">
|
||
</el-table-column>
|
||
<el-table-column prop="remark" label="监听结果" align="center" header-align="center" />
|
||
</el-table>
|
||
<div class="pagination-box">
|
||
<el-pagination v-model:current-page="logQuery.page" v-model:page-size="logQuery.page_size"
|
||
:page-sizes="[10, 20, 30, 40, 50]" :size="logQuery.page_size" background
|
||
layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handleSizeChange"
|
||
@current-change="handleCurrentChange" />
|
||
</div>
|
||
</div>
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<el-button type="primary" @click="dialogLog = false">
|
||
关闭
|
||
</el-button>
|
||
</div>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
</div>
|
||
</template>
|
||
<script setup>
|
||
import { ref, onMounted, reactive, nextTick } from 'vue'
|
||
import { robotList, addRobot, deleteRobot, editRobot, robotLog, robot_monitor } from '@/api/robot'
|
||
import { ElNotification } from 'element-plus';
|
||
import robotStore from '@/store/modules/robotStore'
|
||
import { useRouter } from 'vue-router';
|
||
const userRobotStore = robotStore()
|
||
const router = useRouter()
|
||
const robotCards = ref([])
|
||
const dialogVisible = ref(false)
|
||
const loading = ref(false)
|
||
const ruleFormRef = ref()
|
||
const ruleForm = ref({})
|
||
const isEdit = ref(false)
|
||
const newRobotId = ref('')
|
||
let robotCopy = {}
|
||
const rules = ref({
|
||
name: [
|
||
{
|
||
required: true,
|
||
message: '请输入机器人名称',
|
||
trigger: 'change',
|
||
}
|
||
],
|
||
description: [{
|
||
required: true,
|
||
message: '请输入机器人描述',
|
||
trigger: 'change',
|
||
}],
|
||
server_ip: [{
|
||
required: true,
|
||
message: '请输入机器人地址',
|
||
trigger: 'change',
|
||
}]
|
||
})
|
||
const query = reactive({
|
||
page: 1,
|
||
page_size: 30
|
||
})
|
||
let robtoTotal = 0
|
||
const getTable = async () => {
|
||
const res = await robotList(query)
|
||
robotCards.value = [...robotCards.value, ...res.list]
|
||
robtoTotal = res.total
|
||
}
|
||
|
||
const listLoad = () => {
|
||
console.log('到底了')
|
||
if (robtoTotal > robotCards.value.length) {
|
||
query.page++
|
||
getTable()
|
||
}
|
||
|
||
}
|
||
const handleAdd = () => {
|
||
if (robotCards.value.length > 100) {
|
||
ElNotification({
|
||
title: '提示',
|
||
message: '最多添加100个机器人',
|
||
type: 'warning',
|
||
duration: 2000
|
||
})
|
||
return
|
||
}
|
||
isEdit.value = false
|
||
dialogVisible.value = true
|
||
nextTick(() => {
|
||
ruleForm.value = {}
|
||
ruleFormRef.value.resetFields()
|
||
|
||
})
|
||
}
|
||
let editItem = {}
|
||
let editIndex = 0
|
||
const handleEdit = (item, index) => {
|
||
isEdit.value = true
|
||
editItem = item
|
||
editIndex = index
|
||
ruleForm.value = JSON.parse(JSON.stringify(item))
|
||
dialogVisible.value = true
|
||
}
|
||
const mhtLoading = ref(false)
|
||
const submitRobot = async () => {
|
||
mhtLoading.value = true
|
||
await ruleFormRef.value.validate(async (valid, fields) => {
|
||
if (valid) {
|
||
if (isEdit.value) {
|
||
try {
|
||
|
||
const res = await editRobot(ruleForm.value.id, {
|
||
description: ruleForm.value.description,
|
||
name: ruleForm.value.name,
|
||
})
|
||
editItem = ruleForm.value
|
||
robotCards.value[editIndex] = editItem
|
||
// getTable()
|
||
dialogVisible.value = false
|
||
mhtLoading.value = false
|
||
ElNotification({
|
||
type: 'success',
|
||
message: '操作成功'
|
||
})
|
||
} catch {
|
||
mhtLoading.value = false
|
||
}
|
||
} else {
|
||
try {
|
||
const res = await addRobot(ruleForm.value)
|
||
robotCards.value.push({
|
||
...ruleForm.value,
|
||
id: res.id,
|
||
head_url: res.head_url,
|
||
status: res.status,
|
||
wx_name: res.wx_name
|
||
})
|
||
// getTable()
|
||
dialogVisible.value = false
|
||
mhtLoading.value = false
|
||
ElNotification({
|
||
type: 'success',
|
||
message: '操作成功'
|
||
})
|
||
} catch {
|
||
mhtLoading.value = false
|
||
}
|
||
|
||
}
|
||
|
||
} else {
|
||
mhtLoading.value = false
|
||
}
|
||
})
|
||
|
||
}
|
||
|
||
|
||
const handleDelete = (item, index) => {
|
||
ElMessageBox.confirm(
|
||
'确认删除该机器人吗?',
|
||
'提示',
|
||
{
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning',
|
||
}
|
||
)
|
||
.then(async () => {
|
||
ElNotification({
|
||
message: '删除中,请稍等',
|
||
type: 'success',
|
||
duration: 2000
|
||
})
|
||
await deleteRobot(item.id)
|
||
// getGroups()
|
||
robotCards.value.splice(index, 1)
|
||
|
||
})
|
||
.catch(() => {
|
||
|
||
})
|
||
}
|
||
const handleRobot = (row) => {
|
||
// newRobotId.value = row.id
|
||
userRobotStore.robotInfo = row
|
||
router.push('/dashboard')
|
||
}
|
||
const logQuery = reactive({
|
||
page: 1,
|
||
page_size: 10
|
||
})
|
||
const total = ref(0)
|
||
const dialogLog = ref(false)
|
||
const logList = ref([])
|
||
let robot_data = ''
|
||
const tableLoading = ref(false)
|
||
const openLog = async (row) => {
|
||
dialogLog.value = true
|
||
robot_data = row
|
||
tableLoading.value = true
|
||
const res = await robotLog({
|
||
robot_id: row.id,
|
||
...logQuery
|
||
})
|
||
tableLoading.value = false
|
||
logList.value = res.list
|
||
total.value = res.total
|
||
}
|
||
const handleSizeChange = (e) => {
|
||
logQuery.page = 1
|
||
logQuery.page_size = e
|
||
openLog(robot_data)
|
||
}
|
||
const handleCurrentChange = (e) => {
|
||
logQuery.page = e
|
||
openLog(robot_data)
|
||
}
|
||
|
||
const rowClassname = (e) => {
|
||
if (e.row.status == 1) {
|
||
return 'row-success'
|
||
} else {
|
||
return 'row-danger'
|
||
}
|
||
}
|
||
const xjLoading = ref(false)
|
||
const setMonitor = async (e) => {
|
||
if(xjLoading.value == true) return
|
||
try {
|
||
xjLoading.value = true
|
||
const res = await robot_monitor({
|
||
robot_id: e.id
|
||
})
|
||
e.status_text = res.status_text
|
||
e.status = res.status
|
||
xjLoading.value = false
|
||
ElNotification({
|
||
type: 'success',
|
||
message: '监听成功'
|
||
})
|
||
} catch (e) {
|
||
xjLoading.value = false
|
||
}
|
||
|
||
}
|
||
onMounted(() => {
|
||
query.page = 1
|
||
robotCards.value = []
|
||
getTable()
|
||
// newRobotId.value = userRobotStore.robotInfo.id ? userRobotStore.robotInfo.id : ''
|
||
})
|
||
</script>
|
||
<style></style>
|
||
<style lang="scss" scoped>
|
||
.group-container {
|
||
height: 100%;
|
||
|
||
.infinite-list {
|
||
height: 100%;
|
||
padding: var(--el-main-padding);
|
||
padding-right: 0;
|
||
}
|
||
|
||
.el-card {
|
||
width: 360px;
|
||
height: 160px;
|
||
cursor: pointer;
|
||
transition: all 0.3s;
|
||
position: relative;
|
||
float: left;
|
||
margin-right: 20px;
|
||
margin-bottom: 20px;
|
||
padding: 5px;
|
||
|
||
:deep(.el-card__body) {
|
||
height: 100%;
|
||
}
|
||
|
||
.robot-title {
|
||
overflow: hidden;
|
||
margin-bottom: 10px;
|
||
|
||
.robot-head {
|
||
float: left;
|
||
width: 64px;
|
||
height: 64px;
|
||
border-radius: 10px;
|
||
}
|
||
|
||
.robot-name-box {
|
||
float: left;
|
||
padding-left: 12px;
|
||
width: calc(100% - 66px);
|
||
|
||
label {
|
||
display: block;
|
||
line-height: 16px;
|
||
margin-bottom: 6px;
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
.name {
|
||
font-size: 15px;
|
||
font-weight: bold;
|
||
margin-top: 4px;
|
||
}
|
||
|
||
.wx_name {
|
||
display: block;
|
||
color: var(--el-text-color-regular);
|
||
}
|
||
|
||
.description {
|
||
width: 86%;
|
||
font-size: 14px;
|
||
line-height: 20px;
|
||
display: -webkit-box;
|
||
-webkit-box-orient: vertical;
|
||
/* 设置垂直排列 */
|
||
-webkit-line-clamp: 2;
|
||
/* 设置行数 */
|
||
overflow: hidden;
|
||
/* 设置超出省略 */
|
||
text-overflow: ellipsis;
|
||
/* 设置省略以...结尾 */
|
||
|
||
color: var(--el-text-color-secondary);
|
||
}
|
||
|
||
.success {
|
||
position: absolute;
|
||
right: 20px;
|
||
bottom: 21px;
|
||
font-size: 12px;
|
||
color: var(--el-color-success);
|
||
|
||
&::after {
|
||
position: absolute;
|
||
left: -15px;
|
||
top: 3px;
|
||
content: '';
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: 8px;
|
||
background-color: var(--el-color-success);
|
||
}
|
||
}
|
||
|
||
.danger {
|
||
position: absolute;
|
||
right: 20px;
|
||
bottom: 21px;
|
||
font-size: 12px;
|
||
color: var(--el-color-danger);
|
||
|
||
&::after {
|
||
position: absolute;
|
||
left: -15px;
|
||
top: 3px;
|
||
content: '';
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: 8px;
|
||
background-color: var(--el-color-danger);
|
||
}
|
||
}
|
||
|
||
&:hover {
|
||
transform: translateY(-6px);
|
||
background-color: var(--el-color-primary-light-7);
|
||
}
|
||
|
||
.icon-robot {
|
||
font-size: 66px;
|
||
}
|
||
|
||
.act-icon {
|
||
position: absolute;
|
||
font-size: 40px;
|
||
right: -2px;
|
||
bottom: -8px;
|
||
opacity: 0;
|
||
}
|
||
|
||
}
|
||
|
||
.active-robot {
|
||
.act-icon {
|
||
opacity: 0.6;
|
||
}
|
||
}
|
||
|
||
.add-robot {
|
||
|
||
background-image: url('@/assets/images/add_robot_bg.png');
|
||
background-color: var(--el-color-primary-light-5);
|
||
background-size: 100% auto;
|
||
|
||
&:hover {
|
||
transform: translateY(-10px);
|
||
}
|
||
|
||
.add-box {
|
||
height: 100%;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
color: var(--el-color-primary);
|
||
|
||
.el-icon {
|
||
position: relative;
|
||
top: -1px;
|
||
margin-right: 3px;
|
||
}
|
||
}
|
||
}
|
||
|
||
.edit-icon {
|
||
position: absolute;
|
||
right: 15px;
|
||
top: 14px;
|
||
// display: none;
|
||
height: 30px;
|
||
width: 30px;
|
||
text-align: center;
|
||
line-height: 30px;
|
||
border-radius: 8px;
|
||
transition: all 0.1s;
|
||
|
||
i {
|
||
position: relative;
|
||
left: 2px;
|
||
top: 3px;
|
||
color: var(--el-color-primary);
|
||
// color: #fff;
|
||
// transition: all 0.1s;
|
||
// transform: rotate(90deg);
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
}
|
||
|
||
.popover-list {
|
||
li {
|
||
height: 32px;
|
||
line-height: 32px;
|
||
padding-left: 10px;
|
||
// border-radius: 6px;
|
||
cursor: pointer;
|
||
|
||
// color: var(--el-color-primary);
|
||
.el-icon {
|
||
position: relative;
|
||
top: 2px;
|
||
margin-right: 4px;
|
||
}
|
||
|
||
&:hover {
|
||
background-color: var(--el-color-primary-light-9);
|
||
}
|
||
}
|
||
|
||
.rizhi-icon {
|
||
color: var(--el-color-warning);
|
||
}
|
||
|
||
.edit-icon {
|
||
color: var(--el-color-primary);
|
||
}
|
||
|
||
.delete-icon {
|
||
color: var(--el-color-danger);
|
||
}
|
||
}
|
||
</style> |