13 changed files with 916 additions and 12 deletions
-
1.env.development
-
3.env.production
-
5package.json
-
3public/static/config.js
-
11src/api/stockTask/index.js
-
2src/assets/styles/sidebar.scss
-
3src/main.js
-
15src/utils/upload.js
-
9src/views/visualCheck/checkManage/checkLog/index.vue
-
6src/views/visualCheck/checkManage/dataScreening/girdList.vue
-
515src/views/visualCheck/checkManage/mobileCheck/index.vue
-
271src/views/visualCheck/checkManage/mobileCheck/module/corpper.vue
-
84src/views/visualCheck/checkManage/paramSetting/index.vue
@ -0,0 +1,515 @@ |
|||||
|
<template> |
||||
|
<div class="app-container row-container"> |
||||
|
<!-- style="height: calc(100vh - 200px);" --> |
||||
|
<!-- style="height: calc(100vh);" --> |
||||
|
<div class="container-wrap" :style="{ height: !isMobile ? 'calc(100vh - 200px)' : '' }"> |
||||
|
<span class="right-top-line" /> |
||||
|
<span class="left-bottom-line" /> |
||||
|
<div class="camera-container"> |
||||
|
|
||||
|
<div :class="!isMobile ? 'mobile-step' : 'mobile-step isMobile-step'"> |
||||
|
<!-- <span>选择目标位置</span> --> |
||||
|
<el-divider content-position="left"><img src="@/assets/images/collect/one.png"><span>选择目标位置</span></el-divider> |
||||
|
<div class="step-style"> |
||||
|
<el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="90px"> |
||||
|
<el-form-item class="collection-tree-select" label="所在架位" prop="actualShelfId"> |
||||
|
<treeselect |
||||
|
v-model="form.actualShelfId" |
||||
|
:options="regionTreeData" |
||||
|
flat |
||||
|
:multiple="false" |
||||
|
placeholder="选择架" |
||||
|
:normalizer="normalizer" |
||||
|
:default-expand-level="levelNumber" |
||||
|
style="width: 282px;" |
||||
|
:disabled="!stepOne" |
||||
|
:searchable="false" |
||||
|
@select="node=>treeSelectInput(node)" |
||||
|
> |
||||
|
<div slot="value-label" slot-scope="{ node }">{{ getAutoNameUnknown(node.label) }}</div> |
||||
|
</treeselect> |
||||
|
</el-form-item> |
||||
|
<el-form-item class="collection-tree-select" label="所在层位" prop="gridId"> |
||||
|
<treeselect |
||||
|
v-model="form.gridId" |
||||
|
:options="girdData" |
||||
|
placeholder="选择层位" |
||||
|
:normalizer="normalizerGird" |
||||
|
:default-expand-level="levelNumber" |
||||
|
:disabled="!stepOne" |
||||
|
style="width: 282px; " |
||||
|
:searchable="false" |
||||
|
@select="node=>gridSelectInput(node)" |
||||
|
> |
||||
|
<div slot="value-label" slot-scope="{ node }">{{ getAutoNameUnknown(node.label) }}</div> |
||||
|
</treeselect> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<el-button v-if="stepOne" class="check-btn" style="margin-bottom: 18px" :loading="submitLoading" type="primary" @click="submitStepOne">下一步</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div :class="!isMobile ? 'mobile-step' : 'mobile-step isMobile-step'"> |
||||
|
<!-- <span>拍照上传</span> --> |
||||
|
<el-divider content-position="left"><img src="@/assets/images/collect/two2.png"><span>拍照上传</span></el-divider> |
||||
|
<!-- style="margin: 20px 0;" --> |
||||
|
<div v-if="!stepOne" class="step-style"> |
||||
|
<div class="mobile-check-upload"> |
||||
|
<div class="upload-input"> |
||||
|
<input |
||||
|
ref="imgFile" |
||||
|
accept="image/*" |
||||
|
capture="camera" |
||||
|
type="file" |
||||
|
multiple |
||||
|
:disabled="stepOne" |
||||
|
@change="previewFiles" |
||||
|
> |
||||
|
<div class="upload-zip"><i class="iconfont icon-shangchuan2" />{{ isMobile ? '拍照上传':'上传文件' }}</div> |
||||
|
</div> |
||||
|
<div style="margin-left: 40px;"> |
||||
|
<div v-for="(imgSrc, index) in imageSources" :key="index" style="display: inline-block; margin: 10px;"> |
||||
|
<img |
||||
|
:src="imgSrc" |
||||
|
style="display: inline-block; max-width: 100px; max-height: 100px;" |
||||
|
@click="showCoverPreview(imgSrc)" |
||||
|
> |
||||
|
<i class="iconfont icon-shanchu1" @click="deleteImage(index)" /> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 裁切上传 --> |
||||
|
<!-- <el-form ref="formValidate" :model="formValidate" :rules="ruleCropper" label-width="100px" class="mobile-stepForm"> |
||||
|
<el-form-item label="照片上传" prop="mainImage"> |
||||
|
<div v-if="formValidate.mainImage !== ''" class="list-img-box"> |
||||
|
<img :src="formValidate.mainImage" style="max-width:300px; max-height:150px" alt="图书" @click="showCoverPreview(formValidate.mainImage)"> |
||||
|
</div> |
||||
|
<div class="upload-zip" @click="uploadPicture('flagImg')"><i class="iconfont icon-shangchuan2" />{{ isMobile ? '拍照上传':'上传文件' }}</div> |
||||
|
<input v-model="formValidate.mainImage" type="hidden" placeholder="请添加照片"> |
||||
|
</el-form-item> |
||||
|
</el-form> --> |
||||
|
</div> |
||||
|
<div> |
||||
|
<el-button type="primary" @click="returnStepOne">上一步</el-button> |
||||
|
<el-button class="check-btn" :loading="submitLoading" type="primary" @click="saveData">下一步</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div :class="!isMobile ? 'mobile-step' : 'mobile-step isMobile-step'"> |
||||
|
<!-- <span>开始盘点</span> --> |
||||
|
<el-divider content-position="left"><img src="@/assets/images/collect/three2.png"><span>开始盘点</span></el-divider> |
||||
|
<div v-if="stepThree" class="step-style step-three-text"> |
||||
|
<p v-if="mobileResult"> |
||||
|
移动盘点已创建成功,单号【{{ mobileResult.stockBill }}】,查看详情请转到: |
||||
|
<router-link :to="{ path: '/check/check/checkLog'}"> |
||||
|
盘点日志 |
||||
|
</router-link> |
||||
|
</p> |
||||
|
<p v-else> |
||||
|
移动盘点创建失败 |
||||
|
</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- 点击缩略图看大图 --> |
||||
|
<el-dialog v-if="!isMobile" class="preview-dialog" :append-to-body="true" :close-on-click-modal="false" :before-close="handleClose" :visible="showCoverVisible" title="查看大图"> |
||||
|
<span class="dialog-right-top" /> |
||||
|
<span class="dialog-left-bottom" /> |
||||
|
<div class="setting-dialog" style="max-height:calc(100vh - 230px); overflow:auto;"> |
||||
|
<img style="max-width:100%; object-fit: contain;" :src="previewSrc"> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
<el-dialog v-else class="mobile-dialog" :append-to-body="true" :close-on-click-modal="false" :before-close="handleClose" :visible="showCoverVisible" title="查看大图"> |
||||
|
<span class="dialog-right-top" /> |
||||
|
<span class="dialog-left-bottom" /> |
||||
|
<div class="setting-dialog"> |
||||
|
<img style="max-width:100%; max-height: 100%; object-fit: contain;" :src="previewSrc"> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
|
||||
|
<!-- 剪裁组件弹窗 --> |
||||
|
<el-dialog |
||||
|
title="裁切照片" |
||||
|
:close-on-click-modal="false" |
||||
|
:modal-append-to-body="false" |
||||
|
append-to-body |
||||
|
:visible.sync="cropperModel" |
||||
|
width="950px" |
||||
|
center |
||||
|
> |
||||
|
<cropper-image |
||||
|
ref="child" |
||||
|
@uploadImgSuccess="handleUploadSuccess" |
||||
|
/> |
||||
|
</el-dialog> |
||||
|
<!--查看大图--> |
||||
|
<el-dialog |
||||
|
:close-on-click-modal="false" |
||||
|
:modal-append-to-body="false" |
||||
|
append-to-body |
||||
|
title="查看大图" |
||||
|
:visible.sync="imgVisible" |
||||
|
center |
||||
|
> |
||||
|
<img v-if="imgVisible" :src="imgName" style="width: 100%" alt="查看"> |
||||
|
</el-dialog> |
||||
|
|
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { FetchRegionTree } from '@/api/deviceVI/index' |
||||
|
import { FetchShelfGridAllByShelfId } from '@/api/shelf/index' |
||||
|
import { mapGetters } from 'vuex' |
||||
|
import { removeQUPrefix } from '@/utils/index' |
||||
|
import { mobileUpload } from '@/utils/upload' |
||||
|
|
||||
|
import Treeselect from '@riophae/vue-treeselect' |
||||
|
import '@riophae/vue-treeselect/dist/vue-treeselect.css' |
||||
|
|
||||
|
import CropperImage from './module/corpper.vue' |
||||
|
|
||||
|
export default { |
||||
|
name: 'MobileCheck', |
||||
|
components: { Treeselect, CropperImage }, |
||||
|
data() { |
||||
|
return { |
||||
|
form: { actualShelfId: null, gridId: null }, |
||||
|
levelNumber: 4, |
||||
|
regionTreeData: [], |
||||
|
selectShelfVal: null, |
||||
|
selectGridVal: null, |
||||
|
girdData: [], |
||||
|
permission: { |
||||
|
add: ['admin', 'paramSetting:add'], |
||||
|
edit: ['admin', 'paramSetting:edit'], |
||||
|
del: ['admin', 'paramSetting:del'] |
||||
|
}, |
||||
|
showCoverVisible: false, // 查看大图dialog |
||||
|
previewSrc: '', // 查看大图src |
||||
|
imageSources: [], // 存储图片的数据URL |
||||
|
selectedFiles: [], // 存储选中的图片 File 对象 |
||||
|
isMobile: false, |
||||
|
submitLoading: false, |
||||
|
rules: { |
||||
|
gridId: [ |
||||
|
{ required: true, message: '请选择层位', trigger: 'change' } |
||||
|
], |
||||
|
actualShelfId: [ |
||||
|
{ required: true, message: '请选择书架', trigger: 'change' } |
||||
|
] |
||||
|
}, |
||||
|
stepOne: true, |
||||
|
stepTwo: false, |
||||
|
stepThree: false, |
||||
|
// 裁切图片参数 |
||||
|
formValidate: { |
||||
|
mainImage: '' |
||||
|
}, |
||||
|
ruleCropper: { |
||||
|
mainImage: [ |
||||
|
{ required: true, message: '请上传照片', trigger: 'blur' } |
||||
|
] |
||||
|
}, |
||||
|
cropperModel: false, |
||||
|
imgName: '', |
||||
|
imgVisible: false |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
...mapGetters([ |
||||
|
'baseApi' |
||||
|
]) |
||||
|
}, |
||||
|
created() { |
||||
|
FetchRegionTree().then(res => { |
||||
|
this.regionTreeData = [this.transformData(res)] |
||||
|
}).catch(() => { |
||||
|
}) |
||||
|
this.checkDevice() |
||||
|
}, |
||||
|
beforeDestroy() { |
||||
|
}, |
||||
|
mounted() { |
||||
|
}, |
||||
|
methods: { |
||||
|
// 处理vue-treeSelect回显出现unknown问题 |
||||
|
getAutoNameUnknown(name) { |
||||
|
if (name.lastIndexOf('unknown') > -1) { |
||||
|
return name.split('(')[0] |
||||
|
} else { |
||||
|
return name |
||||
|
} |
||||
|
}, |
||||
|
normalizer(node) { |
||||
|
if (node.children && !node.children.length) { |
||||
|
delete node.children |
||||
|
} |
||||
|
return { |
||||
|
id: node.id, |
||||
|
label: node.label, |
||||
|
children: node.children, |
||||
|
isDisabled: !node.shelfId |
||||
|
} |
||||
|
}, |
||||
|
normalizerGird(node) { |
||||
|
return { |
||||
|
id: node.id, |
||||
|
label: removeQUPrefix(node.gridName) |
||||
|
} |
||||
|
}, |
||||
|
transformData(data) { |
||||
|
return { |
||||
|
id: data.fondsId, |
||||
|
fondsId: data.fondsId, |
||||
|
label: data.fondsName, |
||||
|
children: data.floors.map(floor => ({ |
||||
|
id: floor.id, |
||||
|
floorId: floor.id, |
||||
|
label: floor.floorName, |
||||
|
children: floor.regions.map(region => ({ |
||||
|
id: region.id, |
||||
|
regionId: region.id, |
||||
|
label: region.regionName, |
||||
|
parentFloorId: floor.id, |
||||
|
children: region.bookShelf.map(shelfItem => ({ |
||||
|
id: shelfItem.shelfId, |
||||
|
shelfId: shelfItem.shelfId, |
||||
|
label: shelfItem.shelfName, |
||||
|
regionName: floor.floorName + '-' + region.regionName, |
||||
|
parentRegionId: region.id |
||||
|
})) |
||||
|
})) |
||||
|
})) |
||||
|
} |
||||
|
}, |
||||
|
treeSelectInput(value) { |
||||
|
console.log(value) |
||||
|
// '3F-成人图书借阅区-001排A面' |
||||
|
this.selectShelfVal = value |
||||
|
this.form.gridId = null |
||||
|
this.getShelfGridAllByShelfId() |
||||
|
}, |
||||
|
getShelfGridAllByShelfId() { |
||||
|
const params = { |
||||
|
'shelfId': this.selectShelfVal.id |
||||
|
} |
||||
|
FetchShelfGridAllByShelfId(params).then(res => { |
||||
|
this.girdData = res |
||||
|
}).catch(() => { |
||||
|
}) |
||||
|
}, |
||||
|
gridSelectInput(value) { |
||||
|
console.log(value) |
||||
|
this.selectGridVal = value |
||||
|
}, |
||||
|
checkDevice() { |
||||
|
const userAgent = navigator.userAgent.toLowerCase() |
||||
|
const mobileKeywords = ['android', 'iphone', 'ipad', 'ipod'] |
||||
|
this.isMobile = mobileKeywords.some(keyword => userAgent.includes(keyword)) |
||||
|
}, |
||||
|
previewFiles() { |
||||
|
const files = this.$refs.imgFile.files |
||||
|
const maxImages = 3 |
||||
|
const remainingSlots = maxImages - this.imageSources.length |
||||
|
|
||||
|
if (remainingSlots === 0) { |
||||
|
this.$message({ message: '已有 3 张图片,不能再上传', type: 'error', offset: 8 }) |
||||
|
} |
||||
|
|
||||
|
const validFiles = [] |
||||
|
for (let i = 0; i < files.length; i++) { |
||||
|
const file = files[i] |
||||
|
if (file.type === 'image/jpeg') { |
||||
|
validFiles.push(file) |
||||
|
} else { |
||||
|
this.$message({ message: `文件 ${file.name} 不是 JPG 格式,将忽略该文件`, type: 'error', offset: 8 }) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (validFiles.length > remainingSlots) { |
||||
|
this.$message({ message: `最多只能再上传 ${remainingSlots} 张图片,将只处理部分选择的图片`, type: 'error', offset: 8 }) |
||||
|
} |
||||
|
|
||||
|
const numFilesToProcess = Math.min(validFiles.length, remainingSlots) |
||||
|
for (let i = 0; i < numFilesToProcess; i++) { |
||||
|
const file = validFiles[i] |
||||
|
const reader = new FileReader() |
||||
|
reader.onload = (e) => { |
||||
|
this.imageSources.push(e.target.result) |
||||
|
} |
||||
|
reader.readAsDataURL(file) |
||||
|
this.selectedFiles.push(file) |
||||
|
} |
||||
|
}, |
||||
|
submitStepOne() { |
||||
|
this.$refs.form.validate((valid) => { |
||||
|
if (valid) { |
||||
|
this.stepOne = false |
||||
|
} else { |
||||
|
console.log('error submit!!') |
||||
|
return false |
||||
|
} |
||||
|
}) |
||||
|
}, |
||||
|
returnStepOne() { |
||||
|
this.stepOne = true |
||||
|
this.stepTwo = false |
||||
|
this.imageSources = [] |
||||
|
this.selectedFiles = [] |
||||
|
}, |
||||
|
saveData() { |
||||
|
// this.formValidate.mainImage === '' |
||||
|
if (this.selectedFiles.length === 0) { |
||||
|
this.$message({ message: '请上传照片', type: 'error', offset: 8 }) |
||||
|
} else { |
||||
|
this.submitLoading = true |
||||
|
|
||||
|
const params = { |
||||
|
'gridId': this.form.gridId, |
||||
|
'stockRegion': this.selectShelfVal.regionName + '-' + removeQUPrefix(this.selectGridVal.gridName) |
||||
|
} |
||||
|
mobileUpload(this.baseApi + '/api/stocktask-task/moveBill', this.selectedFiles, params).then(res => { |
||||
|
console.log(res) |
||||
|
if (res.data.code === 200) { |
||||
|
this.mobileResult = res.data.data |
||||
|
this.stepOne = false |
||||
|
this.stepTwo = true |
||||
|
} else { |
||||
|
this.$message({ message: res.data.message, type: 'error', offset: 8 }) |
||||
|
this.mobileResult = null |
||||
|
} |
||||
|
this.submitLoading = false |
||||
|
}) |
||||
|
} |
||||
|
}, |
||||
|
deleteImage(index) { |
||||
|
this.imageSources.splice(index, 1) |
||||
|
this.selectedFiles.splice(index, 1) |
||||
|
}, |
||||
|
handleClose(done) { |
||||
|
this.showCoverVisible = false |
||||
|
done() |
||||
|
}, |
||||
|
// 查看大图 |
||||
|
showCoverPreview(imgSrc) { |
||||
|
this.showCoverVisible = true |
||||
|
this.previewSrc = imgSrc |
||||
|
}, |
||||
|
// 裁切上传照片设置 ----- |
||||
|
uploadPicture() { |
||||
|
this.cropperModel = true |
||||
|
}, |
||||
|
// 图片上传成功后 |
||||
|
handleUploadSuccess(data) { |
||||
|
console.log(data) |
||||
|
this.formValidate.mainImage = data.url |
||||
|
this.selectedFiles = data.file |
||||
|
// switch (data.name) { |
||||
|
// case 'flagImg': |
||||
|
// this.formValidate.mainImage = 'http://ydfblog.cn/dfs/' + data.url |
||||
|
// console.log('最终输出' + data.name) |
||||
|
// break |
||||
|
// } |
||||
|
this.cropperModel = false |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.camera-container{ |
||||
|
height: 100%; |
||||
|
} |
||||
|
.mobile-step{ |
||||
|
position: relative; |
||||
|
height: calc(100% / 3); |
||||
|
::v-deep .el-divider--horizontal{ |
||||
|
margin: 0 !important; |
||||
|
.el-divider__text{ |
||||
|
display: flex; |
||||
|
justify-content: flex-start; |
||||
|
align-items: center; |
||||
|
img{ |
||||
|
display: block; |
||||
|
margin-top: -10px; |
||||
|
} |
||||
|
span{ |
||||
|
font-size: 16px; |
||||
|
margin-left: 10px; |
||||
|
font-weight: bold; |
||||
|
color: #0c0e1e; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
// padding-left: 20px; |
||||
|
// &::before{ |
||||
|
// content: ''; |
||||
|
// position: absolute; |
||||
|
// top: 0; |
||||
|
// left: 0; |
||||
|
// width: 10px; |
||||
|
// height: 10px; |
||||
|
// border-radius: 50%; |
||||
|
// background-color: #0c0e1e; |
||||
|
// } |
||||
|
// &::after{ |
||||
|
// content: ''; |
||||
|
// position: absolute; |
||||
|
// top: 8px; |
||||
|
// left: 4px; |
||||
|
// width: 2px; |
||||
|
// height: calc(100% - 20px); |
||||
|
// background-color: #0c0e1e; |
||||
|
// } |
||||
|
} |
||||
|
|
||||
|
.isMobile-step{ |
||||
|
height: 200px; |
||||
|
} |
||||
|
|
||||
|
.mobile-check-upload{ |
||||
|
display: flex; |
||||
|
justify-content: flex-start; |
||||
|
align-items: center; |
||||
|
.upload-input{ |
||||
|
margin-top: 0 !important; |
||||
|
} |
||||
|
} |
||||
|
// .bg-button{ |
||||
|
// color: #fff; |
||||
|
// background: #1f55eb; |
||||
|
// } |
||||
|
.mobile-dialog{ |
||||
|
::v-deep .el-dialog{ |
||||
|
width: 100%; |
||||
|
} |
||||
|
} |
||||
|
.upload-input input{ |
||||
|
width: 105px; |
||||
|
} |
||||
|
.step-style{ |
||||
|
display: flex; justify-content: space-between; align-items: center; height: calc(100%); padding: 0 16px; |
||||
|
} |
||||
|
.step-three-text { |
||||
|
justify-content: flex-start; |
||||
|
a{ |
||||
|
font-weight: bold; |
||||
|
color: #1f55eb; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.vue-treeselect__search { |
||||
|
display: none; |
||||
|
} |
||||
|
|
||||
|
.mobile-stepForm{ |
||||
|
::v-deep .el-form-item__content{ |
||||
|
display: flex; |
||||
|
justify-content: flex-start; |
||||
|
align-items: end; |
||||
|
.upload-zip{ |
||||
|
margin-left: 40px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,271 @@ |
|||||
|
<template> |
||||
|
<div class="cropper-content"> |
||||
|
<div class="cropper-box"> |
||||
|
<div class="cropper"> |
||||
|
<vue-cropper |
||||
|
ref="cropper" |
||||
|
:img="option.img" |
||||
|
:output-size="option.outputSize" |
||||
|
:output-type="option.outputType" |
||||
|
:info="option.info" |
||||
|
:can-scale="option.canScale" |
||||
|
:auto-crop="option.autoCrop" |
||||
|
:auto-crop-width="option.autoCropWidth" |
||||
|
:auto-crop-height="option.autoCropHeight" |
||||
|
:fixed="option.fixed" |
||||
|
:fixed-number="option.fixedNumber" |
||||
|
:full="option.full" |
||||
|
:fixed-box="option.fixedBox" |
||||
|
:can-move="option.canMove" |
||||
|
:can-move-box="option.canMoveBox" |
||||
|
:original="option.original" |
||||
|
:center-box="option.centerBox" |
||||
|
:height="option.height" |
||||
|
:info-true="option.infoTrue" |
||||
|
:max-img-size="option.maxImgSize" |
||||
|
:enlarge="option.enlarge" |
||||
|
:mode="option.mode" |
||||
|
@realTime="realTime" |
||||
|
@imgLoad="imgLoad" |
||||
|
/> |
||||
|
</div> |
||||
|
<!--底部操作工具按钮--> |
||||
|
<div class="footer-btn"> |
||||
|
<div class="scope-btn"> |
||||
|
<label class="btn" for="uploads">上传照片</label> |
||||
|
<input id="uploads" type="file" style="position:absolute; clip:rect(0 0 0 0);" accept="image/png, image/jpeg, image/gif, image/jpg" capture="camera" @change="selectImg($event)"> |
||||
|
<el-button size="mini" type="danger" icon="el-icon-zoom-in" @click="changeScale(1)">放大</el-button> |
||||
|
<el-button size="mini" type="danger" icon="el-icon-zoom-out" @click="changeScale(-1)">缩小</el-button> |
||||
|
<!-- <el-button size="mini" type="danger" @click="rotateLeft">↺ 左旋转</el-button> |
||||
|
<el-button size="mini" type="danger" @click="rotateRight">↻ 右旋转</el-button> --> |
||||
|
</div> |
||||
|
<div class="upload-cropper-btn"> |
||||
|
<el-button size="mini" type="success" @click="uploadImg('blob')">确认裁切 <i class="el-icon-upload" /></el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!--预览效果图--> |
||||
|
<div class="show-preview"> |
||||
|
<div :style="previews.div" class="preview"> |
||||
|
<img :src="previews.url" :style="previews.img"> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { VueCropper } from 'vue-cropper' |
||||
|
export default { |
||||
|
name: 'CropperImage', |
||||
|
components: { |
||||
|
VueCropper |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
previews: {}, |
||||
|
option: { |
||||
|
img: '', // 裁剪图片的地址 |
||||
|
outputSize: 1, // 裁剪生成图片的质量(可选0.1 - 1) |
||||
|
outputType: 'jpeg', // 裁剪生成图片的格式(jpeg || png || webp) |
||||
|
fixedNumber: [1.53, 1], // 截图框的宽高比例 |
||||
|
infoTrue: false, // true为展示真实输出图片宽高,false展示看到的截图框宽高 |
||||
|
maxImgSize: 10 * 1024 * 1024, // 最大图片大小 10MB |
||||
|
enlarge: 1, // 图片根据截图框输出比例倍数 |
||||
|
full: false, // 输出原图比例截图 props名full |
||||
|
canMove: true, // 上传图片是否可以移动 |
||||
|
original: false, // 上传图片按照原始比例渲染 |
||||
|
height: true, // 是否按照设备的dpr 输出等比例图片 |
||||
|
canMoveBox: true, // 截图框是否可以拖动 |
||||
|
autoCrop: true, // 是否默认生成截图框 |
||||
|
autoCropWidth: 200, // 默认截图框宽度 |
||||
|
autoCropHeight: 200, // 默认生成截图框高度 |
||||
|
fixedBox: false, // 固定截图框大小 |
||||
|
mode: 'cover', // 图片默认渲染方式 |
||||
|
info: true, // 裁剪框的大小信息 |
||||
|
canScale: true, // 图片是否允许滚轮缩放 |
||||
|
fixed: false, // 是否开启截图框宽高固定比例 |
||||
|
centerBox: false // 截图框是否被限制在图片里面 |
||||
|
}, |
||||
|
imageUrl: '' |
||||
|
} |
||||
|
}, |
||||
|
beforeDestroy() { |
||||
|
if (this.imageUrl) { |
||||
|
URL.revokeObjectURL(this.imageUrl) |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
// 初始化函数 |
||||
|
imgLoad(msg) { |
||||
|
console.log('工具初始化函数=====' + msg) |
||||
|
}, |
||||
|
// 图片缩放 |
||||
|
changeScale(num) { |
||||
|
num = num || 1 |
||||
|
this.$refs.cropper.changeScale(num) |
||||
|
}, |
||||
|
// 向左旋转 |
||||
|
rotateLeft() { |
||||
|
this.$refs.cropper.rotateLeft() |
||||
|
}, |
||||
|
// 向右旋转 |
||||
|
rotateRight() { |
||||
|
this.$refs.cropper.rotateRight() |
||||
|
}, |
||||
|
// 实时预览函数 |
||||
|
realTime(data) { |
||||
|
this.previews = data |
||||
|
}, |
||||
|
// 选择图片 |
||||
|
selectImg(e) { |
||||
|
const file = e.target.files[0] |
||||
|
if (!/\.(jpg|jpeg|JPG)$/.test(e.target.value)) { |
||||
|
this.$message({ |
||||
|
message: '图片类型要求:jpeg、jpg', |
||||
|
type: 'error' |
||||
|
}) |
||||
|
return false |
||||
|
} |
||||
|
// 转化为blob |
||||
|
const reader = new FileReader() |
||||
|
reader.onload = (e) => { |
||||
|
let data |
||||
|
if (typeof e.target.result === 'object') { |
||||
|
data = window.URL.createObjectURL(new Blob([e.target.result])) |
||||
|
} else { |
||||
|
data = e.target.result |
||||
|
} |
||||
|
this.option.img = data |
||||
|
} |
||||
|
// 转化为base64 |
||||
|
reader.readAsDataURL(file) |
||||
|
this.selectedFiles = file |
||||
|
}, |
||||
|
// 上传图片 |
||||
|
uploadImg(type) { |
||||
|
const _this = this |
||||
|
if (type === 'blob') { |
||||
|
// 获取截图的blob数据 |
||||
|
this.$refs.cropper.getCropBlob(async(data) => { |
||||
|
console.log('data', data) |
||||
|
// 将 Blob 转换为 File 类型 |
||||
|
const file = new File([data], 'DX.jpg', { type: data.type }) |
||||
|
// 为 File 创建一个临时的 URL |
||||
|
this.imageUrl = URL.createObjectURL(file) |
||||
|
// const formData = new FormData() |
||||
|
// formData.append('file', file, 'DX.jpg') |
||||
|
console.log('file', file) |
||||
|
const imgInfo = { |
||||
|
url: this.imageUrl, |
||||
|
file: file |
||||
|
} |
||||
|
console.log('imgInfo', imgInfo) |
||||
|
_this.$emit('uploadImgSuccess', imgInfo) |
||||
|
// 调用axios上传 |
||||
|
// const { data: res } = await _this.$http.post('/api/file/imgUpload', formData) |
||||
|
// if (res.code === 200) { |
||||
|
// _this.$message({ |
||||
|
// message: res.msg, |
||||
|
// type: 'success' |
||||
|
// }) |
||||
|
// const data = res.data.replace('[', '').replace(']', '').split(',') |
||||
|
// const imgInfo = { |
||||
|
// name: _this.cropperName, |
||||
|
// url: data[0] |
||||
|
// } |
||||
|
// console.log('imgInfo', imgInfo) |
||||
|
// _this.$emit('uploadImgSuccess', imgInfo) |
||||
|
// } else { |
||||
|
// _this.$message({ |
||||
|
// message: '文件服务异常,请联系管理员!', |
||||
|
// type: 'error' |
||||
|
// }) |
||||
|
// } |
||||
|
}) |
||||
|
} |
||||
|
}, |
||||
|
// 将base64的图片转换为file文件 |
||||
|
convertBase64UrlToBlob(urlData) { |
||||
|
const bytes = window.atob(urlData.split(',')[1])// 去掉url的头,并转换为byte |
||||
|
// 处理异常,将ascii码小于0的转换为大于0 |
||||
|
const ab = new ArrayBuffer(bytes.length) |
||||
|
const ia = new Uint8Array(ab) |
||||
|
for (var i = 0; i < bytes.length; i++) { |
||||
|
ia[i] = bytes.charCodeAt(i) |
||||
|
} |
||||
|
return new Blob([ab], { type: 'image/jpeg' }) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.cropper-content{ |
||||
|
display: flex; |
||||
|
display: -webkit-flex; |
||||
|
justify-content: flex-end; |
||||
|
.cropper-box{ |
||||
|
flex: 1; |
||||
|
width: 100%; |
||||
|
.cropper{ |
||||
|
width: auto; |
||||
|
height: 300px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.show-preview{ |
||||
|
flex: 1; |
||||
|
-webkit-flex: 1; |
||||
|
display: flex; |
||||
|
display: -webkit-flex; |
||||
|
justify-content: center; |
||||
|
.preview{ |
||||
|
overflow: hidden; |
||||
|
border:1px solid #67c23a; |
||||
|
background: #cccccc; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
.footer-btn{ |
||||
|
margin-top: 30px; |
||||
|
display: flex; |
||||
|
display: -webkit-flex; |
||||
|
justify-content: space-between; |
||||
|
.scope-btn{ |
||||
|
display: flex; |
||||
|
display: -webkit-flex; |
||||
|
justify-content: space-between; |
||||
|
padding-right: 10px; |
||||
|
} |
||||
|
.upload-cropper-btn{ |
||||
|
flex: 1; |
||||
|
-webkit-flex: 1; |
||||
|
display: flex; |
||||
|
display: -webkit-flex; |
||||
|
justify-content: flex-end; |
||||
|
} |
||||
|
.btn { |
||||
|
outline: none; |
||||
|
display: inline-block; |
||||
|
line-height: 1; |
||||
|
white-space: nowrap; |
||||
|
cursor: pointer; |
||||
|
-webkit-appearance: none; |
||||
|
text-align: center; |
||||
|
-webkit-box-sizing: border-box; |
||||
|
box-sizing: border-box; |
||||
|
outline: 0; |
||||
|
-webkit-transition: .1s; |
||||
|
transition: .1s; |
||||
|
font-weight: 500; |
||||
|
padding: 8px 15px; |
||||
|
font-size: 12px; |
||||
|
border-radius: 3px; |
||||
|
color: #fff; |
||||
|
background-color: #409EFF; |
||||
|
border-color: #409EFF; |
||||
|
margin-right: 10px; |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
|
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue