317 lines
8.4 KiB
Vue
317 lines
8.4 KiB
Vue
<template>
|
|
<view class="container" :class="{ 'container--elder': elderMode }">
|
|
<template v-if="logined">
|
|
<view class="main">
|
|
<scroll-view scroll-y="true" class="main-scroll">
|
|
<view class="card">
|
|
<uni-list>
|
|
<uni-list-item direction="column">
|
|
<template v-slot:body>
|
|
<view class="info-item">
|
|
<text class="item-label">姓名</text>
|
|
<input v-model="form.name" :maxlength="20" class="item-value" type="text"
|
|
placeholder="请输入姓名" />
|
|
</view>
|
|
<view class="info-item">
|
|
<text class="item-label">证件类型</text>
|
|
<text class="item-value">身份证</text>
|
|
</view>
|
|
<view class="info-item">
|
|
<text class="item-label">证件号</text>
|
|
<input v-model="form.certNo" :maxlength="18" class="item-value" type="idcard"
|
|
placeholder="请输入证件号" />
|
|
</view>
|
|
<view class="info-item">
|
|
<text class="item-label">手机号</text>
|
|
<input v-model="form.mobile" :maxlength="11" class="item-value" type="number"
|
|
placeholder="请输入手机号" />
|
|
</view>
|
|
<view class="info-item address-item">
|
|
<view class="address-header">
|
|
<text class="item-label">地址</text>
|
|
<text class="choose-address" @click="chooseAddress">选择地址</text>
|
|
</view>
|
|
<textarea v-model="form.address" :maxlength="200" class="address-textarea"
|
|
placeholder="请输入详细地址"></textarea>
|
|
</view>
|
|
</template>
|
|
</uni-list-item>
|
|
</uni-list>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
|
|
<view class="save-footer">
|
|
<view class="save-btn" :class="{ 'save-btn--disabled': loading }" @click="confirm">
|
|
{{ loading ? '保存中...' : '保存' }}
|
|
</view>
|
|
</view>
|
|
<view class="safearea-bottom"></view>
|
|
</template>
|
|
|
|
<re-login v-else height="80vh" />
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed, ref, watch } from 'vue';
|
|
import { onLoad } from '@dcloudio/uni-app';
|
|
import useUser from '@/hooks/useUser';
|
|
import { addHlwPatient, getHlwPatient, updateHlwPatient } from '@/utils/api';
|
|
import { isChinaId } from '@/utils/validator';
|
|
import { toast } from '@/utils/widget';
|
|
import reLogin from '@/components/re-login.vue';
|
|
|
|
const id = ref('');
|
|
const loading = ref(false);
|
|
const elderMode = ref(false);
|
|
const loadedPatientKey = ref('');
|
|
const form = ref({
|
|
name: '',
|
|
certNo: '',
|
|
mobile: '',
|
|
address: '',
|
|
});
|
|
|
|
const { userInfo, logined } = useUser();
|
|
const accountId = computed(() => userInfo.value && userInfo.value.userId ? userInfo.value.userId : '');
|
|
|
|
function validateForm() {
|
|
if (!form.value.name.trim()) {
|
|
toast('姓名不能为空');
|
|
return false;
|
|
}
|
|
if (!form.value.certNo.trim()) {
|
|
toast('证件号不能为空');
|
|
return false;
|
|
}
|
|
if (!isChinaId(form.value.certNo.trim())[0]) {
|
|
toast('请输入有效的身份证号');
|
|
return false;
|
|
}
|
|
if (!/^1[3-9]\d{9}$/.test(form.value.mobile.trim())) {
|
|
toast('请输入有效的手机号');
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function chooseAddress() {
|
|
uni.chooseLocation({
|
|
success: location => {
|
|
const address = typeof location.address === 'string' ? location.address.trim() : '';
|
|
const name = typeof location.name === 'string' ? location.name.trim() : '';
|
|
form.value.address = address && name && !address.endsWith(name)
|
|
? `${address}${name}`
|
|
: address || name;
|
|
},
|
|
fail: error => {
|
|
if (!error || !/cancel/i.test(error.errMsg || '')) {
|
|
toast('选择地址失败');
|
|
}
|
|
},
|
|
});
|
|
}
|
|
|
|
async function confirm() {
|
|
if (loading.value || !validateForm()) return;
|
|
if (!accountId.value) {
|
|
toast('请先登录');
|
|
return;
|
|
}
|
|
|
|
loading.value = true;
|
|
try {
|
|
const payload = {
|
|
accountId: accountId.value,
|
|
name: form.value.name.trim(),
|
|
certNo: form.value.certNo.trim(),
|
|
mobile: form.value.mobile.trim(),
|
|
address: form.value.address.trim(),
|
|
};
|
|
const api = id.value ? updateHlwPatient : addHlwPatient;
|
|
const res = await api(id.value ? { ...payload, id: id.value } : payload);
|
|
if (!res || !res.success) {
|
|
toast((res && res.message) || '保存失败');
|
|
return;
|
|
}
|
|
|
|
toast('保存成功');
|
|
const pages = getCurrentPages();
|
|
if (pages.length > 1) {
|
|
uni.navigateBack();
|
|
} else {
|
|
uni.redirectTo({ url: '/pages/member/list' });
|
|
}
|
|
} catch (error) {
|
|
toast(error.message || error || '保存失败');
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
async function loadPatient() {
|
|
if (!id.value || !accountId.value) return;
|
|
const patientKey = `${accountId.value}:${id.value}`;
|
|
if (loadedPatientKey.value === patientKey) return;
|
|
|
|
loading.value = true;
|
|
try {
|
|
const res = await getHlwPatient(accountId.value, id.value);
|
|
if (!res || !res.success || !res.data) {
|
|
toast((res && res.message) || '查询就诊人失败');
|
|
return;
|
|
}
|
|
form.value = {
|
|
name: res.data.name || '',
|
|
certNo: res.data.certNo || '',
|
|
mobile: res.data.mobile || '',
|
|
address: res.data.address || '',
|
|
};
|
|
loadedPatientKey.value = patientKey;
|
|
} catch (error) {
|
|
toast(error.message || error || '查询就诊人失败');
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
onLoad(options => {
|
|
id.value = options.id || '';
|
|
uni.setNavigationBarTitle({ title: id.value ? '编辑就诊人' : '新增就诊人' });
|
|
|
|
const savedElderMode = uni.getStorageSync('elderMode');
|
|
if (savedElderMode !== null && savedElderMode !== undefined) {
|
|
elderMode.value = savedElderMode;
|
|
}
|
|
});
|
|
|
|
watch([id, accountId], loadPatient, { immediate: true });
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
background-color: #f5f5f5;
|
|
height: 100vh;
|
|
--font-scale: 1;
|
|
--spacing-scale: 1;
|
|
--border-radius-scale: 1;
|
|
|
|
@at-root &--elder {
|
|
--font-scale: 1.4;
|
|
--spacing-scale: 1.2;
|
|
--border-radius-scale: 1.25;
|
|
}
|
|
}
|
|
|
|
.main {
|
|
position: relative;
|
|
flex-grow: 1;
|
|
}
|
|
|
|
.main-scroll {
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
top: 0;
|
|
bottom: 0;
|
|
}
|
|
|
|
.card {
|
|
margin: calc(30rpx * var(--spacing-scale));
|
|
border-radius: calc(16rpx * var(--border-radius-scale));
|
|
overflow: hidden;
|
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
.info-item {
|
|
background: #fff;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: calc(24rpx * var(--spacing-scale)) calc(30rpx * var(--spacing-scale));
|
|
border-bottom: 1rpx solid #eee;
|
|
min-height: calc(80rpx * var(--spacing-scale));
|
|
|
|
&:last-child {
|
|
border-bottom: none;
|
|
}
|
|
}
|
|
|
|
.address-item {
|
|
display: block;
|
|
}
|
|
|
|
.address-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
width: 100%;
|
|
margin-bottom: calc(20rpx * var(--spacing-scale));
|
|
}
|
|
|
|
.choose-address {
|
|
color: $theme-brown-primary;
|
|
font-size: calc(30rpx * var(--font-scale));
|
|
font-weight: 500;
|
|
}
|
|
|
|
.address-textarea {
|
|
box-sizing: border-box;
|
|
width: 100%;
|
|
height: calc(160rpx * var(--spacing-scale));
|
|
padding: calc(20rpx * var(--spacing-scale));
|
|
border-radius: calc(8rpx * var(--border-radius-scale));
|
|
background: #f7f7f7;
|
|
color: #333;
|
|
font-size: calc(30rpx * var(--font-scale));
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.item-label {
|
|
color: #666;
|
|
font-size: calc(30rpx * var(--font-scale));
|
|
width: calc(200rpx * var(--spacing-scale));
|
|
font-weight: 500;
|
|
}
|
|
|
|
.item-value {
|
|
color: #333;
|
|
font-size: calc(30rpx * var(--font-scale));
|
|
font-weight: 500;
|
|
flex: 1;
|
|
text-align: right;
|
|
|
|
.container--elder & {
|
|
font-weight: 600;
|
|
}
|
|
}
|
|
|
|
.save-footer {
|
|
padding: calc(24rpx * var(--spacing-scale)) calc(30rpx * var(--spacing-scale));
|
|
background: white;
|
|
}
|
|
|
|
.save-btn {
|
|
height: calc(80rpx * var(--spacing-scale));
|
|
background: $theme-brown-primary;
|
|
color: white;
|
|
font-size: calc(28rpx * var(--font-scale));
|
|
border-radius: calc(16rpx * var(--border-radius-scale));
|
|
text-align: center;
|
|
line-height: calc(80rpx * var(--spacing-scale));
|
|
font-weight: 500;
|
|
|
|
&--disabled {
|
|
opacity: 0.6;
|
|
}
|
|
}
|
|
|
|
.safearea-bottom {
|
|
height: env(safe-area-inset-bottom);
|
|
flex-shrink: 0;
|
|
}
|
|
</style>
|