Files
visitor/src/views/apply.vue
T
2024-11-05 17:43:01 +08:00

721 lines
23 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div v-if="true" class='box'>
<div class="apply-box">
<img class="text" src="../assets/zhinengfangke.png" alt="">
<p>来访提前约 拜访开门无需按铃</p>
<div class="apply-content">
<h3>
<img src="../assets/icon-shenfenzheng.png" alt="">
<span>拜访信息<span>(我找谁)</span></span>
</h3>
<div class="apply-content-form">
<!-- <Selectli label="被拜访对象" v-model="form.visitingTel" :columns="visitDict" :isMust="true" :isline="true" name="name" nameId="userId"/> -->
<!-- <div class="search-select-box">
<label class="label"><span>*&nbsp;</span>被拜访人</label>
<div class="search-select-input">
<input @click.stop="onClickVisitor" @input="onInputVisior" :value="visitorName" type="text" placeholder="可填写选择">
<div v-if="isSelect && visitDict.length" class="select-box">
<b></b>
<div class="select-sroll-box">
<div @click.self="onClickSelect(item)" v-for="item in visitDict" :class="item.userId == form.visitingTel ? 'select-active' : ''" class="select-li" :key="item.userId">{{ item.name }}</div>
</div>
</div>
<div v-if="isSelect && !visitDict.length" class="select-box">
<b></b>
<div class="select-li" >查无此人</div>
</div>
</div>
</div> -->
<Inputli v-if="telName" v-model="telName" @input="onInputName" label="被访人" :isMust="true" :isline="true" isMustPosition="left"/>
<Inputli v-else v-model="form.visitingTel" @blur="onBlurTel" @input="onInputTel" label="被访人电话" :isMust="true" :isline="true" isMustPosition="left"/>
<Selectdate v-model="form.hours" label="来访时间" :isMust="true" :isline="false" :minDate="minDate"/>
</div>
</div>
<img class="absolute-img" src="../assets/woyaoyuyue.png" alt="">
</div>
<p class="tips">
说明拜访时间前后一小时都可刷脸通过门禁
</p>
<div class="visitor-content">
<h3>
<img src="../assets/icon-shenfenzheng.png" alt="">
<span>访客信息<span>(我是谁)</span></span>
</h3>
<div class="visitor-content-form">
<Inputli v-model="form.name" label="访客姓名" :isMust="true" :isline="true" isMustPosition="left"/>
<Inputli v-model="form.phone" label="联系方式" :isMust="true" :isline="true" isMustPosition="left"/>
<Inputli v-model="form.visitingNum" label="随行人数" :isMust="true" :isline="true" isMustPosition="left"/>
<Inputli v-model="form.reason" label="来访事由" :isMust="true" :isline="true" isMustPosition="left"/>
<div class="upload-box">
<label for=""><span>*&nbsp;</span>人脸照片</label>
<div v-if="!form.img" class="upload-button">
<img @click="onClickUpload" src="../assets/xiangji.png" alt="">
<input v-if="isDisabled" @change="onChangeFile" type="file" accept="image/*">
</div>
<div v-else class="face-img">
<img :src="form.img" alt="">
<input v-if="true" @change="onChangeFile" type="file" accept="image/*">
</div>
</div>
</div>
</div>
<p class="tips">
说明人脸照片用于通过门禁系统请上传正脸无遮挡照片
</p>
<p class="tel-tips">
如果您在使用中遇到问题请联系<span @click="onClickCall">400040-1573</span>
</p>
<!-- <div class="disclaimer-box">
<input type="checkbox">
<p>勾选表示同意<span>用户协议</span></p>
</div> -->
<button @click="onClcikSubmit" class="submit-button " :class="isSubmit ? 'active-button' : ''">提交</button>
<Successmodel v-if="isSuccess" @click="onClickAffirm" />
<div v-if="false" class="disclaimer-model-fixed">
<h3>用户协议</h3>
<div class="disclaimer-model">
阿哈撒发哈师范哈撒发哈很舒服哈哈
阿哈撒发哈师范哈撒发哈很舒服哈哈
阿哈撒发哈师范哈撒发哈很舒服哈哈
阿哈撒发哈师范哈撒发哈很舒服哈哈
阿哈撒发哈师范哈撒发哈很舒服哈哈
阿哈撒发哈师范哈撒发哈很舒服哈哈
阿哈撒发哈师范哈撒发哈很舒服哈哈
阿哈撒发哈师范哈撒发哈很舒服哈哈
阿哈撒发哈师范哈撒发哈很舒服哈哈
阿哈撒发哈师范哈撒发哈很舒服哈哈
阿哈撒发哈师范哈撒发哈很舒服哈哈
</div>
</div>
</div>
</template>
<script setup>
import { reactive, ref, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useStore } from 'vuex'
import { Toast, ImagePreview , Uploader, Dialog } from 'vant';
import { rulesForm, resetForm, rulesPhone, rulesFormFBoolean, formatDate } from '@/com/index'
import Inputli from '@/components/input-li.vue'
import Selectli from '@/components/select-li.vue'
import Selectdate from '@/components/select-li-date.vue'
import Successmodel from '../components/success.vue'
import { postApply, getVisitor, getUserNameByTel } from '@/api/user.js'
import { uploadApi } from '@/api/upload'
/* @data */
const router = useRouter()
const route = useRoute()
const store = useStore()
const phoneReg = /(^1\d{10}$)|(^[0-9]\d{7}$)/;
let form = reactive({
name: "",
phone: "",
hours: "",
reason: "",
img: "",
visitingTel: "",
visitingNum: '',
})
const isSubmit = ref(false)
const visitDict = ref([]) // 被访客数据
const visitAllDict = ref([]) // 被访客数据
const isDisabled = ref(false) // 是否能提交
const isSuccess = ref(false) // 是否提交成功
const isSelect = ref( false) // 是否显示下拉选择
const visitorName = ref( '') // 是否显示下拉选择的名字
const telName = ref( '') // 电话查询姓名
/* watch */
watch(() => form, (v1, v2) => {
isSubmit.value = rulesFormFBoolean(v2)
if(v2.name && v2.phone){
if(!phoneReg.test(v2.phone)){
isDisabled.value = false
}else{
isDisabled.value = true
}
}else{
isDisabled.value = false
}
},{ deep: true }
) // 深度监听 ) // 监听单个
/* @method */
const onInputTel = (e) =>{
}
const onInputName = (e) =>{
form.visitingTel = ''
telName.value = ''
}
const onBlurTel = (phone) =>{
console.log(phone)
if(rulesPhone(phone)){
getUserNameByTel(phone).then(res =>{
console.log(res)
if(res.data){
telName.value = res.data
}
}).catch(err =>{
Toast.clear();
console.log(err)
Dialog.alert({
message: err.msg,
}).then(() => {
// on close
});
})
}
}
// const onBlurVisitor = () =>{
// isSelect.value = false
// let item = visitAllDict.value.find(item =>{ return item.userId == form.visitingTel })
// if(item){
// visitorName.value = item.name
// visitDict.value = visitAllDict.value
// }else{
// visitorName.value = '' // 是否显示下拉选择的名字
// visitDict.value = visitAllDict.value
// }
// }
// 输入框
// const onInputVisior = (e) =>{
// visitorName.value = e.target.value
// let arr = []
// visitAllDict.value.map( item =>{
// if(item.name.search(e.target.value) != -1){
// arr.push(item)
// }
// })
// visitDict.value = [ ...arr ]
// }
// 点击选择了拜访对象
// const onClickSelect = (item) =>{
// form.visitingTel = item.userId
// visitorName.value = item.name
// isSelect.value = false
// }
// const onClickVisitor = () =>{
// isSelect.value = true
// }
// 点击确认模态框
const onClickAffirm = () =>{
router.go(-1)
}
const onClickUpload = () =>{
if(isDisabled.value){
}else{
Toast.fail('请填写访客姓名和正确的联系方式!')
}
}
const onClcikSubmit = () =>{
if(isSubmit.value){
if(rulesPhone(form.phone) && rulesPhone(form.visitingTel)){
Toast.loading({ duration: 0, forbidClick: true, message: '提交中', });
postApply(form).then(res =>{
Toast.clear();
isSuccess.value = true
})
}
}else{
Toast.fail('请先填写完整信息后提交!')
}
}
// 上传照片
const onChangeFile = (e) =>{
console.log(e.target.files[0].size)
if(e.target.files[0]){
newcompressImg(e.target.files[0], 0.5).then(res =>{
let formData = new FormData()
// formData.append('file', e.target.files[0])
formData.append('file', res.file)
formData.append('userId', form.phone)
formData.append('name', form.name)
Toast.loading({ duration: 0, forbidClick: true, message: '上传中', });
uploadApi(formData).then(res =>{
Toast.success(res.msg);
form.img = res.data
})
}).catch(err =>{
Toast.fail('图片上传失败,请重新上传')
})
}
}
const onClickCall = () =>{
window.location.href = 'tel:400-040-1573'
}
const newcompressImg = (file, quality) =>{
var qualitys = 0.52
if (parseInt((file.size / 1024).toFixed(2)) < 1024) {
qualitys = 0.85
}
if (5 * 1024 < parseInt((file.size / 1024).toFixed(2))) {
qualitys = 0.92
}
if (quality) {
qualitys = quality
}
if (file[0]) {
return Promise.all(Array.from(file).map(e => this.compressImg(e,
qualitys))) // 如果是 file 数组返回 Promise 数组
} else {
return new Promise((resolve) => {
if ((file.size / 1024).toFixed(2) < 300) {
resolve({
file: file
})
} else {
const reader = new FileReader() // 创建 FileReader
reader.onload = ({
target: {
result: src
}
}) => {
const image = new Image() // 创建 img 元素
image.onload = async() => {
const canvas = document.createElement('canvas') // 创建 canvas 元素
const context = canvas.getContext('2d')
var targetWidth = image.width
var targetHeight = image.height
var originWidth = image.width
var originHeight = image.height
if (1 * 1024 <= parseInt((file.size / 1024).toFixed(2)) && parseInt((file.size / 1024).toFixed(2)) <= 10 * 1024) {
var maxWidth = 1600
var maxHeight = 1600
targetWidth = originWidth
targetHeight = originHeight
// 图片尺寸超过的限制
if (originWidth > maxWidth || originHeight > maxHeight) {
if (originWidth / originHeight > maxWidth / maxHeight) {
// 更宽,按照宽度限定尺寸
targetWidth = maxWidth
targetHeight = Math.round(maxWidth * (originHeight / originWidth))
} else {
targetHeight = maxHeight
targetWidth = Math.round(maxHeight * (originWidth / originHeight))
}
}
}
if (10 * 1024 <= parseInt((file.size / 1024).toFixed(2)) && parseInt((file.size / 1024).toFixed(2)) <= 20 * 1024) {
maxWidth = 1400
maxHeight = 1400
targetWidth = originWidth
targetHeight = originHeight
// 图片尺寸超过的限制
if (originWidth > maxWidth || originHeight > maxHeight) {
if (originWidth / originHeight > maxWidth / maxHeight) {
// 更宽,按照宽度限定尺寸
targetWidth = maxWidth
targetHeight = Math.round(maxWidth * (originHeight / originWidth))
} else {
targetHeight = maxHeight
targetWidth = Math.round(maxHeight * (originWidth / originHeight))
}
}
}
canvas.width = targetWidth
canvas.height = targetHeight
context.clearRect(0, 0, targetWidth, targetHeight)
context.drawImage(image, 0, 0, targetWidth, targetHeight) // 绘制 canvas
const canvasURL = canvas.toDataURL('image/jpeg', qualitys)
const buffer = atob(canvasURL.split(',')[1])
let length = buffer.length
const bufferArray = new Uint8Array(new ArrayBuffer(length))
while (length--) {
bufferArray[length] = buffer.charCodeAt(length)
}
const miniFile = new File([bufferArray], file.name, {
type: 'image/jpeg'
})
resolve({
file: miniFile,
origin: file,
beforeSrc: src,
afterSrc: canvasURL,
beforeKB: Number((file.size / 1024).toFixed(2)),
afterKB: Number((miniFile.size / 1024).toFixed(2))
})
}
image.src = src
}
reader.readAsDataURL(file)
}
})
}
}
/* @setup */
const minDate = ref( formatDate(new Date()))
console.log(route.query.tel)
if(route.query.tel){
form.visitingTel = route.query.tel
onBlurTel(route.query.tel)
}
getVisitor().then( res=>{
visitDict.value = res.data
visitAllDict.value = res.data
})
</script>
<style lang='scss' scoped>
.box{
width: 100%;
height: 100%;
background: #F5F5F5;
padding: 0 0 1.08rem /* 81/75 */;
box-sizing: border-box;
overflow: auto;
.apply-box{
position: relative;
width: 100%;
height: 8.0267rem /* 602/75 */;
background: url('../assets/yuyuebeijing.png') left top/ 100% 100% no-repeat;
padding: 1.04rem /* 78/75 */ 0 0;
box-sizing: border-box;
.text{
width: 3.5467rem /* 266/75 */;
height: 1.1467rem /* 86/75 */;
margin-left: .6133rem /* 46/75 */;
}
p{
line-height: .48rem /* 36/75 */;
font-size: $sm-size;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
color: #999999;
padding: .1067rem /* 8/75 */ 0 0 .7467rem /* 56/75 */;
}
.apply-content{
width: 9.2rem /* 690/75 */;
height: 4.32rem /* 324/75 */;
background: #FFFFFF;
border-radius: .2667rem /* 20/75 */;
margin: 1.0133rem /* 76/75 */ auto 0;
h3{
padding: .5067rem /* 38/75 */ .3467rem /* 26/75 */ 0 .4533rem /* 34/75 */;
box-sizing: border-box;
display: flex;
align-items: center;
color: #222222;
font-size: $size30;
img{
width: .5867rem /* 44/75 */;
height: .5333rem /* 40/75 */;
margin-right: .16rem /* 12/75 */;
}
span{
span{
font-size: .32rem /* 24/75 */;
color: #666;
}
}
}
.apply-content-form{
width: 100%;
padding: 0 .3467rem /* 26/75 */ 0 .4533rem /* 34/75 */;
box-sizing: border-box;
.search-select-box{
position: relative;
width: 100%;
height: 1.5733rem /* 118/75 */;
// background: #F9F9F9;
// border-radius: .2667rem /* 20/75 */;
padding: 0 .0267rem /* 2/75 */ 0;
box-sizing: border-box;
display: flex;
// margin-bottom: .2667rem /* 20/75 */;
border-bottom: 0.0267rem dashed #D9D9D9;
.label{
flex: 1;
font-size: $size26;
color: #333333;
line-height: 1.5733rem /* 118/75 */;
span{
color: #FF0000;
margin-right: .0267rem /* 2/75 */;
}
}
.search-select-input{
position: relative;
height: 100%;
box-sizing: border-box;
input{
flex: 1;
border: none;
outline: none;
text-align: right;
font-size: $size26;
color: #333333;
// background: #F9F9F9;
padding-right: 0.3733rem;
// line-height: 1.5733rem /* 118/75 */;
box-sizing: border-box;
height: 100%;
}
input::-webkit-input-placeholder {
font-size: $size26;
color: #999999;
}
.select-box{
position: absolute;
right: 0;
top: 1.8667rem /* 140/75 */;
z-index: 5;
width: 3.7333rem /* 280/75 */;
// max-height: 5.0667rem /* 380/75 */;
background: #FFFFFF;
box-shadow: 0px 0px .2667rem /* 20/75 */ .1067rem /* 8/75 */ rgba(0,0,0,0.1);
border-radius: .0533rem /* 4/75 */ ;
// overflow: auto;
.select-sroll-box{
// position: absolute;
// right: 0;
// top: 1.8667rem /* 140/75 */;
// z-index: 5;
width: 100%;
max-height: 5.0667rem /* 380/75 */;
background: #FFFFFF;
// box-shadow: 0px 0px .2667rem /* 20/75 */ .1067rem /* 8/75 */ rgba(0,0,0,0.1);
// border-radius: .0533rem /* 4/75 */ ;
overflow: auto;
}
.select-li{
height: 1.0133rem /* 76/75 */;
background: #fff;
border-radius: .0533rem /* 4/75 */ .0533rem /* 4/75 */ 0px 0px;
font-size: $size26;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
color: #999999;
line-height: 1.0133rem /* 76/75 */;
text-align: center;
}
.select-active{
color: #30BF78;
background: #F3FEFB;
}
}
b{
position: absolute;
left: 50%;
// top: -100%;
// width: .2rem /* 15/75 */;
// height: 20px;
// background: red;
// display: block;
width: 0;
height: 0;
border: .16rem /* 12/75 */ solid transparent;
border-bottom: .16rem /* 12/75 */ solid #fff;
transform: translateY(-100%) translateX(-50%);
// margin-top: -.6667rem /* 50/75 */;
}
}
}
}
}
.absolute-img{
position: absolute;
top: .5333rem /* 40/75 */;
right: .4rem /* 30/75 */;
width: 4.5067rem /* 338/75 */;
height: 3.7867rem /* 284/75 */;
}
}
.tips{
line-height: .4533rem /* 34/75 */;
font-size: .2933rem /* 22/75 */;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
color: #999999;
padding: .2133rem /* 16/75 */ 0 .4267rem /* 32/75 */ .8rem /* 60/75 */;
box-sizing: border-box;
}
.visitor-content{
width: 9.2rem /* 690/75 */;
// height: 4.32rem /* 324/75 */;
background: #FFFFFF;
border-radius: .2667rem /* 20/75 */;
margin: 0 auto 0;
h3{
padding: .5067rem /* 38/75 */ .3467rem /* 26/75 */ 0 .4533rem /* 34/75 */;
box-sizing: border-box;
display: flex;
align-items: center;
color: #222222;
font-size: $size30;
img{
width: .5867rem /* 44/75 */;
height: .5333rem /* 40/75 */;
margin-right: .16rem /* 12/75 */;
}
span{
span{
font-size: .32rem /* 24/75 */;
color: #666;
}
}
}
.visitor-content-form{
width: 100%;
padding: 0 .3467rem /* 26/75 */ .16rem /* 12/75 */ .4533rem /* 34/75 */;
box-sizing: border-box;
.upload-box{
width: 100%;
height: 1.9733rem /* 148/75 */;
// padding: 0 .6933rem /* 52/75 */ 0 0;
padding-right: .3733rem /* 28/75 */;
box-sizing: border-box;
display: flex;
justify-content: space-between;
align-items: center;
color: #333333;
font-size: $size26;
label{
line-height: 1.9733rem /* 148/75 */;
span{
color: #FF0000;
}
}
.upload-button{
position: relative;
width: 1.3333rem /* 100/75 */;
height: 1.3333rem /* 100/75 */;
background: #FFFFFF;
border-radius: .1333rem /* 10/75 */;
border: .0267rem /* 2/75 */ dashed #D9D9D9;
display: flex;
align-items: center;
justify-content: center;
// overflow: hidden;
input{
position: absolute;
left: 0;
top: 0;
width: 1.3333rem /* 100/75 */;
height: 1.3333rem /* 100/75 */;
opacity: 0;
}
}
.face-img{
position: relative;
width: 1.3333rem /* 100/75 */;
height: 1.3333rem /* 100/75 */;
background: #FFFFFF;
border-radius: .1333rem /* 10/75 */;
img{
width: 100%;
height: 100%;
border-radius: .1333rem /* 10/75 */;
}
input{
position: absolute;
left: 0;
top: 0;
width: 1.3333rem /* 100/75 */;
height: 1.3333rem /* 100/75 */;
opacity: 0;
}
}
}
}
}
.disclaimer-box{
display: flex;
justify-content: center;
input{
margin-right: .1333rem /* 10/75 */;
}
span{
color: #30BF78;
}
}
.tel-tips{
line-height: .4533rem /* 34/75 */;
font-size: .2933rem /* 22/75 */;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
color: #999999;
padding: 0 0 .4267rem /* 32/75 */ .8rem /* 60/75 */;
box-sizing: border-box;
margin-top: -.24rem /* 18/75 */;
span{
color: #409eff;
}
}
.submit-button{
display: block;
width: 6.72rem /* 504/75 */;
height: 1.12rem /* 84/75 */;
background: #D9D9D9;
border-radius: 1.3333rem /* 100/75 */ ;
opacity: 1;
font-size: $size30;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 500;
color: #222222;
border: none;
outline: none;
margin: 1.0133rem /* 76/75 */ auto 0;
}
.active-button{
background-color: #30BF78;
color: #fff;
}
}
.disclaimer-model-fixed{
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: #fff;
display: flex;
flex-direction: column;
padding: .4rem /* 30/75 */;
box-sizing: border-box;
h3{
font-size: .4267rem /* 32/75 */;
line-height: .8rem /* 60/75 */;
text-align: center;
}
.disclaimer-model{
flex: 1;
line-height: .5333rem /* 40/75 */;
text-align: justify;
}
}
</style>