jiangping
2024-06-11 62182a3d0b1f28b1a54d054fda7f951382086d05
最新版本
已添加2个文件
已修改5个文件
459 ■■■■■ 文件已修改
admin/package-lock.json 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaMemberWindow.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/common/ImageCropper.vue 227 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/common/UploadFaceImg.vue 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/interfaceLog.vue 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/platformInterfaceLog.vue 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/package-lock.json
@@ -13920,6 +13920,11 @@
        "clipboard": "^2.0.0"
      }
    },
    "vue-cropper": {
      "version": "0.6.5",
      "resolved": "https://registry.npmmirror.com/vue-cropper/-/vue-cropper-0.6.5.tgz",
      "integrity": "sha512-lSvY6IpeA/Tv/iPZ/FOkMHVRBPSlm7t57nuHEZFBMRNOH8ElvfqVlnHGDOAMlvPhh9gHiddiQoASS+fY0MFX0g=="
    },
    "vue-eslint-parser": {
      "version": "7.6.0",
      "resolved": "https://registry.npm.taobao.org/vue-eslint-parser/download/vue-eslint-parser-7.6.0.tgz?cache=0&sync_timestamp=1614679548045&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-eslint-parser%2Fdownload%2Fvue-eslint-parser-7.6.0.tgz",
admin/package.json
@@ -26,6 +26,7 @@
    "qrcodejs2": "0.0.2",
    "vue": "^2.6.11",
    "vue-clipboard2": "^0.3.1",
    "vue-cropper": "^0.6.5",
    "vue-json-viewer": "^2.2.22",
    "vue-router": "^3.5.1",
    "vuescroll": "^4.17.3",
admin/src/components/business/OperaMemberWindow.vue
@@ -41,7 +41,7 @@
                <el-input v-model="form.code" placeholder="请输入员工工号" v-trim/>
            </el-form-item>
          <el-form-item label="人脸照片" prop="faceImgFull" >
            <UploadAvatarImage
            <UploadFaceImg
                :file="{ 'imgurlfull': form.faceImgFull, 'imgurl': form.faceImg }"
                :uploadData="uploadData"
                @uploadSuccess="uploadAvatarSuccess"
@@ -57,11 +57,12 @@
import BaseOpera from '@/components/base/BaseOpera'
import GlobalWindow from '@/components/common/GlobalWindow'
import UploadAvatarImage from '@/components/common/UploadAvatarImage'
import UploadFaceImg from '@/components/common/UploadFaceImg'
import {checkMobile, validIdCardNo, validIdCardNoNew} from '@/utils/form'
export default {
  name: 'OperaCompanyWindow',
  extends: BaseOpera,
  components: { GlobalWindow, UploadAvatarImage },
  components: { GlobalWindow, UploadAvatarImage,UploadFaceImg },
  data () {
    return {
      uploadData: {
admin/src/components/common/ImageCropper.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,227 @@
<template>
  <div class="iconShot">
    <div class="icon-dialog">
      <div class="clip">
        <div class="img" ref="img">
          <vue-cropper
              ref="cropper"
              :img="imgSrc"
              :canScale="options.canScale"
              :autoCrop="options.autoCrop"
              :canMove="options.canMove"
              :centerBox="options.centerBox"
              :autoCropWidth="options.autoCropWidth"
              :autoCropHeight="options.autoCropHeight"
              @realTime="realTime"
          ></vue-cropper>
        </div>
        <div class="previews">
          <img style="width: 100px;height: 100px;border-radius: 50%;object-fit: cover" :src="cutImgSrc" alt="图片">
          <!--          <el-image-->
          <!--            v-if="cutImgSrc"-->
          <!--            style="width: 100px; height: 100px;vertical-align: middle;border-radius: 50%;"-->
          <!--            :src="cutImgSrc"-->
          <!--            fit="fill"></el-image>-->
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import { VueCropper } from 'vue-cropper'
import {upload} from "@/api/system/common";
export default {
  name: 'ImageCropper',
  components: { VueCropper },
  props: {
    imgSrc: {
      type: String,
      default: ''
    },
    // å›žæ˜¾ä¸Šæ¬¡ä¿å­˜çš„æˆªå›¾çš„位置
    location: {
      type: Object,
      default () {
        return {}
      }
    }
    // iconItem:{
    //   type:Object,
    //   default(){
    //     return {};
    //   }
    // }
  },
  data () {
    return {
      // å­¦ä¹ æˆªå›¾é€‰é¡¹
      iconForm: {
        originImgBase64: '',
        imgBase64: ''
        // location: "",
        // matchingName: "",
        // matchingType: "",
        // note: "",
        // picGroupId: "0",
        // tsId: "",
      },
      // å‚¨å­˜æˆªå›¾åŒºåŸŸçš„图片,自己传
      // imgSrc:'',
      // å‚¨å­˜æˆªå›¾åŽçš„生成的base64图片
      cutImgSrc: '',
      // cropper插件的配置
      options: {
        canScale: false,
        autoCrop: true,
        canMove: false,
        centerBox: true,
        autoCropWidth: 200,
        autoCropHeight: 200,
        fixed: true,
        fixedNumber: [1, 1]
      },
      // æˆªå›¾æ¡†ç›¸å¯¹å›¾ç‰‡çš„位置
      clipAxis: {},
      // æˆªå›¾å›žæ˜¾æ ‡å¿—,只触发一次实现回显,
      flag: true
    }
  },
  mounted () {
  },
  watch: {
  },
  methods: {
    getImagecropper(){
      return  this.$refs.cropper
    },
    // å­¦ä¹ æˆªå›¾æ¡†å˜åŒ–事件
    realTime (data) {
      if (data.h) {
        // èŽ·å–å›¾ç‰‡ç›¸å¯¹å®¹å™¨çš„ä½ç½®
        const img = this.$refs.cropper.getImgAxis()
        // èŽ·å–æˆªå›¾æ¡†ç›¸å¯¹å®¹å™¨çš„ä½ç½®
        const clip = this.$refs.cropper.getCropAxis()
        this.clipAxis.x = clip.x1 - img.x1
        this.clipAxis.y = clip.y1 - img.y1
        // èŽ·å–æˆªå›¾å›¾ç‰‡
        this.$refs.cropper.getCropData(img => {
          this.clipAxis.width = data.w
          this.clipAxis.height = data.h
          this.cutImgSrc = img
        })
        // èŽ·å–åŽŸå›¾base64的图片
        // this.imageUrlToBase64(data.url);
        // å›¾æ ‡åˆ—表编辑回显(初始化只触发一次)
        if (this.location.height != undefined && this.flag) {
          this.$nextTick(() => {
            // auto crop
            this.$refs.cropper.goAutoCrop()
            this.$nextTick(() => {
              // if cropped and has position message, update crop box
              this.$refs.cropper.cropOffsertX = this.location.x + img.x1
              this.$refs.cropper.cropOffsertY = this.location.y + img.y1
              this.$refs.cropper.cropW = this.location.width
              this.$refs.cropper.cropH = this.location.height
              // this.iconForm.location=this.iconItem.location;
              // this.iconForm.matchingName=this.iconItem.matchingName;
              // this.iconForm.matchingType=this.iconItem.matchingType;
              // this.iconForm.note=this.iconItem.note;
              // this.picGroupId=this.iconItem.picGroupId.split(',');
              // this.iconForm.id=this.iconItem.id;
              // this.iconForm.tsId=this.iconItem.tsId;
              this.flag = false
            })
          })
        }
      }
    },
    // åŽŸå›¾é€šè¿‡canvas转为base64的格式
    imageUrlToBase64 (src) {
      // ä¸€å®šè¦è®¾ç½®ä¸ºlet,不然图片不显示
      const image = new Image()
      // è§£å†³è·¨åŸŸé—®é¢˜
      image.setAttribute('crossOrigin', 'anonymous')
      const imageUrl = src
      image.src = imageUrl
      // image.onload为异步加载
      image.onload = () => {
        var canvas = document.createElement('canvas')
        canvas.width = image.width
        canvas.height = image.height
        var context = canvas.getContext('2d')
        context.drawImage(image, 0, 0, image.width, image.height)
        // var quality = 0.8;
        // è¿™é‡Œçš„dataurl就是base64类型
        const dataURL = canvas.toDataURL('image/jpeg')// ä½¿ç”¨toDataUrl将图片转换成jpeg的格式
        this.iconForm.originImgBase64 = dataURL
      }
    }
  }
}
</script>
<style lang="scss" scoped>
.iconShot {
  .icon-dialog {
    .clip {
      .img {
        height: 400px;
        // display: inline-block;
        .vue-cropper {
          background-image: none;
        }
        .cropper-move {
          cursor: default;
        }
        .cropper-face.cropper-move {
          cursor: move;
        }
      }
      .previews {
        width: 100%;
        height: 100px;
        position: relative;
        >img {
          position: absolute;
          left: 50%;
          transform: translateX(-50%);
          max-height: 100%;
        }
      }
    }
  }
  .icon-options {
    font-size: 12px;
    font-weight: 200;
    >.el-row {
      >.el-col {
        >.el-row {
          height: 36px;
          line-height: 36px;
          >.el-col:nth-child(1) {
            font-weight: 600;
            text-align: right;
          }
          .el-col:nth-child(2) {
            .el-input,.el-select {
              width: 185px !important;
            }
          }
          >.el-col {
            padding: 0 10px;
          }
        }
      }
    }
  }
}
</style>
admin/src/components/common/UploadFaceImg.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,197 @@
<template>
  <div>
    <el-upload
        class="avatar-uploader"
        accept=".png,.jpg,.jpeg"
        :style="customStyle"
        action=""
        :auto-upload="false"
        :show-file-list="false"
        :on-change='openUpdateIcon'>
      <img v-if=" file.imgurlfull" style="width: 100%;" :src="file.imgurlfull" :style="customStyle" class="avatar">
      <div v-else :style="customStyle">
        <i class="el-icon-plus avatar-uploader-icon"></i>
        <div class="tips-style">{{ tipsLabel }}</div>
      </div>
    </el-upload>
    <el-dialog
        append-to-body
        :close-on-click-modal="false"
        title="上传图片"
        :visible.sync="updateImg"
        width="800px"
        class="icon-dialog-wrapper dialong-com-style">
      <ImageCropper ref="iconShot" v-if="updateImg" :imgSrc="img" >
      </ImageCropper>
      <span slot="footer" class="dialog-footer">
            <el-button @click="updateImg = false">取 æ¶ˆ</el-button>
            <el-button type="primary" @click="uploadIcon">ç¡® å®š</el-button>
          </span>
    </el-dialog>
  </div>
</template>
<script>
import ImageCropper from '@/components/common/ImageCropper'
import { upload } from '@/api/system/common'
export default {
  components: { ImageCropper },
  props: {
    file: {
      type: Object,
      default: () => {}
    },
    tipsLabel: '',
    customStyle: {
      type: String,
      default: 'width: 90px; height: 90px;'
    },
    uploadData: Object
  },
  data () {
    return {
      fileInfo:{},
      img: null,
      updateImg: false,
      imageSrc: null,
      uploadImgUrl: process.env.VUE_APP_API_PREFIX + '/visitsAdmin/cloudService/public/upload'
    }
  },
  methods: {
    uploadIcon () {
      // èŽ·å–è£å‰ªåŽçš„å›¾ç‰‡
      this.$refs.iconShot.getImagecropper().getCropBlob((fileData) => { // èŽ·å–å½“å‰è£å‰ªå¥½çš„æ•°æ®
        // æ³¨æ­¤æ—¶çš„data是一个Blob数据,部分接口接收的是File转化的FormData数据
        console.log(fileData)
        const formData = new FormData()
        formData.append('folder', 'member')
        formData.append(
            'file',
            new File(
                [fileData], // å°†Blob类型转化成File类型
                this.fileInfo.name, // è®¾ç½®File类型的文件名称
                { type: this.fileInfo.type } // è®¾ç½®File类型的文件类型
            )
        )
        upload(formData).then(res => {
          console.log(res)
          this.file.imgurl = res.imgaddr
          this.file.imgurlfull = res.url
          this.$message.success('上传成功')
          this.imageSrc = res.url
          this.updateImg = false
          this.$emit('uploadSuccess', { imgurl: res.imgaddr, imgurlfull: res.url, name: res.originname })
          this.$emit('uploadEnd')
        })
      })
    },
    // ä¸Šä¼ å›¾ç‰‡
    openUpdateIcon (file, fileList) {
      const isJPG = file.raw.type === 'image/jpeg' || file.raw.type === 'image/png'
      const isLt2M = file.size / 1024 / 1024 < 2
      if (!isJPG) {
        this.$message.error('上传头像图片只能是 JPG/PNG æ ¼å¼!')
        return false
      }
      if (!isLt2M) {
        this.$message.error('上传头像图片大小不能超过 2MB!')
        return false
      }
      // ä¸Šä¼ æˆåŠŸåŽå°†å›¾ç‰‡åœ°å€èµ‹å€¼ç»™è£å‰ªæ¡†æ˜¾ç¤ºå›¾ç‰‡
      this.$nextTick(async () => {
        // base64方式
        // this.option.img = await fileByBase64(file.raw)
        this.fileInfo.name = file.name
        this.fileInfo.type = file.type
        console.log(file, fileList)
        this.img = URL.createObjectURL(file.raw)
        // this.loading = false
        this.updateImg = true
      })
    },
    handleAvatarSuccess (res, file) {
      if (res.code == 200) {
        const { data } = res
        this.file.imgurl = data.imgaddr
        this.file.imgurlfull = data.url
        this.$message.success('上传成功')
        this.imageSrc = data.url
        this.updateImg = true
        // this.$emit('uploadSuccess', { imgurl: data.imgaddr, imgurlfull: data.url, name: data.originname })
      } else {
        this.$message.error('上传失败')
      }
      this.$emit('uploadEnd')
    },
    uploadError () {
      this.$message.error('上传失败')
      this.$emit('uploadEnd')
    },
    // // æ‹¦æˆª
    beforeAvatarUpload (file) {
      this.$emit('uploadBegin')
      return true
    }
  }
}
</script>
<style lang="scss" scoped>
$image-width: 90px;
.avatar-uploader {
  width: $image-width;
  height: $image-width;
}
::v-deep .el-upload {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}
.avatar-uploader .el-upload:hover {
  border-color: #409EFF;
}
.avatar-uploader-icon {
  line-height: 90px;
  font-size: 28px;
  color: #8c939d;
  width: $image-width;
  height: $image-width;
  text-align: center;
}
.avatar {
  width: 100% !important;
  height: auto !important;
  display: block;
}
.tips-style {
  height: 13px;
  font-size: 13px;
  font-weight: 400;
  color: #999999;
  line-height: 13px;
}
</style>
<style lang="scss" scoped>
::v-deep .el-upload--picture-card{
  width: 90px !important;
  height: 90px !important;
}
::v-deep .el-upload-list__item {
  width: 90px !important;
  height: 90px !important;
}
.icon {
  -webkit-transform: translate(-50%,-50%);
  -ms-transform: translate(-50%,-50%);
  transform: translate(0%, -85%);
}
::v-deep .el-upload-list__item {
  width: 90px !important;
  height: 90px !important;
}
</style>
admin/src/views/business/interfaceLog.vue
@@ -113,16 +113,16 @@
  methods: {
    changeRadio (e) {
      if (e === '0') {
        this.searchForm.startTime = timeForMat(0)[0]
        this.searchForm.endTime = timeForMat(0)[1]
        this.searchForm.startDate = timeForMat(0)[0]
        this.searchForm.endDate = timeForMat(0)[1]
        this.time = timeForMat(0)
      } else if (e === '1') {
        this.searchForm.startTime = timeForMat(6)[0]
        this.searchForm.endTime = timeForMat(6)[1]
        this.searchForm.startDate = timeForMat(6)[0]
        this.searchForm.endDate = timeForMat(6)[1]
        this.time = timeForMat(6)
      } else if (e === '2') {
        this.searchForm.startTime = timeForMat(29)[0]
        this.searchForm.endTime = timeForMat(29)[1]
        this.searchForm.startDate = timeForMat(29)[0]
        this.searchForm.endDate = timeForMat(29)[1]
        this.time = timeForMat(29)
      }
      this.search()
admin/src/views/business/platformInterfaceLog.vue
@@ -113,16 +113,16 @@
  methods: {
    changeRadio (e) {
      if (e === '0') {
        this.searchForm.startTime = timeForMat(0)[0]
        this.searchForm.endTime = timeForMat(0)[1]
        this.searchForm.startDate = timeForMat(0)[0]
        this.searchForm.endDate = timeForMat(0)[1]
        this.time = timeForMat(0)
      } else if (e === '1') {
        this.searchForm.startTime = timeForMat(6)[0]
        this.searchForm.endTime = timeForMat(6)[1]
        this.searchForm.startDate = timeForMat(6)[0]
        this.searchForm.endDate = timeForMat(6)[1]
        this.time = timeForMat(6)
      } else if (e === '2') {
        this.searchForm.startTime = timeForMat(29)[0]
        this.searchForm.endTime = timeForMat(29)[1]
        this.searchForm.startDate = timeForMat(29)[0]
        this.searchForm.endDate = timeForMat(29)[1]
        this.time = timeForMat(29)
      }
      this.search()