| | |
| | | |
| | | <view class="form-grid"> |
| | | <!-- 修改后:治疗医院输入框 --> |
| | | <view class="form-item"> |
| | | <!-- <view class="form-item"> |
| | | <text class="item-label required">治疗医院</text> |
| | | <u-input |
| | | v-model="form.treatmenthospitalname" |
| | |
| | | maxlength="100" |
| | | class="custom-input" |
| | | /> |
| | | </view> |
| | | </view> --> |
| | | |
| | | <!-- 新增:上报医院 --> |
| | | <view class="form-item"> |
| | |
| | | |
| | | <!-- 新增:部门名称 --> |
| | | <view class="form-item"> |
| | | <text class="item-label">部门名称</text> |
| | | <text class="item-label">科室名称</text> |
| | | <u-input |
| | | v-model="form.deptName" |
| | | placeholder="请输入部门名称" |
| | | placeholder="请输入上报科室" |
| | | maxlength="50" |
| | | class="custom-input" |
| | | /> |
| | |
| | | placeholder="请输入证件号码" |
| | | maxlength="18" |
| | | class="custom-input" |
| | | @blur="validateIdCard" |
| | | @blur="onIdCardChange" |
| | | /> |
| | | <text class="error-text" v-if="idCardError">{{ |
| | | idCardError |
| | |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view class="form-item"> |
| | | <view class="form-item full-width"> |
| | | <text class="item-label">传染病</text> |
| | | <view class="radio-group horizontal"> |
| | | <view class="checkbox-group single-line"> |
| | | <view |
| | | v-for="bloodType in infectiousDiseaselist" |
| | | :key="bloodType.value" |
| | | class="radio-item" |
| | | @click="form.infectious = bloodType.value" |
| | | v-for="disease in infectiousDiseaselist" |
| | | :key="disease.value" |
| | | class="checkbox-item" |
| | | @click="toggleInfectious(disease.value)" |
| | | > |
| | | <view |
| | | class="radio-dot" |
| | | :class="{ active: form.infectious == bloodType.value }" |
| | | ></view> |
| | | <text class="radio-label">{{ bloodType.label }}</text> |
| | | class="checkbox-box" |
| | | :class="{ active: isInfectiousSelected(disease.value) }" |
| | | > |
| | | <text |
| | | v-if="isInfectiousSelected(disease.value)" |
| | | class="checkbox-check" |
| | | >✓</text |
| | | > |
| | | </view> |
| | | <text class="checkbox-label">{{ disease.label }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view class="form-item"> |
| | | <view class="form-item full-width""> |
| | | <text class="item-label">其他</text> |
| | | <u-input |
| | | v-model="form.infectiousOther" |
| | |
| | | |
| | | <view class="form-grid"> |
| | | <view class="form-item"> |
| | | <text class="item-label">信息员</text> |
| | | <text class="item-label">上报信息员</text> |
| | | <u-input |
| | | v-model="form.infoname" |
| | | v-model="form.infoName" |
| | | placeholder="请输入信息员" |
| | | border="none" |
| | | /> |
| | |
| | | <view class="form-item"> |
| | | <text class="item-label">联系电话</text> |
| | | <u-input |
| | | v-model="form.infophone" |
| | | v-model="form.phone" |
| | | placeholder="请输入联系电话" |
| | | type="number" |
| | | border="none" |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, computed, onMounted } from "vue"; |
| | | import { ref, computed, onMounted, watch } from "vue"; |
| | | import { onLoad } from "@dcloudio/uni-app"; |
| | | import attachmentUpload from "@/components/attachment"; |
| | | import { useUserStore } from "@/stores/user"; |
| | |
| | | const userStore = useUserStore(); |
| | | const isEditMode = ref(false); |
| | | const currentId = ref(null); |
| | | const selectedInfectious = ref([]); // 存储选中的传染病值数组 |
| | | |
| | | // 表单数据 |
| | | const form = ref({ |
| | | caseNo: "", |
| | | treatmenthospitalname: "", |
| | | treatmenthospitalname: userStore.userInfo.user.orgName, |
| | | toHospital: userStore.userInfo.user.orgName, |
| | | coordinatorName: userStore.userInfo.user.coordinatorName, |
| | | coordinatorNo: userStore.userInfo.user.coordinatorNo, |
| | | treatmentdeptname: "", |
| | | name: "", |
| | | nation: "", |
| | |
| | | diagnosisname: "", |
| | | bloodType: "", |
| | | rhYin: "", |
| | | infoname: "", |
| | | infophone: "", |
| | | infoName: userStore.userInfo.user.nickName, |
| | | phone: userStore.userInfo.user.phonenumber, |
| | | reportername: userStore.name || "", |
| | | reporterno: userStore.userId || "", |
| | | reporterphone: "", // 报告者联系电话 |
| | |
| | | nativeplace: "", // 新增:籍贯 |
| | | occupation: "", // 新增:职业 |
| | | patientstate: "", // 新增:病人状况 |
| | | phone: "", // 新增:联系电话 |
| | | registeraddress: "", // 新增:户籍地址 |
| | | registerprovince: "", // 新增:户籍地址省编号 |
| | | registerprovincename: "", // 新增:户籍地址省名称 |
| | |
| | | const currentNation = computed(() => { |
| | | return nationIndex.value >= 0 |
| | | ? nationLabels.value[nationIndex.value] |
| | | : "请选择民族"; |
| | | : (form.value.nation?form.value.nation:"请选择证件类型"); |
| | | }); |
| | | |
| | | const currentIdCardType = computed(() => { |
| | |
| | | // 身份证验证 |
| | | const idCardError = ref(""); |
| | | const validateIdCard = () => { |
| | | if (!form.value.idcardno) { |
| | | const idCard = form.value.idcardno; |
| | | console.log(idCard, "当前输入"); |
| | | |
| | | if (!idCard) { |
| | | idCardError.value = "请输入证件号码"; |
| | | return false; |
| | | } |
| | | |
| | | if (form.value.idcardno.length !== 18) { |
| | | idCardError.value = "请输入18位身份证号码"; |
| | | if (idCard.length !== 18) { |
| | | idCardError.value = "身份证号码必须是18位"; |
| | | return false; |
| | | } |
| | | console.log(1); |
| | | |
| | | // 验证前17位必须是数字 |
| | | const reg = /^\d{17}(\d|X|x)$/; |
| | | if (!reg.test(idCard)) { |
| | | idCardError.value = "身份证号码格式不正确"; |
| | | return false; |
| | | } |
| | | console.log(2); |
| | | |
| | | // 验证出生日期 |
| | | const birthStr = idCard.substring(6, 14); |
| | | const year = birthStr.substring(0, 4); |
| | | const month = birthStr.substring(4, 6); |
| | | const day = birthStr.substring(6, 8); |
| | | |
| | | const birthDate = new Date(`${year}-${month}-${day}`); |
| | | if (isNaN(birthDate.getTime())) { |
| | | idCardError.value = "身份证号码中的出生日期无效"; |
| | | return false; |
| | | } |
| | | console.log(3); |
| | | |
| | | // 验证日期范围(1900年至今) |
| | | const currentYear = new Date().getFullYear(); |
| | | const birthYear = parseInt(year, 10); |
| | | if (birthYear < 1900 || birthYear > currentYear) { |
| | | idCardError.value = "出生年份不在有效范围内"; |
| | | return false; |
| | | } |
| | | console.log(4); |
| | | |
| | | // 验证校验码(第18位) |
| | | if (!validateIdCardCheckCode(idCard)) { |
| | | idCardError.value = "身份证号码校验失败"; |
| | | return false; |
| | | } |
| | | console.log(5); |
| | | |
| | | idCardError.value = ""; |
| | | return true; |
| | | }; |
| | | // 样式方法 |
| | | const inputStyle = (isError) => { |
| | | return isError |
| | | ? "border: 2rpx solid #ff4757; border-radius: 12rpx;" |
| | | : "border: 2rpx solid #e5e5e7; border-radius: 12rpx;"; |
| | | // 身份证号变化处理 |
| | | const onIdCardChange = (value) => { |
| | | // 验证身份证格式 |
| | | if (validateIdCard()) { |
| | | // 尝试提取出生日期 |
| | | extractBirthdayFromIdCard(); |
| | | } |
| | | }; |
| | | // 身份证校验码验证函数 |
| | | const validateIdCardCheckCode = (idCard) => { |
| | | // 系数数组 |
| | | const coefficientArray = [ |
| | | 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, |
| | | ]; |
| | | // 校验码对应值 |
| | | const checkCodeMap = ["1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"]; |
| | | |
| | | let sum = 0; |
| | | for (let i = 0; i < 17; i++) { |
| | | sum += parseInt(idCard.charAt(i), 10) * coefficientArray[i]; |
| | | } |
| | | |
| | | const checkCode = checkCodeMap[sum % 11]; |
| | | return checkCode === idCard.charAt(17).toUpperCase(); |
| | | }; |
| | | // 从身份证号提取出生日期 |
| | | const extractBirthdayFromIdCard = () => { |
| | | const idCard = form.value.idcardno; |
| | | |
| | | if (!idCard || idCard.length !== 18) { |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | // 提取出生日期部分(第7-14位:YYYYMMDD) |
| | | const birthStr = idCard.substring(6, 14); |
| | | const year = birthStr.substring(0, 4); |
| | | const month = birthStr.substring(4, 6); |
| | | const day = birthStr.substring(6, 8); |
| | | |
| | | // 验证日期是否有效 |
| | | const birthDate = new Date(`${year}-${month}-${day}`); |
| | | if (isNaN(birthDate.getTime())) { |
| | | console.log("身份证号码中的出生日期无效"); |
| | | return; |
| | | } |
| | | |
| | | // 验证日期范围(不能是未来日期) |
| | | const today = new Date(); |
| | | if (birthDate > today) { |
| | | console.log("出生日期不能是未来日期"); |
| | | return; |
| | | } |
| | | |
| | | // 验证月份和日期是否合理 |
| | | const monthNum = parseInt(month, 10); |
| | | const dayNum = parseInt(day, 10); |
| | | |
| | | if (monthNum < 1 || monthNum > 12) { |
| | | console.log("月份无效"); |
| | | return; |
| | | } |
| | | |
| | | // 检查日期是否有效(简单验证) |
| | | const daysInMonth = new Date(year, monthNum, 0).getDate(); |
| | | if (dayNum < 1 || dayNum > daysInMonth) { |
| | | console.log("日期无效"); |
| | | return; |
| | | } |
| | | |
| | | // 设置出生日期 |
| | | form.value.birthday = `${year}-${month.padStart(2, "0")}-${day.padStart( |
| | | 2, |
| | | "0", |
| | | )}`; |
| | | |
| | | // 计算年龄 |
| | | calculateAge(); |
| | | |
| | | // 从身份证提取性别(第17位,奇数为男,偶数为女) |
| | | const genderCode = parseInt(idCard.charAt(16), 10); |
| | | if (!isNaN(genderCode)) { |
| | | form.value.sex = genderCode % 2 === 1 ? "1" : "2"; |
| | | } |
| | | |
| | | uni.showToast({ |
| | | title: "已自动提取出生日期和性别", |
| | | icon: "success", |
| | | duration: 1500, |
| | | }); |
| | | } catch (error) { |
| | | console.error("解析身份证出生日期失败:", error); |
| | | } |
| | | }; |
| | | |
| | | const textareaStyle = (isError) => { |
| | |
| | | infectiousDiseaselist.value = dict.value.sys_Infectious || []; |
| | | idCardTypeOptions.value = dict.value.sys_IDType || []; |
| | | nationLabel.value = dict.value.sys_Nation || []; |
| | | |
| | | // 初始化传染病选择状态 |
| | | if (form.value.infectious) { |
| | | // 将逗号分隔的字符串转换为数组 |
| | | selectedInfectious.value = form.value.infectious |
| | | .split(",") |
| | | .filter((item) => item.trim() !== ""); |
| | | } |
| | | }; |
| | | // 切换传染病选择 |
| | | const toggleInfectious = (value) => { |
| | | const index = selectedInfectious.value.indexOf(value); |
| | | |
| | | if (index === -1) { |
| | | // 添加选中 |
| | | selectedInfectious.value.push(value); |
| | | } else { |
| | | // 移除选中 |
| | | selectedInfectious.value.splice(index, 1); |
| | | } |
| | | |
| | | // 更新表单的 infectious 字段(逗号分隔的字符串) |
| | | form.value.infectious = selectedInfectious.value.join(","); |
| | | }; |
| | | // 检查传染病是否被选中 |
| | | const isInfectiousSelected = (value) => { |
| | | return selectedInfectious.value.includes(value); |
| | | }; |
| | | |
| | | // 方法定义 |
| | | const updateCurrentTime = () => { |
| | | const now = new Date(); |
| | |
| | | |
| | | // 检查日期有效性 |
| | | if (isNaN(birthDate.getTime())) { |
| | | form.value.age = ""; |
| | | form.value.ageunit = ""; |
| | | return; |
| | | } |
| | | |
| | | // 检查是否为未来日期 |
| | | if (birthDate > today) { |
| | | uni.showToast({ |
| | | title: "出生日期不能是未来日期", |
| | | icon: "none", |
| | | }); |
| | | form.value.age = ""; |
| | | form.value.ageunit = ""; |
| | | return; |
| | |
| | | deptIndex.value = -1; |
| | | nationIndex.value = -1; |
| | | idCardTypeIndex.value = -1; |
| | | // 重置传染病选择 |
| | | selectedInfectious.value = []; |
| | | |
| | | // 重置附件 |
| | | attachments.value = []; |
| | | form.value.nationality = "中国"; |
| | | form.value.isTransport = "1"; |
| | |
| | | fileName: file.name, |
| | | type: file.type, |
| | | })), |
| | | phone: form.value.infophone, |
| | | isTransport: form.value.isTransport || "1", |
| | | terminationCase: form.value.terminationCase || 0, |
| | | reportStatus: form.value.reportStatus || "1", |
| | |
| | | |
| | | if (res.code) { |
| | | form.value = res.data; |
| | | |
| | | if (res.data.infectious) { |
| | | selectedInfectious.value = res.data.infectious |
| | | .split(",") |
| | | .filter((item) => item.trim() !== ""); |
| | | } |
| | | currentNation.value=form.value.nation; |
| | | idCardTypeIndex.value=form.value.idcardtype; |
| | | // 处理选择器索引 |
| | | // updatePickerIndexes(); |
| | | |
| | | console.log(2, "res"); |
| | | // 处理附件 |
| | | if (res.data.annexfilesList) { |
| | | attachments.value = res.data.annexfilesList; |
| | |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | |
| | | </script> |
| | | <style lang="scss" scoped> |
| | | .case-report-container { |
| | |
| | | padding: 20rpx 24rpx !important; |
| | | background: #fff !important; |
| | | } |
| | | .idcard-hint { |
| | | margin-top: 8rpx; |
| | | padding: 12rpx 16rpx; |
| | | background: #f0f9ff; |
| | | border-radius: 8rpx; |
| | | border-left: 4rpx solid #0f95b0; |
| | | } |
| | | |
| | | .hint-text { |
| | | display: block; |
| | | font-size: 24rpx; |
| | | color: #0f95b0; |
| | | margin-bottom: 4rpx; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .error-text { |
| | | font-size: 24rpx; |
| | | color: #ff4757; |
| | | margin-top: 8rpx; |
| | | } |
| | | .btn { |
| | | flex: 1; |
| | | height: 80rpx; |
| | |
| | | } |
| | | } |
| | | } |
| | | .checkbox-group { |
| | | display: flex; |
| | | flex-wrap: nowrap; /* 禁止换行 */ |
| | | gap: 20rpx; |
| | | overflow-x: auto; /* 水平滚动 */ |
| | | padding-bottom: 10rpx; /* 给滚动条留出空间 */ |
| | | -webkit-overflow-scrolling: touch; /* iOS平滑滚动 */ |
| | | |
| | | &.single-line { |
| | | display: flex; |
| | | flex-wrap: nowrap; |
| | | overflow-x: auto; |
| | | width: 100%; |
| | | |
| | | /* 隐藏滚动条,但保持滚动功能 */ |
| | | &::-webkit-scrollbar { |
| | | display: none; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .checkbox-item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8rpx; |
| | | flex-shrink: 0; /* 防止选项被压缩 */ |
| | | padding: 8rpx 16rpx; |
| | | border-radius: 20rpx; |
| | | background: #f5f5f7; |
| | | transition: all 0.3s ease; |
| | | |
| | | &.active { |
| | | background: rgba(15, 149, 176, 0.1); |
| | | } |
| | | } |
| | | |
| | | .checkbox-box { |
| | | width: 28rpx; |
| | | height: 28rpx; |
| | | border: 2rpx solid #e5e5e7; |
| | | border-radius: 6rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background: #fff; |
| | | transition: all 0.3s ease; |
| | | flex-shrink: 0; |
| | | |
| | | &.active { |
| | | border-color: #0f95b0; |
| | | background: #0f95b0; |
| | | } |
| | | } |
| | | |
| | | .checkbox-check { |
| | | font-size: 20rpx; |
| | | color: white; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .checkbox-label { |
| | | font-size: 24rpx; |
| | | color: #1d1d1f; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | /* 优化单选按钮组的样式,保持一致性 */ |
| | | .radio-group.horizontal { |
| | | display: flex; |
| | | flex-wrap: nowrap; |
| | | overflow-x: auto; |
| | | gap: 20rpx; |
| | | padding-bottom: 10rpx; |
| | | -webkit-overflow-scrolling: touch; |
| | | |
| | | &::-webkit-scrollbar { |
| | | display: none; |
| | | } |
| | | |
| | | .radio-item { |
| | | flex-shrink: 0; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8rpx; |
| | | padding: 8rpx 16rpx; |
| | | border-radius: 20rpx; |
| | | } |
| | | |
| | | .radio-item .radio-dot.active { |
| | | border-color: #0f95b0; |
| | | |
| | | &::after { |
| | | background: #0f95b0; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /* 如果需要固定高度,可以这样设置 */ |
| | | .checkbox-group.single-line { |
| | | min-height: 60rpx; |
| | | align-items: center; |
| | | } |
| | | |
| | | /* 在移动端优化触摸区域 */ |
| | | .checkbox-item { |
| | | min-height: 60rpx; |
| | | padding: 8rpx 20rpx; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | /* 添加选中状态的视觉反馈 */ |
| | | .checkbox-item.active { |
| | | border: 1rpx solid #0f95b0; |
| | | background: rgba(15, 149, 176, 0.08); |
| | | } |
| | | |
| | | /* 响应式调整 */ |
| | | @media (max-width: 768px) { |
| | | .checkbox-group.single-line { |
| | | gap: 12rpx; |
| | | } |
| | | |
| | | .checkbox-item { |
| | | padding: 6rpx 14rpx; |
| | | } |
| | | |
| | | .checkbox-label { |
| | | font-size: 22rpx; |
| | | } |
| | | } |
| | | </style> |