@@ -19,6 +19,7 @@ | |||
"swiper": "^4.5.1", | |||
"vant": "^2.12.48", | |||
"vue": "^2.6.11", | |||
"vue-cropper": "^0.5.11", | |||
"vue-masonry": "^0.16.0", | |||
"vue-router": "^3.2.0", | |||
"vuex": "^3.4.0" | |||
@@ -10,8 +10,32 @@ export function getCodeByPhone(phone) { | |||
url: `/api/user/sendLoginPhoneCode?phone=${phone}`, | |||
method: 'get' | |||
}) | |||
} | |||
/** | |||
* @description 获取图形验证码 | |||
* @param {object} loginParams (phone,password) | |||
* @returns data | |||
*/ | |||
export function getCaptcha() { | |||
return request({ | |||
url: `/api/user/captcha.jpg`, | |||
method: 'get', | |||
}) | |||
} | |||
/** | |||
* @description 密码登录 | |||
* @param {object} loginParams (phone,password,code) | |||
* @returns data | |||
*/ | |||
export function doLogin(loginParams) { | |||
return request({ | |||
url: `/api/user/login`, | |||
method: 'post', | |||
data: loginParams | |||
}) | |||
} | |||
/** | |||
* @description 短信验证码登录 | |||
* @param {object} loginParams (phone,code) | |||
@@ -24,7 +48,42 @@ export function doLoginByPhone(loginParams) { | |||
data: loginParams | |||
}) | |||
} | |||
/**`/api/user/sendLoginPhoneCode?phone=${phone}` | |||
* @description 忘记密码第一步,根据图片验证码和手机号获取短信 | |||
* @param {object} loginParams (phone,code) | |||
* @returns data | |||
*/ | |||
export function doSendPhoneCode(data) { | |||
return request({ | |||
url: `/api/user/sendPhoneCode?phone=${data.phone}&code=${data.code}`, | |||
method: 'get', | |||
}) | |||
} | |||
/** | |||
* @description 修改密码 | |||
* @param {object} loginParams (phone,code,pwd) | |||
* @returns data | |||
*/ | |||
export function doUpdPass(loginParams) { | |||
return request({ | |||
url: `/api/user/updPass`, | |||
method: 'get', | |||
data: loginParams | |||
}) | |||
} | |||
/** | |||
* @description 注册 | |||
* @param {object} loginParams (phone,password) | |||
* @returns data | |||
*/ | |||
export function doRegisterByPhone(loginParams) { | |||
return request({ | |||
url: `/api/user/doRegisterByPhone`, | |||
method: 'post', | |||
data: loginParams | |||
}) | |||
} | |||
/** | |||
* @description 查询用户邀请码状态 | |||
* @returns data | |||
@@ -58,4 +117,11 @@ export function doLoginOut() { | |||
url: `/api/user/loginout`, | |||
method: 'get', | |||
}) | |||
} | |||
} | |||
/** | |||
* @description 获取图形验证码 | |||
* @returns data | |||
*/ | |||
export const codeImg = | |||
'https://smapitest.malls.iformall.com/C/api/user/captcha.jpg' |
@@ -21,4 +21,9 @@ img { | |||
} | |||
.bgcWhite { | |||
background: #fff!important; | |||
} | |||
p { | |||
overflow: hidden; | |||
white-space: nowrap; | |||
text-overflow: ellipsis; | |||
} |
@@ -35,6 +35,7 @@ request.interceptors.response.use( | |||
let code = response.data.code | |||
// 当token过期或损坏时 | |||
if (code == 1052) { | |||
// if (1==1) { | |||
router.push("/login"); | |||
Toast.fail("登录过期,请重新登录!"); | |||
return | |||
@@ -51,6 +52,7 @@ request.interceptors.response.use( | |||
// 其他错误 | |||
} else { | |||
Toast.fail(error.message) | |||
return Promise.reject(response.data) | |||
} | |||
} else { | |||
@@ -0,0 +1,273 @@ | |||
<template> | |||
<div class="uploder"> | |||
<div class="change-photo-setter"> | |||
<van-uploader | |||
class="sett-item" | |||
:before-read="beforeRead" | |||
accept="image/*" | |||
> | |||
<div>照片图库</div> | |||
<img src="https://img01.yzcdn.cn/vant/leaf.jpg" alt="" /> | |||
</van-uploader> | |||
<van-uploader | |||
class="sett-item" | |||
:before-read="beforeRead" | |||
capture="camera" | |||
> | |||
<div>拍照</div> | |||
<img src="https://img01.yzcdn.cn/vant/leaf.jpg" alt="" /> | |||
</van-uploader> | |||
<van-uploader class="sett-item" :before-read="beforeRead"> | |||
<div>选取文件</div> | |||
<img src="https://img01.yzcdn.cn/vant/leaf.jpg" alt="" /> | |||
</van-uploader> | |||
</div> | |||
<div class="uploadava"> | |||
<!-- <van-overlay :show="show" @click="$emit('update:showAta', false),show = false"> | |||
<div class="update-avatar"> | |||
<ul class="avatar-select-type" @click.stop> | |||
<van-uploader :before-read="beforeRead" capture="camera"> | |||
<li class="select-type-photo upload-avator">拍摄</li> | |||
</van-uploader> | |||
<li class="update-avatar-line"></li> | |||
<van-uploader :before-read="beforeRead"> | |||
<li class="select-type-album upload-avator">从手机相册选择</li> | |||
</van-uploader> | |||
</ul> | |||
<p @click.stop="show = false,$emit('update:showAta', false)">取消</p> | |||
</div> | |||
</van-overlay> --> | |||
<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="getCropBlob" | |||
/> | |||
</div> | |||
</van-popup> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import { VueCropper } from 'vue-cropper' | |||
export default { | |||
name: 'uploadAva', | |||
components: { | |||
VueCropper | |||
}, | |||
props: { | |||
showAta: { | |||
default: false, | |||
type: Boolean | |||
}, | |||
avaUrl: { | |||
default: '', | |||
type: String | |||
} | |||
}, | |||
data() { | |||
return { | |||
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) { | |||
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 | |||
} | |||
}, | |||
getCropBlob() { | |||
// let formData = new FormData() | |||
this.loadingShow = true | |||
console.log(this.option) | |||
this.$refs.cropper.getCropBlob((data) => { | |||
// formData.append('headFile', data, this.imageFileName) | |||
// formData.append('id', this.$store.getters.user.userId) | |||
console.log(data) | |||
// uploadAva(formData).then((res) => { | |||
// this.showCropper = false | |||
this.$emit('update:showAta', false) | |||
// this.$emit('update:avaUrl', res.data) | |||
// }) | |||
}) | |||
}, | |||
onClickLeft() { | |||
this.loadingShow = false | |||
this.showCropper = false | |||
this.$parent.showPhotoUploader = false | |||
} | |||
} | |||
} | |||
</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; | |||
} | |||
.change-photo-setter { | |||
width: 400px; | |||
background: #fff; | |||
position: absolute; | |||
top: 11%; | |||
left: 40px; | |||
z-index: 300; | |||
.sett-item { | |||
width: 100%; | |||
} | |||
/deep/.van-uploader__input-wrapper { | |||
width: 100%; | |||
display: flex; | |||
flex-direction: row; | |||
align-items: center; | |||
justify-content: space-between; | |||
padding: 15px; | |||
img { | |||
width: 40px; | |||
height: 40px; | |||
display: block; | |||
} | |||
} | |||
.sett-item:first-child { | |||
border-bottom: 2px solid #ccc; | |||
} | |||
} | |||
.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> |
@@ -20,32 +20,44 @@ | |||
<!-- 密码 --> | |||
<el-form-item class="code" prop="password"> | |||
<el-input | |||
type="password" | |||
maxlength="10" | |||
clearable | |||
v-model="form.code" | |||
v-model="form.password" | |||
placeholder="请输入密码" | |||
></el-input> | |||
</el-form-item> | |||
<!-- 随机验证码 --> | |||
<el-form-item class="yzCode" prop="yzCode"> | |||
<el-form-item class="yzCode" prop="yzCode"> | |||
<el-col :span="12"> | |||
<el-input v-model="form.code" placeholder="请输入验证码"></el-input> | |||
<el-input | |||
v-model="form.yzCode" | |||
placeholder="请输入验证码" | |||
></el-input> | |||
</el-col> | |||
<el-col :span="9"> | |||
<!-- <div class="yzmImg" v-html="codeImg"></div> --> | |||
<img class="yzmImg" :src="codeImg" alt="" /> | |||
</el-col> | |||
<el-col :span="2"> | |||
<i class="el-icon-refresh-right shuaxin"></i> | |||
</el-col> | |||
</el-form-item> | |||
<!-- 短信登录和忘记密码 --> | |||
<div class="morePage greenColor"> | |||
<span @click="loginType=2">短信登录</span> | |||
<span @click="loginType=3">忘记密码?</span> | |||
<span @click="loginType = 2">短信登录</span> | |||
<span @click="loginType = 3">忘记密码?</span> | |||
</div> | |||
<!-- 登录 --> | |||
<el-form-item> | |||
<el-button class="submitBtn" @click="loginByPhoneCode" | |||
>登录/注册</el-button> | |||
>登录/注册</el-button | |||
> | |||
</el-form-item> | |||
<!-- 没有账号 --> | |||
<div> | |||
<span>没有账号?</span> | |||
<span class="greenColor" @click="loginType=5">立即注册</span> | |||
<span class="greenColor" @click="loginType = 5">立即注册</span> | |||
</div> | |||
</el-form> | |||
</div> | |||
@@ -61,30 +73,41 @@ | |||
></el-input> | |||
</el-form-item> | |||
<!-- 短信验证码 --> | |||
<el-form-item class="code" prop="phoneCode"> | |||
<el-form-item class="code" prop="code"> | |||
<el-input | |||
maxlength="10" | |||
clearable | |||
v-model="form.code" | |||
placeholder="请输入短信验证码" | |||
> | |||
<div v-if="!countdownState" @click="triggerCountdown" class="greenColor" slot="suffix" type="primary">获取验证码</div> | |||
<div v-else slot="suffix" type="primary">验证码已发送{{ countNum }}s</div> | |||
</el-input> | |||
<div | |||
v-if="!countdownState" | |||
@click="triggerCountdown" | |||
class="greenColor" | |||
slot="suffix" | |||
type="primary" | |||
> | |||
获取验证码 | |||
</div> | |||
<div v-else slot="suffix" type="primary"> | |||
验证码已发送{{ countNum }}s | |||
</div> | |||
</el-input> | |||
</el-form-item> | |||
<!-- 短信登录和忘记密码 --> | |||
<div class="morePage greenColor inBoxEnd"> | |||
<span @click="loginType=1">账号登录</span> | |||
<span @click="loginType = 1">账号登录</span> | |||
</div> | |||
<!-- 登录 --> | |||
<el-form-item> | |||
<el-button class="submitBtn" @click="loginByPhoneCode" | |||
>登录</el-button> | |||
>登录</el-button | |||
> | |||
</el-form-item> | |||
<!-- 没有账号 --> | |||
<div> | |||
<span>没有账号?</span> | |||
<span class="greenColor" @click="loginType=5">立即注册</span> | |||
<span class="greenColor" @click="loginType = 5">立即注册</span> | |||
</div> | |||
</el-form> | |||
</div> | |||
@@ -102,19 +125,22 @@ | |||
<!-- 随机验证码 --> | |||
<el-form-item class="code" prop="yzCode"> | |||
<el-col :span="12"> | |||
<el-input | |||
maxlength="10" | |||
clearable | |||
v-model="form.code" | |||
v-model="form.yzCode" | |||
placeholder="请输入验证码" | |||
></el-input> | |||
</el-col> | |||
</el-form-item> | |||
<div class="morePage greenColor"> | |||
<span @click="loginType = 1">账户登录</span> | |||
</div> | |||
<!-- 登录 --> | |||
<el-form-item> | |||
<el-button class="submitBtn" @click="loginByPhoneCode" | |||
>获取短信验证码</el-button> | |||
>获取短信验证码</el-button | |||
> | |||
</el-form-item> | |||
</el-form> | |||
</div> | |||
@@ -123,18 +149,19 @@ | |||
<div class="loginBox" v-if="loginType == 4"> | |||
<el-form ref="form" :rules="rules" :model="form"> | |||
<!-- 短信验证码 --> | |||
<el-form-item class="phone" prop="phoneCode"> | |||
<el-form-item class="phone" prop="code1"> | |||
<el-input | |||
v-model="form.phone" | |||
v-model="form.code1" | |||
placeholder="请输入短信验证码" | |||
></el-input> | |||
</el-form-item> | |||
<!-- 新密码1 --> | |||
<el-form-item class="code" prop="newPassword1"> | |||
<el-input | |||
type="password" | |||
maxlength="10" | |||
clearable | |||
v-model="form.code" | |||
v-model="form.newPassword1" | |||
placeholder="请输入您的新密码" | |||
> | |||
</el-input> | |||
@@ -142,19 +169,23 @@ | |||
<!-- 新密码2 --> | |||
<el-form-item class="code" prop="newPassword2"> | |||
<el-input | |||
type="password" | |||
maxlength="10" | |||
clearable | |||
v-model="form.code" | |||
v-model="form.newPassword2" | |||
placeholder="请再次确认您的新密码" | |||
> | |||
</el-input> | |||
</el-form-item> | |||
<div class="morePage greenColor"> | |||
<span @click="loginType = 1">账户登录</span> | |||
</div> | |||
<!-- 登录 --> | |||
<el-form-item> | |||
<el-button class="submitBtn" @click="loginByPhoneCode" | |||
>保存密码</el-button> | |||
>保存密码</el-button | |||
> | |||
</el-form-item> | |||
</el-form> | |||
</div> | |||
@@ -171,9 +202,10 @@ | |||
<!-- 新密码1 --> | |||
<el-form-item class="code" prop="newPassword1"> | |||
<el-input | |||
type="password" | |||
maxlength="10" | |||
clearable | |||
v-model="form.code" | |||
v-model="form.newPassword1" | |||
placeholder="请输入您的密码" | |||
> | |||
</el-input> | |||
@@ -181,19 +213,23 @@ | |||
<!-- 新密码2 --> | |||
<el-form-item class="code" prop="newPassword2"> | |||
<el-input | |||
type="password" | |||
maxlength="10" | |||
clearable | |||
v-model="form.code" | |||
v-model="form.newPassword2" | |||
placeholder="请再次确认您的密码" | |||
> | |||
</el-input> | |||
</el-form-item> | |||
<div class="morePage greenColor"> | |||
<span @click="loginType = 1">账户登录</span> | |||
</div> | |||
<!-- 注册 --> | |||
<el-form-item> | |||
<el-button class="submitBtn" @click="loginByPhoneCode" | |||
>注册</el-button> | |||
>注册</el-button | |||
> | |||
</el-form-item> | |||
</el-form> | |||
</div> | |||
<!-- 弹出层 --> | |||
@@ -210,31 +246,39 @@ import { mapState, mapActions } from 'vuex' | |||
import { scrollToID } from '../../utils' | |||
// 接口 | |||
import { | |||
doLogin, | |||
getCodeByPhone, | |||
doRegisterByPhone, | |||
doLoginByPhone, | |||
doSendPhoneCode, | |||
doUpdPass, | |||
getCaptcha, | |||
doFindInviteCode, | |||
doUpdateInviteCode | |||
doUpdateInviteCode, | |||
codeImg | |||
} from '../../api/login' | |||
Vue.use(Toast) | |||
export default { | |||
data() { | |||
return { | |||
showDialog:false,//弹出层状态 | |||
countNum: 60,// 倒计时 | |||
countdownState:false,//倒计时状态 | |||
showDialog: false, //弹出层状态 | |||
countNum: 60, // 倒计时 | |||
countdownState: false, //倒计时状态 | |||
codeInfo: '获取验证码', | |||
inPage: false, | |||
loginType: 1, //显示页面字符 | |||
codeImg: '', //随机验证码图片 | |||
loginType: 1, //显示页面字符 | |||
// 短信验证码登录 | |||
form: { | |||
phone: '', | |||
password: '', | |||
newPassword1:'', | |||
newPassword2:'', | |||
phoneCode:'', | |||
code: '', | |||
yzCode: '' | |||
phone: '', // 手机号 | |||
password: '', // 密码 | |||
newPassword1: '', // 新密码1 | |||
newPassword2: '', // 新密码2 | |||
phoneCode: '', // | |||
code: '', // 短信验证码 | |||
code1: '', // 忘记密码的短信验证码 | |||
yzCode: '' // 随机图片验证码 | |||
}, | |||
rules: { | |||
phone: [ | |||
@@ -283,7 +327,7 @@ export default { | |||
] | |||
}, | |||
// 短信登录 | |||
// 忘记密码 | |||
// 重设密码 | |||
// 注册 | |||
@@ -307,21 +351,21 @@ export default { | |||
//调用接口 | |||
this.getCode() | |||
// 切换文字 | |||
this.countdownState = !this.countdownState; | |||
this.countdownState = !this.countdownState | |||
// 定时器 | |||
let intervalBtn = setInterval(() => { | |||
// 倒数自减 | |||
this.countNum--; | |||
if(this.countNum < 0) { | |||
// 清除定时器 | |||
clearInterval(intervalBtn) | |||
// 更改状态 | |||
this.countdownState =! this.countdownState; | |||
// 重置倒计时状态 | |||
this.countNum = 60; | |||
}; | |||
// 倒计时 | |||
}, 1000); | |||
// 倒数自减 | |||
this.countNum-- | |||
if (this.countNum < 0) { | |||
// 清除定时器 | |||
clearInterval(intervalBtn) | |||
// 更改状态 | |||
this.countdownState = !this.countdownState | |||
// 重置倒计时状态 | |||
this.countNum = 60 | |||
} | |||
// 倒计时 | |||
}, 1000) | |||
}, | |||
go(url) { | |||
this.$router.push(url) | |||
@@ -350,16 +394,81 @@ export default { | |||
this.getPhoneCode(phoneValue) | |||
} | |||
}, | |||
// 获取随机验证码图片 | |||
getCodeImg() { | |||
this.codeImg = codeImg | |||
}, | |||
// 手机验证码登录 | |||
// 点击登录 | |||
loginByPhoneCode() { | |||
const data = { | |||
phone: this.form.phone, | |||
code: this.form.code | |||
// 密码登录 | |||
if (this.loginType == 1) { | |||
const data = { | |||
phone: this.form.phone, | |||
password: this.form.password, | |||
yzCode: this.form.yzCode | |||
} | |||
this.LoginByPhone(data) | |||
return | |||
} | |||
// 手机验证码登录 | |||
if (this.loginType == 2) { | |||
const data = { | |||
phone: this.form.phone, | |||
code: this.form.code | |||
} | |||
this.LoginByPhone(data) | |||
return | |||
} | |||
if (this.loginType == 3) { | |||
const data = { | |||
phone: this.form.phone, | |||
code: this.form.yzCode | |||
} | |||
this.sendPhoneCode(data) | |||
return | |||
} | |||
if (this.loginType == 4) { | |||
const data = { | |||
phone: this.form.phone, | |||
code: this.form.code1, | |||
pwd: this.form.newPassword1 | |||
} | |||
this.updPass(data) | |||
return | |||
} | |||
if (this.loginType == 5) { | |||
const data = { | |||
phone: this.form.phone, | |||
newPassword1: this.form.newPassword1, | |||
newPassword2: this.form.newPassword2 | |||
} | |||
this.LoginByPhone(data) | |||
return | |||
} | |||
}, | |||
// 忘记密码第一步,根据图片验证码和手机号获取短信 | |||
async sendPhoneCode(data) { | |||
try { | |||
const res = await doSendPhoneCode(data) | |||
console.log(res) | |||
this.loginType = 4 | |||
} catch (error) { | |||
console.log(error, 'error') | |||
Toast.fail(error.message) | |||
} | |||
}, | |||
// 忘记密码第二部,提交验证码和新密码 | |||
async updPass(data) { | |||
try { | |||
const res = await doUpdPass(data) | |||
console.log(res) | |||
this.loginType = 1 | |||
} catch (error) { | |||
console.log(error, 'error') | |||
Toast.fail(error.message) | |||
} | |||
this.LoginByPhone(data) | |||
}, | |||
// 提交邀请码 | |||
submitInviteCode() { | |||
const data = { | |||
@@ -395,7 +504,12 @@ export default { | |||
*/ | |||
async LoginByPhone(loginParams) { | |||
try { | |||
const res = await doLoginByPhone(loginParams) | |||
if (this.loginType == 1) { | |||
const res = await doLogin(loginParams) | |||
} | |||
if (this.loginType == 2) { | |||
const res = await doLoginByPhone(loginParams) | |||
} | |||
console.log(res, '登录数据') | |||
const token = res.data.token | |||
// 将token置入本地存储 | |||
@@ -428,7 +542,12 @@ export default { | |||
Toast.fail(error.message) | |||
} | |||
}, | |||
/** | |||
* @description:查询用户邀请码状态 | |||
*/ | |||
async checkInviteCode() { | |||
this.src = '/api/captcha.jpg?t=' + Date() | |||
}, | |||
/** | |||
* @description:更新邀请码 | |||
*/ | |||
@@ -448,6 +567,7 @@ export default { | |||
// 手机号记忆回填 | |||
const phoneValue = localStorage.getItem('phoneValue') | |||
this.form.phone = phoneValue ? phoneValue : '' | |||
this.getCodeImg() | |||
}, | |||
mounted() { | |||
this.inPage = true | |||
@@ -457,6 +577,17 @@ export default { | |||
</script> | |||
<style lang="scss" scoped> | |||
.shuaxin { | |||
margin-left: 10px; | |||
font-size: 25px; | |||
line-height: 40px; | |||
color: rgb(96, 208, 201); | |||
} | |||
.yzmImg { | |||
margin-left: 10px; | |||
height: 40px; | |||
width: 100%; | |||
} | |||
.greenColor { | |||
color: #5ed5c8; | |||
} | |||
@@ -494,8 +625,8 @@ export default { | |||
margin-bottom: 40px; | |||
} | |||
.inBoxEnd { | |||
display: flex; | |||
justify-content: end !important; | |||
display: flex; | |||
justify-content: end !important; | |||
} | |||
.phone { | |||
position: relative; | |||
@@ -587,6 +718,6 @@ export default { | |||
background-color: #f6f6f6; | |||
} | |||
::v-deep .el-form-item { | |||
margin-bottom: 25px; | |||
margin-bottom: 25px; | |||
} | |||
</style> |
@@ -33,7 +33,7 @@ | |||
</div> --> | |||
<!-- 模板列表 --> | |||
<div class="choose"> | |||
<div class="modeList" v-masonry item-selector=".model" column-width="175"> | |||
<div class="modeList" v-masonry item-selector=".model" column-width="170"> | |||
<div | |||
v-masonry-tile | |||
class="model" | |||
@@ -277,7 +277,6 @@ export default { | |||
} | |||
} | |||
} | |||
.choose { | |||
padding-top: 20px; | |||
margin-bottom: 40px; | |||
@@ -289,7 +288,7 @@ export default { | |||
flex-wrap: wrap; | |||
// margin: auto; | |||
// padding: 0 23px; | |||
padding-left: 20px; | |||
padding-left: 15px; | |||
width: 100%; | |||
margin-right: -20px; | |||
@@ -1,93 +1,280 @@ | |||
<template> | |||
<div | |||
class="image-container" | |||
ref="container" | |||
@touchstart="onTouchStart" | |||
@touchmove="onTouchMove" | |||
@touchend="onTouchEnd" | |||
> | |||
<img | |||
:src="imageUrl" | |||
ref="image" | |||
:style="{ | |||
transform: | |||
'scale(' + scale + ') translate(' + offsetX + 'px, ' + offsetY + 'px)' | |||
}" | |||
/> | |||
<div class="uploder"> | |||
<div class="change-photo-setter"> | |||
<van-uploader | |||
class="sett-item" | |||
:before-read="beforeRead" | |||
accept="image/*" | |||
> | |||
<div>照片图库</div> | |||
<img src="https://img01.yzcdn.cn/vant/leaf.jpg" alt="" /> | |||
</van-uploader> | |||
<van-uploader | |||
class="sett-item" | |||
:before-read="beforeRead" | |||
capture="camera" | |||
> | |||
<div>拍照</div> | |||
<img src="https://img01.yzcdn.cn/vant/leaf.jpg" alt="" /> | |||
</van-uploader> | |||
<van-uploader class="sett-item" :before-read="beforeRead"> | |||
<div>选取文件</div> | |||
<img src="https://img01.yzcdn.cn/vant/leaf.jpg" alt="" /> | |||
</van-uploader> | |||
</div> | |||
<div class="uploadava"> | |||
<!-- <van-overlay :show="show" @click="$emit('update:showAta', false),show = false"> | |||
<div class="update-avatar"> | |||
<ul class="avatar-select-type" @click.stop> | |||
<van-uploader :before-read="beforeRead" capture="camera"> | |||
<li class="select-type-photo upload-avator">拍摄</li> | |||
</van-uploader> | |||
<li class="update-avatar-line"></li> | |||
<van-uploader :before-read="beforeRead"> | |||
<li class="select-type-album upload-avator">从手机相册选择</li> | |||
</van-uploader> | |||
</ul> | |||
<p @click.stop="show = false,$emit('update:showAta', false)">取消</p> | |||
</div> | |||
</van-overlay> --> | |||
<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="getCropBlob" | |||
/> | |||
</div> | |||
</van-popup> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import { VueCropper } from 'vue-cropper' | |||
export default { | |||
name: 'uploadAva', | |||
components: { | |||
VueCropper | |||
}, | |||
props: { | |||
showAta: { | |||
default: false, | |||
type: Boolean | |||
}, | |||
avaUrl: { | |||
default: '', | |||
type: String | |||
} | |||
}, | |||
data() { | |||
return { | |||
imageUrl: 'https://picsum.photos/600/400', | |||
lastX: 0, | |||
lastY: 0, | |||
isDragging: false, | |||
startX: 0, | |||
startY: 0, | |||
scale: 1, | |||
lastScale: 1, | |||
offsetX: 0, | |||
offsetY: 0 | |||
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: { | |||
onTouchStart(event) { | |||
if (event.touches.length === 2) { | |||
this.lastX = (event.touches[0].clientX + event.touches[1].clientX) / 2 | |||
this.lastY = (event.touches[0].clientY + event.touches[1].clientY) / 2 | |||
this.lastScale = this.scale | |||
this.isDragging = false | |||
} else if (event.touches.length === 1) { | |||
this.startX = event.touches[0].clientX | |||
this.startY = event.touches[0].clientY | |||
this.isDragging = true | |||
// 点击上传按钮 | |||
beforeRead(file) { | |||
console.log(file, '111') | |||
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 | |||
}, | |||
onTouchMove(event) { | |||
if (event.touches.length === 2) { | |||
const x = (event.touches[0].clientX + event.touches[1].clientX) / 2 | |||
const y = (event.touches[0].clientY + event.touches[1].clientY) / 2 | |||
const deltaX = x - this.lastX | |||
const deltaY = y - this.lastY | |||
const scale = | |||
(event.touches[0].clientX - event.touches[1].clientX) / | |||
(this.lastX - this.lastY) | |||
this.scale = this.lastScale * scale | |||
this.offsetX += deltaX | |||
this.offsetY += deltaY | |||
this.lastX = x | |||
this.lastY = y | |||
} else if (event.touches.length === 1 && this.isDragging) { | |||
const deltaX = event.touches[0].clientX - this.startX | |||
const deltaY = event.touches[0].clientY - this.startY | |||
this.offsetX += deltaX | |||
this.offsetY += deltaY | |||
this.startX = event.touches[0].clientX | |||
this.startY = event.touches[0].clientY | |||
// 转64 | |||
imageToBase64(file) { | |||
let reader = new FileReader() | |||
console.log(reader) | |||
reader.readAsDataURL(file) | |||
reader.onload = () => { | |||
console.log(reader.result, '222') | |||
this.option.img = reader.result | |||
} | |||
}, | |||
onTouchEnd(event) { | |||
this.isDragging = false | |||
// 处理图片, | |||
getCropBlob() { | |||
// let formData = new FormData() | |||
this.loadingShow = true | |||
console.log(this.option) | |||
console.log(this.$refs.cropper) | |||
// cropper插件上的getCropBlob()方法,data就是截图的图片 | |||
this.$refs.cropper.getCropBlob((data) => { | |||
// formData.append('headFile', data, this.imageFileName) | |||
// formData.append('id', this.$store.getters.user.userId) | |||
console.log(data) | |||
// uploadAva(formData).then((res) => { | |||
// this.showCropper = false | |||
this.$emit('update:showAta', false) | |||
// this.$emit('update:avaUrl', res.data) | |||
// }) | |||
}) | |||
}, | |||
onClickLeft() { | |||
this.loadingShow = false | |||
this.showCropper = false | |||
this.$parent.showPhotoUploader = false | |||
} | |||
} | |||
} | |||
</script> | |||
<style> | |||
.image-container { | |||
width: 100%; | |||
height: 100%; | |||
overflow: hidden; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
<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; | |||
} | |||
.change-photo-setter { | |||
width: 400px; | |||
background: #fff; | |||
position: absolute; | |||
top: 11%; | |||
left: 40px; | |||
z-index: 300; | |||
.sett-item { | |||
width: 100%; | |||
} | |||
/deep/.van-uploader__input-wrapper { | |||
width: 100%; | |||
display: flex; | |||
flex-direction: row; | |||
align-items: center; | |||
justify-content: space-between; | |||
padding: 15px; | |||
img { | |||
width: 40px; | |||
height: 40px; | |||
display: block; | |||
} | |||
} | |||
.sett-item:first-child { | |||
border-bottom: 2px solid #ccc; | |||
} | |||
} | |||
img { | |||
max-width: 100%; | |||
max-height: 100%; | |||
.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> |
@@ -1,46 +1,40 @@ | |||
<template> | |||
<div :class="inPage ? 'page active' : 'page'"> | |||
<div id="top"></div> | |||
<div @touchmove="onMouseMove" class="content"> | |||
<!-- <div | |||
v-for="(item, index) in materialList" | |||
:key="index" | |||
class="material" | |||
style=" | |||
{ | |||
top: item.x + 'px'; | |||
left: item.y + 'px'; | |||
transform: scale(item.scale); | |||
} | |||
" | |||
> | |||
<img :src="item.url" alt="" /> | |||
<div>11233</div> | |||
</div> --> | |||
<div class="content" ref="fatherBox"> | |||
<!-- 控制框 --> | |||
<div class="control"> | |||
<div @click="controlImg(1)">放大</div> | |||
<div @click="controlImg(2)">缩小</div> | |||
<div @click="controlImg(3)">上移一层</div> | |||
<div @click="controlImg(4)">下移一层</div> | |||
</div> | |||
<!-- <div | |||
<div | |||
:id="'item' + index" | |||
@touchmove="onMouseMove(index)" | |||
@touchstart="onMouseDown(index)" | |||
@touchend="onMouseUp(index)" | |||
v-for="(item, index) in materialList" | |||
:key="index" | |||
class="material" | |||
:style="{ top: item.x, left: item.y }" | |||
> | |||
<div>{{ item.text }}</div> | |||
</div> --> | |||
<div | |||
@touchstart="onMouseDown" | |||
@touchend="onMouseUp" | |||
class="material" | |||
:style="{ | |||
transform: | |||
'scale(' + | |||
scale + | |||
item.scale + | |||
') translate(' + | |||
offsetX + | |||
item.x + | |||
'px, ' + | |||
offsetY + | |||
'px)' | |||
item.y + | |||
'px)', | |||
zIndex: item.zIndex | |||
}" | |||
></div> | |||
> | |||
<div>{{ item.text }}</div> | |||
<img :src="item.url" alt="" /> | |||
<!-- 边框 --> | |||
<div :class="domIndex == index ? 'active' : ''"></div> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
@@ -61,10 +55,10 @@ export default { | |||
dragging: false, | |||
startX: 0, | |||
startY: 0, // 鼠标位置x y | |||
windowWidth: 0, | |||
windowHeight: 0, | |||
scale: 1, | |||
lastScale: 1, | |||
offsetX: 200, | |||
offsetY: 200, | |||
domIndex: -1, //当前点击的图片 | |||
materialList: [ | |||
{ | |||
text: '小div1', | |||
@@ -93,9 +87,9 @@ export default { | |||
}, | |||
{ | |||
text: '小div4', | |||
url: '@/assets/icon/icon-trash', | |||
x: '100px', | |||
y: '100px', | |||
url: '../../assets/icon/icon-trash', | |||
x: 100, | |||
y: 100, | |||
scale: 1, | |||
zIndex: 10 | |||
}, | |||
@@ -110,33 +104,92 @@ export default { | |||
] | |||
} | |||
}, | |||
computed: { | |||
...mapState({ | |||
characters: (state) => state.publicObj.characters | |||
}) | |||
// imageStyles() { | |||
// return this.images.map((image, index) => { | |||
// return { | |||
// zIndex: index, | |||
// width: `${image.width}px`, | |||
// height: `${image.height}px`, | |||
// position: 'absolute', | |||
// top: `${image.y}px`, | |||
// left: `${image.x}px`, | |||
// }; | |||
// }); | |||
// }, | |||
}, | |||
methods: { | |||
...mapActions(['setCharacters']), | |||
// 鼠标按下事件 | |||
onMouseDown(event) { | |||
onMouseDown(index) { | |||
this.dragging = true | |||
this.domIndex = index | |||
// 记录点击瞬间的鼠标坐标 | |||
this.startX = event.touches[0].clientX | |||
this.startY = event.touches[0].clientY | |||
}, | |||
// 鼠标抬起 | |||
onMouseUp() { | |||
onMouseUp(index) { | |||
this.dragging = false | |||
// this.domIndex = -1 | |||
}, | |||
// 鼠标在父盒子移动时,判断是否按下,然后再走逻辑 | |||
onMouseMove(event) { | |||
onMouseMove(index) { | |||
// 禁止默认事件--下拉 | |||
event.preventDefault() | |||
if (!this.dragging) return | |||
if (this.domIndex != index) return | |||
// console.log(event.touches[0]) | |||
const deltaX = event.touches[0].clientX - this.startX | |||
const deltaY = event.touches[0].clientY - this.startY | |||
this.offsetX += deltaX | |||
this.offsetY += deltaY | |||
this.materialList[index].x += deltaX | |||
this.materialList[index].y += deltaY | |||
this.startX = event.touches[0].clientX | |||
this.startY = event.touches[0].clientY | |||
// 得到父子盒子信息 | |||
const fatherRect = this.$refs.fatherBox.getBoundingClientRect() | |||
const sonRect = document | |||
.getElementById(`item${index}`) | |||
.getBoundingClientRect() | |||
console.log(fatherRect) | |||
console.log(sonRect) | |||
// 限制X轴 | |||
if (this.materialList[index].x < 0) { | |||
this.materialList[index].x = 0 | |||
} | |||
if (sonRect.left > fatherRect.width - sonRect.width / 2) { | |||
this.materialList[index].x = fatherRect.width - sonRect.width | |||
} | |||
// 限制Y轴 | |||
if (this.materialList[index].y < 0) { | |||
this.materialList[index].y = 0 | |||
} | |||
if (sonRect.top > fatherRect.height - sonRect.height / 2) { | |||
this.materialList[index].y = fatherRect.height - sonRect.height | |||
} | |||
}, | |||
controlImg(type) { | |||
if (this.domIndex == -1) { | |||
Toast('请选择素材') | |||
} | |||
if (type == 1) { | |||
this.materialList[this.domIndex].scale += 0.1 | |||
} | |||
if (type == 2) { | |||
this.materialList[this.domIndex].scale -= 0.1 | |||
} | |||
if (type == 3) { | |||
this.materialList[this.domIndex].zIndex += 1 | |||
} | |||
if (type == 4) { | |||
this.materialList[this.domIndex].zIndex -= 1 | |||
} | |||
}, | |||
go(url) { | |||
this.$router.push(url) | |||
@@ -151,6 +204,23 @@ export default { | |||
</script> | |||
<style lang="scss" scoped> | |||
* { | |||
box-sizing: content-box !important; | |||
} | |||
.control { | |||
position: absolute; | |||
top: 0; | |||
left: 50%; | |||
transform: translateX(-50%); | |||
display: flex; | |||
justify-content: space-around; | |||
width: 200px; | |||
height: 30px; | |||
text-align: center; | |||
line-height: 30px; | |||
background-color: #fff; | |||
z-index: 999999; | |||
} | |||
.page { | |||
transform: translateX(30%); | |||
opacity: 0; | |||
@@ -159,18 +229,32 @@ export default { | |||
opacity: 1; | |||
transform: translateX(0); | |||
} | |||
height: 100%; | |||
width: 100%; | |||
position: fixed; | |||
top: 0; | |||
left: 0; | |||
} | |||
.content { | |||
position: relative; | |||
width: 375px; | |||
height: 667px; | |||
width: 100vw; | |||
height: 100vh; | |||
background-color: green; | |||
overflow: hidden; | |||
.active { | |||
position: absolute; | |||
top: -10px; | |||
left: -10px; | |||
width: 100%; | |||
height: 100%; | |||
border: 10px solid rgba(0, 0, 0, 0.5); | |||
} | |||
.material { | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
width: 50px; | |||
height: 40px; | |||
width: 150px; | |||
height: 140px; | |||
background-color: red; | |||
img { | |||
width: 30px; | |||
@@ -1,32 +1,17 @@ | |||
<template> | |||
<div :class="inPage ? 'page active' : 'page'"> | |||
<div id="top"></div> | |||
<div class="content"> | |||
<!-- <div | |||
v-for="(item, index) in materialList" | |||
:key="index" | |||
class="material" | |||
style=" | |||
{ | |||
top: item.x + 'px'; | |||
left: item.y + 'px'; | |||
transform: scale(item.scale); | |||
} | |||
" | |||
> | |||
<img :src="item.url" alt="" /> | |||
<div>11233</div> | |||
</div> --> | |||
<div class="content" ref="fatherBox"> | |||
<!-- 控制框 --> | |||
<div class="control"> | |||
<div @click="controlImg(1)">放大</div> | |||
<div @click="controlImg(2)">缩小</div> | |||
<div @click="controlImg(3)">上移一层</div> | |||
<div @click="controlImg(4)">下移一层</div> | |||
</div> | |||
<!-- <div | |||
v-for="(item, index) in materialList" | |||
:key="index" | |||
class="material" | |||
:style="{ top: item.x, left: item.y }" | |||
> | |||
<div>{{ item.text }}</div> | |||
</div> --> | |||
<div | |||
:id="'item' + index" | |||
@touchmove="onMouseMove(index)" | |||
@touchstart="onMouseDown(index)" | |||
@touchend="onMouseUp(index)" | |||
@@ -34,19 +19,16 @@ | |||
:key="index" | |||
class="material" | |||
:style="{ | |||
transform: | |||
'scale(' + | |||
item.scale + | |||
') translate(' + | |||
item.x + | |||
'px, ' + | |||
item.y + | |||
'px)', | |||
zIndex: item.zIndex | |||
transform: 'scale(' + item.scale + ') ', | |||
zIndex: item.zIndex, | |||
top: item.y + 'px', | |||
left: item.x + 'px' | |||
}" | |||
> | |||
<img :src="item.url" alt="" /> | |||
<div>{{ item.text }}</div> | |||
<img :src="item.url" alt="" /> | |||
<!-- 边框 --> | |||
<div :class="domIndex == index ? 'active' : ''"></div> | |||
</div> | |||
</div> | |||
</div> | |||
@@ -68,11 +50,10 @@ export default { | |||
dragging: false, | |||
startX: 0, | |||
startY: 0, // 鼠标位置x y | |||
windowWidth: 0, | |||
windowHeight: 0, | |||
scale: 1, | |||
lastScale: 1, | |||
domIndex: -1, //当前点击的图片 | |||
offsetX: 200, | |||
offsetY: 200, | |||
materialList: [ | |||
{ | |||
text: '小div1', | |||
@@ -143,30 +124,74 @@ export default { | |||
onMouseDown(index) { | |||
this.dragging = true | |||
this.domIndex = index | |||
// 记录点击瞬间的鼠标坐标 | |||
this.startX = event.touches[0].clientX | |||
this.startY = event.touches[0].clientY | |||
}, | |||
// 鼠标抬起 | |||
onMouseUp(index) { | |||
this.dragging = false | |||
this.domIndex = -1 | |||
// this.domIndex = -1 | |||
}, | |||
// 鼠标在父盒子移动时,判断是否按下,然后再走逻辑 | |||
onMouseMove(index) { | |||
// 禁止默认事件--下拉 | |||
event.preventDefault() | |||
if (!this.dragging) return | |||
if (this.domIndex != index) return | |||
console.log(event.touches[0]) | |||
const deltaX = event.touches[0].clientX - this.startX | |||
const deltaY = event.touches[0].clientY - this.startY | |||
console.log(deltaX) | |||
this.materialList[index].x += deltaX | |||
this.materialList[index].y += deltaY | |||
this.startX = event.touches[0].clientX | |||
this.startY = event.touches[0].clientY | |||
// 得到父子盒子信息 | |||
const fatherRect = this.$refs.fatherBox.getBoundingClientRect() | |||
const sonRect = document | |||
.getElementById(`item${index}`) | |||
.getBoundingClientRect() | |||
// 限制X轴 | |||
if (this.materialList[index].x < 0) { | |||
this.materialList[index].x = 0 | |||
} | |||
if (sonRect.left > fatherRect.width - sonRect.width / 2) { | |||
this.materialList[index].x = fatherRect.width - sonRect.width | |||
this.exceed() | |||
} | |||
// 限制Y轴 | |||
if (this.materialList[index].y < 0) { | |||
this.materialList[index].y = 0 | |||
} | |||
this.startX = event.touches[0].clientX | |||
this.startY = event.touches[0].clientY | |||
if (sonRect.top > fatherRect.height - sonRect.height / 2) { | |||
this.materialList[index].y = fatherRect.height - sonRect.height | |||
this.exceed() | |||
} | |||
}, | |||
// 控制台 | |||
controlImg(type) { | |||
if (this.domIndex == -1) { | |||
Toast('请选择素材') | |||
} | |||
if (type == 1) { | |||
this.materialList[this.domIndex].scale += 0.1 | |||
} | |||
if (type == 2) { | |||
this.materialList[this.domIndex].scale -= 0.1 | |||
} | |||
if (type == 3) { | |||
this.materialList[this.domIndex].zIndex += 1 | |||
} | |||
if (type == 4) { | |||
this.materialList[this.domIndex].zIndex -= 1 | |||
} | |||
}, | |||
// 素材超出显示范围 | |||
exceed() { | |||
Toast('素材超出显示范围') | |||
}, | |||
go(url) { | |||
this.$router.push(url) | |||
@@ -181,6 +206,23 @@ export default { | |||
</script> | |||
<style lang="scss" scoped> | |||
* { | |||
box-sizing: content-box !important; | |||
} | |||
.control { | |||
position: absolute; | |||
top: 0; | |||
left: 50%; | |||
transform: translateX(-50%); | |||
display: flex; | |||
justify-content: space-around; | |||
width: 200px; | |||
height: 30px; | |||
text-align: center; | |||
line-height: 30px; | |||
background-color: #fff; | |||
z-index: 999999; | |||
} | |||
.page { | |||
transform: translateX(30%); | |||
opacity: 0; | |||
@@ -189,13 +231,26 @@ export default { | |||
opacity: 1; | |||
transform: translateX(0); | |||
} | |||
height: 100%; | |||
width: 100%; | |||
position: fixed; | |||
top: 0; | |||
left: 0; | |||
} | |||
.content { | |||
position: relative; | |||
width: 375px; | |||
height: 667px; | |||
width: 100vw; | |||
height: 100vh; | |||
background-color: green; | |||
overflow: hidden; | |||
.active { | |||
position: absolute; | |||
top: -10px; | |||
left: -10px; | |||
width: 100%; | |||
height: 100%; | |||
border: 10px solid rgba(0, 0, 0, 0.5); | |||
} | |||
.material { | |||
position: absolute; | |||
top: 0; | |||
@@ -9,10 +9,61 @@ | |||
<div class="title"> | |||
<img src="../../assets/img/myVideo.png" alt="" /> | |||
我的视频作品 | |||
<span class="floatRight" style="float: right">草稿箱</span> | |||
<span | |||
v-show="listActive == 1" | |||
class="floatRight" | |||
@click="listActive = 2" | |||
><img src="../../assets/icon/icon-list2.png" alt="" /></span | |||
><span | |||
@click="listActive = 1" | |||
v-show="listActive == 2" | |||
class="floatRight" | |||
><img src="../../assets/icon/icon-list1.png" alt="" | |||
/></span> | |||
<span class="floatRight">只看竖屏</span> | |||
<span class="floatRight">只看横屏</span> | |||
</div> | |||
<!-- 具体内容 --> | |||
<!-- 列表样式--大图 --> | |||
<div | |||
v-show="listActive == 1" | |||
v-masonry | |||
class="waterFall" | |||
item-selector=".waterFall-item" | |||
column-width="170" | |||
> | |||
<div | |||
v-masonry-tile | |||
v-for="(item, index) in videoList" | |||
class="waterFall-item" | |||
:key="item.id ? item.id : index" | |||
@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> | |||
</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> | |||
<!-- 列表样式--小图 --> | |||
<van-swipe-cell | |||
v-show="listActive == 2" | |||
loading | |||
v-for="(item, index) in videoList" | |||
:key="item.id ? item.id : index" | |||
@@ -60,28 +111,12 @@ | |||
<i class="el-icon-delete" /> 删除 | |||
</div> | |||
</van-popup> | |||
<!-- <van-dialog class="dialog" | |||
v-model="clickItem==item?showTrue:showFalse"> | |||
<div @click="closeDialog"><i class="el-icon-edit" /> 编辑</div> | |||
<div><i class="el-icon-delete" /> 删除</div> | |||
</van-dialog> --> | |||
</div> | |||
<!-- 无数据处理 --> | |||
<div v-if="videoList.length <= 0" class="noWork"> | |||
您还没有视频作品 | |||
</div> | |||
</div> | |||
<!-- 右滑 --> | |||
<!-- <template #right> | |||
<van-button | |||
square | |||
text="删除" | |||
type="danger" | |||
class="delete-button" | |||
@click="goDelete(item.id)" | |||
/> | |||
</template> --> | |||
</van-swipe-cell> | |||
</div> | |||
<!-- 分页 --> | |||
@@ -152,7 +187,10 @@ export default { | |||
currentPage: 1, | |||
pageSize: 4, | |||
prePage: '', | |||
total: '' | |||
total: '', | |||
defaultImg: require('@/assets/img/BG@2x.png'), //默认图片 | |||
defaultImg1: require('@/assets/img/bg.png'), //默认图片 | |||
listActive: 1 // 显示列表样式 | |||
} | |||
}, | |||
computed: { | |||
@@ -218,6 +256,7 @@ export default { | |||
path: '/editModel', | |||
query: { | |||
saveID: item.id, | |||
id: item.id, | |||
imgUrl: item.id, | |||
modelId: item.id, | |||
mouldSmId: item.id, | |||
@@ -351,6 +390,14 @@ export default { | |||
</script> | |||
<style lang="scss" scoped> | |||
.floatRight { | |||
margin-left: 15px; | |||
img { | |||
vertical-align: bottom !important; | |||
margin-top: 2px !important; | |||
color: red; | |||
} | |||
} | |||
.page { | |||
transform: translateX(30%); | |||
opacity: 0; | |||
@@ -624,4 +671,69 @@ export default { | |||
height: 100%; | |||
} | |||
} | |||
// 瀑布流 | |||
.waterFall { | |||
display: flex; | |||
flex-wrap: wrap; | |||
justify-content: space-between; | |||
margin-right: -20px; | |||
width: 100%; | |||
&-item { | |||
// max-width: 355px; //非瀑布流 | |||
max-width: 170px; | |||
max-height: 300px; | |||
// background-color: red; | |||
border-radius: 12px; | |||
margin-bottom: 10px; | |||
overflow: hidden; | |||
img { | |||
max-width: 100%; | |||
max-height: 100%; | |||
object-fit: cover; | |||
// background-color: red; | |||
} | |||
&-mask { | |||
position: absolute; | |||
bottom: 0; | |||
left: 0; | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: space-around; | |||
padding: 5px 8px 5px; | |||
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, #000000 100%); | |||
height: 80px; | |||
width: 100%; | |||
color: #f7dcdc; | |||
div { | |||
overflow: hidden; | |||
white-space: nowrap; | |||
text-overflow: ellipsis; | |||
} | |||
} | |||
&-state { | |||
position: absolute; | |||
top: 0px; | |||
left: 0px; | |||
padding: 7.5px; | |||
border-radius: 0 0 12px 0; | |||
color: #f7dcdc; | |||
background-color: rgba(0, 0, 0, 0.3); | |||
} | |||
&-del { | |||
position: absolute; | |||
top: 0px; | |||
right: 0px; | |||
height: 30px; | |||
width: 30px; | |||
padding: 7.5px; | |||
border-radius: 0 0 0 12px; | |||
background-color: rgba(0, 0, 0, 0.3); | |||
img { | |||
height: 15px; | |||
width: 15px; | |||
} | |||
} | |||
} | |||
} | |||
</style> |
@@ -30,7 +30,7 @@ | |||
v-masonry | |||
class="waterFall" | |||
item-selector=".waterFall-item" | |||
column-width="175" | |||
column-width="170" | |||
> | |||
<div | |||
v-masonry-tile | |||
@@ -391,7 +391,7 @@ export default { | |||
<style lang="scss" scoped> | |||
.floatRight { | |||
margin-left: 20px; | |||
margin-left: 15px; | |||
img { | |||
vertical-align: bottom !important; | |||
margin-top: 2px !important; | |||
@@ -700,11 +700,16 @@ export default { | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: space-around; | |||
padding: 5px 8px 0; | |||
padding: 5px 8px 5px; | |||
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, #000000 100%); | |||
height: 80px; | |||
width: 100%; | |||
color: #f7dcdc; | |||
div { | |||
overflow: hidden; | |||
white-space: nowrap; | |||
text-overflow: ellipsis; | |||
} | |||
} | |||
&-state { | |||
position: absolute; | |||