YNUtdPlatform/pages/realName/workbench/electronicContract/contractFill.vue

707 lines
22 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>
<view class="page">
<u-navbar class="u-navbar" title="电子合同" placeholder @leftClick="leftClick" leftIconColor="#fff" bgColor="#00337A" :titleStyle="{ color: '#FFF', fontSize: '32rpx' }"/>
<scroll-view class="content" scroll-y="true">
<view class="face-btn" @click="distinguish">点击人脸识别</view>
<view class="form-box">
<u--form class="addForm" :model="contractForm" :rules="rules" ref="cForm">
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>甲方</text>
</view>
<u-form-item prop='partA' style="width:70%;height: 100%;" >
<u--input v-model="contractForm.partA" type="text" placeholder="请输入" maxlength="40" border="surround" readonly clearable></u--input>
</u-form-item>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>法人代表</text>
</view>
<u-form-item prop='legalPerson' style="width:70%;height: 100%;" >
<u--input v-model="contractForm.legalPerson" type="text" placeholder="请输入" maxlength="20" border="surround" readonly clearable></u--input>
</u-form-item>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>联系电话</text>
</view>
<u-form-item prop='partAPhone' style="width:70%;height: 100%;" >
<u--input v-model="contractForm.partAPhone" type="number" placeholder="请输入" maxlength="11" border="surround" readonly clearable></u--input>
</u-form-item>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>地址</text>
</view>
<u-form-item prop='partAAdress' style="width:70%;height: 100%;" >
<u--input v-model="contractForm.partAAdress" type="text" placeholder="请输入" maxlength="40" border="surround" readonly clearable></u--input>
</u-form-item>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>乙方</text>
</view>
<u-form-item prop='partB' style="width:70%;height: 100%;" >
<u--input v-model="contractForm.partB" type="text" placeholder="请输入" maxlength="40" border="surround" readonly clearable></u--input>
</u-form-item>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>性别</text>
</view>
<u-form-item prop='sex' style="width:70%;height: 100%;" >
<u--input v-model="contractForm.sex" type="text" placeholder="请输入" maxlength="40" border="surround" readonly clearable></u--input>
</u-form-item>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>联系方式</text>
</view>
<u-form-item prop='partBPhone' style="width:70%;height: 100%;" >
<u--input v-model="contractForm.partBPhone" type="number" placeholder="请输入" maxlength="11" border="surround" readonly clearable></u--input>
</u-form-item>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>身份证号</text>
</view>
<u-form-item prop='partBIdCard' style="width:70%;height: 100%;" >
<u--input v-model="contractForm.partBIdCard" type="text" placeholder="请输入" border="surround" readonly clearable></u--input>
</u-form-item>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>家庭地址</text>
</view>
<u-form-item prop='partBAdress' style="width:70%;height: 100%;" >
<u--input v-model="contractForm.partBAdress" type="text" placeholder="请输入" maxlength="40" border="surround" readonly clearable></u--input>
</u-form-item>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>工种</text>
</view>
<u-form-item prop='workTypeId' style="width:70%;height: 100%;">
<u--input v-model="contractForm.workTypeName" type="text" placeholder="请输入" maxlength="40" border="surround" readonly clearable></u--input>
</u-form-item>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>工作任务</text>
</view>
<u-form-item prop='workTask' style="width:70%;height: 100%;" >
<u--input v-model="contractForm.workTask" type="text" placeholder="请输入" maxlength="40" border="surround" clearable></u--input>
</u-form-item>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>工作地点</text>
</view>
<u-form-item prop='workAdress' style="width:70%;height: 100%;" >
<u--input v-model="contractForm.workAdress" type="text" placeholder="请输入" maxlength="40" border="surround" clearable></u--input>
</u-form-item>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>工资核定方式</text>
</view>
<u-form-item prop='verMethod' style="width:70%;height: 100%;" >
<u--input v-model="contractForm.verMethod" type="text" readonly border="surround"></u--input>
</u-form-item>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>工资核定标准</text>
</view>
<u-form-item prop='verStand' style="width:70%;height: 100%;" >
<u--input v-model="contractForm.verStand" type="number" placeholder="请输入" maxlength="3" border="surround" clearable></u--input>
</u-form-item>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>生效日期</text>
</view>
<u-form-item prop='effectDate' style="width:70%;height: 100%;" >
<uni-datetime-picker type="date" :clear-icon="false" format="yyyy-MM-dd" v-model="contractForm.effectDate"/>
</u-form-item>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>其他补充事项</text>
</view>
<u-form-item prop='otherSupply' style="width:70%;height: 100%;" >
<u--input v-model="contractForm.otherSupply" type="text" placeholder="请输入" maxlength="40" border="surround" clearable></u--input>
</u-form-item>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>人员角色</text>
</view>
<u-form-item prop='role' style="width:70%;height: 100%;" >
<uni-data-select v-model="contractForm.role" :localdata="roleList"></uni-data-select>
</u-form-item>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>乙方签名</text>
</view>
<view class="img-box">
<view class="img-item" v-if="bSignImgUrl!=''">
<image class="img" :src="bSignImgUrl" mode=""></image>
</view>
<view style="margin-left: 40rpx;" class="signBtn" @click="openSignView(0)">签名采集</view>
</view>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>班组长签名</text>
</view>
<view class="img-box">
<view class="img-item" v-if="teamSignImgUrl!=''">
<image class="img" :src="teamSignImgUrl" mode=""></image>
</view>
<view style="margin-left: 40rpx;" class="signBtn" @click="openSignView(1)">签名采集</view>
</view>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>验证码</text>
</view>
<u-form-item prop='' style="width:70%;height: 100%;" >
</u-form-item>
</view>
<!-- <view style="width: 100%;height: auto;">
<view style="width:25%;height: 100%;margin: 20rpx;">
<text>合同期限类型</text>
</view>
<u-form-item prop='laborContractType' style="width:96%;height: 100%;margin: 0 auto;" >
<u-radio-group v-model="contractForm.laborContractType" placement="row" style="border: 1rpx solid #ccc;padding:20rpx 10rpx;border-radius: 10rpx;">
<u-radio label="以完成一定工作为期限的合同" name="以完成一定工作为期限的合同" style="margin-right: 20rpx;transform:scale(0.8);"></u-radio>
<u-radio label="固定期限合同" name="固定期限合同" style="transform:scale(0.8);"></u-radio>
</u-radio-group>
</u-form-item>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>合同终止日期</text>
</view>
<u-form-item prop='contractInvalidDate' style="width:70%;height: 100%;" >
<uni-datetime-picker type="date" :clear-icon="false" format="yyyy-MM-dd" v-model="contractForm.contractInvalidDate"/>
</u-form-item>
</view>
<view class="form-input-box">
<view style="width:25%;height: 100%;">
<text>合同类型</text>
</view>
<u-form-item prop='contractType' style="width:70%;height: 100%;" >
<u--input v-model="contractForm.contractType" type="text" readonly border="surround"></u--input>
</u-form-item>
</view> -->
</u--form>
</view>
<view class="bottom-box">
<view class="btn1" @click="leftClick">返回</view>
<view class="btn2" @click="sumbitContract">预览合同</view>
</view>
</scroll-view>
<!-- 签名弹窗 -->
<u-popup :show="signPopup" mode="center" @close="closeSign">
<view style="width:650rpx;height: 100%;position: relative;background-color: #fff;">
<view style="width: 100%;height: 32vh;background-color: #fff;">
<SignView v-on:signConfirm="signConfirm" photoType="contract/bsign" style="width: 100%;height: 100%;" />
</view>
</view>
</u-popup>
</view>
</template>
<script>
import { pathToBase64, base64ToPath } from 'image-tools';
import SignView from '../../components/signView.vue';
import config from '@/config';
export default {
components: { SignView },
data() {
return {
postList:[],
roleList:[
{value:'管理人员',text:'管理人员'},
{value:'务工人员',text:'务工人员'},
{value:'劳资专管员',text:'劳资专管员'}
],
videoUrl:"",
bSignImgUrl:'',
teamSignImgUrl:'',
signPopup:false,
signType:0,//0-本人签名1-班组长签名
faceData:{},
contractForm:{
"videoUrl":"",
"partA": "",//甲方
"legalPerson": "",//法人代表
"partAPhone": "",//甲方电话
"partAAdress": "",//甲方地址
"partB": "",//乙方
"sex":"男",//性别
"partBPhone": "",//乙方电话
"partBIdCard":"",//乙方身份证号
"partBAdress": "",//乙方地址
"workTypeId":"",//工种id
"workType":"",//工种
"workTypeName":"",//工种
"workTask":"",//工作任务
"workAdress":"",//工作地点
"verMethod": "天",//工资核定方式
"verStand": "",//工资核定标准
"effectDate": "",//生效日期
"otherSupply": "",//其他补充事项
"role": "",//人员角色
"partBSign": "",//乙方签名
"teamSign": "",//班组长签名
"post":"",
"message":"",
"signingDate":this.timeFormat(null,'yyyy-mm-dd'),
"faceUrl":"",
"messageTime":"",
"shortMessage":"",
"proId":""
},
rules: {
'verStand': {
type: 'string',
required: true,
message: '请填写工资核定标准',
trigger: ['blur', 'change']
}
},
}
},
onLoad(option) {
this.videoUrl=option.videoUrl||"";
},
onShow() {
},
methods: {
//人脸识别采集
distinguish(){
console.log('人脸识别采集')
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['camera'],
success: res => {
console.log('🚀 ~ res-拍照:', res)
this.imgToBase64(res.tempFilePaths[0]).then(base64 => {
// console.log(base64)
uni.uploadFile({
url: config.realFileUrl+`file/getFaceRecognition`, //服务器地址
fileType:"image",//ZFB必填,不然报错
filePath: res.tempFilePaths[0],//这个就是我们上面拍照返回或者先中照片返回的数组
formData: {
file:base64,
photoType:'face',
},
success: (uploadFileRes) => {
console.log(uploadFileRes)
if(uploadFileRes.statusCode==200){
uploadFileRes=JSON.parse(uploadFileRes.data)
console.log(uploadFileRes)
if(uploadFileRes.code==200){
if(uploadFileRes.data.face){
this.faceData=JSON.parse(uploadFileRes.data.personData)
console.log(this.faceData)
if(this.faceData){
this.initData()
uni.$u.toast('人脸认证成功!');
}else{
uni.$u.toast('识别失败');
}
}else{
uni.$u.toast(uploadFileRes.msg);
}
}else{
uni.$u.toast(uploadFileRes.msg);
}
}else{
uni.$u.toast('识别失败');
}
},
fail: err => {
uni.$u.toast('识别失败');
console.log(err)
}
});
})
},
fail: err => {
console.log('🚀 ~ err:', err)
}
})
},
//获取甲方信息
getPartA(){
let param={
id:this.faceData.subId,
proId:-1
}
uni.request({
url: config.realAppUrl + '/offLine/getSubcontractor',
method: 'post',
data: param,
header: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: uni.getStorageSync('realNameToken')
},
success: res => {
res = res.data;
if(res.code==200){
console.log(res)
this.contractForm.partA = res.data[0].name||"";
this.contractForm.legalPerson = res.data[0].legalName||"";
this.contractForm.partAPhone = res.data[0].legalPhone||"";
this.contractForm.partAAdress = res.data[0].address||"";
}
},
fail: err => {
console.log(err)
}
})
},
initData(){
this.contractForm.partB=this.faceData.name;
this.contractForm.sex=this.faceData.sex;
this.contractForm.partBPhone=this.faceData.phone;
this.contractForm.partBIdCard=this.faceData.idNumber;
this.contractForm.partBAdress=this.faceData.address;
this.contractForm.workTypeId=this.faceData.workerType;
this.contractForm.proId=this.faceData.proId;
this.contractForm.workType=this.faceData.postId;
if(this.faceData.subId){
this.getPartA()
}
if(this.contractForm.workTypeId=='0'){
this.contractForm.workTypeName='临时人员';
}else if(this.contractForm.workTypeId=='1'){
this.contractForm.workTypeName='固有人员';
}else if(this.contractForm.workTypeId=='2'){
this.contractForm.workTypeName='分包管理人员';
}
// "workTask":"",//工作任务
// "workAdress":"",//工作地点
// "verStand": "",//工资核定标准
this.contractForm.effectDate=this.timeFormat(null,'yyyy-mm-dd');
},
openSignView(type){
this.signType=type;
this.signPopup=true;
},
closeSign(){this.signPopup=false;},
signConfirm(url,localPath){
console.log(url)
this.imgToBase64(localPath).then(base64 => {
if(this.signType==0){
this.bSignImgUrl=base64
this.contractForm.partBSign=url;
}
if(this.signType==1){
this.teamSignImgUrl=base64
this.contractForm.teamSign=url;
}
})
this.signPopup=false;
},
sumbitContract(){
this.$refs.cForm.validate().then(res => {
if(this.contractForm.partB==''){
uni.$u.toast('请先采集人脸信息');
}else if(this.contractForm.workTask==''){
uni.$u.toast('请填写工作任务');
}else if(this.contractForm.workAdress==''){
uni.$u.toast('请填写工作地点');
}else if(this.contractForm.verStand==''){
uni.$u.toast('请填写工资核定标准');
}else if(this.contractForm.effectDate==''){
uni.$u.toast('请选择生效日期');
}else if(this.contractForm.otherSupply==''){
uni.$u.toast('请选择其他补充事项');
}else if(this.contractForm.role==''){
uni.$u.toast('请选择人员角色');
}else if(this.contractForm.partBSign==''){
uni.$u.toast('请采集乙方签名');
}else if(this.contractForm.teamSign==''){
uni.$u.toast('请采集班组长签名');
}else if(this.videoUrl==''){
uni.$u.toast('请确认合同视频');
}else{
this.uploadVideo(this.videoUrl)
}
}).catch(errors => {
console.log(errors)
uni.$u.toast('请填写完整数据!')
})
},
//上传合同视频
uploadVideo(filePath){
uni.uploadFile({
url: config.realFileUrl+`file/upload`, //服务器地址
// fileType:"pdf",//ZFB必填,不然报错
filePath: filePath,//这个就是我们上面拍照返回或者先中照片返回的数组
name: "file",
formData: {
photoType:"contract/video",
},
success: (uploadFileRes) => {
console.log(uploadFileRes);
if(uploadFileRes.statusCode==200){
uploadFileRes=JSON.parse(uploadFileRes.data)
if(uploadFileRes.code==200){
this.contractForm.videoUrl=uploadFileRes.data.url;
this.contractPdf()
}else{
uni.$u.toast(uploadFileRes.msg);
}
}else{
uni.$u.toast('上传失败');
}
}
});
},
//预览合同
contractPdf(){
console.log(this.contractForm)
uni.request({
url: config.realFileUrl+'file/contractPdf',
method: 'post',
data: this.contractForm,
header: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: uni.getStorageSync('realNameToken')
},
success: res => {
console.log(res)
res = res.data;
if(res.code==200){
this.contractForm.personPdfUrl=res.data;
let url=config.realFileUrl+ this.contractForm.personPdfUrl;
uni.navigateTo({
url: `/pages/realName/workbench/electronicContract/contractPdfConfirm?pdfUrl=${url}&contractData=${JSON.stringify(this.contractForm)}`
})
}else{
uni.showToast({
title: res.msg,
icon: 'none'
})
}
},
fail: err => {
console.log(err)
}
})
},
imgToBase64(data) {
return new Promise((resolve, reject) => {
pathToBase64(data)
.then(base64 => {
resolve(base64)
})
.catch(error => {
console.error(error)
reject(error)
})
})
},
timeFormat(dateTime = null, formatStr = 'yyyy-mm-dd') {
let date
// 若传入时间为假值,则取当前时间
if (!dateTime) {
date = new Date()
}
// 若为unix秒时间戳则转为毫秒时间戳逻辑有点奇怪但不敢改以保证历史兼容
else if (/^\d{10}$/.test(dateTime?.toString().trim())) {
date = new Date(dateTime * 1000)
}
// 若用户传入字符串格式时间戳new Date无法解析需做兼容
else if (typeof dateTime === 'string' && /^\d+$/.test(dateTime.trim())) {
date = new Date(Number(dateTime))
}
// 处理平台性差异在Safari/Webkit中new Date仅支持/作为分割符的字符串时间
// 处理 '2022-07-10 01:02:03',跳过 '2022-07-10T01:02:03'
else if (typeof dateTime === 'string' && dateTime.includes('-') && !dateTime.includes('T')) {
date = new Date(dateTime.replace(/-/g, '/'))
}
// 其他都认为符合 RFC 2822 规范
else {
date = new Date(dateTime)
}
const timeSource = {
'y': date.getFullYear().toString(), // 年
'm': (date.getMonth() + 1).toString().padStart(2, '0'), // 月
'd': date.getDate().toString().padStart(2, '0'), // 日
'h': date.getHours().toString().padStart(2, '0'), // 时
'M': date.getMinutes().toString().padStart(2, '0'), // 分
's': date.getSeconds().toString().padStart(2, '0') // 秒
// 有其他格式化字符需求可以继续添加,必须转化成字符串
}
for (const key in timeSource) {
const [ret] = new RegExp(`${key}+`).exec(formatStr) || []
if (ret) {
// 年可能只需展示两位
const beginIndex = key === 'y' && ret.length === 2 ? 2 : 0
formatStr = formatStr.replace(ret, timeSource[key].slice(beginIndex))
}
}
return formatStr
},
// 返回
leftClick() {
console.log('返回')
uni.navigateBack({
delta: 1 // 返回
});
}
},
}
</script>
<style lang="scss">
.page {
width: 100vw;
height: 100vh;
background-color: #FFF;
box-sizing: border-box;
position: relative;
.content{
width: 100%;
height: 92vh;
// margin-top: 20rpx;
padding-bottom: 40rpx;
background-color: #FFF;
}
.face-btn{
width: 92%;
height: 80rpx;
margin: 0 auto;
margin-top: 40rpx;
display: flex;
align-items: center;justify-content: center;
color: #FFF;
background: #00337A;
border-radius: 10rpx;
}
.form-box{
width: 94%;
height: auto;
margin: 0 auto;
margin-top: 20rpx;
.addForm{
width: 100%;
height: auto;
font-size: 26rpx;
.form-input-box{
padding: 0 20rpx;
display: flex;
align-items: center;
// border-bottom: 1rpx solid #eee;
}
}
}
.img-box{
width: 70%;
height: auto;
margin: 0rpx auto;
padding:20rpx;
display: flex;
align-items: center;
border-bottom: 1rpx solid #f8f8f8;
.img-item {
float: left;
width: 200upx;
height: 200upx;
border: 1px solid #ddd;
margin: 0 22rpx 20upx 0upx;
position: relative;
box-sizing: border-box;
background: #eee;
.img {
display: block;
width: 100%;
height: 100%;
}
.remove-btn {
position: absolute;
top: -18upx;
right: -18upx;
width: 44upx;
height: 44upx;
z-index: 2;
}
}
.upload-btn {
display: flex;
justify-content: center;
align-items: center;
.img {
width: 60upx;
height: 60upx;
margin: unset;
}
}
}
.signBtn{
background-color:#00337A;
color: #FFF;
height: 36rpx;
line-height: 36rpx;
padding:10rpx 20rpx;
border-radius: 10rpx;
}
.bottom-box{
width: 90%;
margin: 0 auto;
height: 120rpx;
display: flex;
justify-content: space-between;
align-items: center;
.btn1{
width: 40%;
height: 80rpx;
display: flex;
align-items: center;justify-content: center;
color: #FFF;
background: #00337A;
border-radius: 10rpx;
}
.btn2{
width: 40%;
height: 80rpx;
display: flex;
align-items: center;justify-content: center;
color: #FFF;
background: #00337A;
border-radius: 10rpx;
}
}
}
</style>