220 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			220 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
<template>
 | 
						|
  <div class="plan-list">
 | 
						|
    <el-card>
 | 
						|
      <template #header>
 | 
						|
        <div class="card-header">
 | 
						|
          <h2 class="page-title">计划管理</h2>
 | 
						|
          <el-button type="primary" @click="addPlan">添加计划</el-button>
 | 
						|
        </div>
 | 
						|
      </template>
 | 
						|
      
 | 
						|
      <el-table :data="plans" style="width: 100%">
 | 
						|
        <el-table-column prop="id" label="计划ID" width="80" />
 | 
						|
        <el-table-column prop="name" label="计划名称" width="180" />
 | 
						|
        <el-table-column prop="description" label="描述" />
 | 
						|
        <el-table-column prop="execution_type" label="执行类型" width="120">
 | 
						|
          <template #default="scope">
 | 
						|
            <el-tag v-if="scope.row.execution_type === 'automatic'">自动</el-tag>
 | 
						|
            <el-tag v-else>手动</el-tag>
 | 
						|
          </template>
 | 
						|
        </el-table-column>
 | 
						|
        <el-table-column prop="status" label="状态" width="100">
 | 
						|
          <template #default="scope">
 | 
						|
            <el-tag v-if="scope.row.status === 0" type="success">启用</el-tag>
 | 
						|
            <el-tag v-else-if="scope.row.status === 1" type="warning">禁用</el-tag>
 | 
						|
            <el-tag v-else type="info">已完成</el-tag>
 | 
						|
          </template>
 | 
						|
        </el-table-column>
 | 
						|
        <el-table-column label="操作" width="200">
 | 
						|
          <template #default="scope">
 | 
						|
            <el-button size="small" @click="editPlan(scope.row)">编辑</el-button>
 | 
						|
            <el-button size="small" @click="startPlan(scope.row)" :loading="startingPlanId === scope.row.id">
 | 
						|
              启动
 | 
						|
            </el-button>
 | 
						|
            <el-button size="small" type="danger" @click="deletePlan(scope.row)">删除</el-button>
 | 
						|
          </template>
 | 
						|
        </el-table-column>
 | 
						|
      </el-table>
 | 
						|
    </el-card>
 | 
						|
 | 
						|
    <!-- 添加/编辑计划对话框 -->
 | 
						|
    <el-dialog v-model="dialogVisible" :title="dialogTitle" width="50%">
 | 
						|
      <el-form :model="currentPlan" label-width="120px">
 | 
						|
        <el-form-item label="计划名称">
 | 
						|
          <el-input v-model="currentPlan.name" />
 | 
						|
        </el-form-item>
 | 
						|
        <el-form-item label="描述">
 | 
						|
          <el-input v-model="currentPlan.description" type="textarea" />
 | 
						|
        </el-form-item>
 | 
						|
        <el-form-item label="执行类型">
 | 
						|
          <el-select v-model="currentPlan.execution_type" placeholder="请选择执行类型">
 | 
						|
            <el-option label="自动执行" value="automatic" />
 | 
						|
            <el-option label="手动执行" value="manual" />
 | 
						|
          </el-select>
 | 
						|
        </el-form-item>
 | 
						|
        <el-form-item label="内容类型" v-if="!isEdit">
 | 
						|
          <el-radio-group v-model="contentType">
 | 
						|
            <el-radio label="tasks">任务</el-radio>
 | 
						|
            <el-radio label="sub_plans">子计划</el-radio>
 | 
						|
          </el-radio-group>
 | 
						|
        </el-form-item>
 | 
						|
      </el-form>
 | 
						|
      <template #footer>
 | 
						|
        <span class="dialog-footer">
 | 
						|
          <el-button @click="dialogVisible = false">取消</el-button>
 | 
						|
          <el-button type="primary" @click="savePlan">保存</el-button>
 | 
						|
        </span>
 | 
						|
      </template>
 | 
						|
    </el-dialog>
 | 
						|
  </div>
 | 
						|
</template>
 | 
						|
 | 
						|
<script>
 | 
						|
import apiClient from '../api/index.js';
 | 
						|
 | 
						|
export default {
 | 
						|
  name: 'PlanList',
 | 
						|
  data() {
 | 
						|
    return {
 | 
						|
      plans: [],
 | 
						|
      dialogVisible: false,
 | 
						|
      dialogTitle: '',
 | 
						|
      isEdit: false,
 | 
						|
      contentType: 'tasks',
 | 
						|
      currentPlan: {
 | 
						|
        id: null,
 | 
						|
        name: '',
 | 
						|
        description: '',
 | 
						|
        execution_type: 'automatic',
 | 
						|
        content_type: 'tasks'
 | 
						|
      },
 | 
						|
      startingPlanId: null
 | 
						|
    };
 | 
						|
  },
 | 
						|
  async mounted() {
 | 
						|
    await this.loadPlans();
 | 
						|
  },
 | 
						|
  methods: {
 | 
						|
    // 加载计划列表
 | 
						|
    async loadPlans() {
 | 
						|
      try {
 | 
						|
        const response = await apiClient.plans.list();
 | 
						|
        this.plans = response.data?.plans || [];
 | 
						|
      } catch (err) {
 | 
						|
        this.$message.error('加载计划列表失败: ' + (err.message || '未知错误'));
 | 
						|
        console.error('加载计划列表失败:', err);
 | 
						|
      }
 | 
						|
    },
 | 
						|
    
 | 
						|
    addPlan() {
 | 
						|
      this.dialogTitle = '添加计划';
 | 
						|
      this.currentPlan = {
 | 
						|
        id: null,
 | 
						|
        name: '',
 | 
						|
        description: '',
 | 
						|
        execution_type: 'automatic'
 | 
						|
      };
 | 
						|
      this.isEdit = false;
 | 
						|
      this.dialogVisible = true;
 | 
						|
    },
 | 
						|
    
 | 
						|
    editPlan(plan) {
 | 
						|
      this.dialogTitle = '编辑计划';
 | 
						|
      this.currentPlan = { ...plan };
 | 
						|
      this.isEdit = true;
 | 
						|
      this.dialogVisible = true;
 | 
						|
    },
 | 
						|
    
 | 
						|
    async deletePlan(plan) {
 | 
						|
      try {
 | 
						|
        await this.$confirm('确认删除该计划吗?', '提示', {
 | 
						|
          confirmButtonText: '确定',
 | 
						|
          cancelButtonText: '取消',
 | 
						|
          type: 'warning'
 | 
						|
        });
 | 
						|
        
 | 
						|
        await apiClient.plans.delete(plan.id);
 | 
						|
        this.$message.success('删除成功');
 | 
						|
        await this.loadPlans();
 | 
						|
      } catch (err) {
 | 
						|
        if (err !== 'cancel') {
 | 
						|
          this.$message.error('删除失败: ' + (err.message || '未知错误'));
 | 
						|
        }
 | 
						|
      }
 | 
						|
    },
 | 
						|
    
 | 
						|
    async startPlan(plan) {
 | 
						|
      try {
 | 
						|
        this.startingPlanId = plan.id;
 | 
						|
        await apiClient.plans.start(plan.id);
 | 
						|
        this.$message.success('计划启动成功');
 | 
						|
        await this.loadPlans();
 | 
						|
      } catch (err) {
 | 
						|
        this.$message.error('启动失败: ' + (err.message || '未知错误'));
 | 
						|
      } finally {
 | 
						|
        this.startingPlanId = null;
 | 
						|
      }
 | 
						|
    },
 | 
						|
    
 | 
						|
    async savePlan() {
 | 
						|
      try {
 | 
						|
        if (this.isEdit) {
 | 
						|
          // 编辑计划
 | 
						|
          await apiClient.plans.update(this.currentPlan.id, this.currentPlan);
 | 
						|
          this.$message.success('计划更新成功');
 | 
						|
        } else {
 | 
						|
          // 添加新计划
 | 
						|
          const planData = {
 | 
						|
            ...this.currentPlan,
 | 
						|
            content_type: this.contentType
 | 
						|
          };
 | 
						|
          
 | 
						|
          await apiClient.plans.create(planData);
 | 
						|
          this.$message.success('计划添加成功');
 | 
						|
        }
 | 
						|
        
 | 
						|
        this.dialogVisible = false;
 | 
						|
        await this.loadPlans();
 | 
						|
      } catch (err) {
 | 
						|
        this.$message.error('保存失败: ' + (err.message || '未知错误'));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
};
 | 
						|
</script>
 | 
						|
 | 
						|
<style scoped>
 | 
						|
.plan-list {
 | 
						|
  padding: 20px;
 | 
						|
  max-width: 1200px;
 | 
						|
  margin: 0 auto;
 | 
						|
}
 | 
						|
 | 
						|
.card-header {
 | 
						|
  display: flex;
 | 
						|
  justify-content: space-between;
 | 
						|
  align-items: center;
 | 
						|
  padding: 15px 0;
 | 
						|
}
 | 
						|
 | 
						|
.page-title {
 | 
						|
  margin: 0;
 | 
						|
  font-size: 1.5rem;
 | 
						|
  font-weight: bold;
 | 
						|
}
 | 
						|
 | 
						|
.dialog-footer {
 | 
						|
  text-align: right;
 | 
						|
}
 | 
						|
 | 
						|
@media (max-width: 768px) {
 | 
						|
  .plan-list {
 | 
						|
    padding: 10px;
 | 
						|
  }
 | 
						|
  
 | 
						|
  .card-header {
 | 
						|
    flex-direction: column;
 | 
						|
    gap: 15px;
 | 
						|
  }
 | 
						|
}
 | 
						|
</style> |