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