前言
公司在做合同签章业务,需要合同和签署人签署多个印章的问题,需要对印章进行拖拽,
实现
效果图如下
文件列表和签约方可以选择切换,通过拖动标签的印章类型来实现印章的位置预览
预先定义印章类型和一些基础数据
vue3中通过import将印章的背景图片引入
拖动标签位置的vue代码
拖动标签位置的js代码和处理逻辑
drop(e, index, iten) {
// 获取拖拽对象的参数
let data = e.dataTransfer.getData("item");
data = JSON.parse(data);
// 鼠标落点位置相对于当前拖拽存放地的 x y
if (data.type === "crossSign") {
data.left = 840 - data.widthX;
} else {
data.left = e.layerX;
}
if (data.type === "text") {
// 设置文本空间宽高
data.width = 2;
data.height = 1;
}
data.top = e.layerY;
data.fileIndex = index;
data.pageNum = index + 1;
data.id = Math.round(Math.random() * 1000000000);
// 转为后端需要的cm格式
data.x = +((Math.abs(data.left) + data.widthX / 2) / 1188).toFixed(2);
data.y = +(1 - +Math.abs(1188 - data.top - data.heightH / 2) / 1188).toFixed(2);
console.log("data", data);
// 存放到当前拖拽对象生成的列表中
// 显示拖拽印章的 - 操作
this.signTypeFun(data.type);
this.dropData.push(data);
if (!this.fileCheckList[this.fileListIndex]) {
// 当整个数据结构都为空时
this.fileCheckList.push({
signFiles: [],
...this.signerList[this.signIndex]
});
this.fileCheckList[this.fileListIndex].signFiles[this.signIndex] = {
docId: `${this.fileList[this.fileListIndex].id}`,
xySignControls: [
{
...data,
signName: `${this.signerList[this.signIndex].name} - ${this.signerList[this.signIndex].enterpriseName}`
}
]
};
if (data.type === "crossSign") {
this.fileCheckList[this.fileListIndex].signFiles[this.signIndex] = {
docId: `${this.fileList[this.fileListIndex].id}`,
crossSignControls: [
{
...data,
signName: `${this.signerList[this.signIndex].name} - ${this.signerList[this.signIndex].enterpriseName}`
}
],
xySignControls: [
{
...data,
signName: `${this.signerList[this.signIndex].name} - ${this.signerList[this.signIndex].enterpriseName}`
}
]
};
}
} else {
// 切换签约方
if (!this.fileCheckList[this.fileListIndex].signFiles[this.signIndex]) {
this.fileCheckList[this.fileListIndex].signFiles[this.signIndex] = {
docId: `${this.fileList[this.fileListIndex].id}`,
xySignControls: [
{
...data,
signName: `${this.signerList[this.signIndex].name} - ${this.signerList[this.signIndex].enterpriseName}`
}
]
};
if (data.type === "crossSign") {
this.fileCheckList[this.fileListIndex].signFiles[this.signIndex] = {
docId: `${this.fileList[this.fileListIndex].id}`,
crossSignControls: [
{
...data,
docId: `${this.fileList[this.fileListIndex].id}`,
signName: `${this.signerList[this.signIndex].name} - ${this.signerList[this.signIndex].enterpriseName}`
}
],
xySignControls: [
{
...data,
docId: `${this.fileList[this.fileListIndex].id}`,
signName: `${this.signerList[this.signIndex].name} - ${this.signerList[this.signIndex].enterpriseName}`
}
]
};
}
} else {
this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].xySignControls.push({
...data,
signName: `${this.signerList[this.signIndex].name} - ${this.signerList[this.signIndex].enterpriseName}`
});
if (data.type === "crossSign") {
if (!this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].crossSignControls) {
this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].crossSignControls = [];
}
this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].crossSignControls.push({
...data,
signName: `${this.signerList[this.signIndex].name} - ${this.signerList[this.signIndex].enterpriseName}`
});
}
}
}
console.log("draoData", this.fileCheckList);
},
点击获取到印章组件的信息,方便印章的删除操作
getModel(e, item, index) {
this.dropSelectIndex = index;
this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].xySignControls = this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].xySignControls.map((item) => {
item.selectName = "";
return item;
});
item.selectName = "select";
this.signTypeFun(item.type);
e.stopPropagation();
},
拖动的印章可支持删除
// 删除印章
handleDeleteSeal(type) {
if (type === 0) {
this.isSealDrap = false;
this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].xySignControls.splice(this.dropSelectIndex, 1);
} else if (type === 1) {
this.isSeaming = false;
this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].xySignControls.splice(this.dropSelectIndex, 1);
} else if (type === 2) {
this.isSignature = false;
this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].xySignControls.splice(this.dropSelectIndex, 1);
} else if (type === 3) {
this.isDate = false;
this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].xySignControls.splice(this.dropSelectIndex, 1);
} else if (type === 4) {
this.isText = false;
this.fileCheckList[this.fileListIndex].signFiles[this.signIndex].xySignControls.splice(this.dropSelectIndex, 1);
}
},
整个组件基本代码如下:
<template>
<div
class="card"
ref="inCcard"
v-loading='loading'
element-loading-text="准备表单中..">
<el-row>
<el-col :span="10">
</el-col>
<el-col :span="24">
<el-card class="box-card box" shadow='never'>
<el-card class="box-card" style="margin-bottom:5px;">
<Steps :active='active'></Steps>
</el-card>
<el-scrollbar class="height nav" v-show="active === 1">
<BussineInfo
ref="bussineInfo"
:detailsInfo="projectDetailsInfo"
:bankList="bankList"
:companyList="companyList"
@refersh="getDetails"
@addForm="handleGetBussineeInfo" />
<BindProject
v-if="('fdbOrderProjectDTOList' in bussineInfoData || 'fdbOrderProjectDTOList' in projectDetailsInfo) && (bussineInfoData.id !== null || projectDetailsInfo.id !== null) "
ref="bindProject"
:detailsInfo="projectDetailsInfo"
:guaranteeTypeList="guaranteeTypeList"
@refersh="getDetails" />
<div
v-if="('fdbGroupDTOList' in bussineInfoData || 'fdbGroupDTOList' in projectDetailsInfo) && (bussineInfoData.id !== null || projectDetailsInfo.id !== null) ">
<FdbConfig
ref="fdbConfig"
v-if="$route.params.type === 'add'"
:groupMaxCount='bussineInfoData.groupMaxCount'
:detailsInfo="projectDetailsInfo"
@refersh="getDetails"/>
<FdbConfig
ref="fdbConfig"
v-if="$route.params.type === 'update'"
:groupMaxCount='bussineInfoData.groupMaxCount'
:detailsInfo="projectDetailsInfo"
@refersh="getDetails"/>
<FdbConfig
ref="fdbConfig"
v-if="$route.params.type === 'confirmUpdate'"
:groupMaxCount='bussineInfoData.groupMaxCount'
:detailsInfo="projectDetailsInfo"
@refersh="getDetails"/>
</div>
<div
class="step-btn"
v-if="('in' in bussineInfoData || 'fdbOrderProjectDTOList' in projectDetailsInfo) && (bussineInfoData.id !== null || projectDetailsInfo.id !== null) ">
<el-button @click="handlePreStep">取 消</el-button>
<el-button type="primary" class="step-next" :loading="btnLoading" @click="handleNextStep" >保存</el-button>
<el-button type="primary" class="step-next" v-if="this.$route.params.type !=='confirmUpdate' && Number(projectDetailsInfo.businessStatus) !== 7" :loading="btnLoading" @click="handleGoAudit" >去审核</el-button>
</div>
</el-scrollbar>
<el-card class="box-card box" shadow='never' v-if="active === 2">
<AwaitingAudit/>
</el-card>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import {
getConfigTypeList
} from '@/api/fdb/configManagement'
import {
saveAndUpdateOrderToReceiver, // 接单员 - 创建订单
updateStatus // 接单员 - 去审核
} from '@/api/fdb/fdbgroup'
import {
sendSms,
createOrderContractPDF
} from '@/api/fdb/orderVerification'
import Steps from './components/steps.vue' // 步进器
import BussineInfo from './components/bussinessInfo.vue' // 业务信息
import BindProject from './components/bindProject.vue' // 绑定项目
import FdbConfig from './components/fdbConfig.vue' // 反担保配置
import AwaitingAudit from './components/awaitingAudit.vue' // 待审核
export default {
components: {
Steps,
BussineInfo,
BindProject,
FdbConfig,
AwaitingAudit
},
data () {
return {
loading: false,
active: 1,
companyList: [],
bankList: [],
guaranteeTypeList: [],
projectDetailsInfo: {}, // 订单详情
bussineInfoData: {}, // 订单信息
btnLoading: false
}
},
created () {
this.handleSelectChange()
if (this.$route.params.type !== 'add') {
this.init()
}
},
methods: {
// 修改-查询详情
init () {
this.loading = true
// 获取当前管理员信息
return this.$http.get(`/fdb/fdborder/${this.$route.params.projectId}`).then(({ data: res }) => {
this.loading = false
this.projectDetailsInfo = res && res.data
}).catch(() => {})
},
getDetails (id) {
this.$http.get(`/fdb/fdborder/${id}`).then(({ data: res }) => {
this.projectDetailsInfo = res && res.data
}).catch(() => {})
},
// 获取通用类型 - 配置项
async handleSelectChange () {
this.guaranteeTypeList = []
this.companyList = []
this.bankList = []
const { data: res } = await getConfigTypeList({
deptId: this.$store.state.user.deptId,
sceneType: this.$route.params.insuranceCode
})
if (!Number(res.code) === 0) return false
// data 返回值 1:保函类型 2:银行 3:担保公司
// 保函类型
res.data[1].map(item => {
if (Number(item.isTick) === 1) {
return this.guaranteeTypeList.push(item)
}
})
// 担保公司
res.data[2].map(item => {
if (Number(item.isTick) === 1) {
return this.companyList.push(item)
}
})
// 银行
res.data[3].map(item => {
if (Number(item.isTick) === 1) {
return this.bankList.push(item)
}
})
},
// 关闭
handlePreStep () {
this.$router.back(-1)
},
// 去审核
handleGoAudit () {
this.$refs.bussineInfo.$refs.addForm.validate(async (valid) => {
if (valid) {
this.btnLoading = true
const { id } = this.bussineInfoData
const data = {
id,
businessStatus: 2
}
const { data: res } = await updateStatus(data)
this.btnLoading = false
if (res.code !== 0) return false
this.$message.success(`${res.msg}`)
this.$router.back(-1)
} else {
this.$message.error('表单信息请填写完整!')
return false
}
})
},
// 保存
handleNextStep () {
this.$refs.bussineInfo.$refs.addForm.validate(async (valid) => {
if (valid) {
this.btnLoading = true
if (this.$route.params.type === 'confirmUpdate') { // 批改后 直接发起签章
// 先生成pdf
createOrderContractPDF({ id: this.$route.params.projectId }).then(res => {
if (res.data.code === 0) {
sendSms({ id: this.$route.params.projectId }).then((res) => { // 发送短信
if (res.data.code === 0) {
this.btnLoading = false
this.$message.success('审核完成,已发起签章!')
this.$router.back(-1)
} else {
this.btnLoading = false
}
}).catch(() => {
this.btnLoading = false
})
}
}).catch(() => {
this.loading = false
})
} else {
const data = {
...this.bussineInfoData
// sceneName: this.$route.params.insuranceName
}
const { data: res } = await saveAndUpdateOrderToReceiver(data)
if (this.$route.params.type === 'confirmUpdate') { // 批改更改状态
const { id } = this.bussineInfoData
const data = {
id,
businessStatus: 3
}
const { data: res } = await updateStatus(data)
if (res.code !== 0) return false
this.$router.back(-1)
}
if (res.code !== 0) return false
let msg = this.$route.params.type === 'add' ? '保存' : '修改'
this.$message.success(`${msg}成功!`)
if (this.$route.params.type !== 'confirmUpdate') {
this.$router.back(-1)
}
}
} else {
this.$message.error('表单信息请填写完整!')
return false
}
})
},
// 暂存
handleTemporaryStorage () {
},
// 获取添加的订单信息
handleGetBussineeInfo (data) {
this.bussineInfoData = data
}
}
}
</script>
<style lang="scss" scoped>
.box {
height: calc(100vh - 100px);
}
.height {
height: 100%;
}
.nav{
height: calc(100% - 100px);
}
.step-btn {
margin-top: 40px;
text-align: center;
}
.step-next {
margin-left: 20px;
}
</style>