编辑计划详情
This commit is contained in:
@@ -18,35 +18,57 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<span>{{ plan.name }} - 内容</span>
|
<span>{{ plan.name }} - 内容</span>
|
||||||
<el-button class="button" @click="handleEdit">编辑</el-button>
|
<div>
|
||||||
|
<el-button class="button" @click="toggleEditMode">{{ isEditingContent ? '完成编辑' : '编辑内容' }}</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="isEditingContent && plan.content_type === 'sub_plans'"
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
@click="showAddSubPlanDialog"
|
||||||
|
>增加子计划</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="isEditingContent && plan.content_type === 'tasks'"
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
@click="showAddTaskDialog"
|
||||||
|
>增加子任务</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-if="plan.content_type === 'tasks'">
|
<div v-if="plan.content_type === 'tasks'">
|
||||||
<h4>任务列表</h4>
|
<h4>任务列表</h4>
|
||||||
<el-timeline>
|
<el-timeline>
|
||||||
<el-timeline-item
|
<el-timeline-item
|
||||||
v-for="task in sortedContent"
|
v-for="(task, index) in sortedContent"
|
||||||
:key="task.id"
|
:key="task.id || 'new-task-' + index"
|
||||||
:timestamp="'执行顺序: ' + task.order"
|
:timestamp="'执行顺序: ' + (task.order !== undefined ? task.order : index + 1)"
|
||||||
placement="top"
|
placement="top"
|
||||||
>
|
>
|
||||||
<el-card>
|
<el-card>
|
||||||
<h5>{{ task.name }}</h5>
|
<h5>{{ task.name }}</h5>
|
||||||
<p>{{ task.description }}</p>
|
<p>{{ task.description }}</p>
|
||||||
<el-button-group>
|
<el-button-group v-if="isEditingContent">
|
||||||
<el-button type="primary" size="small" @click="editTask(task)">编辑</el-button>
|
<el-button type="primary" size="small" @click="editTask(task)">编辑</el-button>
|
||||||
<el-button type="danger" size="small" @click="deleteTask(task)">删除</el-button>
|
<el-button type="danger" size="small" @click="deleteTask(task)">删除</el-button>
|
||||||
</el-button-group>
|
</el-button-group>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-timeline-item>
|
</el-timeline-item>
|
||||||
</el-timeline>
|
</el-timeline>
|
||||||
|
<el-empty v-if="!sortedContent.length && !isEditingContent" description="暂无任务"></el-empty>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="plan.content_type === 'sub_plans'">
|
<div v-else-if="plan.content_type === 'sub_plans'">
|
||||||
<h4>子计划列表</h4>
|
<h4>子计划列表</h4>
|
||||||
<div v-for="subPlan in sortedContent" :key="subPlan.id" class="sub-plan-container">
|
<div v-for="(subPlan, index) in sortedContent" :key="subPlan.id || 'new-subplan-' + index" class="sub-plan-container">
|
||||||
<!-- 递归使用组件 -->
|
<el-card>
|
||||||
<plan-detail :plan-id="subPlan.id" />
|
<div class="card-header">
|
||||||
|
<plan-detail :plan-id="subPlan.id" />
|
||||||
|
<el-button-group v-if="isEditingContent">
|
||||||
|
<el-button type="danger" size="small" @click="deleteSubPlan(subPlan)">删除</el-button>
|
||||||
|
</el-button-group>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
|
<el-empty v-if="!sortedContent.length && !isEditingContent" description="暂无子计划"></el-empty>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<el-empty description="未知的计划内容类型"></el-empty>
|
<el-empty description="未知的计划内容类型"></el-empty>
|
||||||
@@ -56,11 +78,85 @@
|
|||||||
<div v-else>
|
<div v-else>
|
||||||
<el-empty description="没有计划数据"></el-empty>
|
<el-empty description="没有计划数据"></el-empty>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 增加子计划对话框 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="addSubPlanDialogVisible"
|
||||||
|
title="选择子计划"
|
||||||
|
width="600px"
|
||||||
|
@close="resetAddSubPlanDialog"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
v-model="selectedSubPlanId"
|
||||||
|
placeholder="请选择一个计划作为子计划"
|
||||||
|
filterable
|
||||||
|
style="width: 100%;"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in availablePlans"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="addSubPlanDialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirmAddSubPlan">确定</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 增加子任务对话框 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="addTaskDialogVisible"
|
||||||
|
title="增加子任务"
|
||||||
|
width="600px"
|
||||||
|
@close="resetAddTaskDialog"
|
||||||
|
>
|
||||||
|
<el-form :model="newTaskForm" ref="newTaskFormRef" :rules="newTaskRules" label-width="100px">
|
||||||
|
<el-form-item label="任务类型" prop="type">
|
||||||
|
<el-select v-model="newTaskForm.type" placeholder="请选择任务类型" style="width: 100%;">
|
||||||
|
<el-option label="普通任务" value="normal_task"></el-option>
|
||||||
|
<el-option label="延时任务" value="delay_task"></el-option>
|
||||||
|
<!-- 更多任务类型可以在这里添加 -->
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="任务名称" prop="name">
|
||||||
|
<el-input v-model="newTaskForm.name" placeholder="请输入任务名称"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="任务描述" prop="description">
|
||||||
|
<el-input type="textarea" v-model="newTaskForm.description" placeholder="请输入任务描述"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<!-- 延时任务特有字段 -->
|
||||||
|
<el-form-item
|
||||||
|
v-if="newTaskForm.type === 'delay_task'"
|
||||||
|
label="延时时间(秒)"
|
||||||
|
prop="delay_seconds"
|
||||||
|
>
|
||||||
|
<el-input-number
|
||||||
|
v-model="newTaskForm.delay_seconds"
|
||||||
|
:min="1"
|
||||||
|
:max="3600"
|
||||||
|
placeholder="请输入延时时间"
|
||||||
|
style="width: 100%;"
|
||||||
|
></el-input-number>
|
||||||
|
</el-form-item>
|
||||||
|
<!-- 更多任务类型的特定表单项可以在这里动态渲染 -->
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="addTaskDialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirmAddTask">确定</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import apiClient from '../api/index.js';
|
import apiClient from '../api/index.js';
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'; // 导入ElMessage和ElMessageBox
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'PlanDetail', // 必须设置name属性以供递归调用
|
name: 'PlanDetail', // 必须设置name属性以供递归调用
|
||||||
@@ -75,13 +171,30 @@ export default {
|
|||||||
plan: null,
|
plan: null,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null,
|
error: null,
|
||||||
|
isEditingContent: false, // 新增:是否处于编辑内容模式
|
||||||
|
addSubPlanDialogVisible: false, // 控制增加子计划对话框
|
||||||
|
selectedSubPlanId: null, // 选中的子计划ID
|
||||||
|
availablePlans: [], // 可供选择的计划列表
|
||||||
|
|
||||||
|
addTaskDialogVisible: false, // 控制增加子任务对话框
|
||||||
|
newTaskForm: { // 新任务表单数据
|
||||||
|
type: 'normal_task', // 默认任务类型
|
||||||
|
name: '',
|
||||||
|
description: '',
|
||||||
|
delay_seconds: 1, // 延时任务特有字段
|
||||||
|
},
|
||||||
|
newTaskRules: { // 新任务表单验证规则
|
||||||
|
type: [{ required: true, message: '请选择任务类型', trigger: 'change' }],
|
||||||
|
name: [{ required: true, message: '请输入任务名称', trigger: 'blur' }],
|
||||||
|
delay_seconds: [{ required: true, message: '请输入延时时间', trigger: 'blur' }],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
sortedContent() {
|
sortedContent() {
|
||||||
if (this.plan && Array.isArray(this.plan.content)) {
|
if (this.plan && Array.isArray(this.plan.content)) {
|
||||||
// 假设 `content` 是一个包含 `order` 属性的对象的数组
|
// 假设 `content` 是一个包含 `order` 属性的对象的数组
|
||||||
return [...this.plan.content].sort((a, b) => a.order - b.order);
|
return [...this.plan.content].sort((a, b) => (a.order || 0) - (b.order || 0));
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -101,10 +214,12 @@ export default {
|
|||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.error = null;
|
this.error = null;
|
||||||
try {
|
try {
|
||||||
// 假设存在一个 `apiClient.plans.get(id)` 的方法来获取单个计划的详细信息
|
|
||||||
// 这个返回的计划对象应该包含 `content` 字段, 其中是任务或子计划的数组
|
|
||||||
const response = await apiClient.plans.get(this.planId);
|
const response = await apiClient.plans.get(this.planId);
|
||||||
this.plan = response.data;
|
this.plan = response.data;
|
||||||
|
// 确保content是一个数组,如果后端返回null或undefined
|
||||||
|
if (!this.plan.content) {
|
||||||
|
this.plan.content = [];
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.error = err.message || '未知错误';
|
this.error = err.message || '未知错误';
|
||||||
console.error(`加载计划 (ID: ${this.planId}) 失败:`, err);
|
console.error(`加载计划 (ID: ${this.planId}) 失败:`, err);
|
||||||
@@ -112,18 +227,145 @@ export default {
|
|||||||
this.loading = false;
|
this.loading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleEdit() {
|
toggleEditMode() {
|
||||||
// Placeholder for future implementation
|
this.isEditingContent = !this.isEditingContent;
|
||||||
this.$message.info('编辑功能正在开发中');
|
if (!this.isEditingContent) {
|
||||||
|
// 如果退出编辑模式,保存更改
|
||||||
|
this.savePlanContent();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async savePlanContent() {
|
||||||
|
try {
|
||||||
|
// 假设有一个API来更新计划的内容
|
||||||
|
await apiClient.plans.updateContent(this.planId, this.plan.content);
|
||||||
|
ElMessage.success('计划内容已保存');
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('保存计划内容失败: ' + (error.message || '未知错误'));
|
||||||
|
console.error('保存计划内容失败:', error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async showAddSubPlanDialog() {
|
||||||
|
this.addSubPlanDialogVisible = true;
|
||||||
|
await this.fetchAvailablePlans();
|
||||||
|
},
|
||||||
|
async fetchAvailablePlans() {
|
||||||
|
try {
|
||||||
|
const response = await apiClient.plans.list();
|
||||||
|
// 过滤掉当前计划和已有的子计划,以及防止循环引用
|
||||||
|
this.availablePlans = response.data.plans.filter(p =>
|
||||||
|
p.id !== this.planId &&
|
||||||
|
!this.plan.content.some(sub => sub.id === p.id)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('加载可用计划失败: ' + (error.message || '未知错误'));
|
||||||
|
console.error('加载可用计划失败:', error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
confirmAddSubPlan() {
|
||||||
|
if (!this.selectedSubPlanId) {
|
||||||
|
ElMessage.warning('请选择一个子计划');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedPlan = this.availablePlans.find(p => p.id === this.selectedSubPlanId);
|
||||||
|
if (selectedPlan) {
|
||||||
|
// 确保content_type是sub_plans
|
||||||
|
if (this.plan.content_type !== 'sub_plans') {
|
||||||
|
this.plan.content_type = 'sub_plans';
|
||||||
|
this.plan.content = []; // 清空原有内容
|
||||||
|
}
|
||||||
|
this.plan.content.push({
|
||||||
|
id: selectedPlan.id,
|
||||||
|
name: selectedPlan.name,
|
||||||
|
order: this.plan.content.length + 1, // 简单的排序
|
||||||
|
// 可以根据需要添加其他字段
|
||||||
|
});
|
||||||
|
ElMessage.success(`子计划 "${selectedPlan.name}" 已添加`);
|
||||||
|
this.addSubPlanDialogVisible = false;
|
||||||
|
this.resetAddSubPlanDialog();
|
||||||
|
} else {
|
||||||
|
ElMessage.error('未找到选中的计划');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resetAddSubPlanDialog() {
|
||||||
|
this.selectedSubPlanId = null;
|
||||||
|
this.availablePlans = [];
|
||||||
|
},
|
||||||
|
deleteSubPlan(subPlanToDelete) {
|
||||||
|
ElMessageBox.confirm(`确认删除子计划 "${subPlanToDelete.name}" 吗?`, '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
this.plan.content = this.plan.content.filter(sub => sub.id !== subPlanToDelete.id);
|
||||||
|
// 重新排序
|
||||||
|
this.plan.content.forEach((item, index) => item.order = index + 1);
|
||||||
|
ElMessage.success('子计划已删除');
|
||||||
|
}).catch(() => {
|
||||||
|
// 用户取消
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
showAddTaskDialog() {
|
||||||
|
this.addTaskDialogVisible = true;
|
||||||
|
},
|
||||||
|
confirmAddTask() {
|
||||||
|
this.$refs.newTaskFormRef.validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
|
// 确保content_type是tasks
|
||||||
|
if (this.plan.content_type !== 'tasks') {
|
||||||
|
this.plan.content_type = 'tasks';
|
||||||
|
this.plan.content = []; // 清空原有内容
|
||||||
|
}
|
||||||
|
|
||||||
|
const newTask = {
|
||||||
|
id: Date.now(), // 临时ID,实际应由后端生成
|
||||||
|
order: this.plan.content.length + 1,
|
||||||
|
type: this.newTaskForm.type,
|
||||||
|
name: this.newTaskForm.name,
|
||||||
|
description: this.newTaskForm.description,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.newTaskForm.type === 'delay_task') {
|
||||||
|
newTask.delay_seconds = this.newTaskForm.delay_seconds;
|
||||||
|
}
|
||||||
|
// 可以在这里根据任务类型添加更多字段
|
||||||
|
|
||||||
|
this.plan.content.push(newTask);
|
||||||
|
ElMessage.success(`子任务 "${newTask.name}" 已添加`);
|
||||||
|
this.addTaskDialogVisible = false;
|
||||||
|
this.resetAddTaskDialog();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
resetAddTaskDialog() {
|
||||||
|
this.$refs.newTaskFormRef.resetFields();
|
||||||
|
this.newTaskForm = {
|
||||||
|
type: 'normal_task',
|
||||||
|
name: '',
|
||||||
|
description: '',
|
||||||
|
delay_seconds: 1,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
editTask(task) {
|
editTask(task) {
|
||||||
|
// TODO: 实现编辑任务的逻辑,可能需要一个单独的对话框
|
||||||
|
ElMessage.info('编辑任务功能正在开发中');
|
||||||
console.log('编辑任务:', task);
|
console.log('编辑任务:', task);
|
||||||
this.$message.info('编辑任务功能正在开发中');
|
|
||||||
},
|
},
|
||||||
deleteTask(task) {
|
deleteTask(taskToDelete) {
|
||||||
console.log('删除任务:', task);
|
ElMessageBox.confirm(`确认删除任务 "${taskToDelete.name}" 吗?`, '提示', {
|
||||||
this.$message.info('删除任务功能正在开发中');
|
confirmButtonText: '确定',
|
||||||
}
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
this.plan.content = this.plan.content.filter(task => task.id !== taskToDelete.id);
|
||||||
|
// 重新排序
|
||||||
|
this.plan.content.forEach((item, index) => item.order = index + 1);
|
||||||
|
ElMessage.success('任务已删除');
|
||||||
|
}).catch(() => {
|
||||||
|
// 用户取消
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -142,10 +384,16 @@ export default {
|
|||||||
.sub-plan-container {
|
.sub-plan-container {
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
border-left: 2px solid #ebeef5; /* 增加视觉区分 */
|
||||||
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
.card-header {
|
.card-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
/* 调整子计划卡片内部的header,避免重复样式 */
|
||||||
|
.sub-plan-container .card-header {
|
||||||
|
padding: 0; /* 移除内部card-header的padding */
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
0
src/components/tasks/.gitkeep
Normal file
0
src/components/tasks/.gitkeep
Normal file
Reference in New Issue
Block a user