合同签署 合同审核 接口完善 页面优化

This commit is contained in:
BianLzhaoMin 2025-12-23 10:17:13 +08:00
parent cf7f5eb115
commit cd3d71586b
6 changed files with 926 additions and 21 deletions

View File

@ -1,6 +1,11 @@
<template>
<view class="select-all-container" :style="containerStyle">
<up-button text="全选" type="primary" :customStyle="buttonStyle" @tap="handleSelectAll" />
<up-button
type="primary"
@tap="handleSelectAll"
:customStyle="buttonStyle"
:text="isAllChecked ? '取消全选' : '全选'"
/>
</view>
</template>
@ -8,15 +13,13 @@
import { computed } from 'vue'
import { getSafeAreaInfo } from '@/utils/safeArea'
/**
* 审核页面全选按钮组件
* 业务背景用于批量操作场景提供全选功能
* 设计决策
* 1. 固定在底部右侧方便用户操作
* 2. 适配安全区确保在底部有安全区的设备上正常显示
* 3. 使用国网绿主题色保持视觉一致性
*/
const emit = defineEmits(['selectAll'])
const props = defineProps({
isAllChecked: {
type: Boolean,
default: false,
},
})
//
const containerStyle = computed(() => {

View File

@ -250,6 +250,14 @@
"navigationBarBackgroundColor": "#07c160"
}
},
{
"path": "pages/work/contract-sign/detail",
"style": {
"navigationBarTitleText": "电子合同信息",
"navigationStyle": "custom",
"navigationBarBackgroundColor": "#07c160"
}
},
{
"path": "pages/work/wage-view/index",
"style": {

View File

@ -103,6 +103,16 @@
<text class="label" style="margin-left: 20rpx">签订日期</text>
<text class="value">{{ item.signingDate }}</text>
</view>
<view class="row" v-if="activeTab != 0">
<text class="label">甲方签署状态</text>
<text
class="value"
:style="{ color: item.isSign == 1 ? '#4caf50' : '#ed7b2f' }"
>
{{ item.isSign == 1 ? '已签署' : '待签署' || '-' }}
</text>
</view>
</view>
</view>
</scroll-view>

View File

@ -0,0 +1,737 @@
<template>
<view class="page-container">
<!-- 导航栏 -->
<NavBarModal navBarTitle="电子合同信息">
<template #left>
<view class="back-btn" @tap="handleBack">
<up-icon name="arrow-left" size="20" color="#fff" />
</view>
</template>
</NavBarModal>
<!-- 内容区域 -->
<view class="content-wrapper" :style="contentStyle">
<!-- 下拉选择器 -->
<view v-if="documentOptions.length > 0" class="picker-section">
<CommonPicker
placeholder="请选择文档"
:options="documentOptions"
v-model="currentDocumentValue"
@change="handleDocumentChange"
/>
</view>
<view v-if="error" class="error-wrapper">
<up-icon name="close-circle" size="80" color="#e34d59" />
<text class="error-text">{{ error }}</text>
<up-button
text="重试"
type="primary"
size="small"
:customStyle="{ marginTop: '32rpx' }"
@tap="loadDocument"
/>
</view>
<view v-if="pdfUrl" class="document-wrapper">
<DocumentPreview
:file-url="pdfUrl"
file-type="pdf"
preview-service="pdfjs"
:auto-load="true"
:show-retry="true"
:show-download="true"
:container-style="{ width: '100%', height: '100%' }"
@load="handleDocumentLoad"
@error="handleDocumentError"
/>
</view>
<!-- 空状态 -->
<view v-else class="empty-wrapper">
<up-icon name="file-text" size="80" color="#ccc" />
<text class="empty-text">暂无文档</text>
</view>
<!-- 底部按钮 -->
<view class="button-section">
<up-button
text="返回"
type="default"
:customStyle="backButtonStyle"
@tap="handleBack"
/>
<template v-if="!isSigned">
<up-button
text="查看视频"
type="default"
:customStyle="videoButtonStyle"
@tap="handleViewVideo"
/>
<up-button
text="签署"
type="primary"
:customStyle="signButtonStyle"
@tap="handleSign"
/>
</template>
</view>
</view>
<!-- 签署弹窗 -->
<up-popup :show="showSignModal" mode="center" round="20" @close="handleCancelSign">
<view class="sign-popup">
<view class="sign-title">签署</view>
<scroll-view class="sign-body" scroll-y>
<view class="sign-block">
<text class="block-title">确认信息</text>
<view class="info-text">
<text>您确定要签署这份合同吗</text>
</view>
</view>
<view class="stamp-section">
<up-button
text="获取公章"
type="primary"
@tap="handleGetStamp"
:customStyle="getStampButtonStyle"
:loading="stampLoading"
/>
<view class="stamp-label">电子公章</view>
<view class="stamp-preview" v-if="stampImageUrl">
<image :src="stampImageUrl" mode="aspectFit" class="stamp-image" />
</view>
<view v-else class="stamp-placeholder">
<text class="placeholder-text">暂无公章</text>
</view>
</view>
<view class="sign-actions">
<up-button
text="取消"
type="default"
@tap="handleCancelSign"
:customStyle="cancelBtnStyle"
/>
<up-button
text="确认"
type="primary"
@tap="handleConfirmSign"
:customStyle="confirmBtnStyle"
/>
</view>
</scroll-view>
</view>
</up-popup>
<!-- 视频全屏弹窗 -->
<up-popup :show="showVideoModal" mode="center" round="20" @close="showVideoModal = false">
<view class="video-popup">
<view class="video-header">
<text class="video-title">查看视频</text>
<up-icon name="close" size="24" color="#333" @tap="showVideoModal = false" />
</view>
<view class="video-container">
<video
v-if="videoUrl"
:src="videoUrl"
controls
class="video-player"
:enable-play-gesture="true"
:show-fullscreen-btn="true"
:show-center-play-btn="true"
:enable-progress-gesture="true"
object-fit="contain"
></video>
<view v-else class="video-empty">
<text>暂无视频</text>
</view>
</view>
</view>
</up-popup>
</view>
</template>
<script setup>
import { ref, computed } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import NavBarModal from '@/components/NavBarModal/index.vue'
import DocumentPreview from '@/components/DocumentPreview/index.vue'
import CommonPicker from '@/components/CommonPicker/index.vue'
import { getContentStyle } from '@/utils/safeArea'
import { signContractAPI, getUserElectronicStampAPI } from '@/services/realName/contractSign'
import { useMemberStore, useCommonStore } from '@/stores'
import dayjs from 'dayjs'
const memberStore = useMemberStore()
const commonStore = useCommonStore()
const contentStyle = computed(() => {
return getContentStyle({
includeNavBar: true,
includeStatusBar: true,
includeBottomSafeArea: false,
})
})
//
const contractData = ref({})
// PDFURL
const pdfUrl = ref('')
// URL
const videoUrl = ref('')
//
const isSigned = ref(false)
//
const showSignModal = ref(false)
const cancelBtnStyle = { flex: 1, marginRight: '16rpx' }
const confirmBtnStyle = { flex: 1 }
//
const showVideoModal = ref(false)
//
const loading = ref(false)
//
const error = ref('')
//
const stampImageUrl = ref('')
const stampImagePath = ref('')
const stampLoading = ref(false)
const getStampButtonStyle = {
width: '100%',
height: '88rpx',
marginBottom: '24rpx',
}
//
const documentOptions = ref([])
const currentDocumentValue = ref('contract')
//
const backButtonStyle = computed(() => {
return {
flex: 1,
marginRight: '16rpx',
backgroundColor: '#fff',
border: '1rpx solid #07c160',
color: '#07c160',
}
})
const videoButtonStyle = computed(() => {
return {
flex: 1,
marginRight: '16rpx',
backgroundColor: '#fff',
border: '1rpx solid #07c160',
color: '#07c160',
}
})
const signButtonStyle = computed(() => {
return {
flex: 1,
backgroundColor: '#07c160',
borderColor: '#07c160',
}
})
/**
* 初始化文档选项
*/
const initDocumentOptions = () => {
const options = []
if (contractData.value.personPdfUrl) {
options.push({ label: '电子合同', value: 'contract' })
}
if (contractData.value.aqxysPath) {
options.push({ label: '安全协议书', value: 'safety' })
}
documentOptions.value = options
if (options.length > 0) {
currentDocumentValue.value = options[0].value
handleDocumentChange({ value: options[0].value })
}
}
/**
* 处理文档切换
*/
const handleDocumentChange = (option) => {
const value = option.value || option
if (value === 'contract') {
loadDocument(contractData.value.personPdfUrl)
} else if (value === 'safety') {
loadDocument(contractData.value.aqxysPath)
}
}
/**
* 返回上一页
*/
const handleBack = () => {
uni.navigateBack()
}
/**
* 查看视频
*/
const handleViewVideo = () => {
if (!videoUrl.value) {
uni.$u.toast('暂无视频')
return
}
showVideoModal.value = true
}
/**
* PDF加载完成
*/
const handleDocumentLoad = (data) => {
console.log('PDF加载完成:', data)
loading.value = false
}
/**
* PDF加载错误
*/
const handleDocumentError = (data) => {
console.error('PDF加载失败:', data)
error.value = data.error || 'PDF加载失败'
loading.value = false
}
/**
* 签署
*/
const handleSign = () => {
showSignModal.value = true
}
/**
* 取消签署
*/
const handleCancelSign = () => {
showSignModal.value = false
stampImageUrl.value = '' //
stampImagePath.value = ''
}
/**
* 获取公章
*/
const handleGetStamp = async () => {
const phone = memberStore.realNameUserInfo.phone
if (!phone) {
uni.$u.toast('手机号不存在')
return
}
stampLoading.value = true
try {
const res = await getUserElectronicStampAPI({ phone })
if (res.res === 1 && res.obj) {
const imageUrl = res?.obj?.sealUrl
stampImagePath.value = imageUrl
if (imageUrl) {
// URL
if (imageUrl.startsWith('http')) {
stampImageUrl.value = imageUrl
} else {
stampImageUrl.value = import.meta.env.VITE_API_FILE_ASE_URL + imageUrl
}
uni.$u.toast('获取公章成功')
} else {
uni.$u.toast('未找到公章信息')
}
} else {
uni.$u.toast(res.resMsg || '获取公章失败')
}
} catch (err) {
console.error('获取公章失败:', err)
uni.$u.toast('获取公章失败,请稍后重试')
} finally {
stampLoading.value = false
}
}
/**
* 确认签署
*/
const handleConfirmSign = () => {
handleSignContract()
}
/**
* 签署操作
*/
const handleSignContract = async () => {
if (!contractData.value.id) {
uni.$u.toast('合同信息不完整')
return
}
if (!stampImagePath.value) {
uni.$u.toast('请先获取公章')
return
}
uni.showLoading({
title: '签署中...',
mask: true,
})
try {
const res = await signContractAPI({
companySeal: stampImagePath.value, //
subPdfUrl: contractData.value.personPdfUrl,
legalSeal: null,
aqxysPath: contractData.value.aqxysPath,
partBIdCard: contractData.value.partBIdCard,
id: contractData.value.id,
isSign: 1,
})
uni.hideLoading()
if (res.res == 1) {
uni.$u.toast('签署成功')
showSignModal.value = false
//
setTimeout(() => {
uni.navigateBack()
//
uni.$emit('refreshList')
}, 500)
} else {
uni.$u.toast(res.resMsg || '签署失败')
}
} catch (err) {
uni.hideLoading()
uni.$u.toast('签署失败')
}
}
/**
* 加载文档
*/
const loadDocument = (url) => {
if (!url) {
error.value = '暂无文档'
pdfUrl.value = ''
return
}
try {
loading.value = true
error.value = ''
// URL
if (url.startsWith('http')) {
pdfUrl.value = url
} else {
pdfUrl.value = import.meta.env.VITE_API_FILE_ASE_URL + url
}
} catch (err) {
console.error('加载文档失败:', err)
error.value = '加载失败,请重试'
pdfUrl.value = ''
} finally {
loading.value = false
}
}
/**
* 加载视频
*/
const loadVideo = () => {
try {
if (contractData.value.videoUrl) {
const url = contractData.value.videoUrl
if (url.startsWith('http')) {
videoUrl.value = url
} else {
videoUrl.value = import.meta.env.VITE_API_FILE_ASE_URL + url
}
}
} catch (err) {
console.error('加载视频失败:', err)
}
}
/**
* 页面加载
*/
onLoad((options) => {
if (options.params) {
try {
contractData.value = JSON.parse(decodeURIComponent(options.params))
//
isSigned.value = contractData.value.isSign == 1
//
initDocumentOptions()
//
loadVideo()
} catch (err) {
console.error('解析合同数据失败:', err)
uni.$u.toast('合同数据加载失败')
}
} else {
uni.$u.toast('缺少合同数据')
}
})
</script>
<style lang="scss" scoped>
.page-container {
height: 100vh;
display: flex;
flex-direction: column;
background: #f5f7fa;
}
.content-wrapper {
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
height: 100%;
}
.picker-section {
padding: 24rpx 32rpx;
background: #fff;
border-bottom: 1rpx solid #e5e5e5;
}
.loading-wrapper {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 80rpx 32rpx;
}
.loading-text {
margin-top: 24rpx;
font-size: 28rpx;
color: #999;
}
.error-wrapper {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 80rpx 32rpx;
}
.error-text {
margin-top: 24rpx;
font-size: 28rpx;
color: #e34d59;
text-align: center;
}
.document-wrapper {
flex: 1;
min-height: 0;
position: relative;
background: #fff;
overflow: hidden;
}
.empty-wrapper {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 80rpx 32rpx;
}
.empty-text {
margin-top: 24rpx;
font-size: 28rpx;
color: #999;
}
.button-section {
display: flex;
padding: 32rpx;
gap: 16rpx;
background: #fff;
border-top: 1rpx solid #e5e5e5;
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.04);
}
.back-btn {
display: flex;
align-items: center;
justify-content: center;
width: 64rpx;
height: 64rpx;
border-radius: 50%;
background: rgba(255, 255, 255, 0.2);
transition: all 0.3s ease;
}
.back-btn:active {
background: rgba(255, 255, 255, 0.3);
transform: scale(0.95);
}
.sign-popup {
width: 640rpx;
display: flex;
flex-direction: column;
max-height: 80vh;
background: #fff;
border-radius: 20rpx;
padding: 32rpx;
box-sizing: border-box;
overflow: hidden;
}
.sign-title {
font-size: 36rpx;
font-weight: 700;
color: #333;
margin-bottom: 32rpx;
padding-bottom: 20rpx;
border-bottom: 2rpx solid #f0f0f0;
}
.sign-body {
max-height: 60vh;
}
.sign-block {
margin-bottom: 32rpx;
}
.block-title {
display: block;
font-size: 30rpx;
font-weight: 600;
color: #333;
margin-bottom: 20rpx;
}
.info-text {
padding: 20rpx;
background: #f8f8f8;
border-radius: 12rpx;
border: 1rpx solid #e5e5e5;
font-size: 28rpx;
color: #666;
line-height: 1.6;
}
.stamp-section {
margin-bottom: 32rpx;
}
.stamp-label {
font-size: 28rpx;
color: #666;
margin-bottom: 16rpx;
text-align: center;
}
.stamp-preview {
width: 100%;
min-height: 200rpx;
display: flex;
align-items: center;
justify-content: center;
background: #f8f8f8;
border-radius: 12rpx;
border: 1rpx solid #e5e5e5;
padding: 20rpx;
box-sizing: border-box;
}
.stamp-image {
max-width: 100%;
max-height: 300rpx;
}
.stamp-placeholder {
width: 100%;
min-height: 200rpx;
display: flex;
align-items: center;
justify-content: center;
background: #f8f8f8;
border-radius: 12rpx;
border: 1rpx solid #e5e5e5;
}
.placeholder-text {
font-size: 28rpx;
color: #999;
}
.sign-actions {
display: flex;
justify-content: space-between;
align-items: center;
gap: 16rpx;
margin-top: 32rpx;
}
.video-popup {
width: 90vw;
max-width: 750rpx;
display: flex;
flex-direction: column;
background: #000;
border-radius: 20rpx;
overflow: hidden;
position: relative;
}
.video-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx 32rpx;
background: rgba(255, 255, 255, 0.1);
}
.video-title {
font-size: 32rpx;
font-weight: 600;
color: #fff;
}
.video-container {
width: 100%;
height: 60vh;
min-height: 400rpx;
max-height: 80vh;
display: flex;
align-items: center;
justify-content: center;
background: #000;
position: relative;
}
.video-player {
width: 100%;
height: 100%;
background: #000;
}
.video-empty {
display: flex;
align-items: center;
justify-content: center;
color: #999;
font-size: 28rpx;
}
</style>

View File

@ -18,7 +18,7 @@
<ReviewSearchBar
@search="handleSearch"
@action="handleBatchSign"
action-button-text="批量签署"
:action-button-text="showSignActions ? '批量签署' : ''"
v-model="queryParams.keyWord"
/>
@ -52,6 +52,7 @@
<view
class="sign-status"
v-if="activeTab != 0"
:style="{ color: item.isSign == 1 ? '#4caf50' : '#ed7b2f' }"
>
{{ item.isSign == 1 ? '已签署' : '待签署' }}
@ -106,12 +107,16 @@
</view>
<!-- 全选按钮仅待签署 -->
<ReviewSelectAll v-if="showSignActions" @selectAll="handleSelectAll" />
<ReviewSelectAll
v-if="showSignActions"
@selectAll="handleSelectAll"
:isAllChecked="isAllChecked"
/>
<!-- 签署确认弹窗 -->
<up-popup :show="showSignModal" mode="center" round="20" @close="handleCancelSign">
<view class="sign-popup">
<view class="sign-title">确认签署</view>
<view class="sign-title">签署</view>
<scroll-view class="sign-body" scroll-y>
<view class="sign-block">
<text class="block-title">确认信息</text>
@ -119,6 +124,22 @@
<text>您确定要签署选中的 {{ checkedCount }} 份合同吗</text>
</view>
</view>
<view class="stamp-section">
<up-button
text="获取公章"
type="primary"
@tap="handleGetStamp"
:customStyle="getStampButtonStyle"
:loading="stampLoading"
/>
<view class="stamp-label">电子公章</view>
<view class="stamp-preview" v-if="stampImageUrl">
<image :src="stampImageUrl" mode="aspectFit" class="stamp-image" />
</view>
<view v-else class="stamp-placeholder">
<text class="placeholder-text">暂无公章</text>
</view>
</view>
<view class="sign-actions">
<up-button
text="取消"
@ -127,7 +148,7 @@
:customStyle="cancelBtnStyle"
/>
<up-button
text="确认签署"
text="确认"
type="primary"
@tap="handleConfirmSign"
:customStyle="confirmBtnStyle"
@ -140,7 +161,7 @@
</template>
<script setup>
import { ref, computed } from 'vue'
import { ref, computed, onMounted, onUnmounted } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import NavBarModal from '@/components/NavBarModal/index.vue'
import ReviewTabBar from '@/components/ReviewTabBar/index.vue'
@ -148,13 +169,17 @@ import ReviewSearchBar from '@/components/ReviewSearchBar/index.vue'
import ReviewEmptyState from '@/components/ReviewEmptyState/index.vue'
import ReviewSelectAll from '@/components/ReviewSelectAll/index.vue'
import { getContentStyle } from '@/utils/safeArea'
import { getContractSignListAPI, signContractAPI } from '@/services/realName/contractSign'
import {
signContractAPI,
getContractSignListAPI,
getUserElectronicStampAPI,
} from '@/services/realName/contractSign'
import { useMemberStore, useCommonStore } from '@/stores'
import dayjs from 'dayjs'
const memberStore = useMemberStore()
const commonStore = useCommonStore()
const isAllChecked = ref(false)
const queryParams = ref({
isSign: 0, // 0 1
proId: commonStore.activeProjectId,
@ -179,6 +204,14 @@ const showSignActions = computed(() => activeTab.value === 0)
const showSignModal = ref(false)
const cancelBtnStyle = { flex: 1, marginRight: '16rpx' }
const confirmBtnStyle = { flex: 1 }
const stampImageUrl = ref('')
const stampImagePath = ref('')
const stampLoading = ref(false)
const getStampButtonStyle = {
width: '100%',
height: '88rpx',
marginBottom: '24rpx',
}
//
const checkedCount = computed(() => {
@ -209,6 +242,11 @@ const handleSearch = (keyword) => {
*/
const handleBatchSign = () => {
if (!showSignActions.value) return
if (list.value.length === 0) {
uni.$u.toast('暂无可签署合同')
return
}
const checkedList = list.value.filter((item) => item.isChecked)
if (checkedList.length === 0) {
uni.$u.toast('请选择要签署的合同')
@ -222,6 +260,46 @@ const handleBatchSign = () => {
*/
const handleCancelSign = () => {
showSignModal.value = false
stampImageUrl.value = '' //
stampImagePath.value = ''
}
/**
* 获取公章
*/
const handleGetStamp = async () => {
const phone = memberStore.realNameUserInfo.phone
if (!phone) {
uni.$u.toast('手机号不存在')
return
}
stampLoading.value = true
try {
const res = await getUserElectronicStampAPI({ phone })
if (res.res === 1 && res.obj) {
const imageUrl = res?.obj?.sealUrl
stampImagePath.value = imageUrl
if (imageUrl) {
// URL
if (imageUrl.startsWith('http')) {
stampImageUrl.value = imageUrl
} else {
stampImageUrl.value = import.meta.env.VITE_API_FILE_ASE_URL + imageUrl
}
uni.$u.toast('获取公章成功')
} else {
uni.$u.toast('未找到公章信息')
}
} else {
uni.$u.toast(res.resMsg || '获取公章失败')
}
} catch (err) {
console.error('获取公章失败:', err)
uni.$u.toast('获取公章失败,请稍后重试')
} finally {
stampLoading.value = false
}
}
/**
@ -237,6 +315,7 @@ const handleConfirmSign = () => {
const handleSelectAll = () => {
if (!showSignActions.value) return
const allChecked = list.value.every((item) => item.isChecked)
isAllChecked.value = !allChecked
list.value = list.value.map((item) => ({ ...item, isChecked: !allChecked }))
}
@ -255,7 +334,7 @@ const handleCardClick = (item) => {
//
const params = encodeURIComponent(JSON.stringify(item))
uni.navigateTo({
url: `/pages/work/contract-review/detail?params=${params}`,
url: `/pages/work/contract-sign/detail?params=${params}`,
})
}
@ -289,6 +368,11 @@ const handleSign = async () => {
return
}
if (!stampImagePath.value) {
uni.$u.toast('请先获取公章')
return
}
//
uni.showLoading({
title: '签署中...',
@ -299,11 +383,13 @@ const handleSign = async () => {
// Promise
const signPromises = checkedList.map((item) => {
return signContractAPI({
signer: memberStore?.realNameUserInfo.id,
signTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
isSign: 1, // 1
companySeal: stampImagePath.value, //
subPdfUrl: item.personPdfUrl,
legalSeal: null,
aqxysPath: item.aqxysPath,
partBIdCard: item.partBIdCard,
id: item.id,
isSign: 1,
})
.then((res) => {
return {
@ -362,6 +448,14 @@ const handleBack = () => {
onLoad(() => {
loadList()
})
onMounted(() => {
uni.$on('refreshList', loadList)
})
onUnmounted(() => {
uni.$off('refreshList', loadList)
})
</script>
<style lang="scss" scoped>
@ -523,6 +617,51 @@ onLoad(() => {
line-height: 1.6;
}
.stamp-section {
margin-bottom: 32rpx;
}
.stamp-label {
font-size: 28rpx;
color: #666;
margin-bottom: 16rpx;
text-align: center;
}
.stamp-preview {
width: 100%;
min-height: 200rpx;
display: flex;
align-items: center;
justify-content: center;
background: #f8f8f8;
border-radius: 12rpx;
border: 1rpx solid #e5e5e5;
padding: 20rpx;
box-sizing: border-box;
}
.stamp-image {
max-width: 100%;
max-height: 300rpx;
}
.stamp-placeholder {
width: 100%;
min-height: 200rpx;
display: flex;
align-items: center;
justify-content: center;
background: #f8f8f8;
border-radius: 12rpx;
border: 1rpx solid #e5e5e5;
}
.placeholder-text {
font-size: 28rpx;
color: #999;
}
.sign-actions {
display: flex;
justify-content: space-between;

View File

@ -13,10 +13,18 @@ export const getContractSignListAPI = (data) => {
})
}
// 签署接口
// 合同签署
export const signContractAPI = (data) => {
return realNameHttp({
url: `/workPerson/updateSign?${initParams(data)}`,
method: 'POST',
})
}
// 根据手机号码获取用户的电子公章
export const getUserElectronicStampAPI = (data) => {
return realNameHttp({
url: `/personIdentify/selectSubMsgByPhone?${initParams(data)}`,
method: 'POST',
})
}