Ver código fonte

答应准考证

y595705120 2 anos atrás
pai
commit
6e7ece6f29

+ 5 - 0
package-lock.json

@@ -2760,6 +2760,11 @@
       "resolved": "https://registry.npm.taobao.org/deepmerge/download/deepmerge-1.5.2.tgz",
       "integrity": "sha1-EEmdhohEza1P7ghC34x/bwyVp1M="
     },
+    "default-passive-events": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/default-passive-events/-/default-passive-events-2.0.0.tgz",
+      "integrity": "sha512-eMtt76GpDVngZQ3ocgvRcNCklUMwID1PaNbCNxfpDXuiOXttSh0HzBbda1HU9SIUsDc02vb7g9+3I5tlqe/qMQ=="
+    },
     "default-user-agent": {
       "version": "1.0.0",
       "resolved": "https://registry.npm.taobao.org/default-user-agent/download/default-user-agent-1.0.0.tgz",

+ 1 - 0
package.json

@@ -14,6 +14,7 @@
     "ali-oss": "^6.12.0",
     "axios": "^0.27.2",
     "babel-loader": "^7.1.5",
+    "default-passive-events": "^2.0.0",
     "element-ui": "^2.1.0",
     "es6-promise": "^4.2.8",
     "js-md5": "^0.7.3",

+ 35 - 19
src/containers/center/components/menu/index.vue

@@ -1,25 +1,25 @@
 <template>
   <div class="m-left-block fl lwh-sider" center-sider="">
-    <div class="user-block" style="width:150px;cursor:pointer" ng-click="$state.go('states.accountSetting')">
-      <img style="width:152px;height:152px"  
-        class="user-img" 
-        :src="user.headImg">
+    <div class="user-block" style="width:150px;cursor:pointer">
+      <img style="width:140px;height:160px"
+        class="user-img"
+        :onerror="errorImg"
+        :src="user.headImg||''">
       <p class="user-name" style="margin-top: 10px;margin-bottom: -8px">
         {{user.nickname}}
       </p>
     </div>
 
     <ul class="m-left-list">
-
-      <li class="ng-scope" v-for="(item, index) in menu" :key="index" 
-          :class="{'current':isActive(item.path)}">
+      <li class="ng-scope" v-for="(item, index) in menu" :key="index"
+          :class="{'current':item.active}">
 
         <a href="javascript:void(0)" style="text-decoration: none" @click="goState(item)"
-          class="ng-binding"><span class="p-ico2" :class="item.icon"></span>{{item.name}}</a>
+          class="ng-binding"><span class="p-ico2" :class="item.icon" ></span>{{item.name}}</a>
 
-        <div class="sub-list ng-scope" v-if="item.children">
-          <a v-for="subItem in item.children" :key="subItem.path"
-            @click="goSubState(subItem)" :class="{'current':isActive(subItem.path)}" href="javascript:void(0)"
+        <div class="sub-list ng-scope" v-if="item.children" >
+          <a v-for="subItem in item.children" :key="subItem.path" v-if="!subItem.hidden"
+            @click="goSubState(subItem)" :class="{'current':subItem.active}" href="javascript:void(0)"
             class="ng-binding ng-scope">{{subItem.name}}</a>
         </div>
       </li>
@@ -41,27 +41,43 @@
     data() {
       return {
         exportLoading: false,
-        menu:menu,
+        menu: [] ,
         listLoading: false,
         groups: [],
-        tableData: []
+        tableData: [],
+        errorImg: 'this.src="' + require('../../../../assets/images/default-photo_hash88f70f5253.jpg') + '"'
       };
     },
+    created(){
+      let path = this.$route.path;
+      this.menu = menu.map( v=>{
+        v.active= path.indexOf( v.path ) >-1
+        return v
+      })
+    },
     methods: {
+      allUnactive( path ){
+        for( let i in this.menu){
+          let item = this.menu[i]
+          if( item.path != path ){
+            item.active = false
+          }
+        }
+      },
       goState( item ){
-        if( item.children){
-          this.goSubState( item.children[0] );
+        if( item.children ){
+          item.active = !item.active;
+          if( item.active ){
+            this.allUnactive( item.path )
+          }
         }else{
           this.goSubState( item );
         }
       },
       goSubState(item){
         if(item.path == this.$route.path) return;
+        item.active = true;
         this.$router.push(item.path);
-      },
-      isActive( path ){
-        let rpath = this.$route.path;
-        return rpath.indexOf( path )> -1;
       }
     }
   }

+ 3 - 3
src/containers/center/components/menu/menu.js

@@ -30,9 +30,9 @@ const menu = [
      icon: 'ico-order'
    },
    {
-     path: '/center/message',
-     name: '站内消息',
-     icon: 'ico-news'
+     path: '/center/seat',
+     name: '打印准考证',
+     icon: 'ico-files'
    }
  ]
 

+ 7 - 2
src/containers/center/play/components/media.vue

@@ -2,7 +2,7 @@
   <div>
     <!--  -->
     <video-player
-      class="video-player vjs-custom-skin"
+      class="video-player-box"
       ref="videoPlayer"
       :playsinline="true"
       @pause="onPlayerPause($event)"
@@ -97,6 +97,11 @@
         }
       }
     },
+    mounted() {
+      setTimeout(() => {
+        this.$emit("updateOption", {muted:false})
+      }, 3000)
+    },
     filters:{
       useTime(val){
         let timestr = ""
@@ -146,7 +151,7 @@
         }else{
           setTimeout( ()=>{
             that.doPlay()
-          }, 1000 )
+          }, 2000 )
         }
         this.isReady = true
       },

+ 19 - 11
src/containers/center/play/index.vue

@@ -80,6 +80,7 @@
           @close="closeMedia"
           :mediaType="mediaType"
           @changeMedia="changeMedia"
+          @updateOption = "updateOption"
           @update="update">
         </Media>
     </el-dialog>
@@ -123,10 +124,10 @@
         media:{},
         options:{
           controls:true,
-          autoplay: false, // 如果true,浏览器准备好时开始回放。
-          muted: false, // 默认情况下将会消除任何音频。
+          autoplay: true, // 如果true,浏览器准备好时开始回放。
+          muted: true, // 默认情况下将会消除任何音频。
           loop: false, // 导致视频一结束就重新开始。
-          preload: "true", // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
+          preload: "auto", // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
           language: 'zh-CN',
           aspectRatio: '4:3', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
           fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
@@ -135,14 +136,18 @@
           notSupportedMessage: '无法播放媒体源', // 允许覆盖Video.js无法播放媒体源时显示的默认信息。
           playtimes: '',
           controlBar: {
-            currentTimeDisplay: true, // 当前时间
-            timeDivider: true, // 时间分割线
-            durationDisplay: true, // 总时间
-            progressControl: true, // 进度条
-            remainingTimeDisplay: true, //
-            customControlSpacer: true, //
-            fullscreenToggle: true, // 全屏按钮
-            volumePanel: true
+            timeDivider: true,
+            durationDisplay: true,
+            remainingTimeDisplay: false,
+            fullscreenToggle: true  //全屏按钮
+            // currentTimeDisplay: true, // 当前时间
+            // timeDivider: true, // 时间分割线
+            // durationDisplay: true, // 总时间
+            // progressControl: true, // 进度条
+            // remainingTimeDisplay: true, //
+            // customControlSpacer: true, //
+            // fullscreenToggle: true, // 全屏按钮
+            // volumePanel: true
           }
         },
         list: [],
@@ -296,6 +301,9 @@
         this.info.axs = axs/10
         this.info.percent = (this.info.gxs*10000/this.info.axs)/100;
       },
+      updateOption( param ){
+        this.options = Object.assign( this.options, param);
+      },
       //
       update( item ){
         if( item.position> this.media.position) {

+ 2 - 1
src/containers/center/setting/index.vue

@@ -288,8 +288,8 @@
         this.visible = true;
       },
       setHeadImg( imgUrl ){
-        console.log( 'setHeadImg', imgUrl)
         this.userInfo.headImg = imgUrl;
+        this.saveBaseInfo(this.userInfo)
       },
       setCardImg( url ){
         httpServer("User.addCardImg", {url}).then( res=>{
@@ -334,6 +334,7 @@
         httpServer("User.saveBaseInfo", param).then( res=>{
           if( res.code == 200){
             this.$message.success("保存成功")
+            this.saveBaseInfo(this.userInfo)
           }
         })
       },

+ 182 - 0
src/containers/center/userSeat/components/iPrintCert.vue

@@ -0,0 +1,182 @@
+<template>
+  <div style="margin-top: -100px;">
+    <el-button type="primary" @click="$print($refs.print) " style="margin:40px auto;" class="tc">打印</el-button>
+
+    <div ref="print" >
+      <h1 class="tc" >福建省建设行业从业人员岗位考核考试</h1>
+      <h2  class="tc p10">准考证</h2>
+      <table style="width:900px;margin:10px auto;color: #000000;" class="mtable">
+        <tr>
+          <td class="m-attr" style="width: 100px;">姓名</td>
+          <td class="tl" colspan="2">{{info.nickname}}</td>
+          <td class="m-attr">报考机构</td>
+          <td class="tl" colspan="4">三明市城市建设项目服务中心</td>
+          <td rowspan="6" colspan="1" class="cert-head">
+            <img :src="info.headImg" class="cert-head"/>
+          </td>
+        </tr>
+        <tr>
+          <td class="m-attr">性别</td>
+          <td class="tl" colspan="2">{{info.gender}}</td>
+          <td class="m-attr">身份证</td>
+          <td class="tl" colspan="4">{{info.cardId}}</td>
+        </tr>
+        <tr>
+          <td class="m-attr">考试类别</td>
+          <td colspan="7" class="tl">{{info.examType}}</td>
+        </tr>
+        <tr>
+          <td class="m-attr">岗位名称</td>
+          <td colspan="7" class="tl">{{info.courseName}}</td>
+        </tr>
+        <tr>
+          <td class="m-attr">工作单位</td>
+          <td colspan="7" class="tl">{{info.company}}</td>
+        </tr>
+        <tr>
+          <td class="m-attr">考试地点</td>
+          <td colspan="7" class="tl">{{info.address}}</td>
+        </tr>
+
+        <tr>
+          <td  class="m-attr" style="width: 13%">考试科目</td>
+          <td class="m-attr" colspan="2" style="width: 15%">准考证号</td>
+          <td class="m-attr" style="width: 13%">考试时长</td>
+
+          <td class="m-attr" colspan="3" style="width: 30%">考场号</td>
+          <td class="m-attr" style="width: 9%">座位号</td>
+          <td class="m-attr" colspan="2" style="width: 20%">考试时间</td>
+        </tr>
+
+        <tr>
+          <td  class="tc m-attr">检测试验人员</td>
+          <td class="tc m-attr" colspan="2">{{info.uuid}}</td>
+          <td class="tc">{{info.duration}}</td>
+
+          <td class="tc" colspan="3">{{info.examRoom}}</td>
+          <td class="tc">{{info.seat}}</td>
+
+          <td class="tc" colspan="2">{{info.examTime}}</td>
+        </tr>
+
+        <tr>
+          <td colspan="10">
+            <div display="flex" class="p5">
+              <div style="width:90px;font-weight:700;">注意事项:</div>
+              <div style="margin-left:80px">
+                <p class="m-notice">1、请携带准考证和身份证,按照考试规则要求参加考试;</p>
+                <p class="m-notice">2、成绩查询:https://sm.hqedust.com</p>
+              </div>
+            </div>
+          </td>
+        </tr>
+
+        <tr>
+          <td colspan="10">
+            <div display="flex" class="p5" style="text-indent: 0.1rem;">
+              <h2 class="tc m-title">考试规则</h2>
+
+              <p class="m-rule">
+               1、在考试前15分钟进入考场,对号入座,并将准考证、有效身份证件放 在机位明显位置,以便监考人员查对。证件和准考证两证不齐全的,不予参加考试。开考15分钟后不得入场。开考30分钟后,方能交卷离场,退场后不得再次进入考室。
+              </p>
+
+              <p class="m-rule">
+                2、考生不得携带任何与考试科目有关的书籍和稿纸进入考场(开卷考试除外)。禁止在考室内使用手机等电子设备,除准考证、身份证件以外的其他物品(手机必须关闭)须放在“物品置放处”。
+              </p>
+
+              <p class="m-rule">
+               3、考生开考前凭准考证号、密码登录考试系统,登录后应仔细核对其个人信息(包括姓名、性别、身份证号、准考证号、本人照片等)及考试科目,并认真阅读《考生须知》;如个人信息有误,应举手示意,等待监考员处理。
+              </p>
+
+              <p class="m-rule">
+                4、考试过程中,考生不得离开座位。如遇试题不清晰等异常情况,考生可举手询问,但不得要求监考人员作任何提示或解释。
+              </p>
+              <p class="m-rule">
+                5、考生在考场内应保持安静。不得吸烟、进食。凡发现夹带、翻阅考试相关资料(开卷考试除外)和以旁窥、交头接耳、打手势等方式传接信息的;抄袭、协助他人抄袭试题答案或者与考试内容相关资料的等作弊行为的,经警告无效的,本次考试成绩无效。 5、考生在考场内应保持安静,不得吸烟、进食,凡发现夹带、翻阅考试相关资料(开卷考试除外)和以旁窥、交头接耳、打手势等方式传接信息的:抄装、协助他人抄袭试题答案或者与考试内容相关资料的等作弊行为的,经警告无效的,本次考试成绩无效。
+              </p>
+              <p class="m-rule">
+                6、在考场及禁止的范围内,对扰乱考场秩序,威胁、侮辱、诽谤、诬陷他人行为,影响他人考试的,经警告仍不改正的,交由公安机关依法处理。
+              </p>
+              <p class="m-rule">
+               7、考试时间以考试系统显示为准。迟到者必须按考试规定时间结束考试,不得延长时间。应试人员离开考场时,应保持安静,不得在考场附近逗留、喧哗。
+              </p>
+
+              <p class="m-rule">
+                8、考生应按照考试系统的要求进行操作,不得擅自对电脑进行冷、热启动及其他与考试无关的操作;若考试系统出现故障,应举手示意,等待考务工作人员处理。
+              </p>
+              <p class="m-rule">
+                9、考生确认交卷后,系统自动评卷并显示本次考试成绩。应试人员也可通过三明市建设人才服务中心网站查询本人考试成绩。
+              </p>
+            </div>
+          </td>
+        </tr>
+
+      </table>
+    </div>
+  </div>
+</template>
+<script>
+  export default {
+    name: "Api",
+    data() {
+      return {
+      }
+    },
+    props: ['info']
+  }
+</script>
+<style>
+  .mtable {
+    font-family: FangSong;
+    border-collapse: collapse;
+    border: 1px solid;
+    color: #000000;
+    font-weight: 550;
+    padding-bottom: 8px;
+    line-height: 1.4;
+    letter-spacing: 1px;
+  }
+
+  .mtable td {
+    font-family: FangSong;
+    border: 1px solid black;
+    padding: 2px 12px;
+    font-size: 16px;
+  }
+  .m-attr{
+    text-align:center !important;
+    height: 40px;
+    white-space: nowrap;
+  }
+
+  .m-rule {
+    font-family: FangSong;
+    text-align: left;
+    padding: 2px;
+    margin: 4px auto;
+    line-height: 1.6rem;
+    text-indent: 0px;
+    font-size: 16px;
+  }
+
+  .m-notice {
+    font-family: FangSong;
+    margin: 4px auto;
+    padding: 4px;
+    font-size: 16px;
+    text-align:left;
+  }
+
+  .m-title {
+    font-family: FangSong;
+    text-align: center;
+    font-size: 20px;
+    padding: 10px;
+    font-weight: 800;
+  }
+  .cert-head{
+    width:200px;
+    height: 230px;
+    overflow-y: hidden;
+  }
+</style>

+ 118 - 0
src/containers/center/userSeat/index.vue

@@ -0,0 +1,118 @@
+<template>
+  <div class="m-right-block fr mh576" style="position: relative;">
+    <div class="right-block-bd">
+      <div class="mb10 tc mt20">
+        <span class="p-ico2 worm-ico-o"></span>
+        注:<span class="txt-o"></span>考试前三天才会生成,若未看到,请联系管理员
+      </div>
+
+      <div  class="ng-scope">
+        <el-table v-loading="listLoading" :data="list" border fit highlight-current-row>
+          <el-table-column label="准考号" align="center" width="120" prop="uuid"/>
+          <el-table-column label="考试科目" prop="courseName" align="center" width="110"/>
+
+          <el-table-column label="考试地点" prop="address" align="center"/>
+
+          <el-table-column label="考试时间" prop="examTime" align="center" width="175"/>
+
+          <el-table-column label="考试时长" prop="duration" align="center" width="80"/>
+
+          <el-table-column label="考试座位" prop="seat" align="center" width="80"/>
+
+          <el-table-column label="操作" fixed="right" align="center" width="100">
+            <template slot-scope="{row}">
+              <el-button  @click="printCert( row )" type="text" size="small">打印</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+
+        <el-pagination
+            @current-change="handleCurrentChange"
+            :current-page="page"
+           :page-size="size"
+           layout="total, prev,pager, next"
+           :total="list.length">
+        </el-pagination>
+
+      </div>
+
+      <el-dialog title="" class="previewDialog" :visible.sync="printCertDialog"
+        top="0" append-to-body width="1024px"
+        @close="printCertDialog=false">
+        <div class="el-dialog__body" style="margin-top:-30px">
+          <IPrintCert :info="info" ></IPrintCert>
+        </div>
+
+      </el-dialog>
+    </div>
+  </div>
+</template>
+
+<script>
+  import {httpServer} from "@/components/httpServer/httpServer.js";
+  import {formatTimeToStr} from "@/utils/date.js";
+ import { mapGetters } from "vuex";
+  import IPrintCert from "./components/iPrintCert.vue";
+  export default {
+    name: "Index",
+    data() {
+      return {
+        page:1,
+        size:10,
+        total: 20,
+        info:{},
+        list: [],
+        printCertDialog:false,
+        listLoading: false
+      };
+    },
+    beforeMount() {
+      this.getData()
+    },
+    components:{IPrintCert},
+    computed: {
+    	...mapGetters("user", ["userInfo"])
+    },
+    methods: {
+      getData() {
+        this.listLoading = true
+        httpServer('User.GetUserSeatList', {}).then( res=>{
+            if( res.code == 200){
+              this.list = res.data||[]
+            }
+            this.listLoading = false
+        })
+      },
+      printCert( row  ){
+        document.title = '福建省建设行业从业人员岗位考核考试';
+        this.info = Object.assign(this.info, row);
+        if( !this.userInfo.headImg ){
+          this.$message.errorMsg("还未上传头像", 2)
+          return;
+        }
+        this.info.headImg = this.userInfo.headImg;
+        this.printCertDialog = true;
+      },
+
+      handleCurrentChange: function(page) {
+        this.page = page
+        this.getData()
+      }
+    }
+  }
+</script>
+
+<style>
+  .previewDialog{
+      text-align: center;
+  }
+  .previewDialog.el-dialog {
+    .el-dialog__header {
+      display: none;
+    }
+    .dj-dialog-content {
+      padding: 0;
+      overflow: unset;
+    }
+  }
+</style>

+ 1 - 1
src/containers/login/components/unLogin.vue

@@ -16,7 +16,7 @@
             <span class="p-ico code-ico"></span>
             <span href="javascript:void(0)" style="cursor:pointer" class="p-ico ng-scope"></span>
             <input type="password"  v-model="password" class="ui-ipt ng-scope ng-pristine ng-valid"
-              placeholder="密码">
+              autocomplete="off" placeholder="密码">
           </li>
 
          <li>

+ 8 - 1
src/main.js

@@ -10,15 +10,22 @@ import './assets/css/main.css'
 import { store } from '@/store/index'
 import md5 from 'js-md5';
 Vue.prototype.$md5 = md5;
+import 'default-passive-events'
 
 // import '@babel/polyfill'
-// require('es6-promise').polyfill()
+require('es6-promise').polyfill()
 
 import './icons' // icon
 
 const hls = require('videojs-contrib-hls')
+require('video.js/dist/video-js.css')
+require('vue-video-player/src/custom-theme.css')
+
 Vue.use(hls)
 
+import Print from '@/utils/print'
+Vue.use(Print)
+
 
 Vue.config.productionTip = false
 Vue.use(ElementUI)

+ 7 - 1
src/router/index.js

@@ -36,6 +36,8 @@ import PublicSign from '@/containers/sign/index'
 import CenterMarket from '@/containers/center/market/index'
 import CenterExam from '@/containers/center/exam/index'
 
+import CenterUserSeat from '@/containers/center/userSeat/index'
+
 Vue.use(Router)
 
 export default new Router({
@@ -158,7 +160,11 @@ export default new Router({
         {
           path: 'setting',
           component: CenterSetting,
-        }
+        },
+		{
+		  path: 'seat',
+		  component: CenterUserSeat,
+		},
       ],
     }
   ]

+ 133 - 0
src/utils/print.js

@@ -0,0 +1,133 @@
+const Print = function (dom, options) {
+    if (!(this instanceof Print)) return new Print(dom, options);
+   
+    this.options = this.extend({
+      'noPrint': '.no-print'
+    }, options);
+   
+    if ((typeof dom) === "string") {
+      this.dom = document.querySelector(dom);
+    } else {
+      this.isDOM(dom)
+      this.dom = this.isDOM(dom) ? dom : dom.$el;
+    }
+   
+    this.init();
+  };
+  Print.prototype = {
+    init: function () {
+      var content = this.getStyle() + this.getHtml();
+      this.writeIframe(content);
+    },
+    extend: function (obj, obj2) {
+      for (var k in obj2) {
+        obj[k] = obj2[k];
+      }
+      return obj;
+    },
+   
+    getStyle: function () {
+      var str = "",
+        styles = document.querySelectorAll('style,link');
+      for (var i = 0; i < styles.length; i++) {
+        str += styles[i].outerHTML;
+      }
+      str += "<style>" + (this.options.noPrint ? this.options.noPrint : '.no-print') + "{display:none;}</style>";
+      str += "<style>html,body,div{height: auto!important;font-size:14px}</style>";
+      return str;
+    },
+   
+    getHtml: function () {
+      var inputs = document.querySelectorAll('input');
+      var textareas = document.querySelectorAll('textarea');
+      var selects = document.querySelectorAll('select');
+   
+      for (var k = 0; k < inputs.length; k++) {
+        if (inputs[k].type == "checkbox" || inputs[k].type == "radio") {
+          if (inputs[k].checked == true) {
+            inputs[k].setAttribute('checked', "checked")
+          } else {
+            inputs[k].removeAttribute('checked')
+          }
+        } else if (inputs[k].type == "text") {
+          inputs[k].setAttribute('value', inputs[k].value)
+        } else {
+          inputs[k].setAttribute('value', inputs[k].value)
+        }
+      }
+   
+      for (var k2 = 0; k2 < textareas.length; k2++) {
+        if (textareas[k2].type == 'textarea') {
+          textareas[k2].innerHTML = textareas[k2].value
+        }
+      }
+   
+      for (var k3 = 0; k3 < selects.length; k3++) {
+        if (selects[k3].type == 'select-one') {
+          var child = selects[k3].children;
+          for (var i in child) {
+            if (child[i].tagName == 'OPTION') {
+              if (child[i].selected == true) {
+                child[i].setAttribute('selected', "selected")
+              } else {
+                child[i].removeAttribute('selected')
+              }
+            }
+          }
+        }
+      }
+   
+      return this.dom.outerHTML;
+    },
+   
+    writeIframe: function (content) {
+      var w, doc, iframe = document.createElement('iframe'),
+        f = document.body.appendChild(iframe);
+      iframe.id = "myIframe";
+      //iframe.style = "position:absolute;width:0;height:0;top:-10px;left:-10px;";
+      iframe.setAttribute('style', 'position:absolute;width:0;height:0;top:-10px;left:-10px;');
+      w = f.contentWindow || f.contentDocument;
+      doc = f.contentDocument || f.contentWindow.document;
+      doc.open();
+      doc.write(content);
+      doc.close();
+      var _this = this
+      iframe.onload = function(){
+        _this.toPrint(w);
+        setTimeout(function () {
+          document.body.removeChild(iframe)
+        }, 100)
+      }
+    },
+   
+    toPrint: function (frameWindow) {
+      try {
+        setTimeout(function () {
+          frameWindow.focus();
+          try {
+            if (!frameWindow.document.execCommand('print', false, null)) {
+              frameWindow.print();
+            }
+          } catch (e) {
+            frameWindow.print();
+          }
+          frameWindow.close();
+        }, 10);
+      } catch (err) {
+        console.log('err', err);
+      }
+    },
+    isDOM: (typeof HTMLElement === 'object') ?
+      function (obj) {
+        return obj instanceof HTMLElement;
+      } :
+      function (obj) {
+        return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';
+      }
+  };
+  const MyPlugin = {}
+  MyPlugin.install = function (Vue, options) {
+    // 4. 添加实例方法
+    Vue.prototype.$print = Print
+  }
+  export default MyPlugin