@@ -11,7 +11,17 @@ export function getModeList(sex) { | |||||
method: 'get' | method: 'get' | ||||
}) | }) | ||||
} | } | ||||
/** | |||||
* @description 获取模板列表(新) | |||||
* @param {number} sex | |||||
* @returns data | |||||
*/ | |||||
export function getModeList1(sex) { | |||||
return request({ | |||||
url: `/api/personPatch/list?sex=${sex}&pageNum=1&pageSize=10`, | |||||
method: 'get' | |||||
}) | |||||
} | |||||
/** | /** | ||||
* @description:根据id获取模板详情 | * @description:根据id获取模板详情 | ||||
* @param {number} id | * @param {number} id | ||||
@@ -0,0 +1,280 @@ | |||||
<template> | |||||
<div class="uploder"> | |||||
<div class="change-photo-setter"> | |||||
<van-uploader class="sett-item" :before-read="beforeRead"> | |||||
<div style="height: 100%"><img :src="ImgUrl" alt="" /></div> | |||||
<img src="https://img01.yzcdn.cn/vant/leaf.jpg" alt="" /> | |||||
</van-uploader> | |||||
</div> | |||||
<div class="uploadava"> | |||||
<van-popup | |||||
duration="0" | |||||
v-model="showCropper" | |||||
position="top" | |||||
:style="{ height: '100%' }" | |||||
> | |||||
<div class="cropper-container"> | |||||
<van-loading | |||||
v-show="loadingShow" | |||||
size="50" | |||||
color="#fff" | |||||
vertical | |||||
text-color="#fff" | |||||
>上传中...</van-loading | |||||
> | |||||
<vueCropper | |||||
ref="cropper" | |||||
:img="option.img" | |||||
:outputSize="option.outputSize" | |||||
:outputType="option.outputType" | |||||
:info="option.info" | |||||
:full="option.full" | |||||
:autoCropWidth="option.autoCropWidth" | |||||
:autoCropHeight="option.autoCropHeight" | |||||
:canMove="option.canMove" | |||||
:canMoveBox="option.canMoveBox" | |||||
:original="option.original" | |||||
:autoCrop="option.autoCrop" | |||||
:fixed="option.fixed" | |||||
:fixedNumber="option.fixedNumber" | |||||
:centerBox="option.centerBox" | |||||
:infoTrue="option.infoTrue" | |||||
:fixedBox="option.fixedBox" | |||||
:high="option.high" | |||||
:mode="option.mode" | |||||
/> | |||||
<van-nav-bar | |||||
left-text="取消" | |||||
right-text="确定" | |||||
@click-left="onClickLeft" | |||||
@click-right="onClickRight" | |||||
/> | |||||
</div> | |||||
</van-popup> | |||||
</div> | |||||
</div> | |||||
</template> | |||||
<script> | |||||
import { awsImgUpload } from '@/api/editModel' | |||||
import { Toast } from 'vant' | |||||
import { VueCropper } from 'vue-cropper' | |||||
export default { | |||||
name: 'uploadAva', | |||||
components: { | |||||
VueCropper | |||||
}, | |||||
props: { | |||||
showAta: { | |||||
default: false, | |||||
type: Boolean | |||||
}, | |||||
avaUrl: { | |||||
default: '', | |||||
type: String | |||||
} | |||||
}, | |||||
data() { | |||||
return { | |||||
ImgUrl: '', | |||||
show: true, // 上传类型的弹窗 | |||||
imageFileName: '', | |||||
showCropper: false, // 裁剪的弹窗 | |||||
option: { | |||||
img: '', | |||||
outputSize: 0.8, | |||||
info: false, // 裁剪框的大小信息 | |||||
outputType: 'jpeg', // 裁剪生成图片的格式 | |||||
canScale: true, // 图片是否允许滚轮缩放 | |||||
autoCrop: true, // 是否默认生成截图框 | |||||
autoCropWidth: window.innerWidth - 100 + 'px', // 默认生成截图框宽度 | |||||
autoCropHeight: window.innerWidth - 100 + 'px', // 默认生成截图框高度 | |||||
high: true, // 是否按照设备的dpr 输出等比例图片 | |||||
fixedBox: false, // 固定截图框大小 不允许改变 | |||||
fixed: true, // 是否开启截图框宽高固定比例 | |||||
fixedNumber: [1, 1], // 截图框的宽高比例 | |||||
full: true, // 是否输出原图比例的截图 | |||||
canMoveBox: true, // 截图框能否拖动 | |||||
original: false, // 上传图片按照原始比例渲染 | |||||
centerBox: true, // 截图框是否被限制在图片里面 | |||||
infoTrue: false, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高 | |||||
mode: '100% auto' // 图片默认渲染方式 | |||||
}, | |||||
loadingShow: false // 是否展示loading | |||||
} | |||||
}, | |||||
methods: { | |||||
beforeRead(file) { | |||||
console.log(file) | |||||
if (file.type !== 'image/jpeg' && file.type !== 'image/png') { | |||||
this.$toast('请上传 jpg/png 格式图片') | |||||
return false | |||||
} | |||||
let data = window.URL.createObjectURL(new Blob([file])) | |||||
this.option.img = data //给裁剪图片的路径 | |||||
this.showCropper = true | |||||
return false | |||||
}, | |||||
// 点击裁剪的选择 | |||||
onClickRight() { | |||||
let that = this | |||||
this.loadingShow = true | |||||
this.$refs.cropper.getCropBlob(async (data) => { | |||||
let formData = new FormData() | |||||
formData.append('file', data) | |||||
let file = formData.get('file') | |||||
// 转为 base64 | |||||
let reader = new FileReader() | |||||
reader.onload = async () => { | |||||
// base64结果 | |||||
that.ImgUrl = this.result | |||||
that.loading = false | |||||
} | |||||
reader.readAsDataURL(file) | |||||
// await that.toBase64(file) | |||||
console.log(that.ImgUrl, 'dasdasd') | |||||
// 发请求 | |||||
const AccessToken = localStorage.getItem('AccessToken') | |||||
that | |||||
.$axios({ | |||||
method: 'post', | |||||
url: `https://smapitest.malls.iformall.com/C/api/upload/awsImgUpload`, | |||||
headers: { | |||||
// 'Content-Type': 'application/json;charset=UTF-8', | |||||
'content-type': 'multipart/form-data', | |||||
token: AccessToken, | |||||
'Access-Control-Allow-Credentials': true | |||||
}, | |||||
data: { file: that.base64ToBinary(that.ImgUrl) } | |||||
}) | |||||
.then((res) => { | |||||
console.log(res) | |||||
console.log(that.ImgUrl) | |||||
console.log(that.base64ToBinary(that.ImgUrl)) | |||||
that.loadingShow = false | |||||
that.showCropper = false | |||||
Toast.success('上传成功') | |||||
}) | |||||
}) | |||||
}, | |||||
// 点击取消 | |||||
onClickLeft() { | |||||
this.loadingShow = false | |||||
this.showCropper = false | |||||
this.$parent.showPhotoUploader = false | |||||
}, | |||||
// 上传图片 | |||||
async pushImg(data) { | |||||
try { | |||||
const res = await awsImgUpload(data) | |||||
this.loadingShow = false | |||||
this.showCropper = false | |||||
Toast.success('上传成功') | |||||
} catch (error) { | |||||
console.log(error, 'error') | |||||
Toast.fail(error.message) | |||||
} | |||||
}, | |||||
//图片转base64,异步 | |||||
toBase64(file) { | |||||
let that = this | |||||
return new Promise((resolve, reject) => { | |||||
const reader = new FileReader() | |||||
reader.onload = () => { | |||||
// base64结果 | |||||
that.ImgUrl = this.result | |||||
that.loading = false | |||||
} | |||||
reader.onerror = reject | |||||
reader.readAsDataURL(file) | |||||
}) | |||||
}, | |||||
// base64 转二进制 | |||||
base64ToBinary(base64) { | |||||
console.log(base64) | |||||
const binaryString = window.atob(base64) | |||||
const binaryLength = binaryString.length | |||||
const bytes = new Uint8Array(binaryLength) | |||||
for (let i = 0; i < binaryLength; i++) { | |||||
bytes[i] = binaryString.charCodeAt(i) | |||||
} | |||||
return bytes | |||||
} | |||||
} | |||||
} | |||||
</script> | |||||
<style lang="scss" scoped> | |||||
// .uploder{ | |||||
// overflow: hidden; | |||||
// } | |||||
/deep/.cropper-view-box { | |||||
outline: 2px dashed #fff !important; | |||||
} | |||||
/deep/.crop-point { | |||||
background-color: auto !important; | |||||
} | |||||
/deep/.van-loading { | |||||
position: absolute; | |||||
// color: red; | |||||
z-index: 9999; | |||||
left: 50%; | |||||
top: 50%; | |||||
margin-left: -55px; | |||||
margin-top: -30px; | |||||
background: rgba(0, 0, 0, 0.3); | |||||
padding: 10px 30px; | |||||
border-radius: 25px; | |||||
} | |||||
.uploadava { | |||||
.update-avatar { | |||||
height: 100%; | |||||
text-align: center; | |||||
.update-avatar-line { | |||||
width: 100%; | |||||
height: 1px; | |||||
background-color: #979797; | |||||
} | |||||
.avatar-select-type { | |||||
background-color: #fff; | |||||
width: 346px; | |||||
border-radius: 12px; | |||||
padding-bottom: 4px; | |||||
.upload-avator { | |||||
padding: 14px; | |||||
} | |||||
} | |||||
p { | |||||
margin: 15px 0 30px; | |||||
background-color: #fff; | |||||
width: 346px; | |||||
border-radius: 12px; | |||||
padding: 15px 0 18px; | |||||
} | |||||
} | |||||
.cropper-container { | |||||
height: 94vh; | |||||
.van-nav-bar { | |||||
background-color: rgba(0, 0, 0, 0.87); | |||||
:global(.van-nav-bar__text) { | |||||
color: #fff; | |||||
// font-size: $font-size-normal-x; | |||||
} | |||||
:global(.van-nav-bar__text:nth-child(2)) { | |||||
color: #000; | |||||
font-weight: 500; | |||||
} | |||||
// :global(.van-icon) { | |||||
// color: red; | |||||
// } | |||||
} | |||||
} | |||||
.vue-cropper { | |||||
background: #000; | |||||
height: 100%; | |||||
padding-top: 46px; | |||||
box-sizing: border-box; | |||||
} | |||||
} | |||||
</style> |
@@ -0,0 +1,272 @@ | |||||
<template> | |||||
<div class="uploder"> | |||||
<div class="change-photo-setter"> | |||||
<van-uploader class="sett-item" :before-read="beforeRead"> | |||||
<div style="height: 100%"><img :src="ImgUrl" alt="" /></div> | |||||
<img src="https://img01.yzcdn.cn/vant/leaf.jpg" alt="" /> | |||||
</van-uploader> | |||||
</div> | |||||
<div class="uploadava"> | |||||
<van-popup | |||||
duration="0" | |||||
v-model="showCropper" | |||||
position="top" | |||||
:style="{ height: '100%' }" | |||||
> | |||||
<div class="cropper-container"> | |||||
<van-loading | |||||
v-show="loadingShow" | |||||
size="50" | |||||
color="#fff" | |||||
vertical | |||||
text-color="#fff" | |||||
>上传中...</van-loading | |||||
> | |||||
<vueCropper | |||||
ref="cropper" | |||||
:img="option.img" | |||||
:outputSize="option.outputSize" | |||||
:outputType="option.outputType" | |||||
:info="option.info" | |||||
:full="option.full" | |||||
:autoCropWidth="option.autoCropWidth" | |||||
:autoCropHeight="option.autoCropHeight" | |||||
:canMove="option.canMove" | |||||
:canMoveBox="option.canMoveBox" | |||||
:original="option.original" | |||||
:autoCrop="option.autoCrop" | |||||
:fixed="option.fixed" | |||||
:fixedNumber="option.fixedNumber" | |||||
:centerBox="option.centerBox" | |||||
:infoTrue="option.infoTrue" | |||||
:fixedBox="option.fixedBox" | |||||
:high="option.high" | |||||
:mode="option.mode" | |||||
/> | |||||
<van-nav-bar | |||||
left-text="取消" | |||||
right-text="选择" | |||||
@click-left="onClickLeft" | |||||
@click-right="onClickRight" | |||||
/> | |||||
</div> | |||||
</van-popup> | |||||
</div> | |||||
</div> | |||||
</template> | |||||
<script> | |||||
import { awsImgUpload } from '@/api/editModel' | |||||
import { Toast } from 'vant' | |||||
import { VueCropper } from 'vue-cropper' | |||||
export default { | |||||
name: 'uploadAva', | |||||
components: { | |||||
VueCropper | |||||
}, | |||||
props: { | |||||
showAta: { | |||||
default: false, | |||||
type: Boolean | |||||
}, | |||||
avaUrl: { | |||||
default: '', | |||||
type: String | |||||
} | |||||
}, | |||||
data() { | |||||
return { | |||||
ImgUrl: '', | |||||
show: true, // 上传类型的弹窗 | |||||
imageFileName: '', | |||||
showCropper: false, // 裁剪的弹窗 | |||||
option: { | |||||
img: '', | |||||
outputSize: 0.8, | |||||
info: false, // 裁剪框的大小信息 | |||||
outputType: 'jpeg', // 裁剪生成图片的格式 | |||||
canScale: true, // 图片是否允许滚轮缩放 | |||||
autoCrop: true, // 是否默认生成截图框 | |||||
autoCropWidth: window.innerWidth - 100 + 'px', // 默认生成截图框宽度 | |||||
autoCropHeight: window.innerWidth - 100 + 'px', // 默认生成截图框高度 | |||||
high: true, // 是否按照设备的dpr 输出等比例图片 | |||||
fixedBox: false, // 固定截图框大小 不允许改变 | |||||
fixed: true, // 是否开启截图框宽高固定比例 | |||||
fixedNumber: [1, 1], // 截图框的宽高比例 | |||||
full: true, // 是否输出原图比例的截图 | |||||
canMoveBox: true, // 截图框能否拖动 | |||||
original: false, // 上传图片按照原始比例渲染 | |||||
centerBox: true, // 截图框是否被限制在图片里面 | |||||
infoTrue: false, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高 | |||||
mode: '100% auto' // 图片默认渲染方式 | |||||
}, | |||||
loadingShow: false // 是否展示loading | |||||
} | |||||
}, | |||||
methods: { | |||||
beforeRead(file) { | |||||
console.log(file) | |||||
if (file.type !== 'image/jpeg' && file.type !== 'image/png') { | |||||
this.$toast('请上传 jpg/png 格式图片') | |||||
return false | |||||
} | |||||
// console.log(111, file) | |||||
this.showCropper = true | |||||
this.imageToBase64(file) | |||||
this.imageFileName = file.name | |||||
}, | |||||
imageToBase64(file) { | |||||
let reader = new FileReader() | |||||
console.log(reader) | |||||
reader.readAsDataURL(file) | |||||
reader.onload = () => { | |||||
this.option.img = reader.result | |||||
} | |||||
}, | |||||
onClickRight() { | |||||
// let formData = new FormData() | |||||
this.loadingShow = true | |||||
console.log(this.option) | |||||
// const AccessToken = localStorage.getItem('AccessToken') | |||||
// this.$axios({ | |||||
// method: 'post', | |||||
// url: `https://smapitest.malls.iformall.com/C/api/upload/awsImgUpload`, | |||||
// headers: { | |||||
// // 'Content-Type': 'application/json;charset=UTF-8', | |||||
// 'content-type': 'multipart/form-data', | |||||
// token: AccessToken, | |||||
// 'Access-Control-Allow-Credentials': true | |||||
// }, | |||||
// data: { file: this.option.img } | |||||
// }).then((res) => { | |||||
// console.log(res) | |||||
// this.loadingShow = false | |||||
// this.showCropper = false | |||||
// Toast.success('上传成功') | |||||
// }) | |||||
// this.pushImg({ file: this.option.img }) | |||||
// this.pushImg({ file: require('../assets/icon/icon-yes.png') }) | |||||
// this.$refs.cropper.getCropBlob((data) => { | |||||
console.log(this.$refs.cropper) | |||||
this.$refs.cropper.getCroppedCanvas((data) => { | |||||
this.ImgUrl = data | |||||
console.log(data, 'blob') | |||||
// let blob = window.URL.createObjectURL(data) | |||||
// console.log(blob) | |||||
// formData.append('File', data, this.imageFileName) | |||||
// formData.append('id', this.$store.getters.user.userId) | |||||
// console.log(formData.getAll('File')) | |||||
// console.log(data) | |||||
// this.pushImg({ file: blob }) | |||||
// uploadAva(formData).then((res) => { | |||||
// this.showCropper = false | |||||
// this.$emit('update:showAta', false) | |||||
// this.$emit('update:avaUrl', res.data) | |||||
// }) | |||||
}) | |||||
// this.$refs.cropper.getCroppedCanvas().toBlob((blob) => { | |||||
// const formData = new FormData() | |||||
// formData.append('file', blob, 'avatar.png') | |||||
// this.pushImg({ file: blob }) | |||||
// }) | |||||
}, | |||||
onClickLeft() { | |||||
this.loadingShow = false | |||||
this.showCropper = false | |||||
this.$parent.showPhotoUploader = false | |||||
}, | |||||
// 上传图片 | |||||
async pushImg(data) { | |||||
try { | |||||
const res = await awsImgUpload(data) | |||||
this.loadingShow = false | |||||
this.showCropper = false | |||||
Toast.success('上传成功') | |||||
} catch (error) { | |||||
console.log(error, 'error') | |||||
Toast.fail(error.message) | |||||
} | |||||
} | |||||
} | |||||
} | |||||
</script> | |||||
<style lang="scss" scoped> | |||||
// .uploder{ | |||||
// overflow: hidden; | |||||
// } | |||||
/deep/.cropper-view-box { | |||||
outline: 2px dashed #fff !important; | |||||
} | |||||
/deep/.crop-point { | |||||
background-color: auto !important; | |||||
} | |||||
/deep/.van-loading { | |||||
position: absolute; | |||||
// color: red; | |||||
z-index: 9999; | |||||
left: 50%; | |||||
top: 50%; | |||||
margin-left: -55px; | |||||
margin-top: -30px; | |||||
background: rgba(0, 0, 0, 0.3); | |||||
padding: 10px 30px; | |||||
border-radius: 25px; | |||||
} | |||||
.uploadava { | |||||
.update-avatar { | |||||
height: 100%; | |||||
text-align: center; | |||||
.update-avatar-line { | |||||
width: 100%; | |||||
height: 1px; | |||||
background-color: #979797; | |||||
} | |||||
.avatar-select-type { | |||||
background-color: #fff; | |||||
width: 346px; | |||||
border-radius: 12px; | |||||
padding-bottom: 4px; | |||||
.upload-avator { | |||||
padding: 14px; | |||||
} | |||||
} | |||||
p { | |||||
margin: 15px 0 30px; | |||||
background-color: #fff; | |||||
width: 346px; | |||||
border-radius: 12px; | |||||
padding: 15px 0 18px; | |||||
} | |||||
} | |||||
.cropper-container { | |||||
height: 94vh; | |||||
.van-nav-bar { | |||||
background-color: rgba(0, 0, 0, 0.87); | |||||
:global(.van-nav-bar__text) { | |||||
color: #fff; | |||||
// font-size: $font-size-normal-x; | |||||
} | |||||
:global(.van-nav-bar__text:nth-child(2)) { | |||||
color: #000; | |||||
font-weight: 500; | |||||
} | |||||
// :global(.van-icon) { | |||||
// color: red; | |||||
// } | |||||
} | |||||
} | |||||
.vue-cropper { | |||||
background: #000; | |||||
height: 100%; | |||||
padding-top: 46px; | |||||
box-sizing: border-box; | |||||
} | |||||
} | |||||
</style> |
@@ -2,7 +2,7 @@ | |||||
<div class="uploder"> | <div class="uploder"> | ||||
<div class="change-photo-setter"> | <div class="change-photo-setter"> | ||||
<van-uploader class="sett-item" :before-read="beforeRead"> | <van-uploader class="sett-item" :before-read="beforeRead"> | ||||
<div style="height: 100%"></div> | |||||
<div style="height: 100%"><img :src="ImgUrl" alt="" /></div> | |||||
<img src="https://img01.yzcdn.cn/vant/leaf.jpg" alt="" /> | <img src="https://img01.yzcdn.cn/vant/leaf.jpg" alt="" /> | ||||
</van-uploader> | </van-uploader> | ||||
</div> | </div> | ||||
@@ -45,7 +45,7 @@ | |||||
/> | /> | ||||
<van-nav-bar | <van-nav-bar | ||||
left-text="取消" | left-text="取消" | ||||
right-text="选择" | |||||
right-text="确定" | |||||
@click-left="onClickLeft" | @click-left="onClickLeft" | ||||
@click-right="onClickRight" | @click-right="onClickRight" | ||||
/> | /> | ||||
@@ -76,6 +76,7 @@ export default { | |||||
}, | }, | ||||
data() { | data() { | ||||
return { | return { | ||||
ImgUrl: '', | |||||
show: true, // 上传类型的弹窗 | show: true, // 上传类型的弹窗 | ||||
imageFileName: '', | imageFileName: '', | ||||
showCropper: false, // 裁剪的弹窗 | showCropper: false, // 裁剪的弹窗 | ||||
@@ -109,67 +110,55 @@ export default { | |||||
this.$toast('请上传 jpg/png 格式图片') | this.$toast('请上传 jpg/png 格式图片') | ||||
return false | return false | ||||
} | } | ||||
// console.log(111, file) | |||||
let data = window.URL.createObjectURL(new Blob([file])) | |||||
this.option.img = data //给裁剪图片的路径 | |||||
this.showCropper = true | this.showCropper = true | ||||
this.imageToBase64(file) | |||||
this.imageFileName = file.name | |||||
}, | |||||
imageToBase64(file) { | |||||
let reader = new FileReader() | |||||
console.log(reader) | |||||
reader.readAsDataURL(file) | |||||
reader.onload = () => { | |||||
this.option.img = reader.result | |||||
} | |||||
return false | |||||
}, | }, | ||||
// 点击裁剪的选择 | |||||
onClickRight() { | onClickRight() { | ||||
// let formData = new FormData() | |||||
let that = this | |||||
this.loadingShow = true | this.loadingShow = true | ||||
console.log(this.option) | |||||
const AccessToken = localStorage.getItem('AccessToken') | |||||
this.$axios({ | |||||
method: 'post', | |||||
url: `https://smapitest.malls.iformall.com/C/api/upload/awsImgUpload`, | |||||
headers: { | |||||
// 'Content-Type': 'application/json;charset=UTF-8', | |||||
'content-type': 'multipart/form-data', | |||||
token: AccessToken, | |||||
'Access-Control-Allow-Credentials': true | |||||
}, | |||||
data: { file: this.option.img } | |||||
}).then((res) => { | |||||
console.log(res) | |||||
this.loadingShow = false | |||||
this.showCropper = false | |||||
Toast.success('上传成功') | |||||
this.$refs.cropper.getCropBlob(async (data) => { | |||||
let formData = new FormData() | |||||
formData.append('file', data) | |||||
let file = formData.get('file') | |||||
// 转为 base64 | |||||
let reader = new FileReader() | |||||
const base64Data = await new Promise((resolve, reject) => { | |||||
reader.onload = () => { | |||||
resolve(reader.result) | |||||
} | |||||
reader.readAsDataURL(file) | |||||
}) | |||||
let imgBinary = await that.base64ToBinary(base64Data.substring(23)) | |||||
// base64结果 | |||||
that.ImgUrl = base64Data | |||||
that.loading = false | |||||
console.log(that.ImgUrl, 'dasdasd') | |||||
// 发请求 | |||||
const AccessToken = localStorage.getItem('AccessToken') | |||||
that | |||||
.$axios({ | |||||
method: 'post', | |||||
url: `https://smapitest.malls.iformall.com/C/api/upload/awsImgUpload`, | |||||
headers: { | |||||
'content-type': 'multipart/form-data', | |||||
token: AccessToken, | |||||
'Access-Control-Allow-Credentials': true | |||||
}, | |||||
data: formData | |||||
}) | |||||
.then((res) => { | |||||
console.log(res) | |||||
that.loadingShow = false | |||||
that.showCropper = false | |||||
Toast.success('上传成功') | |||||
}) | |||||
}) | }) | ||||
// this.pushImg({ file: this.option.img }) | |||||
// this.pushImg({ file: require('../assets/icon/icon-yes.png') }) | |||||
this.$refs.cropper.getCropBlob((data) => { | |||||
console.log(data, 'blob') | |||||
// let blob = window.URL.createObjectURL(data) | |||||
// console.log(blob) | |||||
// formData.append('File', data, this.imageFileName) | |||||
// formData.append('id', this.$store.getters.user.userId) | |||||
// console.log(formData.getAll('File')) | |||||
// console.log(data) | |||||
// this.pushImg({ file: blob }) | |||||
// uploadAva(formData).then((res) => { | |||||
// this.showCropper = false | |||||
// this.$emit('update:showAta', false) | |||||
// this.$emit('update:avaUrl', res.data) | |||||
// }) | |||||
}) | |||||
// this.$refs.cropper.getCroppedCanvas().toBlob((blob) => { | |||||
// const formData = new FormData() | |||||
// formData.append('file', blob, 'avatar.png') | |||||
// this.pushImg({ file: blob }) | |||||
// }) | |||||
}, | }, | ||||
// 点击取消 | |||||
onClickLeft() { | onClickLeft() { | ||||
this.loadingShow = false | this.loadingShow = false | ||||
this.showCropper = false | this.showCropper = false | ||||
@@ -186,6 +175,30 @@ export default { | |||||
console.log(error, 'error') | console.log(error, 'error') | ||||
Toast.fail(error.message) | Toast.fail(error.message) | ||||
} | } | ||||
}, | |||||
//图片转base64,异步 | |||||
toBase64(file) { | |||||
let that = this | |||||
return new Promise((resolve, reject) => { | |||||
const reader = new FileReader() | |||||
reader.onload = () => { | |||||
// base64结果 | |||||
that.ImgUrl = this.result | |||||
that.loading = false | |||||
} | |||||
reader.onerror = reject | |||||
reader.readAsDataURL(file) | |||||
}) | |||||
}, | |||||
// base64 转二进制 | |||||
base64ToBinary(base64) { | |||||
const binaryStr = window.atob(base64) | |||||
const len = binaryStr.length | |||||
const bytes = new Uint8Array(len) | |||||
for (let i = 0; i < len; ++i) { | |||||
bytes[i] = binaryStr.charCodeAt(i) | |||||
} | |||||
return bytes | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -68,6 +68,12 @@ const routes = [ | |||||
name: 'editPosition-chatgpt', | name: 'editPosition-chatgpt', | ||||
component: () => import("../views/model/editPosition-chatgpt"), | component: () => import("../views/model/editPosition-chatgpt"), | ||||
}, | }, | ||||
// 编辑位置new | |||||
{ | |||||
path: '/videoDownload', | |||||
name: 'videoDownload', | |||||
component: () => import("../views/videoDownload/videoDownload"), | |||||
}, | |||||
// 聊天首页new | // 聊天首页new | ||||
{ | { | ||||
path: '/chat', | path: '/chat', | ||||
@@ -297,7 +297,7 @@ export default { | |||||
codeInfo: '获取验证码', | codeInfo: '获取验证码', | ||||
inPage: false, | inPage: false, | ||||
codeImg: '', //随机验证码图片 | codeImg: '', //随机验证码图片 | ||||
loginType: 6, //显示页面字符 | |||||
loginType: 1, //显示页面字符 | |||||
showCodeImg: true, // 控制验证码的刷新 | showCodeImg: true, // 控制验证码的刷新 | ||||
// 短信验证码登录 | // 短信验证码登录 | ||||
form: { | form: { | ||||
@@ -16,21 +16,6 @@ | |||||
<van-tab v-for="item in tabList" :key="item" :title="item"> </van-tab> | <van-tab v-for="item in tabList" :key="item" :title="item"> </van-tab> | ||||
</van-tabs> | </van-tabs> | ||||
<!-- <div class="title">选择模板</div> --> | |||||
<!-- 老版吸顶tab栏 --> | |||||
<!-- <div class="typeOutSide"> | |||||
<div class="type"> | |||||
<div :class="type == 0 ? 'active' : ''" @click="chooseType(0)"> | |||||
全部模板 | |||||
</div> | |||||
<div :class="type == 2 ? 'active' : ''" @click="chooseType(2)"> | |||||
女性模板 | |||||
</div> | |||||
<div :class="type == 1 ? 'active' : ''" @click="chooseType(1)"> | |||||
男性模板 | |||||
</div> | |||||
</div> | |||||
</div> --> | |||||
<!-- 模板列表 --> | <!-- 模板列表 --> | ||||
<div class="choose"> | <div class="choose"> | ||||
<div class="modeList" v-masonry item-selector=".model" column-width="170"> | <div class="modeList" v-masonry item-selector=".model" column-width="170"> | ||||
@@ -43,9 +28,11 @@ | |||||
:key="index" | :key="index" | ||||
@click="selectModel(item.id)" | @click="selectModel(item.id)" | ||||
> | > | ||||
<img :src="item.coverImg" alt="" /> | |||||
<div class="modelName">{{ item.title }}</div> | |||||
<div class="setPaper">录入文案</div> | |||||
<div class="model-padding"> | |||||
<img :src="item.coverImg" alt="" /> | |||||
<div class="modelName">{{ item.title }}</div> | |||||
<div class="setPaper">录入文案</div> | |||||
</div> | |||||
</div> | </div> | ||||
<div class="alt" v-if="modeList.length == 0">暂无可用模板</div> | <div class="alt" v-if="modeList.length == 0">暂无可用模板</div> | ||||
</div> | </div> | ||||
@@ -62,6 +49,7 @@ import { Toast } from 'vant' | |||||
import { scrollToID } from '../../utils' | import { scrollToID } from '../../utils' | ||||
import { | import { | ||||
getModeList, | getModeList, | ||||
getModeList1, | |||||
getModeDetailById, | getModeDetailById, | ||||
saveOrUpdateUserVideo | saveOrUpdateUserVideo | ||||
} from '../../api/chooseModel' | } from '../../api/chooseModel' | ||||
@@ -122,7 +110,8 @@ export default { | |||||
async loadModeList(sex) { | async loadModeList(sex) { | ||||
try { | try { | ||||
sex = sex == 0 ? '' : sex | sex = sex == 0 ? '' : sex | ||||
const res = await getModeList(sex) | |||||
// const res = await getModeList(sex) | |||||
const res = await getModeList1(sex) | |||||
console.log(res, '获取模板列表') | console.log(res, '获取模板列表') | ||||
this.modeList = res.data.list | this.modeList = res.data.list | ||||
} catch (error) { | } catch (error) { | ||||
@@ -296,18 +285,15 @@ export default { | |||||
position: relative; | position: relative; | ||||
text-align: left; | text-align: left; | ||||
margin-bottom: 15px; | margin-bottom: 15px; | ||||
// border: 1px solid #00000028; | |||||
// padding: 8px; | |||||
// width: 154px; | |||||
max-width: 170px; | max-width: 170px; | ||||
// height: 305px; | |||||
max-height: 310px; | |||||
// transition: all 0.3s; | |||||
opacity: 0.9; | opacity: 0.9; | ||||
padding: 5px; | |||||
&-padding { | |||||
} | |||||
img { | img { | ||||
border-radius: 8px; | border-radius: 8px; | ||||
width: 100%; | width: 100%; | ||||
height: 273px; | |||||
// height: 273px; | |||||
} | } | ||||
.modelName { | .modelName { | ||||
margin-top: 10px; | margin-top: 10px; | ||||
@@ -58,11 +58,10 @@ export default { | |||||
{ | { | ||||
text: '小div1', | text: '小div1', | ||||
url: 'img/BG@2x.b0cf224b.png', | url: 'img/BG@2x.b0cf224b.png', | ||||
x: 300, | |||||
x: 300, // 相对左上角XY坐标 | |||||
y: 300, | y: 300, | ||||
scale: 1, | |||||
zIndex: 3, | |||||
num: 1 | |||||
scale: 1, //缩放 | |||||
zIndex: 3 //层级 | |||||
}, | }, | ||||
{ | { | ||||
text: '小div2', | text: '小div2', | ||||
@@ -39,25 +39,29 @@ | |||||
:key="item.id ? item.id : index" | :key="item.id ? item.id : index" | ||||
@click="goDetail(item)" | @click="goDetail(item)" | ||||
> | > | ||||
<img :src="index == 1 ? defaultImg : defaultImg1" alt="" /> | |||||
<!-- 渐变遮罩层 --> | |||||
<div class="waterFall-item-mask"> | |||||
<div>{{ item.title || '暂无' }}</div> | |||||
<div>视频时长:{{ formatSeconds(item.videoTime) }}</div> | |||||
<div>视频容量:{{ bytesToSize(item.videoSize) }}</div> | |||||
<div> | |||||
创建时间:{{ changeTime(item.createDate, 'YYYY-MM-DD hh:mm:ss') }} | |||||
<div class="waterFall-item-paddding"> | |||||
<img :src="index == 1 ? defaultImg : defaultImg1" alt="" /> | |||||
<!-- 渐变遮罩层 --> | |||||
<div class="waterFall-item-mask"> | |||||
<div>{{ item.title || '暂无' }}</div> | |||||
<div>视频时长:{{ formatSeconds(item.videoTime) }}</div> | |||||
<div>视频容量:{{ bytesToSize(item.videoSize) }}</div> | |||||
<div> | |||||
创建时间:{{ | |||||
changeTime(item.createDate, 'YYYY-MM-DD hh:mm:ss') | |||||
}} | |||||
</div> | |||||
</div> | |||||
<!-- 视频状态 草稿还是未完成还是失败 --> | |||||
<div class="waterFall-item-state"> | |||||
<div v-if="item.videoStatus == 0" class="cover">草稿</div> | |||||
<div v-if="item.videoStatus == 1" class="cover">视频生成中</div> | |||||
<div v-if="item.videoStatus == 3" class="cover">视频生成失败</div> | |||||
</div> | |||||
<!-- 删除 --> | |||||
<div class="waterFall-item-del" @click.stop="goDelete(item.id)"> | |||||
<img src="../../assets/icon/icon-trash.png" alt="" /> | |||||
</div> | </div> | ||||
</div> | |||||
<!-- 视频状态 草稿还是未完成还是失败 --> | |||||
<div class="waterFall-item-state"> | |||||
<div v-if="item.videoStatus == 0" class="cover">草稿</div> | |||||
<div v-if="item.videoStatus == 1" class="cover">视频生成中</div> | |||||
<div v-if="item.videoStatus == 3" class="cover">视频生成失败</div> | |||||
</div> | |||||
<!-- 删除 --> | |||||
<div class="waterFall-item-del" @click.stop="goDelete(item.id)"> | |||||
<img src="../../assets/icon/icon-trash.png" alt="" /> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -677,16 +681,21 @@ export default { | |||||
display: flex; | display: flex; | ||||
flex-wrap: wrap; | flex-wrap: wrap; | ||||
justify-content: space-between; | justify-content: space-between; | ||||
margin-right: -20px; | |||||
width: 100%; | width: 100%; | ||||
&-item { | &-item { | ||||
// max-width: 355px; //非瀑布流 | // max-width: 355px; //非瀑布流 | ||||
max-width: 170px; | max-width: 170px; | ||||
max-height: 300px; | max-height: 300px; | ||||
// background-color: red; | |||||
padding: 5px; | |||||
border-radius: 12px; | border-radius: 12px; | ||||
margin-bottom: 10px; | |||||
overflow: hidden; | overflow: hidden; | ||||
&-paddding { | |||||
position: relative; | |||||
border-radius: 12px; | |||||
overflow: hidden; | |||||
width: 160px; | |||||
// padding: 5px; | |||||
} | |||||
img { | img { | ||||
max-width: 100%; | max-width: 100%; | ||||
max-height: 100%; | max-height: 100%; | ||||
@@ -0,0 +1,243 @@ | |||||
<template> | |||||
<div :class="inPage ? 'page active' : 'page'"> | |||||
<div id="top"></div> | |||||
<HeadTop /> | |||||
<div class="content"> | |||||
<!-- 视频 --> | |||||
<div class="videoBox"> | |||||
<video | |||||
loop | |||||
download | |||||
ref="video" | |||||
:src="videoSrc" | |||||
@loadedmetadata="onVideoLoaded" | |||||
@click.prevent="() => {}" | |||||
@play="playing = true" | |||||
@pause="playing = false" | |||||
@timeupdate="onTimeUpdate" | |||||
></video> | |||||
<!-- 控制框 --> | |||||
<div class="videoBox-controls"> | |||||
<!-- 前进后退 --> | |||||
<div class="videoBox-controls-left"> | |||||
<div @click="seek(-10)"> | |||||
<i class="el-icon-refresh-left"></i> | |||||
</div> | |||||
<div @click="togglePlay"> | |||||
<i v-show="!this.playing" class="el-icon-video-play"></i> | |||||
<i v-show="this.playing" class="el-icon-video-pause"></i> | |||||
</div> | |||||
<div @click="seek(10)"> | |||||
<i class="el-icon-refresh-right"></i> | |||||
</div> | |||||
</div> | |||||
<!-- 进度条 --> | |||||
<div class="videoBox-controls-middle"> | |||||
<div class="time">{{ formatTime(currentTime) }}</div> | |||||
<van-slider | |||||
active-color="#aa91a5" | |||||
v-model="progress" | |||||
:max="totalTime" | |||||
:value="currentTime" | |||||
@change="onProgressChange" | |||||
></van-slider> | |||||
<div class="time">{{ formatTime(totalTime) }}</div> | |||||
</div> | |||||
<!-- 全屏 --> | |||||
<div class="videoBox-controls-right" @click="toggleScreen"> | |||||
<van-icon name="enlarge" /> | |||||
</div> | |||||
</div> | |||||
<!-- 下载按钮 --> | |||||
<a :href="videoSrc" download class="videoBox-download"> | |||||
<img src="../../assets/icon/icon-download.png" alt="" /> | |||||
</a> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</template> | |||||
<script> | |||||
import Vue from 'vue' | |||||
import { Toast } from 'vant' | |||||
import { mapState, mapActions } from 'vuex' | |||||
import HeadTop from './../../components/common/head.vue' | |||||
// 工具 | |||||
import { scrollToID } from '../../utils' | |||||
Vue.use(Toast) | |||||
export default { | |||||
components: { | |||||
HeadTop | |||||
}, | |||||
data() { | |||||
return { | |||||
inPage: false, | |||||
videoSrc: | |||||
'https://wenlian.wenzhou.gov.cn:8001//upload/video/%E3%80%8A%E7%93%AF%E8%B6%8A%E4%B9%8B%E5%8D%8E%E3%80%8B%E7%89%87%E8%8A%B11.mp4', | |||||
showControls: false, // 控制台显示隐藏 | |||||
playing: false, // 播放 | |||||
isLandscape: false, | |||||
progress: 0, | |||||
currentTime: 0, | |||||
totalTime: 0, | |||||
progressChanging: false | |||||
} | |||||
}, | |||||
computed: { | |||||
...mapState({ | |||||
characters: (state) => state.publicObj.characters | |||||
}) | |||||
}, | |||||
mounted() { | |||||
this.inPage = true | |||||
scrollToID('top') | |||||
this.$refs.video.addEventListener('timeupdate', this.onTimeUpdate) | |||||
this.$refs.video.addEventListener('ended', this.onVideoEnded) | |||||
screen.orientation.addEventListener('change', this.onOrientationChange) | |||||
}, | |||||
destroyed() { | |||||
this.$refs.video.removeEventListener('timeupdate', this.onTimeUpdate) | |||||
this.$refs.video.removeEventListener('ended', this.onVideoEnded) | |||||
screen.orientation.removeEventListener('change', this.onOrientationChange) | |||||
}, | |||||
methods: { | |||||
onVideoLoaded() { | |||||
this.totalTime = this.$refs.video.duration | |||||
}, | |||||
// onTimeUpdate() { | |||||
// if (!this.progressChanging) { | |||||
// this.currentTime = this.$refs.video.currentTime | |||||
// this.progress = this.currentTime | |||||
// } | |||||
// }, | |||||
onVideoEnded() { | |||||
this.playing = false | |||||
}, | |||||
// 播放&暂停 | |||||
togglePlay() { | |||||
this.playing = !this.playing | |||||
if (this.playing) { | |||||
this.$refs.video.play() | |||||
} else { | |||||
this.$refs.video.pause() | |||||
} | |||||
}, | |||||
// 横屏 | |||||
toggleScreen() { | |||||
if (this.isLandscape) { | |||||
screen.orientation.unlock() | |||||
} else { | |||||
screen.orientation.lock('landscape') | |||||
} | |||||
this.isLandscape = !this.isLandscape | |||||
}, | |||||
onOrientationChange() { | |||||
this.fullScreen = screen.orientation.type.includes('landscape') | |||||
}, | |||||
// 控制快进后退 | |||||
seek(seconds) { | |||||
const newTime = Math.max( | |||||
0, | |||||
Math.min(this.totalTime, this.currentTime + seconds) | |||||
) | |||||
this.$refs.video.currentTime = newTime | |||||
this.currentTime = newTime | |||||
}, | |||||
// 拖动滚动条 | |||||
onProgressChange() { | |||||
this.progressChanging = true | |||||
this.$refs.video.currentTime = this.progress | |||||
}, | |||||
//实时更新时间 | |||||
onTimeUpdate() { | |||||
this.currentTime = this.$refs.video.currentTime | |||||
this.progress = this.currentTime | |||||
}, | |||||
// 处理时间 | |||||
formatTime(time) { | |||||
const minutes = Math.floor(time / 60) | |||||
const seconds = Math.round(time % 60) | |||||
return `${minutes}:${seconds.toString().padStart(2, '0')}` | |||||
}, | |||||
...mapActions(['setCharacters']), | |||||
go(url) { | |||||
this.$router.push(url) | |||||
} | |||||
} | |||||
} | |||||
</script> | |||||
<style lang="scss" scoped> | |||||
.page { | |||||
width: 375px; | |||||
height: 100vh; | |||||
overflow-y: hidden; | |||||
} | |||||
.content { | |||||
width: 100%; | |||||
height: calc(100vh - 40px); | |||||
overflow: hidden; | |||||
} | |||||
.videoBox { | |||||
position: relative; | |||||
width: 100%; | |||||
height: 627px; | |||||
background-color: #f8f9f9; | |||||
video { | |||||
width: 100%; | |||||
height: 100%; | |||||
} | |||||
&-controls { | |||||
display: flex; | |||||
justify-content: space-between; | |||||
align-items: center; | |||||
padding: 6px 11px; | |||||
position: absolute; | |||||
left: 50%; | |||||
bottom: 27px; | |||||
transform: translateX(-50%); | |||||
width: calc(100% - 20px); | |||||
height: 26px; | |||||
background: rgba(67, 68, 71, 0.7); | |||||
border-radius: 9px; | |||||
color: #fff; | |||||
&-left { | |||||
display: flex; | |||||
justify-content: space-between; | |||||
align-items: center; | |||||
div { | |||||
padding: 0 8px; | |||||
} | |||||
i { | |||||
display: block; | |||||
width: 11px; | |||||
height: 11px; | |||||
color: #fff; | |||||
} | |||||
} | |||||
&-middle { | |||||
flex: 1; | |||||
display: flex; | |||||
justify-content: space-between; | |||||
align-items: center; | |||||
.time { | |||||
padding: 0 8px; | |||||
} | |||||
::v-deep .van-slider__button { | |||||
width: 5px; | |||||
height: 5px; | |||||
border-radius: 50%; | |||||
} | |||||
} | |||||
} | |||||
&-download { | |||||
position: absolute; | |||||
right: 10px; | |||||
top: 15px; | |||||
display: inline-block; | |||||
width: 24px; | |||||
height: 24px; | |||||
} | |||||
} | |||||
</style> |