Files
supplier-dispatch-h5/src/views/index/supplierAdd.vue
2025-10-23 11:39:01 +08:00

555 lines
17 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 class="wrap">
<div class="top_banner">
<img src="@/assets/supplier/topBg.png" alt="">
</div>
<van-form @submit="applyAdd">
<div class="content_wrap">
<div class="credentials_info">
<img class="title1" src="@/assets/supplier/title1.png" alt="">
<div class="credentials_wrap">
<div class="credentials_item">
<div class="credentials_title">1. 法人身份证正面</div>
<van-uploader
accept="image/*"
v-model="idFrontPhotoList"
:after-read="idFrontPhotoHandler"
:max-size="5 * 1024 * 1024"
max-count="1">
<div class="custom-background">
<img src="@/assets/supplier/idCardPerson.png" alt="">
</div>
</van-uploader>
</div>
<div class="credentials_item ml2">
<div class="credentials_title">2. 法人身份证反面</div>
<van-uploader
accept="image/*"
v-model="idBackPhotoList"
:after-read="idBackPhotoHandler"
:max-size="5 * 1024 * 1024"
max-count="1">
<div class="custom-background">
<img src="@/assets/supplier/idCardBack.png" alt="">
</div>
</van-uploader>
</div>
<div class="credentials_item ml2">
<div class="credentials_title">3. 营业执照</div>
<van-uploader
accept="image/*"
v-model="companyPhotoList"
:after-read="companyPhotoHandler"
:max-size="5 * 1024 * 1024"
max-count="1">
<div class="custom-background">
<img src="@/assets/supplier/companyPhoto.png" alt="">
</div>
</van-uploader>
</div>
</div>
</div>
<div class="company_info">
<img class="title2" src="@/assets/supplier/title2.png" alt="">
<div class="company_wrap">
<van-field :border="true" readonly v-model="form.name" class="required" name="name" label="服务商名称" placeholder="请输入" :rules="[{ required: true, message: '请输入服务商名称' }]" />
<van-field :border="true" readonly v-model="form.areaName" class="required" name="areaName" label="注册地址" placeholder="请输入" :rules="[{ required: true, message: '请输入注册地址' }]" />
<van-field :border="true" readonly v-model="form.legalName" class="required" name="legalName" label="法人姓名" placeholder="请输入" :rules="[{ required: true, message: '请输入法人姓名' }]" />
<van-field :border="true" v-model="form.linkName" class="required" name="linkName" label="联系人姓名" placeholder="请输入" :rules="[{ required: true, message: '请输入联系人姓名' }]" />
<van-field :border="true" v-model="form.linkPhone" class="required" name="linkPhone" label="联系电话" placeholder="请输入" :rules="phoneVerify" />
<van-field :border="true" class="required" name="serviceType" label="服务能力">
<template #input>
<el-tree
show-checkbox
node-key="id"
ref="tree"
:highlight-current="true"
:expand-on-click-node="false"
:data="supplierServiceList"
:props="defaultProps">
</el-tree>
</template>
</van-field>
<van-field :border="true" v-model="form.trailCount" name="trailCount" label="拖车数量" placeholder="请输入" />
<van-field :border="true" v-model="form.minorCount" name="minorCount" label="抢修车数量" placeholder="请输入" />
<van-field :border="true" class="required" label="服务区域" placeholder="请选择">
<template #input>
<el-cascader
v-model="form.serviceAreaCode"
:options="areaList"
:props="areaProps"
ref="areaCascader"
popper-class="responsive-cascader"
:popper-append-to-body="false"
clearable></el-cascader>
</template>
</van-field>
<div class="wei_code_wrap" v-if="form.name && !id">
<div class="wei_title">请先添加企业微信保证申请流程正常进行</div>
<div class="wei_code_bg">
<img v-if="qrCodeUrl" :src="qrCodeUrl" alt="企业微信二维码" />
</div>
</div>
</div>
</div>
</div>
<div class="btn_wrap">
<van-button class="btn" block type="info" :native-type="'submit'">提交申请</van-button>
</div>
</van-form>
<van-popup
v-model="areaShow"
position="bottom"
>
<van-area title="服务区域" :area-list="areaList" :columns-num="3" closeable="true" :value="form.areaCode ? String(form.areaCode) : ''"
@cancel="areaShow = false" @confirm="confirmHandle"/>
</van-popup>
</div>
</template>
<script>
import {leftCopy} from "@/utils/common"
import QRCode from 'qrcode'
import { uploadImage, supplierServicePartTree, ocrHandler, unifiedOCRWithCompress, getArea, saveSupplier, getSupplierInfo, getOrCodeInfo, getContactQrCodeResult } from "@/api/mine"
import {myMixins} from "@/utils/myMixins"
import {Dialog} from "vant";
export default {
name: "supplierAdd",
mixins:[myMixins],
data() {
return {
clickFlag: true,
phoneVerify: [{ required: true, message: '请输入联系电话' }, { validator: value => { return /^1[3456789]\d{9}$/.test(value) }, message: '联系电话格式不正确' }],
id:'', //车辆Id
idBackPhotoList: [],
idBackPhoto: '',
idFrontPhotoList: [],
idFrontPhoto: '',
companyPhotoList: [],
companyPhoto: '',
form: {
name: '',
legalName: '',
areaName: '',
linkName: '',
linkPhone: '',
serviceType: '',
trailCount: '',
minorCount: '',
serviceAreaCode: [],
},
qrCodeUrl: '',
qrCode: '',
areaShow: false,
areaList: [],
supplierServiceList: [],
defaultProps: {
children: 'children',
label: 'title'
},
areaProps: { multiple: true, checkStrictly: true, value: 'id',label: 'title', emitPath: false, },
configId: '',
wechatId: '',
}
},
async mounted() {
const urlParams = new URLSearchParams(window.location.search);
this.id = this.$route.query.id || urlParams.get('id');
await this.getAreaTree();
if(this.id) {
await this.getInfoHandler();
}
await this.getSupplierServiceTree();
},
methods: {
async QrCodeHandler() {
await this.QrCodeInfo()
await this.getQrCode();
},
async QrCodeInfo() {
let res = await getOrCodeInfo({
name: this.form.name
});
this.configId = res?.configId;
this.qrCode = res?.qrCode
console.log('idid', res);
},
async getInfoHandler() {
let res = await getSupplierInfo({
id: this.id
});
let _data = res?.data
leftCopy(this.form, {..._data})
this.idFrontPhoto = _data?.idCardFrontUrl;
this.idBackPhoto = _data?.idCardBackUrl;
this.companyPhoto = _data?.businessLicense;
this.wechatId = _data?.wechatId
if(this.idFrontPhoto) {
this.idFrontPhotoList = [{ url : this.idFrontPhoto }];
}
if(this.idBackPhoto) {
this.idBackPhotoList = [{ url : this.idBackPhoto }];
}
if(this.companyPhoto) {
this.companyPhotoList = [{ url : this.companyPhoto }];
}
if( _data.serviceType ) {
this.$refs.tree.setCheckedKeys(_data.serviceType.split(','))
}
if(_data?.serviceAreaCode) {
this.$set(this.form, 'serviceAreaCode', _data?.serviceAreaCode.split(',').map(item => Number(item)));
// this.form.serviceAreaCode = _data?.serviceAreaCode.split(',').map(item => Number(item));
}
},
async applyAdd() {
if( !this.idFrontPhoto ) {
this.$toast('法人身份证正面照未上传')
return
}
if( !this.idBackPhoto ) {
this.$toast('法人身份证反面照未上传')
return
}
if( !this.companyPhoto ) {
this.$toast('营业执照未上传')
return
}
if( !(this.form.serviceAreaCode.length > 0) ) {
this.$toast('服务区域不能为空')
return
}
if(!this.wechatId) {
await this.QrCodeResult();
if( !this.wechatId ) {
this.$toast('请先添加企微再申请')
return
}
}
if( this.$refs.tree.getCheckedKeys().length > 0 ) {
await this.saveHandler()
} else {
this.$toast('服务能力不能为空')
return
}
},
async QrCodeResult() { //获取添加企微结果
let res = await getContactQrCodeResult({
configId: this.configId
});
console.log('resres', res)
this.wechatId = res?.data?.wechatId
},
async saveHandler() {
if( this.clickFlag ) {
try {
this.clickFlag = false
let _node = this.$refs.areaCascader.getCheckedNodes();
let checkArr = [];
_node.map(item => {
checkArr.push(item.data.id)
})
let res = await saveSupplier({
id: this.id,
...this.form,
idCardFrontUrl: this.idFrontPhoto,
idCardBackUrl: this.idBackPhoto,
businessLicense: this.companyPhoto,
serviceType: this.$refs.tree.getCheckedKeys().join(','),
serviceAreaCode: checkArr.join(','),
wechatId: this.wechatId,
});
Dialog.alert({
title: '提示',
message: "操作成功"
}).then(async () => {
this.goPage('supplierAddResult', { id : res?.data })
this.clickFlag = true
});
} finally {
this.clickFlag = true
}
}
},
async getAreaTree() {
let res = await getArea();
this.areaList = res?.data;
},
async getSupplierServiceTree(){
let res = await supplierServicePartTree({
serviceTypes: '1002,1003',
treeType: 2
});
this.supplierServiceList=res.data
},
confirmHandle(val){
this.region=[]
val?.forEach(item => this.region.push(item.name))
let code=[]
val?.forEach(item => code.push(item.code))
this.form.areaCode=code[code.length - 1]
this.areaShow=false
},
async getQrCode() {
try {
this.qrCodeUrl = await QRCode.toDataURL(this.qrCode, {
width: 150,
margin: 2,
color: {
dark: '#000000',
light: '#FFFFFF'
},
})
} catch (error) {
console.error('生成二维码失败:', error)
}
},
async idBackPhotoHandler(file) {
const formData = new FormData();
formData.append("file" , file.file);
let res = await uploadImage(formData);
this.idBackPhoto = res.data
},
async idFrontPhotoHandler(file) {
const formData = new FormData();
formData.append("file" , file.file);
let res = await uploadImage(formData);
this.idFrontPhoto = res.data;
await this.idCardOcrHandler();
},
async idCardOcrHandler() { // 身份证正面 ocr识别
this.form.legalName = '';
let res = await ocrHandler({
ocrType: 1,
imageUrl: this.idFrontPhoto,
cardSide: 'FRONT'
})
this.form.legalName = res?.data?.name
},
async companyPhotoHandler(file) {
const formData = new FormData();
formData.append("file" , file.file);
let res = await uploadImage(formData);
this.companyPhoto = res.data
await this.companyOcrHandler()
},
async companyOcrHandler() { // 营业照 ocr识别
this.form.name = '';
this.form.areaName = '';
let res = await unifiedOCRWithCompress({
ocrType: 7,
imageUrl: this.companyPhoto,
cardSide: 'FRONT'
})
this.form.name = res?.data?.name;
this.form.areaName = res?.data?.address
await this.QrCodeHandler();
},
},
computed: {
regionText() {
return this.region.length ? `${this.region[0]}/${this.region[1]}/${this.region[2]}` : '请选择所在地区';
}
},
}
</script>
<style scoped lang="scss">
@import "@/styles/mixin.scss";
@import "@/styles/common.scss";
.wrap{
@include wh(100%,100%);
box-sizing: border-box;
padding-bottom: 100px;
overflow-y: auto;
}
.top_banner {
width: 100%;
img {
width: 100%;
height: 169px;
}
}
.content_wrap {
padding: 0 20px;
}
.credentials_info {
height: 170px;
}
.credentials_wrap {
display: flex;
width: 100%;
margin-top: 10px;
.credentials_item {
width: 32%;
text-align: center;
.credentials_title {
font-size: 12px;
color: #4A4A4A;
padding: 10px 0;
}
.custom-background img {
width: 97px;
height: 64px;
}
}
.ml2 {
margin-left: 2%;
}
}
::v-deep .van-uploader__preview-image {
width: 97px;
height: 64px;
}
.title1 {
width: 106px;
height: 19px;
margin-top: 25px;
}
.title2 {
width: 90px;
height: 18px;
margin-top: 25px;
margin-bottom: 10px;
}
.van-cell.required::before{
content: "";
position: absolute;
color: #F00;
left: 0px;
top: .25rem;
font-size: .3rem;
}
.wei_code_wrap {
margin-top: 10px;
.wei_title {
font-size: 15px;
color: #FF553B;
text-align: center;
}
.wei_code_bg {
width: 163px;
height: 173px;
background-image: url("~@/assets/supplier/weiCodeBg.png");
background-size: 100% 100%;
margin: 8px auto;
display: flex;
align-items: center;
justify-content: center;
}
}
.btn_wrap {
width: 100%;
padding: 15px 0;
position: fixed;
bottom: 0;
background: #F7F7F9;
box-shadow: 0px -7px 24px 0px rgba(0, 0, 0, 0.11);
z-index: 10000 !important;
.btn {
width: calc(100% - 80px);
margin-left: 40px;
height: 46px;
background: #0E76F4;
border-radius: 5px;
font-size: 15px;
color: #FFFFFF;
text-align: center;
line-height: 46px;
}
}
/*::v-deep .el-cascader {
width: 100% !important;
}
::v-deep .el-input__inner {
width: 100% !important;
border: none !important;
padding-left: 0 !important;
background: transparent !important;
}
::v-deep .el-input {
width: 100% !important;
}
::v-deep .el-input__suffix {
right: 0 !important;
}*/
</style>
<style>
.responsive-cascader .el-cascader-menu {
min-width: 100px !important;
}
.responsive-cascader .el-cascader-panel {
font-size: 12px !important;
}
.responsive-cascader .el-cascader-node {
padding-left: 5px !important;
padding-right: 4px !important;
}
/* !* 级联选择器下拉框样式 *!
.responsive-cascader {
width: 90vw !important;
max-width: 400px !important;
left: 50% !important;
transform: translateX(-50%) !important;
}
.responsive-cascader .el-cascader-panel {
display: flex !important;
width: 100% !important;
max-height: 60vh !important;
}
.responsive-cascader .el-cascader-node {
padding: 12px 16px !important;
font-size: 12px !important;
height: 20px !important;
!*min-height: 44px !important;*!
display: flex !important;
align-items: center !important;
}
.responsive-cascader .el-cascader-node__label {
font-size: 12px !important;
white-space: nowrap !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
flex: 1 !important;
}
!* 移动端触摸优化 *!
.responsive-cascader .el-cascader-node {
padding: 6px 6px !important;
}
!* 选中状态 *!
.responsive-cascader .el-cascader-node.in-active-path,
.responsive-cascader .el-cascader-node.is-active {
color: #1989fa !important;
background-color: #f2f8ff !important;
}
!* 移动端适配 *!
@media (max-width: 768px) {
.responsive-cascader {
width: 95vw !important;
max-width: none !important;
}
.responsive-cascader .el-cascader-menu {
width: 33.33% !important;
flex: none !important;
}
.responsive-cascader .el-cascader-node__label {
font-size: 13px !important;
}
}*/
</style>