日计划完善

This commit is contained in:
BianLzhaoMin 2025-12-30 14:02:57 +08:00
parent 4d59cb2325
commit 0e9570ca37
10 changed files with 1292 additions and 206 deletions

View File

@ -115,6 +115,7 @@ const getComponentProps = (item) => {
rangeSeparator: item.rangeSeparator || '-', rangeSeparator: item.rangeSeparator || '-',
startPlaceholder: item.startPlaceholder, startPlaceholder: item.startPlaceholder,
endPlaceholder: item.endPlaceholder, endPlaceholder: item.endPlaceholder,
style: item.style,
} }
case 'month': case 'month':
return { return {
@ -133,21 +134,49 @@ const getComponentProps = (item) => {
} }
} }
// paramsList
const processFormData = (data) => {
const processedData = { ...data }
props.formColumns.forEach((item) => {
// paramsList
if (item.paramsList && Array.isArray(item.paramsList) && item.paramsList.length > 0) {
const value = processedData[item.prop]
//
if (Array.isArray(value) && value.length > 0) {
item.paramsList.forEach((paramName, index) => {
if (value[index] !== undefined && value[index] !== null && value[index] !== '') {
processedData[paramName] = value[index]
}
})
}
// month[0] month[1]
delete processedData[item.prop]
}
})
return processedData
}
// //
const handleSearch = () => { const handleSearch = () => {
emit('search', { ...formData }) const processedData = processFormData(formData)
emit('search', processedData)
} }
// //
const handleReset = () => { const handleReset = () => {
formRef.value?.resetFields() formRef.value?.resetFields()
initFormData() initFormData()
emit('reset', { ...formData }) const processedData = processFormData(formData)
emit('reset', processedData)
} }
// //
defineExpose({ defineExpose({
getFormData: () => ({ ...formData }), getFormData: () => processFormData(formData),
resetForm: handleReset, resetForm: handleReset,
formRef, formRef,
}) })

View File

@ -17,6 +17,7 @@
v-model="formData.nowDate" v-model="formData.nowDate"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
placeholder="请选择计划日期" placeholder="请选择计划日期"
@change="onHandleDateChange"
/> />
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -122,6 +123,10 @@ const onSelectionChange = (rows) => {
selectedRows.value = rows selectedRows.value = rows
} }
const onHandleDateChange = (value) => {
fetchData()
}
// //
defineExpose({ defineExpose({
getSelectedTasks: () => selectedRows.value, getSelectedTasks: () => selectedRows.value,

View File

@ -1,33 +1,16 @@
import { reactive } from 'vue' import { reactive } from 'vue'
// 静态选项(可后续替换为接口下拉)
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 },
]
// 月计划列表搜索表单配置 // 月计划列表搜索表单配置
export const buildFormColumns = () => [ export const buildFormColumns = () => [
{ {
type: 'month', type: 'date',
dateType: 'daterange',
paramsList: ['startDate', 'endDate'],
prop: 'month', prop: 'month',
placeholder: '请选择月份', style: {
width: '240px',
},
placeholder: '请选择日期',
}, },
{ {
@ -37,37 +20,42 @@ export const buildFormColumns = () => [
}, },
{ {
type: 'input', type: 'input',
prop: 'keyword', prop: 'projectName',
placeholder: '请输入项目名称', placeholder: '请输入项目名称',
}, },
{ {
type: 'input', type: 'input',
prop: 'keyword', prop: 'workContent',
placeholder: '请输入工作任务', placeholder: '请输入工作任务',
}, },
{ {
type: 'select', type: 'select',
prop: 'riskLevel', prop: 'planCompletionStatus',
placeholder: '请选择计划状态', placeholder: '请选择计划状态',
options: riskLevelOptions, options: [
{ label: '未开始', value: '未开始' },
{ label: '进行中', value: '进行中' },
{ label: '完成', value: '完成' },
],
}, },
] ]
// 月计划列表表格列 // 月计划列表表格列
export const tableColumns = [ export const tableColumns = [
{ prop: 'dayPlan', label: '日期', fixed: true, width: '140' }, { prop: 'dayPlan', label: '日期', fixed: true, width: '140' },
{ prop: 'inspectionStationName', label: '运检站', fixed: true }, { prop: 'inspectionStationName', label: '运检站', fixed: true, width: '140' },
{ prop: 'planMajorName', label: '专业', fixed: true }, { prop: 'planMajorName', label: '专业', fixed: true, width: '80' },
{ prop: 'projectName', label: '项目名称', fixed: true }, { prop: 'projectName', label: '项目名称', fixed: true, width: '140' },
{ prop: 'workContent', label: '工作任务' }, { prop: 'workContent', label: '工作任务', width: '140' },
{ prop: 'riskLevel', label: '风险等级' }, { prop: 'riskLevel', label: '风险等级', width: '80' },
{ prop: 'plannedWorkload', label: '计划工作量(基)' }, { prop: 'plannedWorkload', label: '计划工作量(基)', width: '80' },
] ]
export const tableColumns_1 = [ export const tableColumns_1 = [
{ {
prop: 'stationName', prop: 'stationName',
label: '拟投入作业人员数量', label: '拟投入作业人员数量',
fixed: false, fixed: false,
width: '80',
formatter: (row) => { formatter: (row) => {
return row.proposedPersonnelList?.filter((item) => item.dataSource == 0).length || '' return row.proposedPersonnelList?.filter((item) => item.dataSource == 0).length || ''
@ -77,7 +65,7 @@ export const tableColumns_1 = [
prop: 'majorName', prop: 'majorName',
label: '拟投入作业人员姓名', label: '拟投入作业人员姓名',
fixed: false, fixed: false,
width: '180', width: '200',
formatter: (row) => { formatter: (row) => {
return ( return (
row.proposedPersonnelList row.proposedPersonnelList
@ -91,15 +79,14 @@ export const tableColumns_1 = [
prop: 'proposedLongTimeCar', prop: 'proposedLongTimeCar',
label: '拟投入车辆', label: '拟投入车辆',
fixed: false, fixed: false,
width: '180', width: '200',
formatter: (row) => { slot: 'proposedLongTimeCar',
return `长租车${row.proposedLongTimeCar}辆,临租车${row.proposedTemporaryCar}` || ''
},
}, },
{ {
prop: 'projectName', prop: 'projectName',
label: '实际投入作业人员数量', label: '实际投入作业人员数量',
fixed: false, fixed: false,
width: '80',
formatter: (row) => { formatter: (row) => {
return row.proposedPersonnelList?.filter((item) => item.dataSource == 1).length || '' return row.proposedPersonnelList?.filter((item) => item.dataSource == 1).length || ''
}, },
@ -108,6 +95,7 @@ export const tableColumns_1 = [
prop: 'workTask', prop: 'workTask',
label: '实际投入作业人员姓名', label: '实际投入作业人员姓名',
fixed: false, fixed: false,
width: '200',
formatter: (row) => { formatter: (row) => {
return ( return (
row.proposedPersonnelList row.proposedPersonnelList
@ -121,44 +109,184 @@ export const tableColumns_1 = [
prop: 'actualLongTimeCar', prop: 'actualLongTimeCar',
label: '实际投入车辆', label: '实际投入车辆',
fixed: false, fixed: false,
width: '200',
slot: 'actualLongTimeCar',
// formatter: (row) => {
// return `长租车${row.actualLongTimeCar}辆,临租车${row.actualTemporaryCar}辆` || ''
// },
},
{ prop: 'actualWorkContent', label: '实际完成工作内容', fixed: false, width: '200' },
{ prop: 'actualWorkload', label: '实际完成工作量(基)', fixed: false, width: '80' },
{
prop: 'completionPercentage',
label: '完成比例',
fixed: false,
width: '80',
formatter: (row) => { formatter: (row) => {
return `长租车${row.actualLongTimeCar}辆,临租车${row.actualTemporaryCar}` || '' return row.completionPercentage || ''
}, },
}, },
{ prop: 'actualWorkContent', label: '实际完成工作内容', fixed: false },
{ prop: 'actualWorkload', label: '实际完成工作量(基)', fixed: false },
{ prop: 'completionPercentage', label: '完成比例', fixed: false },
{ prop: 'planCompletionStatus', label: '作业计划完成情况', fixed: false }, { prop: 'planCompletionStatus', label: '作业计划完成情况', fixed: false, width: '200' },
{ prop: 'planChanges', label: '计划变更及未完成情况说明', fixed: false }, { prop: 'planChanges', label: '计划变更及未完成情况说明', fixed: false, width: '200' },
] ]
export const tableColumns_2 = [ export const tableColumns_2 = [
{ prop: 'stationName', label: '拟投入高处作业人员数量', fixed: false },
{ prop: 'majorName', label: '高处作业人员姓名', fixed: false },
{ prop: 'businessTypeName', label: '拟投入地面作业人员数量', fixed: false },
{ prop: 'projectName', label: '地面作业人员姓名', fixed: false },
{ prop: 'workTask', label: '拟投入检修熟练工数量(分包高空作业人员)', fixed: false },
{ prop: 'riskLevelName', label: '拟投入检修辅助工数量(分包地面作业人员)', fixed: false },
{ prop: 'categoryName', label: '拟投入车辆', fixed: false },
{ prop: 'categoryName', label: '实际投入高处作业人员数量', fixed: false },
{ prop: 'categoryName', label: '高处作业人员姓名', fixed: false },
{ prop: 'categoryName', label: '实际投入地面作业人员数量', fixed: false },
{ prop: 'categoryName', label: '地面作业人员姓名', fixed: false },
{ {
prop: 'categoryName', prop: 'stationName',
label: '拟投入高处作业人员数量',
fixed: false,
width: '80',
formatter: (row) => {
return row.proposedPersonnelList?.filter((item) => item.dataSource == 2).length || ''
},
},
{
prop: 'proposedPersonnelListHigh',
label: '高处作业人员姓名',
fixed: false,
width: '200',
formatter: (row) => {
return (
row.proposedPersonnelList
?.filter((item) => item.dataSource == 2)
.map((item) => item.name)
.join(',') || ''
)
},
},
{
prop: 'proposedPersonnelListGroundNum',
label: '拟投入地面作业人员数量',
fixed: false,
width: '80',
formatter: (row) => {
return row.proposedPersonnelList?.filter((item) => item.dataSource == 3).length || ''
},
},
{
prop: 'proposedPersonnelListGround',
label: '地面作业人员姓名',
width: '200',
fixed: false,
formatter: (row) => {
return (
row.proposedPersonnelList
?.filter((item) => item.dataSource == 3)
.map((item) => item.name)
.join(',') || ''
)
},
},
{
prop: 'proposedProficientPersonnel',
label: '拟投入检修熟练工数量(分包高空作业人员)',
fixed: false,
width: '80',
},
{
prop: 'proposedAssistancePersonnel',
label: '拟投入检修辅助工数量(分包地面作业人员)',
fixed: false,
width: '80',
},
{
prop: 'proposedLongTimeCar',
label: '拟投入车辆',
fixed: false,
width: '200',
slot: 'proposedLongTimeCar',
// formatter: (row) => {
// return `长租车${row.proposedLongTimeCar}辆,临租车${row.proposedTemporaryCar}辆` || ''
// },
},
{
prop: 'proposedPersonnelListHighNum',
label: '实际投入高处作业人员数量',
fixed: false,
width: '80',
formatter: (row) => {
return row.proposedPersonnelList?.filter((item) => item.dataSource == 4).length || ''
},
},
{
prop: 'proposedPersonnelListHighName',
label: '高处作业人员姓名',
width: '200',
fixed: false,
formatter: (row) => {
return (
row.proposedPersonnelList
?.filter((item) => item.dataSource == 4)
.map((item) => item.name)
.join(',') || ''
)
},
},
{
prop: 'proposedPersonnelListNum',
label: '实际投入地面作业人员数量',
width: '80',
fixed: false,
formatter: (row) => {
return row.proposedPersonnelList?.filter((item) => item.dataSource == 5).length || ''
},
},
{
prop: 'proposedPersonnelList',
label: '地面作业人员姓名',
width: '200',
fixed: false,
formatter: (row) => {
return (
row.proposedPersonnelList
?.filter((item) => item.dataSource == 5)
.map((item) => item.name)
.join(',') || ''
)
},
},
{
prop: 'actualProficientPersonnel',
label: '实际投入检修熟练工数量(分包高空作业人员)', label: '实际投入检修熟练工数量(分包高空作业人员)',
fixed: false, fixed: false,
width: '80',
}, },
{ {
prop: 'categoryName', prop: 'actualAssistancePersonnel',
label: '实际投入检修辅助工数量(分包高空作业人员)', label: '实际投入检修辅助工数量(分包高空作业人员)',
fixed: false, fixed: false,
width: '80',
}, },
{ prop: 'categoryName', label: '实际投入车辆', fixed: false }, {
{ prop: 'categoryName', label: '实际完成工作内容', fixed: false }, prop: 'actualLongTimeCar',
{ prop: 'categoryName', label: '完成比例', fixed: false }, label: '实际投入车辆',
{ prop: 'categoryName', label: '作业计划完成情况', fixed: false }, width: '200',
{ prop: 'categoryName', label: '计划变更及未完成情况说明', fixed: false }, fixed: false,
slot: 'actualLongTimeCar',
// formatter: (row) => {
// return `长租车${row.actualLongTimeCar}辆,临租车${row.actualTemporaryCar}辆` || ''
// },
},
{
prop: 'workloadCategoryName',
label: '实际完成工作内容',
width: '200',
fixed: false,
formatter: (row) => {
return row.actualWorkloadList?.map((item) => item.workloadCategoryName).join(',') || ''
},
},
{
prop: 'completionPercentage',
label: '完成比例',
fixed: false,
width: '80',
formatter: (row) => {
return row.completionPercentage || ''
},
},
{ prop: 'planCompletionStatus', label: '作业计划完成情况', fixed: false, width: '200' },
{ prop: 'planChanges', label: '计划变更及未完成情况说明', fixed: false, width: '200' },
] ]
export const dialogConfig = reactive({ export const dialogConfig = reactive({

View File

@ -307,22 +307,34 @@ const getRepairFormData = () => ({
planChanges: '', // planChanges: '', //
}) })
// //
const getProjectFormData = () => ({ const getProjectFormData = () => ({
dayPlanId: routeParams.value.dayPlanId, dayPlanId: routeParams.value.dayPlanId,
//
inspectionStationName: routeParams.value.inspectionStationName, inspectionStationName: routeParams.value.inspectionStationName,
projectName: routeParams.value.projectName, projectName: routeParams.value.projectName,
planMajorName: routeParams.value.planMajorName, planMajorName: routeParams.value.planMajorName,
dayPlan: routeParams.value.dayPlan, dayPlan: routeParams.value.dayPlan,
// plannedWorkload: null,
// TODO: highAltitudePersonnelList: [],
planPersonnelList: [], // groundPersonnelList: [],
planPersonnel: '', // 使 proposedProficientPersonnel: null,
// proposedProficientDay: null,
actualPersonnelList: [], // proposedAssistancePersonnel: null,
actualPersonnel: '', // 使 proposedAssistanceDay: null,
// TODO: proposedLongTimeCar: null,
proposedTemporaryCar: null,
proposedSubCar: null,
actualHighAltitudePersonnelList: [],
actualGroundPersonnelList: [],
actualProficientPersonnel: null,
actualAssistancePersonnel: null,
actualLongTimeCar: null,
actualTemporaryCar: null,
actualSubCar: null,
actualWorkContent: '',
completionPercentage: null,
planCompletionStatus: null,
planChanges: '',
}) })
// //
@ -347,19 +359,17 @@ const rules = computed(() => ({}))
const onBack = () => { const onBack = () => {
proxy.$tab.closeOpenPage({ proxy.$tab.closeOpenPage({
path: '/plan/dailyPlan', path: '/plan/dailyPlan',
query: {
dayPlanType: dayPlanType.value,
},
}) })
} }
const onSubmit = async () => { const onSubmit = async () => {
try { try {
// validate Promise<boolean>
const valid = await formRef.value?.validate() const valid = await formRef.value?.validate()
console.log(valid, 'valid')
if (!valid) { if (!valid) {
console.log('校验没有通过')
//
// validate fields
return return
} }
@ -374,7 +384,7 @@ const onSubmit = async () => {
proposedPersonnelList.push({ proposedPersonnelList.push({
dayPlanId: route.query.id, dayPlanId: route.query.id,
inspectionStationName: item.inspectionStationName, inspectionStationName: item.inspectionStationName,
personnelld: item.id, personnelId: item.id,
name: item.name, name: item.name,
dataSource: 0, // dataSource: 0, //
}) })
@ -383,18 +393,18 @@ const onSubmit = async () => {
proposedPersonnelList.push({ proposedPersonnelList.push({
dayPlanId: route.query.id, dayPlanId: route.query.id,
inspectionStationName: item.inspectionStationName, inspectionStationName: item.inspectionStationName,
personnelld: item.id, personnelId: item.id,
name: item.name, name: item.name,
dataSource: 1, // dataSource: 1, //
}) })
}) })
} else if (type === '1' || type === 1) { } else if (type === '1' || type === 1 || type === '2' || type === 2) {
// / & // / &
;(formData.value.highAltitudePersonnelList || []).forEach((item) => { ;(formData.value.highAltitudePersonnelList || []).forEach((item) => {
proposedPersonnelList.push({ proposedPersonnelList.push({
dayPlanId: route.query.id, dayPlanId: route.query.id,
inspectionStationName: item.inspectionStationName, inspectionStationName: item.inspectionStationName,
personnelld: item.id, personnelId: item.id,
name: item.name, name: item.name,
dataSource: 2, // dataSource: 2, //
}) })
@ -403,7 +413,7 @@ const onSubmit = async () => {
proposedPersonnelList.push({ proposedPersonnelList.push({
dayPlanId: route.query.id, dayPlanId: route.query.id,
inspectionStationName: item.inspectionStationName, inspectionStationName: item.inspectionStationName,
personnelld: item.id, personnelId: item.id,
name: item.name, name: item.name,
dataSource: 3, // dataSource: 3, //
}) })
@ -412,7 +422,7 @@ const onSubmit = async () => {
proposedPersonnelList.push({ proposedPersonnelList.push({
dayPlanId: route.query.id, dayPlanId: route.query.id,
inspectionStationName: item.inspectionStationName, inspectionStationName: item.inspectionStationName,
personnelld: item.id, personnelId: item.id,
name: item.name, name: item.name,
dataSource: 4, // dataSource: 4, //
}) })
@ -421,7 +431,7 @@ const onSubmit = async () => {
proposedPersonnelList.push({ proposedPersonnelList.push({
dayPlanId: route.query.id, dayPlanId: route.query.id,
inspectionStationName: item.inspectionStationName, inspectionStationName: item.inspectionStationName,
personnelld: item.id, personnelId: item.id,
name: item.name, name: item.name,
dataSource: 5, // dataSource: 5, //
}) })
@ -447,17 +457,17 @@ const onSubmit = async () => {
} = formData.value } = formData.value
submitData.proposedPersonnelList = proposedPersonnelList submitData.proposedPersonnelList = proposedPersonnelList
submitData.workloadList = formData.value.actualWorkloadList submitData.dayPlanType = type
if (type === '1' || type === 1) {
submitData.workloadList = formData.value.actualWorkloadList
}
console.log('submitData日计划提交参数', submitData)
//
const result = await updateDailyPlanAPI(submitData) const result = await updateDailyPlanAPI(submitData)
if (result.code === 200) { if (result.code === 200) {
proxy.$modal.msgSuccess('保存成功') proxy.$modal.msgSuccess('保存成功')
onBack() onBack()
} }
} catch (error) { } catch (error) {
console.log(error, 'error')
return Promise.reject(error) return Promise.reject(error)
} }
} }
@ -504,9 +514,12 @@ const filteredPersons = computed(() => {
}) })
const selectedManagerNames = computed(() => { const selectedManagerNames = computed(() => {
// if (
if (dayPlanType.value === '1' || dayPlanType.value === 1) { dayPlanType.value === '1' ||
// dayPlanType.value === 1 ||
dayPlanType.value === '2' ||
dayPlanType.value === 2
) {
const highAltitude = (formData.value.highAltitudePersonnelList || []) const highAltitude = (formData.value.highAltitudePersonnelList || [])
.map((item) => item.name) .map((item) => item.name)
.join('、') .join('、')
@ -515,7 +528,6 @@ const selectedManagerNames = computed(() => {
.join('、') .join('、')
return [highAltitude, ground].filter(Boolean).join('、') || '' return [highAltitude, ground].filter(Boolean).join('、') || ''
} }
// 使 planPersonnelList
return (formData.value.planPersonnelList || []).map((item) => item.name).join('、') return (formData.value.planPersonnelList || []).map((item) => item.name).join('、')
}) })
@ -525,7 +537,6 @@ const onOpenPersonPicker = async (type = 'plan') => {
await nextTick() await nextTick()
if (personTableRef.value) { if (personTableRef.value) {
personTableRef.value.clearSelection() personTableRef.value.clearSelection()
//
let currentList = [] let currentList = []
if (type === 'plan') { if (type === 'plan') {
currentList = formData.value.planPersonnelList || [] currentList = formData.value.planPersonnelList || []
@ -612,12 +623,167 @@ const onCloseDialogOuter = (visible) => {
// //
const getDetail = async () => { const getDetail = async () => {
// TODO: API try {
// const result = await getDailyPlanDetailAPI({ dayPlanId: route.query.id }) const result = await getDailyPlanDetailAPI({ dayPlanId: route.query.id })
// if (result.code === 200 && result.data) { if (result.code === 200 && result.data) {
// const data = result.data const data = result.data
// // const type = dayPlanType.value
// }
//
const baseFields = {
dayPlanId: data.dayPlanId,
plannedWorkload: data.plannedWorkload,
proposedLongTimeCar: data.proposedLongTimeCar,
proposedTemporaryCar: data.proposedTemporaryCar,
actualLongTimeCar: data.actualLongTimeCar,
actualTemporaryCar: data.actualTemporaryCar,
actualWorkContent: data.actualWorkContent,
actualWorkload: data.actualWorkload,
completionPercentage: data.completionPercentage,
planCompletionStatus: data.planCompletionStatus,
planChanges: data.planChanges,
}
// proposedPersonnelList dataSource
const proposedPersonnelList = data.proposedPersonnelList || []
if (type === '0' || type === 0) {
// 使 planPersonnelList actualPersonnelList
baseFields.planPersonnelList = proposedPersonnelList
.filter((item) => item.dataSource === 0 || item.dataSource === '0')
.map((item) => ({
id: item.personnelId,
name: item.name || '',
inspectionStationName: item.inspectionStationName || '',
}))
baseFields.actualPersonnelList = proposedPersonnelList
.filter((item) => item.dataSource === 1 || item.dataSource === '1')
.map((item) => ({
id: item.personnelId,
name: item.name || '',
inspectionStationName: item.inspectionStationName || '',
}))
} else if (type === '1' || type === 1 || type === '2' || type === 2) {
// 使 highAltitudePersonnelListgroundPersonnelListactualHighAltitudePersonnelListactualGroundPersonnelList
baseFields.highAltitudePersonnelList = proposedPersonnelList
.filter((item) => item.dataSource === 2 || item.dataSource === '2')
.map((item) => ({
id: item.personnelId,
name: item.name || '',
inspectionStationName: item.inspectionStationName || '',
}))
baseFields.groundPersonnelList = proposedPersonnelList
.filter((item) => item.dataSource === 3 || item.dataSource === '3')
.map((item) => ({
id: item.personnelId,
name: item.name || '',
inspectionStationName: item.inspectionStationName || '',
}))
baseFields.actualHighAltitudePersonnelList = proposedPersonnelList
.filter((item) => item.dataSource === 4 || item.dataSource === '4')
.map((item) => ({
id: item.personnelId,
name: item.name || '',
inspectionStationName: item.inspectionStationName || '',
}))
baseFields.actualGroundPersonnelList = proposedPersonnelList
.filter((item) => item.dataSource === 5 || item.dataSource === '5')
.map((item) => ({
id: item.personnelId,
name: item.name || '',
inspectionStationName: item.inspectionStationName || '',
}))
//
baseFields.proposedProficientPersonnel = data.proposedProficientPersonnel
baseFields.proposedProficientDay = data.proposedProficientDay
baseFields.proposedAssistancePersonnel = data.proposedAssistancePersonnel
baseFields.proposedAssistanceDay = data.proposedAssistanceDay
baseFields.proposedSubCar = data.proposedSubCar
baseFields.actualProficientPersonnel = data.actualProficientPersonnel
baseFields.actualAssistancePersonnel = data.actualAssistancePersonnel
baseFields.actualSubCar = data.actualSubCar
// workloadList
if (type === '1' || type === 1) {
baseFields.actualWorkloadList =
data.workloadList && data.workloadList.length > 0
? data.workloadList.map((item) => ({
workloadCategoryId: item.workloadCategoryId || '',
workloadCategoryName: item.workloadCategoryName || '',
unitPrice: item.unitPrice || '',
workloadNum: item.workloadNum || '',
}))
: [
{
workloadCategoryId: '',
workloadCategoryName: '',
unitPrice: '',
workloadNum: '',
},
]
}
}
//
formData.value = {
...formData.value,
...baseFields,
}
//
let hasActualData = false
if (type === '0' || type === 0) {
//
hasActualData =
baseFields.actualPersonnelList?.length > 0 ||
baseFields.actualWorkload ||
baseFields.actualWorkContent ||
baseFields.actualLongTimeCar ||
baseFields.actualTemporaryCar ||
baseFields.planCompletionStatus
} else if (type === '1' || type === 1) {
//
hasActualData =
baseFields.actualHighAltitudePersonnelList?.length > 0 ||
baseFields.actualGroundPersonnelList?.length > 0 ||
(baseFields.actualWorkloadList?.length > 0 &&
baseFields.actualWorkloadList[0]?.workloadCategoryId) ||
baseFields.actualWorkload ||
baseFields.actualProficientPersonnel ||
baseFields.actualAssistancePersonnel ||
baseFields.actualLongTimeCar ||
baseFields.actualTemporaryCar ||
baseFields.actualSubCar ||
baseFields.planCompletionStatus
} else if (type === '2' || type === 2) {
//
hasActualData =
baseFields.actualHighAltitudePersonnelList?.length > 0 ||
baseFields.actualGroundPersonnelList?.length > 0 ||
baseFields.actualWorkContent ||
baseFields.actualWorkload ||
baseFields.actualProficientPersonnel ||
baseFields.actualAssistancePersonnel ||
baseFields.actualLongTimeCar ||
baseFields.actualTemporaryCar ||
baseFields.actualSubCar ||
baseFields.planCompletionStatus
}
if (hasActualData) {
nextTick(() => {
formRef.value?.showActualCompletionForm?.()
})
}
}
} catch (error) {
console.error('获取详情失败:', error)
}
} }
// //

View File

@ -1,82 +1,514 @@
<template> <template>
<el-card shadow="never" class="card-section"> <div>
<template #header> <el-card shadow="never" class="card-section">
<div class="card-header">投入的资源情况项目部</div> <template #header>
</template> <div class="card-header">计划投入资源情况</div>
<el-form </template>
ref="formRef" <el-form
:model="formData" ref="formRef"
:rules="!isDetail ? rules : {}" size="large"
size="large" :model="formData"
label-width="auto" label-width="180"
:disabled="isDetail" :disabled="isDetail"
> :rules="!isDetail ? rules : {}"
<!-- 项目部类型的表单字段稍后完善 --> :validate-on-rule-change="false"
<el-row :gutter="24"> >
<el-col :span="12"> <el-row :gutter="24">
<el-form-item label="计划工作量" prop="planWorkload"> <el-col :span="12">
<el-input-number <el-form-item label="计划工作量" prop="plannedWorkload">
:model-value="formData.planWorkload" <el-input
@update:model-value="(val) => updateField('planWorkload', val)" clearable
:min="0" maxlength="7"
:precision="2" show-word-limit
placeholder="请输入计划工作量" placeholder="请输入计划工作量"
style="width: 100%" :model-value="formData.plannedWorkload"
/> @update:model-value="(val) => updateField('plannedWorkload', val)"
</el-form-item> >
</el-col> <template #suffix>
<span class="input-suffix"></span>
</template>
</el-input>
</el-form-item>
</el-col>
</el-row>
<el-col :span="12"> <el-row :gutter="24">
<el-form-item label="拟投入作业人员" prop="planPersonnelList"> <el-col :span="12">
<el-input <el-form-item label="拟投入高处作业人员" prop="highAltitudePersonnelList">
:model-value="selectedManagerNames" <el-input
placeholder="请选择作业人员" readonly
readonly class="clickable-suffix"
@click="onOpenPersonPicker" @click="onOpenPersonPicker('highAltitude')"
class="clickable-suffix" placeholder="请选择高处作业人员"
> :model-value="selectedHighAltitudeNames"
<template #suffix> >
<el-icon class="clickable-suffix"> <template #suffix>
<Search /> <el-icon class="clickable-suffix">
</el-icon> <Search />
</el-icon>
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="拟投入地面作业人员" prop="groundPersonnelList">
<el-input
readonly
class="clickable-suffix"
@click="onOpenPersonPicker('ground')"
placeholder="请选择地面作业人员"
:model-value="selectedGroundNames"
>
<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="7">
<el-form-item prop="proposedProficientPersonnel">
<template #label>
<div style="display: flex; flex-direction: column">
<span>计划投入熟练工人员数量</span>
<span
style="
font-size: 12px;
color: #999;
transform: translateY(-20px);
"
>
(分包高空作业人员)
</span>
</div>
</template> </template>
</el-input> <el-input
</el-form-item> clearable
</el-col> maxlength="7"
</el-row> show-word-limit
placeholder="熟练工人员数量"
:model-value="formData.proposedProficientPersonnel"
@update:model-value="
(val) => updateField('proposedProficientPersonnel', val)
"
/>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item
label="计划投入工日"
prop="proposedProficientDay"
label-width="120"
>
<el-input
clearable
maxlength="7"
placeholder="工日"
:model-value="formData.proposedProficientDay"
@update:model-value="
(val) => updateField('proposedProficientDay', val)
"
/>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item prop="proposedAssistancePersonnel">
<template #label>
<div style="display: flex; flex-direction: column">
<span>计划投入辅助工人员数量</span>
<span
style="
font-size: 12px;
color: #999;
transform: translateY(-20px);
"
>
(分包地面作业人员)
</span>
</div>
</template>
<el-input
clearable
maxlength="7"
show-word-limit
placeholder="辅助工人员数量"
:model-value="formData.proposedAssistancePersonnel"
@update:model-value="
(val) => updateField('proposedAssistancePersonnel', val)
"
/>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item
label="计划投入工日"
prop="proposedAssistanceDay"
label-width="120"
>
<el-input
clearable
maxlength="7"
placeholder="工日"
:model-value="formData.proposedAssistanceDay"
@update:model-value="
(val) => updateField('proposedAssistanceDay', val)
"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="拟投入长租车" prop="planLongRentCar"> <el-form-item label="拟投入长租车" prop="proposedLongTimeCar">
<el-input-number <el-input
:model-value="formData.planLongRentCar" clearable
@update:model-value="(val) => updateField('planLongRentCar', val)" maxlength="7"
:min="0" show-word-limit
placeholder="请输入长租车数量" placeholder="请输入长租车数量"
style="width: 100%" :model-value="formData.proposedLongTimeCar"
/> @update:model-value="
</el-form-item> (val) => updateField('proposedLongTimeCar', val)
</el-col> "
>
<template #suffix>
<span class="input-suffix"></span>
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="拟投入临租车" prop="planTempRentCar"> <el-form-item label="拟投入临租车" prop="proposedTemporaryCar">
<el-input-number <el-input
:model-value="formData.planTempRentCar" clearable
@update:model-value="(val) => updateField('planTempRentCar', val)" maxlength="7"
:min="0" show-word-limit
placeholder="请输入临租车数量" placeholder="请输入临租车数量"
style="width: 100%" :model-value="formData.proposedTemporaryCar"
/> @update:model-value="
</el-form-item> (val) => updateField('proposedTemporaryCar', val)
</el-col> "
</el-row> >
</el-form> <template #suffix>
</el-card> <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="proposedSubCar">
<el-input
clearable
maxlength="7"
show-word-limit
placeholder="请输入分包车数量"
:model-value="formData.proposedSubCar"
@update:model-value="(val) => updateField('proposedSubCar', val)"
>
<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="180"
:disabled="isDetail"
:validate-on-rule-change="false"
>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item
label="实际投入高处作业人员"
prop="actualHighAltitudePersonnelList"
>
<el-input
readonly
class="clickable-suffix"
@click="onOpenActualPersonPicker('highAltitude')"
placeholder="请选择高处作业人员"
:model-value="selectedActualHighAltitudeNames"
>
<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="actualGroundPersonnelList">
<el-input
readonly
class="clickable-suffix"
@click="onOpenActualPersonPicker('ground')"
placeholder="请选择地面作业人员"
:model-value="selectedActualGroundNames"
>
<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 prop="actualProficientPersonnel">
<template #label>
<div style="display: flex; flex-direction: column">
<span>实际投入检修熟练工数量</span>
<span
style="
font-size: 12px;
color: #999;
transform: translateY(-20px);
"
>
(分包高空作业人员)
</span>
</div>
</template>
<el-input
clearable
maxlength="7"
show-word-limit
placeholder="熟练工人员数量"
:model-value="formData.actualProficientPersonnel"
@update:model-value="
(val) => updateField('actualProficientPersonnel', val)
"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="actualAssistancePersonnel">
<template #label>
<div style="display: flex; flex-direction: column">
<span>实际投入检修辅助工数量</span>
<span
style="
font-size: 12px;
color: #999;
transform: translateY(-20px);
"
>
(分包地面作业人员)
</span>
</div>
</template>
<el-input
clearable
maxlength="7"
show-word-limit
placeholder="辅助工人员数量"
:model-value="formData.actualAssistancePersonnel"
@update:model-value="
(val) => updateField('actualAssistancePersonnel', val)
"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="实际投入长租车" prop="actualLongTimeCar">
<el-input
clearable
maxlength="7"
show-word-limit
placeholder="请输入长租车数量"
:model-value="formData.actualLongTimeCar"
@update:model-value="(val) => updateField('actualLongTimeCar', 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="actualTemporaryCar">
<el-input
clearable
maxlength="7"
show-word-limit
placeholder="请输入临租车数量"
:model-value="formData.actualTemporaryCar"
@update:model-value="
(val) => updateField('actualTemporaryCar', val)
"
>
<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="actualSubCar">
<el-input
clearable
maxlength="7"
show-word-limit
placeholder="请输入分包车数量"
:model-value="formData.actualSubCar"
@update:model-value="(val) => updateField('actualSubCar', val)"
>
<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="actualWorkload">
<el-input
clearable
maxlength="7"
show-word-limit
placeholder="请输入实际完成工作量"
:model-value="formData.actualWorkload"
@update:model-value="(val) => updateField('actualWorkload', 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="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="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> </template>
<script setup name="ProjectForm"> <script setup name="ProjectForm">
import { ref, computed } from 'vue' import { ref, computed, nextTick, watch } from 'vue'
import { Search } from '@element-plus/icons-vue' import { Search } from '@element-plus/icons-vue'
import ComButton from '@/components/ComButton/index.vue'
const props = defineProps({ const props = defineProps({
formData: { formData: {
@ -93,34 +525,273 @@ const props = defineProps({
}, },
}) })
const emit = defineEmits(['open-person-picker', 'update:formData']) const emit = defineEmits(['open-person-picker', 'update:formData', 'open-actual-person-picker'])
const formRef = ref(null) const formRef = ref(null)
const actualFormRef = ref(null)
const showActualCompletion = ref(false)
const planCompletionStatusOptions = [
{ label: '完成', value: '完成' },
{ label: '进行中', value: '进行中' },
{ label: '未完成', value: '未完成' },
]
//
const updateField = (field, value) => { const updateField = (field, value) => {
emit('update:formData', { const newData = {
...props.formData, ...props.formData,
[field]: value, [field]: value,
}
if (field === 'actualWorkload' || field === 'plannedWorkload') {
newData.completionPercentage = calculateCompletionPercentage(
newData.actualWorkload,
newData.plannedWorkload,
)
}
emit('update:formData', newData)
}
const calculateCompletionPercentage = (actualWorkload, plannedWorkload) => {
try {
const actual = Number(actualWorkload)
const planned = Number(plannedWorkload)
if (isNaN(actual) || isNaN(planned)) {
return null
}
if (planned <= 0) {
return null
}
if (actual < 0) {
return null
}
const percentage = (actual / planned) * 100
const roundedPercentage = Math.round(percentage * 100) / 100
return roundedPercentage > 100 ? 100 : 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('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*$/
const nonNegativeIntegerPattern = /^(0|[1-9]\d*)$/
const rules = computed(() => ({
plannedWorkload: [
{ required: true, message: '请输入计划工作量', trigger: 'blur' },
{ pattern: positiveIntegerPattern, message: '请输入正整数', trigger: 'blur' },
],
highAltitudePersonnelList: [
{ required: true, message: '请选择拟投入高处作业人员', trigger: 'change' },
],
groundPersonnelList: [
{ required: true, message: '请选择拟投入地面作业人员', trigger: 'change' },
],
proposedProficientPersonnel: [
{ required: true, message: '请输入计划投入熟练工人员数量', trigger: 'blur' },
{ pattern: nonNegativeIntegerPattern, message: '请输入非负整数', trigger: 'blur' },
],
proposedProficientDay: [
{ required: true, message: '请输入计划投入工日', trigger: 'blur' },
{ pattern: positiveIntegerPattern, message: '请输入正整数', trigger: 'blur' },
],
proposedAssistancePersonnel: [
{ required: true, message: '请输入计划投入辅助工人员数量', trigger: 'blur' },
{ pattern: nonNegativeIntegerPattern, message: '请输入非负整数', trigger: 'blur' },
],
proposedAssistanceDay: [
{ required: true, message: '请输入计划投入工日', trigger: 'blur' },
{ pattern: positiveIntegerPattern, message: '请输入正整数', trigger: 'blur' },
],
proposedLongTimeCar: [
{ required: true, message: '请输入拟投入长租车数量', trigger: 'blur' },
{ pattern: nonNegativeIntegerPattern, message: '请输入非负整数', trigger: 'blur' },
],
proposedTemporaryCar: [
{ required: true, message: '请输入拟投入临租车数量', trigger: 'blur' },
{ pattern: nonNegativeIntegerPattern, message: '请输入非负整数', trigger: 'blur' },
],
proposedSubCar: [
{ required: true, message: '请输入拟投入分包车数量', trigger: 'blur' },
{ pattern: nonNegativeIntegerPattern, message: '请输入非负整数', trigger: 'blur' },
],
}))
const actualRules = computed(() => ({
actualHighAltitudePersonnelList: [
{ required: true, message: '请选择实际投入高处作业人员', trigger: 'change' },
],
actualGroundPersonnelList: [
{ required: true, message: '请选择实际投入地面作业人员', trigger: 'change' },
],
actualProficientPersonnel: [
{ required: true, message: '请输入实际投入检修熟练工数量', trigger: 'blur' },
{ pattern: nonNegativeIntegerPattern, message: '请输入非负整数', trigger: 'blur' },
],
actualAssistancePersonnel: [
{ required: true, message: '请输入实际投入检修辅助工数量', trigger: 'blur' },
{ pattern: nonNegativeIntegerPattern, message: '请输入非负整数', trigger: 'blur' },
],
actualLongTimeCar: [
{ required: true, message: '请输入实际投入长租车数量', trigger: 'blur' },
{ pattern: nonNegativeIntegerPattern, message: '请输入非负整数', trigger: 'blur' },
],
actualTemporaryCar: [
{ required: true, message: '请输入实际投入临租车数量', trigger: 'blur' },
{ pattern: nonNegativeIntegerPattern, message: '请输入非负整数', trigger: 'blur' },
],
actualSubCar: [
{ required: true, message: '请输入实际投入分包车数量', trigger: 'blur' },
{ pattern: nonNegativeIntegerPattern, 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 selectedHighAltitudeNames = computed(() =>
(props.formData.highAltitudePersonnelList || []).map((item) => item.name).join('、'),
)
const selectedGroundNames = computed(() =>
(props.formData.groundPersonnelList || []).map((item) => item.name).join('、'),
)
const selectedActualHighAltitudeNames = computed(() =>
(props.formData.actualHighAltitudePersonnelList || []).map((item) => item.name).join('、'),
)
const selectedActualGroundNames = computed(() =>
(props.formData.actualGroundPersonnelList || []).map((item) => item.name).join('、'),
)
const onOpenPersonPicker = (type) => {
emit('open-person-picker', type)
}
const onOpenActualPersonPicker = (type) => {
emit('open-person-picker', `actual_${type}`)
}
const onCancelActualCompletion = () => {
showActualCompletion.value = false
const clearedData = {
...props.formData,
actualHighAltitudePersonnelList: [],
actualGroundPersonnelList: [],
actualProficientPersonnel: null,
actualAssistancePersonnel: null,
actualLongTimeCar: null,
actualTemporaryCar: null,
actualSubCar: null,
actualWorkContent: '',
actualWorkload: null,
completionPercentage: null,
planCompletionStatus: null,
planChanges: '',
}
emit('update:formData', clearedData)
nextTick(() => {
actualFormRef.value?.clearValidate()
}) })
} }
//
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({ defineExpose({
validate: () => formRef.value?.validate(), validate: async () => {
clearValidate: () => formRef.value?.clearValidate(), 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)
}
},
showActualCompletionForm: () => {
showActualCompletion.value = true
},
}) })
</script> </script>
@ -172,4 +843,16 @@ defineExpose({
.clickable-suffix { .clickable-suffix {
cursor: pointer; cursor: pointer;
} }
.input-suffix {
color: #909399;
font-size: 14px;
padding-right: 8px;
}
.form-actions {
margin-top: 20px;
display: flex;
justify-content: flex-start;
}
</style> </style>

View File

@ -12,6 +12,7 @@
label-width="180" label-width="180"
:disabled="isDetail" :disabled="isDetail"
:rules="!isDetail ? rules : {}" :rules="!isDetail ? rules : {}"
:validate-on-rule-change="false"
> >
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="12"> <el-col :span="12">
@ -241,6 +242,7 @@
size="large" size="large"
label-width="180" label-width="180"
:disabled="isDetail" :disabled="isDetail"
:validate-on-rule-change="false"
> >
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="12"> <el-col :span="12">
@ -251,8 +253,8 @@
<el-input <el-input
readonly readonly
class="clickable-suffix" class="clickable-suffix"
@click="onOpenActualPersonPicker('highAltitude')"
placeholder="请选择高处作业人员" placeholder="请选择高处作业人员"
@click="onOpenActualPersonPicker('highAltitude')"
:model-value="selectedActualHighAltitudeNames" :model-value="selectedActualHighAltitudeNames"
> >
<template #suffix> <template #suffix>
@ -409,7 +411,7 @@
:class="{ 'hide-required': index !== 0 }" :class="{ 'hide-required': index !== 0 }"
> >
<template #label> <template #label>
<span v-if="index == 0">工作量</span> <span v-if="index == 0">实际完成工作内容</span>
<span v-else style="visibility: hidden">工作量</span> <span v-else style="visibility: hidden">工作量</span>
</template> </template>
<el-select <el-select
@ -648,7 +650,7 @@ const calculateCompletionPercentage = (actualWorkload, plannedWorkload) => {
const percentage = (actual / planned) * 100 const percentage = (actual / planned) * 100
const roundedPercentage = Math.round(percentage * 100) / 100 const roundedPercentage = Math.round(percentage * 100) / 100
return roundedPercentage return roundedPercentage > 100 ? 100 : roundedPercentage
} catch (error) { } catch (error) {
console.error('计算完成比例时出错:', error) console.error('计算完成比例时出错:', error)
return null return null
@ -911,8 +913,8 @@ const onCancelActualCompletion = () => {
...props.formData, ...props.formData,
actualHighAltitudePersonnelList: [], actualHighAltitudePersonnelList: [],
actualGroundPersonnelList: [], actualGroundPersonnelList: [],
actualSkilledWorkerNum: null, actualProficientPersonnel: null,
actualAuxiliaryWorkerNum: null, actualAssistancePersonnel: null,
actualLongTimeCar: null, actualLongTimeCar: null,
actualTemporaryCar: null, actualTemporaryCar: null,
actualSubCar: null, actualSubCar: null,
@ -960,6 +962,9 @@ defineExpose({
actualFormRef.value.scrollToField(prop) actualFormRef.value.scrollToField(prop)
} }
}, },
showActualCompletionForm: () => {
showActualCompletion.value = true
},
}) })
</script> </script>

View File

@ -12,6 +12,7 @@
size="large" size="large"
label-width="140" label-width="140"
:disabled="isDetail" :disabled="isDetail"
:validate-on-rule-change="false"
> >
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="12"> <el-col :span="12">
@ -109,10 +110,11 @@
size="large" size="large"
label-width="140" label-width="140"
:disabled="isDetail" :disabled="isDetail"
:validate-on-rule-change="false"
> >
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="实际入作业人员" prop="actualPersonnelList"> <el-form-item label="实际入作业人员" prop="actualPersonnelList">
<el-input <el-input
:model-value="selectedActualManagerNames" :model-value="selectedActualManagerNames"
placeholder="请选择作业人员" placeholder="请选择作业人员"
@ -349,7 +351,8 @@ const calculateCompletionPercentage = (actualWorkload, plannedWorkload) => {
const roundedPercentage = Math.round(percentage * 100) / 100 const roundedPercentage = Math.round(percentage * 100) / 100
// 100%100% // 100%100%
return roundedPercentage
return roundedPercentage > 100 ? 100 : roundedPercentage
} catch (error) { } catch (error) {
console.error('计算完成比例时出错:', error) console.error('计算完成比例时出错:', error)
return null return null
@ -485,8 +488,8 @@ const onCancelActualCompletion = () => {
const clearedData = { const clearedData = {
...props.formData, ...props.formData,
actualPersonnelList: [], actualPersonnelList: [],
proposedLongTimeCar: null, actualLongTimeCar: null,
proposedTemporaryCar: null, actualTemporaryCar: null,
actualWorkContent: '', actualWorkContent: '',
actualWorkload: null, actualWorkload: null,
completionPercentage: null, completionPercentage: null,
@ -524,6 +527,9 @@ defineExpose({
actualFormRef.value.scrollToField(prop) actualFormRef.value.scrollToField(prop)
} }
}, },
showActualCompletionForm: () => {
showActualCompletion.value = true
},
}) })
</script> </script>

View File

@ -23,6 +23,20 @@
:action-columns="actionColumns" :action-columns="actionColumns"
:defaultQueryParams="{ dayPlanType: tableType }" :defaultQueryParams="{ dayPlanType: tableType }"
> >
<template #proposedLongTimeCar="{ row }">
<span v-if="row.proposedLongTimeCar && row.proposedTemporaryCar">
长租车{{ row.proposedLongTimeCar }}
<br />
临租车{{ row.proposedTemporaryCar }}
</span>
</template>
<template #actualLongTimeCar="{ row }">
<span v-if="row.actualLongTimeCar && row.actualTemporaryCar">
长租车{{ row.actualLongTimeCar }}
<br />
临租车{{ row.actualTemporaryCar }}
</span>
</template>
<template #toolbar> <template #toolbar>
<ComButton type="primary" icon="Plus" @click="onHandleAdd">新增日计划</ComButton> <ComButton type="primary" icon="Plus" @click="onHandleAdd">新增日计划</ComButton>
<ComButton <ComButton
@ -50,8 +64,8 @@
</template> </template>
<script setup name="MonthlyPlan"> <script setup name="MonthlyPlan">
import { ref, computed, getCurrentInstance } from 'vue' import { ref, computed, getCurrentInstance, onMounted } from 'vue'
import { useRouter } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import { listDailyPlanAPI, delDailyPlanAPI, addDailyPlanAPI } from '@/api/planMange/dailyPlan.js' import { listDailyPlanAPI, delDailyPlanAPI, addDailyPlanAPI } from '@/api/planMange/dailyPlan.js'
import useDictStore from '@/store/modules/dict' import useDictStore from '@/store/modules/dict'
import { selectDictLabel } from '@/utils/ruoyi' import { selectDictLabel } from '@/utils/ruoyi'
@ -63,6 +77,7 @@ import ComDialog from '@/components/ComDialog/index.vue'
import AddForm from './addForm.vue' import AddForm from './addForm.vue'
const router = useRouter() const router = useRouter()
const route = useRoute()
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const dictStore = useDictStore() const dictStore = useDictStore()
@ -76,7 +91,16 @@ const {
const comTableRef = ref(null) const comTableRef = ref(null)
const addFormRef = ref(null) const addFormRef = ref(null)
const tableType = ref('0') const tableType = ref(route.query.dayPlanType || '0')
onMounted(() => {
if (route.query.dayPlanType) {
tableType.value = route.query.dayPlanType
}
})
//
const { plan_risk_level } = proxy.useDict('plan_risk_level')
// 使 // 使
const formColumns = computed(() => buildFormColumns()) const formColumns = computed(() => buildFormColumns())
@ -87,7 +111,7 @@ const createDynamicDictFormatter = (dictType, fieldName = null) => {
const value = fieldName ? row[fieldName] : cellValue const value = fieldName ? row[fieldName] : cellValue
// store // store
const dictData = dictStore.getDict(dictType) || [] const dictData = dictStore.getDict(dictType) || []
return selectDictLabel(dictData, value) return selectDictLabel(dictData, value) || value
} }
} }
@ -105,9 +129,36 @@ const tableColumns = computed(() => {
}) })
}) })
// tableColumns_2 tableType
const processedTableColumns_2 = computed(() => {
return tableColumns_2.map((column) => {
//
if (column.label === '实际完成工作内容') {
return {
...column,
formatter: (row) => {
// type === '1'使 actualWorkloadList
if (tableType.value === '1') {
return (
row.workloadList?.map((item) => item.workloadCategoryName).join(',') ||
''
)
}
// type === '2'使 actualWorkContent
if (tableType.value === '2') {
return row.actualWorkContent || ''
}
return ''
},
}
}
return column
})
})
const initTableColumns = computed(() => { const initTableColumns = computed(() => {
if (tableType.value === '0') return [...tableColumns.value, ...tableColumns_1] if (tableType.value === '0') return [...tableColumns.value, ...tableColumns_1]
if (tableType.value !== '0') return [...tableColumns.value, ...tableColumns_2] if (tableType.value !== '0') return [...tableColumns.value, ...processedTableColumns_2.value]
}) })
// //

View File

@ -58,6 +58,10 @@ export const tableColumns = [
prop: 'riskLevel', prop: 'riskLevel',
label: '风险等级', label: '风险等级',
}, },
{
prop: 'remark',
label: '备注',
},
] ]
export const dialogConfig = reactive({ export const dialogConfig = reactive({

View File

@ -15,6 +15,10 @@
<ComButton type="info" icon="Upload" pain @click="onHandleImport"> <ComButton type="info" icon="Upload" pain @click="onHandleImport">
导入计划 导入计划
</ComButton> </ComButton>
<ComButton type="info" icon="Download" pain @click="onHandleDownloadTemplate">
模板下载
</ComButton>
</template> </template>
</ComTable> </ComTable>
@ -207,6 +211,11 @@ const onHandleImport = () => {
console.log('导入计划') console.log('导入计划')
} }
//
const onHandleDownloadTemplate = () => {
console.log('模板下载')
}
// //
const onCloseDialogOuter = (visible) => { const onCloseDialogOuter = (visible) => {
dialogConfig.outerVisible = visible dialogConfig.outerVisible = visible