feat(electron-vue-template):重构认证与设备管理模块
- 统一token存取逻辑,封装getToken/setToken/removeToken方法 -优化设备ID获取逻辑,调整API路径 - 完善设备管理接口类型定义,增强类型安全 - 调整SSE连接逻辑,使用统一配置管理- 重构HTTP客户端,集中管理后端服务配置 - 更新认证相关API接口,完善请求/响应类型 - 优化设备列表展示逻辑,移除冗余字段 - 调整图片代理路径,统一API前缀 - 完善用户反馈列表展示功能,增强交互体验 - 移除冗余的错误处理逻辑,简化代码结构
This commit is contained in:
57
ruoyi-ui/src/api/monitor/feedback.js
Normal file
57
ruoyi-ui/src/api/monitor/feedback.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询反馈列表
|
||||
export function listFeedback(query) {
|
||||
return request({
|
||||
url: '/monitor/feedback/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询反馈详细
|
||||
export function getFeedback(id) {
|
||||
return request({
|
||||
url: '/monitor/feedback/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 更新反馈状态
|
||||
export function updateFeedbackStatus(id, data) {
|
||||
return request({
|
||||
url: '/monitor/feedback/status/' + id,
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除反馈
|
||||
export function delFeedback(id) {
|
||||
return request({
|
||||
url: '/monitor/feedback/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取反馈统计信息
|
||||
export function getFeedbackStatistics() {
|
||||
return request({
|
||||
url: '/monitor/feedback/statistics',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取反馈日志内容(用于在线查看)
|
||||
export function getFeedbackLogContent(id) {
|
||||
return request({
|
||||
url: '/monitor/feedback/log/content/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 下载反馈日志文件
|
||||
export function downloadFeedbackLog(id) {
|
||||
return process.env.VUE_APP_BASE_API + '/monitor/feedback/log/download/' + id
|
||||
}
|
||||
|
||||
@@ -56,17 +56,17 @@
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card class="monitor-card">
|
||||
<el-card class="monitor-card clickable-card" @click.native="showFeedbackList">
|
||||
<template v-slot:header>
|
||||
<div class="card-header">
|
||||
<i class="el-icon-s-data"></i>
|
||||
<span>离线设备</span>
|
||||
<i class="el-icon-chat-line-square"></i>
|
||||
<span>用户反馈</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="card-body">
|
||||
<count-to :start-val="0" :end-val="statisticsData.totalCount - statisticsData.onlineCount" :duration="2500" class="card-value" />
|
||||
<count-to :start-val="0" :end-val="feedbackStats.pendingCount" :duration="2500" class="card-value" />
|
||||
<div class="card-footer">
|
||||
<span>离线设备数</span>
|
||||
<span>待处理: {{ feedbackStats.pendingCount }} / 今日: {{ feedbackStats.todayCount }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
@@ -116,18 +116,18 @@
|
||||
</div>
|
||||
</template>
|
||||
<el-table :data="clientList" style="width: 100%" v-loading="loading">
|
||||
<el-table-column prop="clientId" label="设备ID" width="240" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="username" label="账号" width="120"></el-table-column>
|
||||
<el-table-column prop="hostname" label="设备名称" width="150" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="osName" label="操作系统" width="120"></el-table-column>
|
||||
<el-table-column prop="ipAddress" label="IP地址" width="150"></el-table-column>
|
||||
<el-table-column prop="lastActiveTime" label="最后活跃时间" width="180"></el-table-column>
|
||||
<el-table-column prop="online" label="状态" width="100">
|
||||
<el-table-column prop="clientId" label="设备ID" min-width="240" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="username" label="账号" min-width="120"></el-table-column>
|
||||
<el-table-column prop="hostname" label="设备名称" min-width="150" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="osName" label="操作系统" min-width="120"></el-table-column>
|
||||
<el-table-column prop="ipAddress" label="IP地址" min-width="150"></el-table-column>
|
||||
<el-table-column prop="lastActiveTime" label="最后活跃时间" min-width="180"></el-table-column>
|
||||
<el-table-column prop="online" label="状态" min-width="100">
|
||||
<template v-slot="scope">
|
||||
<el-tag :type="scope.row.online === '1' ? 'success' : 'info'">{{ scope.row.online === '1' ? '在线' : '离线' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120">
|
||||
<el-table-column label="操作" min-width="120">
|
||||
<template v-slot="scope">
|
||||
<el-button size="mini" type="text" @click="viewClientData(scope.row)">详情</el-button>
|
||||
</template>
|
||||
@@ -241,6 +241,111 @@
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 用户反馈列表弹窗 -->
|
||||
<el-dialog title="用户反馈列表" :visible.sync="feedbackDialogVisible" width="80%">
|
||||
<el-table :data="feedbackList" style="width: 100%" v-loading="feedbackLoading">
|
||||
<el-table-column prop="id" label="ID" width="80"></el-table-column>
|
||||
<el-table-column prop="username" label="用户名" width="120"></el-table-column>
|
||||
<el-table-column prop="deviceId" label="设备ID" width="200" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="feedbackContent" label="反馈内容" min-width="250" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="logDate" label="日志日期" width="120">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.logDate || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="getFeedbackStatusType(scope.row.status)" size="small">
|
||||
{{ getFeedbackStatusText(scope.row.status) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="提交时间" width="180"></el-table-column>
|
||||
<el-table-column label="操作" width="300" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" @click="viewFeedbackDetail(scope.row)">详情</el-button>
|
||||
<el-button size="mini" type="text" @click="viewFeedbackLog(scope.row)" v-if="scope.row.logFilePath">
|
||||
查看日志
|
||||
</el-button>
|
||||
<el-button size="mini" type="text" @click="handleFeedbackStatus(scope.row, 'processing')"
|
||||
v-if="scope.row.status === 'pending'">
|
||||
处理中
|
||||
</el-button>
|
||||
<el-button size="mini" type="text" @click="handleFeedbackStatus(scope.row, 'completed')"
|
||||
v-if="scope.row.status !== 'completed'">
|
||||
完成
|
||||
</el-button>
|
||||
<el-button size="mini" type="text" style="color: #F56C6C;" @click="deleteFeedback(scope.row)">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
background
|
||||
@size-change="handleFeedbackSizeChange"
|
||||
@current-change="handleFeedbackCurrentChange"
|
||||
:current-page="feedbackQueryParams.pageNum"
|
||||
:page-sizes="[10, 20, 30, 50]"
|
||||
:page-size="feedbackQueryParams.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="feedbackTotal">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 反馈详情弹窗 -->
|
||||
<el-dialog title="反馈详情" :visible.sync="feedbackDetailDialogVisible" width="60%">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="反馈ID">{{ currentFeedback.id }}</el-descriptions-item>
|
||||
<el-descriptions-item label="用户名">{{ currentFeedback.username }}</el-descriptions-item>
|
||||
<el-descriptions-item label="设备ID" :span="2">{{ currentFeedback.deviceId }}</el-descriptions-item>
|
||||
<el-descriptions-item label="状态">
|
||||
<el-tag :type="getFeedbackStatusType(currentFeedback.status)" size="small">
|
||||
{{ getFeedbackStatusText(currentFeedback.status) }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="日志日期">
|
||||
{{ currentFeedback.logDate || '未附带日志' }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="提交时间" :span="2">{{ currentFeedback.createTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="反馈内容" :span="2">
|
||||
<div style="white-space: pre-wrap; word-wrap: break-word;">{{ currentFeedback.feedbackContent }}</div>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="处理备注" :span="2" v-if="currentFeedback.remark">
|
||||
<div style="white-space: pre-wrap; word-wrap: break-word;">{{ currentFeedback.remark }}</div>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="feedbackDetailDialogVisible = false">关闭</el-button>
|
||||
<el-button type="primary" @click="viewFeedbackLog(currentFeedback)" v-if="currentFeedback.logFilePath">
|
||||
查看日志
|
||||
</el-button>
|
||||
<el-button @click="downloadFeedbackLogFile(currentFeedback)" v-if="currentFeedback.logFilePath">
|
||||
下载日志
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 反馈日志查看弹窗 -->
|
||||
<el-dialog :title="'反馈日志: ' + currentFeedbackLog.username" :visible.sync="feedbackLogDialogVisible" width="80%" top="5vh">
|
||||
<div class="log-container">
|
||||
<div class="log-header">
|
||||
<el-button type="primary" size="small" @click="loadFeedbackLog(currentFeedbackLog.id)" :loading="feedbackLogLoading">
|
||||
<i class="el-icon-refresh"></i> 刷新
|
||||
</el-button>
|
||||
<el-button type="success" size="small" @click="downloadFeedbackLogFile(currentFeedbackLog)">
|
||||
<i class="el-icon-download"></i> 下载日志
|
||||
</el-button>
|
||||
<span class="log-info">日志日期: {{ currentFeedbackLog.logDate || '-' }}</span>
|
||||
</div>
|
||||
<div class="log-content" v-loading="feedbackLogLoading">
|
||||
<pre class="log-text">{{ feedbackLogContent }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -250,6 +355,7 @@ import LineChart from '@/components/Charts/LineChart'
|
||||
import PieChart from '@/components/Charts/PieChart'
|
||||
import { listInfo, listError, listData } from '@/api/monitor/client'
|
||||
import { getVersionInfo } from '@/api/monitor/version'
|
||||
import { listFeedback, getFeedback, updateFeedbackStatus, delFeedback, getFeedbackLogContent, downloadFeedbackLog } from '@/api/monitor/feedback'
|
||||
import request from '@/utils/request'
|
||||
|
||||
export default {
|
||||
@@ -321,7 +427,27 @@ export default {
|
||||
logLoading: false,
|
||||
currentLogClient: {},
|
||||
logContent: '',
|
||||
lastLogUpdate: ''
|
||||
lastLogUpdate: '',
|
||||
// 用户反馈
|
||||
feedbackDialogVisible: false,
|
||||
feedbackLoading: false,
|
||||
feedbackList: [],
|
||||
feedbackQueryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
feedbackTotal: 0,
|
||||
feedbackDetailDialogVisible: false,
|
||||
currentFeedback: {},
|
||||
feedbackStats: {
|
||||
pendingCount: 0,
|
||||
todayCount: 0
|
||||
},
|
||||
// 反馈日志查看
|
||||
feedbackLogDialogVisible: false,
|
||||
feedbackLogLoading: false,
|
||||
feedbackLogContent: '',
|
||||
currentFeedbackLog: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@@ -329,6 +455,7 @@ export default {
|
||||
this.getOnlineClientTrend()
|
||||
this.getDataTypeDistribution()
|
||||
this.getClientList()
|
||||
this.getFeedbackStatistics()
|
||||
},
|
||||
methods: {
|
||||
// 获取统计数据
|
||||
@@ -558,6 +685,186 @@ export default {
|
||||
console.error('获取版本信息失败:', error)
|
||||
this.$message.error('获取下载链接失败: ' + (error.message || '网络错误'))
|
||||
})
|
||||
},
|
||||
|
||||
// 获取反馈统计信息
|
||||
getFeedbackStatistics() {
|
||||
request.get('/monitor/feedback/statistics').then(res => {
|
||||
if (res.code === 200) {
|
||||
this.feedbackStats = {
|
||||
pendingCount: res.data.pendingCount || 0,
|
||||
todayCount: res.data.todayCount || 0
|
||||
}
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('获取反馈统计失败:', error)
|
||||
})
|
||||
},
|
||||
|
||||
// 显示反馈列表
|
||||
showFeedbackList() {
|
||||
this.feedbackDialogVisible = true
|
||||
this.getFeedbackList()
|
||||
},
|
||||
|
||||
// 获取反馈列表
|
||||
getFeedbackList() {
|
||||
this.feedbackLoading = true
|
||||
listFeedback(this.feedbackQueryParams).then(res => {
|
||||
this.feedbackLoading = false
|
||||
if (res.code === 200) {
|
||||
this.feedbackList = res.rows || []
|
||||
this.feedbackTotal = res.total || 0
|
||||
}
|
||||
}).catch(() => {
|
||||
this.feedbackLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 查看反馈详情
|
||||
viewFeedbackDetail(row) {
|
||||
this.currentFeedback = {...row}
|
||||
this.feedbackDetailDialogVisible = true
|
||||
},
|
||||
|
||||
// 查看反馈日志
|
||||
viewFeedbackLog(row) {
|
||||
if (!row.logFilePath) {
|
||||
this.$message.warning('该反馈未附带日志文件')
|
||||
return
|
||||
}
|
||||
this.currentFeedbackLog = {...row}
|
||||
this.feedbackLogDialogVisible = true
|
||||
this.loadFeedbackLog(row.id)
|
||||
},
|
||||
|
||||
// 加载反馈日志内容
|
||||
loadFeedbackLog(id) {
|
||||
this.feedbackLogLoading = true
|
||||
this.feedbackLogContent = ''
|
||||
getFeedbackLogContent(id).then(res => {
|
||||
this.feedbackLogLoading = false
|
||||
if (res.code === 200) {
|
||||
this.feedbackLogContent = res.data.content || '日志内容为空'
|
||||
} else {
|
||||
this.$message.error(res.msg || '获取日志失败')
|
||||
this.feedbackLogContent = '获取日志失败'
|
||||
}
|
||||
}).catch(error => {
|
||||
this.feedbackLogLoading = false
|
||||
this.$message.error('获取日志失败: ' + (error.message || '未知错误'))
|
||||
this.feedbackLogContent = '获取日志失败: ' + (error.message || '未知错误')
|
||||
})
|
||||
},
|
||||
|
||||
// 下载反馈日志
|
||||
downloadFeedbackLogFile(row) {
|
||||
if (!row.logFilePath) {
|
||||
this.$message.warning('该反馈未附带日志文件')
|
||||
return
|
||||
}
|
||||
// 使用request下载文件(带token)
|
||||
const url = '/monitor/feedback/log/download/' + row.id
|
||||
const loading = this.$loading({
|
||||
lock: true,
|
||||
text: '正在下载日志文件...',
|
||||
spinner: 'el-icon-loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)'
|
||||
})
|
||||
|
||||
request({
|
||||
url: url,
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
}).then(response => {
|
||||
const blob = new Blob([response])
|
||||
const link = document.createElement('a')
|
||||
link.href = window.URL.createObjectURL(blob)
|
||||
link.download = `feedback_${row.id}_log.txt`
|
||||
link.click()
|
||||
window.URL.revokeObjectURL(link.href)
|
||||
loading.close()
|
||||
this.$message.success('下载成功')
|
||||
}).catch(error => {
|
||||
loading.close()
|
||||
console.error('下载失败:', error)
|
||||
this.$message.error('下载失败: ' + (error.message || '请稍后重试'))
|
||||
})
|
||||
},
|
||||
|
||||
// 更新反馈状态
|
||||
handleFeedbackStatus(row, status) {
|
||||
this.$prompt('请输入处理备注(可选)', '更新状态', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
inputType: 'textarea'
|
||||
}).then(({ value }) => {
|
||||
updateFeedbackStatus(row.id, {
|
||||
status: status,
|
||||
remark: value || ''
|
||||
}).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.$message.success('状态更新成功')
|
||||
this.getFeedbackList()
|
||||
this.getFeedbackStatistics()
|
||||
} else {
|
||||
this.$message.error(res.msg || '更新失败')
|
||||
}
|
||||
}).catch(error => {
|
||||
this.$message.error('更新失败: ' + (error.message || '未知错误'))
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
// 删除反馈
|
||||
deleteFeedback(row) {
|
||||
this.$confirm('确定要删除该反馈吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
delFeedback(row.id).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.$message.success('删除成功')
|
||||
this.getFeedbackList()
|
||||
this.getFeedbackStatistics()
|
||||
} else {
|
||||
this.$message.error(res.msg || '删除失败')
|
||||
}
|
||||
}).catch(error => {
|
||||
this.$message.error('删除失败: ' + (error.message || '未知错误'))
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
// 反馈分页
|
||||
handleFeedbackSizeChange(val) {
|
||||
this.feedbackQueryParams.pageSize = val
|
||||
this.getFeedbackList()
|
||||
},
|
||||
handleFeedbackCurrentChange(val) {
|
||||
this.feedbackQueryParams.pageNum = val
|
||||
this.getFeedbackList()
|
||||
},
|
||||
|
||||
// 获取状态标签类型
|
||||
getFeedbackStatusType(status) {
|
||||
const typeMap = {
|
||||
'pending': 'warning',
|
||||
'processing': 'primary',
|
||||
'completed': 'success'
|
||||
}
|
||||
return typeMap[status] || 'info'
|
||||
},
|
||||
|
||||
// 获取状态文本
|
||||
getFeedbackStatusText(status) {
|
||||
const textMap = {
|
||||
'pending': '待处理',
|
||||
'processing': '处理中',
|
||||
'completed': '已完成'
|
||||
}
|
||||
return textMap[status] || status
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user