Compare commits

...

3 Commits

Author SHA1 Message Date
3a250e8d73 改样式 2025-09-22 17:16:05 +08:00
a67f55d7c8 增加编辑任务界面 2025-09-22 17:10:21 +08:00
932c88ea75 增加编辑任务按钮 2025-09-22 17:00:30 +08:00
2 changed files with 182 additions and 2 deletions

View File

@@ -0,0 +1,151 @@
<template>
<div class="plan-content-editor">
<div v-if="loading" class="loading">
<el-skeleton animated />
</div>
<div v-else-if="error" class="error">
<el-alert
:title="'加载计划内容失败 (ID: ' + planId + ')'"
:description="error"
type="error"
show-icon
@close="error = null"
/>
<el-button type="primary" @click="fetchPlan" class="retry-btn">重新加载</el-button>
</div>
<div v-else-if="plan">
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>{{ plan.name }} - 内容</span>
<el-button class="button" @click="handleEdit">编辑</el-button>
</div>
</template>
<div v-if="plan.content_type === 'tasks'">
<h4>任务列表</h4>
<el-timeline>
<el-timeline-item
v-for="task in sortedContent"
:key="task.id"
:timestamp="'执行顺序: ' + task.order"
placement="top"
>
<el-card>
<h5>{{ task.name }}</h5>
<p>{{ task.description }}</p>
<el-button-group>
<el-button type="primary" size="small" @click="editTask(task)">编辑</el-button>
<el-button type="danger" size="small" @click="deleteTask(task)">删除</el-button>
</el-button-group>
</el-card>
</el-timeline-item>
</el-timeline>
</div>
<div v-else-if="plan.content_type === 'sub_plans'">
<h4>子计划列表</h4>
<div v-for="subPlan in sortedContent" :key="subPlan.id" class="sub-plan-container">
<!-- 递归使用组件 -->
<plan-content-editor :plan-id="subPlan.id" />
</div>
</div>
<div v-else>
<el-empty description="未知的计划内容类型"></el-empty>
</div>
</el-card>
</div>
<div v-else>
<el-empty description="没有计划数据"></el-empty>
</div>
</div>
</template>
<script>
import apiClient from '../api/index.js';
export default {
name: 'PlanContentEditor', // 必须设置name属性以供递归调用
props: {
planId: {
type: [Number, String],
required: true,
},
},
data() {
return {
plan: null,
loading: false,
error: null,
};
},
computed: {
sortedContent() {
if (this.plan && Array.isArray(this.plan.content)) {
// 假设 `content` 是一个包含 `order` 属性的对象的数组
return [...this.plan.content].sort((a, b) => a.order - b.order);
}
return [];
}
},
watch: {
planId: {
immediate: true,
handler(newId) {
if (newId) {
this.fetchPlan();
}
},
},
},
methods: {
async fetchPlan() {
this.loading = true;
this.error = null;
try {
// 假设存在一个 `apiClient.plans.get(id)` 的方法来获取单个计划的详细信息
// 这个返回的计划对象应该包含 `content` 字段, 其中是任务或子计划的数组
const response = await apiClient.plans.get(this.planId);
this.plan = response.data;
} catch (err) {
this.error = err.message || '未知错误';
console.error(`加载计划 (ID: ${this.planId}) 失败:`, err);
} finally {
this.loading = false;
}
},
handleEdit() {
// Placeholder for future implementation
this.$message.info('编辑功能正在开发中');
},
editTask(task) {
console.log('编辑任务:', task);
this.$message.info('编辑任务功能正在开发中');
},
deleteTask(task) {
console.log('删除任务:', task);
this.$message.info('删除任务功能正在开发中');
}
},
};
</script>
<style scoped>
.plan-content-editor {
margin-top: 10px;
}
.loading, .error {
padding: 20px;
text-align: center;
}
.retry-btn {
margin-top: 15px;
}
.sub-plan-container {
margin-left: 20px;
margin-top: 10px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>

View File

@@ -62,9 +62,10 @@
{{ formatNextExecutionTime(scope.row.cron_expression) }}
</template>
</el-table-column>
<el-table-column label="操作" width="200">
<el-table-column label="操作" width="280">
<template #default="scope">
<el-button size="small" @click="editPlan(scope.row)">编辑</el-button>
<el-button size="small" @click="showDetails(scope.row)">详情</el-button>
<el-button v-if="scope.row.status === 1" size="small" type="warning" @click="stopPlan(scope.row)" :loading="stoppingPlanId === scope.row.id">
停止
</el-button>
@@ -78,7 +79,7 @@
</el-card>
<!-- 使用新的计划表单组件 -->
<!-- 计划表单 -->
<PlanForm
v-model:visible="dialogVisible"
:plan-data="currentPlan"
@@ -86,6 +87,25 @@
@success="handlePlanSuccess"
@cancel="handlePlanCancel"
/>
<!-- 计划详情 -->
<el-dialog
v-model="detailsVisible"
title="计划详情"
width="70%"
top="5vh"
>
<plan-content-editor
v-if="detailsVisible"
:plan-id="selectedPlanIdForDetails"
/>
<template #footer>
<span class="dialog-footer">
<el-button @click="detailsVisible = false">关闭</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
@@ -93,12 +113,14 @@
import { Refresh } from '@element-plus/icons-vue';
import apiClient from '../api/index.js';
import PlanForm from './PlanForm.vue';
import PlanContentEditor from './PlanContentEditor.vue'; // 导入新组件
import cronParser from 'cron-parser';
export default {
name: 'PlanList',
components: {
PlanForm,
PlanContentEditor, // 注册新组件
Refresh
},
data() {
@@ -106,6 +128,7 @@ export default {
plans: [],
originalPlans: [], // Store the original unsorted list
dialogVisible: false,
detailsVisible: false, // 控制详情对话框
isEdit: false,
loading: false,
error: null,
@@ -117,6 +140,7 @@ export default {
execute_num: 0,
cron_expression: ''
},
selectedPlanIdForDetails: null, // 当前要查看详情的计划ID
startingPlanId: null,
stoppingPlanId: null
};
@@ -212,6 +236,11 @@ export default {
this.isEdit = false;
this.dialogVisible = true;
},
showDetails(plan) {
this.selectedPlanIdForDetails = plan.id;
this.detailsVisible = true;
},
editPlan(plan) {
this.currentPlan = { ...plan };