日计划接口调试
This commit is contained in:
parent
55663cc9d2
commit
ca87b0fa8a
Binary file not shown.
|
Before Width: | Height: | Size: 5.5 KiB |
|
|
@ -1,36 +1,45 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
// 计划管理- 查询列表
|
||||
export function listPlanAPI(query) {
|
||||
// 日计划管理- 查询列表
|
||||
export function listDailyPlanAPI(query) {
|
||||
return request({
|
||||
url: '/personnel/getPersonnelList',
|
||||
url: '/dayPlan/getDayPlanList',
|
||||
method: 'GET',
|
||||
params: query,
|
||||
})
|
||||
}
|
||||
|
||||
// 计划管理- 新增
|
||||
export function addPlanAPI(data) {
|
||||
// 日计划管理- 新增
|
||||
export function addDailyPlanAPI(data) {
|
||||
return request({
|
||||
url: '/personnel/addPersonnel',
|
||||
url: '/dayPlan/addDayPlan',
|
||||
method: 'POST',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
// 计划管理- 修改
|
||||
export function updatePlanAPI(data) {
|
||||
// 日计划管理- 新增弹框内获取的计划列表
|
||||
export function listDailyPlanPopupAPI(query) {
|
||||
return request({
|
||||
url: '/personnel/updatePersonnel',
|
||||
url: '/monthlyPlan/getMonthlyPlanLists',
|
||||
method: 'GET',
|
||||
params: query,
|
||||
})
|
||||
}
|
||||
|
||||
// 日计划管理- 修改
|
||||
export function updateDailyPlanAPI(data) {
|
||||
return request({
|
||||
url: '/dayPlan/updateDayPlan',
|
||||
method: 'POST',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
// 计划管理- 删除
|
||||
export function delPlanAPI(data) {
|
||||
// 日计划管理- 删除
|
||||
export function delDailyPlanAPI(data) {
|
||||
return request({
|
||||
url: `/personnel/delPersonnel`,
|
||||
url: `/dayPlan/delDayPlan`,
|
||||
method: 'POST',
|
||||
data,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
:formData="
|
||||
Object.assign({}, searchFormRef?.getFormData() || {}, {
|
||||
pageNum: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
pageSize: pagination.limit,
|
||||
}) || {}
|
||||
"
|
||||
/>
|
||||
|
|
@ -133,7 +133,7 @@ const loading = ref(false)
|
|||
const tableData = ref([])
|
||||
const pagination = reactive({
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
limit: 10,
|
||||
total: 0,
|
||||
})
|
||||
|
||||
|
|
@ -187,7 +187,7 @@ const fetchData = async (formData = {}) => {
|
|||
...formData,
|
||||
...props.defaultQueryParams,
|
||||
pageNum: pagination.page, // 后端可能需要pageNum
|
||||
pageSize: pagination.pageSize, // 后端可能需要pageSize
|
||||
pageSize: pagination.limit, // 后端可能需要pageSize
|
||||
}
|
||||
|
||||
const response = await props.loadData(params)
|
||||
|
|
|
|||
|
|
@ -112,7 +112,8 @@ function logout() {
|
|||
})
|
||||
.then(() => {
|
||||
userStore.logOut().then(() => {
|
||||
location.href = '/index'
|
||||
// location.href = '/index'
|
||||
location.href = import.meta.env.VITE_APP_PUBLIC_PATH + '/index'
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
|
|
@ -130,136 +131,137 @@ function toggleTheme() {
|
|||
|
||||
<style lang="scss" scoped>
|
||||
.navbar {
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background: var(--navbar-bg);
|
||||
border-bottom: 1px solid var(--navbar-border, #f0f0f0);
|
||||
box-shadow: 0 6px 18px rgba(15, 23, 42, 0.04);
|
||||
backdrop-filter: blur(12px);
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background: var(--navbar-bg);
|
||||
border-bottom: 1px solid var(--navbar-border, #f0f0f0);
|
||||
box-shadow: 0 6px 18px rgba(15, 23, 42, 0.04);
|
||||
backdrop-filter: blur(12px);
|
||||
|
||||
.hamburger-container {
|
||||
line-height: 46px;
|
||||
height: 100%;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
transition: background 0.25s ease, transform 0.2s ease;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background: rgba(22, 119, 255, 0.08);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumb-container {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.topmenu-container {
|
||||
position: absolute;
|
||||
left: 50px;
|
||||
}
|
||||
|
||||
.errLog-container {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.right-menu {
|
||||
float: right;
|
||||
height: 100%;
|
||||
line-height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-right: 12px;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.right-menu-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 10px;
|
||||
margin: 0 2px;
|
||||
height: 100%;
|
||||
font-size: 18px;
|
||||
color: #4b5563;
|
||||
vertical-align: middle;
|
||||
border-radius: 999px;
|
||||
transition: background 0.25s ease, color 0.25s ease, transform 0.2s ease, box-shadow 0.2s ease;
|
||||
|
||||
&.hover-effect {
|
||||
.hamburger-container {
|
||||
line-height: 46px;
|
||||
height: 100%;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
transition: background 0.25s ease, transform 0.2s ease;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background: rgba(22, 119, 255, 0.08);
|
||||
color: #1677ff;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 10px rgba(15, 23, 42, 0.12);
|
||||
background: rgba(22, 119, 255, 0.08);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
}
|
||||
|
||||
&.theme-switch-wrapper {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
svg {
|
||||
transition: transform 0.25s ease;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
margin-right: 0;
|
||||
padding-right: 0;
|
||||
|
||||
.avatar-wrapper {
|
||||
position: relative;
|
||||
right: 0;
|
||||
margin-top: 0;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 6px 12px;
|
||||
border-radius: 999px;
|
||||
background: rgba(17, 24, 39, 0.02);
|
||||
transition: background 0.25s ease, transform 0.2s ease, box-shadow 0.2s ease;
|
||||
|
||||
.user-avatar {
|
||||
cursor: pointer;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgba(255, 255, 255, 0.9);
|
||||
box-shadow: 0 2px 6px rgba(15, 23, 42, 0.18);
|
||||
}
|
||||
|
||||
.user-nickname {
|
||||
position: static;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #374151;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
i {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .avatar-wrapper {
|
||||
background: rgba(22, 119, 255, 0.1);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 10px rgba(15, 23, 42, 0.16);
|
||||
}
|
||||
.breadcrumb-container {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.topmenu-container {
|
||||
position: absolute;
|
||||
left: 50px;
|
||||
}
|
||||
|
||||
.errLog-container {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.right-menu {
|
||||
float: right;
|
||||
height: 100%;
|
||||
line-height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-right: 12px;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.right-menu-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 10px;
|
||||
margin: 0 2px;
|
||||
height: 100%;
|
||||
font-size: 18px;
|
||||
color: #4b5563;
|
||||
vertical-align: middle;
|
||||
border-radius: 999px;
|
||||
transition: background 0.25s ease, color 0.25s ease, transform 0.2s ease,
|
||||
box-shadow 0.2s ease;
|
||||
|
||||
&.hover-effect {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: rgba(22, 119, 255, 0.08);
|
||||
color: #1677ff;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 10px rgba(15, 23, 42, 0.12);
|
||||
}
|
||||
}
|
||||
|
||||
&.theme-switch-wrapper {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
svg {
|
||||
transition: transform 0.25s ease;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
margin-right: 0;
|
||||
padding-right: 0;
|
||||
|
||||
.avatar-wrapper {
|
||||
position: relative;
|
||||
right: 0;
|
||||
margin-top: 0;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 6px 12px;
|
||||
border-radius: 999px;
|
||||
background: rgba(17, 24, 39, 0.02);
|
||||
transition: background 0.25s ease, transform 0.2s ease, box-shadow 0.2s ease;
|
||||
|
||||
.user-avatar {
|
||||
cursor: pointer;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgba(255, 255, 255, 0.9);
|
||||
box-shadow: 0 2px 6px rgba(15, 23, 42, 0.18);
|
||||
}
|
||||
|
||||
.user-nickname {
|
||||
position: static;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #374151;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
i {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .avatar-wrapper {
|
||||
background: rgba(22, 119, 255, 0.1);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 10px rgba(15, 23, 42, 0.16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -104,7 +104,8 @@ service.interceptors.response.use(
|
|||
useUserStore()
|
||||
.logOut()
|
||||
.then(() => {
|
||||
location.href = '/index'
|
||||
// location.href = '/index'
|
||||
location.href = import.meta.env.VITE_APP_PUBLIC_PATH + '/index'
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ const editId = ref(null)
|
|||
const { options: inspectionStationOptions } = useOptions(
|
||||
'inspectionStationOptions',
|
||||
getInspectionStationSelectAPI,
|
||||
{ category: 0 },
|
||||
{},
|
||||
)
|
||||
const { options: positionOptions } = useOptions(
|
||||
'positionOptions',
|
||||
|
|
|
|||
|
|
@ -1,102 +1,111 @@
|
|||
<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="large"
|
||||
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="nowDate" class="month-item">
|
||||
<el-date-picker
|
||||
type="date"
|
||||
style="width: 200px"
|
||||
v-model="formData.nowDate"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择计划日期"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 搜索区域 -->
|
||||
<div class="search-section">
|
||||
<el-input
|
||||
clearable
|
||||
@keyup.enter="onSearch"
|
||||
class="search-input"
|
||||
placeholder="输入关键字"
|
||||
v-model.trim="formData.keyword"
|
||||
>
|
||||
<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
|
||||
border
|
||||
:header-cell-style="{ background: '#f5f7fa', color: '#606266', fontWeight: 600 }"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column
|
||||
prop="projectName"
|
||||
label="项目名称"
|
||||
min-width="260"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="workContent"
|
||||
label="工作任务"
|
||||
min-width="360"
|
||||
show-overflow-tooltip
|
||||
align="center"
|
||||
/>
|
||||
</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({
|
||||
// 初始查询参数(比如从父页面传入当前月份)
|
||||
defaultMonth: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 加载任务列表的方法,由父组件传入
|
||||
loadTaskList: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
})
|
||||
import { listDailyPlanPopupAPI } from '@/api/planMange/dailyPlan'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
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({
|
||||
month: props.defaultMonth || '',
|
||||
nowDate: dayjs().add(1, 'day').format('YYYY-MM-DD'), // 默认当天 + 1天
|
||||
keyword: '',
|
||||
})
|
||||
|
||||
const rules = {
|
||||
month: [{ required: true, message: '请选择计划执行月份', trigger: 'change' }],
|
||||
nowDate: [{ required: true, message: '请选择计划执行日期', trigger: 'change' }],
|
||||
}
|
||||
|
||||
// 搜索 / 刷新列表
|
||||
const fetchData = async () => {
|
||||
if (!props.loadTaskList) return
|
||||
await formRef.value.validate()
|
||||
loading.value = true
|
||||
try {
|
||||
const params = {
|
||||
month: formData.value.month,
|
||||
keyword: formData.value.keyword,
|
||||
nowDate: formData.value.nowDate,
|
||||
keyWord: formData.value.keyword,
|
||||
}
|
||||
const res = await props.loadTaskList(params)
|
||||
tableData.value = res?.rows || res?.data?.rows || res?.data || []
|
||||
const res = await listDailyPlanPopupAPI(params)
|
||||
tableData.value = res?.data
|
||||
} catch (e) {
|
||||
console.error('加载计划任务列表失败:', e)
|
||||
tableData.value = []
|
||||
|
|
@ -113,31 +122,125 @@ const onSelectionChange = (rows) => {
|
|||
selectedRows.value = rows
|
||||
}
|
||||
|
||||
// 默认月份变化时,同步到表单
|
||||
watch(
|
||||
() => props.defaultMonth,
|
||||
(val) => {
|
||||
if (val) formData.value.month = val
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
// 暴露方法给父组件:获取选中任务、触发查询、校验
|
||||
defineExpose({
|
||||
getSelectedTasks: () => selectedRows.value,
|
||||
getCurrentDate: () => formData.value.nowDate,
|
||||
search: fetchData,
|
||||
validate: () => formRef.value.validate(),
|
||||
validate: async () => {
|
||||
await formRef.value.validate()
|
||||
if (selectedRows.value.length === 0) {
|
||||
proxy.$modal.msgError('请选择项目')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
fetchData()
|
||||
})
|
||||
</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>
|
||||
|
|
|
|||
|
|
@ -55,11 +55,11 @@ export const buildFormColumns = () => [
|
|||
|
||||
// 月计划列表表格列
|
||||
export const tableColumns = [
|
||||
{ prop: 'stationName', label: '日期', fixed: true },
|
||||
{ prop: 'majorName', label: '运检站', fixed: true },
|
||||
{ prop: 'businessTypeName', label: '专业', fixed: true },
|
||||
{ prop: 'dayPlan', label: '日期', fixed: true, width: '140' },
|
||||
{ prop: 'inspectionStationName', label: '运检站', fixed: true },
|
||||
{ prop: 'planMajorName', label: '专业', fixed: true },
|
||||
{ prop: 'projectName', label: '项目名称', fixed: true },
|
||||
{ prop: 'workTask', label: '工作任务' },
|
||||
{ prop: 'workContent', label: '工作任务' },
|
||||
{ prop: 'riskLevelName', label: '风险等级' },
|
||||
{ prop: 'categoryName', label: '计划工作量(基)' },
|
||||
]
|
||||
|
|
@ -107,7 +107,7 @@ export const tableColumns_2 = [
|
|||
|
||||
export const dialogConfig = reactive({
|
||||
outerVisible: false,
|
||||
outerTitle: '新增计划',
|
||||
outerTitle: '添加计划任务',
|
||||
outerWidth: '70%', // 根据图片缩小宽度更美观
|
||||
minHeight: '70vh',
|
||||
maxHeight: '90vh',
|
||||
|
|
|
|||
|
|
@ -1,301 +1,671 @@
|
|||
<template>
|
||||
<div class="app-container monthly-plan-edit">
|
||||
<div class="app-container daily-plan-edit">
|
||||
<!-- 顶部返回 + 标题 -->
|
||||
<el-page-header @back="onBack" :content="pageTitle" class="page-header" />
|
||||
|
||||
<!-- 基本信息表单(禁用) -->
|
||||
<el-card shadow="never" class="card-section">
|
||||
<template #header>
|
||||
<div class="card-header">基本信息</div>
|
||||
</template>
|
||||
|
||||
<el-form
|
||||
ref="formRef"
|
||||
ref="baseFormRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
:disabled="isDetail"
|
||||
size="large"
|
||||
label-width="180"
|
||||
:disabled="true"
|
||||
>
|
||||
<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.inspectionStationName" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="专业" prop="majorId">
|
||||
<el-select
|
||||
v-model="formData.majorId"
|
||||
placeholder="请选择专业"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in majorOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="业务类型" prop="businessTypeId">
|
||||
<el-select
|
||||
v-model="formData.businessTypeId"
|
||||
placeholder="请选择业务类型"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in businessTypeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="专业">
|
||||
<el-input v-model="formData.planMajorName" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="项目名称" prop="projectName">
|
||||
<el-input
|
||||
v-model.trim="formData.projectName"
|
||||
placeholder="请输入项目名称"
|
||||
maxlength="50"
|
||||
show-word-limit
|
||||
clearable
|
||||
/>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目名称">
|
||||
<el-input v-model="formData.projectName" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="风险等级" prop="riskLevel">
|
||||
<el-select
|
||||
v-model="formData.riskLevel"
|
||||
placeholder="请选择风险等级"
|
||||
clearable
|
||||
>
|
||||
<el-option
|
||||
v-for="item in riskLevelOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<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-col :span="12">
|
||||
<el-form-item label="日期">
|
||||
<el-input v-model="formData.dayPlan" disabled />
|
||||
</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-date-picker
|
||||
v-model="formData.planStartDate"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择计划开始时间"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="计划结束时间" prop="planEndDate">
|
||||
<el-date-picker
|
||||
v-model="formData.planEndDate"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择计划结束时间"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</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-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>
|
||||
</el-card>
|
||||
<!-- 动态表单组件(根据类型切换) -->
|
||||
<component
|
||||
:is="currentFormComponent"
|
||||
:form-data="formData"
|
||||
:is-detail="isDetail"
|
||||
:selected-manager-names="selectedManagerNames"
|
||||
@open-person-picker="onOpenPersonPicker"
|
||||
@update:form-data="formData = $event"
|
||||
ref="formRef"
|
||||
/>
|
||||
|
||||
<!-- 底部操作按钮(详情模式下隐藏) -->
|
||||
<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 :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
|
||||
border
|
||||
ref="personTableRef"
|
||||
:data="filteredPersons"
|
||||
@selection-change="onManagerSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="50" align="center" />
|
||||
<el-table-column
|
||||
show-overflow-tooltip
|
||||
prop="org"
|
||||
label="人员所属单位"
|
||||
align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
show-overflow-tooltip
|
||||
prop="name"
|
||||
label="姓名"
|
||||
width="120"
|
||||
align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
show-overflow-tooltip
|
||||
prop="gender"
|
||||
label="性别"
|
||||
align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
show-overflow-tooltip
|
||||
prop="station"
|
||||
label="岗位"
|
||||
align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
show-overflow-tooltip
|
||||
prop="position"
|
||||
label="岗位性质"
|
||||
align="center"
|
||||
/>
|
||||
<el-table-column
|
||||
show-overflow-tooltip
|
||||
prop="type"
|
||||
label="人员分类"
|
||||
align="center"
|
||||
/>
|
||||
</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
|
||||
:key="item.id"
|
||||
:closable="!isDetail"
|
||||
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="managerDialogConfig.outerVisible = false">
|
||||
取消
|
||||
</ComButton>
|
||||
<ComButton type="primary" @click="onConfirmManager">确定</ComButton>
|
||||
</el-row>
|
||||
</template>
|
||||
</ComDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="MonthlyPlanEdit">
|
||||
import { ref, computed, getCurrentInstance } from 'vue'
|
||||
<script setup name="DailyPlanEdit">
|
||||
import {
|
||||
ref,
|
||||
reactive,
|
||||
computed,
|
||||
getCurrentInstance,
|
||||
nextTick,
|
||||
onMounted,
|
||||
shallowRef,
|
||||
watch,
|
||||
} from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { addPlanAPI, updatePlanAPI } from '@/api/planMange/plan.js'
|
||||
import { getPersonnelCommonListAPI } from '@/api/common.js'
|
||||
import { updateDailyPlanAPI } from '@/api/planMange/dailyPlan.js'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import { useOptions } from '@/hooks/useOptions'
|
||||
import ComButton from '@/components/ComButton/index.vue'
|
||||
import ComDialog from '@/components/ComDialog/index.vue'
|
||||
import RunForm from './forms/runForm.vue'
|
||||
import RepairForm from './forms/repairForm.vue'
|
||||
import ProjectForm from './forms/projectForm.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const { proxy } = getCurrentInstance()
|
||||
|
||||
const mode = computed(() => route.query.mode || 'add')
|
||||
// 使用通用 Hook 获取下拉数据
|
||||
const { options: personnelCommonOptions } = useOptions(
|
||||
'personnelCommonOptions',
|
||||
getPersonnelCommonListAPI,
|
||||
{},
|
||||
)
|
||||
|
||||
const mode = computed(() => route.query.mode || 'edit')
|
||||
const isDetail = computed(() => mode.value === 'detail')
|
||||
|
||||
const pageTitle = computed(() => {
|
||||
if (mode.value === 'edit') return '编辑月计划'
|
||||
if (mode.value === 'detail') return '月计划详情'
|
||||
return '新增月计划'
|
||||
// 获取日计划类型:0-运行,1-检修,2-项目部
|
||||
const dayPlanType = computed(() => {
|
||||
// 优先从路由参数获取
|
||||
if (route.query.dayPlanType !== undefined) {
|
||||
return String(route.query.dayPlanType)
|
||||
}
|
||||
// 如果没有,默认返回运行类型
|
||||
return '0'
|
||||
})
|
||||
|
||||
// 根据类型动态切换表单组件
|
||||
const formComponents = {
|
||||
0: RunForm, // 运行
|
||||
1: RepairForm, // 检修
|
||||
2: ProjectForm, // 项目部
|
||||
}
|
||||
|
||||
const currentFormComponent = shallowRef(formComponents[dayPlanType.value] || RunForm)
|
||||
|
||||
const pageTitle = computed(() => {
|
||||
const typeMap = {
|
||||
0: '运行',
|
||||
1: '检修',
|
||||
2: '项目部',
|
||||
}
|
||||
const typeName = typeMap[dayPlanType.value] || '运行'
|
||||
if (mode.value === 'edit') return `编辑日计划(${typeName})`
|
||||
if (mode.value === 'detail') return `日计划详情(${typeName})`
|
||||
return `新增日计划(${typeName})`
|
||||
})
|
||||
|
||||
const baseFormRef = ref(null)
|
||||
const formRef = ref(null)
|
||||
|
||||
const getInitFormData = () => ({
|
||||
planId: null,
|
||||
stationId: null,
|
||||
majorId: null,
|
||||
businessTypeId: null,
|
||||
projectName: '',
|
||||
workContent: '',
|
||||
riskLevel: null,
|
||||
month: '',
|
||||
planStartDate: '',
|
||||
planEndDate: '',
|
||||
remark: '',
|
||||
// 从路由参数获取基本信息(禁用字段)
|
||||
const routeParams = computed(() => ({
|
||||
inspectionStationName: route.query.inspectionStationName || '',
|
||||
projectName: route.query.projectName || '',
|
||||
planMajorName: route.query.planMajorName || '',
|
||||
dayPlan: route.query.dayPlan || '',
|
||||
dayPlanId: route.query.id || null,
|
||||
}))
|
||||
|
||||
// 运行类型表单数据结构
|
||||
const getRunFormData = () => ({
|
||||
dayPlanId: routeParams.value.dayPlanId,
|
||||
// 基本信息(禁用,从路由参数获取,不传给后端)
|
||||
inspectionStationName: routeParams.value.inspectionStationName,
|
||||
projectName: routeParams.value.projectName,
|
||||
planMajorName: routeParams.value.planMajorName,
|
||||
dayPlan: routeParams.value.dayPlan,
|
||||
// 计划投入资源情况(可编辑,需要传给后端)
|
||||
plannedWorkload: null, // 计划工作量
|
||||
planPersonnelList: [], // 拟投入作业人员(数组,暂时不确定字段名)
|
||||
planPersonnel: '', // 拟投入作业人员(字符串,提交时使用)
|
||||
proposedLongTimeCar: null, // 拟投入长租车
|
||||
proposedTemporaryCar: null, // 拟投入临租车
|
||||
// 实际完成情况
|
||||
actualPersonnelList: [], // 实际入作业人员(数组,暂时不确定字段名)
|
||||
actualPersonnel: '', // 实际入作业人员(字符串,提交时使用)
|
||||
actualLongTimeCar: null, // 实际入长租车
|
||||
actualTemporaryCar: null, // 实际入临租车
|
||||
actualWorkContent: '', // 实际完成工作内容
|
||||
actualWorkload: null, // 实际完成工作量
|
||||
completionPercentage: null, // 完成比例
|
||||
planCompletionStatus: null, // 作业计划完成情况
|
||||
planChanges: '', // 计划变更及未完成情况说明
|
||||
})
|
||||
|
||||
// 检修类型表单数据结构
|
||||
const getRepairFormData = () => ({
|
||||
dayPlanId: routeParams.value.dayPlanId,
|
||||
// 基本信息(禁用,从路由参数获取,不传给后端)
|
||||
inspectionStationName: routeParams.value.inspectionStationName,
|
||||
projectName: routeParams.value.projectName,
|
||||
planMajorName: routeParams.value.planMajorName,
|
||||
dayPlan: routeParams.value.dayPlan,
|
||||
// 计划投入资源情况
|
||||
plannedWorkload: null, // 计划工作量
|
||||
highAltitudePersonnelList: [], // 拟投入高处作业人员(数组)
|
||||
groundPersonnelList: [], // 拟投入地面作业人员(数组)
|
||||
skilledWorkerNum: null, // 计划投入熟练工人员数量
|
||||
skilledWorkerDay: null, // 计划投入工日(熟练工)
|
||||
auxiliaryWorkerNum: null, // 计划投入辅助工人员数量
|
||||
auxiliaryWorkerDay: null, // 计划投入工日(辅助工)
|
||||
proposedLongTimeCar: null, // 拟投入长租车
|
||||
proposedTemporaryCar: null, // 拟投入临租车
|
||||
proposedSubcontractedCar: null, // 拟投入分包车
|
||||
// 实际完成情况
|
||||
actualHighAltitudePersonnelList: [], // 实际投入高处作业人员(数组)
|
||||
actualGroundPersonnelList: [], // 实际投入地面作业人员(数组)
|
||||
actualSkilledWorkerNum: null, // 实际投入检修熟练工数量
|
||||
actualAuxiliaryWorkerNum: null, // 实际投入检修辅助工数量
|
||||
actualLongTimeCar: null, // 实际投入长租车
|
||||
actualTemporaryCar: null, // 实际投入临租车
|
||||
actualSubcontractedCar: null, // 实际投入分包车
|
||||
actualWorkloadList: [
|
||||
{
|
||||
workloadCategoryId: '',
|
||||
workloadCategoryName: '',
|
||||
unitPrice: '',
|
||||
workloadNum: '',
|
||||
},
|
||||
], // 实际完成工作内容(动态列表)
|
||||
actualWorkload: null, // 实际完成工作量
|
||||
completionPercentage: null, // 完成比例
|
||||
planCompletionStatus: null, // 作业计划完成情况
|
||||
planChanges: '', // 计划变更及未完成情况说明
|
||||
})
|
||||
|
||||
// 项目部类型表单数据结构(占位,待后续填充)
|
||||
const getProjectFormData = () => ({
|
||||
dayPlanId: routeParams.value.dayPlanId,
|
||||
// 基本信息(禁用,从路由参数获取,不传给后端)
|
||||
inspectionStationName: routeParams.value.inspectionStationName,
|
||||
projectName: routeParams.value.projectName,
|
||||
planMajorName: routeParams.value.planMajorName,
|
||||
dayPlan: routeParams.value.dayPlan,
|
||||
// 计划投入资源情况(待填充)
|
||||
// TODO: 项目部类型字段待确定
|
||||
planPersonnelList: [], // 拟投入作业人员(数组,暂时不确定字段名)
|
||||
planPersonnel: '', // 拟投入作业人员(字符串,提交时使用)
|
||||
// 实际完成情况(待填充)
|
||||
actualPersonnelList: [], // 实际入作业人员(数组,暂时不确定字段名)
|
||||
actualPersonnel: '', // 实际入作业人员(字符串,提交时使用)
|
||||
// TODO: 项目部类型实际完成情况字段待确定
|
||||
})
|
||||
|
||||
// 根据类型获取对应的表单数据结构
|
||||
const getInitFormData = () => {
|
||||
const type = dayPlanType.value
|
||||
if (type === '0' || type === 0) {
|
||||
return getRunFormData()
|
||||
} else if (type === '1' || type === 1) {
|
||||
return getRepairFormData()
|
||||
} else if (type === '2' || type === 2) {
|
||||
return getProjectFormData()
|
||||
}
|
||||
// 默认返回运行类型
|
||||
return getRunFormData()
|
||||
}
|
||||
|
||||
const formData = ref(getInitFormData())
|
||||
|
||||
// 静态选项(后续可替换为接口下拉)
|
||||
const stationOptions = [
|
||||
{ label: '昆明运检站', value: 1 },
|
||||
{ label: '大理运检站', value: 2 },
|
||||
]
|
||||
|
||||
const majorOptions = [
|
||||
{ label: '输电专业', value: 1 },
|
||||
{ label: '变电专业', value: 2 },
|
||||
]
|
||||
|
||||
const businessTypeOptions = [
|
||||
{ label: '日常巡视', value: 1 },
|
||||
{ label: '缺陷处理', value: 2 },
|
||||
]
|
||||
|
||||
const riskLevelOptions = [
|
||||
{ label: '低风险', value: 1 },
|
||||
{ label: '中风险', value: 2 },
|
||||
{ label: '高风险', value: 3 },
|
||||
]
|
||||
|
||||
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' }],
|
||||
}
|
||||
// 表单校验规则(子组件内部处理,这里保留用于兼容)
|
||||
const rules = computed(() => ({}))
|
||||
|
||||
const onBack = () => {
|
||||
router.back()
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('保存月计划失败:', error)
|
||||
}
|
||||
proxy.$tab.closeOpenPage({
|
||||
path: '/plan/dailyPlan',
|
||||
})
|
||||
}
|
||||
|
||||
const onSubmit = async () => {
|
||||
try {
|
||||
// 调用子组件的校验方法(子组件的 validate 返回 Promise<boolean>)
|
||||
const valid = await formRef.value?.validate()
|
||||
console.log(valid, 'valid')
|
||||
|
||||
if (!valid) {
|
||||
console.log('校验没有通过')
|
||||
// 如果校验失败,尝试滚动到第一个错误字段
|
||||
// 注意:子组件的 validate 方法不返回 fields,所以这里无法获取具体错误字段
|
||||
return
|
||||
}
|
||||
|
||||
// 校验通过,继续执行后续代码
|
||||
const proposedPersonnelList = []
|
||||
|
||||
formData.value.planPersonnelList.forEach((item) => {
|
||||
proposedPersonnelList.push({
|
||||
dayPlanId: route.query.id,
|
||||
inspectionStationName: item.inspectionStationName,
|
||||
personnelld: item.id,
|
||||
name: item.name,
|
||||
dataSource: 0,
|
||||
})
|
||||
})
|
||||
formData.value.actualPersonnelList.forEach((item) => {
|
||||
proposedPersonnelList.push({
|
||||
dayPlanId: route.query.id,
|
||||
inspectionStationName: item.inspectionStationName,
|
||||
personnelld: item.id,
|
||||
name: item.name,
|
||||
dataSource: 1,
|
||||
})
|
||||
})
|
||||
|
||||
// 组装参数:排除基本信息字段,只提交投入资源情况
|
||||
const {
|
||||
inspectionStationName,
|
||||
projectName,
|
||||
planMajorName,
|
||||
dayPlan,
|
||||
planPersonnelList,
|
||||
actualPersonnelList,
|
||||
actualPersonnel,
|
||||
planPersonnel,
|
||||
proposedLongTimeCar,
|
||||
...submitData
|
||||
} = formData.value
|
||||
|
||||
submitData.proposedPersonnelList = proposedPersonnelList
|
||||
const result = await updateDailyPlanAPI(submitData)
|
||||
if (result.code === 200) {
|
||||
proxy.$modal.msgSuccess('保存成功')
|
||||
onBack()
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error, 'error')
|
||||
return Promise.reject(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 人员选择弹窗相关
|
||||
const personTableRef = ref(null)
|
||||
const managerDialogConfig = reactive({
|
||||
outerVisible: false,
|
||||
outerTitle: '选择人员',
|
||||
outerWidth: '70%',
|
||||
minHeight: '60vh',
|
||||
maxHeight: '80vh',
|
||||
})
|
||||
|
||||
const managerDialog = reactive({
|
||||
visible: false,
|
||||
keyword: '',
|
||||
selected: [],
|
||||
type: 'plan', // 'plan', 'actual', 'highAltitude', 'ground', 'actual_highAltitude', 'actual_ground'
|
||||
})
|
||||
|
||||
// 将公共人员列表转换为表格展示需要的字段结构
|
||||
const personList = computed(() => {
|
||||
return (personnelCommonOptions.value || []).map((item) => ({
|
||||
...item,
|
||||
org: item.inspectionStationName, // 人员所属单位
|
||||
gender: item.sex === '1' ? '男' : '女',
|
||||
station: item.positionName, // 岗位
|
||||
position: item.personnelNatureName, // 岗位性质
|
||||
type: item.personnelClassificationName, // 人员分类
|
||||
}))
|
||||
})
|
||||
|
||||
const filteredPersons = computed(() => {
|
||||
const list = personList.value
|
||||
if (!managerDialog.keyword) return list
|
||||
const keyword = managerDialog.keyword.toLowerCase()
|
||||
return list.filter((item) => {
|
||||
const name = (item.name || '').toLowerCase()
|
||||
const org = (item.org || '').toLowerCase()
|
||||
const station = (item.station || '').toLowerCase()
|
||||
return name.includes(keyword) || org.includes(keyword) || station.includes(keyword)
|
||||
})
|
||||
})
|
||||
|
||||
const selectedManagerNames = computed(() => {
|
||||
// 根据不同的表单类型返回对应的人员名称
|
||||
if (dayPlanType.value === '1' || dayPlanType.value === 1) {
|
||||
// 检修类型:返回高处作业人员和地面作业人员的名称
|
||||
const highAltitude = (formData.value.highAltitudePersonnelList || [])
|
||||
.map((item) => item.name)
|
||||
.join('、')
|
||||
const ground = (formData.value.groundPersonnelList || [])
|
||||
.map((item) => item.name)
|
||||
.join('、')
|
||||
return [highAltitude, ground].filter(Boolean).join('、') || ''
|
||||
}
|
||||
// 运行类型和项目部类型:使用 planPersonnelList
|
||||
return (formData.value.planPersonnelList || []).map((item) => item.name).join('、')
|
||||
})
|
||||
|
||||
const onOpenPersonPicker = async (type = 'plan') => {
|
||||
managerDialog.type = type
|
||||
managerDialogConfig.outerVisible = true
|
||||
await nextTick()
|
||||
if (personTableRef.value) {
|
||||
personTableRef.value.clearSelection()
|
||||
// 根据类型获取对应的人员列表
|
||||
let currentList = []
|
||||
if (type === 'plan') {
|
||||
currentList = formData.value.planPersonnelList || []
|
||||
} else if (type === 'actual') {
|
||||
currentList = formData.value.actualPersonnelList || []
|
||||
} else if (type === 'highAltitude') {
|
||||
currentList = formData.value.highAltitudePersonnelList || []
|
||||
} else if (type === 'ground') {
|
||||
currentList = formData.value.groundPersonnelList || []
|
||||
} else if (type === 'actual_highAltitude') {
|
||||
currentList = formData.value.actualHighAltitudePersonnelList || []
|
||||
} else if (type === 'actual_ground') {
|
||||
currentList = formData.value.actualGroundPersonnelList || []
|
||||
}
|
||||
|
||||
personList.value.forEach((row) => {
|
||||
const exists = currentList.find((item) => item.id === row.id)
|
||||
if (exists) {
|
||||
personTableRef.value.toggleRowSelection(row, true)
|
||||
}
|
||||
})
|
||||
managerDialog.selected = [...currentList]
|
||||
}
|
||||
}
|
||||
|
||||
const onManagerSelectionChange = (rows) => {
|
||||
managerDialog.selected = [...rows]
|
||||
}
|
||||
|
||||
const onRemoveManager = (item) => {
|
||||
managerDialog.selected = managerDialog.selected.filter((row) => row.id !== item.id)
|
||||
if (personTableRef.value) {
|
||||
const target = personList.value.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 = () => {
|
||||
const type = managerDialog.type
|
||||
// 根据类型更新对应的人员列表
|
||||
if (type === 'plan') {
|
||||
formData.value.planPersonnelList = [...managerDialog.selected]
|
||||
nextTick(() => {
|
||||
formRef.value?.validateField?.('planPersonnelList')
|
||||
})
|
||||
} else if (type === 'actual') {
|
||||
formData.value.actualPersonnelList = [...managerDialog.selected]
|
||||
nextTick(() => {
|
||||
formRef.value?.validateField?.('actualPersonnelList')
|
||||
})
|
||||
} else if (type === 'highAltitude') {
|
||||
formData.value.highAltitudePersonnelList = [...managerDialog.selected]
|
||||
nextTick(() => {
|
||||
formRef.value?.validateField?.('highAltitudePersonnelList')
|
||||
})
|
||||
} else if (type === 'ground') {
|
||||
formData.value.groundPersonnelList = [...managerDialog.selected]
|
||||
nextTick(() => {
|
||||
formRef.value?.validateField?.('groundPersonnelList')
|
||||
})
|
||||
} else if (type === 'actual_highAltitude') {
|
||||
formData.value.actualHighAltitudePersonnelList = [...managerDialog.selected]
|
||||
nextTick(() => {
|
||||
formRef.value?.validateField?.('actualHighAltitudePersonnelList')
|
||||
})
|
||||
} else if (type === 'actual_ground') {
|
||||
formData.value.actualGroundPersonnelList = [...managerDialog.selected]
|
||||
nextTick(() => {
|
||||
formRef.value?.validateField?.('actualGroundPersonnelList')
|
||||
})
|
||||
}
|
||||
managerDialogConfig.outerVisible = false
|
||||
}
|
||||
|
||||
// 关闭弹框统一处理
|
||||
const onCloseDialogOuter = (visible) => {
|
||||
managerDialogConfig.outerVisible = visible
|
||||
}
|
||||
|
||||
// 获取详情(如果需要从后端获取数据)
|
||||
const getDetail = async () => {
|
||||
// TODO: 如果有详情API,在这里调用
|
||||
// const result = await getDailyPlanDetailAPI({ dayPlanId: route.query.id })
|
||||
// if (result.code === 200 && result.data) {
|
||||
// const data = result.data
|
||||
// // 填充表单数据
|
||||
// }
|
||||
}
|
||||
|
||||
// 监听类型变化,切换组件并重新初始化表单数据
|
||||
watch(
|
||||
() => dayPlanType.value,
|
||||
(newType) => {
|
||||
currentFormComponent.value = formComponents[newType] || RunForm
|
||||
// 类型切换时重新初始化表单数据
|
||||
formData.value = getInitFormData()
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
if (route.query.id) {
|
||||
getDetail()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.monthly-plan-edit {
|
||||
.daily-plan-edit {
|
||||
.page-header {
|
||||
margin-bottom: 16px;
|
||||
margin-bottom: 20px;
|
||||
padding: 16px 20px;
|
||||
background: linear-gradient(135deg, #f5f7fa 0%, #ffffff 100%);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
|
||||
|
||||
:deep(.el-page-header__left) {
|
||||
.el-page-header__back {
|
||||
padding: 8px;
|
||||
border-radius: 6px;
|
||||
transition: all 0.3s ease;
|
||||
background-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background-color: #f0f2f5;
|
||||
color: #1677ff;
|
||||
transform: translateX(-2px);
|
||||
}
|
||||
|
||||
&::before {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-page-header__content) {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #1f2937;
|
||||
margin-left: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-section {
|
||||
margin-bottom: 16px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
overflow: hidden;
|
||||
transition: box-shadow 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
:deep(.el-card__header) {
|
||||
padding: 16px 20px;
|
||||
background-color: #fafbfc;
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
}
|
||||
|
||||
:deep(.el-card__body) {
|
||||
padding: 24px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-header {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.calendar-placeholder {
|
||||
min-height: 240px;
|
||||
font-size: 15px;
|
||||
color: #1f2937;
|
||||
position: relative;
|
||||
padding-left: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #9ca3af;
|
||||
border: 1px dashed #e5e7eb;
|
||||
border-radius: 8px;
|
||||
background-color: #f9fafb;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 4px;
|
||||
height: 16px;
|
||||
background: linear-gradient(180deg, #1677ff 0%, #4096ff 100%);
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.page-footer {
|
||||
|
|
@ -304,5 +674,46 @@ const onSubmit = () => {
|
|||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.clickable-suffix {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,175 @@
|
|||
<template>
|
||||
<el-card shadow="never" class="card-section">
|
||||
<template #header>
|
||||
<div class="card-header">投入的资源情况(项目部)</div>
|
||||
</template>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="!isDetail ? rules : {}"
|
||||
size="large"
|
||||
label-width="auto"
|
||||
:disabled="isDetail"
|
||||
>
|
||||
<!-- 项目部类型的表单字段,稍后完善 -->
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="计划工作量" prop="planWorkload">
|
||||
<el-input-number
|
||||
:model-value="formData.planWorkload"
|
||||
@update:model-value="(val) => updateField('planWorkload', val)"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
placeholder="请输入计划工作量"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="拟投入作业人员" prop="planPersonnelList">
|
||||
<el-input
|
||||
:model-value="selectedManagerNames"
|
||||
placeholder="请选择作业人员"
|
||||
readonly
|
||||
@click="onOpenPersonPicker"
|
||||
class="clickable-suffix"
|
||||
>
|
||||
<template #suffix>
|
||||
<el-icon class="clickable-suffix">
|
||||
<Search />
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="拟投入长租车" prop="planLongRentCar">
|
||||
<el-input-number
|
||||
:model-value="formData.planLongRentCar"
|
||||
@update:model-value="(val) => updateField('planLongRentCar', val)"
|
||||
:min="0"
|
||||
placeholder="请输入长租车数量"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="拟投入临租车" prop="planTempRentCar">
|
||||
<el-input-number
|
||||
:model-value="formData.planTempRentCar"
|
||||
@update:model-value="(val) => updateField('planTempRentCar', val)"
|
||||
:min="0"
|
||||
placeholder="请输入临租车数量"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script setup name="ProjectForm">
|
||||
import { ref, computed } from 'vue'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
|
||||
const props = defineProps({
|
||||
formData: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
isDetail: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
selectedManagerNames: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['open-person-picker', 'update:formData'])
|
||||
|
||||
const formRef = ref(null)
|
||||
|
||||
// 更新表单字段
|
||||
const updateField = (field, value) => {
|
||||
emit('update:formData', {
|
||||
...props.formData,
|
||||
[field]: value,
|
||||
})
|
||||
}
|
||||
|
||||
// 表单校验规则
|
||||
const rules = computed(() => ({
|
||||
planWorkload: [{ required: true, message: '请输入计划工作量', trigger: 'blur' }],
|
||||
planPersonnelList: [{ required: true, message: '请选择拟投入作业人员', trigger: 'change' }],
|
||||
planLongRentCar: [{ required: true, message: '请输入拟投入长租车数量', trigger: 'blur' }],
|
||||
planTempRentCar: [{ required: true, message: '请输入拟投入临租车数量', trigger: 'blur' }],
|
||||
}))
|
||||
|
||||
const onOpenPersonPicker = () => {
|
||||
emit('open-person-picker')
|
||||
}
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
validate: () => formRef.value?.validate(),
|
||||
clearValidate: () => formRef.value?.clearValidate(),
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.card-section {
|
||||
margin-bottom: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
overflow: hidden;
|
||||
transition: box-shadow 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
:deep(.el-card__header) {
|
||||
padding: 16px 20px;
|
||||
background-color: #fafbfc;
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
}
|
||||
|
||||
:deep(.el-card__body) {
|
||||
padding: 24px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-header {
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
color: #1f2937;
|
||||
position: relative;
|
||||
padding-left: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 4px;
|
||||
height: 16px;
|
||||
background: linear-gradient(180deg, #1677ff 0%, #4096ff 100%);
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.clickable-suffix {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,591 @@
|
|||
<template>
|
||||
<div>
|
||||
<!-- 计划投入资源情况 -->
|
||||
<el-card shadow="never" class="card-section">
|
||||
<template #header>
|
||||
<div class="card-header">计划投入资源情况</div>
|
||||
</template>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="!isDetail ? rules : {}"
|
||||
size="large"
|
||||
label-width="140"
|
||||
:disabled="isDetail"
|
||||
>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="计划工作量" prop="plannedWorkload">
|
||||
<el-input
|
||||
clearable
|
||||
maxlength="7"
|
||||
show-word-limit
|
||||
placeholder="请输入计划工作量"
|
||||
:model-value="formData.plannedWorkload"
|
||||
@update:model-value="(val) => updateField('plannedWorkload', val)"
|
||||
>
|
||||
<template #suffix>
|
||||
<span class="input-suffix">基</span>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="拟投入作业人员" prop="planPersonnelList">
|
||||
<el-input
|
||||
readonly
|
||||
class="clickable-suffix"
|
||||
@click="onOpenPersonPicker"
|
||||
placeholder="请选择作业人员"
|
||||
:model-value="selectedManagerNames"
|
||||
>
|
||||
<template #suffix>
|
||||
<el-icon class="clickable-suffix">
|
||||
<Search />
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="拟投入长租车" prop="proposedLongTimeCar">
|
||||
<el-input
|
||||
:model-value="formData.proposedLongTimeCar"
|
||||
@update:model-value="
|
||||
(val) => updateField('proposedLongTimeCar', val)
|
||||
"
|
||||
placeholder="请输入长租车数量"
|
||||
clearable
|
||||
maxlength="7"
|
||||
show-word-limit
|
||||
>
|
||||
<template #suffix>
|
||||
<span class="input-suffix">辆</span>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="拟投入临租车" prop="proposedTemporaryCar">
|
||||
<el-input
|
||||
:model-value="formData.proposedTemporaryCar"
|
||||
@update:model-value="
|
||||
(val) => updateField('proposedTemporaryCar', val)
|
||||
"
|
||||
placeholder="请输入临租车数量"
|
||||
clearable
|
||||
maxlength="7"
|
||||
show-word-limit
|
||||
>
|
||||
<template #suffix>
|
||||
<span class="input-suffix">辆</span>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 实际完成情况(默认隐藏) -->
|
||||
<el-card
|
||||
v-if="showActualCompletion"
|
||||
shadow="never"
|
||||
class="card-section"
|
||||
style="margin-top: 20px"
|
||||
>
|
||||
<template #header>
|
||||
<div class="card-header">实际完成情况</div>
|
||||
</template>
|
||||
<el-form
|
||||
ref="actualFormRef"
|
||||
:model="formData"
|
||||
:rules="!isDetail ? actualRules : {}"
|
||||
size="large"
|
||||
label-width="140"
|
||||
:disabled="isDetail"
|
||||
>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="实际入作业人员" prop="actualPersonnelList">
|
||||
<el-input
|
||||
:model-value="selectedActualManagerNames"
|
||||
placeholder="请选择作业人员"
|
||||
readonly
|
||||
@click="onOpenActualPersonPicker"
|
||||
class="clickable-suffix"
|
||||
>
|
||||
<template #suffix>
|
||||
<el-icon class="clickable-suffix">
|
||||
<Search />
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="实际入长租车" prop="actualLongTimeCar">
|
||||
<el-input
|
||||
:model-value="formData.actualLongTimeCar"
|
||||
@update:model-value="(val) => updateField('actualLongTimeCar', val)"
|
||||
placeholder="请输入长租车数量"
|
||||
clearable
|
||||
maxlength="7"
|
||||
show-word-limit
|
||||
>
|
||||
<template #suffix>
|
||||
<span class="input-suffix">辆</span>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="实际入临租车" prop="actualTemporaryCar">
|
||||
<el-input
|
||||
:model-value="formData.actualTemporaryCar"
|
||||
@update:model-value="
|
||||
(val) => updateField('actualTemporaryCar', val)
|
||||
"
|
||||
placeholder="请输入临租车数量"
|
||||
clearable
|
||||
maxlength="7"
|
||||
show-word-limit
|
||||
>
|
||||
<template #suffix>
|
||||
<span class="input-suffix">辆</span>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="完成比例" prop="completionPercentage">
|
||||
<el-input
|
||||
:model-value="calculatedCompletionPercentage"
|
||||
placeholder="自动计算"
|
||||
readonly
|
||||
disabled
|
||||
>
|
||||
<template #suffix>
|
||||
<span class="input-suffix">%</span>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="实际完成工作内容" prop="actualWorkContent">
|
||||
<el-input
|
||||
:model-value="formData.actualWorkContent"
|
||||
@update:model-value="(val) => updateField('actualWorkContent', val)"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 6, maxRows: 12 }"
|
||||
placeholder="请输入实际完成工作内容"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="实际完成工作量" prop="actualWorkload">
|
||||
<el-input
|
||||
:model-value="formData.actualWorkload"
|
||||
@update:model-value="(val) => updateField('actualWorkload', val)"
|
||||
placeholder="请输入实际完成工作量"
|
||||
clearable
|
||||
maxlength="7"
|
||||
show-word-limit
|
||||
>
|
||||
<template #suffix>
|
||||
<span class="input-suffix">基</span>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="作业计划完成情况" prop="planCompletionStatus">
|
||||
<el-select
|
||||
:model-value="formData.planCompletionStatus"
|
||||
@update:model-value="
|
||||
(val) => updateField('planCompletionStatus', val)
|
||||
"
|
||||
placeholder="请选择作业计划完成情况"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in planCompletionStatusOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="计划变更及未完成情况说明" prop="planChanges">
|
||||
<el-input
|
||||
:model-value="formData.planChanges"
|
||||
@update:model-value="(val) => updateField('planChanges', val)"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 6, maxRows: 12 }"
|
||||
placeholder="请输入计划变更及未完成情况说明"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="form-actions" v-if="!isDetail">
|
||||
<ComButton
|
||||
v-if="!showActualCompletion"
|
||||
type="primary"
|
||||
@click="showActualCompletion = true"
|
||||
>
|
||||
填写实际完成情况
|
||||
</ComButton>
|
||||
<ComButton v-else plain type="info" @click="onCancelActualCompletion">
|
||||
取消实际完成情况
|
||||
</ComButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="RunForm">
|
||||
import { ref, computed, nextTick, watch } from 'vue'
|
||||
import { Search } from '@element-plus/icons-vue'
|
||||
import ComButton from '@/components/ComButton/index.vue'
|
||||
|
||||
const props = defineProps({
|
||||
formData: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
isDetail: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
selectedManagerNames: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['open-person-picker', 'update:formData', 'open-actual-person-picker'])
|
||||
|
||||
const formRef = ref(null)
|
||||
const actualFormRef = ref(null)
|
||||
const showActualCompletion = ref(false)
|
||||
|
||||
// 作业计划完成情况选项
|
||||
const planCompletionStatusOptions = [
|
||||
{ label: '已完成', value: '1' },
|
||||
{ label: '部分完成', value: '2' },
|
||||
{ label: '未完成', value: '3' },
|
||||
{ label: '已取消', value: '4' },
|
||||
]
|
||||
|
||||
// 更新表单字段
|
||||
const updateField = (field, value) => {
|
||||
const newData = {
|
||||
...props.formData,
|
||||
[field]: value,
|
||||
}
|
||||
// 如果更新的是实际完成工作量或计划工作量,自动计算完成比例
|
||||
if (field === 'actualWorkload' || field === 'plannedWorkload') {
|
||||
newData.completionPercentage = calculateCompletionPercentage(
|
||||
newData.actualWorkload,
|
||||
newData.plannedWorkload,
|
||||
)
|
||||
}
|
||||
emit('update:formData', newData)
|
||||
}
|
||||
|
||||
// 计算完成比例:实际完成工作量 ÷ 计划完成工作量 × 100%
|
||||
const calculateCompletionPercentage = (actualWorkload, plannedWorkload) => {
|
||||
try {
|
||||
// 转换为数字
|
||||
const actual = Number(actualWorkload)
|
||||
const planned = Number(plannedWorkload)
|
||||
|
||||
// 检查是否为有效数字
|
||||
if (isNaN(actual) || isNaN(planned)) {
|
||||
return null
|
||||
}
|
||||
|
||||
// 检查计划工作量是否为0或负数
|
||||
if (planned <= 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
// 检查实际完成工作量是否为负数
|
||||
if (actual < 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
// 计算完成比例,保留2位小数
|
||||
const percentage = (actual / planned) * 100
|
||||
const roundedPercentage = Math.round(percentage * 100) / 100
|
||||
|
||||
// 如果超过100%,限制为100%
|
||||
return roundedPercentage
|
||||
} catch (error) {
|
||||
console.error('计算完成比例时出错:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// 计算完成比例(用于显示)
|
||||
const calculatedCompletionPercentage = computed(() => {
|
||||
const percentage = calculateCompletionPercentage(
|
||||
props.formData.actualWorkload,
|
||||
props.formData.plannedWorkload,
|
||||
)
|
||||
return percentage !== null ? percentage : ''
|
||||
})
|
||||
|
||||
// 监听实际完成工作量和计划工作量的变化,自动计算完成比例
|
||||
watch(
|
||||
() => [props.formData.actualWorkload, props.formData.plannedWorkload],
|
||||
([actualWorkload, plannedWorkload]) => {
|
||||
if (showActualCompletion.value) {
|
||||
const percentage = calculateCompletionPercentage(actualWorkload, plannedWorkload)
|
||||
if (percentage !== null && percentage !== props.formData.completionPercentage) {
|
||||
// 使用 emit 直接更新,避免循环调用
|
||||
emit('update:formData', {
|
||||
...props.formData,
|
||||
completionPercentage: percentage,
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
// 监听实际完成情况显示状态,显示时自动计算完成比例
|
||||
watch(
|
||||
() => showActualCompletion.value,
|
||||
(isShow) => {
|
||||
if (isShow && props.formData.actualWorkload && props.formData.plannedWorkload) {
|
||||
const percentage = calculateCompletionPercentage(
|
||||
props.formData.actualWorkload,
|
||||
props.formData.plannedWorkload,
|
||||
)
|
||||
if (percentage !== null) {
|
||||
emit('update:formData', {
|
||||
...props.formData,
|
||||
completionPercentage: percentage,
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
// 正整数正则校验
|
||||
const positiveIntegerPattern = /^[1-9]\d*$/
|
||||
// 非负整数正则校验(包括0)
|
||||
const nonNegativeIntegerPattern = /^(0|[1-9]\d*)$/
|
||||
// 百分比正则校验(0-100)
|
||||
const percentagePattern = /^(0|[1-9]\d?|100)$/
|
||||
|
||||
// 表单校验规则
|
||||
const rules = computed(() => ({
|
||||
plannedWorkload: [
|
||||
{ required: true, message: '请输入计划工作量', trigger: 'blur' },
|
||||
{ pattern: positiveIntegerPattern, message: '请输入正整数', trigger: 'blur' },
|
||||
],
|
||||
planPersonnelList: [{ required: true, message: '请选择拟投入作业人员', trigger: 'change' }],
|
||||
proposedLongTimeCar: [
|
||||
{ required: true, message: '请输入拟投入长租车数量', trigger: 'blur' },
|
||||
{ pattern: nonNegativeIntegerPattern, message: '请输入非负整数', trigger: 'blur' },
|
||||
],
|
||||
proposedTemporaryCar: [
|
||||
{ required: true, message: '请输入拟投入临租车数量', trigger: 'blur' },
|
||||
{ pattern: nonNegativeIntegerPattern, message: '请输入非负整数', trigger: 'blur' },
|
||||
],
|
||||
}))
|
||||
|
||||
// 实际完成情况校验规则
|
||||
const actualRules = computed(() => ({
|
||||
actualPersonnelList: [{ required: true, message: '请选择实际入作业人员', trigger: 'change' }],
|
||||
actualLongTimeCar: [
|
||||
{ required: true, message: '请输入实际入长租车数量', trigger: 'blur' },
|
||||
{ pattern: positiveIntegerPattern, message: '请输入非负整数', trigger: 'blur' },
|
||||
],
|
||||
actualTemporaryCar: [
|
||||
{ required: true, message: '请输入实际入临租车数量', trigger: 'blur' },
|
||||
{ pattern: positiveIntegerPattern, message: '请输入非负整数', trigger: 'blur' },
|
||||
],
|
||||
actualWorkContent: [{ required: true, message: '请输入实际完成工作内容', trigger: 'blur' }],
|
||||
actualWorkload: [
|
||||
{ required: true, message: '请输入实际完成工作量', trigger: 'blur' },
|
||||
{ pattern: positiveIntegerPattern, message: '请输入正整数', trigger: 'blur' },
|
||||
],
|
||||
completionPercentage: [
|
||||
{
|
||||
required: true,
|
||||
validator: (rule, value, callback) => {
|
||||
const percentage = calculateCompletionPercentage(
|
||||
props.formData.actualWorkload,
|
||||
props.formData.plannedWorkload,
|
||||
)
|
||||
if (percentage === null || percentage === '') {
|
||||
callback(new Error('请先填写计划工作量和实际完成工作量'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
planCompletionStatus: [
|
||||
{ required: true, message: '请选择作业计划完成情况', trigger: 'change' },
|
||||
],
|
||||
planChanges: [{ required: false, message: '请输入计划变更及未完成情况说明', trigger: 'blur' }],
|
||||
}))
|
||||
|
||||
// 实际入作业人员名称显示
|
||||
const selectedActualManagerNames = computed(() =>
|
||||
(props.formData.actualPersonnelList || []).map((item) => item.name).join('、'),
|
||||
)
|
||||
|
||||
const onOpenPersonPicker = () => {
|
||||
emit('open-person-picker', 'plan')
|
||||
}
|
||||
|
||||
const onOpenActualPersonPicker = () => {
|
||||
emit('open-person-picker', 'actual')
|
||||
}
|
||||
|
||||
// 取消实际完成情况
|
||||
const onCancelActualCompletion = () => {
|
||||
showActualCompletion.value = false
|
||||
// 清空实际完成情况的数据
|
||||
const clearedData = {
|
||||
...props.formData,
|
||||
actualPersonnelList: [],
|
||||
proposedLongTimeCar: null,
|
||||
proposedTemporaryCar: null,
|
||||
actualWorkContent: '',
|
||||
actualWorkload: null,
|
||||
completionPercentage: null,
|
||||
planCompletionStatus: null,
|
||||
planChanges: '',
|
||||
}
|
||||
emit('update:formData', clearedData)
|
||||
// 清除校验
|
||||
nextTick(() => {
|
||||
actualFormRef.value?.clearValidate()
|
||||
})
|
||||
}
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
validate: async () => {
|
||||
const results = []
|
||||
if (formRef.value) {
|
||||
results.push(await formRef.value.validate())
|
||||
}
|
||||
if (showActualCompletion.value && actualFormRef.value) {
|
||||
results.push(await actualFormRef.value.validate())
|
||||
}
|
||||
return results.every((r) => r !== false)
|
||||
},
|
||||
clearValidate: () => {
|
||||
formRef.value?.clearValidate()
|
||||
actualFormRef.value?.clearValidate()
|
||||
},
|
||||
scrollToField: (prop) => {
|
||||
if (formRef.value) {
|
||||
formRef.value.scrollToField(prop)
|
||||
}
|
||||
if (actualFormRef.value) {
|
||||
actualFormRef.value.scrollToField(prop)
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.card-section {
|
||||
margin-bottom: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
overflow: hidden;
|
||||
transition: box-shadow 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
:deep(.el-card__header) {
|
||||
padding: 16px 20px;
|
||||
background-color: #fafbfc;
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
}
|
||||
|
||||
:deep(.el-card__body) {
|
||||
padding: 24px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-header {
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
color: #1f2937;
|
||||
position: relative;
|
||||
padding-left: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 4px;
|
||||
height: 16px;
|
||||
background: linear-gradient(180deg, #1677ff 0%, #4096ff 100%);
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.clickable-suffix {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.input-suffix {
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -2,9 +2,9 @@
|
|||
<div class="app-container">
|
||||
<el-card class="top-radio">
|
||||
<el-radio-group v-model="tableType">
|
||||
<el-radio-button label="运行" value="运行" />
|
||||
<el-radio-button label="检修" value="检修" />
|
||||
<el-radio-button label="项目部" value="项目部" />
|
||||
<el-radio-button label="运行" value="0" />
|
||||
<el-radio-button label="检修" value="1" />
|
||||
<el-radio-button label="项目部" value="2" />
|
||||
</el-radio-group>
|
||||
|
||||
<ComButton type="info" plain icon="Download"> 下载统计表 </ComButton>
|
||||
|
|
@ -15,13 +15,15 @@
|
|||
:key="tableType"
|
||||
:show-toolbar="true"
|
||||
:show-action="true"
|
||||
:load-data="listPlanAPI"
|
||||
:form-columns="formColumns"
|
||||
:load-data="listDailyPlanAPI"
|
||||
:table-columns="initTableColumns"
|
||||
:action-columns="actionColumns"
|
||||
:defaultQueryParams="{ dayPlanType: tableType }"
|
||||
>
|
||||
<template #toolbar>
|
||||
<ComButton type="primary" icon="Plus" @click="onHandleAdd">新增日计划</ComButton>
|
||||
<ComButton type="primary" icon="Plus" @click="onHandleEdit">编辑调试</ComButton>
|
||||
<ComButton
|
||||
plain
|
||||
type="info"
|
||||
|
|
@ -49,6 +51,7 @@
|
|||
import { ref, computed, getCurrentInstance } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { listPlanAPI, delPlanAPI } from '@/api/planMange/plan.js'
|
||||
import { listDailyPlanAPI, delDailyPlanAPI, addDailyPlanAPI } from '@/api/planMange/dailyPlan.js'
|
||||
import config from './config'
|
||||
import ComTable from '@/components/ComTable/index.vue'
|
||||
import ComButton from '@/components/ComButton/index.vue'
|
||||
|
|
@ -62,17 +65,17 @@ const { tableColumns, tableColumns_1, tableColumns_2, dialogConfig, buildFormCol
|
|||
|
||||
const comTableRef = ref(null)
|
||||
const addFormRef = ref(null)
|
||||
const tableType = ref('运行')
|
||||
const tableType = ref('0')
|
||||
|
||||
// 搜索表单配置(当前月计划场景暂不依赖下拉接口,直接使用静态配置)
|
||||
const formColumns = computed(() => buildFormColumns())
|
||||
const initTableColumns = computed(() => {
|
||||
if (tableType.value === '运行') return [...tableColumns, ...tableColumns_1]
|
||||
if (tableType.value !== '运行') return [...tableColumns, ...tableColumns_2]
|
||||
if (tableType.value === '0') return [...tableColumns, ...tableColumns_1]
|
||||
if (tableType.value !== '0') return [...tableColumns, ...tableColumns_2]
|
||||
})
|
||||
|
||||
// 操作列
|
||||
const actionColumns = [
|
||||
const actionColumns = computed(() => [
|
||||
{
|
||||
label: '详情',
|
||||
type: 'primary',
|
||||
|
|
@ -80,7 +83,15 @@ const actionColumns = [
|
|||
handler: (row) => {
|
||||
router.push({
|
||||
path: '/plan/dailyPlanEdit/index',
|
||||
query: { id: row.planId, mode: 'detail' },
|
||||
query: {
|
||||
id: row.planId || row.dayPlanId,
|
||||
mode: 'detail',
|
||||
dayPlanType: tableType.value,
|
||||
inspectionStationName: row.inspectionStationName,
|
||||
projectName: row.projectName,
|
||||
planMajorName: row.planMajorName,
|
||||
dayPlan: row.dayPlan,
|
||||
},
|
||||
})
|
||||
},
|
||||
},
|
||||
|
|
@ -91,7 +102,15 @@ const actionColumns = [
|
|||
handler: (row) => {
|
||||
router.push({
|
||||
path: '/plan/dailyPlanEdit/index',
|
||||
query: { id: row.planId, mode: 'edit' },
|
||||
query: {
|
||||
id: row.planId || row.dayPlanId,
|
||||
mode: 'edit',
|
||||
dayPlanType: tableType.value,
|
||||
inspectionStationName: row.inspectionStationName,
|
||||
projectName: row.projectName,
|
||||
planMajorName: row.planMajorName,
|
||||
dayPlan: row.dayPlan,
|
||||
},
|
||||
})
|
||||
},
|
||||
},
|
||||
|
|
@ -101,7 +120,7 @@ const actionColumns = [
|
|||
link: true,
|
||||
handler: (row) => {
|
||||
proxy.$modal.confirm('是否确认删除该月计划?').then(async () => {
|
||||
const result = await delPlanAPI({ planId: row.planId })
|
||||
const result = await delDailyPlanAPI({ dayPlanId: row.dayPlanId })
|
||||
if (result.code === 200) {
|
||||
proxy.$modal.msgSuccess('删除成功')
|
||||
comTableRef.value?.refresh()
|
||||
|
|
@ -109,7 +128,7 @@ const actionColumns = [
|
|||
})
|
||||
},
|
||||
},
|
||||
]
|
||||
])
|
||||
|
||||
// 新增
|
||||
const onHandleAdd = () => {
|
||||
|
|
@ -122,14 +141,38 @@ const onHandleCancel = () => {
|
|||
}
|
||||
|
||||
// 保存
|
||||
const onHandleSave = () => {
|
||||
addFormRef.value.validate()
|
||||
const onHandleSave = async () => {
|
||||
await addFormRef.value.validate()
|
||||
const paramsList = addFormRef.value.getSelectedTasks().map((item) => ({
|
||||
dayPlan: addFormRef.value.getCurrentDate(),
|
||||
monthlyPlanId: item.monthlyPlanId,
|
||||
dayPlanType: tableType.value,
|
||||
riskLevel: item.riskLevel,
|
||||
}))
|
||||
|
||||
const result = await addDailyPlanAPI(paramsList)
|
||||
if (result.code === 200) {
|
||||
proxy.$modal.msgSuccess('保存成功')
|
||||
dialogConfig.outerVisible = false
|
||||
comTableRef.value?.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭弹框统一处理
|
||||
const onCloseDialogOuter = (visible) => {
|
||||
dialogConfig.outerVisible = visible
|
||||
}
|
||||
|
||||
// 编辑调试
|
||||
const onHandleEdit = () => {
|
||||
router.push({
|
||||
path: '/plan/dailyPlanEdit/index',
|
||||
query: {
|
||||
mode: 'edit',
|
||||
dayPlanType: tableType.value,
|
||||
},
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
|
|
|||
|
|
@ -76,21 +76,7 @@ import { Search } from '@element-plus/icons-vue'
|
|||
import { listMonthlyPlanPopupAPI } from '@/api/planMange/monthlyPlan'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
const props = defineProps({
|
||||
// 初始查询参数(比如从父页面传入当前月份)
|
||||
defaultMonth: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
// 加载任务列表的方法,由父组件传入
|
||||
loadTaskList: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
})
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
|
||||
const formRef = ref(null)
|
||||
const loading = ref(false)
|
||||
const tableData = ref([
|
||||
|
|
@ -135,15 +121,6 @@ const onSelectionChange = (rows) => {
|
|||
selectedRows.value = rows
|
||||
}
|
||||
|
||||
// 默认月份变化时,同步到表单
|
||||
watch(
|
||||
() => props.defaultMonth,
|
||||
(val) => {
|
||||
if (val) formData.value.month = val
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
// 暴露方法给父组件:获取选中任务、触发查询、校验
|
||||
defineExpose({
|
||||
getSelectedTasks: () => selectedRows.value,
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ export const tableColumns = [
|
|||
|
||||
export const dialogConfig = reactive({
|
||||
outerVisible: false,
|
||||
outerTitle: '新增计划',
|
||||
outerTitle: '添加计划任务',
|
||||
outerWidth: '70%', // 根据图片缩小宽度更美观
|
||||
minHeight: '70vh',
|
||||
maxHeight: '90vh',
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ const onHandleCancel = () => {
|
|||
|
||||
// 保存
|
||||
const onHandleSave = async () => {
|
||||
addFormRef.value.validate()
|
||||
await addFormRef.value.validate()
|
||||
|
||||
const paramsList = addFormRef.value.getSelectedTasks().map((item) => ({
|
||||
planManagementId: item.planManagementId,
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import path from 'path'
|
|||
import createVitePlugins from './vite/plugins'
|
||||
|
||||
// const baseUrl = 'http://192.168.0.133:58080' // 后端接口地址 超子
|
||||
const baseUrl = 'http://localhost:58080' // 后端接口地址
|
||||
// const baseUrl = 'http://192.168.0.60:58080' // 后端接口地址 福海
|
||||
// const baseUrl = 'http://localhost:58062' // 后端接口地址
|
||||
const baseUrl = 'http://192.168.0.60:58062' // 后端接口地址 福海
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(({ mode, command }) => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue