餐饮油烟智能监测与监管一体化平台
riku
2026-03-16 0488cc32d225a28289ba6c70a2a297f347cacdad
src/views/inspection/scene/SceneInspectFile.vue
@@ -6,19 +6,9 @@
    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"
@@ -27,23 +17,15 @@
            :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>
@@ -58,10 +40,7 @@
                    :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="简版"
                  />
@@ -73,10 +52,12 @@
                  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>
@@ -86,9 +67,7 @@
    </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"
@@ -103,8 +82,10 @@
          :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>
@@ -113,24 +94,14 @@
  <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>
@@ -139,108 +110,109 @@
/**
 * 场景巡查单据自动下载
 */
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
  }
}
@@ -249,8 +221,8 @@
  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) {
      // 工地
@@ -262,22 +234,19 @@
            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 {
@@ -287,56 +256,54 @@
            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)
  })
}
// 点击打印按钮操作
@@ -357,29 +324,29 @@
          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>