|
|
@@ -44,6 +44,17 @@ interface PlanRow {
|
|
|
startTime: string
|
|
|
endTime: string
|
|
|
showEndTime: boolean
|
|
|
+ [key: string]: any
|
|
|
+}
|
|
|
+
|
|
|
+interface PlanExtColumn {
|
|
|
+ name: string
|
|
|
+ identifier: string
|
|
|
+ dataType?: string
|
|
|
+ required?: number
|
|
|
+ unit?: string
|
|
|
+ defaultValue?: string | number | null
|
|
|
+ sort?: number
|
|
|
}
|
|
|
|
|
|
const message = useMessage()
|
|
|
@@ -107,9 +118,53 @@ const timestampToDateTime = (timestamp: number | string | null | undefined): str
|
|
|
return dayjs(value).format('YYYY-MM-DD HH:mm')
|
|
|
}
|
|
|
|
|
|
+const currentTableColumns = ref<PlanExtColumn[]>([])
|
|
|
+
|
|
|
+const normalizeWorkloadColumns = (res: any): PlanExtColumn[] => {
|
|
|
+ const columns = Array.isArray(res?.data) ? res.data : Array.isArray(res) ? res : []
|
|
|
+ return columns
|
|
|
+ .filter((item: PlanExtColumn) => item?.identifier)
|
|
|
+ .sort((a: PlanExtColumn, b: PlanExtColumn) => (a?.sort ?? 0) - (b?.sort ?? 0))
|
|
|
+}
|
|
|
+
|
|
|
+const isRequiredColumn = (column: PlanExtColumn) => Number(column.required) === 1
|
|
|
+
|
|
|
+const isEmptyValue = (value: unknown) =>
|
|
|
+ value === undefined || value === null || (typeof value === 'string' && value.trim() === '')
|
|
|
+
|
|
|
+const getPlanDynamicValues = (row: PlanRow) =>
|
|
|
+ currentTableColumns.value.reduce<Record<string, any>>((values, column) => {
|
|
|
+ values[column.identifier] = row[column.identifier] ?? ''
|
|
|
+ return values
|
|
|
+ }, {})
|
|
|
+
|
|
|
+const createPlanRow = (plan?: any): PlanRow => {
|
|
|
+ const row: PlanRow = {
|
|
|
+ id: plan?.id,
|
|
|
+ status: plan?.status || '',
|
|
|
+ startTime: timestampToDateTime(plan?.startTime),
|
|
|
+ endTime: timestampToDateTime(plan?.endTime),
|
|
|
+ showEndTime: plan?.status !== COMPLETED_STATUS
|
|
|
+ }
|
|
|
+
|
|
|
+ currentTableColumns.value.forEach((column) => {
|
|
|
+ row[column.identifier] = plan?.[column.identifier] ?? column.defaultValue ?? ''
|
|
|
+ })
|
|
|
+
|
|
|
+ return row
|
|
|
+}
|
|
|
+
|
|
|
const openPlanDialog = async (row: ProjectTaskRow) => {
|
|
|
currentRow.value = row
|
|
|
planList.value = []
|
|
|
+ currentTableColumns.value = []
|
|
|
+
|
|
|
+ try {
|
|
|
+ const res = await IotProjectTaskScheduleApi.getWorkload(row.id)
|
|
|
+ currentTableColumns.value = normalizeWorkloadColumns(res)
|
|
|
+ } catch {
|
|
|
+ message.error('获取部门数据失败')
|
|
|
+ }
|
|
|
|
|
|
try {
|
|
|
getWorkProgressDictOptions()
|
|
|
@@ -118,16 +173,7 @@ const openPlanDialog = async (row: ProjectTaskRow) => {
|
|
|
})
|
|
|
|
|
|
if (taskSchedules?.length) {
|
|
|
- planList.value = taskSchedules.map((plan: any) => {
|
|
|
- const status = plan.status
|
|
|
- return {
|
|
|
- id: plan.id,
|
|
|
- status,
|
|
|
- startTime: timestampToDateTime(plan.startTime),
|
|
|
- endTime: timestampToDateTime(plan.endTime),
|
|
|
- showEndTime: status !== COMPLETED_STATUS
|
|
|
- }
|
|
|
- })
|
|
|
+ planList.value = taskSchedules.map((plan: any) => createPlanRow(plan))
|
|
|
}
|
|
|
|
|
|
planDialogVisible.value = true
|
|
|
@@ -149,12 +195,7 @@ const onStatusChange = (row: PlanRow) => {
|
|
|
}
|
|
|
|
|
|
const addNewRow = () => {
|
|
|
- planList.value.push({
|
|
|
- status: '',
|
|
|
- startTime: '',
|
|
|
- endTime: '',
|
|
|
- showEndTime: true
|
|
|
- })
|
|
|
+ planList.value.push(createPlanRow())
|
|
|
}
|
|
|
|
|
|
const removeRow = (index: number) => {
|
|
|
@@ -166,8 +207,18 @@ const savePlan = async () => {
|
|
|
saveLoading.value = true
|
|
|
|
|
|
for (let index = 0; index < planList.value.length; index++) {
|
|
|
- if (!planList.value[index].status) {
|
|
|
- message.error(`第${index + 1}行请选择施工状态`)
|
|
|
+ const row = planList.value[index]
|
|
|
+
|
|
|
+ if (!row.startTime) {
|
|
|
+ message.error(`第${index + 1}行请选择开始时间`)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const emptyRequiredColumn = currentTableColumns.value.find(
|
|
|
+ (column) => isRequiredColumn(column) && isEmptyValue(row[column.identifier])
|
|
|
+ )
|
|
|
+ if (emptyRequiredColumn) {
|
|
|
+ message.error(`第${index + 1}行请填写${emptyRequiredColumn.name}`)
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
@@ -178,14 +229,16 @@ const savePlan = async () => {
|
|
|
status: item.status,
|
|
|
startTime: item.startTime ? new Date(item.startTime).getTime() : null,
|
|
|
endTime:
|
|
|
- item.status !== COMPLETED_STATUS && item.endTime ? new Date(item.endTime).getTime() : null
|
|
|
+ item.status !== COMPLETED_STATUS && item.endTime ? new Date(item.endTime).getTime() : null,
|
|
|
+ ...getPlanDynamicValues(item)
|
|
|
}))
|
|
|
|
|
|
await IotProjectTaskScheduleApi.saveTaskSchedule(submitData)
|
|
|
message.success('保存成功')
|
|
|
planDialogVisible.value = false
|
|
|
getList()
|
|
|
- } catch {
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error)
|
|
|
message.error('保存失败')
|
|
|
} finally {
|
|
|
saveLoading.value = false
|
|
|
@@ -292,15 +345,13 @@ onMounted(async () => {
|
|
|
|
|
|
<template>
|
|
|
<div
|
|
|
- class="iot-project-task-page grid grid-rows-[auto_1fr] gap-4 h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]"
|
|
|
- >
|
|
|
+ class="iot-project-task-page grid grid-rows-[auto_1fr] gap-4 h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]">
|
|
|
<el-form
|
|
|
ref="queryFormRef"
|
|
|
:model="queryParams"
|
|
|
size="default"
|
|
|
label-width="72px"
|
|
|
- class="iot-project-task-query bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-6 py-3 min-w-0"
|
|
|
- >
|
|
|
+ class="iot-project-task-query bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-6 py-3 min-w-0">
|
|
|
<div class="query-row">
|
|
|
<el-form-item label="公司" prop="companyId">
|
|
|
<el-select
|
|
|
@@ -308,14 +359,12 @@ onMounted(async () => {
|
|
|
placeholder="请选择公司"
|
|
|
clearable
|
|
|
filterable
|
|
|
- class="w-full"
|
|
|
- >
|
|
|
+ class="w-full">
|
|
|
<el-option
|
|
|
v-for="item in companyDeptList"
|
|
|
:key="item.id"
|
|
|
:label="item.name"
|
|
|
- :value="item.id"
|
|
|
- />
|
|
|
+ :value="item.id" />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="客户名称" prop="manufactureName">
|
|
|
@@ -324,8 +373,7 @@ onMounted(async () => {
|
|
|
placeholder="请输入客户名称"
|
|
|
clearable
|
|
|
class="w-full"
|
|
|
- @keyup.enter="handleQuery"
|
|
|
- />
|
|
|
+ @keyup.enter="handleQuery" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="合同名称" prop="contractName">
|
|
|
<el-input
|
|
|
@@ -333,8 +381,7 @@ onMounted(async () => {
|
|
|
placeholder="请输入合同名称"
|
|
|
clearable
|
|
|
class="w-full"
|
|
|
- @keyup.enter="handleQuery"
|
|
|
- />
|
|
|
+ @keyup.enter="handleQuery" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="合同编号" prop="contractCode">
|
|
|
<el-input
|
|
|
@@ -342,8 +389,7 @@ onMounted(async () => {
|
|
|
placeholder="请输入合同编号"
|
|
|
clearable
|
|
|
class="w-full"
|
|
|
- @keyup.enter="handleQuery"
|
|
|
- />
|
|
|
+ @keyup.enter="handleQuery" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="施工队伍" prop="deptName">
|
|
|
<el-input
|
|
|
@@ -351,8 +397,7 @@ onMounted(async () => {
|
|
|
placeholder="请输入施工队伍"
|
|
|
clearable
|
|
|
class="w-full"
|
|
|
- @keyup.enter="handleQuery"
|
|
|
- />
|
|
|
+ @keyup.enter="handleQuery" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="井号" prop="wellName">
|
|
|
<el-input
|
|
|
@@ -360,8 +405,7 @@ onMounted(async () => {
|
|
|
placeholder="请输入井号"
|
|
|
clearable
|
|
|
class="w-full"
|
|
|
- @keyup.enter="handleQuery"
|
|
|
- />
|
|
|
+ @keyup.enter="handleQuery" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="平台井" prop="platformFlag">
|
|
|
<el-select
|
|
|
@@ -369,8 +413,7 @@ onMounted(async () => {
|
|
|
placeholder="请选择平台井"
|
|
|
clearable
|
|
|
class="w-full"
|
|
|
- @change="handleQuery"
|
|
|
- >
|
|
|
+ @change="handleQuery">
|
|
|
<el-option label="全部" value="A" />
|
|
|
<el-option label="是" value="Y" />
|
|
|
<el-option label="否" value="N" />
|
|
|
@@ -384,8 +427,7 @@ onMounted(async () => {
|
|
|
start-placeholder="开始日期"
|
|
|
end-placeholder="结束日期"
|
|
|
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
|
|
|
- class="w-full"
|
|
|
- />
|
|
|
+ class="w-full" />
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item class="query-actions">
|
|
|
@@ -410,15 +452,13 @@ onMounted(async () => {
|
|
|
:width="width"
|
|
|
:height="height"
|
|
|
:max-height="height"
|
|
|
- show-border
|
|
|
- >
|
|
|
+ show-border>
|
|
|
<ZmTableColumn
|
|
|
type="index"
|
|
|
:label="t('monitor.serial')"
|
|
|
:width="70"
|
|
|
fixed="left"
|
|
|
- hide-in-column-settings
|
|
|
- />
|
|
|
+ hide-in-column-settings />
|
|
|
<ZmTableColumn prop="manufactureName" label="客户名称" min-width="180" fixed="left" />
|
|
|
<ZmTableColumn prop="contractName" label="合同名称" min-width="220" />
|
|
|
<ZmTableColumn prop="contractCode" label="合同编号" min-width="150" />
|
|
|
@@ -437,32 +477,28 @@ onMounted(async () => {
|
|
|
link
|
|
|
type="primary"
|
|
|
@click="openPlanDialog(row)"
|
|
|
- v-hasPermi="['rq:iot-project-task:update']"
|
|
|
- >
|
|
|
+ v-hasPermi="['rq:iot-project-task:update']">
|
|
|
计划
|
|
|
</el-button>
|
|
|
<el-button
|
|
|
v-if="Number(row.deptId) === REPORT_DEPT_ID"
|
|
|
link
|
|
|
type="primary"
|
|
|
- @click="openGenerateReportDialog(row)"
|
|
|
- >
|
|
|
+ @click="openGenerateReportDialog(row)">
|
|
|
生成日报
|
|
|
</el-button>
|
|
|
<el-button
|
|
|
link
|
|
|
type="primary"
|
|
|
@click="openForm('update', row.id, row.projectId)"
|
|
|
- v-hasPermi="['rq:iot-project-task:update']"
|
|
|
- >
|
|
|
+ v-hasPermi="['rq:iot-project-task:update']">
|
|
|
编辑
|
|
|
</el-button>
|
|
|
<el-button
|
|
|
link
|
|
|
type="danger"
|
|
|
@click="handleDelete(row.id)"
|
|
|
- v-hasPermi="['rq:iot-project-task:delete']"
|
|
|
- >
|
|
|
+ v-hasPermi="['rq:iot-project-task:delete']">
|
|
|
删除
|
|
|
</el-button>
|
|
|
</template>
|
|
|
@@ -483,8 +519,7 @@ onMounted(async () => {
|
|
|
:total="total"
|
|
|
layout="total, sizes, prev, pager, next, jumper"
|
|
|
@size-change="handleSizeChange"
|
|
|
- @current-change="handleCurrentChange"
|
|
|
- />
|
|
|
+ @current-change="handleCurrentChange" />
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -492,8 +527,7 @@ onMounted(async () => {
|
|
|
<el-dialog
|
|
|
v-model="planDialogVisible"
|
|
|
:title="`${currentRow?.contractName || ''} - ${currentRow?.wellName || ''} - 任务计划`"
|
|
|
- width="80%"
|
|
|
- >
|
|
|
+ width="80%">
|
|
|
<div class="mb-15px">
|
|
|
<el-button type="primary" @click="addNewRow">
|
|
|
<Icon icon="ep:plus" class="mr-5px" />新增行
|
|
|
@@ -506,24 +540,22 @@ onMounted(async () => {
|
|
|
{{ scope.$index + 1 }}
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="施工状态" min-width="200">
|
|
|
+ <!-- <el-table-column label="施工状态" min-width="200">
|
|
|
<template #default="scope">
|
|
|
<el-select
|
|
|
v-model="scope.row.status"
|
|
|
placeholder="请选择施工状态"
|
|
|
clearable
|
|
|
class="w-full"
|
|
|
- @change="onStatusChange(scope.row)"
|
|
|
- >
|
|
|
+ @change="onStatusChange(scope.row)">
|
|
|
<el-option
|
|
|
v-for="dict in workProgressDictOptions"
|
|
|
:key="dict.value"
|
|
|
:label="dict.label"
|
|
|
- :value="dict.value"
|
|
|
- />
|
|
|
+ :value="dict.value" />
|
|
|
</el-select>
|
|
|
</template>
|
|
|
- </el-table-column>
|
|
|
+ </el-table-column> -->
|
|
|
<el-table-column label="开始时间" min-width="200">
|
|
|
<template #default="scope">
|
|
|
<el-date-picker
|
|
|
@@ -532,8 +564,7 @@ onMounted(async () => {
|
|
|
placeholder="选择开始时间"
|
|
|
value-format="YYYY-MM-DD HH:mm"
|
|
|
format="YYYY-MM-DD HH:mm"
|
|
|
- class="w-full"
|
|
|
- />
|
|
|
+ class="w-full" />
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column label="结束时间" min-width="200">
|
|
|
@@ -545,10 +576,31 @@ onMounted(async () => {
|
|
|
placeholder="选择结束时间"
|
|
|
value-format="YYYY-MM-DD HH:mm"
|
|
|
format="YYYY-MM-DD HH:mm"
|
|
|
- class="w-full"
|
|
|
- />
|
|
|
+ class="w-full" />
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
+
|
|
|
+ <el-table-column
|
|
|
+ min-width="100"
|
|
|
+ v-for="item in currentTableColumns"
|
|
|
+ :key="item.identifier"
|
|
|
+ :prop="item.identifier">
|
|
|
+ <template #header>
|
|
|
+ <span>
|
|
|
+ <span v-if="isRequiredColumn(item)" class="required-mark">*</span>
|
|
|
+ {{ item.unit ? `${item.name}(${item.unit})` : item.name }}
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ <template #default="scope">
|
|
|
+ <!-- <el-input type="number" v-model="scope.row[item.identifier]" placeholder="请输入" /> -->
|
|
|
+ <el-input-number
|
|
|
+ style="width: 150px"
|
|
|
+ v-model="scope.row[item.identifier]"
|
|
|
+ :min="0"
|
|
|
+ placeholder="请输入" />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
<el-table-column label="操作" width="100" align="center">
|
|
|
<template #default="scope">
|
|
|
<el-button link type="danger" @click="removeRow(scope.$index)">删除</el-button>
|
|
|
@@ -573,8 +625,7 @@ onMounted(async () => {
|
|
|
placeholder="请选择日期"
|
|
|
value-format="YYYY-MM-DD"
|
|
|
format="YYYY-MM-DD"
|
|
|
- class="w-full!"
|
|
|
- />
|
|
|
+ class="w-full!" />
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
|
|
|
@@ -585,8 +636,7 @@ onMounted(async () => {
|
|
|
size="default"
|
|
|
type="primary"
|
|
|
:loading="generateReportLoading"
|
|
|
- @click="submitGenerateReport"
|
|
|
- >
|
|
|
+ @click="submitGenerateReport">
|
|
|
确定
|
|
|
</el-button>
|
|
|
</span>
|
|
|
@@ -603,8 +653,7 @@ onMounted(async () => {
|
|
|
placeholder="请选择日期"
|
|
|
value-format="YYYY-MM-DD"
|
|
|
format="YYYY-MM-DD"
|
|
|
- class="w-full!"
|
|
|
- />
|
|
|
+ class="w-full!" />
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
|
|
|
@@ -615,8 +664,7 @@ onMounted(async () => {
|
|
|
size="default"
|
|
|
type="primary"
|
|
|
@click="submitGenerateReport"
|
|
|
- :loading="generateReportLoading"
|
|
|
- >
|
|
|
+ :loading="generateReportLoading">
|
|
|
确定
|
|
|
</el-button>
|
|
|
</span>
|
|
|
@@ -656,6 +704,11 @@ onMounted(async () => {
|
|
|
margin-bottom: 0;
|
|
|
}
|
|
|
|
|
|
+.required-mark {
|
|
|
+ margin-right: 2px;
|
|
|
+ color: var(--el-color-danger);
|
|
|
+}
|
|
|
+
|
|
|
@media (width >= 2200px) {
|
|
|
.query-actions {
|
|
|
grid-column: 4;
|