|
- <template>
- <view class="page">
- <!-- 协议内容 -->
- <view class="section">
- <view class="doc-title">{{ docTitle }}</view>
- <rich-text class="doc-body" :nodes="docContent" />
- </view>
-
- <!-- 收入金额(仅income类型) -->
- <view class="section" v-if="signType === 'income'">
- <view class="form-label">请填写您的个人年可支配收入(元)</view>
- <view class="amount-wrap">
- <text class="amount-prefix">¥</text>
- <u-input v-model="incomeAmount" type="number" placeholder="请输入金额" border="none" maxlength="7" />
- </view>
- </view>
-
- <!-- 监护人信息(仅privacy_jhr类型) -->
- <view class="section" v-if="signType === 'privacy_jhr'">
- <view class="form-label">监护人信息</view>
- <view class="form-row">
- <text class="row-label">监护人姓名</text>
- <u-input v-model="guardianName" placeholder="请输入监护人姓名" border="surround" maxlength="20" />
- </view>
- <view class="form-row">
- <text class="row-label">监护人身份证</text>
- <u-input v-model="guardianIdCard" placeholder="请输入监护人身份证号" border="surround" maxlength="18" />
- </view>
- <view class="form-row">
- <text class="row-label">与患者关系</text>
- <u-input v-model="guardianRelation" placeholder="如:父亲、母亲" border="surround" maxlength="10" />
- </view>
- </view>
-
- <!-- 签名区域 -->
- <view class="section">
- <view class="sign-label">请在下方签名确认</view>
- <view class="canvas-wrap" @tap="goSignature">
- <image v-if="signImageUrl" class="sign-preview" :src="signImageUrl" mode="aspectFit" />
- <view v-else class="canvas-placeholder">
- <u-icon name="edit-pen" size="28" color="#ccc" />
- <text>点击此处去签名</text>
- </view>
- </view>
- <view v-if="signImageUrl" class="sign-actions">
- <view class="clear-btn" @tap="goSignature">重新签名</view>
- </view>
- </view>
-
- <!-- 底部按钮 -->
- <view class="btn-wrap">
- <u-button text="确认签署" :loading="submitting" @click="confirmSign" color="#0E63E3" size="large" />
- </view>
- </view>
- </template>
-
- <script setup>
- import { ref, onBeforeUnmount } from 'vue'
- import { onLoad } from '@dcloudio/uni-app'
- import { get, post } from '@/utils/request.js'
-
- const signType = ref('')
- const docTitle = ref('')
- const docContent = ref('')
- const incomeAmount = ref('')
- const guardianName = ref('')
- const guardianIdCard = ref('')
- const guardianRelation = ref('')
- const signImageUrl = ref('')
- const submitting = ref(false)
-
- const onSignatureResult = (data) => {
- if (data.url) signImageUrl.value = data.url
- }
-
- onLoad((options) => {
- signType.value = options.type || 'privacy'
- // 回显上次填写的数据
- if (options.amount) incomeAmount.value = decodeURIComponent(options.amount)
- if (options.guardianName) guardianName.value = decodeURIComponent(options.guardianName)
- if (options.guardianIdCard) guardianIdCard.value = decodeURIComponent(options.guardianIdCard)
- if (options.guardianRelation) guardianRelation.value = decodeURIComponent(options.guardianRelation)
- uni.$on('signatureResult', onSignatureResult)
- loadContent()
- })
-
- onBeforeUnmount(() => {
- uni.$off('signatureResult', onSignatureResult)
- })
-
- const loadContent = async () => {
- try {
- const key = 'sign_' + signType.value
- const res = await get('/api/content', { key })
- docTitle.value = res.data.title || ''
- docContent.value = res.data.content || ''
- } catch (e) {}
- }
-
- const goSignature = () => {
- uni.navigateTo({ url: '/pages/sign/signature' })
- }
-
- const confirmSign = async () => {
- if (!signImageUrl.value) {
- return uni.showToast({ title: '请先签名', icon: 'none' })
- }
- if (signType.value === 'income' && (!incomeAmount.value || Number(incomeAmount.value) <= 0)) {
- return uni.showToast({ title: '请填写有效的收入金额', icon: 'none' })
- }
- if (signType.value === 'privacy_jhr') {
- if (!guardianName.value.trim()) return uni.showToast({ title: '请输入监护人姓名', icon: 'none' })
- if (!guardianIdCard.value.trim()) return uni.showToast({ title: '请输入监护人身份证号', icon: 'none' })
- if (!/^\d{17}[\dXx]$/.test(guardianIdCard.value)) return uni.showToast({ title: '监护人身份证格式不正确', icon: 'none' })
- if (!guardianRelation.value.trim()) return uni.showToast({ title: '请输入与患者关系', icon: 'none' })
- }
-
- submitting.value = true
- try {
- const params = {
- type: signType.value,
- signImage: signImageUrl.value,
- amount: signType.value === 'income' ? incomeAmount.value : undefined,
- guardianName: signType.value === 'privacy_jhr' ? guardianName.value.trim() : undefined,
- guardianIdCard: signType.value === 'privacy_jhr' ? guardianIdCard.value.trim() : undefined,
- guardianRelation: signType.value === 'privacy_jhr' ? guardianRelation.value.trim() : undefined
- }
- const res = await post('/api/mp/sign', params)
-
- uni.$emit('signResult', {
- type: signType.value,
- url: res.data.url,
- amount: signType.value === 'income' ? incomeAmount.value : undefined,
- guardianName: signType.value === 'privacy_jhr' ? guardianName.value.trim() : undefined,
- guardianIdCard: signType.value === 'privacy_jhr' ? guardianIdCard.value.trim() : undefined,
- guardianRelation: signType.value === 'privacy_jhr' ? guardianRelation.value.trim() : undefined
- })
-
- uni.showToast({ title: '签署成功', icon: 'success' })
- setTimeout(() => uni.navigateBack(), 1000)
- } catch (e) {
- if (e && e.msg) uni.showToast({ title: e.msg, icon: 'none' })
- } finally {
- submitting.value = false
- }
- }
- </script>
-
- <style lang="scss" scoped>
- .page {
- min-height: 100vh;
- background: #f4f4f5;
- padding: 24rpx;
- padding-bottom: calc(140rpx + env(safe-area-inset-bottom));
- }
-
- .section {
- background: #fff;
- margin-bottom: 24rpx;
- border-radius: 10rpx;
- padding: 32rpx;
- border: 1rpx solid #ebeef5;
- }
-
- .doc-title {
- font-size: 32rpx;
- font-weight: 600;
- text-align: center;
- margin-bottom: 32rpx;
- color: #222;
- }
-
- .doc-body {
- font-size: 28rpx;
- color: #555;
- line-height: 1.8;
- }
-
- .form-label {
- font-size: 28rpx;
- color: #333;
- font-weight: 600;
- margin-bottom: 16rpx;
- }
-
- .amount-wrap {
- display: flex;
- align-items: center;
- border: 1rpx solid #ddd;
- border-radius: 12rpx;
- overflow: hidden;
- gap: 12rpx;
- }
-
- .amount-prefix {
- padding: 20rpx 24rpx;
- font-size: 28rpx;
- color: #999;
- background: #f8f8f8;
- }
-
- .form-row {
- margin-bottom: 20rpx;
-
- &:last-child {
- margin-bottom: 0;
- }
- }
-
- .row-label {
- font-size: 26rpx;
- color: #555;
- margin-bottom: 12rpx;
- display: block;
- }
-
- .sign-label {
- font-size: 28rpx;
- color: #333;
- font-weight: 600;
- margin-bottom: 16rpx;
- }
-
- .canvas-wrap {
- position: relative;
- border: 2rpx dashed #ddd;
- border-radius: 12rpx;
- overflow: hidden;
- min-height: 300rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- background: #fafafa;
- }
-
- .sign-preview {
- width: 100%;
- height: 300rpx;
- }
-
- .canvas-placeholder {
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 12rpx;
- padding: 40rpx 0;
-
- text {
- color: #ccc;
- font-size: 28rpx;
- }
- }
-
- .sign-actions {
- display: flex;
- justify-content: flex-end;
- margin-top: 16rpx;
- }
-
- .clear-btn {
- padding: 12rpx 32rpx;
- border: 1rpx solid #ccc;
- border-radius: 12rpx;
- font-size: 26rpx;
- color: #666;
-
- &:active {
- border-color: #0e63e3;
- color: #0e63e3;
- }
- }
-
- .btn-wrap {
- position: fixed;
- bottom: 0;
- left: 0;
- right: 0;
- background: #fff;
- padding: 20rpx 32rpx;
- padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
- box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.06);
- z-index: 100;
- }
- </style>
|