|
|
@@ -0,0 +1,1884 @@
|
|
|
+ <template>
|
|
|
+ <uni-navbar-lite :showLeft="true" title="工分自评">
|
|
|
+ <view class="back-icon" slot="left" @click="goBack">
|
|
|
+ <text class="iconfont icon-back">工分自评</text>
|
|
|
+ </view>
|
|
|
+ </uni-navbar-lite>
|
|
|
+
|
|
|
+ <scroll-view class="container" :scroll-y="true">
|
|
|
+ <view class="header">
|
|
|
+ <text class="title">工分自评</text>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="form">
|
|
|
+ <!-- 工单基本信息 -->
|
|
|
+ <view class="info-card">
|
|
|
+ <view class="info-item">
|
|
|
+ <text class="info-label">工单编码</text>
|
|
|
+ <text class="info-value">{{ selfEvaluationForm.workOrderProjectNo }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="info-item">
|
|
|
+ <text class="info-label">风机编号</text>
|
|
|
+ <text class="info-value">{{ selfEvaluationForm.pcsDeviceName }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="info-item">
|
|
|
+ <text class="info-label">场站</text>
|
|
|
+ <text class="info-value">{{ selfEvaluationForm.pcsStationName }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 工单类型相关字段 -->
|
|
|
+ <view v-if="selfEvaluationForm.orderType == '1'" class="info-card">
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">检修类型<text style="color: red;">*</text></text>
|
|
|
+ <view class="form-picker" @click="showMaintenanceTypePicker = true">
|
|
|
+ <view class="picker-display">
|
|
|
+ <text v-if="selfEvaluationForm.maintenanceType" class="selected-value">{{ getMaintenanceTypeLabel(selfEvaluationForm.maintenanceType) }}</text>
|
|
|
+ <text v-else class="placeholder">请选择检修类型</text>
|
|
|
+ <text class="arrow">▼</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 自定义选择器弹窗 -->
|
|
|
+ <view v-if="showMaintenanceTypePicker" class="picker-modal">
|
|
|
+ <view class="modal-mask" @click="showMaintenanceTypePicker = false"></view>
|
|
|
+ <view class="modal-content">
|
|
|
+ <view class="modal-header">
|
|
|
+ <text class="modal-title">检修类型</text>
|
|
|
+ <text class="modal-close" @click="showMaintenanceTypePicker = false">取消</text>
|
|
|
+ </view>
|
|
|
+ <scroll-view class="modal-body" scroll-y="true">
|
|
|
+ <view
|
|
|
+ v-for="(option, index) in maintenanceTypeOptions"
|
|
|
+ :key="index"
|
|
|
+ class="picker-option"
|
|
|
+ :class="{ 'selected': index == selectedMaintenanceTypeIndex }"
|
|
|
+ @click="selectMaintenanceType(index)"
|
|
|
+ >
|
|
|
+ <text class="option-text">{{ option.label }}</text>
|
|
|
+ <text v-if="index == selectedMaintenanceTypeIndex" class="option-check">✓</text>
|
|
|
+ </view>
|
|
|
+ </scroll-view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view v-if="selfEvaluationForm.orderType == '2'" class="info-card">
|
|
|
+ <view class="info-item">
|
|
|
+ <text class="info-label">维保类型</text>
|
|
|
+
|
|
|
+ <text v-for="(type, index) in selfEvaluationForm.inspectionType" :key="index">
|
|
|
+ {{ getInspectionTypeLabel(type) }}
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ <view class="info-item">
|
|
|
+ <text class="info-label">分项完成系数<text style="color: red;">*</text></text>
|
|
|
+ <input class="info-input" type="digit" :value="itemCompletionFactorStr" @input="onItemCompletionFactorChange" placeholder="请输入分项完成系数" />
|
|
|
+ </view>
|
|
|
+ <view class="info-item">
|
|
|
+ <text class="info-label">分项完成系数和<text style="color: red;">*</text></text>
|
|
|
+ <input class="info-input" type="digit" :value="itemCompletionFactorSumStr" @input="onItemCompletionFactorSumChange" placeholder="请输入分项完成系数和" />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 总结内容 -->
|
|
|
+ <view class="info-card">
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">{{ selfEvaluationForm.orderType == '1' ? '维修总结' : '维保总结' }}<text style="color: red;">*</text></text>
|
|
|
+ <textarea
|
|
|
+ class="textarea"
|
|
|
+ :value="selfEvaluationForm.workSummary"
|
|
|
+ @input="onWorkSummaryInput"
|
|
|
+ placeholder="请输入总结内容"
|
|
|
+ :maxlength="200"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 额外工作总结 - 仅维修工单显示 -->
|
|
|
+ <view v-if="selfEvaluationForm.orderType == '1'" class="form-item">
|
|
|
+ <text class="label">额外工作总结</text>
|
|
|
+ <textarea
|
|
|
+ class="textarea"
|
|
|
+ :value="selfEvaluationForm.extraWork"
|
|
|
+ @input="onExtraWorkInput"
|
|
|
+ @blur="onExtraWorkChange"
|
|
|
+ placeholder="请输入额外工作总结"
|
|
|
+ :maxlength="200"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 人员信息和得分明细 -->
|
|
|
+ <!-- <view class="info-card">
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">外委人员数(人)</text>
|
|
|
+ <text class="value">{{ selfEvaluationForm.wwryNum }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">外来人员数(人)</text>
|
|
|
+ <text class="value">{{ selfEvaluationForm.wlryNum }}</text>
|
|
|
+ </view>
|
|
|
+ </view> -->
|
|
|
+
|
|
|
+ <!-- 得分明细 -->
|
|
|
+ <view class="info-card">
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">得分明细 ({{ isMixedZeroNonZeroInspectionTypes() ? '最少可评总分: ' : '可自评总分: ' }}{{ getSelfEvaluationTotalScore() == 0 ? '未规定' : getSelfEvaluationTotalScore().toFixed(2) + '分' }}, 已自评总分: {{ selfEvaluatedTotalScore.toFixed(2) }}分)</text>
|
|
|
+ </view>
|
|
|
+ <view v-for="(person, index) in selfEvaluationForm.scorePersonList as UTSJSONObject[]" :key="index" class="person-score-item">
|
|
|
+ <view class="person-info">
|
|
|
+ <text class="person-name">{{ (person as UTSJSONObject).get('nickName') }}<text v-if="(person as UTSJSONObject).get('isLeader') == 1"> (工作负责人)</text></text>
|
|
|
+ </view>
|
|
|
+ <view class="score-inputs">
|
|
|
+ <view class="score-item">
|
|
|
+ <text class="score-label">自评分<text style="color: red;">*</text></text>
|
|
|
+ <input
|
|
|
+ class="score-input"
|
|
|
+ type="digit"
|
|
|
+ :value="getPersonScore(person, 'selfScore')"
|
|
|
+ @input="onScoreInput($event, index, 'selfScore')"
|
|
|
+ @blur="onScoreChange"
|
|
|
+ placeholder="0.00"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <!-- 额外工分 - 仅当维修工单且有额外工作总结时显示 -->
|
|
|
+ <view v-if="selfEvaluationForm.orderType == '1' && hasExtraWorkFlag" class="score-item">
|
|
|
+ <text class="score-label">额外工分</text>
|
|
|
+ <input
|
|
|
+ class="score-input"
|
|
|
+ type="digit"
|
|
|
+ :value="getPersonScore(person, 'extraScore')"
|
|
|
+ @input="onScoreInput($event, index, 'extraScore')"
|
|
|
+ @blur="onScoreChange"
|
|
|
+ placeholder="0.00"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <!-- 工单得分 - 仅当维修工单且有额外工作总结时显示 -->
|
|
|
+ <view v-if="selfEvaluationForm.orderType == '1' && hasExtraWorkFlag" class="score-item">
|
|
|
+ <text class="score-label">工单得分</text>
|
|
|
+ <input
|
|
|
+ class="score-input"
|
|
|
+ type="digit"
|
|
|
+ :value="getPersonScore(person, 'totalScore')"
|
|
|
+ readonly
|
|
|
+ disabled
|
|
|
+ placeholder="自动计算"
|
|
|
+ style="pointer-events: none;"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <!-- 额外工分和工单得分 - 仅当维保工单且维保类型包含其他/其它时显示 -->
|
|
|
+ <view v-if="selfEvaluationForm.orderType == '2' && hasOtherOrQitaInspectionType()" class="score-item">
|
|
|
+ <text class="score-label">额外工分</text>
|
|
|
+ <input
|
|
|
+ class="score-input"
|
|
|
+ type="digit"
|
|
|
+ :value="getPersonScore(person, 'extraScore')"
|
|
|
+ @input="onScoreInput($event, index, 'extraScore')"
|
|
|
+ @blur="onScoreChange"
|
|
|
+ placeholder="0.00"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ <view v-if="selfEvaluationForm.orderType == '2' && hasOtherOrQitaInspectionType()" class="score-item">
|
|
|
+ <text class="score-label">工单得分</text>
|
|
|
+ <input
|
|
|
+ class="score-input"
|
|
|
+ type="digit"
|
|
|
+ :value="getPersonScore(person, 'totalScore')"
|
|
|
+ readonly
|
|
|
+ disabled
|
|
|
+ placeholder="自动计算"
|
|
|
+ style="pointer-events: none;"
|
|
|
+ />
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 提交按钮 -->
|
|
|
+ <view class="submit-btn" @click="submitSelfEvaluationForm">
|
|
|
+ <text class="submit-text">提交自评</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </scroll-view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="uts">
|
|
|
+import { ref, onMounted, onLoad, onUnload } from 'vue'
|
|
|
+import { getOrderScoreDetail, submitSelfEvaluation, getMaintenanceTypes, listInspectionTypesByFanType } from '@/api/score/index'
|
|
|
+import { getDictDataByType } from '@/api/dict/index'
|
|
|
+import type { UserInfo } from '@/types/user'
|
|
|
+import type { SysDictData } from '@/types/dict'
|
|
|
+
|
|
|
+/* // 定义事件类型
|
|
|
+// 定义事件类型
|
|
|
+interface InputEvent {
|
|
|
+ detail: any
|
|
|
+ target: any
|
|
|
+} */
|
|
|
+
|
|
|
+// 页面参数
|
|
|
+const id = ref<string>('')
|
|
|
+const orderType = ref<string>('')
|
|
|
+const showMaintenanceTypePicker = ref<boolean>(false)
|
|
|
+// 添加额外工作总结状态变量
|
|
|
+const hasExtraWorkFlag = ref<boolean>(false)
|
|
|
+
|
|
|
+// 验证规则 - 使用UTS兼容的简单对象定义
|
|
|
+const validationRules: any = {
|
|
|
+ workSummary: [
|
|
|
+ { required: true, message: "总结不能为空", trigger: "blur" }
|
|
|
+ ],
|
|
|
+ maintenanceType: [
|
|
|
+ { required: true, message: "请选择检修类型", trigger: "change" }
|
|
|
+ ],
|
|
|
+ inspectionType: [
|
|
|
+ { required: true, message: "请选择维保类型", trigger: "change" }
|
|
|
+ ],
|
|
|
+ itemCompletionFactor: [
|
|
|
+ { required: true, message: "分项完成系数不能为空", trigger: "change" }
|
|
|
+ ],
|
|
|
+ itemCompletionFactorSum: [
|
|
|
+ { required: true, message: "分项完成系数和不能为空", trigger: "change" }
|
|
|
+ ]
|
|
|
+}
|
|
|
+
|
|
|
+// 自评表单数据
|
|
|
+type SelfEvaluationFormData = {
|
|
|
+ orderType: string
|
|
|
+ id: number
|
|
|
+ workOrderProjectNo: string
|
|
|
+ pcsDeviceName: string
|
|
|
+ pcsStationName: string
|
|
|
+ model: string | null // 风机型号,用于获取维保类型选项
|
|
|
+ workSummary: string
|
|
|
+ extraWork: string
|
|
|
+ maintenanceType: string | null
|
|
|
+ inspectionType: string[]
|
|
|
+ itemCompletionFactor: number
|
|
|
+ itemCompletionFactorSum: number
|
|
|
+ scorePersonList: UTSJSONObject[]
|
|
|
+ wwryNum: number
|
|
|
+ wlryNum: number
|
|
|
+}
|
|
|
+
|
|
|
+// 用于input绑定的字符串中转
|
|
|
+let itemCompletionFactorStr = ref<string>('1.0')
|
|
|
+let itemCompletionFactorSumStr = ref<string>('1.0')
|
|
|
+
|
|
|
+// 添加响应式变量来跟踪已自评总分
|
|
|
+let selfEvaluatedTotalScore = ref<number>(0)
|
|
|
+
|
|
|
+const selfEvaluationForm = ref<SelfEvaluationFormData>({
|
|
|
+ orderType: '',
|
|
|
+ id: 0,
|
|
|
+ workOrderProjectNo: '',
|
|
|
+ pcsDeviceName: '',
|
|
|
+ pcsStationName: '',
|
|
|
+ model: null as string | null,
|
|
|
+ workSummary: '',
|
|
|
+ extraWork: '',
|
|
|
+ maintenanceType: null,
|
|
|
+ inspectionType: [],
|
|
|
+ itemCompletionFactor: 1.0,
|
|
|
+ itemCompletionFactorSum: 1.0,
|
|
|
+ scorePersonList: [],
|
|
|
+ wwryNum: 0,
|
|
|
+ wlryNum: 0
|
|
|
+})
|
|
|
+
|
|
|
+type MaintenanceTypeOption = {
|
|
|
+ value: string
|
|
|
+ label: string
|
|
|
+}
|
|
|
+// 检修类型选项
|
|
|
+const maintenanceTypeOptions = ref<MaintenanceTypeOption[]>([])
|
|
|
+const selectedMaintenanceTypeIndex = ref<number>(-1)
|
|
|
+
|
|
|
+// 维保类型选项
|
|
|
+const inspectionTypeOptions = ref<UTSJSONObject[]>([])
|
|
|
+
|
|
|
+// 维保类型字典
|
|
|
+const inspectionTypeDictList = ref<SysDictData[]>([])
|
|
|
+
|
|
|
+// 获取已自评总分
|
|
|
+function getSelfEvaluatedTotalScore(): number {
|
|
|
+ const scorePersonList = selfEvaluationForm.value.scorePersonList as UTSJSONObject[]
|
|
|
+ if (scorePersonList == null || scorePersonList.length == 0) {
|
|
|
+ return 0
|
|
|
+ }
|
|
|
+
|
|
|
+ let totalSelfScore = 0
|
|
|
+
|
|
|
+ for (let i = 0; i < scorePersonList.length; i++) {
|
|
|
+ const person = scorePersonList[i]
|
|
|
+ const selfScoreVal = person.get('selfScore')
|
|
|
+ if (selfScoreVal != null) {
|
|
|
+ // 统一处理分数值,无论是number还是string类型
|
|
|
+ const scoreValue = typeof selfScoreVal == 'number' ? selfScoreVal : (selfScoreVal != '' ? parseFloat(selfScoreVal as string) : 0);
|
|
|
+ if (!isNaN(scoreValue) && scoreValue != 0) {
|
|
|
+ totalSelfScore += scoreValue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ console.log("getSelfEvaluatedTotalScore==",totalSelfScore)
|
|
|
+ return totalSelfScore
|
|
|
+}
|
|
|
+
|
|
|
+// 更新已自评总分的响应式变量
|
|
|
+function updateSelfEvaluatedTotalScore(): void {
|
|
|
+ selfEvaluatedTotalScore.value = getSelfEvaluatedTotalScore()
|
|
|
+}
|
|
|
+
|
|
|
+// 更新总分
|
|
|
+function updateTotalScores(): void {
|
|
|
+ const scorePersonList = selfEvaluationForm.value.scorePersonList as UTSJSONObject[]
|
|
|
+ if (scorePersonList == null || scorePersonList.length == 0) return
|
|
|
+ console.log("scorePersonList",scorePersonList);
|
|
|
+ for (let i = 0; i < scorePersonList.length; i++) {
|
|
|
+ const person = scorePersonList[i]
|
|
|
+ const selfScoreVal = person.get('selfScore')
|
|
|
+ const extraScoreVal = person.get('extraScore')
|
|
|
+
|
|
|
+ // 根据工单类型和条件决定是否计算总分
|
|
|
+ // 检查当前工单类型并获取对应条件
|
|
|
+ const isMaintenanceOrderWithExtraWork = selfEvaluationForm.value.orderType == '1' && hasExtraWorkFlag.value;
|
|
|
+ const isMaintenanceOrderType = selfEvaluationForm.value.orderType == '2';
|
|
|
+ // 手动实现hasOtherOrQitaInspectionType函数的逻辑
|
|
|
+ let hasOtherOrQitaType = false;
|
|
|
+ if (isMaintenanceOrderType) {
|
|
|
+ if (selfEvaluationForm.value.orderType != '2') {
|
|
|
+ hasOtherOrQitaType = false;
|
|
|
+ } else if (!Array.isArray(selfEvaluationForm.value.inspectionType)) {
|
|
|
+ hasOtherOrQitaType = false;
|
|
|
+ } else {
|
|
|
+ for (let i = 0; i < selfEvaluationForm.value.inspectionType.length; i++) {
|
|
|
+ const typeId = selfEvaluationForm.value.inspectionType[i];
|
|
|
+ // 内联getInspectionTypeLabel函数的逻辑
|
|
|
+ let label = '';
|
|
|
+ if (typeId == '') {
|
|
|
+ label = '';
|
|
|
+ } else {
|
|
|
+ const list = inspectionTypeDictList.value;
|
|
|
+ for (let j = 0; j < list.length; j++) {
|
|
|
+ const item = list[j];
|
|
|
+ if (item.dictValue == typeId) {
|
|
|
+ label = (item.dictLabel != null ? item.dictLabel : typeId) as string;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (label == '其他' || label == '其它') {
|
|
|
+ hasOtherOrQitaType = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (isMaintenanceOrderWithExtraWork) {
|
|
|
+ // 维修工单且有额外工作总结时,总分 = 自评分 + 额外工分
|
|
|
+ if (selfScoreVal != null && extraScoreVal != null) {
|
|
|
+ const selfScore = typeof selfScoreVal == 'number' ? selfScoreVal : (selfScoreVal != '' ? parseFloat(selfScoreVal as string) : 0)
|
|
|
+ const extraScore = typeof extraScoreVal == 'number' ? extraScoreVal : (extraScoreVal != '' ? parseFloat(extraScoreVal as string) : 0)
|
|
|
+ person.set('totalScore', selfScore + extraScore)
|
|
|
+ } else if (selfScoreVal != null) {
|
|
|
+ // 如果只有自评分,没有额外工分
|
|
|
+ const selfScore = typeof selfScoreVal == 'number' ? selfScoreVal : (selfScoreVal != '' ? parseFloat(selfScoreVal as string) : 0)
|
|
|
+ person.set('totalScore', selfScore)
|
|
|
+ }
|
|
|
+ } else if (isMaintenanceOrderType && hasOtherOrQitaType) {
|
|
|
+ // 维保工单且维保类型包含其他/其它时,总分 = 自评分 + 额外工分
|
|
|
+ if (selfScoreVal != null && extraScoreVal != null) {
|
|
|
+ const selfScore = typeof selfScoreVal == 'number' ? selfScoreVal : (selfScoreVal != '' ? parseFloat(selfScoreVal as string) : 0)
|
|
|
+ const extraScore = typeof extraScoreVal == 'number' ? extraScoreVal : (extraScoreVal != '' ? parseFloat(extraScoreVal as string) : 0)
|
|
|
+ person.set('totalScore', selfScore + extraScore)
|
|
|
+ } else if (selfScoreVal != null) {
|
|
|
+ // 如果只有自评分,没有额外工分
|
|
|
+ const selfScore = typeof selfScoreVal == 'number' ? selfScoreVal : (selfScoreVal != '' ? parseFloat(selfScoreVal as string) : 0)
|
|
|
+ person.set('totalScore', selfScore)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 其他情况只显示自评分
|
|
|
+ if (selfScoreVal != null) {
|
|
|
+ const selfScore = typeof selfScoreVal == 'number' ? selfScoreVal : (selfScoreVal != '' ? parseFloat(selfScoreVal as string) : 0)
|
|
|
+ if (!isNaN(selfScore)) {
|
|
|
+ person.set('totalScore', selfScore)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ person.set('totalScore', 0)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 同步分项完成系数和显示
|
|
|
+ itemCompletionFactorStr.value = selfEvaluationForm.value.itemCompletionFactor.toFixed(2)
|
|
|
+ itemCompletionFactorSumStr.value = selfEvaluationForm.value.itemCompletionFactorSum.toFixed(2)
|
|
|
+
|
|
|
+ // 更新已自评总分显示
|
|
|
+ updateSelfEvaluatedTotalScore()
|
|
|
+}
|
|
|
+
|
|
|
+// 计算得分 - 实际上在自评中,这是手动输入的,不需要自动计算
|
|
|
+function calculateScores(): void {
|
|
|
+ // 在自评阶段,分数是手动输入的,不需要自动计算
|
|
|
+ // 但我们需要根据工单类型和配置来验证总分是否符合规则
|
|
|
+ updateTotalScores()
|
|
|
+
|
|
|
+ // 更新已自评总分显示
|
|
|
+ updateSelfEvaluatedTotalScore()
|
|
|
+}
|
|
|
+
|
|
|
+// 根据值获取维保类型标签
|
|
|
+function getInspectionTypeLabel(value: string): string {
|
|
|
+ if (value == '') return ''
|
|
|
+ const list = inspectionTypeDictList.value
|
|
|
+ for (let i = 0; i < list.length; i++) {
|
|
|
+ const item = list[i]
|
|
|
+ if (item.dictValue == value) {
|
|
|
+ return (item.dictLabel != null ? item.dictLabel : value) as string
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return value
|
|
|
+}
|
|
|
+
|
|
|
+// 检查维保类型是否包含'其他'或'其它'选项
|
|
|
+function hasOtherOrQitaInspectionType(): boolean {
|
|
|
+ if (selfEvaluationForm.value.orderType != '2') return false
|
|
|
+ if (!Array.isArray(selfEvaluationForm.value.inspectionType)) return false
|
|
|
+
|
|
|
+ for (let i = 0; i < selfEvaluationForm.value.inspectionType.length; i++) {
|
|
|
+ const typeId = selfEvaluationForm.value.inspectionType[i]
|
|
|
+ const label = getInspectionTypeLabel(typeId)
|
|
|
+ if (label == '其他' || label == '其它') {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false
|
|
|
+}
|
|
|
+
|
|
|
+// 检查维保类型是否既有零分又有非零分的情况
|
|
|
+function isMixedZeroNonZeroInspectionTypes(): boolean {
|
|
|
+ if (selfEvaluationForm.value.orderType != '2') return false
|
|
|
+ if (!Array.isArray(selfEvaluationForm.value.inspectionType)) return false
|
|
|
+ if (selfEvaluationForm.value.inspectionType.length <= 1) return false // 单选不会出现混合情况
|
|
|
+
|
|
|
+ let hasZeroScore = false;
|
|
|
+ let hasNonZeroScore = false;
|
|
|
+
|
|
|
+ const selectedInspectionTypes: string[] = selfEvaluationForm.value.inspectionType;
|
|
|
+
|
|
|
+ for (let i = 0; i < selectedInspectionTypes.length; i++) {
|
|
|
+ const typeId = selectedInspectionTypes[i];
|
|
|
+ for (let j = 0; j < inspectionTypeOptions.value.length; j++) {
|
|
|
+ const selectedType = inspectionTypeOptions.value[j];
|
|
|
+ // 使用inspectionTypeId进行匹配
|
|
|
+ if (selectedType.get('inspectionTypeId').toString() == typeId) {
|
|
|
+ // 从标签中提取分数
|
|
|
+ const score = selectedType.get('score');
|
|
|
+ if (score != null && typeof score == 'number') {
|
|
|
+ if (score == 0) {
|
|
|
+ hasZeroScore = true;
|
|
|
+ } else if (score > 0) {
|
|
|
+ hasNonZeroScore = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果既有零分又有非零分,则返回true
|
|
|
+ return hasZeroScore && hasNonZeroScore;
|
|
|
+}
|
|
|
+
|
|
|
+// 获取工单总分
|
|
|
+ function getTotalScore(): number {
|
|
|
+ console.log("getTotalScore 开始执行");
|
|
|
+ console.log("订单类型:", selfEvaluationForm.value.orderType);
|
|
|
+ let totalScore = 0;
|
|
|
+
|
|
|
+ if (selfEvaluationForm.value.orderType == '1') {
|
|
|
+ // 维修工单:根据检修类型获取总分
|
|
|
+ console.log("处理维修工单,维护类型:", selfEvaluationForm.value.maintenanceType);
|
|
|
+ console.log("维护类型选项数量:", maintenanceTypeOptions.value.length);
|
|
|
+ for (let i = 0; i < maintenanceTypeOptions.value.length; i++) {
|
|
|
+ const typeOption = maintenanceTypeOptions.value[i]
|
|
|
+ console.log("检查选项", i, "值:", typeOption.value, "标签:", typeOption.label);
|
|
|
+ if (typeOption.value == selfEvaluationForm.value.maintenanceType) {
|
|
|
+ // 从标签中提取分数
|
|
|
+ const regex = /\((\d+(\.\d+)?)分\)/
|
|
|
+ const match = typeOption.label.match(regex)
|
|
|
+ console.log("正则匹配结果:", match);
|
|
|
+ if (match != null && match.length > 1 && match[1] != null) {
|
|
|
+ totalScore = parseFloat(match[1] as string);
|
|
|
+ console.log("解析到总分:", totalScore);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (selfEvaluationForm.value.orderType == '2') {
|
|
|
+ // 维保工单:根据选中的维保类型和分项完成系数获取总分
|
|
|
+ console.log("处理维保工单");
|
|
|
+ console.log("分项完成系数:", selfEvaluationForm.value.itemCompletionFactor);
|
|
|
+ console.log("维保类型选项数量:", inspectionTypeOptions.value.length);
|
|
|
+ console.log("选中的维保类型:", selfEvaluationForm.value.inspectionType);
|
|
|
+
|
|
|
+ const completionFactor = selfEvaluationForm.value.itemCompletionFactor != null ? selfEvaluationForm.value.itemCompletionFactor : 1;
|
|
|
+
|
|
|
+ // 获取选中的维保项目(现在是多选)
|
|
|
+ const selectedInspectionTypes: string[] = selfEvaluationForm.value.inspectionType != null ? selfEvaluationForm.value.inspectionType : [];
|
|
|
+
|
|
|
+ // 计算所有选中维保项目的总分值
|
|
|
+ let totalScoreFromDB = 0; // 默认值
|
|
|
+
|
|
|
+ if (Array.isArray(selectedInspectionTypes) && selectedInspectionTypes.length > 0) {
|
|
|
+ console.log("开始遍历选中的维保类型:", selectedInspectionTypes);
|
|
|
+ for (let i = 0; i < selectedInspectionTypes.length; i++) {
|
|
|
+ const typeId = selectedInspectionTypes[i];
|
|
|
+ console.log("查找维保类型ID:", typeId);
|
|
|
+ for (let j = 0; j < inspectionTypeOptions.value.length; j++) {
|
|
|
+ const selectedType = inspectionTypeOptions.value[j];
|
|
|
+ const inspectionTypeId = selectedType.get('inspectionTypeId');
|
|
|
+ const score = selectedType.get('score');
|
|
|
+ console.log("比较维保类型ID:", inspectionTypeId, "与", typeId, "得分:", score);
|
|
|
+ // 使用toString()方法确保类型一致进行匹配
|
|
|
+ if ((inspectionTypeId as number).toString() == typeId) {
|
|
|
+ if (score != null && typeof score == 'number') {
|
|
|
+ console.log("找到匹配项,增加分数:", score);
|
|
|
+ totalScoreFromDB += score;
|
|
|
+ } else {
|
|
|
+ console.log("找到匹配项,但分数无效:", score, "类型:", typeof score);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.log("没有选中的维保类型或不是数组");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算总分:总分 = 所有选中维保类型组合的总得分 * 分项完成系数
|
|
|
+ totalScore = totalScoreFromDB * completionFactor;
|
|
|
+ console.log("计算后的总分:", totalScore, "= 数据库总分:", totalScoreFromDB, "* 系数:", completionFactor);
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log("getTotalScore 最终返回:", totalScore);
|
|
|
+ return totalScore;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取可自评总分
|
|
|
+ function getSelfEvaluationTotalScore(): number {
|
|
|
+ console.log("== getSelfEvaluationTotalScore 开始执行 ==");
|
|
|
+ console.log("订单类型:", selfEvaluationForm.value.orderType);
|
|
|
+ console.log("人员列表长度:", selfEvaluationForm.value.scorePersonList.length);
|
|
|
+
|
|
|
+ // 获取工单总分
|
|
|
+ const totalScore = getTotalScore();
|
|
|
+ console.log("获取到的工单总分:", totalScore);
|
|
|
+
|
|
|
+ // 如果总分为0,返回0
|
|
|
+ if (totalScore == 0) {
|
|
|
+ console.log("工单总分为0,进入特殊处理逻辑");
|
|
|
+
|
|
|
+ // 特殊处理:对于维保工单且多选维保类型的情况,如果存在零分和非零分的混合情况
|
|
|
+ if (selfEvaluationForm.value.orderType == '2' && Array.isArray(selfEvaluationForm.value.inspectionType) && selfEvaluationForm.value.inspectionType.length > 1) {
|
|
|
+ console.log("维保工单且多选维保类型,检查零分和非零分混合情况");
|
|
|
+
|
|
|
+ // 获取选中的维保类型
|
|
|
+ const selectedInspectionTypes: string[] = selfEvaluationForm.value.inspectionType != null ? selfEvaluationForm.value.inspectionType : [];
|
|
|
+ console.log("选中的维保类型:", selectedInspectionTypes);
|
|
|
+
|
|
|
+ // 计算所有选中维保类型的非零分值
|
|
|
+ let minScoreFromDB = 0; // 非零分值总和
|
|
|
+ let hasZeroScore = false; // 是否存在零分
|
|
|
+
|
|
|
+ if (Array.isArray(selectedInspectionTypes) && selectedInspectionTypes.length > 0) {
|
|
|
+ console.log("开始遍历选中的维保类型以计算非零分值");
|
|
|
+ for (let i = 0; i < selectedInspectionTypes.length; i++) {
|
|
|
+ const typeId = selectedInspectionTypes[i];
|
|
|
+ console.log("检查维保类型ID:", typeId);
|
|
|
+ for (let j = 0; j < inspectionTypeOptions.value.length; j++) {
|
|
|
+ const selectedType = inspectionTypeOptions.value[j];
|
|
|
+ const inspectionTypeId = selectedType.get('inspectionTypeId');
|
|
|
+ const score = selectedType.get('score');
|
|
|
+ console.log("比较ID:", inspectionTypeId, "与", typeId, "分数:", score);
|
|
|
+ // 使用toString()方法确保类型一致进行匹配
|
|
|
+ if ((inspectionTypeId as number).toString() == typeId) {
|
|
|
+ if (score != null && typeof score == 'number') {
|
|
|
+ console.log("找到匹配项,分数:", score);
|
|
|
+ if (score == 0) {
|
|
|
+ console.log("发现零分项");
|
|
|
+ hasZeroScore = true;
|
|
|
+ } else if (score > 0) {
|
|
|
+ console.log("发现非零分项,增加到minScoreFromDB:", score);
|
|
|
+ minScoreFromDB += score;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log("检查结果 - 有零分:", hasZeroScore, "非零分总和:", minScoreFromDB);
|
|
|
+
|
|
|
+ // 如果存在零分且存在非零分的情况,返回非零分的总和加上工作负责人的0.5分
|
|
|
+ if (hasZeroScore && minScoreFromDB > 0) {
|
|
|
+ const completionFactor = selfEvaluationForm.value.itemCompletionFactor != null ? selfEvaluationForm.value.itemCompletionFactor : 1;
|
|
|
+ const result = (minScoreFromDB * completionFactor) + 0.5;
|
|
|
+ console.log("零分非零分混合情况,返回结果:", result, "= (非零分:", minScoreFromDB, "* 系数:", completionFactor, ") + 0.5");
|
|
|
+ return result;
|
|
|
+ } else {
|
|
|
+ console.log("不符合零分非零分混合条件,hasZeroScore:", hasZeroScore, "minScoreFromDB:", minScoreFromDB);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ console.log("工单总分为0,返回0");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log("工单总分不为0,检查是否存在工作负责人");
|
|
|
+ // 检查是否存在工作负责人
|
|
|
+ const scorePersonList = selfEvaluationForm.value.scorePersonList as UTSJSONObject[];
|
|
|
+ for (let i = 0; i < scorePersonList.length; i++) {
|
|
|
+ const person = scorePersonList[i];
|
|
|
+ const isLeader = person.get('isLeader');
|
|
|
+ console.log("检查第", i, "个人员是否为负责人,isLeader值:", isLeader, "类型:", typeof isLeader);
|
|
|
+ if (isLeader != null && isLeader as number == 1) {
|
|
|
+ // 如果存在工作负责人,可自评总分加0.5分
|
|
|
+ const result = totalScore + 0.5;
|
|
|
+ console.log("找到工作负责人,返回总分+0.5:", result, "= 原总分:", totalScore, "+ 0.5");
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log("未找到工作负责人,返回原总分:", totalScore);
|
|
|
+ return totalScore;
|
|
|
+ }
|
|
|
+
|
|
|
+// 人员评分验证
|
|
|
+function validatePersonScore(score: string, fieldName: string): string | null {
|
|
|
+ if (score == null || score == '') {
|
|
|
+ if (fieldName == 'selfScore') {
|
|
|
+ return '自评分不能为空';
|
|
|
+ }
|
|
|
+ return null; // 额外工分可以为空
|
|
|
+ }
|
|
|
+
|
|
|
+ const numScore = parseFloat(score);
|
|
|
+ if (isNaN(numScore)) {
|
|
|
+ return `${fieldName == 'selfScore' ? '自评分' : '额外工分'}必须为数字`;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (numScore < 0) {
|
|
|
+ return `${fieldName == 'selfScore' ? '自评分' : '额外工分'}不能小于0`;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (fieldName == 'selfScore' && numScore <= 0) {
|
|
|
+ return '自评分必须大于0';
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+}
|
|
|
+
|
|
|
+// 字段验证函数
|
|
|
+function validateField(fieldName: string, value: any): string | null {
|
|
|
+ console.log('验证字段:', fieldName, '值:', value);
|
|
|
+ // 根据字段名称确定验证规则
|
|
|
+ if (fieldName == 'workSummary') {
|
|
|
+ // 验证工作/维保总结
|
|
|
+ if (value == null || value == '') {
|
|
|
+ const summaryType = selfEvaluationForm.value.orderType == '1' ? '维修' : '维保';
|
|
|
+ return `${summaryType}总结不能为空`;
|
|
|
+ }
|
|
|
+ } else if (fieldName == 'maintenanceType') {
|
|
|
+ // 验证检修类型
|
|
|
+ console.log('验证检修类型,当前值:', value, '类型:', typeof value, '是否为null:', value == null, '是否为空字符串:', value == '');
|
|
|
+ if (value == null || value == '') {
|
|
|
+ return "请选择检修类型";
|
|
|
+ }
|
|
|
+ } else if (fieldName == 'inspectionType') {
|
|
|
+ // 验证维保类型
|
|
|
+ if (value == null || (Array.isArray(value) && value.length == 0)) {
|
|
|
+ return "请选择维保类型";
|
|
|
+ }
|
|
|
+ } else if (fieldName == 'itemCompletionFactor') {
|
|
|
+ // 验证分项完成系数
|
|
|
+ if (value == null || value == '') {
|
|
|
+ return "分项完成系数不能为空";
|
|
|
+ }
|
|
|
+ // 验证数值范围
|
|
|
+ if (typeof value == 'string' && value != '') {
|
|
|
+ const numValue = parseFloat(value);
|
|
|
+ if (isNaN(numValue) || numValue < 0 || numValue > 1) {
|
|
|
+ return '分项完成系数必须在0到1之间';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (fieldName == 'itemCompletionFactorSum') {
|
|
|
+ // 验证分项完成系数和
|
|
|
+ if (value == null || value == '') {
|
|
|
+ return "分项完成系数和不能为空";
|
|
|
+ }
|
|
|
+ // 验证数值范围
|
|
|
+ if (typeof value == 'string' && value != '') {
|
|
|
+ const numValue = parseFloat(value);
|
|
|
+ if (isNaN(numValue) || numValue < 0 || numValue > 1) {
|
|
|
+ return '分项完成系数和必须在0到1之间';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+}
|
|
|
+
|
|
|
+// 验证评分规则
|
|
|
+function validateScoringRules(): any {
|
|
|
+ // 获取工单总分
|
|
|
+ const totalScore = getTotalScore()
|
|
|
+
|
|
|
+ // 获取自评分总和
|
|
|
+ const totalSelfScore = getSelfEvaluatedTotalScore()
|
|
|
+
|
|
|
+ const scorePersonList = selfEvaluationForm.value.scorePersonList as UTSJSONObject[]
|
|
|
+ if (scorePersonList == null || scorePersonList.length == 0) {
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', true);
|
|
|
+ result.set('message', '');
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查每个人员的评分
|
|
|
+ let hasEmptyScore = false;
|
|
|
+ let leaderScore: number | null = null;
|
|
|
+
|
|
|
+ for (let i = 0; i < scorePersonList.length; i++) {
|
|
|
+ const person = scorePersonList[i];
|
|
|
+
|
|
|
+ // 验证自评分
|
|
|
+ const selfScore = person.get('selfScore');
|
|
|
+ if (selfScore == null || selfScore == '' || (typeof selfScore == 'number' && isNaN(selfScore as number))) {
|
|
|
+ hasEmptyScore = true;
|
|
|
+ } else {
|
|
|
+ const scoreStr = typeof selfScore == 'number' ? selfScore.toFixed(2) : selfScore as string;
|
|
|
+ const validationError = validatePersonScore(scoreStr, 'selfScore');
|
|
|
+ if (validationError != null) {
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', false);
|
|
|
+ result.set('message', `${person.get('nickName')}:${validationError}`);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ const score = typeof selfScore == 'number' ? selfScore : parseFloat(selfScore as string);
|
|
|
+ if (person.get('isLeader') != null && person.get('isLeader') as number == 1) {
|
|
|
+ leaderScore = score;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证额外工分(如果存在)
|
|
|
+ const extraScore = person.get('extraScore');
|
|
|
+ if (extraScore != null && extraScore != '' && !(typeof extraScore == 'number' && isNaN(extraScore as number))) {
|
|
|
+ const extraScoreStr = typeof extraScore == 'number' ? extraScore.toFixed(2) : extraScore as string;
|
|
|
+ const extraScoreError = validatePersonScore(extraScoreStr, 'extraScore');
|
|
|
+ if (extraScoreError != null) {
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', false);
|
|
|
+ result.set('message', `${person.get('nickName')}:${extraScoreError}`);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果有人没评分,返回错误
|
|
|
+ if (hasEmptyScore) {
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', false);
|
|
|
+ result.set('message', '部分人员未评分');
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查工作负责人得分-0.5后是否小于等于0
|
|
|
+ if (leaderScore != null) {
|
|
|
+ const leaderScoreAfterReduction = leaderScore - 0.5
|
|
|
+ if (leaderScoreAfterReduction <= 0) {
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', false);
|
|
|
+ result.set('message', `工作负责人得分减去0.5后不能小于等于0(当前:${leaderScore.toFixed(2)} - 0.5 = ${leaderScoreAfterReduction.toFixed(2)})`);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查工单类型是否为维保工单且多选维保类型的情况,检查是否存在零分和非零分混合
|
|
|
+ let isMultipleInspectionWithMixedScores = isMixedZeroNonZeroInspectionTypes();
|
|
|
+
|
|
|
+ // 如果总分为0,则评分无上限
|
|
|
+ if (totalScore == 0) {
|
|
|
+ // 检查工作负责人得分-0.5后是否小于等于0
|
|
|
+ if (leaderScore != null) {
|
|
|
+ const leaderScoreAfterReduction = leaderScore - 0.5
|
|
|
+ if (leaderScoreAfterReduction <= 0) {
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', false);
|
|
|
+ result.set('message', `工作负责人得分减去0.5后不能小于等于0(当前:${leaderScore.toFixed(2)} - 0.5 = ${leaderScoreAfterReduction.toFixed(2)})`);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', true);
|
|
|
+ result.set('message', '');
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查自评分总和是否超过总分
|
|
|
+ /* if (totalSelfScore > totalScore + 0.01) { // 使用0.01作为容差
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', false);
|
|
|
+ result.set('message', `自评分总和不能超过工单总分 ${totalScore.toFixed(2)} 分(当前:${totalSelfScore.toFixed(2)} 分)`);
|
|
|
+ return result;
|
|
|
+ } */
|
|
|
+
|
|
|
+ // 检查特殊情况:对于非零总分且非多选维保类型零分非零混合的情况,自评分总和必须等于总分+0.5
|
|
|
+ if (totalScore > 0 && !isMultipleInspectionWithMixedScores) {
|
|
|
+ // 计算理论总分(总分+0.5,因为工作负责人会额外加0.5分)
|
|
|
+ const expectedTotal = totalScore + 0.5;
|
|
|
+
|
|
|
+ // 总得分必须等于总分+0.5(使用容差比较)
|
|
|
+ if (Math.abs(totalSelfScore - expectedTotal) > 0.01) {
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', false);
|
|
|
+ result.set('message', `总得分必须等于 ${expectedTotal.toFixed(2)} 分(当前:${totalSelfScore.toFixed(2)} 分)`);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果是维保工单且多选维保类型且存在零分和非零分混合的情况,需要特殊处理
|
|
|
+ if (isMultipleInspectionWithMixedScores) {
|
|
|
+ // 在这种情况下,总分可能有最小值要求
|
|
|
+ const completionFactor = selfEvaluationForm.value.itemCompletionFactor != null ? selfEvaluationForm.value.itemCompletionFactor : 1
|
|
|
+ // 重新计算非零分项的总分
|
|
|
+ let minScoreFromDB = 0;
|
|
|
+ const selectedInspectionTypes: string[] = selfEvaluationForm.value.inspectionType != null ? selfEvaluationForm.value.inspectionType : []
|
|
|
+
|
|
|
+ for (let i = 0; i < selectedInspectionTypes.length; i++) {
|
|
|
+ const typeId = selectedInspectionTypes[i]
|
|
|
+ for (let j = 0; j < inspectionTypeOptions.value.length; j++) {
|
|
|
+ const selectedType = inspectionTypeOptions.value[j]
|
|
|
+ // 使用inspectionTypeId进行匹配
|
|
|
+ if (selectedType.get('inspectionTypeId').toString() == typeId) {
|
|
|
+ const score = selectedType.get('score');
|
|
|
+ if (score != null && typeof score == 'number' && score > 0) { // 只累加非零分
|
|
|
+ minScoreFromDB += score;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算最低理论总分(非零项的总分 * 分项完成系数 + 0.5)
|
|
|
+ const minExpectedTotal = (minScoreFromDB * completionFactor) + 0.5
|
|
|
+
|
|
|
+ // 总得分不得低于最低理论总分
|
|
|
+ if (totalSelfScore < minExpectedTotal - 0.01) { // 使用0.01作为容差
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', false);
|
|
|
+ result.set('message', `总得分不得低于 ${minExpectedTotal.toFixed(2)} 分(当前:${totalSelfScore.toFixed(2)} 分)`);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', true);
|
|
|
+ result.set('message', '');
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+// 验证整个表单
|
|
|
+function validateForm(): any {
|
|
|
+ console.log('开始验证表单,工单类型:', selfEvaluationForm.value.orderType);
|
|
|
+ console.log('当前检修类型值:', selfEvaluationForm.value.maintenanceType);
|
|
|
+
|
|
|
+ // 首先验证必填字段,按优先级排序
|
|
|
+
|
|
|
+ // 验证工单类型为1(维修工单)时的检修类型
|
|
|
+ if (selfEvaluationForm.value.orderType == '1') {
|
|
|
+ console.log('验证维修工单的检修类型');
|
|
|
+ console.log('当前maintenanceType值:', selfEvaluationForm.value.maintenanceType, '类型:', typeof selfEvaluationForm.value.maintenanceType);
|
|
|
+ console.log('maintenanceType == null:', selfEvaluationForm.value.maintenanceType == null);
|
|
|
+ console.log('maintenanceType == null:', selfEvaluationForm.value.maintenanceType == null);
|
|
|
+ console.log('maintenanceType == :', selfEvaluationForm.value.maintenanceType == '');
|
|
|
+
|
|
|
+ let validationMessage: string | null = null;
|
|
|
+ try {
|
|
|
+ validationMessage = validateField('maintenanceType', selfEvaluationForm.value.maintenanceType as any);
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error('检修类型验证过程中出现异常:', error);
|
|
|
+ validationMessage = '检修类型验证失败';
|
|
|
+ }
|
|
|
+ console.log('检修类型验证结果:', validationMessage);
|
|
|
+ if (validationMessage != null) {
|
|
|
+ console.log('检修类型验证失败:', validationMessage);
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', false);
|
|
|
+ result.set('message', validationMessage);
|
|
|
+ console.log('准备返回验证失败结果');
|
|
|
+ return result;
|
|
|
+ } else {
|
|
|
+ console.log('检修类型验证通过');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证总结内容(这个也必须在前面验证)
|
|
|
+ console.log('验证工作总结,内容:', selfEvaluationForm.value.workSummary);
|
|
|
+ console.log('工作总结内容长度:', selfEvaluationForm.value.workSummary?.length ?? 0);
|
|
|
+ let summaryValidation: string | null = null;
|
|
|
+ try {
|
|
|
+ summaryValidation = validateField('workSummary', selfEvaluationForm.value.workSummary as any);
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error('工作总结验证过程中出现异常:', error);
|
|
|
+ summaryValidation = '工作总结验证失败';
|
|
|
+ }
|
|
|
+ console.log('工作总结验证结果:', summaryValidation);
|
|
|
+ if (summaryValidation != null) {
|
|
|
+ console.log('工作总结验证失败:', summaryValidation);
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', false);
|
|
|
+ result.set('message', summaryValidation);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证工单类型为2(维保工单)时的分项完成系数
|
|
|
+ if (selfEvaluationForm.value.orderType == '2') {
|
|
|
+ // 检查分项完成系数是否为空字符串(即用户清空了输入框)
|
|
|
+ console.log("itemCompletionFactorStr.value",itemCompletionFactorStr.value)
|
|
|
+ if (itemCompletionFactorStr.value == '') {
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', false);
|
|
|
+ result.set('message', '分项完成系数不能为空');
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ let validationMessage: string | null = null;
|
|
|
+ try {
|
|
|
+ validationMessage = validateField('itemCompletionFactor', selfEvaluationForm.value.itemCompletionFactor as any);
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error('分项完成系数验证过程中出现异常:', error);
|
|
|
+ validationMessage = '分项完成系数验证失败';
|
|
|
+ }
|
|
|
+ if (validationMessage != null) {
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', false);
|
|
|
+ result.set('message', validationMessage);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证分项完成系数和
|
|
|
+ // 检查分项完成系数和是否为空字符串(即用户清空了输入框)
|
|
|
+ console.log("itemCompletionFactorSumStr.value",itemCompletionFactorSumStr.value)
|
|
|
+ if (itemCompletionFactorSumStr.value == '') {
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', false);
|
|
|
+ result.set('message', '分项完成系数和不能为空');
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ validationMessage = null;
|
|
|
+ try {
|
|
|
+ validationMessage = validateField('itemCompletionFactorSum', selfEvaluationForm.value.itemCompletionFactorSum as any);
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error('分项完成系数和验证过程中出现异常:', error);
|
|
|
+ validationMessage = '分项完成系数和验证失败';
|
|
|
+ }
|
|
|
+ if (validationMessage != null) {
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', false);
|
|
|
+ result.set('message', validationMessage);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证维保类型(仅适用于维保工单)
|
|
|
+ if (selfEvaluationForm.value.orderType == '2') {
|
|
|
+ let validationMessage: string | null = null;
|
|
|
+ try {
|
|
|
+ validationMessage = validateField('inspectionType', selfEvaluationForm.value.inspectionType as any);
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error('维保类型验证过程中出现异常:', error);
|
|
|
+ validationMessage = '维保类型验证失败';
|
|
|
+ }
|
|
|
+ if (validationMessage != null) {
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', false);
|
|
|
+ result.set('message', validationMessage);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证评分规则
|
|
|
+ let scoringValidation: UTSJSONObject;
|
|
|
+ try {
|
|
|
+ scoringValidation = validateScoringRules() as UTSJSONObject;
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error('评分规则验证过程中出现异常:', error);
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', false);
|
|
|
+ result.set('message', '评分规则验证失败');
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ if (!(scoringValidation.get('valid') as boolean)) {
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', false);
|
|
|
+ result.set('message', scoringValidation.get('message') as string);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ const result = new UTSJSONObject();
|
|
|
+ result.set('valid', true);
|
|
|
+ result.set('message', '');
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+// 加载检修类型选项
|
|
|
+async function loadMaintenanceTypes() {
|
|
|
+ try {
|
|
|
+ /* uni.showLoading({
|
|
|
+ title: '加载中...'
|
|
|
+ }) */
|
|
|
+
|
|
|
+ const response: any = await getMaintenanceTypes()
|
|
|
+ const resultObj = response as UTSJSONObject
|
|
|
+ const code = resultObj.get('code') as number
|
|
|
+
|
|
|
+ if (code == 200) {
|
|
|
+ const data = resultObj.get('rows') as UTSJSONObject[]
|
|
|
+ if (data != null && Array.isArray(data)) {
|
|
|
+ // 将后端返回的数据转换为页面需要的格式
|
|
|
+ const options: MaintenanceTypeOption[] = []
|
|
|
+ for (let i = 0; i < data.length; i++) {
|
|
|
+ const item = data[i]
|
|
|
+ const option: MaintenanceTypeOption = {
|
|
|
+ value: (item.get('maintenanceType') as string | null) ?? '',
|
|
|
+ label: `${(item.get('projectName') as string | null) ?? ''}(${(item.get('scorePerCompletion') as number | null) ?? 0}分)`
|
|
|
+ }
|
|
|
+ options.push(option)
|
|
|
+ }
|
|
|
+ maintenanceTypeOptions.value = options
|
|
|
+
|
|
|
+ // 设置选中项索引
|
|
|
+ const mt = selfEvaluationForm.value.maintenanceType
|
|
|
+ if (mt != null && mt != '') {
|
|
|
+ const index = maintenanceTypeOptions.value.findIndex(item => item.value == mt)
|
|
|
+ if (index >= 0) {
|
|
|
+ selectedMaintenanceTypeIndex.value = index
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 如果maintenanceType为空,重置选中索引
|
|
|
+ selectedMaintenanceTypeIndex.value = -1
|
|
|
+ selfEvaluationForm.value.maintenanceType = null
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ const msg = resultObj.get('msg') as string | null
|
|
|
+ console.error('加载检修类型失败:', msg ?? '未知错误')
|
|
|
+ }
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error('加载检修类型失败:', error)
|
|
|
+ } finally {
|
|
|
+ //uni.hideLoading()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 加载维保类型选项
|
|
|
+async function loadInspectionTypeOptions() {
|
|
|
+ try {
|
|
|
+ // 加载维保类型选项
|
|
|
+ if (orderType.value == '2') {
|
|
|
+ // 根据风机型号获取维保类型选项
|
|
|
+ const fanType = selfEvaluationForm.value.model; // 使用风机型号
|
|
|
+ console.log('准备加载维保类型选项,风机型号:', fanType);
|
|
|
+
|
|
|
+ if (fanType != null && fanType != '') {
|
|
|
+ console.log('正在调用listInspectionTypesByFanType,参数:', fanType as string);
|
|
|
+ const response: any = await listInspectionTypesByFanType(fanType as string);
|
|
|
+ console.log('API响应:', response);
|
|
|
+
|
|
|
+ const resultObj = response as UTSJSONObject;
|
|
|
+ const code = resultObj.get('code') as number;
|
|
|
+
|
|
|
+ if (code == 200) {
|
|
|
+ const data = resultObj.get('data') as UTSJSONObject[];
|
|
|
+
|
|
|
+ if (data != null && Array.isArray(data)) {
|
|
|
+ inspectionTypeOptions.value = data;
|
|
|
+ console.log('维保类型选项加载成功,数量:', data.length);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.error('API返回错误码:', code);
|
|
|
+ console.error('错误信息:', resultObj.get('msg'));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.warn('风机型号为空,无法加载维保类型选项');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (e: any) {
|
|
|
+ console.error('获取维保类型选项失败:', e.message);
|
|
|
+ //console.error('错误堆栈:', e.stack);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 加载工单详情
|
|
|
+async function loadOrderDetail() {
|
|
|
+ try {
|
|
|
+ uni.showLoading({
|
|
|
+ title: '加载中...'
|
|
|
+ })
|
|
|
+
|
|
|
+ const response: any = await getOrderScoreDetail(orderType.value, id.value)
|
|
|
+ console.log("工单详情response==")
|
|
|
+ console.log(response)
|
|
|
+ const resultObj = response as UTSJSONObject
|
|
|
+ const code = resultObj.get('code') as number
|
|
|
+
|
|
|
+ if (code == 200) {
|
|
|
+ const data = resultObj.get('data') as UTSJSONObject
|
|
|
+
|
|
|
+ // 设置表单数据
|
|
|
+ const formData: SelfEvaluationFormData = {
|
|
|
+ orderType: orderType.value,
|
|
|
+ id: (data.get('id') as number | null) ?? 0,
|
|
|
+ workOrderProjectNo: (data.get('workOrderProjectNo') as string | null) ?? '',
|
|
|
+ pcsDeviceName: (data.get('pcsDeviceName') as string | null) ?? '',
|
|
|
+ pcsStationName: (data.get('pcsStationName') as string | null) ?? '',
|
|
|
+ workSummary: orderType.value == '1' ? ((data.get('content') as string | null) ?? '') : ((data.get('realContent') as string | null) ?? ''),
|
|
|
+ extraWork: orderType.value == '1' ? ((data.get('extraWork') as string | null) ?? '') : '',
|
|
|
+ maintenanceType: (data.get('maintenanceType') as string | null),
|
|
|
+ model: (data.get('model') as string | null), // 风机型号
|
|
|
+ inspectionType: orderType.value == '2' ?
|
|
|
+ (Array.isArray(data.get('inspectionType')) ?
|
|
|
+ data.get('inspectionType') as string[] :
|
|
|
+ (((data.get('inspectionType') as string | null)?.split(',') ?? []) as string[])) : [],
|
|
|
+ itemCompletionFactor: (data.get('itemCompletionFactor') as number | null) ?? 1.0,
|
|
|
+ itemCompletionFactorSum: (data.get('itemCompletionFactorSum') as number | null) ?? 1.0,
|
|
|
+ scorePersonList: orderType.value == '1' ?
|
|
|
+ ((data.get('repairOrderPersonList') as UTSJSONObject[] | null) ?? []) :
|
|
|
+ ((data.get('workOrderPersonList') as UTSJSONObject[] | null) ?? []),
|
|
|
+ wwryNum: (data.get('wwryNum') as number | null) ?? 0,
|
|
|
+ wlryNum: (data.get('wlryNum') as number | null) ?? 0
|
|
|
+ }
|
|
|
+ selfEvaluationForm.value = formData
|
|
|
+
|
|
|
+ // 为人员列表设置初始分数
|
|
|
+ /* const list = (formData.scorePersonList as UTSJSONObject[])
|
|
|
+ for (let i = 0; i < list.length; i++) {
|
|
|
+ const person = list[i]
|
|
|
+ if (person.get('selfScore') == null) {
|
|
|
+ person.set('selfScore', '')
|
|
|
+ }
|
|
|
+ if (person.get('extraScore') == null) {
|
|
|
+ person.set('extraScore', '')
|
|
|
+ }
|
|
|
+ if (person.get('totalScore') == null) {
|
|
|
+ person.set('totalScore', '')
|
|
|
+ }
|
|
|
+ } */
|
|
|
+
|
|
|
+ // 初始化字符串中转值
|
|
|
+ itemCompletionFactorStr.value = formData.itemCompletionFactor.toFixed(2)
|
|
|
+ itemCompletionFactorSumStr.value = formData.itemCompletionFactorSum.toFixed(2)
|
|
|
+
|
|
|
+ // 加载检修类型选项
|
|
|
+ if (orderType.value == '1') {
|
|
|
+ await loadMaintenanceTypes()
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加载维保类型选项
|
|
|
+ if (orderType.value == '2') {
|
|
|
+ await loadInspectionTypeOptions()
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算初始分数
|
|
|
+ calculateScores()
|
|
|
+
|
|
|
+ // 设置额外工作总结状态标志
|
|
|
+ hasExtraWorkFlag.value = formData.extraWork != null && formData.extraWork.trim() != '';
|
|
|
+
|
|
|
+ // 初始化已自评总分
|
|
|
+ updateSelfEvaluatedTotalScore()
|
|
|
+ } else {
|
|
|
+ const msg = resultObj.get('msg') as string | null
|
|
|
+ uni.showToast({
|
|
|
+ title: msg ?? '加载失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error('加载工单详情失败:', error)
|
|
|
+ uni.showToast({
|
|
|
+ title: '加载失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ } finally {
|
|
|
+ uni.hideLoading()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 加载字典数据
|
|
|
+async function loadDictData() {
|
|
|
+ try {
|
|
|
+ // 加载维保类型字典
|
|
|
+ if (orderType.value == '2') {
|
|
|
+ const result = await getDictDataByType('gxt_inspection_type')
|
|
|
+ const resultObj = result as UTSJSONObject
|
|
|
+
|
|
|
+ if (resultObj.get('code') == 200) {
|
|
|
+ const data = resultObj.get('data') as any[]
|
|
|
+ const dictData: SysDictData[] = []
|
|
|
+
|
|
|
+ if (data != null && data.length > 0) {
|
|
|
+ for (let i = 0; i < data.length; i++) {
|
|
|
+ const item = data[i] as UTSJSONObject
|
|
|
+ // 只提取需要的字段
|
|
|
+ const dictItem: SysDictData = {
|
|
|
+ dictValue: item.get('dictValue') as string | null,
|
|
|
+ dictLabel: item.get('dictLabel') as string | null,
|
|
|
+ dictCode: null,
|
|
|
+ dictSort: null,
|
|
|
+ dictType: null,
|
|
|
+ cssClass: null,
|
|
|
+ listClass: null,
|
|
|
+ isDefault: null,
|
|
|
+ status: null,
|
|
|
+ default: null,
|
|
|
+ createTime: null,
|
|
|
+ remark: null
|
|
|
+ }
|
|
|
+ dictData.push(dictItem)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ inspectionTypeDictList.value = dictData
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (e: any) {
|
|
|
+ console.error('获取维保类型字典失败:', e.message)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 检修类型选择变化
|
|
|
+function selectMaintenanceType(index: number) {
|
|
|
+ selectedMaintenanceTypeIndex.value = index
|
|
|
+ if (index >= 0 && index < maintenanceTypeOptions.value.length) {
|
|
|
+ selfEvaluationForm.value.maintenanceType = maintenanceTypeOptions.value[index].value
|
|
|
+ }
|
|
|
+ showMaintenanceTypePicker.value = false
|
|
|
+
|
|
|
+ // 选择后立即触发验证
|
|
|
+ const validationMessage = validateField('maintenanceType', selfEvaluationForm.value.maintenanceType as any);
|
|
|
+ if (validationMessage != null) {
|
|
|
+ uni.showToast({
|
|
|
+ title: validationMessage,
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 根据值获取检修类型标签
|
|
|
+function getMaintenanceTypeLabel(value: string | null): string {
|
|
|
+ if (value == null || value == '') return ''
|
|
|
+ const item = maintenanceTypeOptions.value.find(item => item.value == value)
|
|
|
+ return item != null ? item.label : value
|
|
|
+}
|
|
|
+
|
|
|
+// 工作总结输入处理
|
|
|
+function onWorkSummaryInput(e: UniInputEvent) {
|
|
|
+ const value = e.detail?.value as string
|
|
|
+ selfEvaluationForm.value.workSummary = value
|
|
|
+}
|
|
|
+
|
|
|
+// 分项完成系数变化
|
|
|
+function onItemCompletionFactorChange(e: UniInputEvent) {
|
|
|
+ const rawValue = e.detail?.value as string
|
|
|
+
|
|
|
+ // 如果输入为空,设置为0
|
|
|
+ if (rawValue == '') {
|
|
|
+ selfEvaluationForm.value.itemCompletionFactor = 0
|
|
|
+ itemCompletionFactorStr.value = ''
|
|
|
+ } else {
|
|
|
+ const val = parseFloat(rawValue)
|
|
|
+
|
|
|
+ // 验证分项完成系数
|
|
|
+ if (isNaN(val)) {
|
|
|
+ console.warn('分项完成系数必须为数字')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (val < 0 || val > 1) {
|
|
|
+ console.warn('分项完成系数必须在0到1之间')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ selfEvaluationForm.value.itemCompletionFactor = val
|
|
|
+ itemCompletionFactorStr.value = rawValue
|
|
|
+ }
|
|
|
+ calculateScores()
|
|
|
+}
|
|
|
+
|
|
|
+// 分项完成系数和变化
|
|
|
+function onItemCompletionFactorSumChange(e: UniInputEvent) {
|
|
|
+ const rawValue = e.detail?.value as string
|
|
|
+
|
|
|
+ // 如果输入为空,设置为0
|
|
|
+ if (rawValue == '') {
|
|
|
+ selfEvaluationForm.value.itemCompletionFactorSum = 0
|
|
|
+ itemCompletionFactorSumStr.value = ''
|
|
|
+ } else {
|
|
|
+ const val = parseFloat(rawValue)
|
|
|
+
|
|
|
+ // 验证分项完成系数和
|
|
|
+ if (isNaN(val)) {
|
|
|
+ console.warn('分项完成系数和必须为数字')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if (val < 0 || val > 1) {
|
|
|
+ console.warn('分项完成系数和必须在0到1之间')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ selfEvaluationForm.value.itemCompletionFactorSum = val
|
|
|
+ itemCompletionFactorSumStr.value = rawValue
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 额外工作总结变化
|
|
|
+function onExtraWorkChange() {
|
|
|
+ // 更新额外工作总结状态标志
|
|
|
+ // 使用更严格的检查,包括检查长度
|
|
|
+ let extraWorkStr = '';
|
|
|
+ if (selfEvaluationForm.value.extraWork != null) {
|
|
|
+ extraWorkStr = selfEvaluationForm.value.extraWork;
|
|
|
+ }
|
|
|
+ const trimmedStr = extraWorkStr.trim();
|
|
|
+ const newHasExtraWork = trimmedStr.length > 0;
|
|
|
+ hasExtraWorkFlag.value = newHasExtraWork;
|
|
|
+
|
|
|
+ // 如果额外工作总结为空,则清空额外工分和总分字段
|
|
|
+ if (trimmedStr.length == 0) {
|
|
|
+ // 清空所有人员的额外工分和总分
|
|
|
+ const scorePersonList = selfEvaluationForm.value.scorePersonList as UTSJSONObject[]
|
|
|
+ for (let i = 0; i < scorePersonList.length; i++) {
|
|
|
+ const person = scorePersonList[i]
|
|
|
+ person.set('extraScore', 0)
|
|
|
+ // 重新计算总分(此时额外工分为空,所以总分等于自评分)
|
|
|
+ const selfScoreVal = person.get('selfScore');
|
|
|
+ if (selfScoreVal != null) {
|
|
|
+ const selfScore = typeof selfScoreVal == 'number' ? selfScoreVal : (selfScoreVal != '' ? parseFloat(selfScoreVal as string) : 0);
|
|
|
+ if (!isNaN(selfScore)) {
|
|
|
+ person.set('totalScore', selfScore);
|
|
|
+ } else {
|
|
|
+ person.set('totalScore', 0);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ person.set('totalScore', 0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新已自评总分显示
|
|
|
+ updateSelfEvaluatedTotalScore()
|
|
|
+
|
|
|
+ // 当额外工作总结变化时,可能需要重新计算总分
|
|
|
+ updateTotalScores()
|
|
|
+
|
|
|
+ // 强制触发视图更新
|
|
|
+ /* console.log("额外工作总结变化,当前内容:", selfEvaluationForm.value.extraWork);
|
|
|
+ console.log("hasExtraWorkFlag.value", hasExtraWorkFlag.value);
|
|
|
+ console.log("newHasExtraWork", newHasExtraWork);
|
|
|
+ console.log("extraWork != null", selfEvaluationForm.value.extraWork != null);
|
|
|
+ console.log("extraWork.trim() != ''", extraWorkStr.trim() != '');
|
|
|
+ console.log("extraWork.trim()", JSON.stringify(extraWorkStr.trim()));
|
|
|
+ console.log("extraWork.trim().length", extraWorkStr.trim().length);
|
|
|
+ console.log("trimmedStr.length > 0", trimmedStr.length > 0); */
|
|
|
+}
|
|
|
+
|
|
|
+// 额外工作总结输入处理
|
|
|
+function onExtraWorkInput(e: UniInputEvent) {
|
|
|
+ const value = e.detail?.value;
|
|
|
+ // 确保当值为null时设置为空字符串
|
|
|
+ if (value == null) {
|
|
|
+ selfEvaluationForm.value.extraWork = '';
|
|
|
+ } else {
|
|
|
+ selfEvaluationForm.value.extraWork = value.toString();
|
|
|
+ }
|
|
|
+ // 每次输入都触发变化处理
|
|
|
+ onExtraWorkChange()
|
|
|
+}
|
|
|
+
|
|
|
+// 获取人员评分
|
|
|
+function getPersonScore(person: UTSJSONObject, field: string): string {
|
|
|
+ const value = person.get(field as string)
|
|
|
+ if (value == null || value == '' || (typeof value == 'number' && isNaN(value))) {
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+ // 统一处理为字符串返回给UI
|
|
|
+ if (typeof value == 'number') {
|
|
|
+ const stringValue = value.toString();
|
|
|
+ return stringValue;
|
|
|
+ //return value.toFixed(2);
|
|
|
+ }
|
|
|
+ return value as string
|
|
|
+}
|
|
|
+
|
|
|
+// 设置人员评分
|
|
|
+function setPersonScore(person: UTSJSONObject, field: string, value: string) {
|
|
|
+ person.set(field as string, value)
|
|
|
+}
|
|
|
+
|
|
|
+// 通用评分输入处理
|
|
|
+function onScoreInput(e: UniInputEvent, index: number, field: string) {
|
|
|
+ const value = e.detail?.value as string
|
|
|
+ console.log(field + "输入 - 值:", value, "索引:", index)
|
|
|
+
|
|
|
+ if (index >= 0 && index < selfEvaluationForm.value.scorePersonList.length) {
|
|
|
+ const person = selfEvaluationForm.value.scorePersonList[index] as UTSJSONObject
|
|
|
+ if (person != null) {
|
|
|
+ // 将输入的字符串转换为数字存储
|
|
|
+ const numericValue = value == '' ? null : parseFloat(value);
|
|
|
+ person.set(field, (numericValue != null && isNaN(numericValue)) ? null : numericValue);
|
|
|
+
|
|
|
+ // 实时验证评分
|
|
|
+ if (value != '') {
|
|
|
+ const validationError = validatePersonScore(value, field)
|
|
|
+ if (validationError != null) { // 修复条件判断
|
|
|
+ // 显示验证错误(在实际应用中,这里可以显示在界面上)
|
|
|
+ console.warn(`评分验证错误: ${validationError}`)
|
|
|
+ // 可以考虑用uni.showToast显示错误信息
|
|
|
+ /* uni.showToast({
|
|
|
+ title: validationError,
|
|
|
+ icon: 'none',
|
|
|
+ duration: 2000
|
|
|
+ }) */
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ updateTotalScores()
|
|
|
+ updateSelfEvaluatedTotalScore()
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 分数变化
|
|
|
+function onScoreChange() {
|
|
|
+ updateTotalScores()
|
|
|
+ updateSelfEvaluatedTotalScore() // 更新已自评总分显示
|
|
|
+ // 确保已自评总分在分数变化后被重新计算
|
|
|
+ console.log("分数变化,当前已自评总分:", getSelfEvaluatedTotalScore())
|
|
|
+}
|
|
|
+
|
|
|
+// 返回按钮事件
|
|
|
+function goBack() {
|
|
|
+ uni.navigateBack()
|
|
|
+}
|
|
|
+
|
|
|
+// 提交自评
|
|
|
+async function submitSelfEvaluationForm(): Promise<void> {
|
|
|
+ try {
|
|
|
+ console.log('开始提交验证');
|
|
|
+ // 使用完整的表单验证
|
|
|
+ const validation = validateForm() as UTSJSONObject;
|
|
|
+ const isValid = validation.get('valid') as boolean;
|
|
|
+ const validationMsg = validation.get('message') as string;
|
|
|
+ console.log('验证结果:', isValid, '消息:', validationMsg);
|
|
|
+ console.log('验证结果类型:', typeof isValid, '是否为false:', isValid == false);
|
|
|
+ if (!isValid) {
|
|
|
+ console.log('验证失败,显示错误:', validationMsg);
|
|
|
+ uni.showToast({
|
|
|
+ title: validationMsg,
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ uni.showLoading({
|
|
|
+ title: '提交中...'
|
|
|
+ })
|
|
|
+
|
|
|
+ // 创建新的UTSJSONObject来存储表单数据
|
|
|
+ const formValue = new UTSJSONObject();
|
|
|
+
|
|
|
+ // 复制基本字段
|
|
|
+ formValue.set('id', selfEvaluationForm.value.id);
|
|
|
+ formValue.set('orderType', selfEvaluationForm.value.orderType);
|
|
|
+ formValue.set('workOrderProjectNo', selfEvaluationForm.value.workOrderProjectNo);
|
|
|
+ formValue.set('pcsDeviceName', selfEvaluationForm.value.pcsDeviceName);
|
|
|
+ formValue.set('pcsStationName', selfEvaluationForm.value.pcsStationName);
|
|
|
+ formValue.set('workSummary', selfEvaluationForm.value.workSummary);
|
|
|
+ formValue.set('extraWork', selfEvaluationForm.value.extraWork);
|
|
|
+ formValue.set('maintenanceType', selfEvaluationForm.value.maintenanceType);
|
|
|
+ formValue.set('itemCompletionFactor', selfEvaluationForm.value.itemCompletionFactor);
|
|
|
+ formValue.set('itemCompletionFactorSum', selfEvaluationForm.value.itemCompletionFactorSum);
|
|
|
+ formValue.set('wwryNum', selfEvaluationForm.value.wwryNum);
|
|
|
+ formValue.set('wlryNum', selfEvaluationForm.value.wlryNum);
|
|
|
+
|
|
|
+ // 处理inspectionType字段:如果是数组则转换为字符串
|
|
|
+ if (Array.isArray(selfEvaluationForm.value.inspectionType)) {
|
|
|
+ const strValue = (selfEvaluationForm.value.inspectionType as string[]).join(',');
|
|
|
+ formValue.set('inspectionType', strValue);
|
|
|
+ } else {
|
|
|
+ formValue.set('inspectionType', selfEvaluationForm.value.inspectionType);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 复制scorePersonList数组
|
|
|
+ const scorePersonListArray: UTSJSONObject[] = [];
|
|
|
+ for (let i = 0; i < selfEvaluationForm.value.scorePersonList.length; i++) {
|
|
|
+ const person = selfEvaluationForm.value.scorePersonList[i];
|
|
|
+ // 将UTSJSONObject添加到数组中
|
|
|
+ scorePersonListArray.push(person);
|
|
|
+ }
|
|
|
+ formValue.set('scorePersonList', scorePersonListArray);
|
|
|
+
|
|
|
+ const response: any = await submitSelfEvaluation(formValue);
|
|
|
+
|
|
|
+ const resultObj = response as UTSJSONObject
|
|
|
+ const code = resultObj.get('code' as string) as number
|
|
|
+
|
|
|
+ if (code == 200) {
|
|
|
+ uni.showToast({
|
|
|
+ title: '自评提交成功',
|
|
|
+ icon: 'success'
|
|
|
+ })
|
|
|
+
|
|
|
+ // 设置标记,通知上一个页面需要刷新数据
|
|
|
+ uni.setStorageSync('needRefresh', true)
|
|
|
+
|
|
|
+ // 延迟返回上一页
|
|
|
+ setTimeout(() => {
|
|
|
+ uni.navigateBack()
|
|
|
+ }, 1000)
|
|
|
+ } else {
|
|
|
+ const msg = resultObj.get('msg' as string) as string | null
|
|
|
+ uni.showToast({
|
|
|
+ title: msg ?? '提交失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error('提交自评失败:', error)
|
|
|
+ uni.showToast({
|
|
|
+ title: '提交失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ } finally {
|
|
|
+ uni.hideLoading()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+ // 页面初始化
|
|
|
+ onLoad((options: any) => {
|
|
|
+ const params = options as UTSJSONObject
|
|
|
+ id.value = (params.get('id') != null ? params.get('id') as string : '')
|
|
|
+ orderType.value = (params.get('orderType') != null ? params.get('orderType') as string : '')
|
|
|
+
|
|
|
+
|
|
|
+ console.log("id.value==",id.value)
|
|
|
+ console.log("orderType.value==",orderType.value)
|
|
|
+ // 加载字典数据
|
|
|
+ loadDictData()
|
|
|
+ // 加载工单详情
|
|
|
+ loadOrderDetail()
|
|
|
+ })
|
|
|
+
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss">
|
|
|
+.container {
|
|
|
+ flex: 1;
|
|
|
+ background-color: #e8f0f9;
|
|
|
+ height: 100vh;
|
|
|
+}
|
|
|
+
|
|
|
+.header {
|
|
|
+ padding: 30rpx;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.title {
|
|
|
+ font-size: 36rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+
|
|
|
+.form {
|
|
|
+ padding: 0 30rpx 30rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.info-card {
|
|
|
+ background-color: #ffffff;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ padding: 30rpx;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.info-item {
|
|
|
+ flex-direction: row;
|
|
|
+ padding: 20rpx 0;
|
|
|
+ border-bottom: 1rpx solid #f0f0f0;
|
|
|
+
|
|
|
+ &:last-child {
|
|
|
+ border-bottom: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .info-label {
|
|
|
+ width: 240rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #666666;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+
|
|
|
+ .info-value {
|
|
|
+ flex: 1;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333333;
|
|
|
+ text-align: right;
|
|
|
+ }
|
|
|
+
|
|
|
+ .info-input {
|
|
|
+ flex: 1;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333333;
|
|
|
+ border: 1rpx solid #e0e0e0;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ padding: 10rpx;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.form-item {
|
|
|
+ margin-bottom: 30rpx;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+
|
|
|
+.label {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #666;
|
|
|
+ margin-bottom: 10rpx;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+
|
|
|
+.value {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+
|
|
|
+.textarea {
|
|
|
+ width: 100%;
|
|
|
+ height: 200rpx;
|
|
|
+ border: 1rpx solid #e5e5e5;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ padding: 20rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+
|
|
|
+.picker {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.picker-display {
|
|
|
+ flex-direction: row;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ padding: 10rpx;
|
|
|
+ border: 1rpx solid #e5e5e5;
|
|
|
+ border-radius: 8rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.selected-value {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+
|
|
|
+.placeholder {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+
|
|
|
+.arrow {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #999;
|
|
|
+}
|
|
|
+
|
|
|
+.selected-values {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 10rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.selected-value-tag {
|
|
|
+ background-color: #f0f0f0;
|
|
|
+ padding: 8rpx 16rpx;
|
|
|
+ border-radius: 20rpx;
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #666;
|
|
|
+}
|
|
|
+
|
|
|
+.person-score-item {
|
|
|
+ margin-bottom: 30rpx;
|
|
|
+ padding: 20rpx;
|
|
|
+ background-color: #f8f9fa;
|
|
|
+ border-radius: 12rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.person-info {
|
|
|
+ margin-bottom: 15rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.person-name {
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #333;
|
|
|
+}
|
|
|
+
|
|
|
+.score-inputs {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 15rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.score-item {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+}
|
|
|
+
|
|
|
+.score-label {
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #666;
|
|
|
+ width: 120rpx;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.score-input {
|
|
|
+ flex: 1;
|
|
|
+ height: 60rpx;
|
|
|
+ border: 1rpx solid #e0e0e0;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ padding: 0 15rpx;
|
|
|
+ font-size: 26rpx;
|
|
|
+ color: #333;
|
|
|
+ text-align: right;
|
|
|
+}
|
|
|
+
|
|
|
+.submit-btn {
|
|
|
+ margin-top: 40rpx;
|
|
|
+ height: 80rpx;
|
|
|
+ background-color: #165DFF;
|
|
|
+ border-radius: 10rpx;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+.submit-text {
|
|
|
+ font-size: 32rpx;
|
|
|
+ color: #fff;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+
|
|
|
+/* 自定义选择器样式 */
|
|
|
+.picker-modal {
|
|
|
+ position: fixed;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ z-index: 1000;
|
|
|
+}
|
|
|
+
|
|
|
+.modal-mask {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ background-color: rgba(0, 0, 0, 0.5);
|
|
|
+}
|
|
|
+
|
|
|
+.modal-content {
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ background-color: #ffffff;
|
|
|
+ border-top-left-radius: 16rpx;
|
|
|
+ border-top-right-radius: 16rpx;
|
|
|
+ min-height: 700rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.modal-header {
|
|
|
+ flex-direction: row;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ padding: 30rpx;
|
|
|
+ border-bottom: 1rpx solid #f0f0f0;
|
|
|
+}
|
|
|
+
|
|
|
+.modal-title {
|
|
|
+ font-size: 32rpx;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #333333;
|
|
|
+}
|
|
|
+
|
|
|
+.modal-close {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #165DFF;
|
|
|
+}
|
|
|
+
|
|
|
+.modal-body {
|
|
|
+ max-height: 600rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.picker-option {
|
|
|
+ flex-direction: row;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ padding: 24rpx 30rpx;
|
|
|
+ border-bottom: 1rpx solid #f0f0f0;
|
|
|
+}
|
|
|
+
|
|
|
+.picker-option.selected {
|
|
|
+ background-color: #f8f9fa;
|
|
|
+}
|
|
|
+
|
|
|
+.option-text {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333333;
|
|
|
+}
|
|
|
+
|
|
|
+.option-check {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #165DFF;
|
|
|
+}
|
|
|
+
|
|
|
+.form-picker {
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.picker-display {
|
|
|
+ flex-direction: row;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ min-height: 40rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.selected-value {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333333;
|
|
|
+}
|
|
|
+
|
|
|
+.placeholder {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #999999;
|
|
|
+}
|
|
|
+
|
|
|
+.arrow {
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #999999;
|
|
|
+ margin-left: 12rpx;
|
|
|
+}
|
|
|
+</style>
|