14 changed files with 1217 additions and 58 deletions
@ -0,0 +1,797 @@ |
|||
<!--合同签署表单页面--> |
|||
<template> |
|||
<view class="main_box"> |
|||
<!-- 自定义导航栏 --> |
|||
<view class="navbar_section"> |
|||
<view class="navbar_back" @click="goBack"> |
|||
<text class="back_icon">‹</text> |
|||
</view> |
|||
<view class="navbar_title">合同签署</view> |
|||
<view class="navbar_action"></view> |
|||
</view> |
|||
|
|||
<!-- 合同信息 --> |
|||
<view class="contract_info_section" v-if="contractInfo"> |
|||
<view class="info_header"> |
|||
<view class="contract_name">{{ contractInfo.contract_name }}</view> |
|||
<view class="contract_type">{{ contractInfo.contract_type }}</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 合同内容 --> |
|||
<view class="contract_content_section" v-if="contractContent"> |
|||
<view class="content_header"> |
|||
<view class="content_title">合同内容</view> |
|||
<view class="content_expand_btn" @click="toggleContentExpand"> |
|||
{{ contentExpanded ? '收起' : '展开' }} |
|||
</view> |
|||
</view> |
|||
<view class="content_body" :class="{ expanded: contentExpanded }"> |
|||
<text class="content_text">{{ renderContractContent }}</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 表单内容 --> |
|||
<view class="form_section" v-if="!loading"> |
|||
<view class="form_title">请填写以下信息</view> |
|||
<view class="form_content"> |
|||
<view |
|||
v-for="(field, index) in formFields" |
|||
:key="index" |
|||
class="form_field" |
|||
> |
|||
<view class="field_label"> |
|||
{{ field.name }} |
|||
<text v-if="field.is_required" class="required_mark">*</text> |
|||
</view> |
|||
|
|||
<!-- 手写签名字段 --> |
|||
<view v-if="field.data_type === 'signature'" class="field_signature"> |
|||
<view |
|||
class="signature_button" |
|||
@click="goToSignature(field)" |
|||
:class="formData[field.placeholder] ? 'signed' : ''" |
|||
> |
|||
<text class="signature_icon">✒️</text> |
|||
<text class="signature_text"> |
|||
{{ formData[field.placeholder] ? '已签名' : '手写签名' }} |
|||
</text> |
|||
</view> |
|||
<view v-if="formData[field.placeholder]" class="signature_preview"> |
|||
<image :src="formData[field.placeholder]" mode="aspectFit" /> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 签名图片上传字段 --> |
|||
<view v-else-if="field.data_type === 'sign_img'" class="field_sign_img"> |
|||
<view |
|||
class="sign_img_button" |
|||
@click="chooseSignImage(field)" |
|||
:class="formData[field.placeholder] ? 'uploaded' : ''" |
|||
> |
|||
<text class="sign_img_icon">📷</text> |
|||
<text class="sign_img_text"> |
|||
{{ formData[field.placeholder] ? '已上传' : '上传签名图片' }} |
|||
</text> |
|||
</view> |
|||
<view v-if="formData[field.placeholder]" class="sign_img_preview"> |
|||
<image :src="formData[field.placeholder]" mode="aspectFit" /> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 文本输入框 --> |
|||
<view v-else-if="field.field_type === 'text'" class="field_input"> |
|||
<input |
|||
type="text" |
|||
:placeholder="field.placeholder || '请输入' + field.name" |
|||
v-model="formData[field.placeholder]" |
|||
:disabled="field.data_type !== 'user_input'" |
|||
:class="field.data_type !== 'user_input' ? 'disabled' : ''" |
|||
/> |
|||
</view> |
|||
|
|||
<!-- 日期选择器 --> |
|||
<view v-else-if="field.field_type === 'date'" class="field_input"> |
|||
<picker |
|||
mode="date" |
|||
:value="formData[field.placeholder]" |
|||
@change="handleDateChange(field.placeholder, $event)" |
|||
:disabled="field.data_type !== 'user_input'" |
|||
> |
|||
<input |
|||
type="text" |
|||
:placeholder="field.placeholder || '请选择' + field.name" |
|||
:value="formData[field.placeholder]" |
|||
:disabled="field.data_type !== 'user_input'" |
|||
:class="field.data_type !== 'user_input' ? 'disabled' : ''" |
|||
readonly |
|||
/> |
|||
</picker> |
|||
</view> |
|||
|
|||
<!-- 数字输入框 --> |
|||
<view v-else-if="field.field_type === 'number'" class="field_input"> |
|||
<input |
|||
type="number" |
|||
:placeholder="field.placeholder || '请输入' + field.name" |
|||
v-model="formData[field.placeholder]" |
|||
:disabled="field.data_type !== 'user_input'" |
|||
:class="field.data_type !== 'user_input' ? 'disabled' : ''" |
|||
/> |
|||
</view> |
|||
|
|||
<!-- 文本域 --> |
|||
<view v-else-if="field.field_type === 'textarea'" class="field_textarea"> |
|||
<textarea |
|||
:placeholder="field.placeholder || '请输入' + field.name" |
|||
v-model="formData[field.placeholder]" |
|||
:disabled="field.data_type !== 'user_input'" |
|||
:class="field.data_type !== 'user_input' ? 'disabled' : ''" |
|||
></textarea> |
|||
</view> |
|||
|
|||
<!-- 提示信息 --> |
|||
<view v-if="field.data_type !== 'user_input' && field.data_type !== 'signature' && field.data_type !== 'sign_img'" class="field_hint"> |
|||
{{ getFieldHint(field) }} |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 加载状态 --> |
|||
<view v-if="loading" class="loading_section"> |
|||
<view class="loading_spinner"></view> |
|||
<view class="loading_text">加载表单配置中...</view> |
|||
</view> |
|||
|
|||
<!-- 提交按钮 --> |
|||
<view class="submit_section" v-if="!loading"> |
|||
<fui-button |
|||
type="warning" |
|||
btn-size="medium" |
|||
width="100%" |
|||
:loading="submitting" |
|||
@click="submitContract" |
|||
> |
|||
{{ submitting ? '提交中...' : '提交签署' }} |
|||
</fui-button> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import apiRoute from '@/api/apiRoute.js' |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
contractId: 0, |
|||
studentId: 0, |
|||
contractName: '', |
|||
contractInfo: null, |
|||
contractContent: '', |
|||
contentExpanded: false, |
|||
formFields: [], |
|||
formData: {}, |
|||
loading: true, |
|||
submitting: false |
|||
} |
|||
}, |
|||
|
|||
computed: { |
|||
// 渲染合同内容,替换占位符为实际值 |
|||
renderContractContent() { |
|||
if (!this.contractContent) return '' |
|||
|
|||
let content = this.contractContent |
|||
// 将表单数据替换到合同内容中的占位符 |
|||
Object.keys(this.formData).forEach(key => { |
|||
const value = this.formData[key] || '' |
|||
const regex = new RegExp(`\\{\\{${key}\\}\\}`, 'g') |
|||
content = content.replace(regex, value) |
|||
}) |
|||
|
|||
return content |
|||
} |
|||
}, |
|||
|
|||
onLoad(options) { |
|||
this.contractId = parseInt(options.contract_id) || 0 |
|||
this.studentId = parseInt(options.student_id) || 0 |
|||
this.contractName = decodeURIComponent(options.contract_name || '') |
|||
|
|||
if (this.contractId && this.studentId) { |
|||
this.loadSignForm() |
|||
} else { |
|||
uni.showToast({ |
|||
title: '参数错误', |
|||
icon: 'none' |
|||
}) |
|||
setTimeout(() => { |
|||
uni.navigateBack() |
|||
}, 1500) |
|||
} |
|||
}, |
|||
|
|||
onShow() { |
|||
// 从签名页面返回时,检查是否有新的签名数据 |
|||
const pages = getCurrentPages() |
|||
const currentPage = pages[pages.length - 1] |
|||
if (currentPage.data && currentPage.data.newSignature) { |
|||
const { fieldPlaceholder, signatureData } = currentPage.data.newSignature |
|||
this.formData[fieldPlaceholder] = signatureData |
|||
// 清除临时数据 |
|||
delete currentPage.data.newSignature |
|||
} |
|||
}, |
|||
|
|||
methods: { |
|||
goBack() { |
|||
uni.navigateBack() |
|||
}, |
|||
|
|||
async loadSignForm() { |
|||
this.loading = true |
|||
try { |
|||
console.log('加载签署表单:', { contractId: this.contractId, studentId: this.studentId }) |
|||
|
|||
// 获取签署表单配置 |
|||
const response = await apiRoute.getStudentContractSignForm({ |
|||
contract_id: this.contractId, |
|||
student_id: this.studentId |
|||
}) |
|||
|
|||
if (response.code === 1) { |
|||
const data = response.data |
|||
this.contractInfo = { |
|||
contract_name: data.contract_name, |
|||
contract_type: data.contract_type |
|||
} |
|||
this.contractContent = data.contract_content || '' |
|||
this.formFields = data.form_fields || [] |
|||
|
|||
// 初始化表单数据 |
|||
this.initFormData() |
|||
|
|||
console.log('表单配置加载成功:', this.formFields) |
|||
} else { |
|||
uni.showToast({ |
|||
title: response.msg || '获取表单配置失败', |
|||
icon: 'none' |
|||
}) |
|||
setTimeout(() => { |
|||
uni.navigateBack() |
|||
}, 1500) |
|||
} |
|||
} catch (error) { |
|||
console.error('获取表单配置失败:', error) |
|||
uni.showToast({ |
|||
title: '获取表单配置失败', |
|||
icon: 'none' |
|||
}) |
|||
setTimeout(() => { |
|||
uni.navigateBack() |
|||
}, 1500) |
|||
} finally { |
|||
this.loading = false |
|||
} |
|||
}, |
|||
|
|||
initFormData() { |
|||
const data = {} |
|||
this.formFields.forEach(field => { |
|||
const key = field.placeholder || field.name |
|||
// 根据数据类型设置初始值 |
|||
if (field.data_type === 'database' || field.data_type === 'system') { |
|||
data[key] = field.default_value || '' |
|||
} else { |
|||
data[key] = field.default_value || '' |
|||
} |
|||
}) |
|||
this.formData = data |
|||
}, |
|||
|
|||
handleDateChange(fieldKey, event) { |
|||
this.formData[fieldKey] = event.detail.value |
|||
}, |
|||
|
|||
toggleContentExpand() { |
|||
this.contentExpanded = !this.contentExpanded |
|||
}, |
|||
|
|||
goToSignature(field) { |
|||
// 跳转到签名页面 |
|||
const fieldPlaceholder = field.placeholder || field.name |
|||
uni.navigateTo({ |
|||
url: `/pages-common/contract/contract_sign?field_name=${encodeURIComponent(field.name)}&field_placeholder=${encodeURIComponent(fieldPlaceholder)}&contract_id=${this.contractId}` |
|||
}) |
|||
}, |
|||
|
|||
chooseSignImage(field) { |
|||
// 选择签名图片 |
|||
const fieldPlaceholder = field.placeholder || field.name |
|||
uni.chooseImage({ |
|||
count: 1, |
|||
sizeType: ['compressed'], |
|||
sourceType: ['album', 'camera'], |
|||
success: (res) => { |
|||
const tempFilePath = res.tempFilePaths[0] |
|||
|
|||
// 上传图片到服务器 |
|||
this.uploadSignImage(tempFilePath, fieldPlaceholder) |
|||
}, |
|||
fail: (err) => { |
|||
console.error('选择图片失败:', err) |
|||
uni.showToast({ |
|||
title: '选择图片失败', |
|||
icon: 'none' |
|||
}) |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
async uploadSignImage(tempFilePath, fieldPlaceholder) { |
|||
// 显示上传进度 |
|||
uni.showLoading({ |
|||
title: '上传中...', |
|||
mask: true |
|||
}) |
|||
|
|||
try { |
|||
// 上传图片到服务器 |
|||
const uploadResult = await new Promise((resolve, reject) => { |
|||
uni.uploadFile({ |
|||
url: 'http://localhost:20080/api/upload/image', |
|||
filePath: tempFilePath, |
|||
name: 'image', |
|||
header: { |
|||
'Authorization': uni.getStorageSync('token') || '' |
|||
}, |
|||
success: (uploadRes) => { |
|||
try { |
|||
const result = JSON.parse(uploadRes.data) |
|||
if (result.code === 1) { |
|||
resolve(result.data) |
|||
} else { |
|||
reject(new Error(result.msg || '上传失败')) |
|||
} |
|||
} catch (e) { |
|||
reject(new Error('上传响应解析失败')) |
|||
} |
|||
}, |
|||
fail: (err) => { |
|||
reject(new Error('上传请求失败')) |
|||
} |
|||
}) |
|||
}) |
|||
|
|||
// 上传成功,使用服务器返回的URL |
|||
this.formData[fieldPlaceholder] = uploadResult.url || uploadResult.path || tempFilePath |
|||
|
|||
uni.hideLoading() |
|||
uni.showToast({ |
|||
title: '上传成功', |
|||
icon: 'success' |
|||
}) |
|||
|
|||
console.log('签名图片上传成功:', uploadResult) |
|||
|
|||
} catch (error) { |
|||
console.error('签名图片上传失败:', error) |
|||
|
|||
// 上传失败时使用本地临时路径(仅供预览) |
|||
this.formData[fieldPlaceholder] = tempFilePath |
|||
|
|||
uni.hideLoading() |
|||
uni.showToast({ |
|||
title: '上传失败,使用本地图片', |
|||
icon: 'none', |
|||
duration: 2000 |
|||
}) |
|||
} |
|||
}, |
|||
|
|||
getFieldHint(field) { |
|||
switch (field.data_type) { |
|||
case 'database': |
|||
return '此信息将从系统数据库自动获取' |
|||
case 'system': |
|||
return '此信息将由系统自动生成' |
|||
default: |
|||
return '' |
|||
} |
|||
}, |
|||
|
|||
validateForm() { |
|||
// 验证必填字段 |
|||
for (const field of this.formFields) { |
|||
if (field.is_required) { |
|||
const key = field.placeholder || field.name |
|||
const value = this.formData[key] |
|||
if (!value || value.toString().trim() === '') { |
|||
uni.showToast({ |
|||
title: `请填写${field.name}`, |
|||
icon: 'none' |
|||
}) |
|||
return false |
|||
} |
|||
} |
|||
} |
|||
return true |
|||
}, |
|||
|
|||
async submitContract() { |
|||
if (!this.validateForm()) { |
|||
return |
|||
} |
|||
|
|||
this.submitting = true |
|||
try { |
|||
console.log('提交合同签署:', { |
|||
contractId: this.contractId, |
|||
studentId: this.studentId, |
|||
formData: this.formData |
|||
}) |
|||
|
|||
// 提交签署数据 |
|||
const response = await apiRoute.signStudentContract({ |
|||
contract_id: this.contractId, |
|||
student_id: this.studentId, |
|||
form_data: this.formData |
|||
}) |
|||
|
|||
if (response.code === 1) { |
|||
uni.showToast({ |
|||
title: '合同签署成功', |
|||
icon: 'success', |
|||
duration: 2000 |
|||
}) |
|||
|
|||
setTimeout(() => { |
|||
// 返回合同列表并刷新 |
|||
uni.navigateBack() |
|||
}, 2000) |
|||
} else { |
|||
uni.showToast({ |
|||
title: response.msg || '合同签署失败', |
|||
icon: 'none' |
|||
}) |
|||
} |
|||
} catch (error) { |
|||
console.error('合同签署失败:', error) |
|||
uni.showToast({ |
|||
title: '合同签署失败', |
|||
icon: 'none' |
|||
}) |
|||
} finally { |
|||
this.submitting = false |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.main_box { |
|||
background: #f8f9fa; |
|||
min-height: 100vh; |
|||
padding-bottom: 120rpx; |
|||
} |
|||
|
|||
// 自定义导航栏 |
|||
.navbar_section { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
background: #29D3B4; |
|||
padding: 40rpx 32rpx 20rpx; |
|||
|
|||
// 小程序端适配状态栏 |
|||
// #ifdef MP-WEIXIN |
|||
padding-top: 80rpx; |
|||
// #endif |
|||
|
|||
.navbar_back { |
|||
width: 60rpx; |
|||
|
|||
.back_icon { |
|||
color: #fff; |
|||
font-size: 40rpx; |
|||
font-weight: 600; |
|||
} |
|||
} |
|||
|
|||
.navbar_title { |
|||
color: #fff; |
|||
font-size: 32rpx; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.navbar_action { |
|||
width: 60rpx; |
|||
} |
|||
} |
|||
|
|||
// 合同信息 |
|||
.contract_info_section { |
|||
background: #fff; |
|||
margin: 20rpx; |
|||
border-radius: 16rpx; |
|||
padding: 24rpx; |
|||
|
|||
.info_header { |
|||
.contract_name { |
|||
font-size: 32rpx; |
|||
font-weight: 600; |
|||
color: #333; |
|||
margin-bottom: 8rpx; |
|||
} |
|||
|
|||
.contract_type { |
|||
font-size: 24rpx; |
|||
color: #666; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 合同内容区域 |
|||
.contract_content_section { |
|||
background: #fff; |
|||
margin: 20rpx; |
|||
border-radius: 16rpx; |
|||
padding: 24rpx; |
|||
|
|||
.content_header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
margin-bottom: 16rpx; |
|||
|
|||
.content_title { |
|||
font-size: 28rpx; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.content_expand_btn { |
|||
font-size: 24rpx; |
|||
color: #29D3B4; |
|||
padding: 8rpx 16rpx; |
|||
border: 1rpx solid #29D3B4; |
|||
border-radius: 8rpx; |
|||
background: rgba(41, 211, 180, 0.05); |
|||
} |
|||
} |
|||
|
|||
.content_body { |
|||
max-height: 200rpx; |
|||
overflow: hidden; |
|||
transition: max-height 0.3s ease; |
|||
|
|||
&.expanded { |
|||
max-height: none; |
|||
} |
|||
|
|||
.content_text { |
|||
font-size: 26rpx; |
|||
color: #666; |
|||
line-height: 1.6; |
|||
word-break: break-all; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 表单区域 |
|||
.form_section { |
|||
margin: 20rpx; |
|||
|
|||
.form_title { |
|||
font-size: 28rpx; |
|||
font-weight: 600; |
|||
color: #333; |
|||
margin-bottom: 20rpx; |
|||
padding: 0 8rpx; |
|||
} |
|||
|
|||
.form_content { |
|||
.form_field { |
|||
background: #fff; |
|||
border-radius: 16rpx; |
|||
padding: 24rpx; |
|||
margin-bottom: 20rpx; |
|||
|
|||
.field_label { |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
margin-bottom: 16rpx; |
|||
font-weight: 500; |
|||
|
|||
.required_mark { |
|||
color: #e74c3c; |
|||
margin-left: 4rpx; |
|||
} |
|||
} |
|||
|
|||
.field_input { |
|||
input { |
|||
width: 100%; |
|||
height: 80rpx; |
|||
padding: 0 20rpx; |
|||
border: 2rpx solid #e0e0e0; |
|||
border-radius: 12rpx; |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
background: #fff; |
|||
|
|||
&::placeholder { |
|||
color: #999; |
|||
} |
|||
|
|||
&.disabled { |
|||
background: #f5f5f5; |
|||
color: #666; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.field_textarea { |
|||
textarea { |
|||
width: 100%; |
|||
min-height: 120rpx; |
|||
padding: 20rpx; |
|||
border: 2rpx solid #e0e0e0; |
|||
border-radius: 12rpx; |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
background: #fff; |
|||
|
|||
&::placeholder { |
|||
color: #999; |
|||
} |
|||
|
|||
&.disabled { |
|||
background: #f5f5f5; |
|||
color: #666; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.field_signature { |
|||
.signature_button { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
height: 80rpx; |
|||
border: 2rpx dashed #29D3B4; |
|||
border-radius: 12rpx; |
|||
background: rgba(41, 211, 180, 0.05); |
|||
|
|||
&.signed { |
|||
border-color: #27ae60; |
|||
background: rgba(39, 174, 96, 0.05); |
|||
} |
|||
|
|||
.signature_icon { |
|||
font-size: 32rpx; |
|||
margin-right: 8rpx; |
|||
} |
|||
|
|||
.signature_text { |
|||
font-size: 28rpx; |
|||
color: #29D3B4; |
|||
|
|||
.signed & { |
|||
color: #27ae60; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.signature_preview { |
|||
margin-top: 16rpx; |
|||
|
|||
image { |
|||
width: 100%; |
|||
height: 120rpx; |
|||
border-radius: 8rpx; |
|||
border: 1rpx solid #e0e0e0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.field_sign_img { |
|||
.sign_img_button { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
height: 80rpx; |
|||
border: 2rpx dashed #409eff; |
|||
border-radius: 12rpx; |
|||
background: rgba(64, 158, 255, 0.05); |
|||
|
|||
&.uploaded { |
|||
border-color: #67c23a; |
|||
background: rgba(103, 194, 58, 0.05); |
|||
} |
|||
|
|||
.sign_img_icon { |
|||
font-size: 32rpx; |
|||
margin-right: 8rpx; |
|||
} |
|||
|
|||
.sign_img_text { |
|||
font-size: 28rpx; |
|||
color: #409eff; |
|||
|
|||
.uploaded & { |
|||
color: #67c23a; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.sign_img_preview { |
|||
margin-top: 16rpx; |
|||
|
|||
image { |
|||
width: 100%; |
|||
height: 120rpx; |
|||
border-radius: 8rpx; |
|||
border: 1rpx solid #e0e0e0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.field_hint { |
|||
margin-top: 8rpx; |
|||
font-size: 22rpx; |
|||
color: #999; |
|||
font-style: italic; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 加载状态 |
|||
.loading_section { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
padding: 120rpx 32rpx; |
|||
|
|||
.loading_spinner { |
|||
width: 60rpx; |
|||
height: 60rpx; |
|||
border: 4rpx solid #f0f0f0; |
|||
border-left: 4rpx solid #29D3B4; |
|||
border-radius: 50%; |
|||
animation: spin 1s linear infinite; |
|||
margin-bottom: 24rpx; |
|||
} |
|||
|
|||
.loading_text { |
|||
font-size: 28rpx; |
|||
color: #666; |
|||
} |
|||
} |
|||
|
|||
@keyframes spin { |
|||
0% { transform: rotate(0deg); } |
|||
100% { transform: rotate(360deg); } |
|||
} |
|||
|
|||
// 提交按钮 |
|||
.submit_section { |
|||
position: fixed; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
background: #fff; |
|||
padding: 20rpx 32rpx 40rpx; |
|||
border-top: 1rpx solid #f0f0f0; |
|||
|
|||
// 小程序端适配底部安全区域 |
|||
// #ifdef MP-WEIXIN |
|||
padding-bottom: calc(40rpx + env(safe-area-inset-bottom)); |
|||
// #endif |
|||
} |
|||
</style> |
|||
Loading…
Reference in new issue