月计划填报管理页面优化
This commit is contained in:
parent
3c394a9c2e
commit
6e60d53b8d
|
|
@ -0,0 +1,37 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
// 计划管理- 查询列表
|
||||
export function listPlanAPI(query) {
|
||||
return request({
|
||||
url: '/personnel/getPersonnelList',
|
||||
method: 'GET',
|
||||
params: query,
|
||||
})
|
||||
}
|
||||
|
||||
// 计划管理- 新增
|
||||
export function addPlanAPI(data) {
|
||||
return request({
|
||||
url: '/personnel/addPersonnel',
|
||||
method: 'POST',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
// 计划管理- 修改
|
||||
export function updatePlanAPI(data) {
|
||||
return request({
|
||||
url: '/personnel/updatePersonnel',
|
||||
method: 'POST',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
// 计划管理- 删除
|
||||
export function delPlanAPI(data) {
|
||||
return request({
|
||||
url: `/personnel/delPersonnel`,
|
||||
method: 'POST',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
// 计划管理- 查询列表
|
||||
export function listPlanAPI(query) {
|
||||
return request({
|
||||
url: '/personnel/getPersonnelList',
|
||||
method: 'GET',
|
||||
params: query,
|
||||
})
|
||||
}
|
||||
|
||||
// 计划管理- 新增
|
||||
export function addPlanAPI(data) {
|
||||
return request({
|
||||
url: '/personnel/addPersonnel',
|
||||
method: 'POST',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
// 计划管理- 修改
|
||||
export function updatePlanAPI(data) {
|
||||
return request({
|
||||
url: '/personnel/updatePersonnel',
|
||||
method: 'POST',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
// 计划管理- 删除
|
||||
export function delPlanAPI(data) {
|
||||
return request({
|
||||
url: `/personnel/delPersonnel`,
|
||||
method: 'POST',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
|
@ -320,7 +320,7 @@ const props = defineProps({
|
|||
},
|
||||
actionWidth: {
|
||||
type: [String, Number],
|
||||
default: 240, // 默认宽度可容纳3个按钮
|
||||
default: 200, // 默认宽度可容纳3个按钮
|
||||
},
|
||||
actionFixed: {
|
||||
type: [String, Boolean],
|
||||
|
|
|
|||
|
|
@ -31,7 +31,15 @@
|
|||
>
|
||||
<!-- 工具栏插槽 -->
|
||||
<template #toolbar>
|
||||
<slot name="toolbar" />
|
||||
<slot
|
||||
name="toolbar"
|
||||
:formData="
|
||||
Object.assign({}, searchFormRef?.getFormData() || {}, {
|
||||
pageNum: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
}) || {}
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- 自定义列插槽 -->
|
||||
|
|
@ -125,7 +133,7 @@ const loading = ref(false)
|
|||
const tableData = ref([])
|
||||
const pagination = reactive({
|
||||
page: 1,
|
||||
limit: 10,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
})
|
||||
|
||||
|
|
@ -179,7 +187,7 @@ const fetchData = async (formData = {}) => {
|
|||
...formData,
|
||||
...props.defaultQueryParams,
|
||||
pageNum: pagination.page, // 后端可能需要pageNum
|
||||
pageSize: pagination.limit, // 后端可能需要pageSize
|
||||
pageSize: pagination.pageSize, // 后端可能需要pageSize
|
||||
}
|
||||
|
||||
const response = await props.loadData(params)
|
||||
|
|
|
|||
|
|
@ -1,296 +1,383 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
|
||||
<el-form-item label="任务名称" prop="jobName">
|
||||
<el-input
|
||||
v-model="queryParams.jobName"
|
||||
placeholder="请输入任务名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@keyup.enter="handleQuery"
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch">
|
||||
<el-form-item label="任务名称" prop="jobName">
|
||||
<el-input
|
||||
v-model="queryParams.jobName"
|
||||
placeholder="请输入任务名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="任务组名" prop="jobGroup">
|
||||
<el-select
|
||||
v-model="queryParams.jobGroup"
|
||||
placeholder="请选择任务组名"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
>
|
||||
<el-option
|
||||
v-for="dict in sys_job_group"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="任务状态" prop="status">
|
||||
<el-select
|
||||
v-model="queryParams.status"
|
||||
placeholder="请选择任务状态"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
>
|
||||
<el-option
|
||||
v-for="dict in sys_job_status"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="Plus"
|
||||
@click="handleAdd"
|
||||
v-hasPermi="['monitor:job:add']"
|
||||
>新增</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="Edit"
|
||||
:disabled="single"
|
||||
@click="handleUpdate"
|
||||
v-hasPermi="['monitor:job:edit']"
|
||||
>修改</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="Delete"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
v-hasPermi="['monitor:job:remove']"
|
||||
>删除</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="Download"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['monitor:job:export']"
|
||||
>导出</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="info"
|
||||
plain
|
||||
icon="Operation"
|
||||
@click="handleJobLog"
|
||||
v-hasPermi="['monitor:job:query']"
|
||||
>日志</el-button
|
||||
>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="jobList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="任务编号" width="100" align="center" prop="jobId" />
|
||||
<el-table-column
|
||||
label="任务名称"
|
||||
align="center"
|
||||
prop="jobName"
|
||||
:show-overflow-tooltip="true"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="任务组名" prop="jobGroup">
|
||||
<el-select v-model="queryParams.jobGroup" placeholder="请选择任务组名" clearable style="width: 200px">
|
||||
<el-option
|
||||
v-for="dict in sys_job_group"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="任务状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择任务状态" clearable style="width: 200px">
|
||||
<el-option
|
||||
v-for="dict in sys_job_status"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table-column label="任务组名" align="center" prop="jobGroup">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_job_group" :value="scope.row.jobGroup" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="调用目标字符串"
|
||||
align="center"
|
||||
prop="invokeTarget"
|
||||
:show-overflow-tooltip="true"
|
||||
/>
|
||||
<el-table-column
|
||||
label="cron执行表达式"
|
||||
align="center"
|
||||
prop="cronExpression"
|
||||
:show-overflow-tooltip="true"
|
||||
/>
|
||||
<el-table-column label="状态" align="center">
|
||||
<template #default="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.status"
|
||||
active-value="0"
|
||||
inactive-value="1"
|
||||
@change="handleStatusChange(scope.row)"
|
||||
></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="操作"
|
||||
align="center"
|
||||
width="200"
|
||||
class-name="small-padding fixed-width"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-tooltip content="修改" placement="top">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="Edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['monitor:job:edit']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="删除" placement="top">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="Delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
v-hasPermi="['monitor:job:remove']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="执行一次" placement="top">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="CaretRight"
|
||||
@click="handleRun(scope.row)"
|
||||
v-hasPermi="['monitor:job:changeStatus']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="任务详细" placement="top">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="View"
|
||||
@click="handleView(scope.row)"
|
||||
v-hasPermi="['monitor:job:query']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="调度日志" placement="top">
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="Operation"
|
||||
@click="handleJobLog(scope.row)"
|
||||
v-hasPermi="['monitor:job:query']"
|
||||
></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="Plus"
|
||||
@click="handleAdd"
|
||||
v-hasPermi="['monitor:job:add']"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
icon="Edit"
|
||||
:disabled="single"
|
||||
@click="handleUpdate"
|
||||
v-hasPermi="['monitor:job:edit']"
|
||||
>修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="Delete"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
v-hasPermi="['monitor:job:remove']"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="Download"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['monitor:job:export']"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="info"
|
||||
plain
|
||||
icon="Operation"
|
||||
@click="handleJobLog"
|
||||
v-hasPermi="['monitor:job:query']"
|
||||
>日志</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<el-table v-loading="loading" :data="jobList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="任务编号" width="100" align="center" prop="jobId" />
|
||||
<el-table-column label="任务名称" align="center" prop="jobName" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="任务组名" align="center" prop="jobGroup">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_job_group" :value="scope.row.jobGroup" />
|
||||
<!-- 添加或修改定时任务对话框 -->
|
||||
<el-dialog :title="title" v-model="open" width="820px" append-to-body>
|
||||
<el-form ref="jobRef" :model="form" :rules="rules" label-width="120px">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="任务名称" prop="jobName">
|
||||
<el-input v-model="form.jobName" placeholder="请输入任务名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="任务分组" prop="jobGroup">
|
||||
<el-select v-model="form.jobGroup" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="dict in sys_job_group"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item prop="invokeTarget">
|
||||
<template #label>
|
||||
<span>
|
||||
调用方法
|
||||
<el-tooltip placement="top">
|
||||
<template #content>
|
||||
<div>
|
||||
Bean调用示例:ryTask.ryParams('ry')
|
||||
<br />Class类调用示例:com.ruoyi.quartz.task.RyTask.ryParams('ry')
|
||||
<br />参数说明:支持字符串,布尔类型,长整型,浮点型,整型
|
||||
</div>
|
||||
</template>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
<el-input
|
||||
v-model="form.invokeTarget"
|
||||
placeholder="请输入调用目标字符串"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="cron表达式" prop="cronExpression">
|
||||
<el-input
|
||||
v-model="form.cronExpression"
|
||||
placeholder="请输入cron执行表达式"
|
||||
>
|
||||
<template #append>
|
||||
<el-button type="primary" @click="handleShowCron">
|
||||
生成表达式
|
||||
<i class="el-icon-time el-icon--right"></i>
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="form.jobId !== undefined">
|
||||
<el-form-item label="状态">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio
|
||||
v-for="dict in sys_job_status"
|
||||
:key="dict.value"
|
||||
:value="dict.value"
|
||||
>{{ dict.label }}</el-radio
|
||||
>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="执行策略" prop="misfirePolicy">
|
||||
<el-radio-group v-model="form.misfirePolicy">
|
||||
<el-radio-button value="1">立即执行</el-radio-button>
|
||||
<el-radio-button value="2">执行一次</el-radio-button>
|
||||
<el-radio-button value="3">放弃执行</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否并发" prop="concurrent">
|
||||
<el-radio-group v-model="form.concurrent">
|
||||
<el-radio-button value="0">允许</el-radio-button>
|
||||
<el-radio-button value="1">禁止</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="cron执行表达式" align="center" prop="cronExpression" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="状态" align="center">
|
||||
<template #default="scope">
|
||||
<el-switch
|
||||
v-model="scope.row.status"
|
||||
active-value="0"
|
||||
inactive-value="1"
|
||||
@change="handleStatusChange(scope.row)"
|
||||
></el-switch>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="Cron表达式生成器" v-model="openCron" append-to-body destroy-on-close>
|
||||
<crontab
|
||||
ref="crontabRef"
|
||||
@hide="openCron = false"
|
||||
@fill="crontabFill"
|
||||
:expression="expression"
|
||||
></crontab>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 任务日志详细 -->
|
||||
<el-dialog title="任务详细" v-model="openView" width="700px" append-to-body>
|
||||
<el-form :model="form" label-width="120px">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="任务编号:">{{ form.jobId }}</el-form-item>
|
||||
<el-form-item label="任务名称:">{{ form.jobName }}</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="任务分组:">{{ jobGroupFormat(form) }}</el-form-item>
|
||||
<el-form-item label="创建时间:">{{ form.createTime }}</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="cron表达式:">{{ form.cronExpression }}</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="下次执行时间:">{{
|
||||
parseTime(form.nextValidTime)
|
||||
}}</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="调用目标方法:">{{ form.invokeTarget }}</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="任务状态:">
|
||||
<div v-if="form.status == 0">正常</div>
|
||||
<div v-else-if="form.status == 1">暂停</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否并发:">
|
||||
<div v-if="form.concurrent == 0">允许</div>
|
||||
<div v-else-if="form.concurrent == 1">禁止</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="执行策略:">
|
||||
<div v-if="form.misfirePolicy == 0">默认策略</div>
|
||||
<div v-else-if="form.misfirePolicy == 1">立即执行</div>
|
||||
<div v-else-if="form.misfirePolicy == 2">执行一次</div>
|
||||
<div v-else-if="form.misfirePolicy == 3">放弃执行</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="openView = false">关 闭</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="200" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-tooltip content="修改" placement="top">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['monitor:job:edit']"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="删除" placement="top">
|
||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['monitor:job:remove']"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="执行一次" placement="top">
|
||||
<el-button link type="primary" icon="CaretRight" @click="handleRun(scope.row)" v-hasPermi="['monitor:job:changeStatus']"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="任务详细" placement="top">
|
||||
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['monitor:job:query']"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="调度日志" placement="top">
|
||||
<el-button link type="primary" icon="Operation" @click="handleJobLog(scope.row)" v-hasPermi="['monitor:job:query']"></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改定时任务对话框 -->
|
||||
<el-dialog :title="title" v-model="open" width="820px" append-to-body>
|
||||
<el-form ref="jobRef" :model="form" :rules="rules" label-width="120px">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="任务名称" prop="jobName">
|
||||
<el-input v-model="form.jobName" placeholder="请输入任务名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="任务分组" prop="jobGroup">
|
||||
<el-select v-model="form.jobGroup" placeholder="请选择">
|
||||
<el-option
|
||||
v-for="dict in sys_job_group"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item prop="invokeTarget">
|
||||
<template #label>
|
||||
<span>
|
||||
调用方法
|
||||
<el-tooltip placement="top">
|
||||
<template #content>
|
||||
<div>
|
||||
Bean调用示例:ryTask.ryParams('ry')
|
||||
<br />Class类调用示例:com.ruoyi.quartz.task.RyTask.ryParams('ry')
|
||||
<br />参数说明:支持字符串,布尔类型,长整型,浮点型,整型
|
||||
</div>
|
||||
</template>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
<el-input v-model="form.invokeTarget" placeholder="请输入调用目标字符串" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="cron表达式" prop="cronExpression">
|
||||
<el-input v-model="form.cronExpression" placeholder="请输入cron执行表达式">
|
||||
<template #append>
|
||||
<el-button type="primary" @click="handleShowCron">
|
||||
生成表达式
|
||||
<i class="el-icon-time el-icon--right"></i>
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24" v-if="form.jobId !== undefined">
|
||||
<el-form-item label="状态">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio
|
||||
v-for="dict in sys_job_status"
|
||||
:key="dict.value"
|
||||
:value="dict.value"
|
||||
>{{ dict.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="执行策略" prop="misfirePolicy">
|
||||
<el-radio-group v-model="form.misfirePolicy">
|
||||
<el-radio-button value="1">立即执行</el-radio-button>
|
||||
<el-radio-button value="2">执行一次</el-radio-button>
|
||||
<el-radio-button value="3">放弃执行</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否并发" prop="concurrent">
|
||||
<el-radio-group v-model="form.concurrent">
|
||||
<el-radio-button value="0">允许</el-radio-button>
|
||||
<el-radio-button value="1">禁止</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="Cron表达式生成器" v-model="openCron" append-to-body destroy-on-close>
|
||||
<crontab ref="crontabRef" @hide="openCron=false" @fill="crontabFill" :expression="expression"></crontab>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 任务日志详细 -->
|
||||
<el-dialog title="任务详细" v-model="openView" width="700px" append-to-body>
|
||||
<el-form :model="form" label-width="120px">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="任务编号:">{{ form.jobId }}</el-form-item>
|
||||
<el-form-item label="任务名称:">{{ form.jobName }}</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="任务分组:">{{ jobGroupFormat(form) }}</el-form-item>
|
||||
<el-form-item label="创建时间:">{{ form.createTime }}</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="cron表达式:">{{ form.cronExpression }}</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="下次执行时间:">{{ parseTime(form.nextValidTime) }}</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="调用目标方法:">{{ form.invokeTarget }}</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="任务状态:">
|
||||
<div v-if="form.status == 0">正常</div>
|
||||
<div v-else-if="form.status == 1">暂停</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否并发:">
|
||||
<div v-if="form.concurrent == 0">允许</div>
|
||||
<div v-else-if="form.concurrent == 1">禁止</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="执行策略:">
|
||||
<div v-if="form.misfirePolicy == 0">默认策略</div>
|
||||
<div v-else-if="form.misfirePolicy == 1">立即执行</div>
|
||||
<div v-else-if="form.misfirePolicy == 2">执行一次</div>
|
||||
<div v-else-if="form.misfirePolicy == 3">放弃执行</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="openView = false">关 闭</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Job">
|
||||
import Crontab from '@/components/Crontab'
|
||||
import { listJob, getJob, delJob, addJob, updateJob, runJob, changeJobStatus } from "@/api/monitor/job"
|
||||
import {
|
||||
listJob,
|
||||
getJob,
|
||||
delJob,
|
||||
addJob,
|
||||
updateJob,
|
||||
runJob,
|
||||
changeJobStatus,
|
||||
} from '@/api/monitor/job'
|
||||
|
||||
const router = useRouter()
|
||||
const { proxy } = getCurrentInstance()
|
||||
const { sys_job_group, sys_job_status } = proxy.useDict("sys_job_group", "sys_job_status")
|
||||
const { sys_job_group, sys_job_status } = proxy.useDict('sys_job_group', 'sys_job_status')
|
||||
|
||||
const jobList = ref([])
|
||||
const open = ref(false)
|
||||
|
|
@ -300,202 +387,218 @@ const ids = ref([])
|
|||
const single = ref(true)
|
||||
const multiple = ref(true)
|
||||
const total = ref(0)
|
||||
const title = ref("")
|
||||
const title = ref('')
|
||||
const openView = ref(false)
|
||||
const openCron = ref(false)
|
||||
const expression = ref("")
|
||||
const expression = ref('')
|
||||
|
||||
const data = reactive({
|
||||
form: {},
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
jobName: undefined,
|
||||
jobGroup: undefined,
|
||||
status: undefined
|
||||
},
|
||||
rules: {
|
||||
jobName: [{ required: true, message: "任务名称不能为空", trigger: "blur" }],
|
||||
invokeTarget: [{ required: true, message: "调用目标字符串不能为空", trigger: "blur" }],
|
||||
cronExpression: [{ required: true, message: "cron执行表达式不能为空", trigger: "change" }]
|
||||
}
|
||||
form: {},
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
jobName: undefined,
|
||||
jobGroup: undefined,
|
||||
status: undefined,
|
||||
},
|
||||
rules: {
|
||||
jobName: [{ required: true, message: '任务名称不能为空', trigger: 'blur' }],
|
||||
invokeTarget: [{ required: true, message: '调用目标字符串不能为空', trigger: 'blur' }],
|
||||
cronExpression: [{ required: true, message: 'cron执行表达式不能为空', trigger: 'change' }],
|
||||
},
|
||||
})
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data)
|
||||
|
||||
/** 查询定时任务列表 */
|
||||
function getList() {
|
||||
loading.value = true
|
||||
listJob(queryParams.value).then(response => {
|
||||
jobList.value = response.rows
|
||||
total.value = response.total
|
||||
loading.value = false
|
||||
})
|
||||
loading.value = true
|
||||
listJob(queryParams.value).then((response) => {
|
||||
jobList.value = response.rows
|
||||
total.value = response.total
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
/** 任务组名字典翻译 */
|
||||
function jobGroupFormat(row, column) {
|
||||
return proxy.selectDictLabel(sys_job_group.value, row.jobGroup)
|
||||
return proxy.selectDictLabel(sys_job_group.value, row.jobGroup)
|
||||
}
|
||||
|
||||
/** 取消按钮 */
|
||||
function cancel() {
|
||||
open.value = false
|
||||
reset()
|
||||
open.value = false
|
||||
reset()
|
||||
}
|
||||
|
||||
/** 表单重置 */
|
||||
function reset() {
|
||||
form.value = {
|
||||
jobId: undefined,
|
||||
jobName: undefined,
|
||||
jobGroup: undefined,
|
||||
invokeTarget: undefined,
|
||||
cronExpression: undefined,
|
||||
misfirePolicy: 1,
|
||||
concurrent: 1,
|
||||
status: "0"
|
||||
}
|
||||
proxy.resetForm("jobRef")
|
||||
form.value = {
|
||||
jobId: undefined,
|
||||
jobName: undefined,
|
||||
jobGroup: undefined,
|
||||
invokeTarget: undefined,
|
||||
cronExpression: undefined,
|
||||
misfirePolicy: 1,
|
||||
concurrent: 1,
|
||||
status: '0',
|
||||
}
|
||||
proxy.resetForm('jobRef')
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
function handleQuery() {
|
||||
queryParams.value.pageNum = 1
|
||||
getList()
|
||||
queryParams.value.pageNum = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
/** 重置按钮操作 */
|
||||
function resetQuery() {
|
||||
proxy.resetForm("queryRef")
|
||||
handleQuery()
|
||||
proxy.resetForm('queryRef')
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
// 多选框选中数据
|
||||
function handleSelectionChange(selection) {
|
||||
ids.value = selection.map(item => item.jobId)
|
||||
single.value = selection.length != 1
|
||||
multiple.value = !selection.length
|
||||
ids.value = selection.map((item) => item.jobId)
|
||||
single.value = selection.length != 1
|
||||
multiple.value = !selection.length
|
||||
}
|
||||
|
||||
// 更多操作触发
|
||||
function handleCommand(command, row) {
|
||||
switch (command) {
|
||||
case "handleRun":
|
||||
handleRun(row)
|
||||
break
|
||||
case "handleView":
|
||||
handleView(row)
|
||||
break
|
||||
case "handleJobLog":
|
||||
handleJobLog(row)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
switch (command) {
|
||||
case 'handleRun':
|
||||
handleRun(row)
|
||||
break
|
||||
case 'handleView':
|
||||
handleView(row)
|
||||
break
|
||||
case 'handleJobLog':
|
||||
handleJobLog(row)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 任务状态修改
|
||||
function handleStatusChange(row) {
|
||||
let text = row.status === "0" ? "启用" : "停用"
|
||||
proxy.$modal.confirm('确认要"' + text + '""' + row.jobName + '"任务吗?').then(function () {
|
||||
return changeJobStatus(row.jobId, row.status)
|
||||
}).then(() => {
|
||||
proxy.$modal.msgSuccess(text + "成功")
|
||||
}).catch(function () {
|
||||
row.status = row.status === "0" ? "1" : "0"
|
||||
})
|
||||
let text = row.status === '0' ? '启用' : '停用'
|
||||
proxy.$modal
|
||||
.confirm('确认要"' + text + '""' + row.jobName + '"任务吗?')
|
||||
.then(function () {
|
||||
return changeJobStatus(row.jobId, row.status)
|
||||
})
|
||||
.then(() => {
|
||||
proxy.$modal.msgSuccess(text + '成功')
|
||||
})
|
||||
.catch(function () {
|
||||
row.status = row.status === '0' ? '1' : '0'
|
||||
})
|
||||
}
|
||||
|
||||
/* 立即执行一次 */
|
||||
function handleRun(row) {
|
||||
proxy.$modal.confirm('确认要立即执行一次"' + row.jobName + '"任务吗?').then(function () {
|
||||
return runJob(row.jobId, row.jobGroup)
|
||||
}).then(() => {
|
||||
proxy.$modal.msgSuccess("执行成功")})
|
||||
.catch(() => {})
|
||||
proxy.$modal
|
||||
.confirm('确认要立即执行一次"' + row.jobName + '"任务吗?')
|
||||
.then(function () {
|
||||
return runJob(row.jobId, row.jobGroup)
|
||||
})
|
||||
.then(() => {
|
||||
proxy.$modal.msgSuccess('执行成功')
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
/** 任务详细信息 */
|
||||
function handleView(row) {
|
||||
getJob(row.jobId).then(response => {
|
||||
form.value = response.data
|
||||
openView.value = true
|
||||
})
|
||||
getJob(row.jobId).then((response) => {
|
||||
form.value = response.data
|
||||
openView.value = true
|
||||
})
|
||||
}
|
||||
|
||||
/** cron表达式按钮操作 */
|
||||
function handleShowCron() {
|
||||
expression.value = form.value.cronExpression
|
||||
openCron.value = true
|
||||
expression.value = form.value.cronExpression
|
||||
openCron.value = true
|
||||
}
|
||||
|
||||
/** 确定后回传值 */
|
||||
function crontabFill(value) {
|
||||
form.value.cronExpression = value
|
||||
form.value.cronExpression = value
|
||||
}
|
||||
|
||||
/** 任务日志列表查询 */
|
||||
function handleJobLog(row) {
|
||||
const jobId = row.jobId || 0
|
||||
router.push('/monitor/job-log/index/' + jobId)
|
||||
const jobId = row.jobId || 0
|
||||
router.push('/monitor/job-log/index/' + jobId)
|
||||
}
|
||||
|
||||
/** 新增按钮操作 */
|
||||
function handleAdd() {
|
||||
reset()
|
||||
open.value = true
|
||||
title.value = "添加任务"
|
||||
reset()
|
||||
open.value = true
|
||||
title.value = '添加任务'
|
||||
}
|
||||
|
||||
/** 修改按钮操作 */
|
||||
function handleUpdate(row) {
|
||||
reset()
|
||||
const jobId = row.jobId || ids.value
|
||||
getJob(jobId).then(response => {
|
||||
form.value = response.data
|
||||
open.value = true
|
||||
title.value = "修改任务"
|
||||
})
|
||||
reset()
|
||||
const jobId = row.jobId || ids.value
|
||||
getJob(jobId).then((response) => {
|
||||
form.value = response.data
|
||||
open.value = true
|
||||
title.value = '修改任务'
|
||||
})
|
||||
}
|
||||
|
||||
/** 提交按钮 */
|
||||
function submitForm() {
|
||||
proxy.$refs["jobRef"].validate(valid => {
|
||||
if (valid) {
|
||||
if (form.value.jobId != undefined) {
|
||||
updateJob(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("修改成功")
|
||||
open.value = false
|
||||
getList()
|
||||
})
|
||||
} else {
|
||||
addJob(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("新增成功")
|
||||
open.value = false
|
||||
getList()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
proxy.$refs['jobRef'].validate((valid) => {
|
||||
if (valid) {
|
||||
if (form.value.jobId != undefined) {
|
||||
updateJob(form.value).then((response) => {
|
||||
proxy.$modal.msgSuccess('修改成功')
|
||||
open.value = false
|
||||
getList()
|
||||
})
|
||||
} else {
|
||||
addJob(form.value).then((response) => {
|
||||
proxy.$modal.msgSuccess('新增成功')
|
||||
open.value = false
|
||||
getList()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
function handleDelete(row) {
|
||||
const jobIds = row.jobId || ids.value
|
||||
proxy.$modal.confirm('是否确认删除定时任务编号为"' + jobIds + '"的数据项?').then(function () {
|
||||
return delJob(jobIds)
|
||||
}).then(() => {
|
||||
getList()
|
||||
proxy.$modal.msgSuccess("删除成功")
|
||||
}).catch(() => {})
|
||||
const jobIds = row.jobId || ids.value
|
||||
proxy.$modal
|
||||
.confirm('是否确认删除定时任务编号为"' + jobIds + '"的数据项?')
|
||||
.then(function () {
|
||||
return delJob(jobIds)
|
||||
})
|
||||
.then(() => {
|
||||
getList()
|
||||
proxy.$modal.msgSuccess('删除成功')
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
/** 导出按钮操作 */
|
||||
function handleExport() {
|
||||
proxy.download("monitor/job/export", {
|
||||
...queryParams.value,
|
||||
}, `job_${new Date().getTime()}.xlsx`)
|
||||
proxy.download(
|
||||
'monitor/job/export',
|
||||
{
|
||||
...queryParams.value,
|
||||
},
|
||||
`job_${new Date().getTime()}.xlsx`,
|
||||
)
|
||||
}
|
||||
|
||||
getList()
|
||||
|
|
|
|||
|
|
@ -1,59 +1,75 @@
|
|||
<template>
|
||||
<div class="monthly-add-form">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
size="large"
|
||||
class="month-form"
|
||||
>
|
||||
<el-row :gutter="12" align="middle">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="计划执行月份" prop="month">
|
||||
<el-date-picker
|
||||
v-model="formData.month"
|
||||
type="month"
|
||||
value-format="YYYY-MM"
|
||||
placeholder="请选择月份"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<el-form-item prop="keyword" class="keyword-item">
|
||||
<el-input
|
||||
placeholder="输入关键字"
|
||||
clearable
|
||||
v-model.trim="formData.keyword"
|
||||
@keyup.enter="onSearch"
|
||||
style="width: 240px"
|
||||
<!-- 表单区域 -->
|
||||
<div class="form-section">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-width="140px"
|
||||
size="default"
|
||||
class="month-form"
|
||||
>
|
||||
<template #suffix>
|
||||
<el-icon @click="onSearch" style="cursor: pointer">
|
||||
<Search />
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="月计划执行月份:" prop="month" class="month-item">
|
||||
<el-date-picker
|
||||
v-model="formData.month"
|
||||
type="month"
|
||||
value-format="YYYY-MM"
|
||||
placeholder="xxxx-xx"
|
||||
style="width: 200px"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 搜索区域 -->
|
||||
<div class="search-section">
|
||||
<el-input
|
||||
v-model.trim="formData.keyword"
|
||||
placeholder="输入关键字"
|
||||
clearable
|
||||
@keyup.enter="onSearch"
|
||||
class="search-input"
|
||||
>
|
||||
<template #prefix>
|
||||
<el-icon class="search-icon" @click="onSearch">
|
||||
<Search />
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 任务列表 -->
|
||||
<el-table
|
||||
border
|
||||
:data="tableData"
|
||||
v-loading="loading"
|
||||
@selection-change="onSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column align="center" prop="projectName" label="项目名称" min-width="260" />
|
||||
<el-table-column align="center" prop="workTask" label="工作任务" min-width="360" />
|
||||
</el-table>
|
||||
<div class="table-section">
|
||||
<el-table
|
||||
:data="tableData"
|
||||
v-loading="loading"
|
||||
@selection-change="onSelectionChange"
|
||||
class="task-table"
|
||||
stripe
|
||||
:header-cell-style="{ background: '#f5f7fa', color: '#606266', fontWeight: 600 }"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="项目名称"
|
||||
min-width="260"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="workTask"
|
||||
label="工作任务"
|
||||
min-width="360"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="MonthlyPlanAddForm">
|
||||
import { ref, watch, getCurrentInstance } from 'vue'
|
||||
import { ref, watch, getCurrentInstance, reactive } from 'vue'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
|
||||
const props = defineProps({
|
||||
|
|
@ -73,7 +89,10 @@ const { proxy } = getCurrentInstance()
|
|||
|
||||
const formRef = ref(null)
|
||||
const loading = ref(false)
|
||||
const tableData = ref([])
|
||||
const tableData = ref([
|
||||
{ name: '项目1', workTask: '工作任务1' },
|
||||
{ name: '项目2', workTask: '工作任务2' },
|
||||
])
|
||||
const selectedRows = ref([])
|
||||
|
||||
const formData = ref({
|
||||
|
|
@ -126,18 +145,116 @@ watch(
|
|||
defineExpose({
|
||||
getSelectedTasks: () => selectedRows.value,
|
||||
search: fetchData,
|
||||
validate: () => formRef.value.validate(),
|
||||
validate: async () => {
|
||||
await formRef.value.validate()
|
||||
if (selectedRows.value.length === 0) {
|
||||
proxy.$modal.msgError('请选择项目')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.monthly-add-form {
|
||||
.month-form {
|
||||
margin-bottom: 12px;
|
||||
padding: 0;
|
||||
|
||||
.form-section {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.month-form {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.month-item {
|
||||
margin-bottom: 0;
|
||||
|
||||
:deep(.el-form-item__label) {
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
|
||||
&::before {
|
||||
content: '*';
|
||||
color: #f56c6c;
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-form-item__content) {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-section {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
margin-top: 16px;
|
||||
|
||||
.search-input {
|
||||
width: 300px;
|
||||
|
||||
:deep(.el-input__wrapper) {
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 0 1px #dcdfe6 inset;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 0 0 1px #c0c4cc inset;
|
||||
}
|
||||
|
||||
&.is-focus {
|
||||
box-shadow: 0 0 0 1px #409eff inset;
|
||||
}
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
color: #909399;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.keyword-item :deep(.el-form-item__content) {
|
||||
justify-content: flex-end;
|
||||
.table-section {
|
||||
.task-table {
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
|
||||
:deep(.el-table__header) {
|
||||
th {
|
||||
padding: 12px 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-table__body) {
|
||||
td {
|
||||
padding: 12px 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
tr {
|
||||
&:hover {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-checkbox) {
|
||||
.el-checkbox__input.is-checked .el-checkbox__inner {
|
||||
background-color: #409eff;
|
||||
border-color: #409eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -12,29 +12,18 @@
|
|||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
label-width="180"
|
||||
size="large"
|
||||
:disabled="isDetail"
|
||||
>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="运检站" prop="stationId">
|
||||
<el-select
|
||||
v-model="formData.stationId"
|
||||
placeholder="请选择运检站"
|
||||
clearable
|
||||
filterable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in stationOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="运检站">
|
||||
<el-input v-model="formData.stationName" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="专业" prop="majorId">
|
||||
<el-select
|
||||
v-model="formData.majorId"
|
||||
|
|
@ -42,16 +31,18 @@
|
|||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in majorOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
v-for="item in majorOptions"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="业务类型" prop="businessTypeId">
|
||||
<el-select
|
||||
v-model="formData.businessTypeId"
|
||||
|
|
@ -67,28 +58,38 @@
|
|||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="项目名称" prop="projectName">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目名称">
|
||||
<el-input
|
||||
v-model.trim="formData.projectName"
|
||||
placeholder="请输入项目名称"
|
||||
maxlength="50"
|
||||
show-word-limit
|
||||
clearable
|
||||
disabled
|
||||
placeholder="请输入项目名称"
|
||||
v-model.trim="formData.projectName"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="风险等级" prop="riskLevel">
|
||||
<el-select
|
||||
v-model="formData.riskLevel"
|
||||
placeholder="请选择风险等级"
|
||||
clearable
|
||||
>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="工作任务">
|
||||
<el-input
|
||||
type="textarea"
|
||||
v-model.trim="formData.workContent"
|
||||
placeholder="请输入作业内容"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
disabled
|
||||
:autosize="{ minRows: 4, maxRows: 12 }"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="类别" prop="typeId">
|
||||
<el-select v-model="formData.typeId" placeholder="请选择类别" clearable>
|
||||
<el-option
|
||||
v-for="item in riskLevelOptions"
|
||||
:key="item.value"
|
||||
|
|
@ -98,34 +99,70 @@
|
|||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="计划执行月份" prop="month">
|
||||
<el-date-picker
|
||||
v-model="formData.month"
|
||||
type="month"
|
||||
value-format="YYYY-MM"
|
||||
placeholder="请选择月份"
|
||||
style="width: 100%"
|
||||
<el-row :gutter="24">
|
||||
<template v-for="(item, index) in formData.workLoadList" :key="index">
|
||||
<el-col :span="8">
|
||||
<el-form-item :label="index == 0 ? '工作量' : ''" prop="workType">
|
||||
<el-select
|
||||
clearable
|
||||
v-model="item.workType"
|
||||
placeholder="请选择工作量类别"
|
||||
>
|
||||
<el-option
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
v-for="item in riskLevelOptions"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-form-item label-width="0" prop="count">
|
||||
<el-input
|
||||
v-model="item.count"
|
||||
style="width: 240px"
|
||||
placeholder="输入数量"
|
||||
>
|
||||
<template #suffix>
|
||||
<el-button
|
||||
type="success"
|
||||
icon="Plus"
|
||||
size="small"
|
||||
v-if="index === 0 && !isDetail"
|
||||
@click="onAddWorkLoad"
|
||||
/>
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="Delete"
|
||||
size="small"
|
||||
v-if="index !== 0 && !isDetail"
|
||||
@click="onDeleteWorkLoad(index)"
|
||||
/>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</template>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="塔基数" prop="towerCount">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入塔基数量"
|
||||
v-model.trim="formData.towerCount"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item label="作业任务" prop="workContent">
|
||||
<el-input
|
||||
type="textarea"
|
||||
v-model.trim="formData.workContent"
|
||||
placeholder="请输入作业内容"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
:autosize="{ minRows: 3, maxRows: 6 }"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="计划开始时间" prop="planStartDate">
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="计划开始时间">
|
||||
<el-date-picker
|
||||
v-model="formData.planStartDate"
|
||||
type="date"
|
||||
|
|
@ -135,8 +172,8 @@
|
|||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="计划结束时间" prop="planEndDate">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="计划结束时间">
|
||||
<el-date-picker
|
||||
v-model="formData.planEndDate"
|
||||
type="date"
|
||||
|
|
@ -148,42 +185,293 @@
|
|||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
type="textarea"
|
||||
v-model.trim="formData.remark"
|
||||
placeholder="请输入备注"
|
||||
maxlength="200"
|
||||
show-word-limit
|
||||
:autosize="{ minRows: 3, maxRows: 6 }"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="计划投入管理人员" prop="planManagers">
|
||||
<el-input
|
||||
v-model="selectedManagerNames"
|
||||
readonly
|
||||
placeholder="点击选择管理人员"
|
||||
@click="onOpenPersonPicker"
|
||||
>
|
||||
<template #suffix>
|
||||
<el-icon
|
||||
class="clickable-suffix"
|
||||
@click.stop="onOpenPersonPicker"
|
||||
>
|
||||
<Search />
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="计划投入车辆数量" prop="planVehicleCount">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入车辆数量"
|
||||
v-model.trim="formData.planVehicleCount"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="7">
|
||||
<el-form-item label="计划投入熟练工人数" prop="skilledStaffCount">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入熟练工人数"
|
||||
v-model.trim="formData.skilledStaffCount"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<el-form-item
|
||||
label="计划投入工日"
|
||||
prop="skilledWorkDays"
|
||||
label-width="auto"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入熟练工工日"
|
||||
v-model.trim="formData.skilledWorkDays"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="7">
|
||||
<el-form-item label="计划投入辅助工人数" prop="assistantStaffCount">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入辅助工人数"
|
||||
v-model.trim="formData.assistantStaffCount"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<el-form-item
|
||||
label="计划投入工日"
|
||||
prop="assistantWorkDays"
|
||||
label-width="auto"
|
||||
>
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入辅助工工日"
|
||||
v-model.trim="formData.assistantWorkDays"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="计划投入分包车辆" prop="subcontractVehicleCount">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入分包车辆数量"
|
||||
v-model.trim="formData.subcontractVehicleCount"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="实际工作天数">
|
||||
<el-input
|
||||
clearable
|
||||
placeholder="请输入实际工作天数"
|
||||
v-model.trim="formData.actualWorkDays"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 人员排班区域:先留出结构,后续可按业务补充 -->
|
||||
<!-- 人员排班区域 -->
|
||||
<el-card shadow="never" class="card-section">
|
||||
<template #header>
|
||||
<div class="card-header">人员排班</div>
|
||||
</template>
|
||||
<div class="calendar-placeholder">
|
||||
<span>这里展示月份日历和每日人员排班(待与后端字段对接后完善)</span>
|
||||
<div class="schedule-wrapper">
|
||||
<div class="schedule-tip">
|
||||
<span class="schedule-tip-extra">
|
||||
仅在“计划开始时间 ~
|
||||
计划结束时间”范围内可排班;表单中的“计划投入管理人员”只是模板,不会被日历上的增删影响。
|
||||
</span>
|
||||
</div>
|
||||
<div class="schedule-grid">
|
||||
<div
|
||||
v-for="day in calendarDays"
|
||||
:key="day.date"
|
||||
class="schedule-cell"
|
||||
:class="{ 'is-disabled': !day.isInRange }"
|
||||
>
|
||||
<div class="cell-date">{{ day.label }}</div>
|
||||
<div class="cell-persons">
|
||||
<template v-if="day.managers && day.managers.length">
|
||||
<el-popover
|
||||
v-if="day.managers.length > maxShowInCell"
|
||||
placement="top"
|
||||
trigger="hover"
|
||||
>
|
||||
<template #reference>
|
||||
<div class="person-tags">
|
||||
<el-tag
|
||||
size="small"
|
||||
v-for="person in day.managers.slice(
|
||||
0,
|
||||
maxShowInCell,
|
||||
)"
|
||||
:key="person.id"
|
||||
closable
|
||||
@close.stop="
|
||||
onRemovePersonFromDay(day.date, person)
|
||||
"
|
||||
>
|
||||
{{ person.name }}
|
||||
</el-tag>
|
||||
<span class="more-text">
|
||||
+{{ day.managers.length - maxShowInCell }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="popover-list">
|
||||
<el-tag
|
||||
v-for="person in day.managers"
|
||||
:key="person.id"
|
||||
size="small"
|
||||
closable
|
||||
@close.stop="onRemovePersonFromDay(day.date, person)"
|
||||
>
|
||||
{{ person.name }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</el-popover>
|
||||
<template v-else>
|
||||
<div class="person-tags">
|
||||
<el-tag
|
||||
size="small"
|
||||
v-for="person in day.managers"
|
||||
:key="person.id"
|
||||
closable
|
||||
@close.stop="onRemovePersonFromDay(day.date, person)"
|
||||
>
|
||||
{{ person.name }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<span
|
||||
v-else
|
||||
class="empty-tip-small"
|
||||
:class="{ 'is-disabled-text': !day.isInRange }"
|
||||
>
|
||||
{{ day.isInRange ? '未安排人员' : '不可排班' }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="cell-actions" v-if="!isDetail">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
plain
|
||||
:disabled="!day.isInRange || !formData.planManagers.length"
|
||||
@click="onFillManagersForDay(day.date)"
|
||||
>
|
||||
安排人员
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
plain
|
||||
:disabled="!day.isInRange || !day.managers.length"
|
||||
@click="onClearManagersForDay(day.date)"
|
||||
>
|
||||
清除
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 底部操作按钮(详情模式下隐藏) -->
|
||||
<div v-if="!isDetail" class="page-footer">
|
||||
<ComButton plain type="info" @click="onBack">取消</ComButton>
|
||||
<ComButton type="primary" @click="onSubmit">保存</ComButton>
|
||||
<div class="page-footer">
|
||||
<ComButton plain type="info" @click="onBack">
|
||||
{{ isDetail ? '返回' : '取消' }}
|
||||
</ComButton>
|
||||
<ComButton v-if="!isDetail" type="primary" @click="onSubmit">保存</ComButton>
|
||||
</div>
|
||||
|
||||
<!-- 人员选择弹窗(使用封装的 ComDialog) -->
|
||||
<ComDialog :dialog-config="managerDialogConfig" @closeDialogOuter="onCloseDialogOuter">
|
||||
<template #outerContent>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="16">
|
||||
<div class="person-search-bar">
|
||||
<el-input
|
||||
v-model.trim="managerDialog.keyword"
|
||||
placeholder="输入姓名搜索"
|
||||
clearable
|
||||
prefix-icon="Search"
|
||||
/>
|
||||
</div>
|
||||
<el-table
|
||||
ref="personTableRef"
|
||||
:data="filteredPersons"
|
||||
height="400px"
|
||||
@selection-change="onManagerSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="50" />
|
||||
<el-table-column prop="org" label="人员所属单位" width="140" />
|
||||
<el-table-column prop="name" label="姓名" width="120" />
|
||||
<el-table-column prop="gender" label="性别" width="80" />
|
||||
<el-table-column prop="station" label="岗位" width="140" />
|
||||
<el-table-column prop="position" label="岗位性质" width="140" />
|
||||
<el-table-column prop="type" label="人员分类" />
|
||||
</el-table>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="selected-panel">
|
||||
<div class="panel-header">
|
||||
<span>已选人员</span>
|
||||
<el-button type="text" @click="onClearManagers">清空</el-button>
|
||||
</div>
|
||||
<div class="selected-list">
|
||||
<div>
|
||||
<el-tag
|
||||
closable
|
||||
:key="item.id"
|
||||
class="selected-tag"
|
||||
@close="onRemoveManager(item)"
|
||||
v-for="item in managerDialog.selected"
|
||||
>
|
||||
{{ item.name }}
|
||||
</el-tag>
|
||||
</div>
|
||||
|
||||
<div v-if="!managerDialog.selected.length" class="empty-tip">
|
||||
暂未选择人员
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row class="common-btn-row" justify="end" style="margin-top: 16px">
|
||||
<ComButton plain type="info" @click="managerDialog.visible = false">
|
||||
取消
|
||||
</ComButton>
|
||||
<ComButton type="primary" @click="onConfirmManager">确定</ComButton>
|
||||
</el-row>
|
||||
</template>
|
||||
</ComDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="MonthlyPlanEdit">
|
||||
import { ref, computed, getCurrentInstance } from 'vue'
|
||||
import { ref, reactive, computed, getCurrentInstance, nextTick } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { addPlanAPI, updatePlanAPI } from '@/api/planMange/plan.js'
|
||||
import ComButton from '@/components/ComButton/index.vue'
|
||||
import ComDialog from '@/components/ComDialog/index.vue'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
|
@ -202,16 +490,34 @@ const formRef = ref(null)
|
|||
|
||||
const getInitFormData = () => ({
|
||||
planId: null,
|
||||
stationId: null,
|
||||
stationName: '测试运检站1',
|
||||
majorId: null,
|
||||
businessTypeId: null,
|
||||
projectName: '',
|
||||
workContent: '',
|
||||
projectName: '测试项目123',
|
||||
workContent:
|
||||
'工作内容非常多工作内容非常多···工作内容非常多···工作内容非常多···工作内容非常多···工作内容非常多···工作内容非常多······--',
|
||||
riskLevel: null,
|
||||
month: '',
|
||||
planStartDate: '',
|
||||
planEndDate: '',
|
||||
remark: '',
|
||||
// 默认演示:2025 年 12 月
|
||||
month: '2025-12',
|
||||
planStartDate: '2025-12-06',
|
||||
planEndDate: '2025-12-30',
|
||||
typeId: null,
|
||||
towerCount: '',
|
||||
planManagers: [],
|
||||
planVehicleCount: '',
|
||||
skilledStaffCount: '',
|
||||
skilledWorkDays: '',
|
||||
assistantStaffCount: '',
|
||||
assistantWorkDays: '',
|
||||
subcontractVehicleCount: '',
|
||||
actualWorkDays: '',
|
||||
|
||||
workLoadList: [
|
||||
{
|
||||
workType: '',
|
||||
count: '',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const formData = ref(getInitFormData())
|
||||
|
|
@ -239,15 +545,21 @@ const riskLevelOptions = [
|
|||
]
|
||||
|
||||
const rules = {
|
||||
stationId: [{ required: true, message: '请选择运检站', trigger: 'change' }],
|
||||
majorId: [{ required: true, message: '请选择专业', trigger: 'change' }],
|
||||
businessTypeId: [{ required: true, message: '请选择业务类型', trigger: 'change' }],
|
||||
projectName: [{ required: true, message: '请输入项目名称', trigger: 'blur' }],
|
||||
workContent: [{ required: true, message: '请输入作业内容', trigger: 'blur' }],
|
||||
riskLevel: [{ required: true, message: '请选择风险等级', trigger: 'change' }],
|
||||
month: [{ required: true, message: '请选择计划执行月份', trigger: 'change' }],
|
||||
planStartDate: [{ required: true, message: '请选择计划开始时间', trigger: 'change' }],
|
||||
planEndDate: [{ required: true, message: '请选择计划结束时间', trigger: 'change' }],
|
||||
typeId: [{ required: true, message: '请输选择类别', trigger: 'change' }],
|
||||
workType: [{ required: true, message: '请选择计工作量类别', trigger: 'change' }],
|
||||
count: [{ required: true, message: '请输入数量', trigger: 'blur' }],
|
||||
towerCount: [{ required: true, message: '请输入塔基数量', trigger: 'blur' }],
|
||||
planManagers: [{ required: true, message: '请选择计划投入管理人员', trigger: 'blur' }],
|
||||
planVehicleCount: [{ required: true, message: '请输入计划投入车数量', trigger: 'blur' }],
|
||||
skilledStaffCount: [{ required: true, message: '请输入计划投入熟练工人数', trigger: 'blur' }],
|
||||
skilledWorkDays: [{ required: true, message: '请输入计划投入工日', trigger: 'blur' }],
|
||||
assistantStaffCount: [{ required: true, message: '请输入计划投入辅助工人数', trigger: 'blur' }],
|
||||
subcontractVehicleCount: [
|
||||
{ required: true, message: '请输入计划投入分包车辆数量', trigger: 'blur' },
|
||||
],
|
||||
assistantWorkDays: [{ required: true, message: '请输入辅助工工日', trigger: 'blur' }],
|
||||
}
|
||||
|
||||
const onBack = () => {
|
||||
|
|
@ -255,21 +567,238 @@ const onBack = () => {
|
|||
}
|
||||
|
||||
const onSubmit = () => {
|
||||
formRef.value.validate(async (valid) => {
|
||||
if (!valid) return
|
||||
const API = mode.value === 'edit' ? updatePlanAPI : addPlanAPI
|
||||
const payload = { ...formData.value }
|
||||
try {
|
||||
const res = await API(payload)
|
||||
if (res.code === 200) {
|
||||
proxy.$modal.msgSuccess(mode.value === 'edit' ? '编辑成功' : '新增成功')
|
||||
onBack()
|
||||
formRef.value.validate(async (valid, fields) => {
|
||||
if (!valid) {
|
||||
// 表单校验未通过时,自动滚动到第一个报错字段
|
||||
if (fields && Object.keys(fields).length) {
|
||||
const firstProp = Object.keys(fields)[0]
|
||||
formRef.value.scrollToField(firstProp)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存月计划失败:', error)
|
||||
return
|
||||
}
|
||||
|
||||
// 组装参数
|
||||
|
||||
// const API = mode.value === 'edit' ? updatePlanAPI : addPlanAPI
|
||||
// const payload = { ...formData.value }
|
||||
// try {
|
||||
// const res = await API(payload)
|
||||
// if (res.code === 200) {
|
||||
// proxy.$modal.msgSuccess(mode.value === 'edit' ? '编辑成功' : '新增成功')
|
||||
// onBack()
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error('保存月计划失败:', error)
|
||||
// }
|
||||
})
|
||||
}
|
||||
|
||||
const onAddWorkLoad = () => {
|
||||
formData.value.workLoadList.push({
|
||||
workType: '',
|
||||
count: '',
|
||||
})
|
||||
}
|
||||
|
||||
const onDeleteWorkLoad = (index) => {
|
||||
formData.value.workLoadList.splice(index, 1)
|
||||
}
|
||||
|
||||
// 人员选择弹窗相关
|
||||
const personTableRef = ref(null)
|
||||
const managerDialogConfig = reactive({
|
||||
outerVisible: false,
|
||||
outerTitle: '选择人员',
|
||||
outerWidth: '70%',
|
||||
minHeight: '60vh',
|
||||
maxHeight: '80vh',
|
||||
})
|
||||
|
||||
const managerDialog = reactive({
|
||||
visible: false,
|
||||
keyword: '',
|
||||
selected: [],
|
||||
data: [
|
||||
{
|
||||
id: 1,
|
||||
org: '昆明运检站',
|
||||
name: '张三',
|
||||
gender: '男',
|
||||
station: '站长',
|
||||
position: '全职',
|
||||
type: '运检人员',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
org: '昆明运检站',
|
||||
name: '李四钱七',
|
||||
gender: '男',
|
||||
station: '副站长',
|
||||
position: '全职',
|
||||
type: '运检人员',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
org: '昆明运检站',
|
||||
name: '王五',
|
||||
gender: '男',
|
||||
station: '安全员',
|
||||
position: '全职',
|
||||
type: '运检人员',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
org: '大理运检站',
|
||||
name: '赵六钱七',
|
||||
gender: '女',
|
||||
station: '文员',
|
||||
position: '派遣',
|
||||
type: '后勤人员',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
org: '大理运检站',
|
||||
name: '钱七',
|
||||
gender: '男',
|
||||
station: '驾驶员',
|
||||
position: '派遣',
|
||||
type: '运检人员',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
org: '大理运检站',
|
||||
name: '钱七钱七',
|
||||
gender: '男',
|
||||
station: '驾驶员',
|
||||
position: '派遣',
|
||||
type: '运检人员',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
org: '大理运检站',
|
||||
name: '钱七',
|
||||
gender: '男',
|
||||
station: '驾驶员',
|
||||
position: '派遣',
|
||||
type: '运检人员',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const filteredPersons = computed(() => {
|
||||
if (!managerDialog.keyword) return managerDialog.data
|
||||
const keyword = managerDialog.keyword.toLowerCase()
|
||||
return managerDialog.data.filter(
|
||||
(item) =>
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.org.toLowerCase().includes(keyword) ||
|
||||
item.station.toLowerCase().includes(keyword),
|
||||
)
|
||||
})
|
||||
|
||||
const selectedManagerNames = computed(() =>
|
||||
formData.value.planManagers.map((item) => item.name).join('、'),
|
||||
)
|
||||
|
||||
const onOpenPersonPicker = async () => {
|
||||
managerDialog.visible = true
|
||||
managerDialogConfig.outerVisible = true
|
||||
await nextTick()
|
||||
if (personTableRef.value) {
|
||||
personTableRef.value.clearSelection()
|
||||
managerDialog.data.forEach((row) => {
|
||||
const exists = formData.value.planManagers.find((item) => item.id === row.id)
|
||||
if (exists) {
|
||||
personTableRef.value.toggleRowSelection(row, true)
|
||||
}
|
||||
})
|
||||
}
|
||||
managerDialog.selected = [...formData.value.planManagers]
|
||||
}
|
||||
|
||||
const onManagerSelectionChange = (rows) => {
|
||||
managerDialog.selected = [...rows]
|
||||
}
|
||||
|
||||
const onRemoveManager = (item) => {
|
||||
managerDialog.selected = managerDialog.selected.filter((row) => row.id !== item.id)
|
||||
if (personTableRef.value) {
|
||||
const target = managerDialog.data.find((row) => row.id === item.id)
|
||||
if (target) personTableRef.value.toggleRowSelection(target, false)
|
||||
}
|
||||
}
|
||||
|
||||
const onClearManagers = () => {
|
||||
managerDialog.selected = []
|
||||
if (personTableRef.value) personTableRef.value.clearSelection()
|
||||
}
|
||||
|
||||
const onConfirmManager = () => {
|
||||
formData.value.planManagers = [...managerDialog.selected]
|
||||
managerDialog.visible = false
|
||||
managerDialogConfig.outerVisible = false
|
||||
}
|
||||
|
||||
// 关闭弹框统一处理
|
||||
const onCloseDialogOuter = (visible) => {
|
||||
managerDialogConfig.outerVisible = visible
|
||||
}
|
||||
|
||||
// 人员排班:按月份生成日期表
|
||||
const dayAssignments = ref({}) // { '2025-01-01': [person, ...] }
|
||||
const maxShowInCell = 5
|
||||
|
||||
const calendarDays = computed(() => {
|
||||
const monthStr = formData.value.month
|
||||
if (!monthStr) return []
|
||||
|
||||
const [yearStr, monthStrNum] = monthStr.split('-')
|
||||
const year = Number(yearStr)
|
||||
const month = Number(monthStrNum)
|
||||
if (!year || !month) return []
|
||||
|
||||
const daysInMonth = new Date(year, month, 0).getDate()
|
||||
const start = formData.value.planStartDate
|
||||
const end = formData.value.planEndDate
|
||||
|
||||
const pad = (n) => (n < 10 ? `0${n}` : `${n}`)
|
||||
|
||||
const list = []
|
||||
for (let d = 1; d <= daysInMonth; d++) {
|
||||
const date = `${year}-${pad(month)}-${pad(d)}`
|
||||
const label = `${month}月${pad(d)}日`
|
||||
let isInRange = false
|
||||
if (start && end) {
|
||||
isInRange = date >= start && date <= end
|
||||
}
|
||||
list.push({
|
||||
date,
|
||||
label,
|
||||
isInRange,
|
||||
managers: dayAssignments.value[date] || [],
|
||||
})
|
||||
}
|
||||
return list
|
||||
})
|
||||
|
||||
// 将计划投入管理人员模板填充到某一天
|
||||
const onFillManagersForDay = (date) => {
|
||||
if (!formData.value.planManagers || !formData.value.planManagers.length) return
|
||||
dayAssignments.value[date] = formData.value.planManagers.map((p) => ({ ...p }))
|
||||
}
|
||||
|
||||
// 清除某一天的人员
|
||||
const onClearManagersForDay = (date) => {
|
||||
if (dayAssignments.value[date]) {
|
||||
dayAssignments.value[date] = []
|
||||
}
|
||||
}
|
||||
|
||||
// 从某一天删除单个人员,不影响表单里的模板
|
||||
const onRemovePersonFromDay = (date, person) => {
|
||||
const list = dayAssignments.value[date] || []
|
||||
dayAssignments.value[date] = list.filter((item) => item.id !== person.id)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
|
@ -287,17 +816,6 @@ const onSubmit = () => {
|
|||
font-size: 14px;
|
||||
}
|
||||
|
||||
.calendar-placeholder {
|
||||
min-height: 240px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #9ca3af;
|
||||
border: 1px dashed #e5e7eb;
|
||||
border-radius: 8px;
|
||||
background-color: #f9fafb;
|
||||
}
|
||||
|
||||
.page-footer {
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
|
|
@ -305,4 +823,138 @@ const onSubmit = () => {
|
|||
gap: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.person-search-bar {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.selected-panel {
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 8px;
|
||||
padding: 12px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.selected-list {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.selected-tag {
|
||||
margin-left: 6px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.clickable-suffix {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.schedule-wrapper {
|
||||
.schedule-tip {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: 12px;
|
||||
color: #6b7280;
|
||||
margin-bottom: 8px;
|
||||
|
||||
.schedule-tip-extra {
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.schedule-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, minmax(0, 1fr)); // 一行 7 个格子
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.schedule-cell {
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 4px;
|
||||
padding: 6px 8px;
|
||||
min-height: 150px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
background-color: #ffffff;
|
||||
|
||||
&.is-disabled {
|
||||
background-color: #f9fafb;
|
||||
color: #9ca3af;
|
||||
}
|
||||
}
|
||||
|
||||
.cell-date {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.cell-persons {
|
||||
flex: 1;
|
||||
// min-height: 52px;
|
||||
// max-height: 52px;
|
||||
overflow: hidden;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.person-tags {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.more-text {
|
||||
font-size: 12px;
|
||||
color: #2563eb;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.empty-tip-small {
|
||||
font-size: 12px;
|
||||
color: #9ca3af;
|
||||
|
||||
&.is-disabled-text {
|
||||
color: #d1d5db;
|
||||
}
|
||||
}
|
||||
|
||||
.cell-actions {
|
||||
margin-top: 4px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.el-button + .el-button {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.popover-list {
|
||||
.popover-item {
|
||||
display: flex;
|
||||
font-size: 12px;
|
||||
// padding: 2px 6px;
|
||||
background-color: #f3f4f6;
|
||||
border-radius: 2px;
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -10,8 +10,32 @@
|
|||
:show-action="true"
|
||||
:action-columns="actionColumns"
|
||||
>
|
||||
<template #toolbar>
|
||||
<template #toolbar="{ formData }">
|
||||
<ComButton type="primary" icon="Plus" @click="onHandleAdd">新增月计划</ComButton>
|
||||
<ComButton
|
||||
type="info"
|
||||
plain
|
||||
icon="UploadFilled"
|
||||
@click="onExportPersonArrange(formData)"
|
||||
>
|
||||
导出人员安排表
|
||||
</ComButton>
|
||||
<ComButton
|
||||
type="info"
|
||||
plain
|
||||
icon="UploadFilled"
|
||||
@click="onExportOverallSummary(formData)"
|
||||
>
|
||||
导出整体汇总表
|
||||
</ComButton>
|
||||
<ComButton
|
||||
type="info"
|
||||
plain
|
||||
icon="UploadFilled"
|
||||
@click="onExportWorkloadSummary(formData)"
|
||||
>
|
||||
导出工作量汇总表
|
||||
</ComButton>
|
||||
</template>
|
||||
</ComTable>
|
||||
|
||||
|
|
@ -68,7 +92,7 @@ const actionColumns = [
|
|||
handler: (row) => {
|
||||
router.push({
|
||||
path: '/plan/monthlyPlanEdit/index',
|
||||
query: { id: row.planId, mode: 'detail' },
|
||||
query: { id: row.planId, mode: 'edit' },
|
||||
})
|
||||
},
|
||||
},
|
||||
|
|
@ -107,6 +131,28 @@ const onHandleSave = () => {
|
|||
const onCloseDialogOuter = (visible) => {
|
||||
dialogConfig.outerVisible = visible
|
||||
}
|
||||
|
||||
// 导出人员安排表
|
||||
const onExportPersonArrange = (queryParams) => {
|
||||
console.log('queryParams', queryParams)
|
||||
// proxy.download(
|
||||
// 'xxx/xxx',
|
||||
// {
|
||||
// ...queryParams.value,
|
||||
// },
|
||||
// `job_${new Date().getTime()}.xlsx`,
|
||||
// )
|
||||
}
|
||||
|
||||
// 导出整体汇总表
|
||||
const onExportOverallSummary = (queryParams) => {
|
||||
console.log('queryParams', queryParams)
|
||||
}
|
||||
|
||||
// 导出工作量汇总表
|
||||
const onExportWorkloadSummary = (queryParams) => {
|
||||
console.log('queryParams', queryParams)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ import { defineConfig, loadEnv } from 'vite'
|
|||
import path from 'path'
|
||||
import createVitePlugins from './vite/plugins'
|
||||
|
||||
const baseUrl = 'http://192.168.0.133:58080' // 后端接口地址 超子
|
||||
// const baseUrl = 'http://192.168.0.133:58080' // 后端接口地址 超子
|
||||
const baseUrl = 'http://localhost:58080' // 后端接口地址 超子
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(({ mode, command }) => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue