diff --git a/app.json b/app.json index af1578b..d9d1bba 100644 --- a/app.json +++ b/app.json @@ -14,7 +14,8 @@ "pages/askingSyDetails/askingSyDetails", "pages/advisory/advisory", "pages/releaseSuffer/releaseSuffer", - "pages/precept/precept" + "pages/precept/precept", + "pages/attestation/attestation" ] }, { diff --git a/pagesA/pages/askingSy/askingSy.js b/pagesA/pages/askingSy/askingSy.js index 025df01..844e5d5 100644 --- a/pagesA/pages/askingSy/askingSy.js +++ b/pagesA/pages/askingSy/askingSy.js @@ -1,7 +1,9 @@ import http from '../../../utils/api' +const baseUrl = require('../../../utils/baseUrl') Page({ data: { - diagnosisList: [] + diagnosisList: [], + baseUrl:baseUrl }, onLoad: function () { diff --git a/pagesA/pages/askingSy/askingSy.wxml b/pagesA/pages/askingSy/askingSy.wxml index 9c89855..f125b39 100644 --- a/pagesA/pages/askingSy/askingSy.wxml +++ b/pagesA/pages/askingSy/askingSy.wxml @@ -33,7 +33,7 @@ - + {{item.farmerName || '用户'}} diff --git a/pagesA/pages/attestation/attestation.js b/pagesA/pages/attestation/attestation.js new file mode 100644 index 0000000..8610fcb --- /dev/null +++ b/pagesA/pages/attestation/attestation.js @@ -0,0 +1,472 @@ +// pages/auth/real-name-auth.js +import http from '../../../utils/api' + +Page({ + data: { + // 表单数据 + name: '', + idNumber: '', + + // 焦点状态 + nameFocus: false, + idNumberFocus: false, + + // 错误提示 + nameError: '', + idNumberError: '', + + // 提示显示控制 + showNameHint: false, + showIdNumberHint: false, + + // 验证状态 + isNameValid: false, + isIdNumberValid: false, + + // 协议状态 + agreed: false, + + // 提交状态 + canSubmit: false, + isSubmitting: false, + + // 进度条 + currentStep: 1, + lineProgress1: 0, + lineProgress2: 0, + + // 弹窗数据 + showModal: false, + modalTitle: '', + modalContent: '', + + // 成功弹窗数据 + showSuccessModal: false, + maskedIdNumber: '', + + // 错误弹窗数据 + showErrorModal: false, + errorTitle: '', + errorMessage: '' + }, + + onLoad() { + // 页面加载时启动进度条动画 + setTimeout(() => { + this.setData({ lineProgress1: 50 }); + }, 600); + }, + + // 姓名输入处理 + onNameInput(e) { + const value = e.detail.value.trim(); + let error = ''; + let showHint = true; + let isValid = false; + + if (value) { + if (!/^[\u4e00-\u9fa5]{2,10}$/.test(value)) { + error = '姓名应为2-10个汉字'; + } else { + isValid = true; + // 验证通过时保持提示显示,但无错误 + } + } else { + // 内容为空时显示正常提示 + error = ''; + } + + this.setData({ + name: value, + nameError: error, + showNameHint: showHint, + isNameValid: isValid + }, () => { + this.checkForm(); + }); + }, + + onNameFocus() { + this.setData({ + nameFocus: true, + showNameHint: true // 获得焦点时显示提示 + }); + }, + + onNameBlur() { + const { name } = this.data; + + this.setData({ + nameFocus: false, + // 失去焦点时,如果内容为空或验证失败,保持提示显示 + showNameHint: !!(name && !this.data.isNameValid) + }); + }, + + // 清除姓名 + clearName() { + this.setData({ + name: '', + nameError: '', + showNameHint: false, + isNameValid: false + }, () => { + this.checkForm(); + }); + }, + + // 身份证号输入处理 + onIdNumberInput(e) { + const value = e.detail.value.trim().toUpperCase(); + let error = ''; + let showHint = true; + let isValid = false; + + if (value) { + if (value.length < 18) { + error = '还需输入' + (18 - value.length) + '位'; + } else if (value.length === 18) { + if (this.validateIdNumber(value)) { + isValid = true; + // 验证通过时保持提示显示,但无错误 + } else { + error = '身份证号格式不正确'; + } + } + } else { + // 内容为空时显示正常提示 + error = ''; + } + + this.setData({ + idNumber: value, + idNumberError: error, + showIdNumberHint: showHint, + isIdNumberValid: isValid + }, () => { + this.checkForm(); + }); + }, + + onIdNumberFocus() { + this.setData({ + idNumberFocus: true, + showIdNumberHint: true // 获得焦点时显示提示 + }); + }, + + onIdNumberBlur() { + const { idNumber } = this.data; + let error = ''; + let isValid = false; + + // 最终验证 + if (idNumber) { + if (idNumber.length < 18) { + error = '还需输入' + (18 - idNumber.length) + '位'; + } else if (idNumber.length === 18) { + if (this.validateIdNumber(idNumber)) { + isValid = true; + } else { + error = '身份证号格式不正确'; + } + } + } + + this.setData({ + idNumberFocus: false, + idNumberError: error, + isIdNumberValid: isValid, + // 失去焦点时,如果内容为空或验证失败,保持提示显示 + showIdNumberHint: !!(idNumber && !isValid) + }); + }, + + // 清除身份证号 + clearIdNumber() { + this.setData({ + idNumber: '', + idNumberError: '', + showIdNumberHint: false, + isIdNumberValid: false + }, () => { + this.checkForm(); + }); + }, + + // 身份证验证函数 + validateIdNumber(idNumber) { + // 基础格式验证 + if (!/^\d{17}[\dXx]$/.test(idNumber)) { + return false; + } + + // 地区码验证(简化的验证,实际应该更严谨) + const areaCode = idNumber.substring(0, 2); + const validAreaCodes = ['11', '12', '13', '14', '15', '21', '22', '23', + '31', '32', '33', '34', '35', '36', '37', '41', + '42', '43', '44', '45', '46', '50', '51', '52', + '53', '54', '61', '62', '63', '64', '65']; + + if (!validAreaCodes.includes(areaCode)) { + return false; + } + + // 出生日期验证 + const year = parseInt(idNumber.substring(6, 10)); + const month = parseInt(idNumber.substring(10, 12)); + const day = parseInt(idNumber.substring(12, 14)); + + const currentYear = new Date().getFullYear(); + if (year < 1900 || year > currentYear) return false; + if (month < 1 || month > 12) return false; + if (day < 1 || day > 31) return false; + + // 校验码验证 + const checkCode = idNumber.charAt(17).toUpperCase(); + const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]; + const checkCodes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']; + + let sum = 0; + for (let i = 0; i < 17; i++) { + sum += parseInt(idNumber.charAt(i)) * weights[i]; + } + + const mod = sum % 11; + return checkCode === checkCodes[mod]; + }, + + // 协议处理 + toggleAgreement() { + const newAgreed = !this.data.agreed; + this.setData({ + agreed: newAgreed + }, () => { + this.checkForm(); + }); + }, + + // 显示协议弹窗 + showAgreementModal() { + const title = '用户服务协议'; + const content = `欢迎您使用"与牧同行"服务!\n\n在使用我们的服务前,请您仔细阅读并同意以下协议:\n\n1. 服务条款\n您在使用与牧同行提供的各项服务时,应当遵守相关法律法规,不得从事任何非法行为。\n\n2. 用户责任\n您需要保证所提供信息的真实性、准确性和完整性。\n\n3. 服务变更\n我们保留随时修改、暂停或终止服务的权利。\n\n4. 免责声明\n在法律法规允许的最大范围内,我们对因使用服务而产生的任何间接损失不承担责任。\n\n5. 法律适用\n本协议的订立、执行和解释及争议的解决均适用中华人民共和国法律。\n\n请您确保已阅读并理解以上条款。`; + + this.showModal(title, content); + }, + + // 显示隐私弹窗 + showPrivacyModal() { + const title = '隐私保护协议'; + const content = `我们非常重视您的隐私保护,请您仔细阅读以下隐私政策:\n\n1. 信息收集\n我们仅收集为您提供服务所必需的信息,包括姓名、身份证号等实名信息。\n\n2. 信息使用\n您的信息仅用于身份验证和服务提供,不会用于其他商业用途。\n\n3. 信息保护\n我们采用先进的安全技术保护您的信息,防止未经授权的访问、使用或泄露。\n\n4. 信息共享\n除非获得您的明确同意,我们不会向第三方共享您的个人信息。\n\n5. 您的权利\n您可以随时查看、更正或删除您的个人信息。\n\n6. 政策更新\n我们可能会不时更新本隐私政策,更新后的政策将在本页面公布。\n\n我们承诺严格遵守相关法律法规,保护您的个人信息安全。`; + + this.showModal(title, content); + }, + + // 显示弹窗 + showModal(title, content) { + this.setData({ + modalTitle: title, + modalContent: content, + showModal: true + }); + }, + + // 关闭弹窗 + closeModal() { + this.setData({ showModal: false }); + }, + + // 显示错误弹窗 + showErrorModal(title, message) { + this.setData({ + errorTitle: title || '认证失败', + errorMessage: message || '请检查信息后重试', + showErrorModal: true + }); + }, + + // 关闭错误弹窗 + closeErrorModal() { + this.setData({ + showErrorModal: false, + isSubmitting: false // 关闭错误弹窗时重置提交状态 + }); + }, + + // 阻止事件冒泡 + stopPropagation(e) { + // 阻止冒泡 + }, + + // 检查表单 + checkForm() { + const { + isNameValid, + isIdNumberValid, + agreed + } = this.data; + + const isValid = isNameValid && + isIdNumberValid && + agreed; + + this.setData({ + canSubmit: isValid + }); + }, + + // 提交认证 + async submitAuth() { + if (!this.data.canSubmit || this.data.isSubmitting) return; + + // 最终验证 + const { name, idNumber } = this.data; + + if (!/^[\u4e00-\u9fa5]{2,10}$/.test(name)) { + this.setData({ + nameError: '姓名应为2-10个汉字', + showNameHint: true, + canSubmit: false + }); + return; + } + + if (!this.validateIdNumber(idNumber)) { + this.setData({ + idNumberError: '身份证号格式不正确', + showIdNumberHint: true, + canSubmit: false + }); + return; + } + + this.setData({ + isSubmitting: true, + currentStep: 2, + lineProgress1: 100, + lineProgress2: 50 + }); + + // 显示加载动画 + wx.showLoading({ + title: '正在验证...', + mask: true + }); + + try { + // 调用实名认证接口 + const result = await this.callRealNameApi(name, idNumber); + + wx.hideLoading(); + + if (result.success) { + // 处理身份证号脱敏显示 + const maskedId = idNumber.substring(0, 4) + '**********' + idNumber.substring(14); + + // 显示成功弹窗 + this.showSuccessModal(maskedId); + + this.setData({ + isSubmitting: false, + currentStep: 3, + lineProgress2: 100 + }); + } else { + // 接口返回失败 + this.handleApiError(result); + } + + } catch (error) { + wx.hideLoading(); + this.setData({ + isSubmitting: false, + currentStep: 1, + lineProgress2: 0 + }); + + this.showErrorModal('网络错误', '认证请求失败,请检查网络连接后重试'); + console.error('实名认证错误:', error); + } + }, + + // 调用实名认证API + async callRealNameApi(realName, idCard) { + return new Promise((resolve, reject) => { + http.realName({ + data: { + realName: realName, // 姓名字段 + idCard: idCard // 身份证号字段 + }, + success: (res) => { + console.log('API响应:', res); + + // 根据实际API响应结构调整 + if (res.code === 200 || res.code === 0) { + resolve({ + success: true, + data: res.data || {} + }); + } else { + resolve({ + success: false, + code: res.code, + message: res.msg || '认证失败' + }); + } + }, + fail: (err) => { + reject(err); + } + }); + }); + }, + + // 处理API错误 + handleApiError(result) { + console.log('API错误:', result); + + this.setData({ + isSubmitting: false, + currentStep: 1, + lineProgress2: 0 + }); + + // 根据错误码显示不同提示 + let title = '认证失败'; + let message = result.message || '请检查信息后重试'; + + // 根据不同的错误码定制提示信息 + if (result.code === 500) { + message = result.message || '服务器内部错误,请稍后重试'; + } else if (result.code === 400) { + message = result.message || '请求参数错误,请检查填写的信息'; + } else if (result.code === 401) { + message = result.message || '身份验证失败,请重新登录'; + } else if (result.code === 403) { + message = result.message || '认证信息不正确,请核对姓名和身份证号'; + } + + this.showErrorModal(title, message); + }, + + // 显示成功弹窗 + showSuccessModal(maskedId) { + this.setData({ + maskedIdNumber: maskedId, + showSuccessModal: true + }); + }, + + // 关闭成功弹窗 + closeSuccessModal() { + this.setData({ showSuccessModal: false }); + }, + + // 返回 + goToHome() { + this.closeSuccessModal(); + wx.switchTab({ + url: '/pages/personal/personal' + }); + } +}); \ No newline at end of file diff --git a/pagesA/pages/attestation/attestation.json b/pagesA/pages/attestation/attestation.json new file mode 100644 index 0000000..8b3ccf1 --- /dev/null +++ b/pagesA/pages/attestation/attestation.json @@ -0,0 +1,4 @@ +{ + "navigationBarTitleText":"实名认证", + "usingComponents": {} +} \ No newline at end of file diff --git a/pagesA/pages/attestation/attestation.wxml b/pagesA/pages/attestation/attestation.wxml new file mode 100644 index 0000000..a69aba6 --- /dev/null +++ b/pagesA/pages/attestation/attestation.wxml @@ -0,0 +1,285 @@ + + + + + + + + + + + + + 与牧同行 + 专业牧业,贴心同行 + + + + + + 实名认证 + 必填 + + + 为了更好的服务体验,请完成实名认证 + + + + + + + + + 1 + + 填写信息 + + + + + + + + + 2 + + 信息验证 + + + + + + + + + 3 + + 完成认证 + + + + + + + + + + 真实姓名 + * + + + + + + + + + + + + + + + + + + + {{name.length}}/10 + + + + + + + {{nameError || '请输入与身份证一致的姓名(2-10个汉字)'}} + + + + + + + + + 身份证号 + * + + + + + + + + + + + + + + + + + + + {{idNumber.substring(0, 6) || '地区'}} + {{idNumber.substring(6, 14) || '出生'}} + {{idNumber.substring(14, 17) || '顺序'}} + {{idNumber.substring(17) || '校验'}} + + + + + + + {{idNumberError || '请输入有效的18位身份证号码'}} + + + + + + + + + + + + + + + + + + + + {{modalTitle}} + + + + + + {{modalContent}} + + + + + + + + + + + + + + + + + + + + + 认证成功! + + 欢迎加入与牧同行大家庭 + + + + + + + 姓名 + + {{name}} + + + + + + 身份证号 + + {{maskedIdNumber}} + + + + + + + + + + + + + + + {{errorTitle}} + + + + + + {{errorMessage}} + + + + + + + + + \ No newline at end of file diff --git a/pagesA/pages/attestation/attestation.wxss b/pagesA/pages/attestation/attestation.wxss new file mode 100644 index 0000000..ddfcfac --- /dev/null +++ b/pagesA/pages/attestation/attestation.wxss @@ -0,0 +1,1392 @@ +/* 基础样式 */ +page { + background: #f8fafc; + overflow-x: hidden; +} + +.auth-container { + min-height: 100vh; + position: relative; + padding-bottom: 40rpx; +} + +/* 背景装饰 */ +.background-design { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 0; + overflow: hidden; +} + +.bg-circle { + position: absolute; + border-radius: 50%; + background: linear-gradient(135deg, rgba(20, 184, 166, 0.08) 0%, rgba(20, 184, 166, 0.03) 100%); + animation: float 20s infinite ease-in-out; +} + +.circle-1 { + width: 600rpx; + height: 600rpx; + top: -200rpx; + right: -200rpx; + animation-delay: 0s; +} + +.circle-2 { + width: 400rpx; + height: 400rpx; + top: 300rpx; + left: -100rpx; + animation-delay: 5s; +} + +.bg-wave { + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 300rpx; + background: linear-gradient(to top, rgba(20, 184, 166, 0.05) 0%, transparent 100%); + clip-path: polygon(0% 100%, 100% 100%, 100% 30%, 80% 20%, 60% 40%, 40% 20%, 20% 40%, 0% 20%); +} + +@keyframes float { + 0%, 100% { transform: translateY(0) scale(1); } + 50% { transform: translateY(-20rpx) scale(1.05); } +} + +/* 头部区域 */ +.header-section { + position: relative; + z-index: 1; + padding: 60rpx 40rpx 30rpx; + animation: slideInDown 0.6s ease-out; +} + +.brand-header { + display: flex; + align-items: center; + margin-bottom: 40rpx; +} + +.brand-text { + flex: 1; + animation: fadeInRight 0.8s ease-out 0.2s both; +} + +.brand-name { + font-size: 44rpx; + font-weight: 800; + color: #0f766e; + letter-spacing: 2rpx; + margin-bottom: 6rpx; + background: linear-gradient(135deg, #0f766e 0%, #14b8a6 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +.brand-slogan { + font-size: 26rpx; + color: #64748b; +} + +.auth-header { + text-align: center; + margin-bottom: 30rpx; + animation: fadeInUp 0.6s ease-out 0.4s both; +} + +.auth-title { + display: flex; + align-items: center; + justify-content: center; + gap: 20rpx; + margin-bottom: 16rpx; +} + +.title-text { + font-size: 40rpx; + font-weight: 700; + color: #0f172a; +} + +.title-badge { + background: linear-gradient(135deg, #f97316 0%, #ea580c 100%); + color: white; + font-size: 22rpx; + padding: 4rpx 16rpx; + border-radius: 20rpx; + font-weight: 500; + animation: pulse 2s infinite; +} + +@keyframes pulse { + 0%, 100% { transform: scale(1); } + 50% { transform: scale(1.05); } +} + +.auth-description { + font-size: 28rpx; + color: #64748b; + line-height: 1.5; +} + +/* 进度指示器 */ +.progress-indicator { + display: flex; + align-items: center; + justify-content: center; + padding: 0 40rpx 50rpx; + position: relative; + z-index: 1; + animation: fadeInUp 0.6s ease-out 0.6s both; +} + +.progress-step { + display: flex; + flex-direction: column; + align-items: center; + position: relative; + flex: 1; + transition: all 0.3s ease; +} + +.step-bubble { + width: 60rpx; + height: 60rpx; + background: #e2e8f0; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 12rpx; + transition: all 0.3s ease; + position: relative; + overflow: hidden; +} + +.step-bubble::before { + content: ''; + position: absolute; + top: -2rpx; + left: -2rpx; + right: -2rpx; + bottom: -2rpx; + background: linear-gradient(135deg, #0f766e 0%, #14b8a6 100%); + border-radius: 50%; + opacity: 0; + transition: opacity 0.3s ease; +} + +.progress-step.active .step-bubble::before { + opacity: 1; +} + +.step-number { + font-size: 28rpx; + font-weight: 600; + color: #64748b; + position: relative; + z-index: 1; + transition: all 0.3s ease; +} + +.progress-step.active .step-number { + color: white; +} + +.step-label { + font-size: 26rpx; + color: #94a3b8; + font-weight: 500; + transition: all 0.3s ease; +} + +.progress-step.active .step-label { + color: #0f766e; + font-weight: 600; +} + +.progress-line { + flex: 1; + height: 4rpx; + background: #e2e8f0; + border-radius: 2rpx; + position: relative; + margin: 0 20rpx; + overflow: hidden; + transition: all 0.3s ease; +} + +.line-progress { + position: absolute; + top: 0; + left: 0; + height: 100%; + background: linear-gradient(90deg, #0f766e 0%, #14b8a6 100%); + border-radius: 2rpx; + transition: width 0.5s ease; +} + +/* 表单区域 */ +.form-section { + position: relative; + z-index: 1; + padding: 0 40rpx; +} + +.input-card { + background: white; + border-radius: 24rpx; + padding: 32rpx; + margin-bottom: 30rpx; + box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.08); + border: 1rpx solid #f1f5f9; + transition: all 0.3s ease; + overflow: hidden; + animation: fadeInUp 0.6s ease-out; + opacity: 0; + animation-fill-mode: forwards; + position: relative; +} + +.input-card:nth-child(1) { + animation-delay: 0.7s; +} + +.input-card:nth-child(2) { + animation-delay: 0.8s; +} + +.input-card:focus-within::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 3rpx; + background: linear-gradient(90deg, #0f766e 0%, #14b8a6 100%); + animation: underlineProgress 0.3s ease forwards; +} + +@keyframes underlineProgress { + from { transform: translateX(-100%); } + to { transform: translateX(0); } +} + +.input-label { + display: flex; + align-items: center; + margin-bottom: 24rpx; + transition: all 0.3s ease; +} + +.label-icon { + width: 28rpx; + height: 28rpx; + margin-right: 12rpx; + transition: all 0.3s ease; +} + +.input-field:focus + .input-label .label-icon, +.input-card:focus-within .label-icon { + transform: scale(1.1) rotate(5deg); + filter: brightness(1.2); +} + +.label-text { + font-size: 30rpx; + font-weight: 600; + color: #0f172a; + flex: 1; +} + +.required-star { + color: #ef4444; + font-size: 24rpx; + margin-left: 4rpx; +} + +.input-container { + position: relative; + margin-bottom: 8rpx; +} + +/* 输入框样式 */ +.input-field { + height: 88rpx; + font-size: 32rpx; + color: #0f172a; + padding: 0 80rpx 0 24rpx; + background: #f8fafc; + border-radius: 16rpx; + border: 2rpx solid #e2e8f0; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + z-index: 2; + position: relative; + width: 100%; + box-sizing: border-box; +} + +.input-field.error { + border-color: #ef4444; + background: rgba(239, 68, 68, 0.02); + animation: shake 0.5s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; +} + +.input-field.valid { + border-color: #22c55e; + background: rgba(34, 197, 94, 0.02); +} + +.input-field.has-value { + border-color: #94a3b8; +} + +.placeholder { + color: #94a3b8; + font-size: 28rpx; + transition: all 0.3s ease; +} + +/* 清除按钮 */ +.clear-wrapper { + position: absolute; + right: 20rpx; + top: 50%; + transform: translateY(-50%); + z-index: 10; + animation: fadeIn 0.3s ease-out; +} + +.clear-btn { + width: 44rpx; + height: 44rpx; + padding: 0; + margin: 0; + background: transparent; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + transition: all 0.2s ease; + position: relative; + overflow: hidden; + line-height: 1; +} + +.clear-btn::after { + display: none; + border: none; +} + +.clear-btn:active { + background-color: rgba(0, 0, 0, 0.1); + transform: scale(0.95); +} + +.clear-icon { + width: 26rpx; + height: 26rpx; + opacity: 0.6; + filter: brightness(0%); + transition: all 0.2s ease; +} + +.clear-btn:active .clear-icon { + opacity: 1; +} + +/* 字符计数 */ +.char-count { + position: absolute; + right: 80rpx; + top: 50%; + transform: translateY(-50%); + font-size: 24rpx; + color: #94a3b8; + z-index: 1; + transition: all 0.3s ease; + opacity: 0.8; + background: transparent; + pointer-events: none; +} + +.input-field.focused ~ .char-count { + opacity: 1; + transform: translateY(-50%) scale(1.1); +} + +.char-count.warning { + color: #f59e0b; + animation: pulse 1.5s infinite; +} + +/* 输入框下划线 */ +.input-underline { + position: relative; + height: 2rpx; + margin-top: -2rpx; + overflow: hidden; +} + +.underline-bg { + position: absolute; + top: 0; + left: 0; + right: 0; + height: 100%; + background: #e2e8f0; +} + +.underline-progress { + position: absolute; + top: 0; + left: 0; + width: 0; + height: 100%; + background: #14b8a6; + transition: width 0.3s ease; +} + +.underline-progress.active { + width: 100%; + animation: underlineExpand 0.3s ease forwards; +} + +@keyframes underlineExpand { + from { width: 0; } + to { width: 100%; } +} + +/* 身份证分段显示 */ +.id-segments { + position: absolute; + bottom: -40rpx; + left: 0; + right: 0; + display: flex; + justify-content: space-between; + padding: 0 8rpx; + opacity: 0; + transform: translateY(10rpx); + transition: all 0.3s ease; + pointer-events: none; +} + +.id-segments.show { + opacity: 0.7; + transform: translateY(0); +} + +.id-segment { + font-size: 20rpx; + color: #94a3b8; + padding: 4rpx 8rpx; + background: #f1f5f9; + border-radius: 6rpx; + min-width: 60rpx; + text-align: center; + transition: all 0.3s ease; + transform: scale(0.9); +} + +.id-segment.filled { + color: #0f766e; + background: rgba(20, 184, 166, 0.1); + font-weight: 500; + transform: scale(1); + animation: segmentFill 0.3s ease-out; +} + +@keyframes segmentFill { + 0% { + transform: scale(0.9); + opacity: 0.5; + } + 50% { + transform: scale(1.05); + } + 100% { + transform: scale(1); + opacity: 1; + } +} + +.id-segment.last { + min-width: 40rpx; +} + +/* 提示信息*/ +.hint-container { + display: flex; + align-items: center; + min-height: 36rpx; + padding-top: 8rpx; + opacity: 1; + transform: translateY(0); + transition: all 0.3s ease; + pointer-events: none; +} + +.hint-text { + font-size: 24rpx; + line-height: 1.4; + flex: 1; + transition: all 0.3s ease; +} + +.hint-text.normal { + color: #64748b; +} + +.hint-text.error { + color: #ef4444; + animation: fadeInUp 0.3s ease-out; +} + +/* 协议卡片 */ +.agreement-card { + background: white; + border-radius: 24rpx; + padding: 32rpx; + margin-top: 40rpx; + box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.08); + transition: all 0.3s ease; + animation: fadeInUp 0.6s ease-out 0.9s both; +} + +.agreement-item { + display: flex; + align-items: center; + cursor: pointer; +} + +.agreement-checkbox { + width: 40rpx; + height: 40rpx; + border: 2rpx solid #cbd5e1; + border-radius: 10rpx; + margin-right: 20rpx; + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; + overflow: hidden; +} + +.agreement-checkbox::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(135deg, #0f766e 0%, #14b8a6 100%); + opacity: 0; + transition: opacity 0.3s ease; +} + +.agreement-checkbox.checked { + border-color: #14b8a6; + animation: checkboxCheck 0.4s ease-out; +} + +.agreement-checkbox.checked::before { + opacity: 1; +} + +@keyframes checkboxCheck { + 0% { + transform: scale(0.8); + opacity: 0.5; + } + 50% { + transform: scale(1.1); + } + 100% { + transform: scale(1); + opacity: 1; + } +} + +.checkmark { + width: 26rpx; + height: 26rpx; + position: relative; + z-index: 1; + animation: checkmarkAppear 0.3s ease-out 0.1s both; +} + +@keyframes checkmarkAppear { + 0% { + transform: scale(0); + opacity: 0; + } + 100% { + transform: scale(1); + opacity: 1; + } +} + +.agreement-content { + font-size: 28rpx; + color: #475569; + line-height: 1.5; + flex: 1; + transition: color 0.3s ease; +} + +.link-text { + color: #0f766e; + font-weight: 600; + margin: 0 4rpx; + position: relative; + display: inline-block; + transition: all 0.3s ease; +} + +.link-text::after { + content: ''; + position: absolute; + bottom: -2rpx; + left: 0; + right: 0; + height: 2rpx; + background: #0f766e; + transform: scaleX(0); + transform-origin: right; + transition: transform 0.3s ease; +} + +.link-text:active::after { + transform: scaleX(1); + transform-origin: left; +} + +/* 提交区域*/ +.submit-section { + position: relative; + z-index: 1; + padding: 40rpx 40rpx 30rpx; + animation: fadeInUp 0.6s ease-out 1s both; +} + +.submit-button { + width: 100%; + padding: 10rpx 0; + border-radius: 50rpx; + font-size: 32rpx; + font-weight: 600; + margin: 0; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; + overflow: hidden; + border: none; + outline: none; + display: block; +} + +.submit-button::after { + border: none; +} + +.submit-button.disabled { + background: #cbd5e1 !important; + color: #94a3b8 !important; + box-shadow: none !important; + transform: none !important; + cursor: not-allowed; +} + +.submit-button.active { + background: linear-gradient(135deg, #0f766e 0%, #14b8a6 100%); + color: white; + box-shadow: 0 12rpx 40rpx rgba(20, 184, 166, 0.4); +} + +.submit-button.active::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient( + 90deg, + transparent 0%, + rgba(255, 255, 255, 0.2) 50%, + transparent 100% + ); + transform: translateX(-100%); + animation: shimmer 2s infinite; +} + +.button-hover { + opacity: 0.95; + transform: translateY(-2rpx) scale(1.01) !important; +} + + + +/* 协议弹窗 */ +.modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(15, 23, 42, 0.5); + backdrop-filter: blur(10rpx); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + opacity: 0; + visibility: hidden; + transition: all 0.3s ease; +} + +.modal-overlay.show { + opacity: 1; + visibility: visible; +} + +.modal-overlay.show .modal-container { + animation: modalSlideUp 0.4s cubic-bezier(0.4, 0, 0.2, 1); +} + +@keyframes modalSlideUp { + 0% { + transform: translateY(50rpx); + opacity: 0; + } + 100% { + transform: translateY(0); + opacity: 1; + } +} + +.modal-container { + width: 680rpx; + background: white; + border-radius: 32rpx; + overflow: hidden; + box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.3); + max-height: 80vh; + display: flex; + flex-direction: column; +} + +.modal-header { + padding: 40rpx 48rpx 24rpx; + display: flex; + align-items: center; + justify-content: space-between; + border-bottom: 1rpx solid #f1f5f9; +} + +.modal-title { + font-size: 36rpx; + font-weight: 700; + color: #0f172a; +} + +.modal-close { + width: 44rpx; + height: 44rpx; + padding: 0; + margin: 0; + background: #f1f5f9; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; + border: none; + outline: none; +} + +.modal-close::after { + border: none; +} + +.modal-close:active { + background: #e2e8f0; + transform: scale(0.95); +} + +.close-icon { + width: 26rpx; + height: 26rpx; + filter: brightness(0); +} + +.modal-content { + flex: 1; + padding: 32rpx 48rpx; + max-height: 60vh; + box-sizing: border-box; +} + +.modal-text { + font-size: 28rpx; + color: #475569; + line-height: 1.6; + white-space: pre-line; + animation: fadeIn 0.5s ease-out 0.2s both; +} + +.modal-footer { + padding: 32rpx 48rpx 30rpx; + margin-top: 20rpx; +} + +.modal-confirm { + width: 100%; + background: linear-gradient(135deg, #0f766e 0%, #14b8a6 100%); + border-radius: 24rpx; + font-size: 30rpx; + font-weight: 600; + color: white; + padding: 0; + margin: 0; + transition: all 0.2s ease; + border: none; + outline: none; + height: 88rpx; + display: flex; + align-items: center; + justify-content: center; +} + +.modal-confirm::after { + border: none; +} + +.modal-confirm:active { + opacity: 0.9; + transform: scale(0.98); +} + +/* 成功弹窗 */ +.success-modal { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 1000; + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + visibility: hidden; + transition: all 0.3s ease; +} + +.success-modal.show { + opacity: 1; + visibility: visible; +} + +.success-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(15, 23, 42, 0.5); + backdrop-filter: blur(10rpx); +} + +.success-modal.show .success-container { + animation: successZoomIn 0.6s cubic-bezier(0.4, 0, 0.2, 1); +} + +@keyframes successZoomIn { + 0% { + transform: scale(0.9); + opacity: 0; + } + 50% { + transform: scale(1.05); + } + 100% { + transform: scale(1); + opacity: 1; + } +} + +.success-container { + position: relative; + width: 680rpx; + background: white; + border-radius: 32rpx; + overflow: hidden; + box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.3); +} + +.success-icon { + padding: 60rpx 0 40rpx; + text-align: center; + position: relative; +} + +.success-badge { + width: 120rpx; + height: 120rpx; + margin: 0 auto; + position: relative; + z-index: 1; + filter: brightness(0); + animation: successBadge 0.8s ease-out; +} + +@keyframes successBadge { + 0% { + transform: scale(0); + opacity: 0; + } + 50% { + transform: scale(1.2); + } + 100% { + transform: scale(1); + opacity: 1; + } +} + +.success-ring { + position: absolute; + top: 50%; + left: 50%; + border: 2rpx solid rgba(20, 184, 166, 0.3); + border-radius: 50%; +} + +.ring-1 { + width: 160rpx; + height: 160rpx; + animation: ringPulse 2s ease-out infinite; +} + +.ring-2 { + width: 200rpx; + height: 200rpx; + animation: ringPulse 2s ease-out 0.5s infinite; +} + +@keyframes ringPulse { + 0% { + transform: translate(-50%, -50%) scale(0.8); + opacity: 0; + } + 50% { + opacity: 1; + } + 100% { + transform: translate(-50%, -50%) scale(1.2); + opacity: 0; + } +} + +.success-body { + padding: 0 48rpx 40rpx; + animation: fadeInUp 0.6s ease-out 0.3s both; +} + +.success-title { + font-size: 44rpx; + font-weight: 700; + color: #0f172a; + text-align: center; + margin-bottom: 16rpx; +} + +.success-message { + font-size: 32rpx; + color: #475569; + text-align: center; + margin-bottom: 40rpx; +} + +.brand { + color: #0f766e; + font-weight: 700; + margin: 0 4rpx; +} + +.success-details { + background: #f8fafc; + border-radius: 20rpx; + padding: 32rpx; + animation: fadeInUp 0.6s ease-out 0.5s both; +} + +.detail-item { + display: flex; + flex-direction: column; + gap: 12rpx; +} + +.detail-item:not(:last-child) { + margin-bottom: 24rpx; +} + +.detail-label { + display: flex; + align-items: center; + gap: 12rpx; +} + +.detail-icon { + width: 24rpx; + height: 24rpx; + animation: iconBounce 0.6s ease-out; +} + +@keyframes iconBounce { + 0%, 100% { + transform: translateY(0); + } + 50% { + transform: translateY(-4rpx); + } +} + +.detail-label text { + font-size: 26rpx; + color: #64748b; +} + +.detail-value { + font-size: 30rpx; + font-weight: 600; + color: #0f172a; + padding-left: 36rpx; +} + +.success-footer { + padding: 0 48rpx 40rpx; + animation: fadeInUp 0.6s ease-out 0.7s both; +} + +.success-button { + width: 100%; + height: 88rpx; + background: linear-gradient(135deg, #0f766e 0%, #14b8a6 100%); + border-radius: 24rpx; + font-size: 30rpx; + font-weight: 600; + color: white; + padding: 0; + margin: 0; + display: flex; + align-items: center; + justify-content: center; + gap: 12rpx; + transition: all 0.2s ease; + border: none; + outline: none; +} + +.success-button::after { + border: none; +} + +.success-button:active { + opacity: 0.9; + transform: scale(0.98); +} + + +@keyframes homeFloat { + 0%, 100% { + transform: translateY(0); + } + 50% { + transform: translateY(-4rpx); + } +} + +/* 通用动画 */ +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(20rpx); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes fadeInRight { + from { + opacity: 0; + transform: translateX(-20rpx); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +@keyframes fadeInDown { + from { + opacity: 0; + transform: translateY(-20rpx); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideInDown { + from { + transform: translateY(-50rpx); + opacity: 0; + } + to { + transform: translateY(0); + opacity: 1; + } +} + +@keyframes bounceIn { + 0%, 20%, 40%, 60%, 80%, 100% { + animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); + } + 0% { + opacity: 0; + transform: scale3d(0.3, 0.3, 0.3); + } + 20% { + transform: scale3d(1.1, 1.1, 1.1); + } + 40% { + transform: scale3d(0.9, 0.9, 0.9); + } + 60% { + opacity: 1; + transform: scale3d(1.03, 1.03, 1.03); + } + 80% { + transform: scale3d(0.97, 0.97, 0.97); + } + 100% { + opacity: 1; + transform: scale3d(1, 1, 1); + } +} + +@keyframes shake { + 10%, 90% { + transform: translateX(-1rpx); + } + 20%, 80% { + transform: translateX(2rpx); + } + 30%, 50%, 70% { + transform: translateX(-4rpx); + } + 40%, 60% { + transform: translateX(4rpx); + } +} + +/* 响应式适配 */ +@media (max-width: 480px) { + .header-section, + .form-section, + .submit-section, + .progress-indicator { + padding-left: 30rpx; + padding-right: 30rpx; + } + + .input-card, + .agreement-card { + padding: 24rpx; + } + + .modal-container, + .success-container { + width: 90%; + margin: 0 5%; + } + + .modal-header, + .modal-content, + .modal-footer, + .success-body, + .success-footer { + padding-left: 32rpx; + padding-right: 32rpx; + } + + .id-segments { + display: none; + } +} + +/* 加载状态 */ +.loading-indicator { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(255, 255, 255, 0.9); + display: flex; + align-items: center; + justify-content: center; + z-index: 9999; + opacity: 0; + visibility: hidden; + transition: all 0.3s ease; +} + +.loading-indicator.show { + opacity: 1; + visibility: visible; +} + +.loading-spinner { + width: 60rpx; + height: 60rpx; + border: 4rpx solid #f3f3f3; + border-top: 4rpx solid #14b8a6; + border-radius: 50%; + animation: spin 1s linear infinite; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + + +/* 错误弹窗样式 */ +.error-modal .modal-container { + background: #fff; + border-radius: 20rpx; + overflow: hidden; + animation: modalSlideUp 0.3s ease; +} + +.error-modal .modal-header { + padding: 40rpx 40rpx 20rpx; + text-align: center; + border-bottom: 2rpx solid #f0f0f0; +} + +.error-modal .error-title { + color: #ff4444; + font-size: 36rpx; + font-weight: 600; + text-align: center; + width: 100%; +} + +.error-modal .modal-content { + padding: 40rpx; + text-align: center; +} + + + +.error-modal .error-message { + color: #666; + font-size: 28rpx; + line-height: 1.6; + text-align: center; + padding: 0 20rpx; +} + +.error-modal .modal-footer { + padding: 30rpx 40rpx 40rpx; +} + +.error-modal .error-confirm { + background: linear-gradient(135deg, #ff4444, #ff6666); + color: white; + border: none; + border-radius: 50rpx; + height: 80rpx; + line-height: 80rpx; + font-size: 30rpx; + font-weight: 500; + width: 100%; + transition: all 0.3s ease; +} + +.error-modal .error-confirm:active { + opacity: 0.9; + transform: scale(0.98); +} + +/* 弹窗动画 */ +@keyframes modalSlideUp { + from { + opacity: 0; + transform: translateY(100rpx); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* 修复原有的模态框样式 */ +.modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + visibility: hidden; + transition: all 0.3s ease; + z-index: 9999; +} + +.modal-overlay.show { + opacity: 1; + visibility: visible; +} + +.modal-container { + max-width: 90vw; + background: #fff; + border-radius: 20rpx; + overflow: hidden; + transform: translateY(20rpx); + transition: transform 0.3s ease; +} + +.modal-overlay.show .modal-container { + transform: translateY(0); +} \ No newline at end of file diff --git a/pagesA/pages/precept/precept.js b/pagesA/pages/precept/precept.js index 025df01..4bd1fd2 100644 --- a/pagesA/pages/precept/precept.js +++ b/pagesA/pages/precept/precept.js @@ -1,66 +1,218 @@ import http from '../../../utils/api' +const baseUrl = require('../../../utils/baseUrl') Page({ data: { - diagnosisList: [] + diagnosisList: [], + // 弹窗相关 + showPlanPopup: false, + consultationId: null, + baseUrl:baseUrl, + planForm: { + title: '', // 新增方案标题 + diagnosis: '', + treatmentMethod: '', + treatmentDesc: '', + precautions: '' + } }, - onLoad: function () { - + onLoad: function() { + // 页面加载时可做一些初始化 }, - onShow:function(){ + onShow: function() { this.getwzd() }, - - // 问诊单 + // 获取问诊列表 getwzd() { http.wzd({ data: {}, success: res => { - console.log(1111, res); + console.log('问诊列表:', res); this.setData({ - diagnosisList: res.rows + diagnosisList: res.rows || [] }) + }, + fail: err => { + console.error('获取问诊列表失败', err); + wx.showToast({ + title: '加载失败', + icon: 'none' + }); } }) }, + // 制定方案(打开弹窗) + bindPlan(e) { + const consultationId = e.currentTarget.dataset.id; + console.log('当前咨询ID:', consultationId); + + // 重置表单(包含title字段) + this.setData({ + consultationId: consultationId, + planForm: { + title: '', + diagnosis: '', + treatmentMethod: '', + treatmentDesc: '', + precautions: '' + }, + showPlanPopup: true + }); + }, + // 关闭弹窗 + closePlanPopup() { + this.setData({ + showPlanPopup: false, + consultationId: null + }); + }, - // 格式化日期显示 - formatDate: function (dateString) { - const date = new Date(dateString); - const now = new Date(); - const diff = now - date; - const diffDays = Math.floor(diff / (1000 * 60 * 60 * 24)); - const diffHours = Math.floor(diff / (1000 * 60 * 60)); - const diffMinutes = Math.floor(diff / (1000 * 60)); - - if (diffMinutes < 60) { - return `${diffMinutes}分钟前`; - } else if (diffHours < 24) { - return `${diffHours}小时前`; - } else if (diffDays === 1) { - return '昨天'; - } else if (diffDays === 2) { - return '前天'; - } else if (diffDays < 7) { - return `${diffDays}天前`; - } else { - const month = date.getMonth() + 1; - const day = date.getDate(); - return `${month}月${day}日`; - } + // 表单输入处理函数 + onTitleInput(e) { + this.setData({ + 'planForm.title': e.detail.value + }); }, + onDiagnosisInput(e) { + this.setData({ + 'planForm.diagnosis': e.detail.value + }); + }, - // 查看详情 - viewDetail: function (e) { - const data = e.currentTarget.dataset.value - wx.navigateTo({ - url: `/pagesA/pages/askingSyDetails/askingSyDetails?data=${encodeURIComponent(JSON.stringify(data))}`, + onTreatmentMethodInput(e) { + this.setData({ + 'planForm.treatmentMethod': e.detail.value + }); + }, + + onTreatmentDescInput(e) { + this.setData({ + 'planForm.treatmentDesc': e.detail.value + }); + }, + + onPrecautionsInput(e) { + this.setData({ + 'planForm.precautions': e.detail.value + }); + }, + + // 提交方案 + submitPlan() { + const { title, diagnosis, treatmentMethod, treatmentDesc } = this.data.planForm; + const consultationId = this.data.consultationId; + + // 必填校验(包含标题) + if (!title || !title.trim()) { + wx.showToast({ + title: '请填写方案标题', + icon: 'none', + duration: 2000 + }); + return; + } + + if (!diagnosis || !diagnosis.trim()) { + wx.showToast({ + title: '请填写诊断结果', + icon: 'none', + duration: 2000 + }); + return; + } + + if (!treatmentMethod || !treatmentMethod.trim()) { + wx.showToast({ + title: '请填写治疗方式', + icon: 'none', + duration: 2000 + }); + return; + } + + if (!treatmentDesc || !treatmentDesc.trim()) { + wx.showToast({ + title: '请填写治疗方案描述', + icon: 'none', + duration: 2000 + }); + return; + } + + if (!consultationId) { + wx.showToast({ + title: '咨询ID缺失,请重试', + icon: 'none' + }); + return; + } + + // 显示加载 + wx.showLoading({ + title: '提交中...', + mask: true + }); + + // 构建提交数据(包含title) + const submitData = { + consultationId: consultationId, + title: title.trim(), // 新增标题字段 + diagnosis: diagnosis.trim(), + treatmentMethod: treatmentMethod.trim(), + treatmentDesc: treatmentDesc.trim(), + precautions: this.data.planForm.precautions?.trim() || '' + }; + + console.log('提交数据:', submitData); + + // 调用API + http.fazdAdd({ + data: submitData, + success: (res) => { + wx.hideLoading(); + // 根据实际接口返回结构调整判断条件 + if (res.code === 200 || res.code === 0 || res.success) { + wx.showToast({ + title: '方案提交成功', + icon: 'success', + duration: 2000 + }); + + // 关闭弹窗 + this.closePlanPopup(); + + // 刷新列表(可选) + setTimeout(() => { + this.getwzd(); + }, 500); + } else { + wx.showToast({ + title: res.msg || '提交失败', + icon: 'none' + }); + } + }, + fail: (err) => { + wx.hideLoading(); + console.error('提交失败', err); + wx.showToast({ + title: '网络错误,请重试', + icon: 'none' + }); + } }); }, + // 查看详情 + viewDetail: function(e) { + const data = e.currentTarget.dataset.value; + wx.navigateTo({ + url: `/pagesA/pages/askingSyDetails/askingSyDetails?data=${encodeURIComponent(JSON.stringify(data))}`, + }); + } }); \ No newline at end of file diff --git a/pagesA/pages/precept/precept.json b/pagesA/pages/precept/precept.json index 8835af0..c847926 100644 --- a/pagesA/pages/precept/precept.json +++ b/pagesA/pages/precept/precept.json @@ -1,3 +1,4 @@ { + "navigationBarTitleText":"制定方案", "usingComponents": {} } \ No newline at end of file diff --git a/pagesA/pages/precept/precept.wxml b/pagesA/pages/precept/precept.wxml index 4ec1cae..1005a4c 100644 --- a/pagesA/pages/precept/precept.wxml +++ b/pagesA/pages/precept/precept.wxml @@ -24,47 +24,47 @@ - - - - - - - - {{item.farmerName || '用户'}} - - - {{item.status}} - - - - - - - - - 牲畜信息 + + + + + + + {{item.farmerName || '用户'}} + + + {{item.status}} - - - - {{item.animalType}} + + + + + + 牲畜信息 + + - - {{item.animalAge}} - - - {{item.animalGender}} + + + + {{item.animalType}} + + + {{item.animalAge}} + + + {{item.animalGender}} + - - - - - {{item.description}} + + + + {{item.description}} + @@ -78,7 +78,7 @@ - 制定方案 + 制定方案 @@ -91,5 +91,112 @@ + + + + + + + + 制定诊疗方案 + + + + + + + + 方案标题 + * + + + + + + + + 诊断结果 + * + + + + + + + + 治疗方式 + * + + + + + + + + 治疗方案描述 + * + +