|  | @@ -0,0 +1,1168 @@
 | 
	
		
			
				|  |  | +<template>
 | 
	
		
			
				|  |  | +  <ContentWrap v-loading="formLoading">
 | 
	
		
			
				|  |  | +    <!-- 第一部分:日报标题 -->
 | 
	
		
			
				|  |  | +    <div class="daily-report-title">
 | 
	
		
			
				|  |  | +      <h2>{{ isApprovalMode ? dailyReportApprovalTitle : dailyReportTitle }}</h2>
 | 
	
		
			
				|  |  | +      <!-- 在审批模式下显示审批状态提示 -->
 | 
	
		
			
				|  |  | +      <div v-if="isApprovalMode" class="approval-notice">
 | 
	
		
			
				|  |  | +        <el-alert title="审批模式:所有字段均为只读" type="info" :closable="false" />
 | 
	
		
			
				|  |  | +      </div>
 | 
	
		
			
				|  |  | +    </div>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    <!-- 第二部分:项目/任务信息 -->
 | 
	
		
			
				|  |  | +    <ContentWrap>
 | 
	
		
			
				|  |  | +      <div class="info-table" style="margin-top: 1em">
 | 
	
		
			
				|  |  | +        <!-- 表格行 -->
 | 
	
		
			
				|  |  | +        <div class="table-row">
 | 
	
		
			
				|  |  | +          <div class="table-cell">
 | 
	
		
			
				|  |  | +            <div class="cell-content">
 | 
	
		
			
				|  |  | +              <span class="cell-label">甲方:</span>
 | 
	
		
			
				|  |  | +              <!-- 甲方字段:添加 single-line-ellipsis 类 + title 绑定完整内容 -->
 | 
	
		
			
				|  |  | +              <span
 | 
	
		
			
				|  |  | +                class="cell-value single-line-ellipsis"
 | 
	
		
			
				|  |  | +                :title="dailyReportData.manufactureName || '-'"
 | 
	
		
			
				|  |  | +              >
 | 
	
		
			
				|  |  | +              {{ dailyReportData.manufactureName || '-' }}
 | 
	
		
			
				|  |  | +            </span>
 | 
	
		
			
				|  |  | +            </div>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +          <div class="table-cell">
 | 
	
		
			
				|  |  | +            <div class="cell-content">
 | 
	
		
			
				|  |  | +              <span class="cell-label">合同号:</span>
 | 
	
		
			
				|  |  | +              <span class="cell-value">{{ dailyReportData.contractName || '-' }}</span>
 | 
	
		
			
				|  |  | +            </div>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +          <div class="table-cell">
 | 
	
		
			
				|  |  | +            <div class="cell-content">
 | 
	
		
			
				|  |  | +              <span class="cell-label">井号:</span>
 | 
	
		
			
				|  |  | +              <span class="cell-value">{{ dailyReportData.wellName || dailyReportData.taskName || '-' }}</span>
 | 
	
		
			
				|  |  | +            </div>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        <div class="table-row">
 | 
	
		
			
				|  |  | +          <div class="table-cell">
 | 
	
		
			
				|  |  | +            <div class="cell-content">
 | 
	
		
			
				|  |  | +              <span class="cell-label">施工队伍:</span>
 | 
	
		
			
				|  |  | +              <span class="cell-value">{{ dailyReportData.deptName || '-' }}</span>
 | 
	
		
			
				|  |  | +            </div>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +          <div class="table-cell">
 | 
	
		
			
				|  |  | +            <div class="cell-content">
 | 
	
		
			
				|  |  | +              <span class="cell-label">施工地点:</span>
 | 
	
		
			
				|  |  | +              <span class="cell-value">{{ dailyReportData.location || '-' }}</span>
 | 
	
		
			
				|  |  | +            </div>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +          <div class="table-cell">
 | 
	
		
			
				|  |  | +            <div class="cell-content">
 | 
	
		
			
				|  |  | +              <span class="cell-label">工艺:</span>
 | 
	
		
			
				|  |  | +              <span class="cell-value">{{ dailyReportData.techniqueNames || '-' }}</span>
 | 
	
		
			
				|  |  | +            </div>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        <div class="table-row">
 | 
	
		
			
				|  |  | +          <div class="table-cell">
 | 
	
		
			
				|  |  | +            <div class="cell-content">
 | 
	
		
			
				|  |  | +              <span class="cell-label">搬迁日期:</span>
 | 
	
		
			
				|  |  | +              <span class="cell-value">{{ formatDate(dailyReportData.dpDate) || '-' }}</span>
 | 
	
		
			
				|  |  | +            </div>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +          <div class="table-cell">
 | 
	
		
			
				|  |  | +            <div class="cell-content">
 | 
	
		
			
				|  |  | +              <span class="cell-label">开工日期:</span>
 | 
	
		
			
				|  |  | +              <span class="cell-value">{{ formatDate(dailyReportData.sgDate) || '-' }}</span>
 | 
	
		
			
				|  |  | +            </div>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +          <div class="table-cell">
 | 
	
		
			
				|  |  | +            <div class="cell-content">
 | 
	
		
			
				|  |  | +              <span class="cell-label">完工日期:</span>
 | 
	
		
			
				|  |  | +              <span class="cell-value">{{ formatDate(dailyReportData.wgDate) || '-' }}</span>
 | 
	
		
			
				|  |  | +            </div>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        <div class="table-row">
 | 
	
		
			
				|  |  | +          <div class="table-cell">
 | 
	
		
			
				|  |  | +            <div class="cell-content">
 | 
	
		
			
				|  |  | +              <span class="cell-label">施工周期D:</span>
 | 
	
		
			
				|  |  | +              <span class="cell-value">{{ constructionPeriod || 0 }}</span>
 | 
	
		
			
				|  |  | +            </div>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +          <div class="table-cell">
 | 
	
		
			
				|  |  | +            <div class="cell-content">
 | 
	
		
			
				|  |  | +              <span class="cell-label">停待时间D:</span>
 | 
	
		
			
				|  |  | +              <span class="cell-value">{{ dailyReportData.faultDowntime || 0 }}</span>
 | 
	
		
			
				|  |  | +            </div>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +          <div class="table-cell">
 | 
	
		
			
				|  |  | +            <div class="cell-content">
 | 
	
		
			
				|  |  | +              <span class="cell-label">带班干部:</span>
 | 
	
		
			
				|  |  | +              <span class="cell-value">{{ dailyReportData.responsiblePersonNames || '-' }}</span>
 | 
	
		
			
				|  |  | +            </div>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        <!-- 第五行:设备配置(单独一行) -->
 | 
	
		
			
				|  |  | +        <div class="table-row">
 | 
	
		
			
				|  |  | +          <div class="table-cell full-width">
 | 
	
		
			
				|  |  | +            <div class="cell-content">
 | 
	
		
			
				|  |  | +              <span class="cell-label">设备配置:</span>
 | 
	
		
			
				|  |  | +              <span class="cell-value indent-multiline">{{ dailyReportData.deviceNames || '-' }}</span>
 | 
	
		
			
				|  |  | +            </div>
 | 
	
		
			
				|  |  | +          </div>
 | 
	
		
			
				|  |  | +        </div>
 | 
	
		
			
				|  |  | +      </div>
 | 
	
		
			
				|  |  | +    </ContentWrap>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    <!-- 第三部分:日报填报表单 -->
 | 
	
		
			
				|  |  | +    <ContentWrap class="section-padding">
 | 
	
		
			
				|  |  | +      <el-form
 | 
	
		
			
				|  |  | +        ref="formRef"
 | 
	
		
			
				|  |  | +        :model="formData"
 | 
	
		
			
				|  |  | +        :rules="isApprovalMode ? {} : formRules"
 | 
	
		
			
				|  |  | +        v-loading="formLoading"
 | 
	
		
			
				|  |  | +        style="margin-top: 1em"
 | 
	
		
			
				|  |  | +        label-width="200px"
 | 
	
		
			
				|  |  | +        :disabled="isApprovalMode"
 | 
	
		
			
				|  |  | +      >
 | 
	
		
			
				|  |  | +        <!-- 第一行:时间节点、施工状态 -->
 | 
	
		
			
				|  |  | +        <el-row :gutter="30">
 | 
	
		
			
				|  |  | +          <el-col :span="12">
 | 
	
		
			
				|  |  | +            <el-form-item label="时间节点" prop="timeRange">
 | 
	
		
			
				|  |  | +              <el-time-picker
 | 
	
		
			
				|  |  | +                is-range
 | 
	
		
			
				|  |  | +                v-model="formData.timeRange"
 | 
	
		
			
				|  |  | +                range-separator="至"
 | 
	
		
			
				|  |  | +                start-placeholder="开始时间"
 | 
	
		
			
				|  |  | +                end-placeholder="结束时间"
 | 
	
		
			
				|  |  | +                placeholder="选择时间范围"
 | 
	
		
			
				|  |  | +                style="width: 100%"
 | 
	
		
			
				|  |  | +                :readonly="isApprovalMode"
 | 
	
		
			
				|  |  | +              />
 | 
	
		
			
				|  |  | +            </el-form-item>
 | 
	
		
			
				|  |  | +          </el-col>
 | 
	
		
			
				|  |  | +          <el-col :span="12">
 | 
	
		
			
				|  |  | +            <el-form-item label="施工状态" prop="rdStatus">
 | 
	
		
			
				|  |  | +              <el-select v-model="formData.rdStatus" placeholder="请选择施工状态" style="width: 100%" :disabled="isApprovalMode">
 | 
	
		
			
				|  |  | +                <el-option
 | 
	
		
			
				|  |  | +                  v-for="dict in rdStatusOptions"
 | 
	
		
			
				|  |  | +                  :key="dict.value"
 | 
	
		
			
				|  |  | +                  :label="dict.label"
 | 
	
		
			
				|  |  | +                  :value="dict.value"
 | 
	
		
			
				|  |  | +                />
 | 
	
		
			
				|  |  | +              </el-select>
 | 
	
		
			
				|  |  | +            </el-form-item>
 | 
	
		
			
				|  |  | +          </el-col>
 | 
	
		
			
				|  |  | +        </el-row>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        <!-- 第二行:施工工艺 -->
 | 
	
		
			
				|  |  | +        <el-row>
 | 
	
		
			
				|  |  | +          <el-col :span="24">
 | 
	
		
			
				|  |  | +            <el-form-item label="施工工艺" prop="techniqueIds">
 | 
	
		
			
				|  |  | +              <el-select v-model="formData.techniqueIds" placeholder="请选择施工工艺"
 | 
	
		
			
				|  |  | +                         style="width: 100%" multiple :disabled="isApprovalMode">
 | 
	
		
			
				|  |  | +                <el-option
 | 
	
		
			
				|  |  | +                  v-for="dict in techniqueOptions"
 | 
	
		
			
				|  |  | +                  :key="dict.value"
 | 
	
		
			
				|  |  | +                  :label="dict.label"
 | 
	
		
			
				|  |  | +                  :value="dict.value"
 | 
	
		
			
				|  |  | +                />
 | 
	
		
			
				|  |  | +              </el-select>
 | 
	
		
			
				|  |  | +            </el-form-item>
 | 
	
		
			
				|  |  | +          </el-col>
 | 
	
		
			
				|  |  | +        </el-row>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        <!-- 动态属性区域:施工工艺与当日生产动态之间 -->
 | 
	
		
			
				|  |  | +        <el-row v-if="dynamicAttrs.length > 0" :gutter="30">
 | 
	
		
			
				|  |  | +          <el-col
 | 
	
		
			
				|  |  | +            v-for="attr in dynamicAttrs"
 | 
	
		
			
				|  |  | +            :key="attr.id"
 | 
	
		
			
				|  |  | +            :span="attr.dataType === 'textarea' ? 24 : 12"
 | 
	
		
			
				|  |  | +          >
 | 
	
		
			
				|  |  | +            <el-form-item
 | 
	
		
			
				|  |  | +              :label="attr.name + (attr.unit ? `(${attr.unit})` : '')"
 | 
	
		
			
				|  |  | +              :prop="'dynamicFields.' + attr.identifier"
 | 
	
		
			
				|  |  | +              :rules="isApprovalMode ? [] : getDynamicAttrRules(attr)"
 | 
	
		
			
				|  |  | +            >
 | 
	
		
			
				|  |  | +              <!-- 文本类型 -->
 | 
	
		
			
				|  |  | +              <el-input
 | 
	
		
			
				|  |  | +                v-if="attr.dataType === 'text'"
 | 
	
		
			
				|  |  | +                v-model="formData.dynamicFields[attr.identifier]"
 | 
	
		
			
				|  |  | +                :placeholder="`请输入${attr.name}`"
 | 
	
		
			
				|  |  | +                :readonly="isApprovalMode"
 | 
	
		
			
				|  |  | +              />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +              <!-- 文本域类型 -->
 | 
	
		
			
				|  |  | +              <el-input
 | 
	
		
			
				|  |  | +                v-else-if="attr.dataType === 'textarea'"
 | 
	
		
			
				|  |  | +                v-model="formData.dynamicFields[attr.identifier]"
 | 
	
		
			
				|  |  | +                :placeholder="`请输入${attr.name}`"
 | 
	
		
			
				|  |  | +                type="textarea"
 | 
	
		
			
				|  |  | +                :rows="3"
 | 
	
		
			
				|  |  | +                :readonly="isApprovalMode"
 | 
	
		
			
				|  |  | +              />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +              <!-- 数字类型 -->
 | 
	
		
			
				|  |  | +              <el-input
 | 
	
		
			
				|  |  | +                v-else-if="attr.dataType === 'double'"
 | 
	
		
			
				|  |  | +                v-model="formData.dynamicFields[attr.identifier]"
 | 
	
		
			
				|  |  | +                :placeholder="`请输入${attr.name}`"
 | 
	
		
			
				|  |  | +                type="number"
 | 
	
		
			
				|  |  | +                :min="attr.minValue || undefined"
 | 
	
		
			
				|  |  | +                :max="attr.maxValue || undefined"
 | 
	
		
			
				|  |  | +                :readonly="isApprovalMode"
 | 
	
		
			
				|  |  | +              />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +              <!-- 日期类型 -->
 | 
	
		
			
				|  |  | +              <el-date-picker
 | 
	
		
			
				|  |  | +                v-else-if="attr.dataType === 'date'"
 | 
	
		
			
				|  |  | +                v-model="formData.dynamicFields[attr.identifier]"
 | 
	
		
			
				|  |  | +                type="date"
 | 
	
		
			
				|  |  | +                value-format="x"
 | 
	
		
			
				|  |  | +                :placeholder="`选择${attr.name}`"
 | 
	
		
			
				|  |  | +                style="width: 100%"
 | 
	
		
			
				|  |  | +                :readonly="isApprovalMode"
 | 
	
		
			
				|  |  | +              />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +              <!-- 默认文本输入 -->
 | 
	
		
			
				|  |  | +              <el-input
 | 
	
		
			
				|  |  | +                v-else
 | 
	
		
			
				|  |  | +                v-model="formData.dynamicFields[attr.identifier]"
 | 
	
		
			
				|  |  | +                :placeholder="`请输入${attr.name}`"
 | 
	
		
			
				|  |  | +                :readonly="isApprovalMode"
 | 
	
		
			
				|  |  | +              />
 | 
	
		
			
				|  |  | +            </el-form-item>
 | 
	
		
			
				|  |  | +          </el-col>
 | 
	
		
			
				|  |  | +        </el-row>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        <!-- 第三行:当日生产动态 -->
 | 
	
		
			
				|  |  | +        <el-row>
 | 
	
		
			
				|  |  | +          <el-col :span="24">
 | 
	
		
			
				|  |  | +            <el-form-item label="当日生产动态" prop="productionStatus">
 | 
	
		
			
				|  |  | +              <el-input
 | 
	
		
			
				|  |  | +                v-model="formData.productionStatus"
 | 
	
		
			
				|  |  | +                type="textarea"
 | 
	
		
			
				|  |  | +                :rows="3"
 | 
	
		
			
				|  |  | +                placeholder="请输入当日生产动态"
 | 
	
		
			
				|  |  | +                :readonly="isApprovalMode"
 | 
	
		
			
				|  |  | +              />
 | 
	
		
			
				|  |  | +            </el-form-item>
 | 
	
		
			
				|  |  | +          </el-col>
 | 
	
		
			
				|  |  | +        </el-row>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        <!-- 第四行:下步工作计划 -->
 | 
	
		
			
				|  |  | +        <el-row>
 | 
	
		
			
				|  |  | +          <el-col :span="24">
 | 
	
		
			
				|  |  | +            <el-form-item label="下步工作计划" prop="nextPlan">
 | 
	
		
			
				|  |  | +              <el-input
 | 
	
		
			
				|  |  | +                v-model="formData.nextPlan"
 | 
	
		
			
				|  |  | +                type="textarea"
 | 
	
		
			
				|  |  | +                :rows="3"
 | 
	
		
			
				|  |  | +                placeholder="请输入下步工作计划"
 | 
	
		
			
				|  |  | +                :readonly="isApprovalMode"
 | 
	
		
			
				|  |  | +              />
 | 
	
		
			
				|  |  | +            </el-form-item>
 | 
	
		
			
				|  |  | +          </el-col>
 | 
	
		
			
				|  |  | +        </el-row>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        <!-- 第五行:外租设备 -->
 | 
	
		
			
				|  |  | +        <el-row>
 | 
	
		
			
				|  |  | +          <el-col :span="24">
 | 
	
		
			
				|  |  | +            <el-form-item label="外租设备" prop="externalRental">
 | 
	
		
			
				|  |  | +              <el-input
 | 
	
		
			
				|  |  | +                v-model="formData.externalRental"
 | 
	
		
			
				|  |  | +                type="textarea"
 | 
	
		
			
				|  |  | +                :rows="3"
 | 
	
		
			
				|  |  | +                placeholder="请输入外租设备信息"
 | 
	
		
			
				|  |  | +                :readonly="isApprovalMode"
 | 
	
		
			
				|  |  | +              />
 | 
	
		
			
				|  |  | +            </el-form-item>
 | 
	
		
			
				|  |  | +          </el-col>
 | 
	
		
			
				|  |  | +        </el-row>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        <!-- 第六行:上传附件 -->
 | 
	
		
			
				|  |  | +        <el-row>
 | 
	
		
			
				|  |  | +          <el-col :span="24">
 | 
	
		
			
				|  |  | +            <el-form-item label="上传附件">
 | 
	
		
			
				|  |  | +              <!-- 文件上传组件 -->
 | 
	
		
			
				|  |  | +              <FileUpload
 | 
	
		
			
				|  |  | +                v-if="!isApprovalMode"
 | 
	
		
			
				|  |  | +                ref="fileUploadRef"
 | 
	
		
			
				|  |  | +                :device-id="deviceId"
 | 
	
		
			
				|  |  | +                :show-folder-button="false"
 | 
	
		
			
				|  |  | +                @upload-success="handleUploadSuccess"
 | 
	
		
			
				|  |  | +              />
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +              <!-- 已上传附件列表显示 -->
 | 
	
		
			
				|  |  | +              <div v-if="formData.attachments && formData.attachments.length > 0" class="attachment-list">
 | 
	
		
			
				|  |  | +                <div
 | 
	
		
			
				|  |  | +                  v-for="(attachment, index) in formData.attachments"
 | 
	
		
			
				|  |  | +                  :key="attachment.id || index"
 | 
	
		
			
				|  |  | +                  class="attachment-item"
 | 
	
		
			
				|  |  | +                >
 | 
	
		
			
				|  |  | +                  <span class="attachment-name">{{ attachment.filename }}</span>
 | 
	
		
			
				|  |  | +                  <el-button
 | 
	
		
			
				|  |  | +                    v-if="!isApprovalMode"
 | 
	
		
			
				|  |  | +                    type="danger"
 | 
	
		
			
				|  |  | +                    link
 | 
	
		
			
				|  |  | +                    size="small"
 | 
	
		
			
				|  |  | +                    @click="removeAttachment(index)"
 | 
	
		
			
				|  |  | +                  >
 | 
	
		
			
				|  |  | +                    删除
 | 
	
		
			
				|  |  | +                  </el-button>
 | 
	
		
			
				|  |  | +                </div>
 | 
	
		
			
				|  |  | +              </div>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +              <!-- 审批模式下只显示附件列表 -->
 | 
	
		
			
				|  |  | +              <div v-else-if="isApprovalMode && (!formData.attachments || formData.attachments.length === 0)" class="no-attachment">
 | 
	
		
			
				|  |  | +                无附件
 | 
	
		
			
				|  |  | +              </div>
 | 
	
		
			
				|  |  | +            </el-form-item>
 | 
	
		
			
				|  |  | +          </el-col>
 | 
	
		
			
				|  |  | +        </el-row>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      </el-form>
 | 
	
		
			
				|  |  | +    </ContentWrap>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    <!-- 第四部分:审批意见 - 只在审批模式下显示 -->
 | 
	
		
			
				|  |  | +    <ContentWrap class="section-padding" v-if="isApprovalMode">
 | 
	
		
			
				|  |  | +      <el-form
 | 
	
		
			
				|  |  | +        ref="approvalFormRef"
 | 
	
		
			
				|  |  | +        :model="approvalForm"
 | 
	
		
			
				|  |  | +        style="margin-top: 1em"
 | 
	
		
			
				|  |  | +        label-width="200px"
 | 
	
		
			
				|  |  | +      >
 | 
	
		
			
				|  |  | +        <el-row>
 | 
	
		
			
				|  |  | +          <el-col :span="24">
 | 
	
		
			
				|  |  | +            <el-form-item label="审批意见" prop="opinion">
 | 
	
		
			
				|  |  | +              <el-input
 | 
	
		
			
				|  |  | +                v-model="approvalForm.opinion"
 | 
	
		
			
				|  |  | +                type="textarea"
 | 
	
		
			
				|  |  | +                :rows="4"
 | 
	
		
			
				|  |  | +                placeholder="请输入审批意见"
 | 
	
		
			
				|  |  | +                maxlength="500"
 | 
	
		
			
				|  |  | +                show-word-limit
 | 
	
		
			
				|  |  | +              />
 | 
	
		
			
				|  |  | +            </el-form-item>
 | 
	
		
			
				|  |  | +          </el-col>
 | 
	
		
			
				|  |  | +        </el-row>
 | 
	
		
			
				|  |  | +      </el-form>
 | 
	
		
			
				|  |  | +    </ContentWrap>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    <!-- 操作按钮 -->
 | 
	
		
			
				|  |  | +    <ContentWrap class="section-padding" v-if="!isApprovalMode">
 | 
	
		
			
				|  |  | +      <el-form>
 | 
	
		
			
				|  |  | +        <el-form-item style="float: right">
 | 
	
		
			
				|  |  | +          <el-button @click="submitForm" type="primary" :disabled="formLoading">
 | 
	
		
			
				|  |  | +            {{ t('common.save') }}
 | 
	
		
			
				|  |  | +          </el-button>
 | 
	
		
			
				|  |  | +          <el-button @click="close">{{ t('common.cancel') }}</el-button>
 | 
	
		
			
				|  |  | +        </el-form-item>
 | 
	
		
			
				|  |  | +      </el-form>
 | 
	
		
			
				|  |  | +    </ContentWrap>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    <!-- 审批模式下的操作按钮 -->
 | 
	
		
			
				|  |  | +    <ContentWrap class="section-padding" v-if="isApprovalMode">
 | 
	
		
			
				|  |  | +      <el-form>
 | 
	
		
			
				|  |  | +        <el-form-item style="float: right">
 | 
	
		
			
				|  |  | +          <el-button @click="handleApprove('pass')" type="success">
 | 
	
		
			
				|  |  | +            审批通过
 | 
	
		
			
				|  |  | +          </el-button>
 | 
	
		
			
				|  |  | +          <el-button @click="handleApprove('reject')" type="danger">
 | 
	
		
			
				|  |  | +            审批驳回
 | 
	
		
			
				|  |  | +          </el-button>
 | 
	
		
			
				|  |  | +          <el-button @click="close">{{ t('common.close') }}</el-button>
 | 
	
		
			
				|  |  | +        </el-form-item>
 | 
	
		
			
				|  |  | +      </el-form>
 | 
	
		
			
				|  |  | +    </ContentWrap>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  </ContentWrap>
 | 
	
		
			
				|  |  | +</template>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +<script setup lang="ts">
 | 
	
		
			
				|  |  | +import { ref, reactive, computed, onMounted, nextTick, watch } from 'vue'
 | 
	
		
			
				|  |  | +import { useI18n } from '@/hooks/web/useI18n'
 | 
	
		
			
				|  |  | +import { useMessage } from '@/hooks/web/useMessage'
 | 
	
		
			
				|  |  | +import { useTagsViewStore } from '@/store/modules/tagsView'
 | 
	
		
			
				|  |  | +import { useRouter, useRoute } from 'vue-router'
 | 
	
		
			
				|  |  | +import {DICT_TYPE, getDictLabel, getStrDictOptions} from '@/utils/dict'
 | 
	
		
			
				|  |  | +import { IotRdDailyReportApi } from '@/api/pms/iotrddailyreport'
 | 
	
		
			
				|  |  | +import { IotDailyReportAttrsApi } from '@/api/pms/iotdailyreportattrs'
 | 
	
		
			
				|  |  | +import * as DeptApi from '@/api/system/dept'
 | 
	
		
			
				|  |  | +import { useUserStore } from '@/store/modules/user'
 | 
	
		
			
				|  |  | +import dayjs from 'dayjs'
 | 
	
		
			
				|  |  | +import FileUpload from "@/components/UploadFile/src/FileUpload.vue";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const { t } = useI18n()
 | 
	
		
			
				|  |  | +const message = useMessage()
 | 
	
		
			
				|  |  | +const { delView } = useTagsViewStore()
 | 
	
		
			
				|  |  | +const { push, currentRoute } = useRouter()
 | 
	
		
			
				|  |  | +const { params } = useRoute()
 | 
	
		
			
				|  |  | +const userStore = useUserStore()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/** 填报日报 表单 */
 | 
	
		
			
				|  |  | +defineOptions({ name: 'FillDailyReportForm' })
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const formLoading = ref(false)
 | 
	
		
			
				|  |  | +const formRef = ref()
 | 
	
		
			
				|  |  | +const id = params.id // 瑞都日报id
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 日报数据
 | 
	
		
			
				|  |  | +const dailyReportData = ref<any>({})
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 动态属性相关变量
 | 
	
		
			
				|  |  | +const dynamicAttrs = ref<any[]>([]) // 存储动态属性列表
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 添加审批表单相关变量
 | 
	
		
			
				|  |  | +const approvalFormRef = ref()
 | 
	
		
			
				|  |  | +const approvalForm = reactive({
 | 
	
		
			
				|  |  | +  opinion: '' // 审批意见
 | 
	
		
			
				|  |  | +})
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 审批表单验证规则(可选,根据需求添加)
 | 
	
		
			
				|  |  | +const approvalFormRules = reactive({
 | 
	
		
			
				|  |  | +  opinion: [
 | 
	
		
			
				|  |  | +    { required: false, message: '请输入审批意见', trigger: 'blur' },
 | 
	
		
			
				|  |  | +    { min: 0, max: 500, message: '审批意见长度不能超过500个字符', trigger: 'blur' }
 | 
	
		
			
				|  |  | +  ]
 | 
	
		
			
				|  |  | +})
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 添加文件上传组件的引用
 | 
	
		
			
				|  |  | +const fileUploadRef = ref()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 表单数据
 | 
	
		
			
				|  |  | +const formData = ref({
 | 
	
		
			
				|  |  | +  id: undefined,
 | 
	
		
			
				|  |  | +  deptId: undefined,
 | 
	
		
			
				|  |  | +  companyId: undefined,
 | 
	
		
			
				|  |  | +  deptName: undefined,
 | 
	
		
			
				|  |  | +  constructionStartDate: undefined,
 | 
	
		
			
				|  |  | +  contractName: undefined,
 | 
	
		
			
				|  |  | +  projectDepartment: '',
 | 
	
		
			
				|  |  | +  costCenterId: undefined,
 | 
	
		
			
				|  |  | +  costCenter: '',
 | 
	
		
			
				|  |  | +  // 新增日报填报字段
 | 
	
		
			
				|  |  | +  timeRange: [ // 设置默认时间范围 8:00 - 8:00
 | 
	
		
			
				|  |  | +    dayjs().hour(8).minute(0).second(0).toDate(),
 | 
	
		
			
				|  |  | +    dayjs().hour(8).minute(0).second(0).toDate()
 | 
	
		
			
				|  |  | +  ],
 | 
	
		
			
				|  |  | +  startTime: undefined, // 开始时间
 | 
	
		
			
				|  |  | +  endTime: undefined, // 结束时间
 | 
	
		
			
				|  |  | +  rdStatus: '', // 施工状态
 | 
	
		
			
				|  |  | +  techniqueIds: [], // 施工工艺
 | 
	
		
			
				|  |  | +  productionStatus: '', // 当日生产动态
 | 
	
		
			
				|  |  | +  nextPlan: '', // 下步工作计划
 | 
	
		
			
				|  |  | +  externalRental: '', // 外租设备
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // 添加动态字段对象
 | 
	
		
			
				|  |  | +  dynamicFields: {} as Record<string, any>,
 | 
	
		
			
				|  |  | +  // 附件列表
 | 
	
		
			
				|  |  | +  attachments: [] as any[]
 | 
	
		
			
				|  |  | +})
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 添加上传成功处理函数
 | 
	
		
			
				|  |  | +const handleUploadSuccess = (result: any) => {
 | 
	
		
			
				|  |  | +  console.log('上传成功:', result)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  try {
 | 
	
		
			
				|  |  | +    // 检查响应是否成功
 | 
	
		
			
				|  |  | +    if (!result.response) {
 | 
	
		
			
				|  |  | +      message.error('上传响应数据异常')
 | 
	
		
			
				|  |  | +      return
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (result.response.code !== 0) {
 | 
	
		
			
				|  |  | +      message.error(result.response.msg || '文件上传失败')
 | 
	
		
			
				|  |  | +      return
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const responseData = result.response.data
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (!responseData) {
 | 
	
		
			
				|  |  | +      message.error('上传数据为空')
 | 
	
		
			
				|  |  | +      return
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 处理返回的文件列表
 | 
	
		
			
				|  |  | +    if (responseData.files && Array.isArray(responseData.files) && responseData.files.length > 0) {
 | 
	
		
			
				|  |  | +      responseData.files.forEach((file: any) => {
 | 
	
		
			
				|  |  | +        if (!file.filePath) {
 | 
	
		
			
				|  |  | +          console.warn('文件缺少 filePath:', file)
 | 
	
		
			
				|  |  | +          return
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // 根据后端返回的数据结构构建附件对象
 | 
	
		
			
				|  |  | +        const attachment = {
 | 
	
		
			
				|  |  | +          id: undefined,
 | 
	
		
			
				|  |  | +          category: 'daily_report',
 | 
	
		
			
				|  |  | +          bizId: formData.value.id,
 | 
	
		
			
				|  |  | +          type: 'attachment',
 | 
	
		
			
				|  |  | +          filename: file.name || '未知文件',
 | 
	
		
			
				|  |  | +          fileType: getFileType(file.name),
 | 
	
		
			
				|  |  | +          filePath: file.filePath, // 关键修改:使用正确的 filePath
 | 
	
		
			
				|  |  | +          fileSize: formatFileSize(file.size || 0),
 | 
	
		
			
				|  |  | +          remark: ''
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // 添加到附件列表
 | 
	
		
			
				|  |  | +        if (!formData.value.attachments) {
 | 
	
		
			
				|  |  | +          formData.value.attachments = []
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        formData.value.attachments.push(attachment)
 | 
	
		
			
				|  |  | +      })
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      message.success(`成功上传 ${responseData.files.length} 个文件`)
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      console.warn('上传成功但没有返回文件信息')
 | 
	
		
			
				|  |  | +      message.warning('上传成功但未获取到文件信息')
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  } catch (error) {
 | 
	
		
			
				|  |  | +    console.error('处理上传结果时发生错误:', error)
 | 
	
		
			
				|  |  | +    message.error('处理上传结果失败')
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 删除附件
 | 
	
		
			
				|  |  | +const removeAttachment = (index: number) => {
 | 
	
		
			
				|  |  | +  if (formData.value.attachments && formData.value.attachments.length > index) {
 | 
	
		
			
				|  |  | +    formData.value.attachments.splice(index, 1)
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 获取文件类型辅助函数
 | 
	
		
			
				|  |  | +const getFileType = (filename: string) => {
 | 
	
		
			
				|  |  | +  const ext = filename.split('.').pop()?.toLowerCase()
 | 
	
		
			
				|  |  | +  if (['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(ext || '')) {
 | 
	
		
			
				|  |  | +    return 'image'
 | 
	
		
			
				|  |  | +  } else if (['pdf'].includes(ext || '')) {
 | 
	
		
			
				|  |  | +    return 'pdf'
 | 
	
		
			
				|  |  | +  } else if (['doc', 'docx'].includes(ext || '')) {
 | 
	
		
			
				|  |  | +    return 'word'
 | 
	
		
			
				|  |  | +  } else if (['xls', 'xlsx'].includes(ext || '')) {
 | 
	
		
			
				|  |  | +    return 'excel'
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    return 'other'
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 格式化文件大小辅助函数
 | 
	
		
			
				|  |  | +const formatFileSize = (bytes: number) => {
 | 
	
		
			
				|  |  | +  if (bytes === 0) return '0 Bytes'
 | 
	
		
			
				|  |  | +  const k = 1024
 | 
	
		
			
				|  |  | +  const sizes = ['Bytes', 'KB', 'MB', 'GB']
 | 
	
		
			
				|  |  | +  const i = Math.floor(Math.log(bytes) / Math.log(k))
 | 
	
		
			
				|  |  | +  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 表单验证规则
 | 
	
		
			
				|  |  | +const formRules = reactive({
 | 
	
		
			
				|  |  | +  timeRange: [{ required: true, message: '时间节点不能为空', trigger: 'change' }],
 | 
	
		
			
				|  |  | +  rdStatus: [{ required: true, message: '施工状态不能为空', trigger: 'change' }],
 | 
	
		
			
				|  |  | +  techniqueIds: [{ required: true, message: '施工工艺不能为空', trigger: 'change' }],
 | 
	
		
			
				|  |  | +  productionStatus: [{ required: true, message: '当日生产动态不能为空', trigger: 'blur' }]
 | 
	
		
			
				|  |  | +})
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const queryParams = reactive({
 | 
	
		
			
				|  |  | +  deptId: undefined,
 | 
	
		
			
				|  |  | +  techniqueIds: [],
 | 
	
		
			
				|  |  | +})
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 添加审批模式判断
 | 
	
		
			
				|  |  | +const isApprovalMode = computed(() => params.mode === 'approval')
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 下拉选项
 | 
	
		
			
				|  |  | +const rdStatusOptions = getStrDictOptions(DICT_TYPE.PMS_PROJECT_RD_STATUS)   // 施工状态
 | 
	
		
			
				|  |  | +const techniqueOptions = getStrDictOptions(DICT_TYPE.PMS_PROJECT_RD_TECHNOLOGY) // 瑞都施工工艺
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 计算属性:日报标题
 | 
	
		
			
				|  |  | +const dailyReportTitle = computed(() => {
 | 
	
		
			
				|  |  | +  if (!dailyReportData.value.wellName || !dailyReportData.value.constructionStartDate) {
 | 
	
		
			
				|  |  | +    return '日报填报'
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  const dateStr = formatDate(dailyReportData.value.constructionStartDate)
 | 
	
		
			
				|  |  | +  return `${dailyReportData.value.wellName} - ${dateStr} 生产日报`
 | 
	
		
			
				|  |  | +})
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 日报审批:日报标题
 | 
	
		
			
				|  |  | +const dailyReportApprovalTitle = computed(() => {
 | 
	
		
			
				|  |  | +  if (!dailyReportData.value.wellName || !dailyReportData.value.constructionStartDate) {
 | 
	
		
			
				|  |  | +    return '日报审批'
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  const dateStr = formatDate(dailyReportData.value.constructionStartDate)
 | 
	
		
			
				|  |  | +  return `${dailyReportData.value.wellName} - ${dateStr} 日报审批`
 | 
	
		
			
				|  |  | +})
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 计算属性:施工周期
 | 
	
		
			
				|  |  | +const constructionPeriod = computed(() => {
 | 
	
		
			
				|  |  | +  const start = dailyReportData.value.constructionStartDate
 | 
	
		
			
				|  |  | +  const end = dailyReportData.value.constructionEndDate
 | 
	
		
			
				|  |  | +  if (!start || !end) return 0
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const startDate = dayjs(start)
 | 
	
		
			
				|  |  | +  const endDate = dayjs(end)
 | 
	
		
			
				|  |  | +  return endDate.diff(startDate, 'day')
 | 
	
		
			
				|  |  | +})
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 日期格式化函数
 | 
	
		
			
				|  |  | +const formatDate = (timestamp: number) => {
 | 
	
		
			
				|  |  | +  if (!timestamp) return ''
 | 
	
		
			
				|  |  | +  return dayjs(timestamp).format('YYYY-MM-DD')
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const close = () => {
 | 
	
		
			
				|  |  | +  delView(unref(currentRoute))
 | 
	
		
			
				|  |  | +  push({ name: 'FillDailyReport', params: {} })
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/** 提交表单 */
 | 
	
		
			
				|  |  | +const emit = defineEmits(['success'])
 | 
	
		
			
				|  |  | +const submitForm = async () => {
 | 
	
		
			
				|  |  | +  // 验证表单
 | 
	
		
			
				|  |  | +  try {
 | 
	
		
			
				|  |  | +    await formRef.value.validate()
 | 
	
		
			
				|  |  | +  } catch (error) {
 | 
	
		
			
				|  |  | +    return
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // 处理时间范围数据
 | 
	
		
			
				|  |  | +  if (formData.value.timeRange && formData.value.timeRange.length === 2) {
 | 
	
		
			
				|  |  | +    // 将时间范围转换为 LocalTime 格式的字符串
 | 
	
		
			
				|  |  | +    const startDate = dayjs(formData.value.timeRange[0])
 | 
	
		
			
				|  |  | +    const endDate = dayjs(formData.value.timeRange[1])
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 格式化为 HH:mm:ss 字符串,后端会自动转换为 LocalTime
 | 
	
		
			
				|  |  | +    formData.value.startTime = startDate.format('HH:mm:ss')
 | 
	
		
			
				|  |  | +    formData.value.endTime = endDate.format('HH:mm:ss')
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // 构建动态属性 extProperty 数组
 | 
	
		
			
				|  |  | +  const extProperties = dynamicAttrs.value.map(attr => {
 | 
	
		
			
				|  |  | +    return {
 | 
	
		
			
				|  |  | +      name: attr.name,
 | 
	
		
			
				|  |  | +      sort: attr.sort,
 | 
	
		
			
				|  |  | +      unit: attr.unit,
 | 
	
		
			
				|  |  | +      actualValue: formData.value.dynamicFields[attr.identifier] || '', // 从 dynamicFields 中获取用户填写的值
 | 
	
		
			
				|  |  | +      dataType: attr.dataType,
 | 
	
		
			
				|  |  | +      maxValue: attr.maxValue,
 | 
	
		
			
				|  |  | +      minValue: attr.minValue,
 | 
	
		
			
				|  |  | +      required: attr.required,
 | 
	
		
			
				|  |  | +      accessMode: attr.accessMode,
 | 
	
		
			
				|  |  | +      identifier: attr.identifier,
 | 
	
		
			
				|  |  | +      defaultValue: attr.defaultValue
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  })
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // 准备提交数据,包含动态字段
 | 
	
		
			
				|  |  | +  const submitData = {
 | 
	
		
			
				|  |  | +    ...formData.value,
 | 
	
		
			
				|  |  | +    // 将动态字段组装成 extProperty 数组
 | 
	
		
			
				|  |  | +    extProperty: extProperties
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // 提交请求
 | 
	
		
			
				|  |  | +  formLoading.value = true
 | 
	
		
			
				|  |  | +  try {
 | 
	
		
			
				|  |  | +    // 调用更新接口
 | 
	
		
			
				|  |  | +    await IotRdDailyReportApi.updateIotRdDailyReport(submitData)
 | 
	
		
			
				|  |  | +    message.success(t('common.updateSuccess'))
 | 
	
		
			
				|  |  | +    close()
 | 
	
		
			
				|  |  | +    // 发送操作成功的事件
 | 
	
		
			
				|  |  | +    emit('success')
 | 
	
		
			
				|  |  | +  } catch (error) {
 | 
	
		
			
				|  |  | +    console.error('提交失败:', error)
 | 
	
		
			
				|  |  | +  } finally {
 | 
	
		
			
				|  |  | +    formLoading.value = false
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/** 重置表单 */
 | 
	
		
			
				|  |  | +const resetForm = () => {
 | 
	
		
			
				|  |  | +  formRef.value?.resetFields()
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 初始化动态属性
 | 
	
		
			
				|  |  | +const initDynamicAttrs = (reportData: any) => {
 | 
	
		
			
				|  |  | +  if (reportData.dailyReportAttrs && reportData.dailyReportAttrs.length > 0) {
 | 
	
		
			
				|  |  | +    dynamicAttrs.value = reportData.dailyReportAttrs
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 初始化动态字段的值
 | 
	
		
			
				|  |  | +    const initialDynamicFields: Record<string, any> = {}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 优先从 extProperty 中获取实际值(编辑时)
 | 
	
		
			
				|  |  | +    if (reportData.extProperty && reportData.extProperty.length > 0) {
 | 
	
		
			
				|  |  | +      reportData.extProperty.forEach((extProp: any) => {
 | 
	
		
			
				|  |  | +        if (extProp.identifier) {
 | 
	
		
			
				|  |  | +          initialDynamicFields[extProp.identifier] = extProp.actualValue || ''
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      })
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    reportData.dailyReportAttrs.forEach((attr: any) => {
 | 
	
		
			
				|  |  | +      if (!initialDynamicFields.hasOwnProperty(attr.identifier)) {
 | 
	
		
			
				|  |  | +        // 优先使用实际值,如果没有则使用默认值
 | 
	
		
			
				|  |  | +        const value = (attr.extProperty && attr.extProperty.actualValue !== undefined &&
 | 
	
		
			
				|  |  | +          attr.extProperty.actualValue !== null && attr.extProperty.actualValue !== '')
 | 
	
		
			
				|  |  | +          ? attr.extProperty.actualValue
 | 
	
		
			
				|  |  | +          : (attr.defaultValue || (attr.extProperty?.defaultValue || ''))
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        initialDynamicFields[attr.identifier] = value
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    })
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    formData.value.dynamicFields = initialDynamicFields
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 获取动态字段的验证规则
 | 
	
		
			
				|  |  | +const getDynamicAttrRules = (attr: any) => {
 | 
	
		
			
				|  |  | +  const rules = []
 | 
	
		
			
				|  |  | +  if (attr.required === 1) {
 | 
	
		
			
				|  |  | +    rules.push({
 | 
	
		
			
				|  |  | +      required: true,
 | 
	
		
			
				|  |  | +      message: `${attr.name}不能为空`,
 | 
	
		
			
				|  |  | +      trigger: 'blur'
 | 
	
		
			
				|  |  | +    })
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // 数字类型验证
 | 
	
		
			
				|  |  | +  if (attr.dataType === 'double') {
 | 
	
		
			
				|  |  | +    rules.push({
 | 
	
		
			
				|  |  | +      validator: (rule: any, value: any, callback: any) => {
 | 
	
		
			
				|  |  | +        if (value === '' || value === null || value === undefined) {
 | 
	
		
			
				|  |  | +          callback()
 | 
	
		
			
				|  |  | +          return
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        const numValue = Number(value)
 | 
	
		
			
				|  |  | +        if (isNaN(numValue)) {
 | 
	
		
			
				|  |  | +          callback(new Error(`${attr.name}必须是数字`))
 | 
	
		
			
				|  |  | +        } else if (attr.minValue && numValue < Number(attr.minValue)) {
 | 
	
		
			
				|  |  | +          callback(new Error(`${attr.name}不能小于${attr.minValue}`))
 | 
	
		
			
				|  |  | +        } else if (attr.maxValue && numValue > Number(attr.maxValue)) {
 | 
	
		
			
				|  |  | +          callback(new Error(`${attr.name}不能大于${attr.maxValue}`))
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          callback()
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +      },
 | 
	
		
			
				|  |  | +      trigger: 'blur'
 | 
	
		
			
				|  |  | +    })
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  return rules
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 更新动态属性(处理交集、新增和删除)
 | 
	
		
			
				|  |  | +const updateDynamicAttrs = async (newAttrs: any[], newTechniqueIds: string[], oldTechniqueIds?: string[]) => {
 | 
	
		
			
				|  |  | +  const oldAttrs = [...dynamicAttrs.value]
 | 
	
		
			
				|  |  | +  const oldDynamicFields = { ...formData.value.dynamicFields }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // 计算需要保留的字段(交集)
 | 
	
		
			
				|  |  | +  const commonAttrs = oldAttrs.filter(oldAttr =>
 | 
	
		
			
				|  |  | +    newAttrs.some(newAttr => newAttr.identifier === oldAttr.identifier)
 | 
	
		
			
				|  |  | +  )
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // 计算需要新增的字段
 | 
	
		
			
				|  |  | +  const addedAttrs = newAttrs.filter(newAttr =>
 | 
	
		
			
				|  |  | +    !oldAttrs.some(oldAttr => oldAttr.identifier === newAttr.identifier)
 | 
	
		
			
				|  |  | +  )
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // 计算需要删除的字段
 | 
	
		
			
				|  |  | +  const removedAttrs = oldAttrs.filter(oldAttr =>
 | 
	
		
			
				|  |  | +    !newAttrs.some(newAttr => newAttr.identifier === oldAttr.identifier)
 | 
	
		
			
				|  |  | +  )
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // 构建新的动态属性数组
 | 
	
		
			
				|  |  | +  const updatedAttrs = [...commonAttrs, ...addedAttrs]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // 构建新的动态字段对象
 | 
	
		
			
				|  |  | +  const updatedDynamicFields = { ...oldDynamicFields }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // 移除已删除的字段
 | 
	
		
			
				|  |  | +  removedAttrs.forEach(attr => {
 | 
	
		
			
				|  |  | +    delete updatedDynamicFields[attr.identifier]
 | 
	
		
			
				|  |  | +  })
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // 初始化新增字段的值
 | 
	
		
			
				|  |  | +  addedAttrs.forEach(attr => {
 | 
	
		
			
				|  |  | +    if (!updatedDynamicFields[attr.identifier]) {
 | 
	
		
			
				|  |  | +      // 如果有默认值使用默认值,否则为空
 | 
	
		
			
				|  |  | +      updatedDynamicFields[attr.identifier] = attr.defaultValue ||
 | 
	
		
			
				|  |  | +        (attr.extProperty?.defaultValue || '')
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  })
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // 更新响应式数据
 | 
	
		
			
				|  |  | +  dynamicAttrs.value = updatedAttrs
 | 
	
		
			
				|  |  | +  formData.value.dynamicFields = updatedDynamicFields
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 加载动态属性
 | 
	
		
			
				|  |  | +const loadDynamicAttrs = async (newTechniqueIds: string[], oldTechniqueIds?: string[]) => {
 | 
	
		
			
				|  |  | +  try {
 | 
	
		
			
				|  |  | +    formLoading.value = true
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const queryParams = {
 | 
	
		
			
				|  |  | +      techniqueIds: newTechniqueIds.join(',')
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const response = await IotDailyReportAttrsApi.dailyReportAttrs(queryParams)
 | 
	
		
			
				|  |  | +    const newAttrs = response || []
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 处理动态属性更新
 | 
	
		
			
				|  |  | +    await updateDynamicAttrs(newAttrs, newTechniqueIds, oldTechniqueIds)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  } catch (error) {
 | 
	
		
			
				|  |  | +    console.error('加载动态属性失败:', error)
 | 
	
		
			
				|  |  | +    message.error('加载动态属性失败')
 | 
	
		
			
				|  |  | +  } finally {
 | 
	
		
			
				|  |  | +    formLoading.value = false
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 监听施工工艺变化
 | 
	
		
			
				|  |  | +watch(() => formData.value.techniqueIds, async (newTechniqueIds, oldTechniqueIds) => {
 | 
	
		
			
				|  |  | +  if (newTechniqueIds && newTechniqueIds.length > 0) {
 | 
	
		
			
				|  |  | +    await loadDynamicAttrs(newTechniqueIds, oldTechniqueIds)
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    dynamicAttrs.value = []
 | 
	
		
			
				|  |  | +    formData.value.dynamicFields = {}
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}, { deep: true })
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 初始化表单数据
 | 
	
		
			
				|  |  | +const initFormData = (reportData: any) => {
 | 
	
		
			
				|  |  | +  formData.value = {
 | 
	
		
			
				|  |  | +    ...formData.value,
 | 
	
		
			
				|  |  | +    id: reportData.id,
 | 
	
		
			
				|  |  | +    deptId: reportData.deptId,
 | 
	
		
			
				|  |  | +    rdStatus: reportData.rdStatus || '',
 | 
	
		
			
				|  |  | +    techniqueIds: reportData.techniqueIds ? reportData.techniqueIds.map((id: number) => id.toString()) : [],
 | 
	
		
			
				|  |  | +    productionStatus: reportData.productionStatus || '',
 | 
	
		
			
				|  |  | +    nextPlan: reportData.nextPlan || '',
 | 
	
		
			
				|  |  | +    externalRental: reportData.externalRental || '',
 | 
	
		
			
				|  |  | +    startTime: reportData.startTime || undefined,
 | 
	
		
			
				|  |  | +    endTime: reportData.endTime || undefined,
 | 
	
		
			
				|  |  | +    companyId: reportData.companyId || '',
 | 
	
		
			
				|  |  | +    dynamicFields: {}, // 确保有初始值
 | 
	
		
			
				|  |  | +    // 初始化附件数据
 | 
	
		
			
				|  |  | +    attachments: reportData.attachments || []
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  queryParams.deptId = reportData.companyId
 | 
	
		
			
				|  |  | +  // 设置时间范围选择器
 | 
	
		
			
				|  |  | +  if (reportData.startTime && reportData.startTime[0] && reportData.endTime && reportData.endTime[0]) {
 | 
	
		
			
				|  |  | +    formData.value.timeRange = [
 | 
	
		
			
				|  |  | +      new Date(reportData.startTime[0]),
 | 
	
		
			
				|  |  | +      new Date(reportData.endTime[0])
 | 
	
		
			
				|  |  | +    ]
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  // 初始化动态属性
 | 
	
		
			
				|  |  | +  initDynamicAttrs(reportData)
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +onMounted(async () => {
 | 
	
		
			
				|  |  | +  formLoading.value = true
 | 
	
		
			
				|  |  | +  try {
 | 
	
		
			
				|  |  | +    // 加载当前登录人所属部门
 | 
	
		
			
				|  |  | +    const deptId = userStore.getUser.deptId
 | 
	
		
			
				|  |  | +    const dept = await DeptApi.getDept(deptId)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 查询瑞都日报详情
 | 
	
		
			
				|  |  | +    if (id) {
 | 
	
		
			
				|  |  | +      const response = await IotRdDailyReportApi.getIotRdDailyReport(id)
 | 
	
		
			
				|  |  | +      dailyReportData.value = response || {}
 | 
	
		
			
				|  |  | +      initFormData(dailyReportData.value)
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  } catch (error) {
 | 
	
		
			
				|  |  | +    console.error('初始化数据失败:', error)
 | 
	
		
			
				|  |  | +    message.error('数据加载失败')
 | 
	
		
			
				|  |  | +  } finally {
 | 
	
		
			
				|  |  | +    formLoading.value = false
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +})
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/** 审批操作 */
 | 
	
		
			
				|  |  | +const handleApprove = async (action: 'pass' | 'reject') => {
 | 
	
		
			
				|  |  | +  try {
 | 
	
		
			
				|  |  | +    // 验证审批表单(如果需要)
 | 
	
		
			
				|  |  | +    // await approvalFormRef.value.validate()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    formLoading.value = true
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 处理时间范围数据
 | 
	
		
			
				|  |  | +    if (formData.value.timeRange && formData.value.timeRange.length === 2) {
 | 
	
		
			
				|  |  | +      // 将时间范围转换为 LocalTime 格式的字符串
 | 
	
		
			
				|  |  | +      const startDate = dayjs(formData.value.timeRange[0])
 | 
	
		
			
				|  |  | +      const endDate = dayjs(formData.value.timeRange[1])
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // 格式化为 HH:mm:ss 字符串,后端会自动转换为 LocalTime
 | 
	
		
			
				|  |  | +      formData.value.startTime = startDate.format('HH:mm:ss')
 | 
	
		
			
				|  |  | +      formData.value.endTime = endDate.format('HH:mm:ss')
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 构建审批数据,包含审批意见
 | 
	
		
			
				|  |  | +    const approveData = {
 | 
	
		
			
				|  |  | +      ...formData.value,
 | 
	
		
			
				|  |  | +      id: Number(id),
 | 
	
		
			
				|  |  | +      opinion: approvalForm.opinion,
 | 
	
		
			
				|  |  | +      auditStatus: action === 'pass' ? 20 : 30
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // 这里可以调用审批API
 | 
	
		
			
				|  |  | +    if (action === 'pass') {
 | 
	
		
			
				|  |  | +      // 审批通过逻辑
 | 
	
		
			
				|  |  | +      await IotRdDailyReportApi.approveRdDailyReport(approveData)
 | 
	
		
			
				|  |  | +      message.success('审批通过')
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      // 审批驳回逻辑
 | 
	
		
			
				|  |  | +      await IotRdDailyReportApi.approveRdDailyReport(approveData)
 | 
	
		
			
				|  |  | +      message.success('审批驳回')
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    close()
 | 
	
		
			
				|  |  | +  } catch (error) {
 | 
	
		
			
				|  |  | +    console.error('审批操作失败:', error)
 | 
	
		
			
				|  |  | +    message.error('审批操作失败')
 | 
	
		
			
				|  |  | +  } finally {
 | 
	
		
			
				|  |  | +    formLoading.value = false
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +</script>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +<style scoped>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.info-table {
 | 
	
		
			
				|  |  | +  border: 1px solid #e0e0e0;
 | 
	
		
			
				|  |  | +  border-radius: 4px;
 | 
	
		
			
				|  |  | +  overflow: hidden;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.table-row {
 | 
	
		
			
				|  |  | +  display: flex;
 | 
	
		
			
				|  |  | +  border-bottom: 1px solid #e0e0e0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.table-row:last-child {
 | 
	
		
			
				|  |  | +  border-bottom: none;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.table-cell {
 | 
	
		
			
				|  |  | +  flex: 1;
 | 
	
		
			
				|  |  | +  border-right: 1px solid #e0e0e0;
 | 
	
		
			
				|  |  | +  padding: 12px 8px;
 | 
	
		
			
				|  |  | +  min-height: 44px;
 | 
	
		
			
				|  |  | +  display: flex;
 | 
	
		
			
				|  |  | +  align-items: center;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.table-cell:last-child {
 | 
	
		
			
				|  |  | +  border-right: none;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.table-cell.full-width {
 | 
	
		
			
				|  |  | +  flex: 1;
 | 
	
		
			
				|  |  | +  border-right: none;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.cell-content {
 | 
	
		
			
				|  |  | +  display: flex;
 | 
	
		
			
				|  |  | +  align-items: center;
 | 
	
		
			
				|  |  | +  width: 100%;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.cell-label {
 | 
	
		
			
				|  |  | +  font-weight: 500;
 | 
	
		
			
				|  |  | +  /* 统一字体大小为 14px(Element 表单默认) */
 | 
	
		
			
				|  |  | +  font-size: 14px;
 | 
	
		
			
				|  |  | +  color: #606266;
 | 
	
		
			
				|  |  | +  min-width: 80px;
 | 
	
		
			
				|  |  | +  margin-right: 8px;
 | 
	
		
			
				|  |  | +  flex-shrink: 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.cell-value {
 | 
	
		
			
				|  |  | +  /* 统一字体大小为 14px(Element 输入框默认) */
 | 
	
		
			
				|  |  | +  font-size: 14px;
 | 
	
		
			
				|  |  | +  color: #303133;
 | 
	
		
			
				|  |  | +  /* 统一行高为 1.5(Element 组件默认行高) */
 | 
	
		
			
				|  |  | +  line-height: 1.5;
 | 
	
		
			
				|  |  | +  flex: 1;
 | 
	
		
			
				|  |  | +  word-break: break-all;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* 响应式设计 */
 | 
	
		
			
				|  |  | +@media (max-width: 768px) {
 | 
	
		
			
				|  |  | +  .table-row {
 | 
	
		
			
				|  |  | +    flex-direction: column;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  .table-cell {
 | 
	
		
			
				|  |  | +    border-right: none;
 | 
	
		
			
				|  |  | +    border-bottom: 1px solid #e0e0e0;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  .table-cell:last-child {
 | 
	
		
			
				|  |  | +    border-bottom: none;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.daily-report-title {
 | 
	
		
			
				|  |  | +  text-align: center;
 | 
	
		
			
				|  |  | +  margin: 20px 0;
 | 
	
		
			
				|  |  | +  padding: 10px;
 | 
	
		
			
				|  |  | +  border-bottom: 2px solid #409eff;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.daily-report-title h2 {
 | 
	
		
			
				|  |  | +  margin: 0;
 | 
	
		
			
				|  |  | +  color: #303133;
 | 
	
		
			
				|  |  | +  font-size: 16px;
 | 
	
		
			
				|  |  | +  font-weight: bold;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* 为第二、三部分增加左右留白 */
 | 
	
		
			
				|  |  | +.section-padding {
 | 
	
		
			
				|  |  | +  padding-left: 0px;
 | 
	
		
			
				|  |  | +  padding-right: 40px;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.project-info-section {
 | 
	
		
			
				|  |  | +  margin: 20px 0;
 | 
	
		
			
				|  |  | +  padding: 20px;
 | 
	
		
			
				|  |  | +  background-color: #f8f9fa;
 | 
	
		
			
				|  |  | +  border-radius: 4px;
 | 
	
		
			
				|  |  | +  border: 1px solid #e9ecef;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.info-row {
 | 
	
		
			
				|  |  | +  padding: 12px 0;
 | 
	
		
			
				|  |  | +  border-bottom: 1px solid #e9ecef;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.info-row:last-child {
 | 
	
		
			
				|  |  | +  border-bottom: none;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.info-label {
 | 
	
		
			
				|  |  | +  font-weight: bold;
 | 
	
		
			
				|  |  | +  color: #495057;
 | 
	
		
			
				|  |  | +  margin-right: 8px;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.info-value {
 | 
	
		
			
				|  |  | +  color: #212529;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +:deep(.el-textarea .el-textarea__inner) {
 | 
	
		
			
				|  |  | +  min-height: 80px;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* 确保表单label不换行 */
 | 
	
		
			
				|  |  | +:deep(.el-form-item__label) {
 | 
	
		
			
				|  |  | +  white-space: nowrap;
 | 
	
		
			
				|  |  | +  text-overflow: ellipsis;
 | 
	
		
			
				|  |  | +  overflow: hidden;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* 甲方字段:单行显示+超出省略 */
 | 
	
		
			
				|  |  | +.single-line-ellipsis {
 | 
	
		
			
				|  |  | +  /* 强制文本单行显示 */
 | 
	
		
			
				|  |  | +  white-space: nowrap;
 | 
	
		
			
				|  |  | +  /* 超出容器部分隐藏 */
 | 
	
		
			
				|  |  | +  overflow: hidden;
 | 
	
		
			
				|  |  | +  /* 超出部分显示省略号 */
 | 
	
		
			
				|  |  | +  text-overflow: ellipsis;
 | 
	
		
			
				|  |  | +  /* 避免文本被截断(可选,根据需求调整) */
 | 
	
		
			
				|  |  | +  word-break: normal;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* 设备配置字段:换行缩进(与首行对齐) */
 | 
	
		
			
				|  |  | +.indent-multiline {
 | 
	
		
			
				|  |  | +  /* 首行及换行后缩进 2em(与 label 宽度匹配,可根据需求调整) */
 | 
	
		
			
				|  |  | +  text-indent: 0em;
 | 
	
		
			
				|  |  | +  /* 允许长文本换行(覆盖原有 cell-value 的 break-all,确保中文换行正常) */
 | 
	
		
			
				|  |  | +  word-break: break-word;
 | 
	
		
			
				|  |  | +  /* 保证换行后文本正常显示(可选,清除可能的 nowrap 影响) */
 | 
	
		
			
				|  |  | +  white-space: normal;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* 添加审批模式下的样式 */
 | 
	
		
			
				|  |  | +.approval-notice {
 | 
	
		
			
				|  |  | +  margin-top: 10px;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* 审批模式下表单字段的只读样式 */
 | 
	
		
			
				|  |  | +:deep(.el-form-item.is-disabled .el-input__inner),
 | 
	
		
			
				|  |  | +:deep(.el-form-item.is-disabled .el-textarea__inner) {
 | 
	
		
			
				|  |  | +  background-color: #f5f7fa;
 | 
	
		
			
				|  |  | +  border-color: #e4e7ed;
 | 
	
		
			
				|  |  | +  color: #c0c4cc;
 | 
	
		
			
				|  |  | +  cursor: not-allowed;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +:deep(.el-form-item.is-disabled .el-select .el-input__inner) {
 | 
	
		
			
				|  |  | +  background-color: #f5f7fa;
 | 
	
		
			
				|  |  | +  border-color: #e4e7ed;
 | 
	
		
			
				|  |  | +  color: #c0c4cc;
 | 
	
		
			
				|  |  | +  cursor: not-allowed;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +:deep(.el-form-item.is-disabled .el-date-editor .el-input__inner) {
 | 
	
		
			
				|  |  | +  background-color: #f5f7fa;
 | 
	
		
			
				|  |  | +  border-color: #e4e7ed;
 | 
	
		
			
				|  |  | +  color: #c0c4cc;
 | 
	
		
			
				|  |  | +  cursor: not-allowed;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* 添加审批意见区域的样式 */
 | 
	
		
			
				|  |  | +.approval-opinion-section {
 | 
	
		
			
				|  |  | +  margin-top: 20px;
 | 
	
		
			
				|  |  | +  border-top: 2px solid #f0f0f0;
 | 
	
		
			
				|  |  | +  padding-top: 20px;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* 审批意见文本域样式 */
 | 
	
		
			
				|  |  | +:deep(.approval-opinion .el-textarea__inner) {
 | 
	
		
			
				|  |  | +  min-height: 100px;
 | 
	
		
			
				|  |  | +  resize: vertical;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* 审批意见标签样式 */
 | 
	
		
			
				|  |  | +:deep(.approval-opinion .el-form-item__label) {
 | 
	
		
			
				|  |  | +  font-weight: bold;
 | 
	
		
			
				|  |  | +  color: #606266;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* 附件列表样式 */
 | 
	
		
			
				|  |  | +.attachment-list {
 | 
	
		
			
				|  |  | +  margin-top: 10px;
 | 
	
		
			
				|  |  | +  border: 1px solid #e0e0e0;
 | 
	
		
			
				|  |  | +  border-radius: 4px;
 | 
	
		
			
				|  |  | +  padding: 10px;
 | 
	
		
			
				|  |  | +  background-color: #fafafa;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.attachment-item {
 | 
	
		
			
				|  |  | +  display: flex;
 | 
	
		
			
				|  |  | +  justify-content: space-between;
 | 
	
		
			
				|  |  | +  align-items: center;
 | 
	
		
			
				|  |  | +  padding: 8px 12px;
 | 
	
		
			
				|  |  | +  border-bottom: 1px solid #f0f0f0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.attachment-item:last-child {
 | 
	
		
			
				|  |  | +  border-bottom: none;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.attachment-name {
 | 
	
		
			
				|  |  | +  flex: 1;
 | 
	
		
			
				|  |  | +  color: #606266;
 | 
	
		
			
				|  |  | +  font-size: 14px;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +.no-attachment {
 | 
	
		
			
				|  |  | +  color: #909399;
 | 
	
		
			
				|  |  | +  font-style: italic;
 | 
	
		
			
				|  |  | +  margin-top: 10px;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +</style>
 |