修bug
This commit is contained in:
		| @@ -197,10 +197,7 @@ import http from '../utils/http'; | ||||
|  * @returns {Promise<Array<PigBatchResponseDTO>>} | ||||
|  */ | ||||
| export const getPigBatches = (params) => { | ||||
|   const newParams = { | ||||
|     is_active: params.is_active, | ||||
|   }; | ||||
|   return http.get('/api/v1/pig-batches', { params: newParams }); | ||||
|     return http.get('/api/v1/pig-batches', params); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -209,7 +206,7 @@ export const getPigBatches = (params) => { | ||||
|  * @returns {Promise<PigBatchResponseDTO>} | ||||
|  */ | ||||
| export const createPigBatch = (batchData) => { | ||||
|   return http.post('/api/v1/pig-batches', batchData); | ||||
|     return http.post('/api/v1/pig-batches', batchData); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -218,7 +215,7 @@ export const createPigBatch = (batchData) => { | ||||
|  * @returns {Promise<PigBatchResponseDTO>} | ||||
|  */ | ||||
| export const getPigBatchById = (id) => { | ||||
|   return http.get(`/api/v1/pig-batches/${id}`); | ||||
|     return http.get(`/api/v1/pig-batches/${id}`); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -228,7 +225,7 @@ export const getPigBatchById = (id) => { | ||||
|  * @returns {Promise<PigBatchResponseDTO>} | ||||
|  */ | ||||
| export const updatePigBatch = (id, batchData) => { | ||||
|   return http.put(`/api/v1/pig-batches/${id}`, batchData); | ||||
|     return http.put(`/api/v1/pig-batches/${id}`, batchData); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -237,7 +234,7 @@ export const updatePigBatch = (id, batchData) => { | ||||
|  * @returns {Promise<Response>} | ||||
|  */ | ||||
| export const deletePigBatch = (id) => { | ||||
|   return http.delete(`/api/v1/pig-batches/${id}`); | ||||
|     return http.delete(`/api/v1/pig-batches/${id}`); | ||||
| }; | ||||
|  | ||||
| // --- 猪批次业务操作 --- | ||||
| @@ -249,7 +246,7 @@ export const deletePigBatch = (id) => { | ||||
|  * @returns {Promise<Response>} | ||||
|  */ | ||||
| export const assignPensToBatch = (id, pensData) => { | ||||
|   return http.post(`/api/v1/pig-batches/assign-pens/${id}`, pensData); | ||||
|     return http.post(`/api/v1/pig-batches/assign-pens/${id}`, pensData); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -259,7 +256,7 @@ export const assignPensToBatch = (id, pensData) => { | ||||
|  * @returns {Promise<Response>} | ||||
|  */ | ||||
| export const removePenFromBatch = (penID, batchID) => { | ||||
|   return http.delete(`/api/v1/pig-batches/remove-pen/${penID}/${batchID}`); | ||||
|     return http.delete(`/api/v1/pig-batches/remove-pen/${penID}/${batchID}`); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -269,7 +266,7 @@ export const removePenFromBatch = (penID, batchID) => { | ||||
|  * @returns {Promise<Response>} | ||||
|  */ | ||||
| export const buyPigsForBatch = (id, buyData) => { | ||||
|   return http.post(`/api/v1/pig-batches/buy-pigs/${id}`, buyData); | ||||
|     return http.post(`/api/v1/pig-batches/buy-pigs/${id}`, buyData); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -279,7 +276,7 @@ export const buyPigsForBatch = (id, buyData) => { | ||||
|  * @returns {Promise<Response>} | ||||
|  */ | ||||
| export const sellPigsFromBatch = (id, sellData) => { | ||||
|   return http.post(`/api/v1/pig-batches/sell-pigs/${id}`, sellData); | ||||
|     return http.post(`/api/v1/pig-batches/sell-pigs/${id}`, sellData); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -289,7 +286,7 @@ export const sellPigsFromBatch = (id, sellData) => { | ||||
|  * @returns {Promise<Response>} | ||||
|  */ | ||||
| export const movePigsIntoPen = (id, moveData) => { | ||||
|   return http.post(`/api/v1/pig-batches/move-pigs-into-pen/${id}`, moveData); | ||||
|     return http.post(`/api/v1/pig-batches/move-pigs-into-pen/${id}`, moveData); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -299,7 +296,7 @@ export const movePigsIntoPen = (id, moveData) => { | ||||
|  * @returns {Promise<Response>} | ||||
|  */ | ||||
| export const transferPigsWithinBatch = (id, transferData) => { | ||||
|   return http.post(`/api/v1/pig-batches/transfer-within-batch/${id}`, transferData); | ||||
|     return http.post(`/api/v1/pig-batches/transfer-within-batch/${id}`, transferData); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -309,7 +306,7 @@ export const transferPigsWithinBatch = (id, transferData) => { | ||||
|  * @returns {Promise<Response>} | ||||
|  */ | ||||
| export const transferPigsAcrossBatches = (sourceBatchID, transferData) => { | ||||
|   return http.post(`/api/v1/pig-batches/transfer-across-batches/${sourceBatchID}`, transferData); | ||||
|     return http.post(`/api/v1/pig-batches/transfer-across-batches/${sourceBatchID}`, transferData); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -319,7 +316,7 @@ export const transferPigsAcrossBatches = (sourceBatchID, transferData) => { | ||||
|  * @returns {Promise<Response>} | ||||
|  */ | ||||
| export const reclassifyPenToNewBatch = (fromBatchID, reclassifyData) => { | ||||
|   return http.post(`/api/v1/pig-batches/reclassify-pen/${fromBatchID}`, reclassifyData); | ||||
|     return http.post(`/api/v1/pig-batches/reclassify-pen/${fromBatchID}`, reclassifyData); | ||||
| }; | ||||
|  | ||||
| // --- 猪只数量变更记录 --- | ||||
| @@ -331,7 +328,7 @@ export const reclassifyPenToNewBatch = (fromBatchID, reclassifyData) => { | ||||
|  * @returns {Promise<Response>} | ||||
|  */ | ||||
| export const recordSickPigsInBatch = (id, sickData) => { | ||||
|   return http.post(`/api/v1/pig-batches/record-sick-pigs/${id}`, sickData); | ||||
|     return http.post(`/api/v1/pig-batches/record-sick-pigs/${id}`, sickData); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -341,7 +338,7 @@ export const recordSickPigsInBatch = (id, sickData) => { | ||||
|  * @returns {Promise<Response>} | ||||
|  */ | ||||
| export const recordSickPigRecoveryInBatch = (id, recoveryData) => { | ||||
|   return http.post(`/api/v1/pig-batches/record-sick-pig-recovery/${id}`, recoveryData); | ||||
|     return http.post(`/api/v1/pig-batches/record-sick-pig-recovery/${id}`, recoveryData); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -351,7 +348,7 @@ export const recordSickPigRecoveryInBatch = (id, recoveryData) => { | ||||
|  * @returns {Promise<Response>} | ||||
|  */ | ||||
| export const recordSickPigDeathInBatch = (id, deathData) => { | ||||
|   return http.post(`/api/v1/pig-batches/record-sick-pig-death/${id}`, deathData); | ||||
|     return http.post(`/api/v1/pig-batches/record-sick-pig-death/${id}`, deathData); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -361,7 +358,7 @@ export const recordSickPigDeathInBatch = (id, deathData) => { | ||||
|  * @returns {Promise<Response>} | ||||
|  */ | ||||
| export const recordSickPigCullInBatch = (id, cullData) => { | ||||
|   return http.post(`/api/v1/pig-batches/record-sick-pig-cull/${id}`, cullData); | ||||
|     return http.post(`/api/v1/pig-batches/record-sick-pig-cull/${id}`, cullData); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -371,7 +368,7 @@ export const recordSickPigCullInBatch = (id, cullData) => { | ||||
|  * @returns {Promise<Response>} | ||||
|  */ | ||||
| export const recordDeathInBatch = (id, deathData) => { | ||||
|   return http.post(`/api/v1/pig-batches/record-death/${id}`, deathData); | ||||
|     return http.post(`/api/v1/pig-batches/record-death/${id}`, deathData); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -381,7 +378,7 @@ export const recordDeathInBatch = (id, deathData) => { | ||||
|  * @returns {Promise<Response>} | ||||
|  */ | ||||
| export const recordCullInBatch = (id, cullData) => { | ||||
|   return http.post(`/api/v1/pig-batches/record-cull/${id}`, cullData); | ||||
|     return http.post(`/api/v1/pig-batches/record-cull/${id}`, cullData); | ||||
| }; | ||||
|  | ||||
| // --- 新增的猪栏和猪舍API --- | ||||
| @@ -391,7 +388,7 @@ export const recordCullInBatch = (id, cullData) => { | ||||
|  * @returns {Promise<Array<PenResponse>>} | ||||
|  */ | ||||
| export const getAllPens = () => { | ||||
|   return http.get('/api/v1/pens'); | ||||
|     return http.get('/api/v1/pens'); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -399,29 +396,29 @@ export const getAllPens = () => { | ||||
|  * @returns {Promise<Array<PigHouseResponse>>} | ||||
|  */ | ||||
| export const getAllPigHouses = () => { | ||||
|   return http.get('/api/v1/pig-houses'); | ||||
|     return http.get('/api/v1/pig-houses'); | ||||
| }; | ||||
|  | ||||
| export const PigBatchApi = { | ||||
|   getPigBatches, | ||||
|   createPigBatch, | ||||
|   getPigBatchById, | ||||
|   updatePigBatch, | ||||
|   deletePigBatch, | ||||
|   assignPensToBatch, | ||||
|   removePenFromBatch, | ||||
|   buyPigsForBatch, | ||||
|   sellPigsFromBatch, | ||||
|   movePigsIntoPen, | ||||
|   transferPigsWithinBatch, | ||||
|   transferPigsAcrossBatches, | ||||
|   reclassifyPenToNewBatch, | ||||
|   recordSickPigsInBatch, | ||||
|   recordSickPigRecoveryInBatch, | ||||
|   recordSickPigDeathInBatch, | ||||
|   recordSickPigCullInBatch, | ||||
|   recordDeathInBatch, | ||||
|   recordCullInBatch, | ||||
|   getAllPens, | ||||
|   getAllPigHouses, | ||||
|     getPigBatches, | ||||
|     createPigBatch, | ||||
|     getPigBatchById, | ||||
|     updatePigBatch, | ||||
|     deletePigBatch, | ||||
|     assignPensToBatch, | ||||
|     removePenFromBatch, | ||||
|     buyPigsForBatch, | ||||
|     sellPigsFromBatch, | ||||
|     movePigsIntoPen, | ||||
|     transferPigsWithinBatch, | ||||
|     transferPigsAcrossBatches, | ||||
|     reclassifyPenToNewBatch, | ||||
|     recordSickPigsInBatch, | ||||
|     recordSickPigRecoveryInBatch, | ||||
|     recordSickPigDeathInBatch, | ||||
|     recordSickPigCullInBatch, | ||||
|     recordDeathInBatch, | ||||
|     recordCullInBatch, | ||||
|     getAllPens, | ||||
|     getAllPigHouses, | ||||
| }; | ||||
|   | ||||
| @@ -1,15 +1,15 @@ | ||||
| <template> | ||||
|   <div class="plan-detail"> | ||||
|     <div v-if="loading" class="loading"> | ||||
|       <el-skeleton animated /> | ||||
|       <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" | ||||
|           :title="'加载计划内容失败 (ID: ' + planId + ')'" | ||||
|           :description="error" | ||||
|           type="error" | ||||
|           show-icon | ||||
|           @close="error = null" | ||||
|       /> | ||||
|       <el-button type="primary" @click="fetchPlan" class="retry-btn">重新加载</el-button> | ||||
|     </div> | ||||
| @@ -20,27 +20,35 @@ | ||||
|             <span>{{ plan.name }} - 内容</span> | ||||
|             <div> | ||||
|               <template v-if="!isSubPlan"> | ||||
|                 <el-button class="button" type="primary" @click="savePlanContent" v-if="isEditingContent" :disabled="plan.plan_type === '系统任务'">保存</el-button> | ||||
|                 <el-button class="button" type="danger" @click="cancelEdit" v-if="isEditingContent" :disabled="plan.plan_type === '系统任务'">取消</el-button> | ||||
|                 <el-button class="button" @click="enterEditMode" v-else :disabled="plan.plan_type === '系统任务'">编辑内容</el-button> | ||||
|                 <el-button class="button" type="primary" @click="savePlanContent" v-if="isEditingContent" | ||||
|                            :disabled="plan.plan_type === '系统任务'">保存 | ||||
|                 </el-button> | ||||
|                 <el-button class="button" type="danger" @click="cancelEdit" v-if="isEditingContent" | ||||
|                            :disabled="plan.plan_type === '系统任务'">取消 | ||||
|                 </el-button> | ||||
|                 <el-button class="button" @click="enterEditMode" v-else :disabled="plan.plan_type === '系统任务'"> | ||||
|                   编辑内容 | ||||
|                 </el-button> | ||||
|               </template> | ||||
|  | ||||
|               <!-- Dynamic Add Buttons --> | ||||
|               <template v-if="isEditingContent"> | ||||
|                 <el-button | ||||
|                   v-if="plan.content_type === 'sub_plans' || !plan.content_type" | ||||
|                   type="primary" | ||||
|                   size="small" | ||||
|                   @click="showAddSubPlanDialog" | ||||
|                   :disabled="plan.plan_type === '系统任务'" | ||||
|                 >增加子计划</el-button> | ||||
|                     v-if="plan.content_type === 'sub_plans' || !plan.content_type" | ||||
|                     type="primary" | ||||
|                     size="small" | ||||
|                     @click="showAddSubPlanDialog" | ||||
|                     :disabled="plan.plan_type === '系统任务'" | ||||
|                 >增加子计划 | ||||
|                 </el-button> | ||||
|                 <el-button | ||||
|                   v-if="plan.content_type === 'tasks' || !plan.content_type" | ||||
|                   type="primary" | ||||
|                   size="small" | ||||
|                   @click="showTaskEditorDialog()" | ||||
|                   :disabled="plan.plan_type === '系统任务'" | ||||
|                 >增加子任务</el-button> | ||||
|                     v-if="plan.content_type === 'tasks' || !plan.content_type" | ||||
|                     type="primary" | ||||
|                     size="small" | ||||
|                     @click="showTaskEditorDialog()" | ||||
|                     :disabled="plan.plan_type === '系统任务'" | ||||
|                 >增加子任务 | ||||
|                 </el-button> | ||||
|               </template> | ||||
|             </div> | ||||
|           </div> | ||||
| @@ -51,10 +59,10 @@ | ||||
|           <h4>任务列表</h4> | ||||
|           <el-timeline v-if="plan.tasks.length > 0"> | ||||
|             <el-timeline-item | ||||
|               v-for="(task, index) in plan.tasks" | ||||
|               :key="task.id || 'new-task-' + index" | ||||
|               :timestamp="'执行顺序: ' + (task.execution_order !== undefined ? task.execution_order : index + 1)" | ||||
|               placement="top" | ||||
|                 v-for="(task, index) in plan.tasks" | ||||
|                 :key="task.id || 'new-task-' + index" | ||||
|                 :timestamp="'执行顺序: ' + (task.execution_order !== undefined ? task.execution_order : index + 1)" | ||||
|                 placement="top" | ||||
|             > | ||||
|               <el-card> | ||||
|                 <h5>{{ task.name }} ({{ task.type === 'waiting' ? '延时任务' : '未知任务' }})</h5> | ||||
| @@ -63,8 +71,12 @@ | ||||
|                   延时: {{ task.parameters.delay_duration }} 秒 | ||||
|                 </p> | ||||
|                 <el-button-group v-if="isEditingContent"> | ||||
|                   <el-button type="primary" size="small" @click="editTask(task)" :disabled="plan.plan_type === '系统任务'">编辑</el-button> | ||||
|                   <el-button type="danger" size="small" @click="deleteTask(task)" :disabled="plan.plan_type === '系统任务'">删除</el-button> | ||||
|                   <el-button type="primary" size="small" @click="editTask(task)" | ||||
|                              :disabled="plan.plan_type === '系统任务'">编辑 | ||||
|                   </el-button> | ||||
|                   <el-button type="danger" size="small" @click="deleteTask(task)" | ||||
|                              :disabled="plan.plan_type === '系统任务'">删除 | ||||
|                   </el-button> | ||||
|                 </el-button-group> | ||||
|               </el-card> | ||||
|             </el-timeline-item> | ||||
| @@ -76,13 +88,16 @@ | ||||
|         <div v-else-if="plan.content_type === 'sub_plans'"> | ||||
|           <h4>子计划列表</h4> | ||||
|           <div v-if="plan.sub_plans.length > 0"> | ||||
|             <div v-for="(subPlan, index) in plan.sub_plans" :key="subPlan.id || 'new-subplan-' + index" class="sub-plan-wrapper"> | ||||
|             <div v-for="(subPlan, index) in plan.sub_plans" :key="subPlan.id || 'new-subplan-' + index" | ||||
|                  class="sub-plan-wrapper"> | ||||
|               <el-card> | ||||
|                 <div class="sub-plan-card-content"> | ||||
|                   <!-- Pass child_plan_id to recursive PlanDetail --> | ||||
|                   <plan-detail :plan-id="subPlan.child_plan_id" :is-sub-plan="true" /> | ||||
|                   <plan-detail :plan-id="subPlan.child_plan_id" :is-sub-plan="true"/> | ||||
|                   <el-button-group v-if="isEditingContent" class="sub-plan-actions"> | ||||
|                     <el-button type="danger" size="small" @click="deleteSubPlan(subPlan)" :disabled="plan.plan_type === '系统任务'">删除</el-button> | ||||
|                     <el-button type="danger" size="small" @click="deleteSubPlan(subPlan)" | ||||
|                                :disabled="plan.plan_type === '系统任务'">删除 | ||||
|                     </el-button> | ||||
|                   </el-button-group> | ||||
|                 </div> | ||||
|               </el-card> | ||||
| @@ -102,22 +117,22 @@ | ||||
|  | ||||
|     <!-- Add Sub-plan Dialog --> | ||||
|     <el-dialog | ||||
|       v-model="addSubPlanDialogVisible" | ||||
|       title="选择子计划" | ||||
|       width="600px" | ||||
|       @close="resetAddSubPlanDialog" | ||||
|         v-model="addSubPlanDialogVisible" | ||||
|         title="选择子计划" | ||||
|         width="600px" | ||||
|         @close="resetAddSubPlanDialog" | ||||
|     > | ||||
|       <el-select | ||||
|         v-model="selectedSubPlanId" | ||||
|         placeholder="请选择一个计划作为子计划" | ||||
|         filterable | ||||
|         style="width: 100%;" | ||||
|           v-model="selectedSubPlanId" | ||||
|           placeholder="请选择一个计划作为子计划" | ||||
|           filterable | ||||
|           style="width: 100%;" | ||||
|       > | ||||
|         <el-option | ||||
|           v-for="item in availablePlans" | ||||
|           :key="item.id" | ||||
|           :label="item.name" | ||||
|           :value="item.id" | ||||
|             v-for="item in availablePlans" | ||||
|             :key="item.id" | ||||
|             :label="item.name" | ||||
|             :value="item.id" | ||||
|         ></el-option> | ||||
|       </el-select> | ||||
|       <template #footer> | ||||
| @@ -130,32 +145,35 @@ | ||||
|  | ||||
|     <!-- Task Editor Dialog (for Add and Edit) --> | ||||
|     <el-dialog | ||||
|       v-model="taskEditorDialogVisible" | ||||
|       :title="isEditingTask ? '编辑子任务' : '增加子任务'" | ||||
|       width="600px" | ||||
|       @close="resetTaskEditorDialog" | ||||
|         v-model="taskEditorDialogVisible" | ||||
|         :title="isEditingTask ? '编辑子任务' : '增加子任务'" | ||||
|         width="600px" | ||||
|         @close="resetTaskEditorDialog" | ||||
|     > | ||||
|       <el-form :model="currentTaskForm" ref="taskFormRef" :rules="taskFormRules" label-width="100px"> | ||||
|         <el-form-item label="任务类型" prop="type"> | ||||
|           <el-select v-model="currentTaskForm.type" placeholder="请选择任务类型" style="width: 100%;" :disabled="isEditingTask || plan.plan_type === '系统任务'"> | ||||
|           <el-select v-model="currentTaskForm.type" placeholder="请选择任务类型" style="width: 100%;" | ||||
|                      :disabled="isEditingTask || plan.plan_type === '系统任务'"> | ||||
|             <!-- Only Delay Task for now --> | ||||
|             <el-option label="延时任务" value="delay_task"></el-option> | ||||
|           </el-select> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="任务名称" prop="name"> | ||||
|           <el-input v-model="currentTaskForm.name" placeholder="请输入任务名称" :disabled="plan.plan_type === '系统任务'"></el-input> | ||||
|           <el-input v-model="currentTaskForm.name" placeholder="请输入任务名称" | ||||
|                     :disabled="plan.plan_type === '系统任务'"></el-input> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="任务描述" prop="description"> | ||||
|           <el-input type="textarea" v-model="currentTaskForm.description" placeholder="请输入任务描述" :disabled="plan.plan_type === '系统任务'"></el-input> | ||||
|           <el-input type="textarea" v-model="currentTaskForm.description" placeholder="请输入任务描述" | ||||
|                     :disabled="plan.plan_type === '系统任务'"></el-input> | ||||
|         </el-form-item> | ||||
|         <!-- Dynamic task component for specific parameters --> | ||||
|         <template v-if="currentTaskForm.type === 'delay_task'"> | ||||
|           <DelayTaskEditor | ||||
|             :parameters="currentTaskForm.parameters" | ||||
|             @update:parameters="val => currentTaskForm.parameters = val" | ||||
|             prop-path="parameters.delay_duration" | ||||
|             :is-editing="true"  | ||||
|             :disabled="plan.plan_type === '系统任务'" | ||||
|               :parameters="currentTaskForm.parameters" | ||||
|               @update:parameters="val => currentTaskForm.parameters = val" | ||||
|               prop-path="parameters.delay_duration" | ||||
|               :is-editing="true" | ||||
|               :disabled="plan.plan_type === '系统任务'" | ||||
|           /> | ||||
|         </template> | ||||
|         <!-- More task types can be rendered here --> | ||||
| @@ -172,17 +190,17 @@ | ||||
|  | ||||
| <script> | ||||
| import apiClient from '../api/index.js'; | ||||
| import { ElMessage, ElMessageBox } from 'element-plus'; | ||||
| import { ArrowDown } from '@element-plus/icons-vue';  | ||||
| import DelayTaskEditor from './tasks/DelayTask.vue';  | ||||
| import {ElMessage, ElMessageBox} from 'element-plus'; | ||||
| import {ArrowDown} from '@element-plus/icons-vue'; | ||||
| import DelayTaskEditor from './tasks/DelayTask.vue'; | ||||
|  | ||||
| export default { | ||||
|   name: 'PlanDetail', | ||||
|   components: { | ||||
|     DelayTaskEditor,  | ||||
|     DelayTaskEditor, | ||||
|     // Self-reference for recursion | ||||
|     'plan-detail': this, | ||||
|     ArrowDown,  | ||||
|     ArrowDown, | ||||
|   }, | ||||
|   props: { | ||||
|     planId: { | ||||
| @@ -203,9 +221,9 @@ export default { | ||||
|         execution_type: 'automatic', | ||||
|         execute_num: 0, | ||||
|         cron_expression: '', | ||||
|         content_type: null,  | ||||
|         sub_plans: [],  | ||||
|         tasks: [],      | ||||
|         content_type: null, | ||||
|         sub_plans: [], | ||||
|         tasks: [], | ||||
|       }, | ||||
|       loading: false, | ||||
|       error: null, | ||||
| @@ -217,25 +235,25 @@ export default { | ||||
|       availablePlans: [], | ||||
|  | ||||
|       // Task Editor dialog (for Add and Edit) | ||||
|       taskEditorDialogVisible: false,  | ||||
|       isEditingTask: false,  | ||||
|       editingTaskOriginalId: null,  | ||||
|       currentTaskForm: {  | ||||
|         type: 'delay_task',  | ||||
|       taskEditorDialogVisible: false, | ||||
|       isEditingTask: false, | ||||
|       editingTaskOriginalId: null, | ||||
|       currentTaskForm: { | ||||
|         type: 'delay_task', | ||||
|         name: '', | ||||
|         description: '', | ||||
|         parameters: {},  | ||||
|         parameters: {}, | ||||
|       }, | ||||
|       taskFormRules: {  | ||||
|         type: [{ required: true, message: '请选择任务类型', trigger: 'change' }], | ||||
|         name: [{ required: true, message: '请输入任务名称', trigger: 'blur' }], | ||||
|       taskFormRules: { | ||||
|         type: [{required: true, message: '请选择任务类型', trigger: 'change'}], | ||||
|         name: [{required: true, message: '请输入任务名称', trigger: 'blur'}], | ||||
|         // Rule for delay_duration will be added/removed dynamically | ||||
|       }, | ||||
|     }; | ||||
|   }, | ||||
|   computed: { | ||||
|     delayDurationRules() { | ||||
|       return [{ required: true, message: '请输入延时时间', trigger: 'blur' }]; | ||||
|       return [{required: true, message: '请输入延时时间', trigger: 'blur'}]; | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
| @@ -247,7 +265,7 @@ export default { | ||||
|         } | ||||
|       }, | ||||
|     }, | ||||
|     'currentTaskForm.type'(newType) {  | ||||
|     'currentTaskForm.type'(newType) { | ||||
|       console.log("PlanDetail: currentTaskForm.type changed to", newType); | ||||
|       if (newType === 'delay_task') { | ||||
|         this.taskFormRules['parameters.delay_duration'] = this.delayDurationRules; | ||||
| @@ -274,7 +292,7 @@ export default { | ||||
|           sub_plans: response.data.sub_plans || [], | ||||
|           tasks: response.data.tasks || [], | ||||
|         }; | ||||
|         this.updateContentType();  | ||||
|         this.updateContentType(); | ||||
|       } catch (err) { | ||||
|         this.error = err.message || '未知错误'; | ||||
|         console.error(`加载计划 (ID: ${this.planId}) 失败:`, err); | ||||
| @@ -288,7 +306,7 @@ export default { | ||||
|       } else if (this.plan.tasks.length > 0) { | ||||
|         this.plan.content_type = 'tasks'; | ||||
|       } else { | ||||
|         this.plan.content_type = null;  | ||||
|         this.plan.content_type = null; | ||||
|       } | ||||
|     }, | ||||
|     enterEditMode() { | ||||
| @@ -296,27 +314,27 @@ export default { | ||||
|       console.log("PlanDetail: Entered edit mode."); | ||||
|     }, | ||||
|     async savePlanContent() { | ||||
|       this.updateContentType();  | ||||
|       this.updateContentType(); | ||||
|       try { | ||||
|         const submitData = { | ||||
|           id: this.plan.id,  | ||||
|           id: this.plan.id, | ||||
|           name: this.plan.name, | ||||
|           description: this.plan.description, | ||||
|           execution_type: this.plan.execution_type, | ||||
|           execute_num: this.plan.execute_num, | ||||
|           cron_expression: this.plan.cron_expression, | ||||
|           sub_plan_ids: this.plan.content_type === 'sub_plans' | ||||
|             ? this.plan.sub_plans.map(sp => sp.child_plan_id)  | ||||
|             : [], | ||||
|               ? this.plan.sub_plans.map(sp => sp.child_plan_id) | ||||
|               : [], | ||||
|           tasks: this.plan.content_type === 'tasks' | ||||
|             ? this.plan.tasks.map((task, index) => ({ | ||||
|               ? this.plan.tasks.map((task, index) => ({ | ||||
|                 name: task.name, | ||||
|                 description: task.description, | ||||
|                 type: task.type, | ||||
|                 execution_order: index + 1,  | ||||
|                 execution_order: index + 1, | ||||
|                 parameters: task.parameters || {}, | ||||
|               })) | ||||
|             : [], | ||||
|               : [], | ||||
|         }; | ||||
|  | ||||
|         delete submitData.execute_count; | ||||
| @@ -325,8 +343,8 @@ export default { | ||||
|         console.log("PlanDetail: Submitting data", submitData); | ||||
|         await apiClient.plans.updatePlan(this.planId, submitData); | ||||
|         ElMessage.success('计划内容已保存'); | ||||
|         this.isEditingContent = false;  | ||||
|         this.fetchPlan();  | ||||
|         this.isEditingContent = false; | ||||
|         this.fetchPlan(); | ||||
|       } catch (error) { | ||||
|         ElMessage.error('保存计划内容失败: ' + (error.message || '未知错误')); | ||||
|         console.error('保存计划内容失败:', error); | ||||
| @@ -335,7 +353,7 @@ export default { | ||||
|     async cancelEdit() { | ||||
|       console.log("PlanDetail: Cancelled edit, re-fetching plan."); | ||||
|       await this.fetchPlan(); | ||||
|       this.isEditingContent = false;  | ||||
|       this.isEditingContent = false; | ||||
|       ElMessage.info('已取消编辑'); | ||||
|     }, | ||||
|  | ||||
| @@ -348,7 +366,7 @@ export default { | ||||
|             cancelButtonText: '取消', | ||||
|             type: 'warning' | ||||
|           }); | ||||
|           this.plan.tasks = [];  | ||||
|           this.plan.tasks = []; | ||||
|         } catch (e) { | ||||
|           return; | ||||
|         } | ||||
| @@ -358,9 +376,9 @@ export default { | ||||
|     }, | ||||
|     async fetchAvailablePlans() { | ||||
|       try { | ||||
|         const response = await apiClient.plans.getPlans({ plan_type: '自定义任务' });  | ||||
|         const response = await apiClient.plans.getPlans({plan_type: '自定义任务', page: 1, page_size: 1000}); | ||||
|         this.availablePlans = response.data.plans.filter(p => | ||||
|           p.id !== this.planId | ||||
|             p.id !== this.planId | ||||
|         ); | ||||
|       } catch (error) { | ||||
|         ElMessage.error('加载可用计划失败: ' + (error.message || '未知错误')); | ||||
| @@ -376,12 +394,12 @@ export default { | ||||
|       const selectedPlan = this.availablePlans.find(p => p.id === this.selectedSubPlanId); | ||||
|       if (selectedPlan) { | ||||
|         this.plan.sub_plans.push({ | ||||
|           id: Date.now(),  | ||||
|           id: Date.now(), | ||||
|           child_plan_id: selectedPlan.id, | ||||
|           child_plan: selectedPlan,  | ||||
|           child_plan: selectedPlan, | ||||
|           execution_order: this.plan.sub_plans.length + 1, | ||||
|         }); | ||||
|         this.updateContentType();  | ||||
|         this.updateContentType(); | ||||
|         ElMessage.success(`子计划 "${selectedPlan.name}" 已添加`); | ||||
|         this.addSubPlanDialogVisible = false; | ||||
|         this.resetAddSubPlanDialog(); | ||||
| @@ -400,29 +418,29 @@ export default { | ||||
|         type: 'warning' | ||||
|       }).then(() => { | ||||
|         this.plan.sub_plans = this.plan.sub_plans.filter(sub => sub.id !== subPlanToDelete.id); | ||||
|         this.plan.sub_plans.forEach((item, index) => item.execution_order = index + 1);  | ||||
|         this.updateContentType();  | ||||
|         this.plan.sub_plans.forEach((item, index) => item.execution_order = index + 1); | ||||
|         this.updateContentType(); | ||||
|         ElMessage.success('子计划已删除'); | ||||
|       }).catch(() => { | ||||
|       }); | ||||
|     }, | ||||
|  | ||||
|     // --- Task related methods --- | ||||
|     showTaskEditorDialog(task = null) {  | ||||
|     showTaskEditorDialog(task = null) { | ||||
|       console.log("PlanDetail: Showing task editor dialog."); | ||||
|       if (this.plan.sub_plans.length > 0 && !task) {  | ||||
|       if (this.plan.sub_plans.length > 0 && !task) { | ||||
|         ElMessageBox.confirm('当前计划包含子计划,添加任务将清空现有子计划。是否继续?', '警告', { | ||||
|             confirmButtonText: '确定', | ||||
|             cancelButtonText: '取消', | ||||
|             type: 'warning' | ||||
|           }).then(() => { | ||||
|             this.plan.sub_plans = [];  | ||||
|             this.taskEditorDialogVisible = true; | ||||
|             this.prepareTaskForm(task); | ||||
|           }).catch(() => { | ||||
|             // User cancelled | ||||
|           }); | ||||
|           return; | ||||
|           confirmButtonText: '确定', | ||||
|           cancelButtonText: '取消', | ||||
|           type: 'warning' | ||||
|         }).then(() => { | ||||
|           this.plan.sub_plans = []; | ||||
|           this.taskEditorDialogVisible = true; | ||||
|           this.prepareTaskForm(task); | ||||
|         }).catch(() => { | ||||
|           // User cancelled | ||||
|         }); | ||||
|         return; | ||||
|       } | ||||
|       this.taskEditorDialogVisible = true; | ||||
|       this.prepareTaskForm(task); | ||||
| @@ -447,11 +465,11 @@ export default { | ||||
|         this.isEditingTask = false; | ||||
|         this.editingTaskOriginalId = null; | ||||
|         // For new tasks, ensure delay_duration is reactive from start | ||||
|         this.currentTaskForm.parameters = { delay_duration: null };  | ||||
|         this.currentTaskForm.parameters = {delay_duration: null}; | ||||
|         console.log("PlanDetail: Prepared currentTaskForm for adding:", JSON.parse(JSON.stringify(this.currentTaskForm))); | ||||
|       } | ||||
|       // Manually trigger watch for type to ensure rules and default parameters are set | ||||
|       this.updateTaskFormRules();  | ||||
|       this.updateTaskFormRules(); | ||||
|     }, | ||||
|     updateTaskFormRules() { | ||||
|       // Clear existing dynamic rules | ||||
| @@ -464,7 +482,7 @@ export default { | ||||
|       } | ||||
|       console.log("PlanDetail: Updated taskFormRules:", JSON.parse(JSON.stringify(this.taskFormRules))); | ||||
|     }, | ||||
|     confirmTaskEdit() {  | ||||
|     confirmTaskEdit() { | ||||
|       console.log("PlanDetail: confirmTaskEdit called. currentTaskForm before validation:", JSON.parse(JSON.stringify(this.currentTaskForm))); | ||||
|       this.$refs.taskFormRef.validate(async (valid) => { | ||||
|         console.log("PlanDetail: Form validation result:", valid); | ||||
| @@ -479,47 +497,46 @@ export default { | ||||
|                 name: this.currentTaskForm.name, | ||||
|                 description: this.currentTaskForm.description, | ||||
|                 type: this.currentTaskForm.type === 'delay_task' ? 'waiting' : this.currentTaskForm.type, | ||||
|                 parameters: { ...this.currentTaskForm.parameters }, // Deep copy parameters to ensure new reference | ||||
|                 parameters: {...this.currentTaskForm.parameters}, // Deep copy parameters to ensure new reference | ||||
|               }; | ||||
|               this.plan.tasks.splice(index, 1, updatedTask); // Replace the old task with the new one | ||||
|               ElMessage.success(`子任务 "${this.currentTaskForm.name}" 已更新`); | ||||
|             } else { | ||||
|               ElMessage.error('未找到要编辑的任务'); | ||||
|             } | ||||
|           } | ||||
|           else { | ||||
|           } else { | ||||
|             // Add a new task | ||||
|             const newTask = { | ||||
|               id: Date.now(),  | ||||
|               id: Date.now(), | ||||
|               execution_order: this.plan.tasks.length + 1, | ||||
|               type: this.currentTaskForm.type === 'delay_task' ? 'waiting' : this.currentTaskForm.type, | ||||
|               name: this.currentTaskForm.name, | ||||
|               description: this.currentTaskForm.description, | ||||
|               parameters: { ...this.currentTaskForm.parameters }, // Deep copy parameters to ensure new reference | ||||
|               parameters: {...this.currentTaskForm.parameters}, // Deep copy parameters to ensure new reference | ||||
|             }; | ||||
|             this.plan.tasks = [...this.plan.tasks, newTask]; // Create a new array reference | ||||
|             ElMessage.success(`子任务 "${newTask.name}" 已添加`); | ||||
|           } | ||||
|           this.updateContentType();  | ||||
|           this.updateContentType(); | ||||
|           this.taskEditorDialogVisible = false; | ||||
|           this.resetTaskEditorDialog(); | ||||
|         } | ||||
|       }); | ||||
|     }, | ||||
|     resetTaskEditorDialog() {  | ||||
|     resetTaskEditorDialog() { | ||||
|       console.log("PlanDetail: Resetting task editor dialog."); | ||||
|       this.$refs.taskFormRef.resetFields(); | ||||
|       this.isEditingTask = false; | ||||
|       this.editingTaskOriginalId = null; | ||||
|       // Manually reset properties to ensure clean state for next use | ||||
|       this.currentTaskForm.type = 'delay_task';  | ||||
|       this.currentTaskForm.type = 'delay_task'; | ||||
|       this.currentTaskForm.name = ''; | ||||
|       this.currentTaskForm.description = ''; | ||||
|       this.currentTaskForm.parameters = {};  | ||||
|       this.currentTaskForm.parameters = {}; | ||||
|       console.log("PlanDetail: currentTaskForm after full reset:", JSON.parse(JSON.stringify(this.currentTaskForm))); | ||||
|       this.updateTaskFormRules();  | ||||
|       this.updateTaskFormRules(); | ||||
|     }, | ||||
|     editTask(task) {  | ||||
|     editTask(task) { | ||||
|       console.log('PlanDetail: Calling showTaskEditorDialog for editing task:', task); | ||||
|       this.showTaskEditorDialog(task); | ||||
|     }, | ||||
| @@ -530,8 +547,8 @@ export default { | ||||
|         type: 'warning' | ||||
|       }).then(() => { | ||||
|         this.plan.tasks = this.plan.tasks.filter(task => task.id !== taskToDelete.id); | ||||
|         this.plan.tasks.forEach((item, index) => item.execution_order = index + 1);  | ||||
|         this.updateContentType();  | ||||
|         this.plan.tasks.forEach((item, index) => item.execution_order = index + 1); | ||||
|         this.updateContentType(); | ||||
|         ElMessage.success('任务已删除'); | ||||
|       }).catch(() => { | ||||
|       }); | ||||
| @@ -544,37 +561,45 @@ export default { | ||||
| .plan-detail { | ||||
|   margin-top: 10px; | ||||
| } | ||||
|  | ||||
| .loading, .error { | ||||
|   padding: 20px; | ||||
|   text-align: center; | ||||
| } | ||||
|  | ||||
| .retry-btn { | ||||
|   margin-top: 15px; | ||||
| } | ||||
|  | ||||
| .sub-plan-wrapper { | ||||
|   margin-bottom: 10px;  | ||||
|   margin-bottom: 10px; | ||||
| } | ||||
|  | ||||
| .sub-plan-container { | ||||
|   margin-left: 20px; | ||||
|   margin-top: 10px; | ||||
|   border-left: 2px solid #ebeef5;  | ||||
|   border-left: 2px solid #ebeef5; | ||||
|   padding-left: 10px; | ||||
| } | ||||
|  | ||||
| .sub-plan-card-content { | ||||
|   display: flex; | ||||
|   flex-direction: column;  | ||||
|   gap: 10px;  | ||||
|   flex-direction: column; | ||||
|   gap: 10px; | ||||
| } | ||||
|  | ||||
| .sub-plan-actions { | ||||
|   align-self: flex-end;  | ||||
|   align-self: flex-end; | ||||
| } | ||||
|  | ||||
| .card-header { | ||||
|   display: flex; | ||||
|   justify-content: space-between; | ||||
|   align-items: center; | ||||
| } | ||||
|  | ||||
| /* 调整子计划卡片内部的header,避免重复样式 */ | ||||
| .sub-plan-container .card-header { | ||||
|   padding: 0;  | ||||
|   padding: 0; | ||||
| } | ||||
| </style> | ||||
|   | ||||
| @@ -6,12 +6,15 @@ | ||||
|           <div class="title-container"> | ||||
|             <h2 class="page-title">计划管理</h2> | ||||
|             <el-button type="text" @click="loadPlans" class="refresh-btn" title="刷新计划列表"> | ||||
|               <el-icon :size="20"><Refresh /></el-icon> | ||||
|               <el-icon :size="20"> | ||||
|                 <Refresh/> | ||||
|               </el-icon> | ||||
|             </el-button> | ||||
|           </div> | ||||
|            | ||||
|  | ||||
|           <div class="filter-and-add"> | ||||
|             <el-select v-model="planTypeFilter" placeholder="选择计划类型" @change="loadPlans" style="width: 150px; margin-right: 10px;"> | ||||
|             <el-select v-model="planTypeFilter" placeholder="选择计划类型" @change="loadPlans" | ||||
|                        style="width: 150px; margin-right: 10px;"> | ||||
|               <el-option label="所有任务" value="所有任务"></el-option> | ||||
|               <el-option label="自定义任务" value="自定义任务"></el-option> | ||||
|               <el-option label="系统任务" value="系统任务"></el-option> | ||||
| @@ -20,36 +23,36 @@ | ||||
|           </div> | ||||
|         </div> | ||||
|       </template> | ||||
|        | ||||
|  | ||||
|       <!-- 加载状态 --> | ||||
|       <div v-if="loading" class="loading"> | ||||
|         <el-skeleton animated /> | ||||
|         <el-skeleton animated/> | ||||
|       </div> | ||||
|        | ||||
|  | ||||
|       <!-- 错误状态 --> | ||||
|       <div v-else-if="error" class="error"> | ||||
|         <el-alert | ||||
|           title="获取计划数据失败" | ||||
|           :description="error" | ||||
|           type="error" | ||||
|           show-icon | ||||
|           closable | ||||
|           @close="error = null" | ||||
|             title="获取计划数据失败" | ||||
|             :description="error" | ||||
|             type="error" | ||||
|             show-icon | ||||
|             closable | ||||
|             @close="error = null" | ||||
|         /> | ||||
|         <el-button type="primary" @click="loadPlans" class="retry-btn">重新加载</el-button> | ||||
|       </div> | ||||
|        | ||||
|       <el-table  | ||||
|         v-else | ||||
|         :data="plans" | ||||
|         style="width: 100%"  | ||||
|         class="plan-list-table" | ||||
|         :fit="true" | ||||
|         :scrollbar-always-on="true" | ||||
|         @sort-change="handleSortChange"> | ||||
|         <el-table-column prop="id" label="计划ID" min-width="100" sortable="custom" /> | ||||
|         <el-table-column prop="name" label="计划名称" min-width="120" sortable="custom" /> | ||||
|         <el-table-column prop="description" label="计划描述" min-width="150" /> | ||||
|  | ||||
|       <el-table | ||||
|           v-else | ||||
|           :data="plans" | ||||
|           style="width: 100%" | ||||
|           class="plan-list-table" | ||||
|           :fit="true" | ||||
|           :scrollbar-always-on="true" | ||||
|           @sort-change="handleSortChange"> | ||||
|         <el-table-column prop="id" label="计划ID" min-width="100" sortable="custom"/> | ||||
|         <el-table-column prop="name" label="计划名称" min-width="120" sortable="custom"/> | ||||
|         <el-table-column prop="description" label="计划描述" min-width="150"/> | ||||
|         <el-table-column prop="execution_type" label="执行类型" min-width="150" sortable="custom"> | ||||
|           <template #default="scope"> | ||||
|             <el-tag v-if="scope.row.execution_type === 'manual'">手动</el-tag> | ||||
| @@ -57,7 +60,7 @@ | ||||
|             <el-tag v-else type="warning">自动({{ scope.row.execute_num }}次)</el-tag> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column prop="execute_count" label="已执行次数" min-width="120" sortable="custom" /> | ||||
|         <el-table-column prop="execute_count" label="已执行次数" min-width="120" sortable="custom"/> | ||||
|         <el-table-column prop="status" label="状态" min-width="100" sortable="custom"> | ||||
|           <template #default="scope"> | ||||
|             <el-tag v-if="scope.row.status === 0" type="danger">禁用计划</el-tag> | ||||
| @@ -73,43 +76,46 @@ | ||||
|         </el-table-column> | ||||
|         <el-table-column label="操作" width="280"> | ||||
|           <template #default="scope"> | ||||
|             <el-button size="small" @click="editPlan(scope.row)" :disabled="scope.row.plan_type === '系统任务'">编辑</el-button> | ||||
|             <el-button size="small" @click="editPlan(scope.row)" :disabled="scope.row.plan_type === '系统任务'">编辑 | ||||
|             </el-button> | ||||
|             <el-button size="small" @click="showDetails(scope.row)">详情</el-button> | ||||
|             <el-button  | ||||
|               size="small"  | ||||
|               :type="scope.row.status === 1 ? 'warning' : 'primary'" | ||||
|               @click="scope.row.status === 1 ? stopPlan(scope.row) : startPlan(scope.row)" | ||||
|               :loading="stoppingPlanId === scope.row.id || startingPlanId === scope.row.id" | ||||
|               :disabled="scope.row.plan_type === '系统任务'" | ||||
|             <el-button | ||||
|                 size="small" | ||||
|                 :type="scope.row.status === 1 ? 'warning' : 'primary'" | ||||
|                 @click="scope.row.status === 1 ? stopPlan(scope.row) : startPlan(scope.row)" | ||||
|                 :loading="stoppingPlanId === scope.row.id || startingPlanId === scope.row.id" | ||||
|                 :disabled="scope.row.plan_type === '系统任务'" | ||||
|             > | ||||
|               {{ scope.row.status === 1 ? '停止' : '启动' }} | ||||
|             </el-button> | ||||
|             <el-button size="small" type="danger" @click="deletePlan(scope.row)" :disabled="scope.row.plan_type === '系统任务'">删除</el-button> | ||||
|             <el-button size="small" type="danger" @click="deletePlan(scope.row)" | ||||
|                        :disabled="scope.row.plan_type === '系统任务'">删除 | ||||
|             </el-button> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </el-table> | ||||
|        | ||||
|  | ||||
|     </el-card> | ||||
|  | ||||
|     <!-- 计划表单 --> | ||||
|     <PlanForm  | ||||
|       v-model:visible="dialogVisible"  | ||||
|       :plan-data="currentPlan"  | ||||
|       :is-edit="isEdit" | ||||
|       @success="handlePlanSuccess" | ||||
|       @cancel="handlePlanCancel" | ||||
|     <PlanForm | ||||
|         v-model:visible="dialogVisible" | ||||
|         :plan-data="currentPlan" | ||||
|         :is-edit="isEdit" | ||||
|         @success="handlePlanSuccess" | ||||
|         @cancel="handlePlanCancel" | ||||
|     /> | ||||
|  | ||||
|     <!-- 计划详情 --> | ||||
|     <el-dialog | ||||
|       v-model="detailsVisible" | ||||
|       title="计划详情" | ||||
|       width="70%" | ||||
|       top="5vh" | ||||
|         v-model="detailsVisible" | ||||
|         title="计划详情" | ||||
|         width="70%" | ||||
|         top="5vh" | ||||
|     > | ||||
|       <plan-detail | ||||
|         v-if="detailsVisible"  | ||||
|         :plan-id="selectedPlanIdForDetails" | ||||
|           v-if="detailsVisible" | ||||
|           :plan-id="selectedPlanIdForDetails" | ||||
|       /> | ||||
|       <template #footer> | ||||
|         <span class="dialog-footer"> | ||||
| @@ -122,7 +128,7 @@ | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { Refresh } from '@element-plus/icons-vue'; | ||||
| import {Refresh} from '@element-plus/icons-vue'; | ||||
| import apiClient from '../../api'; | ||||
| import PlanForm from '../../components/PlanForm.vue'; | ||||
| import PlanDetail from '../../components/PlanDetail.vue'; // 导入新组件 | ||||
| @@ -166,9 +172,9 @@ export default { | ||||
|     async loadPlans() { | ||||
|       this.loading = true; | ||||
|       this.error = null; | ||||
|        | ||||
|  | ||||
|       try { | ||||
|         const response = await apiClient.plans.getPlans({ plan_type: this.planTypeFilter }); // 传递 plan_typeFilter | ||||
|         const response = await apiClient.plans.getPlans({plan_type: this.planTypeFilter, page: 1, page_size: 1000}); // 传递 plan_typeFilter | ||||
|         let fetchedPlans = response.data?.plans || []; | ||||
|         // Default sort by ID ascending | ||||
|         fetchedPlans.sort((a, b) => a.id - b.id); | ||||
| @@ -183,7 +189,7 @@ export default { | ||||
|     }, | ||||
|  | ||||
|     // 处理表格排序 | ||||
|     handleSortChange({ prop, order }) { | ||||
|     handleSortChange({prop, order}) { | ||||
|       if (!order) { | ||||
|         // 恢复原始顺序 | ||||
|         this.plans = [...this.originalPlans]; | ||||
| @@ -221,13 +227,13 @@ export default { | ||||
|         return 0; | ||||
|       }); | ||||
|     }, | ||||
|      | ||||
|  | ||||
|     // 格式化下次执行时间 | ||||
|     formatNextExecutionTime(cronExpression) { | ||||
|       if (!cronExpression) { | ||||
|         return '-'; | ||||
|       } | ||||
|        | ||||
|  | ||||
|       try { | ||||
|         // 正确使用cron-parser库 | ||||
|         const parser = cronParser.default || cronParser; | ||||
| @@ -239,7 +245,7 @@ export default { | ||||
|         return '无效的表达式'; | ||||
|       } | ||||
|     }, | ||||
|      | ||||
|  | ||||
|     addPlan() { | ||||
|       this.currentPlan = { | ||||
|         id: null, | ||||
| @@ -257,13 +263,13 @@ export default { | ||||
|       this.selectedPlanIdForDetails = plan.id; | ||||
|       this.detailsVisible = true; | ||||
|     }, | ||||
|      | ||||
|  | ||||
|     editPlan(plan) { | ||||
|       this.currentPlan = { ...plan }; | ||||
|       this.currentPlan = {...plan}; | ||||
|       this.isEdit = true; | ||||
|       this.dialogVisible = true; | ||||
|     }, | ||||
|      | ||||
|  | ||||
|     async deletePlan(plan) { | ||||
|       try { | ||||
|         await this.$confirm('确认删除该计划吗?', '提示', { | ||||
| @@ -271,7 +277,7 @@ export default { | ||||
|           cancelButtonText: '取消', | ||||
|           type: 'warning' | ||||
|         }); | ||||
|          | ||||
|  | ||||
|         await apiClient.plans.deletePlan(plan.id); | ||||
|         this.$message.success('删除成功'); | ||||
|         await this.loadPlans(); | ||||
| @@ -281,7 +287,7 @@ export default { | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|      | ||||
|  | ||||
|     async startPlan(plan) { | ||||
|       try { | ||||
|         this.startingPlanId = plan.id; | ||||
| @@ -307,7 +313,7 @@ export default { | ||||
|         this.stoppingPlanId = null; | ||||
|       } | ||||
|     }, | ||||
|      | ||||
|  | ||||
|     // 处理计划表单提交成功 | ||||
|     async handlePlanSuccess(planData) { | ||||
|       try { | ||||
| @@ -321,17 +327,17 @@ export default { | ||||
|             ...planData, | ||||
|             content_type: 'tasks' // 默认使用任务类型 | ||||
|           }; | ||||
|            | ||||
|  | ||||
|           await apiClient.plans.createPlan(planRequest); | ||||
|           this.$message.success('计划添加成功'); | ||||
|         } | ||||
|          | ||||
|  | ||||
|         await this.loadPlans(); | ||||
|       } catch (err) { | ||||
|         this.$message.error('保存失败: ' + (err.message || '未知错误')); | ||||
|       } | ||||
|     }, | ||||
|      | ||||
|  | ||||
|     // 处理计划表单取消 | ||||
|     handlePlanCancel() { | ||||
|       this.dialogVisible = false; | ||||
| @@ -411,6 +417,7 @@ export default { | ||||
|   .plan-list { | ||||
|     padding: 10px; | ||||
|   } | ||||
|  | ||||
|   .card-header { | ||||
|     flex-direction: column; | ||||
|     gap: 15px; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user