diff --git a/src/api/modules/task.js b/src/api/modules/task.js
index 0fdd0f1..9d9d9b2 100644
--- a/src/api/modules/task.js
+++ b/src/api/modules/task.js
@@ -8,6 +8,18 @@ const taskApi = {
// 停止指定任务
stopTask: (taskId) => instance.get(`/task/stopTask?taskId=${taskId}`),
+
+ // 获取任务日志列表
+ getLogsList: (id) => instance.get(`/task/logsList?id=${id}`),
+
+ // 获取任务日志消息
+ getLogsMsg: (id) => instance.get(`/task/logsMsg?id=${id}`),
+
+ // 获取任务详细日志列表
+ getLogsDetailList: (taskId, shopId) => instance.get(`/task/logsDetailList/${taskId}/${shopId}`),
+
+ // 下载日志文件
+ downloadLogs: (fileName) => instance.get(`/task/downloadLogs/${fileName}`, { responseType: 'blob' }),
};
// 导出模块
diff --git a/src/views/Task/List.vue b/src/views/Task/List.vue
index e8eecc8..dbca112 100644
--- a/src/views/Task/List.vue
+++ b/src/views/Task/List.vue
@@ -13,15 +13,8 @@
暂无运行中的任务
-
+
@@ -34,35 +27,39 @@
-
+
-
- 停止任务
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
{{ currentTask.id }}
@@ -71,16 +68,76 @@
{{ currentTask.dataNum }}
{{ currentTask.createTime }}
-
+
{{ currentTask.msg }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ scope.row.progress }}%
+
+
+
+
+ {{ scope.row.createTime }} / {{ scope.row.updateTime }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -88,6 +145,7 @@
import { ref, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { taskApi } from '@/api/modules/task'
+import { Document, VideoPause, View, Download, Refresh } from '@element-plus/icons-vue'
// 任务列表数据
const taskList = ref([])
@@ -101,16 +159,23 @@ const total = ref(0)
const currentPage = ref(1) // 界面显示的当前页,从1开始
const pageSize = ref(10) // 每页条数
+// 日志相关数据
+const logsVisible = ref(false)
+const logsLoading = ref(false)
+const logsList = ref([])
+const logsMessage = ref('')
+const currentTaskId = ref('')
+
// 获取任务列表
const fetchTaskList = async () => {
loading.value = true
try {
// 将currentPage转换为后端需要的pageSize(0表示第一页)
const pageIndex = currentPage.value - 1
-
+
const res = await taskApi.getRunningTasks(pageIndex, pageSize.value)
console.log('API响应数据:', res)
-
+
if (res.code === 200) {
// 适应后端返回的数据结构
if (res.data) {
@@ -175,7 +240,7 @@ const refreshTasks = () => {
// 停止任务
const handleStopTask = async (taskId) => {
- console.log("taskId",taskId)
+ console.log("taskId", taskId)
try {
await ElMessageBox.confirm(
`确定要停止任务吗?`,
@@ -186,10 +251,10 @@ const handleStopTask = async (taskId) => {
type: 'warning',
}
)
-
+
stoppingTasks.value.push(taskId)
const res = await taskApi.stopTask(taskId)
-
+
if (res.code === 200) {
ElMessage.success('任务已成功停止')
// 停止成功后刷新列表
@@ -239,27 +304,151 @@ const showTaskDetail = (task) => {
// 计算进度
const calculateProgress = (task) => {
if (!task || !task.msg) return 0
-
+
try {
// 尝试从消息中提取进度信息
const totalMatch = task.msg.match(/总执行数据:(\d+)条/)
const executedMatch = task.msg.match(/已执行条数:(\d+)条/)
-
+
if (totalMatch && executedMatch) {
const total = parseInt(totalMatch[1])
const executed = parseInt(executedMatch[1])
-
+
if (total > 0) {
return Math.floor((executed / total) * 100)
}
}
-
+
return 0
} catch (e) {
return 0
}
}
+// 查看日志
+const handleViewLogs = async (taskId) => {
+ currentTaskId.value = taskId
+ logsVisible.value = true
+ await fetchLogs()
+}
+
+// 获取日志数据
+const fetchLogs = async () => {
+ logsLoading.value = true
+ try {
+ // 并行调用两个接口
+ const [logsListRes, logsMsgRes] = await Promise.all([
+ taskApi.getLogsList(currentTaskId.value),
+ taskApi.getLogsMsg(currentTaskId.value)
+ ])
+
+ console.log('日志列表响应:', logsListRes)
+ console.log('日志消息响应:', logsMsgRes)
+
+ // 处理日志列表数据
+ if (logsListRes.code === 200) {
+ if (Array.isArray(logsListRes.data)) {
+ logsList.value = logsListRes.data
+ } else if (logsListRes.data && Array.isArray(logsListRes.data.data)) {
+ logsList.value = logsListRes.data.data
+ } else {
+ logsList.value = []
+ }
+ } else {
+ logsList.value = []
+ ElMessage.error('获取日志列表失败: ' + (logsListRes.message || '未知错误'))
+ }
+
+ // 处理日志消息数据
+ if (logsMsgRes.code === 200) {
+ // 如果返回的是字符串,直接使用
+ if (typeof logsMsgRes.data === 'string') {
+ logsMessage.value = logsMsgRes.data
+ }
+ // 如果返回的是对象,尝试获取消息字段
+ else if (logsMsgRes.data && typeof logsMsgRes.data === 'object') {
+ logsMessage.value = logsMsgRes.data.message || logsMsgRes.data.msg || JSON.stringify(logsMsgRes.data)
+ } else {
+ logsMessage.value = '暂无日志消息'
+ }
+ } else {
+ logsMessage.value = '获取日志消息失败'
+ ElMessage.error('获取日志消息失败: ' + (logsMsgRes.message || '未知错误'))
+ }
+
+ } catch (error) {
+ console.error('获取日志数据出错:', error)
+ ElMessage.error('获取日志数据失败: ' + (error.message || '未知错误'))
+ logsList.value = []
+ logsMessage.value = '获取日志数据失败'
+ } finally {
+ logsLoading.value = false
+ }
+}
+
+// 刷新日志
+const refreshLogs = () => {
+ fetchLogs()
+}
+
+// 查看详细日志
+const handleViewDetail = async (row) => {
+ try {
+ const res = await taskApi.getLogsDetailList(row.taskId, row.shopId)
+ console.log('详细日志响应:', res)
+
+ if (res.code === 200) {
+ // 这里可以打开一个新的弹窗显示详细日志,或者跳转到详细页面
+ ElMessage.success('查看详细日志功能待实现')
+ } else {
+ ElMessage.error('获取详细日志失败: ' + (res.message || '未知错误'))
+ }
+ } catch (error) {
+ console.error('获取详细日志出错:', error)
+ ElMessage.error('获取详细日志失败: ' + (error.message || '未知错误'))
+ }
+}
+
+// 下载日志
+const handleDownload = async (row) => {
+ try {
+ // 构建文件名,根据后端逻辑应该是 taskId + shopId + ".txt"
+ const fileName = `${row.taskId}${row.shopId}.txt`
+
+ const response = await taskApi.downloadLogs(fileName)
+
+ // 创建下载链接
+ const blob = new Blob([response.data])
+ const url = window.URL.createObjectURL(blob)
+ const link = document.createElement('a')
+ link.href = url
+ link.download = fileName
+ document.body.appendChild(link)
+ link.click()
+ document.body.removeChild(link)
+ window.URL.revokeObjectURL(url)
+
+ ElMessage.success('文件下载成功')
+ } catch (error) {
+ console.error('下载日志文件出错:', error)
+ ElMessage.error('下载日志文件失败: ' + (error.message || '未知错误'))
+ }
+}
+
+// 格式化日志消息
+const formatLogMessage = (message) => {
+ if (!message) return ['暂无日志消息']
+
+ // 将日志消息按行分割,处理各种可能的换行符
+ const lines = message.split(/\r?\n|\r/).filter(line => line.trim() !== '')
+
+ if (lines.length === 0) {
+ return ['暂无日志消息']
+ }
+
+ return lines
+}
+
// 组件挂载时获取任务列表
onMounted(() => {
fetchTaskList()
@@ -270,18 +459,22 @@ onMounted(() => {
.task-list-container {
padding: 20px;
}
+
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
-.empty-content, .loading-content {
+
+.empty-content,
+.loading-content {
min-height: 300px;
display: flex;
justify-content: center;
align-items: center;
color: #909399;
}
+
.task-msg {
white-space: pre-line;
max-height: 150px;
@@ -290,6 +483,7 @@ onMounted(() => {
background-color: #f8f8f8;
border-radius: 4px;
}
+
.pagination-container {
margin-top: 15px;
background-color: #fff;
@@ -300,6 +494,21 @@ onMounted(() => {
justify-content: flex-end;
}
+.operation-buttons {
+ display: flex;
+ justify-content: center;
+ gap: 10px;
+}
+
+.operation-buttons .el-button {
+ margin: 0;
+ transition: transform 0.2s;
+}
+
+.operation-buttons .el-button:hover {
+ transform: scale(1.1);
+}
+
/* 表格样式 */
:deep(.el-table) {
border-radius: 4px;
@@ -341,4 +550,92 @@ onMounted(() => {
padding: 8px;
height: 50px;
}
-
\ No newline at end of file
+
+/* 日志弹窗样式 */
+.logs-container {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+.logs-message-section {
+ background-color: #f5f7fa;
+ border-radius: 8px;
+ padding: 16px;
+ position: relative;
+}
+
+.logs-message-content {
+ margin-bottom: 10px;
+}
+
+.logs-text {
+ color: #606266;
+ line-height: 1.6;
+ white-space: pre-line;
+ font-size: 14px;
+ min-height: 120px;
+ padding: 12px;
+ background-color: #fff;
+ border-radius: 4px;
+ border: 1px solid #e4e7ed;
+}
+
+.log-line {
+ margin-bottom: 4px;
+ color: #606266;
+ font-size: 14px;
+}
+
+.loading-text {
+ color: #909399;
+ text-align: center;
+ padding: 40px;
+ font-size: 14px;
+}
+
+.refresh-btn-container {
+ display: flex;
+ justify-content: flex-end;
+}
+
+.logs-table-section {
+ margin-top: 10px;
+}
+
+/* 日志弹窗表格样式 */
+.logs-table-section :deep(.el-table) {
+ border-radius: 8px;
+}
+
+.logs-table-section :deep(.el-table th) {
+ background-color: #f5f7fa !important;
+ color: #606266;
+ font-weight: 500;
+}
+
+.logs-table-section :deep(.el-button) {
+ margin-right: 4px;
+}
+
+.logs-table-section :deep(.el-button:last-child) {
+ margin-right: 0;
+}
+
+/* 弹窗底部样式 */
+.dialog-footer {
+ text-align: right;
+}
+
+/* 日志弹窗标题样式 */
+:deep(.el-dialog__header) {
+ padding: 20px 20px 10px;
+ border-bottom: 1px solid #e4e7ed;
+}
+
+:deep(.el-dialog__title) {
+ font-size: 18px;
+ font-weight: 500;
+ color: #303133;
+}
+
\ No newline at end of file
diff --git a/src/views/Tools/Cards/List.vue b/src/views/Tools/Cards/List.vue
index cdddda7..5af6b9e 100644
--- a/src/views/Tools/Cards/List.vue
+++ b/src/views/Tools/Cards/List.vue
@@ -368,7 +368,7 @@ const submitCardSecretRequest = async () => {
};
const res = await cardsApi.createCardSecret(cardData)
// 由于createCardSecret方法已经处理了响应,所以直接使用res
- console.log("res",res)
+ console.log("res",res)
if (res.code === 200) {
cardSecretValue.value = res.data
@@ -380,7 +380,10 @@ const submitCardSecretRequest = async () => {
}
} catch (error) {
console.error('获取卡密失败:', error)
- ElMessage.error('获取卡密失败: ' + (error.message || '未知错误'))
+ // if(error.status === 400){
+ // ElMessage.error('获取卡密失败: ' + (error.message || '未知错误'))
+ // }
+ ElMessage.error('获取卡密失败: ' + (error.response.data.message || '未知错误'))
}
}
diff --git a/src/views/User/Edit.vue b/src/views/User/Edit.vue
deleted file mode 100644
index 263a3d7..0000000
--- a/src/views/User/Edit.vue
+++ /dev/null
@@ -1,9 +0,0 @@
-
- 编辑/新增
-
-
-
-
-
\ No newline at end of file