| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349 |
- <template>
- <ContentWrap>
- <el-form
- class="-mb-15px"
- :model="searchInfo"
- ref="queryFormRef"
- :inline="true"
- label-width="140px"
- >
- <el-form-item label="任务单号" prop="orderNo">
- <el-input
- v-model="searchInfo.orderNo"
- placeholder="请输入任务单号"
- clearable
- @keyup.enter="getList"
- class="!w-200px"
- />
- </el-form-item>
- <el-form-item label="工程号" prop="equipCode">
- <el-input
- v-model="searchInfo.equipCode"
- placeholder="请输入工程号"
- clearable
- @keyup.enter="getList"
- class="!w-200px"
- />
- </el-form-item>
- <el-form-item label="使用单位" prop="unitName">
- <el-input
- v-model="searchInfo.unitName"
- placeholder="请输入使用单位"
- clearable
- @keyup.enter="getList"
- class="!w-200px"
- />
- </el-form-item>
- <el-form-item label="检验性质" prop="checkType">
- <el-select
- v-model="searchInfo.checkType"
- placeholder="请选择检验性质"
- clearable
- class="!w-200px"
- >
- <el-option
- v-for="(item, key) in PressurePipeCheckTypeMap"
- :key="key"
- :label="item"
- :value="key"
- />
- </el-select>
- </el-form-item>
- <el-form-item label="设备类别" prop="equipType">
- <el-select
- v-model="searchInfo.equipType"
- placeholder="请选择设备类别"
- clearable
- class="!w-200px"
- >
- <el-option
- v-for="(item) in equipmentTypeMap"
- :key="item.value"
- :label="item.label"
- :value="item.value"
- />
- </el-select>
- </el-form-item>
- <el-form-item label="检验时间" prop="checkDate">
- <el-date-picker
- v-model="searchInfo.checkDate"
- value-format="YYYY-MM-DD HH:mm:ss"
- type="daterange"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
- class="!w-200px"
- />
- </el-form-item>
- <el-form-item label="检验员" prop="checkUserIds">
- <CustomUserSelectModal
- class="!w-200px"
- v-model="searchInfo.checkUserIds"
- :multiple="true"
- :collapse-tags="true"
- :collapse-tags-tooltip="true"
- clearable
- placeholder="请选择"
- />
- </el-form-item>
- <el-form-item label="接收人姓名" prop="recipient">
- <el-input
- v-model="searchInfo.recipient"
- placeholder="请输入接收人姓名"
- clearable
- @keyup.enter="getList"
- class="!w-200px"
- />
- </el-form-item>
- <el-form-item label="接收人手机号" prop="recipientPhone">
- <el-input
- v-model="searchInfo.recipientPhone"
- placeholder="请输入接收人手机号"
- clearable
- @keyup.enter="getList"
- class="!w-200px"
- />
- </el-form-item>
- <!-- <el-form-item label="剩余期限" prop="remainingDays">
- <el-input
- v-model="searchInfo.remainingDays"
- placeholder="请输入剩余期限"
- clearable
- @keyup.enter="getList"
- class="!w-200px"
- />
- </el-form-item> -->
- <el-form-item label="客户剩余期限" prop="remainingDays">
- <el-select
- v-model="searchInfo.isOverdue"
- placeholder="请选择客户剩余期限"
- clearable
- class="!w-200px"
- >
- <el-option label="未超期" :value="false" />
- <el-option label="已超期" :value="true" />
- </el-select>
- </el-form-item>
- <el-form-item label="所属部门" prop="deptId">
- <el-select v-model="searchInfo.deptId" placeholder="请选择所属部门" class="!w-200px">
- <el-option
- v-for="item in deptDataList"
- :key="item.id"
- :label="item.name"
- :value="item.id"
- />
- </el-select>
- </el-form-item>
- <el-form-item label="意见书经办人" prop="handlerIdList">
- <CustomUserSelectModal
- v-model="searchInfo.handlerId"
- :collapseTags="true"
- :collapseTagsTooltip="true"
- :multiple="false"
- placeholder="请选择用户"
- clearable
- class="!w-200px"
- />
- </el-form-item>
- <el-form-item label="检验通知书状态" prop="rectificationStatusList">
- <el-select
- v-model="searchInfo.rectificationStatusList"
- placeholder="请选择检验通知书状态"
- clearable
- multiple
- collapse-tags
- collapse-tags-tooltip
- class="!w-200px"
- >
- <el-option
- v-for="(item, key) in rectificationStatusMap"
- :key="key"
- :label="item"
- :value="key"
- />
- </el-select>
- </el-form-item>
- <el-form-item label="公众号推送客户状态" prop="mpSendStatusList">
- <el-select
- v-model="searchInfo.mpSendStatusList"
- placeholder="请选择任务状态"
- clearable
- multiple
- collapse-tags
- collapse-tags-tooltip
- class="!w-200px"
- >
- <el-option v-for="(item, key) in mpSendStatusMap" :key="key" :label="item" :value="key" />
- </el-select>
- </el-form-item>
- <el-form-item label="出具月份" prop="ratifyMonth">
- <el-date-picker
- v-model="searchInfo.ratifyMonth"
- type="month"
- value-format="YYYY-MM"
- placeholder="选择月份"
- clearable
- class="!w-200px"
- />
- </el-form-item>
- <el-form-item>
- <el-button @click="search(1)"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
- <el-button @click="search(2)"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
- </el-form-item>
- </el-form>
- </ContentWrap>
- <ContentWrap>
- <div class="toolBox">
- <el-button type="primary" plain @click="handleExport" :loading="exportLoading">
- <Icon icon="ep:download" class="mr-5px" /> 导出
- </el-button>
- <el-button type="primary" plain @click="batchRePush" :disabled="disabled">
- 批量消息推送
- </el-button>
- </div>
- <!-- <el-radio-group class="mb-[10px]" v-model="tableStatus" @change="handleRadioChange">
- <el-radio-button label="全部" value="" />
- <el-radio-button label="未发送" value="1" />
- <el-radio-button label="发送失败" value="2" />
- <el-radio-button label="已超期" value="3" />
- </el-radio-group> -->
- <el-table ref="tableRef" :data="dataSource" :stripe="true" border height="calc(100vh - 500px)">
- <el-table-column type="selection" width="55" fixed="left" />
- <el-table-column label="操作" align="center" min-width="300" fixed="left">
- <template #default="{ row }">
- <div class="flex justify-center">
- <!-- <el-button link type="primary" v-if="filerFileUrlShowFn(row)" @click="handleFilePreview(row)"> 查看附件 </el-button>-->
- <el-button link type="primary" @click="handleRePush(row)"> 消息推送 </el-button>
- <el-button link type="primary" @click="() => handleFollowRecord(row)">
- 跟进记录
- </el-button>
- <el-button
- link
- type="primary"
- @click="() => handleRowDownload(row)"
- :disabled="disabled"
- >
- 下载意见书
- </el-button>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="检验通知书状态" align="center" min-width="150px">
- <template #default="scope">
- {{ rectificationStatusMap[scope.row.rectificationStatus] }}
- </template>
- </el-table-column>
- <el-table-column label="意见书编号" align="center" prop="reportedNo" width="150px" />
- <el-table-column
- label="使用单位"
- align="center"
- prop="unitName"
- min-width="150px"
- show-overflow-tooltip
- >
- <template #default="{row}">
- <div style="color: #015293; cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" @click="handleUnitCodeFn(row.unitCode)">{{row.unitName}}</div>
- </template>
- </el-table-column>
- <el-table-column label="回收截止时间" align="center" prop="recycleExpireDate" min-width="170">
- <template #default="{ row }">
- {{ formatDate(row.recycleExpireDate,'YYYY-MM-DD') }}
- </template>
- </el-table-column>
- <el-table-column label="接收人姓名" align="center" prop="recipient" min-width="150px">
- <template #default="scope">
- {{ scope.row.recipient || '-' }}
- </template>
- </el-table-column>
- <el-table-column label="接收人手机号" align="center" prop="recipientPhone" min-width="150px">
- <template #default="scope">
- {{ scope.row.recipientPhone || '-' }}
- </template>
- </el-table-column>
- <el-table-column label="跟进记录手机号" align="center" prop="followRecordReceiverPhone" min-width="150px">
- <template #default="scope">
- {{ scope.row.followRecordReceiverPhone || '-' }}
- </template>
- </el-table-column>
- <!-- <el-table-column
- label="详细信息"
- align="center"
- prop="detailedInfo"
- min-width="150px"
- show-overflow-tooltip
- >
- <template #default="{ row }">
- <span class="cursor-pointer" @click="handleUpdateRow(row)">{{
- row.detailedInfo || '-'
- }}</span>
- </template>
- </el-table-column> -->
- <el-table-column
- label="发送方式"
- align="center"
- prop="distributionMethod"
- min-width="150px"
- show-overflow-tooltip
- />
- <el-table-column label="发送时间" align="center" prop="sendTime" min-width="170">
- <template #default="{ row }">
- {{ formatDate(row.sendTime) }}
- </template>
- </el-table-column>
- <el-table-column label="确认接收时间" align="center" prop="signTime" min-width="150px">
- <template #default="{ row }">
- {{ formatDate(row.signTime) }}
- </template>
- </el-table-column>
- <el-table-column label="回收时间" align="center" prop="rectificationTime" min-width="170">
- <template #default="{ row }">
- {{ formatDate(row.rectificationTime) }}
- </template>
- </el-table-column>
- <el-table-column label="检验员" align="center" prop="checkUsers" min-width="200">
- <template #default="scope">
- <div v-if="scope.row.checkUsers && scope.row.checkUsers.length > 0">
- <div v-for="user in scope.row.checkUsers" :key="user.id">
- {{ `${user.nickname}(${user.employeeNo})` }}
- </div>
- </div>
- <div v-else></div>
- </template>
- </el-table-column>
- <el-table-column
- align="center"
- label="客户剩余确认时间(天)"
- prop="confirmationTimeStr"
- min-width="190"
- >
- <template #default="{ row }">
- {{ row.rectificationStatus !== 0 ? '-' : row.confirmationTimeStr || '-' }}
- </template>
- </el-table-column>
- <el-table-column label="区域" align="center" prop="equipDistrictName" width="150px" />
- <el-table-column
- label="公众号推送客户状态"
- align="center"
- prop="mpSendStatus"
- min-width="155"
- >
- <template #default="{ row }">
- {{ mpSendStatusMap[row.mpSendStatus] || '-' }}
- </template>
- </el-table-column>
- <el-table-column label="任务单号" align="center" prop="orderNo" min-width="150px" />
- <el-table-column label="工程号" align="center" prop="equipCode" min-width="270">
- <template #default="{ row }">
- <div>
- {{ row.equipCode }}
- <el-tag v-if="row.productNo" type="success">
- {{ row.productNo }}
- </el-tag>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="使用证编号" align="center" prop="useRegisterNo" min-width="120" />
- <el-table-column
- label="设备类别"
- align="center"
- prop="equipmentType"
- min-width="150px"
- show-overflow-tooltip
- >
- <template #default="{ row }">
- {{ equipmentTypeMap.find((item) => item.value == row.equipmentType)?.label || '-' }}
- </template>
- </el-table-column>
- <el-table-column label="检验性质" align="center" prop="checkType" min-width="120px">
- <template #default="scope">
- {{ PressurePipeCheckTypeMap[scope.row.checkType] }}
- </template>
- </el-table-column>
- <el-table-column label="检验时间" align="center" prop="checkDate" min-width="120px">
- <template #default="{ row }">
- {{ formatArrayDate(row.checkDate) }}
- </template>
- </el-table-column>
- <el-table-column label="审批通过日期" align="center" prop="ratifyTime" min-width="120px">
- <template #default="{ row }">
- {{ formatDate(row.ratifyTime, "YYYY-MM-DD") }}
- </template>
- </el-table-column>
- <!-- <el-table-column
- label="剩余回收时间"
- align="center"
- prop="remainingRecoveryTimeStr"
- min-width="120px"
- /> -->
- <el-table-column label="所属部门" align="center" prop="deptName" min-width="180" />
- <el-table-column label="意见书经办人" align="center" prop="handlerInfoList" min-width="200">
- <template #default="{ row }">
- {{ row.handlerUserList?.map((item: Recordable) => item.nickname).join('/') || '' }}
- </template>
- </el-table-column>
- </el-table>
- <!-- 分页 -->
- <Pagination
- :total="pagination.total"
- v-model:page="pagination.pageNo"
- v-model:limit="pagination.pageSize"
- @pagination="getList"
- />
- </ContentWrap>
- <!-- 单个重新推送和批量重新推送 -->
- <el-dialog
- v-if="recipientDialogVisible"
- :title="recipientType === 'single' ? '重新推送' : '批量重新推送'"
- v-model="recipientDialogVisible"
- width="40%"
- :before-close="handleClose"
- >
- <ContentWrap>
- <el-form
- ref="recipientFormRef"
- :model="recipientFormData"
- :rules="recipientFormRules"
- label-width="140px"
- :validate-on-rule-change="false"
- >
- <el-form-item label="接收人名称:" prop="recipient">
- <el-input
- v-model="recipientFormData.recipient"
- placeholder="请输入接收人名称"
- class="!w-300px"
- />
- </el-form-item>
- <el-form-item label="接收人手机号码:" prop="recipientPhone">
- <el-input
- v-model="recipientFormData.recipientPhone"
- placeholder="请输入接收人手机号码"
- class="!w-300px"
- />
- </el-form-item>
- </el-form>
- </ContentWrap>
- <template #footer>
- <el-button @click="handleClose">取消</el-button>
- <el-button type="primary" :loading="submitting" @click="submitForm">提交</el-button>
- </template>
- </el-dialog>
- <!-- 预览查看下载报告 -->
- <CustomDialog
- v-model="showReportDialog"
- lock-scroll
- align-center
- :show-footer="false"
- width="1000px"
- top="0"
- class="h-[95vh] overflow-hidden"
- @cancel="handleCancel"
- >
- <el-button type="primary" v-if="isCanDownload" :disabled="!reportSource" @click="handleDownload"
- >下载</el-button
- >
- <el-scrollbar always noresize max-height="calc(95vh - 48px)">
- <VuePdfEmbed
- v-if="showReportDialog"
- v-loading="pdfLoading"
- :width="968"
- :source="reportSource"
- @rendered="handlePdfRendered"
- />
- </el-scrollbar>
- </CustomDialog>
- <ReportListUploadModal
- ref="reportListUploadModalRef"
- :flag="true"
- :selectedItem="currentReport"
- :reportList="allReportList"
- />
- <Dialog
- v-if="followRecordRespFlag"
- :close-on-click-modal="false"
- v-model:modelValue="followRecordRespFlag"
- title="跟进记录"
- width="70%"
- :showCancel="false"
- :showFooter="false"
- :dialogAttrs="{ showClose: false }"
- @close="handleCloseFollowRecordRespDialog"
- >
- <section v-loading="recordLoading">
- <SmartTable
- ref="followRecordRespTableRef"
- v-model:pageNo="followRecordRespTableParams.pageNo"
- v-model:pageSize="followRecordRespTableParams.pageSize"
- v-model:total="followRecordRespTableParams.total"
- :columns="getFollowRecordRespColumns"
- :data="followRecordRespList"
- :useBorderLayout="false"
- :showRefresh="false"
- :buttons="[]"
- height="450px"
- :page-sizes="[10, 20, 50, 100]"
- @on-page-no-change="() => followRecordRespTablePage()"
- @on-page-size-change="() => followRecordRespTablePage()"
- />
- <div class="flex gap-10px mt-10px" style="width: 100%">
- <div class="!w-[70px] flex items-center justify-end">类 型:</div>
- <div class="flex-1">
- <el-radio-group
- v-model="followParams.type"
- style="width: 100%"
- @change="handleFollowTypeChange"
- >
- <el-radio v-for="item in getFollowTypeList" :key="item.value" :value="item.value">
- {{ item.label }}
- </el-radio>
- </el-radio-group>
- </div>
- </div>
- <div v-if="followParams.type === 3" class="flex gap-10px mt-10px" style="width: 100%">
- <div class="!w-[90px] flex items-center justify-end">发送方式:</div>
- <div class="flex-1">
- <el-input
- v-model="followParams.distributionMethod"
- style="width: 100%"
- placeholder="请输入发送方式"
- show-word-limit
- :maxlength="20"
- />
- </div>
- </div>
- <div v-if="followParams.type === 3" class="flex gap-10px mt-10px" style="width: 100%">
- <div class="!w-[90px] flex items-center justify-end">接收人姓名:</div>
- <div class="flex-1">
- <el-input
- v-model="followParams.receiver"
- style="width: 100%"
- placeholder="请输入接收人姓名"
- show-word-limit
- :maxlength="20"
- />
- </div>
- </div>
- <div v-if="followParams.type === 3" class="flex gap-10px mt-10px" style="width: 100%">
- <div class="!w-[90px] flex items-center justify-end">接收人电话:</div>
- <div class="flex-1">
- <el-input
- v-model="followParams.receiverPhone"
- style="width: 100%"
- placeholder="请输入接收人电话"
- show-word-limit
- />
- </div>
- </div>
- <div v-if="followParams.type === 3" class="flex gap-10px mt-10px" style="width: 100%">
- <div class="!w-[90px] flex items-center justify-end">确认接收时间:</div>
- <div class="flex-1">
- <el-date-picker
- v-model="followParams.receiveConfirmTime"
- type="datetime"
- placeholder="选择时间"
- format="YYYY-MM-DD HH:mm:ss"
- value-format="x"
- />
- </div>
- </div>
- <div class="flex gap-10px mt-10px" style="width: 100%">
- <div class="!w-[90px] flex items-center justify-end">发送时间:</div>
- <div class="flex-1">
- <!-- 嵌入的时间选择器 -->
- <el-date-picker
- v-model="followParams.followTime"
- type="datetime"
- :disabled="[1, 4].includes(followParams.type)"
- placeholder="选择时间"
- format="YYYY-MM-DD HH:mm:ss"
- value-format="x"
- />
- </div>
- </div>
- <div class="flex gap-10px mt-10px" style="width: 100%">
- <div class="!w-[90px] text-right">跟进记录:</div>
- <div class="flex-1">
- <div class="flex-1">
- <div
- style="
- border: 1px solid #dcdfe6;
- border-radius: 4px;
- padding: 10px;
- display: flex;
- flex-direction: column;
- gap: 10px;
- "
- >
- <!-- 模拟的 textarea 输入框 -->
- <el-input
- v-model="followParams.remark"
- type="textarea"
- :maxlength="300"
- show-word-limit
- :rows="7"
- placeholder="请输入内容"
- style="
- width: 100%;
- border: none;
- resize: vertical;
- outline: none;
- font-family: inherit;
- "
- />
- <div
- style="
- width: 100%;
- display: flex;
- justify-content: space-between;
- align-items: center;
- "
- >
-
- <div
- >跟进人:<el-tag
- >{{ userStore.getUser.nickname }}{{ userStore.getUser.employeeNo }}</el-tag
- ></div
- >
- </div>
- </div>
- </div>
- </div>
- </div>
- <div class="dialog-footer">
- <el-button type="primary" @click="handleFollowRecordRespConfirm">保存</el-button>
- <el-button type="default" @click="followRecordRespFlag = false">取消</el-button>
- </div>
- </section>
- </Dialog>
- <Dialog
- :close-on-click-modal="false"
- v-model:modelValue="updateDialogVisible"
- title="更新详细信息"
- width="60%"
- :showCancel="false"
- :showFooter="false"
- :dialogAttrs="{ showClose: false }"
- @close="handleCloseUpdateDialog"
- >
- <section v-loading="recordLoading">
- <el-form
- ref="updateFormRef"
- :model="updateFormData"
- :rules="updateFormRules"
- label-width="100px"
- :validate-on-rule-change="false"
- >
- <el-form-item label="详细信息:" prop="detailedInfo">
- <el-input
- v-model="updateFormData.detailedInfo"
- placeholder="请输入详细信息"
- type="textarea"
- :rows="7"
- show-word-limit
- maxlength="300"
- class="!w-full"
- />
- </el-form-item>
- </el-form>
- <div class="dialog-footer">
- <el-button type="primary" @click="handleUpdateFollowRecordRespConfirm">保存</el-button>
- <el-button type="default" @click="handleCloseUpdateDialog">取消</el-button>
- </div>
- </section>
- </Dialog>
- <unitContainerForm ref="unitContainerFormRef" />
- <!-- PDF预览 + 消息推送弹窗 -->
- <FilePreview
- v-if="previewVisible"
- v-model="previewVisible"
- :id="currentPreviewId"
- :reportId="currentReportId"
- :filename="currentFilename"
- :title="'检验意见通知书'"
- @close="handlePreviewClose"
- @sbmit="fiePreviewEmitFn"
- />
- </template>
- <script setup lang="ts">
- import { ref, reactive } from 'vue'
- import VuePdfEmbed from 'vue-pdf-embed'
- import {PressurePipeCheckTypeMap} from '@/utils/constants'
- import unitContainerForm from '@/components/unitContainerForm/index.vue'
- import { formatArrayDate, formatDate } from '@/utils/formatTime'
- import { ElMessage, FormRules, ElForm, FormInstance } from 'element-plus'
- import ReportListUploadModal from '@/views/pressure/checker/components/reportListUploadModal.vue'
- import { PipeTaskOrderApi, PipeTaskOrderOrderItemVO } from '@/api/pressure2/pipetaskorder'
- import { getDeptList } from '@/api/laboratory/dept'
- import CustomUserSelectModal from '@/components/SmartTable/components/selectUserModal.vue'
- import SmartTable from '@/components/SmartTable/SmartTable'
- import { usePageLoading } from '@/hooks/web/usePageLoading'
- import FilePreview from './component/FilePreview.vue'
- import { useRoute } from 'vue-router'
- import {DICT_TYPE, getStrDictOptions} from '@/utils/dict'
- const route = useRoute()
- const { loadStart, loadDone } = usePageLoading()
- const reportListUploadModalRef = ref<InstanceType<typeof ReportListUploadModal>>()
- const unitContainerFormRef = ref<InstanceType<typeof unitContainerForm>>()
- const userStore = useUserStoreWithOut() // 用户信息缓存
- const equipmentTypeMap = getStrDictOptions(DICT_TYPE.PIPE_TYPE)
- import dayJs from 'dayjs'
- import download from '@/utils/download'
- import { cloneDeep } from 'lodash-es'
- import { useUserStoreWithOut } from '@/store/modules/user'
- import { buildFileUrl } from '@/utils'
- import {PipeInputApi} from "@/api/pressure2/pipeInput";
- const currentPreviewId = ref<string>('')
- const currentFilename = ref<string>('')
- const previewVisible = ref<boolean>(false)
- const currentReportId = ref<string>('')
- const message = useMessage() // 消息弹窗
- const currentReport = ref<any>({})
- // 表单数据
- const recipientRow = ref<Record<string, any>>({})
- const recipientType = ref<'single' | 'batch'>()
- const recipientFormRef = ref<InstanceType<typeof ElForm>>()
- const allReportList = ref<any>([])
- const recipientFormData = reactive<any>({
- recipient: '',
- recipientPhone: ''
- })
- // 表单验证规则 - 只在提交时验证,不设置实时验证触发器
- const recipientFormRules = ref<FormRules<any>>({
- recipient: [{ required: true, message: '请输入接收人名称' }],
- recipientPhone: [
- { required: true, message: '请输入接收人手机号码' },
- { type: 'pattern', pattern: /^1[3-9]\d{9}$/, message: '请输入正确的接收人手机号码' }
- ]
- })
- const recipientDialogVisible = ref(false)
- const submitting = ref(false)
- const submitForm = async () => {
- const subFormValid = await recipientFormRef.value?.validate()
- if (!subFormValid) {
- ElMessage.warning('请填写完整的表单信息')
- return
- }
- submitting.value = true
- let fetchApi
- let params
- if (recipientType.value === 'single') {
- params = {
- ...recipientFormData,
- id: recipientRow.value.reportId
- }
- fetchApi = PipeTaskOrderApi.inspectionOpinionSend
- } else {
- const list = tableRef.value.getSelectionRows()
- params = list.map((item) => ({
- id: item.reportId,
- ...recipientFormData
- }))
- fetchApi = PipeTaskOrderApi.inspectionOpinionSendBatch
- }
- try {
- await fetchApi(params)
- ElMessage.success(recipientType.value === 'single' ? '重新推送成功' : '批量重新推送成功')
- handleClose()
- handlePreviewClose()
- getList()
- } finally {
- submitting.value = false
- }
- }
- // 关闭对话框
- const handleClose = () => {
- recipientDialogVisible.value = false
- recipientRow.value = {}
- recipientFormRef.value?.resetFields()
- }
- const rectificationStatusMap = reactive({
- 0: '待确认',
- 1: '待整改',
- 2: '已提交',
- 3: '材料有误',
- 4: '整改通过',
- 5: '整改不通过'
- })
- const mpSendStatusMap = reactive({
- '0': '成功',
- '1': '拒绝接收',
- '2': '其他原因失败',
- '3': '发送失败',
- '4': '未发送'
- })
- const queryFormRef = ref<FormInstance>()
- const searchInfo = ref({
- handlerId: userStore.getUser.id,
- // rectificationStatusList: ['0']
- }) as any
- const dataSource = ref<PipeTaskOrderOrderItemVO[]>([]) // 列表数据源
- const pagination = ref({
- pageNo: 1,
- pageSize: 20,
- total: 0
- })
- const tableRef = ref(null) as any
- // 获取部门数据
- const deptDataList = ref<any>([]) // 部门数据
- const getDeptDataList = async () => {
- const res = await getDeptList({ pageNo: 1, pageSize: 1000 })
- deptDataList.value = res || []
- }
- /**
- * 获取列表数据
- */
- const getList = async () => {
- // getReportCountData()
- loadStart()
- try {
- const params: any = cloneDeep({
- ...searchInfo.value,
- orderByType: 2,
- pageNo: pagination.value.pageNo,
- pageSize: pagination.value.pageSize
- })
- // 出具月份转换
- if (params.ratifyMonth) {
- const [y, m] = params.ratifyMonth.split('-')
- params.ratifyTimeStart = `${y}-${m}-01 00:00:00`
- const lastDay = new Date(Number(y), Number(m), 0).getDate()
- params.ratifyTimeEnd = `${y}-${m}-${String(lastDay).padStart(2, '0')} 23:59:59`
- delete params.ratifyMonth
- }
- if (!params.tableStatus) delete params.tableStatus
- const res = await PipeTaskOrderApi.getCheckBookList(params)
- dataSource.value = res?.list || []
- pagination.value.total = res?.total || 0
- } catch (error) {
- dataSource.value = []
- pagination.value.total = 0
- ElMessage.error('获取列表数据失败')
- } finally {
- loadDone()
- }
- }
- /**
- * 搜索、重置
- * @param type 1 搜索 2重置
- */
- const search = (type: number) => {
- if (type == 2) {
- tableStatus.value = ''
- // queryFormRef.value?.resetFields()
- searchInfo.value = {
- handlerId: userStore.getUser.id
- }
- }
- getList()
- }
- const showReportDialog = ref(false)
- const pdfLoading = ref(false)
- const reportSource = ref('')
- const handlePdfRendered = () => {
- pdfLoading.value = false
- }
- const handleCancel = () => {
- isCanDownload.value = false
- reportSource.value = ''
- }
- const isCanDownload = ref(false)
- const handleDownload = () => {
- reportSource.value && window.open(reportSource.value, '_blank')
- }
- /**
- * 批量重新推送
- */
- const batchRePush = async () => {
- const list = tableRef.value.getSelectionRows()
- if (!list.length) {
- ElMessage.warning('请选择数据进行操作!')
- return
- }
- recipientType.value = 'batch'
- recipientDialogVisible.value = true
- }
- /**
- * 重新推送
- */
- const handleRePush = async (row) => {
- recipientRow.value = row
- recipientType.value = 'single'
- currentReportId.value = row.opinionReportedUrl
- currentPreviewId.value = row.id
- currentFilename.value = '检验意见通知书.pdf'
- // 重置上次推送的接收人信息
- recipientFormData.recipient = ''
- recipientFormData.recipientPhone = ''
- previewVisible.value = true
- }
- const fiePreviewEmitFn = async () => {
- try {
- recipientFormData.recipient = (recipientRow.value as any).recipient || (recipientRow.value as any).defaultRecipient || ''
- recipientFormData.recipientPhone = (recipientRow.value as any).recipientPhone || (recipientRow.value as any).defaultRecipientPhone || ''
- } catch (e) {
- console.warn('获取推送接收人信息失败,使用默认值', e)
- }
- // 兜底使用行数据中的默认值
- if (!recipientFormData.recipient) {
- recipientFormData.recipient = (recipientRow.value as any).defaultRecipient || ''
- recipientFormData.recipientPhone = (recipientRow.value as any).defaultRecipientPhone || ''
- }
- recipientDialogVisible.value = true
- }
- const handleFilePreview = (row) => {
- currentReport.value = row
- allReportList.value = [{id: row.id, reportName: row.reportName}]
- reportListUploadModalRef.value?.openModal(false, currentReport.value)
- }
- const filerFileUrlShowFn = (row) => {
- if (row?.attachment || row?.image || row?.video) {
- return true
- }else {
- return false
- }
- }
- // 存储展开状态的响应式数据
- // 判断行是否展开
- // 切换展开状态
- const disabled = ref(false)
- const exportLoading = ref(false)
- /**
- * 导出
- */
- const handleExport = async () => {
- const list = tableRef.value.getSelectionRows()
- if (!list.length) {
- ElMessage.warning('请选择数据进行操作!')
- return
- }
- const confirm = await message.exportConfirm().catch(() => false)
- if (!confirm) return
- try {
- exportLoading.value = true
- loadStart()
- const params = {
- ...searchInfo.value,
- pageNo: pagination.value.pageNo,
- pageSize: pagination.value.pageSize
- }
- params.idList = list?.map((m) => m.id) || []
- const data = await PipeTaskOrderApi.opinionReportedExcel(params)
- download.excel(data, `检验意见通知书-${dayJs().format('YYYYMMDDHHmmss')}.xlsx`)
- } catch (err) {
- console.log('err:log', err)
- ElMessage.error('导出失败')
- } finally {
- exportLoading.value = false
- loadDone()
- }
- }
- // 跟进记录
- const followRecordRespFlag = ref<boolean>(false)
- const recordLoading = ref<boolean>(false)
- const followRecordRespTableParams = reactive({
- pageNo: 1,
- pageSize: 10,
- total: 0
- })
- const followRecordRespList = ref<any[]>([])
- const currentRow = ref<Recordable>({})
- const followParams = ref<Recordable>({
- type: undefined,
- remark: undefined,
- distributionMethod: undefined,
- receiverPhone: undefined,
- receiver: undefined,
- receiveConfirmTime: undefined,
- followTime: new Date().getTime()
- })
- const followTypeList = reactive([
- {
- label: '消息推送',
- value: 0
- },
- {
- label: '跟进情况',
- value: 1
- },
- {
- label: '线下材料递交',
- value: 2
- },
- {
- label: '人工消息推送',
- value: 3
- },
- {
- label: '客户未回复意见书',
- value: 4
- }
- ])
- const getFollowTypeList = followTypeList.filter((item) => item.value !== 0)
- const getFollowRecordRespColumns = ref([
- {
- label: '序号',
- prop: 'index',
- fieldProps: {
- type: 'index',
- align: 'center',
- width: 80
- }
- },
- {
- label: '类型',
- prop: 'type',
- fieldProps: {
- align: 'center',
- minWidth: 120,
- showOverflowTooltip: true
- },
- render: (_row, value) => followTypeList.find((item) => item.value === value)?.label || ''
- },
- {
- label: '发送方式',
- prop: 'distributionMethod',
- fieldProps: {
- align: 'center',
- minWidth: 120,
- showOverflowTooltip: true
- }
- },
- {
- label: '跟进记录手机号',
- prop: 'followRecordReceiverPhone',
- fieldProps: {
- align: 'center',
- minWidth: 140,
- showOverflowTooltip: true
- }
- },
- {
- label: '跟进时间',
- prop: 'followTime',
- fieldProps: {
- align: 'center',
- minWidth: 135,
- showOverflowTooltip: true
- },
- render: (_row, value) => dayJs(value).format('YYYY-MM-DD HH:mm:ss')
- },
- {
- label: '备注',
- prop: 'remark',
- fieldProps: {
- align: 'center',
- minWidth: 255,
- showOverflowTooltip: true
- }
- },
- {
- label: '跟进人',
- prop: 'creatorName',
- fieldProps: {
- align: 'center',
- minWidth: 120,
- showOverflowTooltip: true
- }
- }
- ])
- const handleCloseFollowRecordRespDialog = () => {
- followRecordRespFlag.value = false
- currentRow.value = {}
- }
- const handleFollowTypeChange = (val: number) => {
- followParams.value.distributionMethod = undefined
- followParams.value.remark = val === 2 ? '客户线下递交整改材料' : ''
- }
- const handleFollowRecordRespConfirm = async () => {
- if (!followParams.value.type) {
- ElMessage.error('请选择跟进类型')
- return
- }
- if (followParams.value.type === 3 && !followParams.value.distributionMethod) {
- ElMessage.error('请输入发送方式')
- return
- }
- if (followParams.value.type === 3 && !followParams.value.receiveConfirmTime) {
- ElMessage.error('请选择确认接收时间')
- return
- }
- if (!followParams.value.remark) {
- ElMessage.error('请输入跟进记录')
- return
- }
- if (!followParams.value.followTime) {
- ElMessage.error('请输入跟进时间')
- return
- }
- recordLoading.value = true
- const params = {
- ...followParams.value,
- reportId: currentRow.value.reportId,
- equipMainType: 300
- }
- if (followParams.value.type != 3) {
- delete params.receiveConfirmTime
- delete params.receiverPhone
- delete params.receiver
- }
- try {
- const res = await PipeTaskOrderApi.createFollowRecord(params)
- followRecordRespFlag.value = false
- currentRow.value = {}
- if (res) {
- ElMessage.success('保存成功')
- followRecordRespFlag.value = false
- getList()
- }
- } finally {
- recordLoading.value = false
- }
- }
- const handleFollowRecord = (row) => {
- currentRow.value = row
- followParams.value = {
- type: undefined,
- remark: undefined,
- distributionMethod: undefined,
- followTime: new Date().getTime()
- }
- followRecordRespTablePage()
- followRecordRespFlag.value = true
- }
- const followRecordRespTablePage = async () => {
- const params = {
- pageNo: followRecordRespTableParams.pageNo,
- pageSize: followRecordRespTableParams.pageSize,
- reportId: currentRow.value.reportId
- }
- recordLoading.value = true
- const recordRes = await PipeTaskOrderApi.getFollowRecordList(params)
- followRecordRespList.value = recordRes?.list || []
- followRecordRespTableParams.total = recordRes?.total || 0
- recordLoading.value = false
- }
- const updateDialogVisible = ref(false)
- const handleUpdateRow = (row) => {
- updateFormData.value = {
- id: row.reportId,
- detailedInfo: row.detailedInfo
- }
- updateDialogVisible.value = true
- }
- const handleCloseUpdateDialog = () => {
- updateDialogVisible.value = false
- updateFormData.value = {}
- }
- const handleUpdateFollowRecordRespConfirm = async () => {
- updateFormRef.value?.validate().then(() => {
- recordLoading.value = true
- PipeTaskOrderApi
- .updateFollowRecord({ ...updateFormData.value })
- .then(() => {
- ElMessage.success('更新成功')
- updateDialogVisible.value = false
- getList()
- })
- .finally(() => {
- recordLoading.value = false
- })
- })
- }
- const updateFormRef = ref<FormInstance>()
- const updateFormData = ref<Recordable>({})
- const updateFormRules = reactive({
- detailedInfo: [{ required: true, message: '请输入详细信息', trigger: ['blur'] }]
- })
- // tableStatus 表格状态查询
- const tableStatus = ref('')
- const handleRadioChange = (val) => {
- switch (val) {
- case '1':
- searchInfo.value.handlerId = userStore.getUser.id
- searchInfo.value.mpSendStatus = ['4']
- searchInfo.value.rectificationStatusList = ['0']
- delete searchInfo.value.isOverdue
- break
- case '2':
- searchInfo.value.handlerId = userStore.getUser.id
- searchInfo.value.mpSendStatus = ['1', '2', '3']
- searchInfo.value.rectificationStatusList = ['0']
- delete searchInfo.value.isOverdue
- break
- case '3':
- searchInfo.value.handlerId = userStore.getUser.id
- searchInfo.value.rectificationStatusList = ['0']
- searchInfo.value.isOverdue = true
- break
- default:
- searchInfo.value = {
- handlerId: userStore.getUser.id
- }
- break
- }
- getList()
- }
- // 下载意见书
- const downloadFile = async (blob, filename) => {
- try{
- //创建一个链接来触发下载
- const link = document.createElement('a')
- const objectUrl = URL.createObjectURL(blob)
- link.href = objectUrl
- link.download = filename
- // 触发点击事件来下载文件
- document.body.appendChild(link)
- link.click()
- // 清理
- document.body.removeChild(link)
- URL.revokeObjectURL(objectUrl)
- } catch (error) {console.error('下载文件时发生错误',error)
- ElMessage.error('下载失败')
- }
- }
- const handleRowDownload = async (row) => {
- let data: any[] = []
- data.push({
- taskStatus: 100,
- templateId: row.templateId,
- reportUrl: '',
- id: row.reportId,
- })
- const loadingInstance = ElLoading.service({
- fullscreen: true,
- text: '正在生成...'
- })
- const { reportedNo, opinionReportedUrl } = row
- loadStart()
- try {
- // 调用 API 获取 ZIP blob
- const pdfBlob = await PipeInputApi.handlePrint(data)
- if (pdfBlob) {
- downloadFile(pdfBlob, `${reportedNo}检验意见通知书.pdf`)
- } else {
- ElMessage.error('获取文件失败')
- }
- } catch (error) {
- ElMessage.error('下载失败')
- } finally {
- loadingInstance.close()
- loadDone()
- }
- }
- const handleUnitCodeFn = (code) => {
- if (!code) {
- return ElMessage.warning('该单位信息异常!')
- }
- unitContainerFormRef.value?.open('', code)
- }
- const handlePreviewClose = () => {
- currentPreviewId.value = ''
- currentFilename.value = ''
- currentReportId.value = ''
- previewVisible.value = false
- }
- const { bpmUserId } = route.query as Recordable
- if (bpmUserId) {
- searchInfo.value.inspectorIds = [bpmUserId]
- searchInfo.value.rectificationStatus = '0'
- }
- getList()
- getDeptDataList()
- </script>
- <style lang="scss" scoped>
- .report-name-list {
- word-wrap: break-word; /* 自动换行 */
- white-space: pre-wrap; /* 保留空格并换行 */
- word-break: break-word; /* 在单词之间也能换行 */
- }
- .toolBox {
- margin-bottom: 20px;
- }
- .reportDOList-item {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- width: 100%;
- //max-width: 150px;
- }
- .report-item-animated {
- line-height: 1.5;
- }
- .report-name-list {
- position: relative;
- .collapsed::after {
- content: '';
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- height: 15px;
- background: linear-gradient(transparent, rgba(255, 255, 255, 0.9));
- pointer-events: none;
- }
- }
- .dialog-footer {
- box-sizing: border-box;
- padding-top: 20px;
- margin-top: 20px;
- display: flex;
- justify-content: flex-end;
- align-items: center;
- border-top: 1px solid #dcdfe6;
- }
- </style>
|