Browse Source

feat : 送检信息修改

master
leiyun 2 weeks ago
parent
commit
c888e16f64
3 changed files with 362 additions and 27 deletions
  1. +159
    -7
      pages/message/detail.vue
  2. +24
    -3
      pages/message/message.vue
  3. +179
    -17
      pages/sample-info/sample-info.vue

+ 159
- 7
pages/message/detail.vue View File

@@ -4,44 +4,96 @@
<!-- 顶部:图标 + 标题 + 标签 -->
<view class="header-row">
<text class="header-icon">📢</text>
<text class="header-title">审核通知</text>
<view class="tag" :class="msg.type === 1 ? 'tag-success' : 'tag-fail'">
{{ msg.type === 1 ? '已通过' : '已驳回' }}
<text class="header-title">{{ headerTitle }}</text>
<view class="tag" :class="tagClass">
{{ tagText }}
</view>
</view>

<!-- 大标题 -->
<view class="main-title">{{ msg.type === 1 ? '您提交的资料已通过审核' : '您提交的资料未通过审核' }}</view>
<view class="main-title">{{ mainTitle }}</view>
<view class="time">{{ msg.create_time }}</view>

<!-- 正文 -->
<view class="body">
<text class="greeting">尊敬的{{ msg.patient_name || '' }}:</text>
<text class="body-text" v-if="msg.type === 1">您提交的个人资料经审核已通过。</text>
<text class="body-text" v-else>您于 {{ formatDate(msg.create_time) }} 提交的个人资料经审核未通过。</text>
<text class="body-text" v-if="msg.type === 1">{{ auditApprovedText }}</text>
<text class="body-text" v-else-if="msg.type === 2">您于 {{ formatDate(msg.create_time) }} 提交的个人资料经审核未通过。</text>
<text class="body-text" v-else-if="msg.type === 3">您的样品已经寄回,请注意查收。</text>
<text class="body-text" v-if="msg.type === 2">请根据以下原因修改后重新提交。</text>
</view>

<view v-if="msg.type === 1" class="receiver-box">
<view class="receiver-title">送检信息</view>
<view class="receiver-tip">{{ sampleSendTip }}</view>
<view class="receiver-row">
<text class="receiver-label">收件地址</text>
<text class="receiver-value">{{ sampleReceiverInfo.address || '—' }}</text>
</view>
<view class="receiver-row">
<text class="receiver-label">收件人</text>
<text class="receiver-value">{{ sampleReceiverInfo.receiver || '—' }}</text>
</view>
<view class="receiver-row">
<text class="receiver-label">电话</text>
<text class="receiver-value">{{ sampleReceiverInfo.phone || '—' }}</text>
</view>
</view>

<!-- 驳回原因 -->
<view v-if="msg.type === 2 && msg.reason" class="reason-box">
<text class="reason-label">驳回原因:</text>
<text class="reason-text">{{ msg.reason }}</text>
</view>

<view v-if="msg.type === 3" class="return-box">
<text class="return-label">回寄物流单号</text>
<text class="return-no">{{ returnTrackingNo || '—' }}</text>
</view>

<!-- 操作按钮 -->
<view v-if="msg.type === 1" class="btn-area">
<u-button text="复制送检信息" @click="copySampleReceiverInfo" color="#0E63E3" size="large" />
</view>
<view v-if="msg.type === 2" class="btn-area">
<u-button text="重新提交资料" @click="goMyInfo" color="#0E63E3" size="large" />
</view>
<view v-if="msg.type === 3" class="btn-area">
<u-button text="复制单号" @click="copyReturnTrackingNo" color="#0E63E3" size="large" />
</view>
</view>
</view>
</template>

<script setup>
import { ref } from 'vue'
import { computed, ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { get } from '@/utils/request.js'

const msg = ref(null)
const auditApprovedText = '您提交的肠愈同行患者关爱项目资料已审核通过,请于7天内在小程序-个人中心-送检信息中提交相关信息。'
const sampleSendTip = '样本请发顺丰到付,血液样本需要联系顺丰快递员加冰袋。'
const sampleReceiverInfo = computed(() => (msg.value && msg.value.sample_receiver_info) || {})
const returnTrackingNo = computed(() => (msg.value && msg.value.reason) || '')
const tagText = computed(() => {
if (!msg.value) return ''
if (msg.value.type === 1) return '已通过'
if (msg.value.type === 3) return '已寄回'
return '已驳回'
})
const headerTitle = computed(() => (msg.value && msg.value.type === 3) ? '回寄信息' : '审核通知')
const tagClass = computed(() => {
if (!msg.value) return ''
if (msg.value.type === 1) return 'tag-success'
if (msg.value.type === 3) return 'tag-return'
return 'tag-fail'
})
const mainTitle = computed(() => {
if (!msg.value) return ''
if (msg.value.type === 1) return '资料已审核通过'
if (msg.value.type === 3) return '样品已经寄回'
return '您提交的资料未通过审核'
})

onLoad(async (options) => {
if (!options.id) return
@@ -62,6 +114,27 @@ const formatDate = (dateStr) => {
const goMyInfo = () => {
uni.navigateTo({ url: '/pages/myinfo/myinfo' })
}

const copySampleReceiverInfo = () => {
const info = sampleReceiverInfo.value
const text = [
`收件地址:${info.address || ''}`,
`收件人:${info.receiver || ''}`,
`电话:${info.phone || ''}`
].join('\n')
uni.setClipboardData({
data: text,
success: () => uni.showToast({ title: '已复制', icon: 'success' })
})
}

const copyReturnTrackingNo = () => {
if (!returnTrackingNo.value) return uni.showToast({ title: '暂无单号', icon: 'none' })
uni.setClipboardData({
data: returnTrackingNo.value,
success: () => uni.showToast({ title: '单号已复制', icon: 'success' })
})
}
</script>

<style lang="scss" scoped>
@@ -111,6 +184,12 @@ const goMyInfo = () => {
color: #f5222d;
border: 1rpx solid #ffa39e;
}

&.tag-return {
background: #f0f5ff;
color: #0e63e3;
border: 1rpx solid #adc6ff;
}
}

.main-title {
@@ -166,6 +245,79 @@ const goMyInfo = () => {
line-height: 1.7;
}

.return-box {
margin-top: 36rpx;
background: #f0f5ff;
border-left: 6rpx solid #0e63e3;
border-radius: 8rpx;
padding: 28rpx 24rpx;
}

.return-label {
font-size: 28rpx;
font-weight: 600;
color: #303133;
display: block;
margin-bottom: 12rpx;
}

.return-no {
font-size: 34rpx;
font-weight: 600;
color: #0e63e3;
line-height: 1.5;
}

.receiver-box {
margin-top: 36rpx;
background: #fafafa;
border: 1rpx solid #ebeef5;
border-radius: 8rpx;
padding: 28rpx 24rpx;
}

.receiver-title {
font-size: 30rpx;
font-weight: 600;
color: #333;
margin-bottom: 20rpx;
}

.receiver-tip {
font-size: 26rpx;
color: #fa541c;
line-height: 1.6;
background: #fff7e6;
border: 1rpx solid #ffd591;
border-radius: 8rpx;
padding: 16rpx 20rpx;
margin-bottom: 20rpx;
}

.receiver-row {
display: flex;
gap: 20rpx;
margin-bottom: 14rpx;

&:last-child {
margin-bottom: 0;
}
}

.receiver-label {
width: 120rpx;
flex-shrink: 0;
font-size: 26rpx;
color: #909399;
}

.receiver-value {
flex: 1;
font-size: 26rpx;
color: #303133;
line-height: 1.6;
}

.btn-area {
margin-top: 48rpx;
}


+ 24
- 3
pages/message/message.vue View File

@@ -2,9 +2,8 @@
<view class="page">
<view v-if="list.length" class="msg-list">
<view class="msg-item" v-for="item in list" :key="item.id" @tap="goDetail(item.id)">
<view class="msg-icon" :class="item.type === 1 ? 'success' : 'fail'">
<u-icon :name="item.type === 1 ? 'checkmark-circle-fill' : 'close-circle-fill'" size="22"
:color="item.type === 1 ? '#52c41a' : '#f5222d'" />
<view class="msg-icon" :class="getMsgClass(item)">
<u-icon :name="getMsgIcon(item)" size="22" :color="getMsgColor(item)" />
</view>
<view class="msg-body">
<view class="msg-title-row">
@@ -74,6 +73,24 @@ const loadMessages = async () => {
loading.value = false
}

const getMsgClass = (item) => {
if (item.type === 1) return 'success'
if (item.type === 3) return 'return'
return 'fail'
}

const getMsgIcon = (item) => {
if (item.type === 1) return 'checkmark-circle-fill'
if (item.type === 3) return 'order'
return 'close-circle-fill'
}

const getMsgColor = (item) => {
if (item.type === 1) return '#52c41a'
if (item.type === 3) return '#0e63e3'
return '#f5222d'
}

const goDetail = (id) => {
const item = list.value.find(m => m.id === id)
if (item) item.is_read = 1
@@ -116,6 +133,10 @@ const goDetail = (id) => {
&.fail {
background: #fff2f0;
}

&.return {
background: #f0f5ff;
}
}

.msg-body {


+ 179
- 17
pages/sample-info/sample-info.vue View File

@@ -25,65 +25,95 @@
</view>
</view>

<!-- 平台收件信息 -->
<view class="section">
<view class="section-title">
<u-icon name="order" size="18" color="#0e63e3" />
<text>平台收件信息</text>
</view>
<view class="receiver-info">
<view class="receiver-row">
<text class="receiver-label">收件地址</text>
<text class="receiver-value">{{ sampleReceiverInfo.address || '—' }}</text>
</view>
<view class="receiver-row">
<text class="receiver-label">收件人</text>
<text class="receiver-value">{{ sampleReceiverInfo.receiver || '—' }}</text>
</view>
<view class="receiver-row">
<text class="receiver-label">电话</text>
<text class="receiver-value">{{ sampleReceiverInfo.phone || '—' }}</text>
</view>
</view>
<view class="copy-receiver" @tap="copySampleReceiverInfo">复制送检信息</view>
</view>

<!-- 送检信息 -->
<view class="section">
<view class="section-title">
<u-icon name="file-text" size="18" color="#fa541c" />
<text>送检信息</text>
<text v-if="sampleInfoStatusText" class="status-pill" :class="sampleInfoStatusClass">{{ sampleInfoStatusText }}</text>
</view>
<view v-if="isSampleReturned" class="return-info">
<text class="return-title">样品已经寄回</text>
<text class="return-text">回寄物流单号:{{ returnTrackingNo || '—' }}</text>
<text v-if="returnTime" class="return-time">回寄时间:{{ returnTime }}</text>
<text class="copy-return-no" @tap="copyReturnTrackingNo">复制单号</text>
</view>
<view class="form-group">
<text class="form-label">送检样本类型{{ sampleRequired ? '' : '(选填)' }}</text>
<u-checkbox-group v-model="form.sample_types" placement="row" :wrap="true" @change="onSampleTypesChange">
<u-checkbox v-for="st in sampleTypeList" :key="st.id" :label="st.name" :name="st.name"
activeColor="#0E63E3" :customStyle="{ marginRight: '24rpx', marginBottom: '16rpx' }" />
:disabled="isSampleInfoLocked" activeColor="#0E63E3" :customStyle="{ marginRight: '24rpx', marginBottom: '16rpx' }" />
</u-checkbox-group>
</view>
<view class="form-group" v-if="showWaxReturn">
<text class="form-label">{{ needReturnNames }}是否需寄回</text>
<u-radio-group v-model="form.wax_return" placement="row">
<u-radio label="是" :name="1" activeColor="#0E63E3" :customStyle="{ marginRight: '40rpx' }" />
<u-radio label="否" :name="0" activeColor="#0E63E3" />
<u-radio label="是" :name="1" :disabled="isSampleInfoLocked" activeColor="#0E63E3" :customStyle="{ marginRight: '40rpx' }" />
<u-radio label="否" :name="0" :disabled="isSampleInfoLocked" activeColor="#0E63E3" />
</u-radio-group>
</view>
<template v-if="form.wax_return === 1 && showWaxReturn">
<view class="form-group">
<view style="display:flex;align-items:center;justify-content:space-between;">
<text class="form-label" style="margin-bottom:0;">收件人姓名</text>
<text class="fill-self-btn" @tap="fillSelfReturn">本人接收</text>
<text :class="['fill-self-btn', isSampleInfoLocked ? 'disabled' : '']" @tap="fillSelfReturn">本人接收</text>
</view>
<u-input v-model="form.return_name" placeholder="请输入收件人姓名" border="surround" :customStyle="{ marginTop: '16rpx' }" />
<u-input v-model="form.return_name" :disabled="isSampleInfoLocked" placeholder="请输入收件人姓名" border="surround" :customStyle="{ marginTop: '16rpx' }" />
</view>
<view class="form-group">
<text class="form-label">收件人电话</text>
<u-input v-model="form.return_phone" type="number" placeholder="请输入收件人电话" border="surround" maxlength="11" />
<u-input v-model="form.return_phone" :disabled="isSampleInfoLocked" type="number" placeholder="请输入收件人电话" border="surround" maxlength="11" />
</view>
<view class="form-group">
<text class="form-label">收件地址</text>
<view class="region-row" @tap="showRegionPicker = true">
<view :class="['region-row', isSampleInfoLocked ? 'disabled' : '']" @tap="openRegionPicker">
<text :class="['region-text', returnRegionText ? '' : 'placeholder']">{{ returnRegionText || '请选择省/市/区' }}</text>
<text class="arrow">›</text>
</view>
<u-input v-model="form.return_address" placeholder="详细门牌号" border="surround"
<u-input v-model="form.return_address" :disabled="isSampleInfoLocked" placeholder="详细门牌号" border="surround"
:customStyle="{ marginTop: '16rpx' }" />
</view>
</template>
<template v-if="(form.sample_types && form.sample_types.length) || sampleRequired">
<view class="form-group">
<text class="form-label">报告接收邮箱</text>
<u-input v-model="form.report_email" placeholder="请输入邮箱地址" border="surround" />
<u-input v-model="form.report_email" :disabled="isSampleInfoLocked" placeholder="请输入邮箱地址" border="surround" />
</view>
<view class="form-group">
<text class="form-label">送检样本物流单号</text>
<u-input v-model="form.sample_tracking_no" placeholder="请输入物流单号" border="surround" />
<u-input v-model="form.sample_tracking_no" :disabled="isSampleInfoLocked" placeholder="请输入物流单号" border="surround" />
</view>
<view class="form-group">
<text class="form-label">送检单照片(可上传多张)</text>
<view class="upload-row">
<view class="upload-item" v-for="(photo, idx) in form.sample_photos" :key="'sp'+idx">
<image class="upload-img" :src="photo" mode="aspectFill" @tap="previewSamplePhoto(idx)" />
<view class="upload-del" @tap="form.sample_photos.splice(idx, 1)">×</view>
<view v-if="!isSampleInfoLocked" class="upload-del" @tap="form.sample_photos.splice(idx, 1)">×</view>
</view>
<view class="upload-box" @tap="chooseSamplePhoto">
<view v-if="!isSampleInfoLocked" class="upload-box" @tap="chooseSamplePhoto">
<text class="upload-icon">+</text>
<text class="upload-text">上传图片</text>
</view>
@@ -94,14 +124,14 @@

<!-- 提交按钮 -->
<view class="btn-wrap">
<view class="agree-row" @tap="agreed = !agreed">
<view class="agree-row" @tap="toggleAgree">
<u-checkbox-group>
<u-checkbox :checked="agreed" shape="circle" activeColor="#0E63E3" size="18" @change="agreed = !agreed" />
<u-checkbox :checked="agreed" :disabled="isSampleInfoLocked" shape="circle" activeColor="#0E63E3" size="18" />
</u-checkbox-group>
<text class="agree-text">请阅读并同意</text>
<text class="agree-link" @tap.stop="openNotice">《患者告知书》</text>
</view>
<u-button text="提交送检信息" :loading="submitting" @click="handleSubmit" color="#0E63E3" size="large" />
<u-button :text="submitButtonText" :loading="submitting" @click="handleSubmit" color="#0E63E3" size="large" />
</view>

<!-- 地区选择器 -->
@@ -133,6 +163,23 @@ const submitting = ref(false)
const agreed = ref(false)
const sampleTypeList = ref([])
const sampleRequired = ref(false)
const sampleReceiverInfo = ref({ address: '', receiver: '', phone: '' })
const sampleInfoStatus = ref(0)
const returnTrackingNo = ref('')
const returnTime = ref('')
const isSampleReturned = computed(() => sampleInfoStatus.value === 2)
const isSampleInfoLocked = computed(() => sampleInfoStatus.value === 1 || sampleInfoStatus.value === 2)
const sampleInfoStatusText = computed(() => {
if (sampleInfoStatus.value === 2) return '已寄回'
if (sampleInfoStatus.value === 1) return '已生效'
return ''
})
const sampleInfoStatusClass = computed(() => sampleInfoStatus.value === 2 ? 'returned' : 'effective')
const submitButtonText = computed(() => {
if (sampleInfoStatus.value === 2) return '样品已寄回'
if (sampleInfoStatus.value === 1) return '送检信息已生效'
return '提交送检信息'
})

// 地区数据
const allRegions = ref([])
@@ -196,6 +243,7 @@ const returnRegionText = computed(() => {
})

const onSampleTypesChange = () => {
if (isSampleInfoLocked.value) return
if (!showWaxReturn.value) {
form.wax_return = 0
}
@@ -214,6 +262,7 @@ const onSampleTypesChange = () => {
}

const fillSelfReturn = () => {
if (isSampleInfoLocked.value) return showLockedTip()
form.return_name = patient.value.name || ''
form.return_phone = patient.value.phone || ''
form.return_province_code = patient.value.province_code || ''
@@ -222,6 +271,11 @@ const fillSelfReturn = () => {
form.return_address = patient.value.address || ''
}

const openRegionPicker = () => {
if (isSampleInfoLocked.value) return showLockedTip()
showRegionPicker.value = true
}

onLoad(async () => {
await loadRegions()
await loadPatientInfo()
@@ -245,6 +299,13 @@ const loadPatientInfo = async () => {
form.report_email = res.data.report_email || ''
form.sample_tracking_no = res.data.sample_tracking_no || ''
form.sample_photos = res.data.sample_photos || []
sampleInfoStatus.value = Number(res.data.sample_info_status) || 0
returnTrackingNo.value = res.data.return_tracking_no || ''
returnTime.value = res.data.return_time || ''
sampleReceiverInfo.value = res.data.sample_receiver_info || { address: '', receiver: '', phone: '' }
if (sampleInfoStatus.value === 1) {
setTimeout(() => showLockedTip(), 300)
}
}
} catch (e) {}
}
@@ -288,6 +349,7 @@ const onRegionChange = (e) => {
}

const onRegionConfirm = (e) => {
if (isSampleInfoLocked.value) return
const idxs = e.indexs || e.index || [0, 0, 0]
const provinces = allRegions.value
const prov = provinces[idxs[0]]
@@ -300,6 +362,7 @@ const onRegionConfirm = (e) => {
}

const chooseSamplePhoto = () => {
if (isSampleInfoLocked.value) return showLockedTip()
uni.chooseImage({
count: 9 - form.sample_photos.length,
sizeType: ['compressed'],
@@ -325,7 +388,87 @@ const openNotice = () => {
uni.navigateTo({ url: '/pages/content/content?key=patient_information_sheet' })
}

const getContactPhone = () => sampleReceiverInfo.value.contact_phone || ''
const getCleanPhone = () => getContactPhone().replace(/[^\d+]/g, '')

const contactPlatform = () => {
const phone = getContactPhone()
if (!phone) return uni.showToast({ title: '暂无联系电话', icon: 'none' })
// #ifdef H5
uni.setClipboardData({
data: phone,
success: () => uni.showToast({ title: '电话已复制', icon: 'success' })
})
// #endif
// #ifndef H5
uni.makePhoneCall({ phoneNumber: getCleanPhone() })
// #endif
}

const showLockedTip = () => {
if (isSampleReturned.value) {
uni.showModal({
title: '提示',
content: `样品已经寄回,回寄物流单号:${returnTrackingNo.value || '—'}。`,
cancelText: '知道了',
confirmText: '复制单号',
success: (res) => {
if (res.confirm) copyReturnTrackingNo()
}
})
return
}
const phone = getContactPhone()
if (!phone) {
uni.showModal({
title: '提示',
content: '送检信息已生效,如需修改请联系平台重置修改权限。',
showCancel: false,
confirmText: '知道了'
})
return
}
uni.showModal({
title: '提示',
content: `送检信息已生效,如需修改请联系平台【${phone}】重置修改权限。`,
cancelText: '知道了',
confirmText: '联系平台',
success: (res) => {
if (res.confirm) contactPlatform()
}
})
}

const copyReturnTrackingNo = () => {
if (!returnTrackingNo.value) return uni.showToast({ title: '暂无单号', icon: 'none' })
uni.setClipboardData({
data: returnTrackingNo.value,
success: () => uni.showToast({ title: '单号已复制', icon: 'success' })
})
}

const copySampleReceiverInfo = () => {
const info = sampleReceiverInfo.value
const text = [
`收件地址:${info.address || ''}`,
`收件人:${info.receiver || ''}`,
`电话:${info.phone || ''}`
].join('\n')
uni.setClipboardData({
data: text,
success: () => uni.showToast({ title: '已复制', icon: 'success' })
})
}

const toggleAgree = () => {
if (isSampleInfoLocked.value) return showLockedTip()
agreed.value = !agreed.value
}

const handleSubmit = async () => {
if (isSampleInfoLocked.value) {
return showLockedTip()
}
if (!agreed.value) {
return uni.showToast({ title: '请阅读并同意《患者告知书》', icon: 'none' })
}
@@ -347,9 +490,17 @@ const handleSubmit = async () => {
submitting.value = true
try {
await post('/api/mp/saveSampleInfo', { ...form })
sampleInfoStatus.value = 1
uni.showToast({ title: '提交成功', icon: 'success' })
setTimeout(() => uni.navigateBack(), 1500)
} catch (e) {
if (e && e.data && [1, 2].includes(Number(e.data.sample_info_status))) {
sampleInfoStatus.value = Number(e.data.sample_info_status)
returnTrackingNo.value = e.data.return_tracking_no || returnTrackingNo.value
returnTime.value = e.data.return_time || returnTime.value
if (e.data.sample_receiver_info) sampleReceiverInfo.value = e.data.sample_receiver_info
return showLockedTip()
}
if (e && e.msg) uni.showToast({ title: e.msg, icon: 'none' })
} finally {
submitting.value = false
@@ -361,15 +512,26 @@ const handleSubmit = async () => {
.page { min-height: 100vh; background: #f4f4f5; padding: 24rpx; padding-bottom: 260rpx; }
.section { background: #fff; border-radius: 10rpx; padding: 32rpx; margin-bottom: 24rpx; border: 1rpx solid #ebeef5; }
.section-title { display: flex; align-items: center; gap: 12rpx; font-size: 32rpx; font-weight: 600; color: #333; margin-bottom: 28rpx; }
.status-pill { margin-left: auto; font-size: 22rpx; font-weight: 500; padding: 4rpx 14rpx; border-radius: 6rpx; &.effective { color: #52c41a; background: #f6ffed; border: 1rpx solid #b7eb8f; } &.returned { color: #0e63e3; background: #f0f5ff; border: 1rpx solid #adc6ff; } }
.info-compact { padding-bottom: 8rpx; }
.info-compact-row { display: flex; gap: 32rpx; margin-bottom: 12rpx; &:last-child { margin-bottom: 0; } }
.info-compact-item { font-size: 26rpx; color: #666; }
.return-info { background: #f0f5ff; border-left: 6rpx solid #0e63e3; border-radius: 8rpx; padding: 24rpx; margin-bottom: 20rpx; }
.return-title { display: block; font-size: 30rpx; font-weight: 600; color: #303133; margin-bottom: 12rpx; }
.return-text { display: block; font-size: 28rpx; color: #0e63e3; font-weight: 600; line-height: 1.5; }
.return-time { display: block; font-size: 24rpx; color: #909399; margin-top: 8rpx; }
.copy-return-no { display: block; text-align: right; font-size: 26rpx; color: #0e63e3; margin-top: 12rpx; }
.receiver-info { padding-bottom: 8rpx; }
.receiver-row { display: flex; gap: 20rpx; margin-bottom: 14rpx; &:last-child { margin-bottom: 0; } }
.receiver-label { width: 120rpx; flex-shrink: 0; font-size: 26rpx; color: #909399; }
.receiver-value { flex: 1; font-size: 26rpx; color: #303133; line-height: 1.6; }
.copy-receiver { margin-top: 20rpx; color: #0e63e3; font-size: 26rpx; text-align: right; }
.form-group { padding: 20rpx 0; border-bottom: 1rpx solid #f0f0f0; &:last-child { border-bottom: none; } }
.form-label { font-size: 28rpx; color: #555; margin-bottom: 16rpx; display: block; }
.region-row { display: flex; align-items: center; justify-content: space-between; padding: 20rpx 24rpx; border: 1rpx solid #ddd; border-radius: 8rpx; }
.region-row { display: flex; align-items: center; justify-content: space-between; padding: 20rpx 24rpx; border: 1rpx solid #ddd; border-radius: 8rpx; &.disabled { background: #f7f8fa; } }
.region-text { font-size: 28rpx; color: #333; &.placeholder { color: #c0c4cc; } }
.arrow { font-size: 28rpx; color: #c0c4cc; }
.fill-self-btn { font-size: 24rpx; color: #0e63e3; padding: 6rpx 16rpx; border: 1rpx solid #d0e0ff; border-radius: 20rpx; background: #f0f5ff; }
.fill-self-btn { font-size: 24rpx; color: #0e63e3; padding: 6rpx 16rpx; border: 1rpx solid #d0e0ff; border-radius: 20rpx; background: #f0f5ff; &.disabled { color: #c0c4cc; border-color: #e4e7ed; background: #f7f8fa; } }
.upload-row { display: flex; gap: 16rpx; flex-wrap: wrap; }
.upload-item { position: relative; width: 180rpx; height: 180rpx; }
.upload-img { width: 180rpx; height: 180rpx; border-radius: 8rpx; border: 1rpx solid #eee; }


Loading…
Cancel
Save