| | |
| | | class="dialog-wrapper" |
| | | v-loading="loading" |
| | | > |
| | | <el-scrollbar |
| | | ref="scrollbarRef" |
| | | height="50vh" |
| | | v-loading="loading" |
| | | :always="true" |
| | | > |
| | | <el-scrollbar ref="scrollbarRef" height="50vh" v-loading="loading" :always="true"> |
| | | <el-checkbox-group v-model="checkList"> |
| | | <el-space |
| | | direction="vertical" |
| | | alignment="flex-start" |
| | | fill |
| | | style="width: 90%" |
| | | > |
| | | <el-space direction="vertical" alignment="flex-start" fill style="width: 90%"> |
| | | <el-checkbox |
| | | v-for="(item, index) in sceneInfoList" |
| | | :key="item.scense.guid" |
| | |
| | | :class="(item.invalid ? 'checkbox-invalid' : '') + ' checkbox'" |
| | | > |
| | | <div> |
| | | <el-text size="large" truncated style="width: 600px">{{ |
| | | item.scense.name |
| | | }}</el-text> |
| | | <el-text size="large" truncated style="width: 600px">{{ item.scense.name }}</el-text> |
| | | </div> |
| | | <div class="m-t-4"> |
| | | <el-text size="small">{{ |
| | | '地址:' + item.scense.location |
| | | }}</el-text> |
| | | <el-text size="small">{{ '地址:' + item.scense.location }}</el-text> |
| | | </div> |
| | | <el-row justify="space-between"> |
| | | <el-space class="m-t-4"> |
| | | <el-tag> |
| | | {{ |
| | | item.scense.cityname + |
| | | item.scense.districtname + |
| | | item.scense.townname |
| | | }} |
| | | {{ item.scense.cityname + item.scense.districtname + item.scense.townname }} |
| | | </el-tag> |
| | | <el-tag>{{ item.scense.type }}</el-tag> |
| | | </el-space> |
| | |
| | | :loading="item._loading" |
| | | :disabled="item._isFirstInspect" |
| | | inline-prompt |
| | | style=" |
| | | --el-switch-on-color: #13ce66; |
| | | --el-switch-off-color: #c75000; |
| | | " |
| | | style="--el-switch-on-color: #13ce66; --el-switch-off-color: #c75000" |
| | | active-text="详版" |
| | | inactive-text="简版" |
| | | /> |
| | |
| | | type="default" |
| | | size="small" |
| | | class="m-t-4" |
| | | icon="IconPrinter" |
| | | :disabled="!item._valid" |
| | | @click="handlePreview(item)" |
| | | > |
| | | <el-icon> |
| | | <Icon icon="solar:printer-minimalistic-line-duotone" /> |
| | | </el-icon> |
| | | </el-button> |
| | | </el-space> |
| | | </el-row> |
| | |
| | | </el-scrollbar> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="danger" @click="cancel" icon="CloseBold" |
| | | >取消</el-button |
| | | > |
| | | <el-button type="danger" @click="cancel" icon="CloseBold">取消</el-button> |
| | | <el-button |
| | | type="primary" |
| | | :loading="docLoading" |
| | |
| | | :loading="docLoading" |
| | | :disabled="checkList.length == 0" |
| | | @click="handlePreview()" |
| | | icon="IconPrinter" |
| | | > |
| | | <el-icon class="el-icon--left"> |
| | | <Icon icon="solar:printer-minimalistic-line-duotone" /> |
| | | </el-icon> |
| | | 打印所选 |
| | | </el-button> |
| | | </div> |
| | |
| | | <el-dialog v-model="previewVisible" :show-close="false" fullscreen> |
| | | <template #header="{ close, titleId, titleClass }"> |
| | | <el-row justify="end" style="background-color: white"> |
| | | <el-button type="danger" @click="close" icon="CircleCloseFilled"> |
| | | 关闭 |
| | | </el-button> |
| | | <el-button |
| | | type="primary" |
| | | @click="handelPrint(refWord)" |
| | | icon="IconPrinter" |
| | | > |
| | | <el-button type="danger" @click="close" icon="CircleCloseFilled"> 关闭 </el-button> |
| | | <el-button type="primary" @click="handelPrint(refWord)" icon="IconPrinter"> |
| | | 打印 |
| | | </el-button> |
| | | </el-row> |
| | | </template> |
| | | <div ref="refWord"> |
| | | <div |
| | | :id="`word-preview-${i}`" |
| | | v-for="(item, i) in previewList" |
| | | :key="item" |
| | | ></div> |
| | | <div :id="`word-preview-${i}`" v-for="(item, i) in previewList" :key="item"></div> |
| | | </div> |
| | | <!-- <iframe ref="pdfPreview" width="100%" height="100vh" style="height: calc(100vh - 60px);"></iframe> --> |
| | | </el-dialog> |
| | |
| | | /** |
| | | * 场景巡查单据自动下载 |
| | | */ |
| | | import { ref, watch } from 'vue'; |
| | | import { useRouter } from 'vue-router'; |
| | | import { Icon } from '@iconify/vue' |
| | | import { ref, watch } from 'vue' |
| | | import { useRouter } from 'vue-router' |
| | | import { |
| | | exportDocx, |
| | | prepareDocxBlob, |
| | | preparePdf, |
| | | previewDocx, |
| | | downloadDocx, |
| | | print |
| | | } from '@/utils/doc'; |
| | | import sceneApi from '@/api/fysp/sceneApi'; |
| | | import subtaskApi from '@/api/fysp/subtaskApi'; |
| | | print, |
| | | } from '@/utils/doc' |
| | | import sceneApi from '@/api/fysp/sceneApi' |
| | | import subtaskApi from '@/api/fysp/subtaskApi' |
| | | |
| | | // 2025.12.22:有巡查单据模板的场景类型,[1:工地, 5:餐饮] |
| | | const validSceneType = [1, 5]; |
| | | const validSceneType = [1, 5] |
| | | |
| | | const props = defineProps({ |
| | | // 对话框开关 |
| | | modelValue: Boolean, |
| | | // 场景基础信息数组 |
| | | value: Array, |
| | | previewElement: String |
| | | }); |
| | | previewElement: String, |
| | | }) |
| | | |
| | | const emits = defineEmits(['update:modelValue']); |
| | | const emits = defineEmits(['update:modelValue']) |
| | | |
| | | const router = useRouter(); |
| | | const router = useRouter() |
| | | |
| | | const refWord = ref(null); |
| | | const pdfPreview = ref(null); |
| | | const refWord = ref(null) |
| | | const pdfPreview = ref(null) |
| | | |
| | | const loading = ref(false); |
| | | const scrollbarRef = ref(); |
| | | const sceneInfoList = ref([]); |
| | | const checkList = ref([]); |
| | | const docLoading = ref(false); |
| | | const loading = ref(false) |
| | | const scrollbarRef = ref() |
| | | const sceneInfoList = ref([]) |
| | | const checkList = ref([]) |
| | | const docLoading = ref(false) |
| | | |
| | | // 预览对话框开关 |
| | | const previewVisible = ref(false); |
| | | const previewVisible = ref(false) |
| | | // 预览的文档 |
| | | const previewList = ref([]); |
| | | const previewList = ref([]) |
| | | |
| | | watch( |
| | | () => [props.modelValue, props.value], |
| | | (nV, oV) => { |
| | | if (nV[0] && nV[1] && nV[1] != oV[1]) { |
| | | fetchSceneInfo(nV[1]); |
| | | fetchSceneInfo(nV[1]) |
| | | } |
| | | } |
| | | ); |
| | | }, |
| | | ) |
| | | |
| | | function fetchSceneInfo(sceneIdList) { |
| | | loading.value = true; |
| | | sceneInfoList.value = []; |
| | | checkList.value = []; |
| | | loading.value = true |
| | | sceneInfoList.value = [] |
| | | checkList.value = [] |
| | | sceneIdList.forEach((sid) => { |
| | | sceneApi |
| | | .getSceneDetail(sid) |
| | | .then((res) => { |
| | | sceneInfoList.value.push(res.data); |
| | | sceneInfoList.value.push(res.data) |
| | | if (validSceneType.indexOf(res.data?.scense?.typeid) != -1) { |
| | | checkList.value.push(sceneInfoList.value.length - 1); |
| | | checkList.value.push(sceneInfoList.value.length - 1) |
| | | |
| | | // todo _valid 的逻辑有错误 |
| | | const lastScene = sceneInfoList.value[sceneInfoList.value.length - 1]; |
| | | lastScene._valid = true; |
| | | lastScene._loading = true; |
| | | const lastScene = sceneInfoList.value[sceneInfoList.value.length - 1] |
| | | lastScene._valid = true |
| | | lastScene._loading = true |
| | | subtaskApi |
| | | .findByDate(sid) |
| | | .then((res) => { |
| | | if (res.length == 0) { |
| | | lastScene._isFirstInspect = true; |
| | | lastScene._isDetail = true; |
| | | lastScene._isFirstInspect = true |
| | | lastScene._isDetail = true |
| | | } |
| | | }) |
| | | .finally(() => { |
| | | lastScene._loading = false; |
| | | }); |
| | | lastScene._loading = false |
| | | }) |
| | | } |
| | | }) |
| | | .finally(() => { |
| | | loading.value = false; |
| | | scrollbarRef.value.setScrollTop(0); |
| | | }); |
| | | }); |
| | | loading.value = false |
| | | scrollbarRef.value.setScrollTop(0) |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | function handleDialogChange(value) { |
| | | emits('update:modelValue', value); |
| | | emits('update:modelValue', value) |
| | | } |
| | | |
| | | function setParam(value, length) { |
| | | const _value = value ? value : ''; |
| | | const offset = length - _value.length; |
| | | const _value = value ? value : '' |
| | | const offset = length - _value.length |
| | | if (offset > 0) { |
| | | let str = _value; |
| | | let str = _value |
| | | for (let i = 0; i < offset; i++) { |
| | | str += ' '; |
| | | str += ' ' |
| | | } |
| | | return str; |
| | | return str |
| | | } else { |
| | | return _value; |
| | | return _value |
| | | } |
| | | } |
| | | |
| | |
| | | const selected = item |
| | | ? [item] |
| | | : sceneInfoList.value.filter((v, i) => { |
| | | return checkList.value.indexOf(i) != -1; |
| | | }); |
| | | return checkList.value.indexOf(i) != -1 |
| | | }) |
| | | const param = selected.map((v) => { |
| | | switch (v.scense.typeid) { |
| | | // 工地 |
| | |
| | | district: v.scense?.districtname ?? '', |
| | | name: setParam(v.scense?.name ?? '', 0), |
| | | employerUnit: setParam(v.subScene?.csEmployerUnit ?? '', 0), |
| | | constructionUnit: setParam( |
| | | v.subScene ? v.subScene.csConstructionUnit : '', |
| | | 0 |
| | | ), |
| | | constructionUnit: setParam(v.subScene ? v.subScene.csConstructionUnit : '', 0), |
| | | timeRange: setParam( |
| | | v.subScene && v.subScene.csStartTime |
| | | ? `${v.subScene.csStartTime}至${v.subScene.csEndTime}` |
| | | : '', |
| | | 0 |
| | | 0, |
| | | ), |
| | | stage: setParam(v.subScene ? v.subScene.siExtension1 : '', 0), |
| | | contacts: setParam(v.scense?.contacts ?? '', 0), |
| | | contactsTel: setParam(v.scense?.contactst ?? '', 0), |
| | | location: setParam(v.scense?.location ?? '', 0) |
| | | location: setParam(v.scense?.location ?? '', 0), |
| | | }, |
| | | } |
| | | }; |
| | | // 餐饮 |
| | | case 5: |
| | | return { |
| | |
| | | location: setParam(v.scense.location, 63), |
| | | name: setParam(v.scense.name, 64), |
| | | contacts: setParam(v.scense.contacts, 67), |
| | | contactsTel: setParam(v.scense.contactst, 62) |
| | | contactsTel: setParam(v.scense.contactst, 62), |
| | | }, |
| | | } |
| | | }; |
| | | // default: |
| | | // v.invalid = true; |
| | | // return undefined; |
| | | } |
| | | }); |
| | | }) |
| | | |
| | | return param; |
| | | return param |
| | | } |
| | | |
| | | // 根据场景类型,生成对应的word文档 |
| | | function generateDoc(param, callback) { |
| | | param.map((p, index) => { |
| | | let template, _param; |
| | | let template, _param |
| | | switch (p.type) { |
| | | // 工地 |
| | | case 1: |
| | | template = p._isDetail |
| | | ? '/工地巡查单据模板-详版.docx' |
| | | : '/工地巡查单据模板-简版.docx'; |
| | | _param = p.params; |
| | | break; |
| | | template = p._isDetail ? '/工地巡查单据模板-详版.docx' : '/工地巡查单据模板-简版.docx' |
| | | _param = p.params |
| | | break |
| | | // 餐饮 |
| | | case 5: |
| | | template = '/餐饮巡查单据模板.docx'; |
| | | _param = p.params; |
| | | break; |
| | | template = '/餐饮巡查单据模板.docx' |
| | | _param = p.params |
| | | break |
| | | default: |
| | | break; |
| | | break |
| | | } |
| | | prepareDocxBlob(template, _param).then((blob) => { |
| | | callback(blob, `${_param.name}巡查单据.docx`, index); |
| | | }); |
| | | }); |
| | | callback(blob, `${_param.name}巡查单据.docx`, index) |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | function filePrepare(callback) { |
| | | const param = parseParam(); |
| | | const param = parseParam() |
| | | if (param) { |
| | | return generateDoc(param, callback); |
| | | return generateDoc(param, callback) |
| | | } |
| | | } |
| | | |
| | | // 点击下载按钮操作, 下载word文档 |
| | | function handelDownload() { |
| | | filePrepare((blob, name) => { |
| | | downloadDocx(blob, name); |
| | | }); |
| | | downloadDocx(blob, name) |
| | | }) |
| | | } |
| | | |
| | | // 点击打印按钮操作 |
| | |
| | | justify-content: space-between; |
| | | align-items: flex-end; |
| | | } |
| | | ` |
| | | }); |
| | | `, |
| | | }) |
| | | } |
| | | } |
| | | |
| | | function handlePreview(item) { |
| | | // 预览的文档,区分单独打印和打印全部 |
| | | previewList.value = item ? ['0'] : checkList.value; |
| | | const param = item ? parseParam(item) : parseParam(); |
| | | previewList.value = item ? ['0'] : checkList.value |
| | | const param = item ? parseParam(item) : parseParam() |
| | | if (param) { |
| | | generateDoc(param, (blob, name, index) => { |
| | | previewVisible.value = true; |
| | | previewVisible.value = true |
| | | setTimeout(() => { |
| | | previewDocx(blob, document.getElementById(`word-preview-${index}`)); |
| | | }, 200); |
| | | }); |
| | | previewDocx(blob, document.getElementById(`word-preview-${index}`)) |
| | | }, 200) |
| | | }) |
| | | } |
| | | } |
| | | |
| | | // 取消操作 |
| | | function cancel() { |
| | | // 关闭对话框 |
| | | handleDialogChange(false); |
| | | handleDialogChange(false) |
| | | } |
| | | </script> |
| | | <style scoped> |