效果图:
在这里插入图片描述
在这里插入图片描述

一、打印预览引入两个依赖文件

ref=“exportPdf” 指向只能指向div这些dom原生元素,不然会报Element is not attached to a
Document错误。

npm install html2canvas --save
npm install print-js --save

二、封装一个组件 excel(不规格表格 粗暴方法实现)

<template>
  <div>
    <div class="title">{{title}}</div>
    <div class="cont">
      <!-- 第一行表格 五列 -->
      <div class="table">
        <div class="lump" v-for="(item, index) in tableArr" :key="index">
          <div class="box">
            <div class="content1">{{ item.key }}</div>
            <el-tooltip v-if="item.value.length > 11" class="item" :content="item.value" placement="top">
              <div :class="item.border !== 'none' ? 'content2' : 'content_border'">{{ item.value}}</div>
            </el-tooltip>
            <div v-else :class="item.border !== 'none' ? 'content2' : 'content_border'">{{ item.value}}</div>
          </div>
        </div>
      </div>
      <!-- 第二行表格 三列 2-4 -->
      <div class="table">
        <div class="lump2" v-for="(item, index) in tableArr2" :key="index">
          <div class="box">
            <div class="content1" :style="'width:'+ item.width">{{ item.key }}</div>
            <el-tooltip v-if="item.value.length > 11" class="item" :content="item.value" placement="top">
              <div :class="item.border !== 'none' ? 'content2' : 'content_border'" :style="'width:'+ item._width">{{ item.value}}</div>
            </el-tooltip>
            <div v-else :class="item.border !== 'none' ? 'content2' : 'content_border'" :style="'width:'+ item._width">{{ item.value}}</div>
          </div>
        </div>
      </div>
      <!-- 第三行表格 一列-->
      <div class="table">
        <div class="content3">现场处理情况信息</div>
      </div>
      <!-- 第四行表格 二列 -->
      <div class="table">
        <template v-for="(item, index) in tableArr4">
          <div class="lump4" :key="index">
            <div :key="'info'+ index" :class="item.type == 2 ? 'conttent4' : 'conttent6'">
              <!-- 不是3隐藏 -->
              <template v-if="item.type !== 3">
                <div :class="item.type == 1 ? 'conttent6-title' : 'conttent4-title'">{{item.key+ ':'}}</div>
                <el-tooltip v-if="item.value.length > 20" class="item" :content="item.value" placement="top">
                  <div :class="item.type == 1 ? 'conttent6-txt' : 'conttent4-txt'">{{item.value}}</div>
                </el-tooltip>
                <div v-else :class="item.type == 1 ? 'conttent6-txt' : 'conttent4-txt'">{{item.value}}</div>
              </template>
              <!-- 评价 -->
              <template v-if="item.type == 3">
                <div class="conttent6-score">
                  <div class="conttent6-score-title">{{item.key+ ':'}}</div>
                  <el-row class="conttent6-score-affirm">
                    <el-col>维保工程师是否按约定时间上门:是</el-col>
                    <el-col>是否主动出示上岗工作牌:是</el-col>
                    <el-col>维护完毕是否逐项检验正常:是</el-col>
                    <el-col>维护完毕后是否清洁设备和现场:是</el-col>
                    <el-col>满意度:非常满意</el-col>
                  </el-row>
                </div>
              </template>
            </div>
            <div :key="index" :class="item.type == 2 ? 'conttent5' : 'conttent7'">
              <template v-if="item.type !== 3">
                <div :class="item.type == 1 ? 'conttent7-title' : 'conttent5-title'">{{item.key2+ ':'}}</div>
                <el-tooltip v-if="item.value2.length > 20" class="item" :content="item.value2" placement="top">
                  <div :class="item.type == 1 ? 'conttent7-txt' : 'conttent5-txt'">{{item.value2}}</div>
                </el-tooltip>
                <div v-else :class="item.type == 1 ? 'conttent7-txt' : 'conttent5-txt'">{{item.value2}}</div>
              </template>
              <!-- 签名 -->
              <template v-if="item.type == 3">
                <div class="conttent7-sign">
                  <div class="conttent7-sign-title">{{item.key2+ ':'}}</div>
                  <div class="conttent7-sign-txt">{{item.value2}}</div>
                </div>
                <img
                  v-if="item.type == 3"
                  src="http://t13.baidu.com/it/u=1883019352,930630496&fm=224&app=112&f=JPEG?w=500&h=500&s=4B843862418D69E3567530C60000E0B1"
                  style="padding-left: 25%; width:200px; height:150px"
                  alt
                />
              </template>
            </div>
          </div>
        </template>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    title: {
      type: String,
      default: ''
    },
    tableArr: {
      type: Array,
      default: () => {
        return []
      }
    },
    tableArr2: {
      type: Array,
      default: () => {
        return []
      }
    },
    tableArr4: {
      type: Array,
      default: () => {
        return []
      }
    }
  },
  data() {
    return {}
  },
  computed: {},
  created() {},
  mounted() {},
  watch: {},
  methods: {},
  components: {}
}
</script>

<style scoped lang="scss">
$titleColor: rgb(117, 117, 117);
$borderColor: 1px solid #e9e9e9;
.title {
  width: 100%; // 1200px
  margin: 0 auto;
  margin-top: 30px;
  padding: 20px 0;
  font-size: 18px;
  font-weight: 600;
  background-color: #e1e1e1;
  // border: 1px solid #e1e1e1;
}
.cont {
  border-right: $borderColor;
}
.table {
  width: 100%; // 1200px
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
}
.lump {
  width: 20%;
}
.lump2 {
  width: 40%;
}
.lump2:nth-child(3),
.lump2:nth-child(6),
.lump2:last-child {
  width: 20%;
}
.box {
  width: 100%;
  height: 40px;
  display: flex;
  border-top: $borderColor;
  .content1 {
    width: 40%;
    height: 40px;
    line-height: 40px;
    text-align: center;
    background-color: #fafafa;
    border-left: $borderColor;
    border-bottom: $borderColor;
    color: $titleColor;
    font-size: 14px;
  }
  .content2 {
    width: 60%;
    height: 40px;
    line-height: 40px;
    text-align: center;
    background-color: #fff;
    border-left: $borderColor;
    border-bottom: $borderColor;
    color: 000;
    font-size: 14px;
    cursor: pointer;
    overflow: hidden; //超出的文本隐藏
    text-overflow: ellipsis; //溢出用省略号显示
    white-space: nowrap; //溢出不换行
  }
  // .content2:last-child {
  //   border-right: $borderColor;
  // }
  .content_border {
    width: 60%;
    height: 40px;
    line-height: 40px;
    text-align: center;
    background-color: #fff;
    border-left: $borderColor;
    border-bottom: $borderColor;
    color: 000;
    font-size: 14px;
    cursor: pointer;
    overflow: hidden; //超出的文本隐藏
    text-overflow: ellipsis; //溢出用省略号显示
    white-space: nowrap; //溢出不换行
  }
}
// 三列样式
.content3 {
  width: 100%;
  height: 40px;
  display: inline-block;
  line-height: 40px;
  text-align: center;
  background-color: #fff;
  border: $borderColor;
  border-right: none;
  color: 000;
  font-size: 14px;
  font-weight: 600;
}
// 四列样式
.lump4 {
  width: 100%;
  display: flex;
  // align-items: center;
  flex-wrap: wrap;
  box-sizing: border-box;
  border: $borderColor;
  border-top: none;
  border-right: none;
  .conttent4 {
    display: flex;
    align-items: center;
    width: calc(48% - 1px);
    height: 40px;
    line-height: 40px;
    border-right: $borderColor;
    background-color: #fff;
    text-align: left;
    cursor: pointer;
    white-space: nowrap; //溢出不换行
    &-title {
      color: $titleColor;
      padding-left: 12px;
    }
    &-txt {
      overflow: hidden; //超出的文本隐藏
      text-overflow: ellipsis; //溢出用省略号显示
      white-space: nowrap; //溢出不换行
    }
  }
  .conttent5 {
    display: flex;
    align-items: center;
    width: 52%;
    height: 40px;
    line-height: 40px;
    text-align: left;
    background-color: #fff;
    cursor: pointer;
    white-space: nowrap;
    &-title {
      padding-left: 12px;
      color: $titleColor;
    }
    &-txt {
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
  }
  .conttent6 {
    width: calc(48% - 1px);
    min-height: 100px;
    text-align: left;
    // border-right: $borderColor;
    background: #fff;
    border-top: none;
    cursor: pointer;
    // white-space: nowrap;
    &-title {
      color: $titleColor;
      padding: 12px;
    }
    &-txt {
      padding: 0 12px;
      overflow: hidden;
      text-overflow: ellipsis;
      display: -webkit-box;
      -webkit-box-orient: vertical;
      -webkit-line-clamp: 2;
    }
    // 评价
    &-score {
      padding: 12px;
      &-title {
        color: $titleColor;
      }
      &-affirm {
        padding: 12px;
        padding-left: 0;
        ::v-deep .el-col {
          padding-bottom: 12px;
        }
        ::v-deep .el-col:last-child {
          padding-bottom: 0;
        }
      }
    }
  }
  .conttent7 {
    width: calc(52% - 30px);
    min-height: 100px;
    text-align: left;
    background: #fff;
    border-left: $borderColor;
    cursor: pointer;
    &-title {
      color: $titleColor;
      padding: 12px;
    }
    &-txt {
      padding: 0 12px;
      overflow: hidden;
      text-overflow: ellipsis;
      display: -webkit-box;
      -webkit-box-orient: vertical;
      -webkit-line-clamp: 2;
    }
    // 签名
    &-sign {
      display: flex;
      align-items: center;
      padding: 12px;
      &-title {
        color: $titleColor;
      }
    }
  }
}
</style>

三、父组件调用

<template>
  <div>
    <el-dialog title="工单详情" :visible.sync="detailsVisible" :width="dialogWidth" @close="handleClose">
      <!-- 卡片试图区域 -->
      <el-card class="box-card">
        <template>
          <div class="steps-cont">
            <div
              class="date"
              v-show="item != ''"
              :style="{'left': `${index*((timeList.length==3 ? number*2 :timeList.length==4 ? number*3:number)/(timeList.length-1))+ percentum}%`}"
              v-for="(item, index) in timeList"
              ref="refTime"
              :key="index"
            >
              <div>{{item.year}}</div>
              <div class="date-time">{{item.time}}</div>
            </div>
            <el-steps :active="2" align-center>
              <el-step title="待接单" description="派遣到维修人员 黄某"></el-step>
              <el-step title="已接单" description="维修接单 李某"></el-step>
              <el-step title="执行中" description="执行中 王某"></el-step>
              <el-step title="已结单" description="已完成 王某"></el-step>
            </el-steps>
          </div>
        </template>
        <!-- 打印预览 print-->
        <el-main class="main">
          <div ref="exportPdf" id="exportPdf">
            <!-- 表格 -->
            <Excel ref="refExcel" :title="excel_title" :tableArr="tableArr" :tableArr2="tableArr2" :tableArr4="tableArr4" />
          </div>
        </el-main>
        <div>
          <el-button type="primary" size="mini" @click="printHandle">打印预览</el-button>
        </div>
        <el-footer class="table" style="padding-top:10px">
          <el-descriptions title="其他信息">
            <template v-for="(item, index) in otherList">
              <el-descriptions-item :key="index" :label="item.label">{{item.value}}</el-descriptions-item>
            </template>
          </el-descriptions>
        </el-footer>
      </el-card>
    </el-dialog>
  </div>
</template>

<script>
import html2canvas from 'html2canvas' // 转为图片
import printJS from 'print-js' // 打印
import Excel from './excel'
export default {
  name: 'OrderDetails',
  components: { Excel },
  props: {
    orderVisible: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      dialogWidth: '1500px',
      // 订单时间线
      timeList: [
        { year: '2022', time: '03-01 15:25:13' },
        { year: '2022', time: '04-01 15:25:13' }
        // { year: '2022', time: '05-01 15:25:13' }
        // { year: '2022', time: '06-01 15:25:13' }
      ],
      number: 25, // 平均偏移位置
      percentum: '', // 初始位置百分比
      // 悬浮显示
      isShowTooltip: true,
      // 表格数据
      excel_title: '云南XXX服务XX单',
      tableArr: [
        {
          key: '订单号',
          value: 'wb-2022-03-1801',
          border: 'none'
        },
        {
          key: '客户名称',
          value: '大理市政府',
          border: 'none'
        },
        {
          key: '办公室地址',
          value: '923',
          border: 'none'
        },
        {
          key: '联系电话',
          value: '13511112222',
          border: 'none'
        },
        {
          key: '维修工程师',
          value: '张飞'
        }
      ],
      // 第二列表格
      tableArr2: [
        {
          key: '保修时间',
          value: '2022-03-18 12:00',
          width: '101.44px',
          _width: '383.8px',
          border: 'none'
        },
        {
          key: '预计时间',
          value: '2小时',
          width: '101.44px',
          _width: '383.8px',
          border: 'none'
        },
        {
          key: '报修人',
          value: '关羽',
          width: '101.44px',
          _width: '152.3px'
        },
        // ------------------
        {
          key: '服务内容',
          value: '打印机连不上',
          width: '101.44px',
          _width: '383.8px',
          border: 'none'
        },
        {
          key: '服务方式',
          value: '上门服务',
          width: '101.44px',
          _width: '383.8px',
          border: 'none'
        },
        {
          key: '报修方式',
          value: '在线报修',
          width: '101.44px',
          _width: '152.3px'
        },
        // --------------------
        {
          key: '影响范围',
          value: '一般',
          width: '101.44px',
          _width: '383.8px',
          border: 'none'
        },
        {
          key: '紧急程度',
          value: '一般',
          width: '101.44px',
          _width: '383.8px',
          border: 'none'
        },
        {
          key: '其他',
          value: '',
          width: '101.44px',
          _width: '152.3px'
        }
      ],
      // 第四列
      tableArr4: [
        {
          key: '故障原因',
          value: '经排查,网络断开,内网故障',
          key2: '维修处理情况',
          value2: '国产电脑连接共享打印机,已处理完成',
          type: 1
        },
        {
          key: '注:若需要重装系统, 数据请客户提前备份。客户确认签字',
          value: '',
          key2: '修复时间',
          value2: '2022-03-08 11:00',
          type: 2
        },
        {
          key: '客户填写部分',
          value: '',
          key2: '客户签字及日期',
          value2: '2022-03-08 12:00',
          type: 3
        }
      ],
      otherList: [
        { label: '工单状态', value: '已结单' },
        { label: '工单耗时', value: '0分钟' },
        { label: '工单来源', value: '小程序' },
        { label: '收费项目', value: '无收费项目' },
        { label: '收费金额', value: '000000' },
        { label: '到场时间', value: '2022-03-12 09:45:25' }
      ],
      // 窗口变化
      screenWidth: document.body.clientWidth
    }
  },
  created() {
    if (this.screenWidth > 1700) {
      this.dialogWidth = '1500px'
      this.percentum = 7
    } else {
      this.dialogWidth = '1050px'
      this.percentum = 4.2
    }
  },
  mounted() {
    // 获取窗口变化
    const that = this
    window.onresize = () => {
      return (() => {
        window.screenWidth = document.body.clientWidth
        that.screenWidth = window.screenWidth
        this.$nextTick(() => {
          // console.log(this.$refs.refTime.width, 'ref')
        })
      })()
    }
  },
  watch: {
    // 监听窗口变化
    screenWidth(val) {
      // 为了避免频繁触发resize函数导致页面卡顿,使用定时器
      if (!this.timer) {
        // 一旦监听到的screenWidth值改变,就将其重新赋给data里的screenWidth
        this.screenWidth = val
        this.timer = true
        let that = this

        if (this.screenWidth > 1700) {
          that.dialogWidth = '1500px'
          that.percentum = 7
        } else {
          that.dialogWidth = '1050px'
          that.percentum = 4.2
        }
        setTimeout(function () {
          // 打印screenWidth变化的值
          console.log(that.screenWidth)
          that.timer = false
        }, 400)
      }
    }
  },
  computed: {
    detailsVisible: {
      get() {
        return this.orderVisible
      },
      set(val) {
        console.log(val)
        this.$emit('update:orderVisible', val) // detailsVisible改变的时候通知父组件
      }
    }
  },
  methods: {
    // 关闭弹框
    handleClose() {
      // this.orderVisible = false
    },
    //转图片打印
    printHandle() {
      html2canvas(this.$refs.exportPdf, {
        backgroundColor: null,
        useCORS: true,
        windowHeight: document.body.scrollHeight
      }).then(canvas => {
        const url = canvas.toDataURL()
        this.img = url
        printJS({
          printable: url,
          type: 'image',
          documentTitle: ''
        })
      })
    },
    printContext() {
      this.$print(this.$refs.print)
    }
  }
}
</script>
<style lang="scss" scoped>
$titleColor: rgb(117, 117, 117);
$borderColor: 1px solid #e9e9e9;
.steps-cont {
  // width: 80%;
  margin: 0 auto;
  position: relative;
  padding-top: 22px;
}
.date {
  position: absolute;
  top: -50px;
  left: 5.5%;
  padding: 8px 30px;
  color: #fff;
  background: $nav-bg;
  border-radius: 35px;
  &-time {
    font-size: 12px;
  }
}
.date:after {
  content: ''; /*CSS伪类用法*/
  position: absolute; /*定位背景横线的位置*/
  top: 52px;
  left: 49%;
  background: $nav-bg; /*宽和高做出来的背景横线*/
  width: 4px;
  height: 22px;
}
.box-card {
  padding-top: 20px;
  width: 100%;
  min-height: 100vh;
  box-sizing: border-box;
  padding: 50px;
}
.table {
  width: 100%; // 1200px
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
}
</style>
Logo

前往低代码交流专区

更多推荐