|
|
@@ -607,6 +607,20 @@
|
|
|
|
|
|
<!-- 新加 -->
|
|
|
<Teleport v-if="teleportBtnRef" to=".teleport-btn">
|
|
|
+ <template v-if="showCheckBook && getReportStatusEnd">
|
|
|
+ <div v-if="[0, 2].includes(checkBookDetail.rectificationStatus)" class="default-toolbar">
|
|
|
+ <el-button type="success" size="small" @click="() => handlePass(0)">整改通过</el-button>
|
|
|
+ <el-button type="success" size="small" @click="() => handlePass(2)">整改不通过</el-button>
|
|
|
+ <el-button type="primary" size="small" @click="handleRectificationMaterials">上传整改材料</el-button>
|
|
|
+ <template v-if="checkBookDetail.rectificationStatus === 2">
|
|
|
+ <el-button type="primary" size="small" @click="() => handlePass(1)">回退</el-button>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ <div v-if="[3].includes(checkBookDetail.rectificationStatus)" class="default-toolbar">
|
|
|
+ <el-button type="primary" size="small" @click="handleRectificationMaterials">上传整改材料</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
<div class="operation-btns">
|
|
|
<!-- 报告办结后,这部分按钮不再显示 -->
|
|
|
<template v-if="!getReportStatusEnd && selectedItem">
|
|
|
@@ -694,6 +708,7 @@
|
|
|
>OA审核</el-button>
|
|
|
</template>
|
|
|
</div>
|
|
|
+ </template>
|
|
|
</Teleport>
|
|
|
|
|
|
<AssociationOperationManual
|
|
|
@@ -706,14 +721,119 @@
|
|
|
handleRefresh()
|
|
|
}"
|
|
|
/>
|
|
|
+
|
|
|
+ <!-- 上传整改材料弹窗 -->
|
|
|
+ <Dialog
|
|
|
+ v-model="ectificationMaterialsVisible"
|
|
|
+ title="上传整改材料"
|
|
|
+ width="750px"
|
|
|
+ style="margin-bottom: 0px; height: 100vh"
|
|
|
+ top="0vh"
|
|
|
+ :scroll="true"
|
|
|
+ height="100vh"
|
|
|
+ :maxHeight="'calc(100vh - 55px - 60px - 63px)'"
|
|
|
+ @close="handleClosePectificationMaterialsDialog"
|
|
|
+ >
|
|
|
+ <div v-loading="ectificationMaterialsLoading" class="rectification-dialog">
|
|
|
+ <!-- 检验意见通知书上传 -->
|
|
|
+ <div class="upload-section required">
|
|
|
+ <div class="section-header">
|
|
|
+ <div class="header-left">
|
|
|
+ <i class="icon-document"></i>
|
|
|
+ <span class="section-title">检验意见通知书</span>
|
|
|
+ <span class="required-mark">*</span>
|
|
|
+ </div>
|
|
|
+ <span class="section-tip">仅支持PDF格式,限1个文件</span>
|
|
|
+ </div>
|
|
|
+ <div class="upload-area">
|
|
|
+ <CustomUploadFile
|
|
|
+ v-model:fileList="ectificationMaterialsData.rectificationUrl"
|
|
|
+ apiUrl="infra/file/upload"
|
|
|
+ :limit="1"
|
|
|
+ :disabled="ectificationMaterialsData.rectificationUrl.length >= 1 || ectificationMaterialsLoading"
|
|
|
+ accept=".pdf"
|
|
|
+ listType="picture"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 整改图片上传 -->
|
|
|
+ <div class="upload-section">
|
|
|
+ <div class="section-header">
|
|
|
+ <div class="header-left">
|
|
|
+ <i class="icon-image"></i>
|
|
|
+ <span class="section-title">整改图片</span>
|
|
|
+ </div>
|
|
|
+ <span class="section-tip">支持JPG、PNG格式,最多20张,单个不超过2MB</span>
|
|
|
+ </div>
|
|
|
+ <div class="upload-area">
|
|
|
+ <CustomUploadFile
|
|
|
+ v-model:fileList="ectificationMaterialsData.rectificationImage"
|
|
|
+ apiUrl="infra/file/upload"
|
|
|
+ :limit="20"
|
|
|
+ :disabled="ectificationMaterialsData.rectificationImage.length >= 20 || ectificationMaterialsLoading"
|
|
|
+ accept=".jpg,.jpeg,.png"
|
|
|
+ :multiple="true"
|
|
|
+ :maxSize="2097152"
|
|
|
+ listType="picture"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 整改视频上传 -->
|
|
|
+ <div class="upload-section">
|
|
|
+ <div class="section-header">
|
|
|
+ <div class="header-left">
|
|
|
+ <i class="icon-video"></i>
|
|
|
+ <span class="section-title">整改视频</span>
|
|
|
+ </div>
|
|
|
+ <span class="section-tip">支持MP4格式,最多5个,单个不超过10MB</span>
|
|
|
+ </div>
|
|
|
+ <div class="upload-area">
|
|
|
+ <CustomUploadFile
|
|
|
+ v-model:fileList="ectificationMaterialsData.rectificationVideo"
|
|
|
+ apiUrl="infra/file/upload"
|
|
|
+ :limit="5"
|
|
|
+ :disabled="ectificationMaterialsData.rectificationVideo.length >= 5 || ectificationMaterialsLoading"
|
|
|
+ accept=".mp4"
|
|
|
+ :multiple="true"
|
|
|
+ :maxSize="10485760"
|
|
|
+ listType="picture"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 温馨提示 -->
|
|
|
+ <div class="info-tips">
|
|
|
+ <i class="icon-info"></i>
|
|
|
+ <div class="tips-content">
|
|
|
+ <p class="tips-title">温馨提示:</p>
|
|
|
+ <p>1. 请确保上传的文件清晰可辨,以便审核</p>
|
|
|
+ <p>2. 整改材料将作为审核依据,请如实上传</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="()=> ectificationMaterialsVisible = false">取消</el-button>
|
|
|
+ <el-button
|
|
|
+ :loading="ectificationMaterialsLoading"
|
|
|
+ type="primary"
|
|
|
+ @click="handleSubmitChangeEctificationMaterialsDialog"
|
|
|
+ >
|
|
|
+ 确定提交
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ </Dialog>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="tsx">
|
|
|
import SmartTable from '@/components/SmartTable/SmartTable'
|
|
|
-import { computed, nextTick, ref, watch } from 'vue'
|
|
|
+import CustomUploadFile from '@/components/CustomUploadFile/index.vue'
|
|
|
+import { computed, nextTick, reactive, ref, watch } from 'vue'
|
|
|
import { useRouter, useRoute } from 'vue-router'
|
|
|
import { InfoFilled, View, Back, Right, WarningFilled } from '@element-plus/icons-vue'
|
|
|
-import { dayjs, ElMessage, ElMessageBox } from 'element-plus'
|
|
|
+import { dayjs, ElMessage, ElMessageBox, FormInstance, FormRules } from 'element-plus'
|
|
|
const CustomDialog = defineAsyncComponent(() => import('@/components/CustomDialog/index.vue'))
|
|
|
import VuePdfEmbed from 'vue-pdf-embed'
|
|
|
import { getReportAllowedApplyModify, getReportCheckPdf } from '@/api/laboratory/functional/report'
|
|
|
@@ -723,6 +843,7 @@ import {
|
|
|
PressureCheckerMyTaskStatus,
|
|
|
PressureReportType,
|
|
|
PressureTaskOrderTaskStatus,
|
|
|
+ SugguestionApproveConfig,
|
|
|
} from '@/utils/constants'
|
|
|
import { OAApprovalResultMap, OAApprovalResultType } from '@/utils/pressure2/oaConstants'
|
|
|
import type {
|
|
|
@@ -754,6 +875,7 @@ import {SpreadViewer} from "@/components/DynamicReport";
|
|
|
import {InitParams} from "@/components/DynamicReport/SpreadInterface";
|
|
|
import { cloneDeep, debounce } from 'lodash-es'
|
|
|
import {PipeTaskOrderApi} from "@/api/pressure2/pipetaskorder";
|
|
|
+import * as UserGroupApi from '@/api/bpm/userGroup'
|
|
|
|
|
|
interface Props {
|
|
|
selectedItem: ReportItemVO | null
|
|
|
@@ -912,6 +1034,20 @@ const canSubmitMainReportType = (tipsText: string)=>{
|
|
|
// 校核人选择对话框状态
|
|
|
const showBatchSubmitToRecheckDialog = ref(false)
|
|
|
const isShowAuditDialog = ref(false)
|
|
|
+const btnLoading = ref(false)
|
|
|
+// 检验意见通知书提交审核
|
|
|
+const sugguestionApproveConfig = ref<any[]>(cloneDeep(SugguestionApproveConfig))
|
|
|
+const isShowSuggestionAuditDialog = ref(false)
|
|
|
+const suggestionFormRef = ref<FormInstance>()
|
|
|
+const suggestionFormData = ref<any>({})
|
|
|
+const suggestionFormRules = reactive({
|
|
|
+ sugguestionAuditId: [
|
|
|
+ { required: true, message: '请选择审核人', trigger: 'blur' }
|
|
|
+ ],
|
|
|
+ sugguestionApproveId: [
|
|
|
+ { required: true, message: '请选择审批人', trigger: 'blur' }
|
|
|
+ ]
|
|
|
+})
|
|
|
const handleSelectVerfiyer = async () => {
|
|
|
|
|
|
try {
|
|
|
@@ -1101,7 +1237,7 @@ const rectificationStatusMap = reactive({
|
|
|
})
|
|
|
const getReportAuditInfo = async () => {
|
|
|
if (props.selectedItem?.reportType === PressureReportType['SUGGUESTION']) {
|
|
|
- const res = await reportInfoApi.exportCheckBookDetail({
|
|
|
+ const res = await BoilerTaskOrderApi.exportCheckBookDetail({
|
|
|
id: props.taskId
|
|
|
})
|
|
|
console.log(res, '查询检验意见通知书详细信息')
|
|
|
@@ -1153,6 +1289,54 @@ const handlePass = async (type) => {
|
|
|
})
|
|
|
}
|
|
|
|
|
|
+// 上传整改材料
|
|
|
+const ectificationMaterialsData = ref<any>({
|
|
|
+ rectificationUrl: [],
|
|
|
+ rectificationImage: [],
|
|
|
+ rectificationVideo: [],
|
|
|
+})
|
|
|
+const ectificationMaterialsVisible = ref(false)
|
|
|
+const ectificationMaterialsLoading = ref(false)
|
|
|
+
|
|
|
+const handleRectificationMaterials = () => {
|
|
|
+ const detail = checkBookDetail.value || {}
|
|
|
+ ectificationMaterialsData.value = {
|
|
|
+ rectificationUrl: detail.rectificationUrl ? detail.rectificationUrl.split(',').filter(Boolean).map((url: string) => ({ url })) : [],
|
|
|
+ rectificationImage: detail.rectificationImage ? detail.rectificationImage.split(',').filter(Boolean).map((url: string) => ({ url })) : [],
|
|
|
+ rectificationVideo: detail.rectificationVideo ? detail.rectificationVideo.split(',').filter(Boolean).map((url: string) => ({ url })) : [],
|
|
|
+ }
|
|
|
+ ectificationMaterialsVisible.value = true
|
|
|
+}
|
|
|
+
|
|
|
+const handleClosePectificationMaterialsDialog = () => {
|
|
|
+ ectificationMaterialsVisible.value = false
|
|
|
+}
|
|
|
+
|
|
|
+const handleSubmitChangeEctificationMaterialsDialog = async () => {
|
|
|
+ if (ectificationMaterialsData.value?.rectificationUrl?.length == 0) {
|
|
|
+ return ElMessage.error('请上传证明材料')
|
|
|
+ }
|
|
|
+ ectificationMaterialsLoading.value = true
|
|
|
+ try {
|
|
|
+ const data = {
|
|
|
+ reportId: props.selectedItem?.id || '',
|
|
|
+ businessType: 1,
|
|
|
+ rectificationUrl: ectificationMaterialsData.value?.rectificationUrl?.length ? ectificationMaterialsData.value?.rectificationUrl?.map(item => item.url)?.join(',') : '',
|
|
|
+ rectificationImage: ectificationMaterialsData.value?.rectificationImage?.length ? ectificationMaterialsData.value?.rectificationImage?.map(item => item.url)?.join(',') : '',
|
|
|
+ rectificationVideo: ectificationMaterialsData.value?.rectificationVideo?.length ? ectificationMaterialsData.value?.rectificationVideo?.map(item => item.url)?.join(',') : '',
|
|
|
+ }
|
|
|
+ const response = await BoilerTaskOrderApi.inspectionOpinionRectifyApi(data)
|
|
|
+ if (response) {
|
|
|
+ ectificationMaterialsLoading.value = false
|
|
|
+ ElMessage.success('上传成功')
|
|
|
+ ectificationMaterialsVisible.value = false
|
|
|
+ emit('refresh')
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ ectificationMaterialsLoading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// 获取检验员名称
|
|
|
const getCheckersName = (): string => {
|
|
|
if (!props.selectedItem?.checkUsers || props.selectedItem.checkUsers.length === 0) {
|
|
|
@@ -1559,6 +1743,74 @@ const handleCompletion = async () => {
|
|
|
ElMessage.success('报告已办结')
|
|
|
}
|
|
|
|
|
|
+const handleOpenSuggestionAuditDialog = () => {
|
|
|
+ isShowSuggestionAuditDialog.value = true
|
|
|
+ btnLoading.value = true
|
|
|
+ UserApi.getApprovalDetail({})
|
|
|
+ .then(async (res) => {
|
|
|
+ if (res) {
|
|
|
+ const opinionNotificationJsonData = res.opinionNotificationJson ? JSON.parse(res.opinionNotificationJson) : {}
|
|
|
+ suggestionFormData.value = {
|
|
|
+ ...res,
|
|
|
+ ...opinionNotificationJsonData,
|
|
|
+ }
|
|
|
+ const suggestionFilds = sugguestionApproveConfig.value.map((item) => item.filed)
|
|
|
+ const suggestionPromise = suggestionFilds.map((category) =>
|
|
|
+ UserGroupApi.getUserGroupUserList({ category: category, status: 0 })
|
|
|
+ )
|
|
|
+ const suggestionResult = await Promise.all(suggestionPromise)
|
|
|
+ sugguestionApproveConfig.value.forEach((item, index) => {
|
|
|
+ const auditOptions = suggestionResult[index] || []
|
|
|
+ item.auditOptions = auditOptions
|
|
|
+ const auditId = suggestionFormData.value[item.auditIdProp]
|
|
|
+ const auditUser = auditOptions.find((v) => v.id === auditId) || {}
|
|
|
+ suggestionFormData.value[item.auditIdPropUser] = { ...auditUser, nickname: `${auditUser.nickname || ''}${auditUser.employeeNo ? `(${auditUser.employeeNo})` : ''}` }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }).finally(() => {
|
|
|
+ btnLoading.value = false
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const handleSubmitSuggestionAudit = () => {
|
|
|
+ suggestionFormRef.value?.validate().then(async (valid) => {
|
|
|
+ if (valid) {
|
|
|
+ btnLoading.value = true
|
|
|
+ const params = {
|
|
|
+ id: templateParams.value?.id,
|
|
|
+ auditUserIds: [suggestionFormData.value?.sugguestionAuditId],
|
|
|
+ approveUserIds: [suggestionFormData.value?.sugguestionApproveId]
|
|
|
+ }
|
|
|
+ BoilerTaskOrderApi.submitOpinionNoticeApproval(params).then((submitResult) => {
|
|
|
+ if (submitResult) {
|
|
|
+ emit('template-confirm')
|
|
|
+ }
|
|
|
+ }).catch(() => {
|
|
|
+ btnLoading.value = false
|
|
|
+ ElMessage.error('提交失败')
|
|
|
+ }).finally(() => {
|
|
|
+ btnLoading.value = false
|
|
|
+ isShowSuggestionAuditDialog.value = false
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const getUserLists = async (userList, params) => {
|
|
|
+ const nickname = params.nickname
|
|
|
+ const list = nickname ? userList.filter((item) => item.nickname.includes(nickname)) : userList
|
|
|
+ const optList = list.map((item) => ({
|
|
|
+ ...item,
|
|
|
+ nickname: `${item.nickname}${item.employeeNo ? `(${item.employeeNo})` : ''}`,
|
|
|
+ }))
|
|
|
+ return Promise.resolve({ list: optList, total: list.length })
|
|
|
+}
|
|
|
+
|
|
|
+const handleChangeHandler = (val, prop) => {
|
|
|
+ const { id } = val
|
|
|
+ suggestionFormData.value[prop] = id
|
|
|
+}
|
|
|
+
|
|
|
const getRecheckUserList = async (params) => {
|
|
|
params.orderId = props.taskInfo.id
|
|
|
return await BoilerTaskOrderApi.getRecheckUserList(params)
|
|
|
@@ -2799,7 +3051,7 @@ watch(() => props.isFullscreen, () => {
|
|
|
display: flex;
|
|
|
justify-content: flex-end;
|
|
|
gap: 16px;
|
|
|
- margin-bottom: 20px;
|
|
|
+
|
|
|
white-space: nowrap;
|
|
|
::v-deep .el-button {
|
|
|
margin-left: 0;
|
|
|
@@ -2845,8 +3097,146 @@ watch(() => props.isFullscreen, () => {
|
|
|
.preview-image,.preview-video {
|
|
|
height: 65vh;
|
|
|
max-width: 100vw;
|
|
|
- // object-fit: cover;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+.rectification-dialog {
|
|
|
+ padding: 8px 0;
|
|
|
+ .upload-section {
|
|
|
+ margin-bottom: 24px;
|
|
|
+ padding: 20px;
|
|
|
+ background: #fafafa;
|
|
|
+ border-radius: 8px;
|
|
|
+ transition: all 0.3s ease;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: #f5f5f5;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.required {
|
|
|
+ border: 1px solid #e8f4ff;
|
|
|
+ background: #f7fbff;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: #f0f8ff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .section-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin-bottom: 16px;
|
|
|
+
|
|
|
+ .header-left {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+
|
|
|
+ .section-title {
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #303133;
|
|
|
+ }
|
|
|
+
|
|
|
+ .required-mark {
|
|
|
+ color: #f56c6c;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: bold;
|
|
|
+ }
|
|
|
+
|
|
|
+ i[class^="icon-"] {
|
|
|
+ font-size: 18px;
|
|
|
+ color: #409eff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .section-tip {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+ background: #fff;
|
|
|
+ padding: 4px 12px;
|
|
|
+ border-radius: 12px;
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .upload-area {
|
|
|
+ min-height: 80px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .info-tips {
|
|
|
+ display: flex;
|
|
|
+ gap: 12px;
|
|
|
+ padding: 16px;
|
|
|
+ background: linear-gradient(135deg, #fff9e6 0%, #fff5cc 100%);
|
|
|
+ border-left: 4px solid #e6a23c;
|
|
|
+ border-radius: 6px;
|
|
|
+ margin-top: 20px;
|
|
|
+
|
|
|
+ .icon-info {
|
|
|
+ font-size: 20px;
|
|
|
+ color: #e6a23c;
|
|
|
+ flex-shrink: 0;
|
|
|
+ margin-top: 2px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .tips-content {
|
|
|
+ flex: 1;
|
|
|
+
|
|
|
+ .tips-title {
|
|
|
+ font-weight: 600;
|
|
|
+ color: #606266;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ p {
|
|
|
+ font-size: 13px;
|
|
|
+ color: #606266;
|
|
|
+ line-height: 1.8;
|
|
|
+ margin: 0;
|
|
|
+
|
|
|
+ &:not(.tips-title) {
|
|
|
+ padding-left: 12px;
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ &::before {
|
|
|
+ content: "•";
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ color: #e6a23c;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.icon-document::before {
|
|
|
+ content: "📄";
|
|
|
+}
|
|
|
+
|
|
|
+.icon-image::before {
|
|
|
+ content: "🖼️";
|
|
|
+}
|
|
|
+
|
|
|
+.icon-video::before {
|
|
|
+ content: "🎬";
|
|
|
+}
|
|
|
+
|
|
|
+.icon-info::before {
|
|
|
+ content: "ℹ️";
|
|
|
+}
|
|
|
+
|
|
|
+.dialog-content {
|
|
|
+ font-size: 15px;
|
|
|
+ line-height: 30px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
</style>
|