Browse Source

远程诊疗,提交方案功能

master
ZhaoYang 1 month ago
parent
commit
814b57ddde
  1. 3
      app.json
  2. 4
      pagesA/pages/askingSy/askingSy.js
  3. 2
      pagesA/pages/askingSy/askingSy.wxml
  4. 472
      pagesA/pages/attestation/attestation.js
  5. 4
      pagesA/pages/attestation/attestation.json
  6. 285
      pagesA/pages/attestation/attestation.wxml
  7. 1392
      pagesA/pages/attestation/attestation.wxss
  8. 216
      pagesA/pages/precept/precept.js
  9. 1
      pagesA/pages/precept/precept.json
  10. 117
      pagesA/pages/precept/precept.wxml
  11. 274
      pagesA/pages/precept/precept.wxss
  12. 8
      utils/api.js

3
app.json

@ -14,7 +14,8 @@
"pages/askingSyDetails/askingSyDetails", "pages/askingSyDetails/askingSyDetails",
"pages/advisory/advisory", "pages/advisory/advisory",
"pages/releaseSuffer/releaseSuffer", "pages/releaseSuffer/releaseSuffer",
"pages/precept/precept"
"pages/precept/precept",
"pages/attestation/attestation"
] ]
}, },
{ {

4
pagesA/pages/askingSy/askingSy.js

@ -1,7 +1,9 @@
import http from '../../../utils/api' import http from '../../../utils/api'
const baseUrl = require('../../../utils/baseUrl')
Page({ Page({
data: { data: {
diagnosisList: []
diagnosisList: [],
baseUrl:baseUrl
}, },
onLoad: function () { onLoad: function () {

2
pagesA/pages/askingSy/askingSy.wxml

@ -33,7 +33,7 @@
<!-- 卡片头部:用户信息 + 状态 --> <!-- 卡片头部:用户信息 + 状态 -->
<view class="card-header"> <view class="card-header">
<view class="user-section"> <view class="user-section">
<image class="user-avatar" src="{{item.userInfo.avatar || '/pages/images/tx.png'}}"></image>
<image class="user-avatar" src="{{baseUrl+item.avatar || '/pages/images/tx.png'}}"></image>
<text class="user-name">{{item.farmerName || '用户'}}</text> <text class="user-name">{{item.farmerName || '用户'}}</text>
</view> </view>
<view class="status-tag {{item.status === '已回复' ? 'status-replied' : 'status-pending'}}"> <view class="status-tag {{item.status === '已回复' ? 'status-replied' : 'status-pending'}}">

472
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'
});
}
});

4
pagesA/pages/attestation/attestation.json

@ -0,0 +1,4 @@
{
"navigationBarTitleText":"实名认证",
"usingComponents": {}
}

285
pagesA/pages/attestation/attestation.wxml

@ -0,0 +1,285 @@
<view class="auth-container">
<!-- 背景装饰 -->
<view class="background-design">
<view class="bg-circle circle-1"></view>
<view class="bg-circle circle-2"></view>
<view class="bg-wave"></view>
</view>
<!-- 头部区域 -->
<view class="header-section">
<view class="brand-header">
<view class="brand-text">
<view class="brand-name">与牧同行</view>
<view class="brand-slogan">专业牧业,贴心同行</view>
</view>
</view>
<view class="auth-header">
<view class="auth-title">
<text class="title-text">实名认证</text>
<view class="title-badge">必填</view>
</view>
<view class="auth-description">
为了更好的服务体验,请完成实名认证
</view>
</view>
</view>
<!-- 进度指示 -->
<view class="progress-indicator">
<view class="progress-step active">
<view class="step-bubble">
<view class="step-number">1</view>
</view>
<view class="step-label">填写信息</view>
</view>
<view class="progress-line">
<view class="line-progress" style="width: {{lineProgress1}}%;"></view>
</view>
<view class="progress-step {{currentStep >= 2 ? 'active' : ''}}">
<view class="step-bubble">
<view class="step-number">2</view>
</view>
<view class="step-label">信息验证</view>
</view>
<view class="progress-line">
<view class="line-progress" style="width: {{lineProgress2}}%;"></view>
</view>
<view class="progress-step {{currentStep >= 3 ? 'active' : ''}}">
<view class="step-bubble">
<view class="step-number">3</view>
</view>
<view class="step-label">完成认证</view>
</view>
</view>
<!-- 表单区域 -->
<view class="form-section">
<!-- 姓名输入 -->
<view class="input-card">
<view class="input-label">
<image class="label-icon" src="/pagesA/images/name.png" mode="aspectFit"></image>
<text class="label-text">真实姓名</text>
<text class="required-star">*</text>
</view>
<view class="input-container">
<input
class="input-field {{nameFocus ? 'focused' : ''}} {{nameError ? 'error' : ''}} {{name ? 'has-value' : ''}} {{isNameValid ? 'valid' : ''}}"
placeholder="请输入您的真实姓名"
placeholder-class="placeholder"
value="{{name}}"
bindinput="onNameInput"
bindfocus="onNameFocus"
bindblur="onNameBlur"
maxlength="10"
/>
<!-- 删除按钮 -->
<view class="clear-wrapper" wx:if="{{name}}">
<button class="clear-btn" bindtap="clearName" hover-class="btn-hover">
<image class="clear-icon" src="/pagesA/images/ch.png" mode="aspectFit"></image>
</button>
</view>
<!-- 输入框下划线 -->
<view class="input-underline">
<view class="underline-bg"></view>
<view class="underline-progress {{nameFocus ? 'active' : ''}}"></view>
</view>
<!-- 字符计数 -->
<view class="char-count {{name.length > 8 ? 'warning' : ''}}">
{{name.length}}/10
</view>
</view>
<!-- 提示信息 -->
<view class="hint-container" wx:if="{{showNameHint || nameError}}">
<text class="hint-text {{nameError ? 'error' : 'normal'}}">
{{nameError || '请输入与身份证一致的姓名(2-10个汉字)'}}
</text>
</view>
</view>
<!-- 身份证号输入 -->
<view class="input-card">
<view class="input-label">
<image class="label-icon" src="/pagesA/images/sfz.png" mode="aspectFit"></image>
<text class="label-text">身份证号</text>
<text class="required-star">*</text>
</view>
<view class="input-container">
<input
class="input-field {{idNumberError ? 'error' : ''}} {{isIdNumberValid ? 'valid' : ''}} {{idNumber ? 'has-value' : ''}}"
placeholder="请输入18位身份证号码"
placeholder-class="placeholder"
value="{{idNumber}}"
bindinput="onIdNumberInput"
bindfocus="onIdNumberFocus"
bindblur="onIdNumberBlur"
maxlength="18"
type="idcard"
/>
<!-- 删除按钮 -->
<view class="clear-wrapper" wx:if="{{idNumber}}">
<button class="clear-btn" bindtap="clearIdNumber" hover-class="btn-hover">
<image class="clear-icon" src="/pagesA/images/ch.png" mode="aspectFit"></image>
</button>
</view>
<!-- 输入框下划线 -->
<view class="input-underline">
<view class="underline-bg"></view>
<view class="underline-progress {{idNumberFocus ? 'active' : ''}}"></view>
</view>
<!-- 分段显示 -->
<view class="id-segments {{idNumberFocus || idNumber ? 'show' : ''}}">
<view class="id-segment {{idNumber.length >= 6 ? 'filled' : ''}}">{{idNumber.substring(0, 6) || '地区'}}</view>
<view class="id-segment {{idNumber.length >= 14 ? 'filled' : ''}}">{{idNumber.substring(6, 14) || '出生'}}</view>
<view class="id-segment {{idNumber.length >= 17 ? 'filled' : ''}}">{{idNumber.substring(14, 17) || '顺序'}}</view>
<view class="id-segment last {{idNumber.length === 18 ? 'filled' : ''}}">{{idNumber.substring(17) || '校验'}}</view>
</view>
</view>
<!-- 提示信息 -->
<view class="hint-container" wx:if="{{showIdNumberHint || idNumberError}}">
<text class="hint-text {{idNumberError ? 'error' : 'normal'}}">
{{idNumberError || '请输入有效的18位身份证号码'}}
</text>
</view>
</view>
<!-- 协议条款 -->
<view class="agreement-card">
<label class="agreement-item" bindtap="toggleAgreement">
<view class="agreement-checkbox {{agreed ? 'checked' : ''}}">
<image
wx:if="{{agreed}}"
class="checkmark"
src="/pagesA/images/duig.png"
mode="aspectFit"
></image>
</view>
<view class="agreement-content">
<text>我已阅读并同意</text>
<text class="link-text" bindtap="showAgreementModal">《用户服务协议》</text>
<text>和</text>
<text class="link-text" bindtap="showPrivacyModal">《隐私保护协议》</text>
</view>
</label>
</view>
</view>
<!-- 提交区域 -->
<view class="submit-section">
<button
class="submit-button {{canSubmit ? 'active' : 'disabled'}}"
bindtap="submitAuth"
disabled="{{!canSubmit}}"
hover-class="button-hover"
loading="{{isSubmitting}}"
>
验证
</button>
</view>
<!-- 协议弹窗 -->
<view class="modal-overlay {{showModal ? 'show' : ''}}" bindtap="closeModal">
<view class="modal-container" catchtap="stopPropagation">
<view class="modal-header">
<view class="modal-title">{{modalTitle}}</view>
<button class="modal-close" bindtap="closeModal">
<image class="close-icon" src="/pagesA/images/ch.png" mode="aspectFit"></image>
</button>
</view>
<scroll-view class="modal-content" scroll-y>
<view class="modal-text">
{{modalContent}}
</view>
</scroll-view>
<view class="modal-footer">
<button class="modal-confirm" bindtap="closeModal">
我已阅读并理解
</button>
</view>
</view>
</view>
<!-- 成功弹窗 -->
<view class="success-modal {{showSuccessModal ? 'show' : ''}}">
<view class="success-overlay" bindtap="closeSuccessModal"></view>
<view class="success-container">
<view class="success-icon">
<image class="success-badge" src="/pagesA/images/duig.png" mode="aspectFit"></image>
<view class="success-ring ring-1"></view>
<view class="success-ring ring-2"></view>
</view>
<view class="success-body">
<view class="success-title">认证成功!</view>
<view class="success-message">
欢迎加入<text class="brand">与牧同行</text>大家庭
</view>
<view class="success-details">
<view class="detail-item">
<view class="detail-label">
<image class="detail-icon" src="/pagesA/images/name.png" mode="aspectFit"></image>
<text>姓名</text>
</view>
<view class="detail-value">{{name}}</view>
</view>
<view class="detail-item">
<view class="detail-label">
<image class="detail-icon" src="/pagesA/images/sfz.png" mode="aspectFit"></image>
<text>身份证号</text>
</view>
<view class="detail-value">{{maskedIdNumber}}</view>
</view>
</view>
</view>
<view class="success-footer">
<button class="success-button" bindtap="goToHome">
<text>开始使用</text>
</button>
</view>
</view>
</view>
<!-- 错误弹窗(新增) -->
<view class="modal-overlay {{showErrorModal ? 'show' : ''}}" bindtap="closeErrorModal">
<view class="modal-container error-modal" catchtap="stopPropagation">
<view class="modal-header">
<view class="modal-title error-title">{{errorTitle}}</view>
<button class="modal-close" bindtap="closeErrorModal">
<image class="close-icon" src="/pagesA/images/ch.png" mode="aspectFit"></image>
</button>
</view>
<view class="modal-content error-content">
<view class="error-message">
{{errorMessage}}
</view>
</view>
<view class="modal-footer">
<button class="modal-confirm error-confirm" bindtap="closeErrorModal">
确定
</button>
</view>
</view>
</view>
</view>

1392
pagesA/pages/attestation/attestation.wxss
File diff suppressed because it is too large
View File

216
pagesA/pages/precept/precept.js

@ -1,66 +1,218 @@
import http from '../../../utils/api' import http from '../../../utils/api'
const baseUrl = require('../../../utils/baseUrl')
Page({ Page({
data: { 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() this.getwzd()
}, },
// 问诊单
// 获取问诊列表
getwzd() { getwzd() {
http.wzd({ http.wzd({
data: {}, data: {},
success: res => { success: res => {
console.log(1111, res);
console.log('问诊列表:', res);
this.setData({ 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
});
},
// 表单输入处理函数
onTitleInput(e) {
this.setData({
'planForm.title': e.detail.value
});
},
onDiagnosisInput(e) {
this.setData({
'planForm.diagnosis': e.detail.value
});
},
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
});
},
// 格式化日期显示
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}天前`;
// 提交方案
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 { } else {
const month = date.getMonth() + 1;
const day = date.getDate();
return `${month}${day}`;
wx.showToast({
title: res.msg || '提交失败',
icon: 'none'
});
} }
}, },
fail: (err) => {
wx.hideLoading();
console.error('提交失败', err);
wx.showToast({
title: '网络错误,请重试',
icon: 'none'
});
}
});
},
// 查看详情 // 查看详情
viewDetail: function(e) { viewDetail: function(e) {
const data = e.currentTarget.dataset.value
const data = e.currentTarget.dataset.value;
wx.navigateTo({ wx.navigateTo({
url: `/pagesA/pages/askingSyDetails/askingSyDetails?data=${encodeURIComponent(JSON.stringify(data))}`, url: `/pagesA/pages/askingSyDetails/askingSyDetails?data=${encodeURIComponent(JSON.stringify(data))}`,
}); });
},
}
}); });

1
pagesA/pages/precept/precept.json

@ -1,3 +1,4 @@
{ {
"navigationBarTitleText":"制定方案",
"usingComponents": {} "usingComponents": {}
} }

117
pagesA/pages/precept/precept.wxml

@ -24,13 +24,12 @@
<!-- 问诊记录卡片 --> <!-- 问诊记录卡片 -->
<view wx:else class="records-container"> <view wx:else class="records-container">
<view wx:for="{{diagnosisList}}" wx:key="id" class="record-card" bindtap="viewDetail" data-value="{{item}}">
<view wx:for="{{diagnosisList}}" wx:key="id" class="record-card">
<view bindtap="viewDetail" data-value="{{item}}">
<!-- 卡片头部:用户信息 + 状态 --> <!-- 卡片头部:用户信息 + 状态 -->
<view class="card-header"> <view class="card-header">
<view class="user-section"> <view class="user-section">
<image class="user-avatar" src="{{item.userInfo.avatar || '/pages/images/tx.png'}}"></image>
<image class="user-avatar" src="{{baseUrl+item.avatar || '/pages/images/tx.png'}}"></image>
<text class="user-name">{{item.farmerName || '用户'}}</text> <text class="user-name">{{item.farmerName || '用户'}}</text>
</view> </view>
<view class="status-tag {{item.status === '已回复' ? 'status-replied' : 'status-pending'}}"> <view class="status-tag {{item.status === '已回复' ? 'status-replied' : 'status-pending'}}">
@ -67,6 +66,7 @@
<text class="symptom-text">{{item.description}}</text> <text class="symptom-text">{{item.description}}</text>
</view> </view>
</view> </view>
</view>
<!-- 卡片底部 --> <!-- 卡片底部 -->
<view class="card-footer"> <view class="card-footer">
@ -78,7 +78,7 @@
<view class="footer-right"> <view class="footer-right">
<view class="reply-info"> <view class="reply-info">
<text class="reply-count">制定方案</text>
<text class="reply-count" bindtap="bindPlan" data-id="{{item.formId}}">制定方案</text>
</view> </view>
</view> </view>
</view> </view>
@ -91,5 +91,112 @@
</view> </view>
</scroll-view> </scroll-view>
<!-- 制定方案弹窗 -->
<view class="plan-popup" wx:if="{{showPlanPopup}}">
<!-- 遮罩层 -->
<view class="popup-mask" bindtap="closePlanPopup"></view>
<!-- 弹窗主体(从底部滑入) -->
<view class="popup-content">
<view class="popup-header">
<text class="popup-title">制定诊疗方案</text>
<text class="popup-close" bindtap="closePlanPopup">✕</text>
</view>
<scroll-view scroll-y class="popup-form" enhanced show-scrollbar="{{false}}">
<!-- 方案标题(新增字段) -->
<view class="form-item">
<view class="item-label-wrapper">
<text class="item-label">方案标题</text>
<text class="required-star">*</text>
</view>
<input
class="item-input"
type="text"
placeholder="请输入方案标题,如:呼吸道感染治疗方案"
placeholder-class="placeholder-style"
value="{{planForm.title}}"
bindinput="onTitleInput"
maxlength="100"
/>
</view>
<!-- 诊断结果 -->
<view class="form-item">
<view class="item-label-wrapper">
<text class="item-label">诊断结果</text>
<text class="required-star">*</text>
</view>
<input
class="item-input"
type="text"
placeholder="请输入诊断结果,如:细菌性肠炎"
placeholder-class="placeholder-style"
value="{{planForm.diagnosis}}"
bindinput="onDiagnosisInput"
maxlength="100"
/>
</view>
<!-- 治疗方式 -->
<view class="form-item">
<view class="item-label-wrapper">
<text class="item-label">治疗方式</text>
<text class="required-star">*</text>
</view>
<input
class="item-input"
type="text"
placeholder="请输入治疗方式,如:西药治疗、手术治疗等"
placeholder-class="placeholder-style"
value="{{planForm.treatmentMethod}}"
bindinput="onTreatmentMethodInput"
maxlength="50"
/>
</view>
<!-- 治疗方案描述(文本域) -->
<view class="form-item">
<view class="item-label-wrapper">
<text class="item-label">治疗方案描述</text>
<text class="required-star">*</text>
</view>
<textarea
class="item-textarea"
placeholder="详细描述治疗方案,包括用药、剂量、疗程等"
placeholder-class="placeholder-style"
value="{{planForm.treatmentDesc}}"
bindinput="onTreatmentDescInput"
maxlength="500"
auto-height
/>
<text class="word-count">{{planForm.treatmentDesc.length || 0}}/500</text>
</view>
<!-- 注意事项(文本域) -->
<view class="form-item">
<view class="item-label-wrapper">
<text class="item-label">注意事项</text>
<text class="optional-tip">(选填)</text>
</view>
<textarea
class="item-textarea"
placeholder="饮食、护理、复诊提醒等注意事项"
placeholder-class="placeholder-style"
value="{{planForm.precautions}}"
bindinput="onPrecautionsInput"
maxlength="300"
auto-height
/>
<text class="word-count">{{planForm.precautions.length || 0}}/300</text>
</view>
</scroll-view>
<!-- 弹窗底部按钮 -->
<view class="popup-footer">
<button class="btn-cancel" bindtap="closePlanPopup">取消</button>
<button class="btn-submit" bindtap="submitPlan">提交方案</button>
</view>
</view>
</view>
</view> </view>

274
pagesA/pages/precept/precept.wxss

@ -82,44 +82,6 @@
padding-top: 24rpx; padding-top: 24rpx;
} }
/* 列表头部 */
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
padding: 0 4rpx;
}
.section-title {
font-size: 32rpx;
font-weight: 700;
color: #1A1A1A;
position: relative;
padding-left: 16rpx;
}
.section-title::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 4rpx;
height: 20rpx;
background: linear-gradient(180deg, #6D9EFF 0%, #4A7CFF 100%);
border-radius: 2rpx;
}
.section-count {
font-size: 26rpx;
color: #666;
background: #F0F7FF;
padding: 6rpx 16rpx;
border-radius: 16rpx;
font-weight: 500;
}
/* 问诊记录卡片 */ /* 问诊记录卡片 */
.record-card { .record-card {
background: #FFFFFF; background: #FFFFFF;
@ -231,16 +193,6 @@
letter-spacing: 1rpx; letter-spacing: 1rpx;
} }
@keyframes cowPulse {
0%, 100% {
transform: scale(1) rotate(0deg);
}
50% {
transform: scale(1.1) rotate(5deg);
}
}
.livestock-tags { .livestock-tags {
display: flex; display: flex;
gap: 16rpx; gap: 16rpx;
@ -350,6 +302,8 @@
font-size: 24rpx; font-size: 24rpx;
font-weight: 500; font-weight: 500;
color: #4A7CFF; color: #4A7CFF;
display: inline-block;
padding: 8rpx 16rpx;
} }
/* 空状态优化 */ /* 空状态优化 */
@ -394,7 +348,6 @@
letter-spacing: 1rpx; letter-spacing: 1rpx;
} }
/* 卡片入场动画 */ /* 卡片入场动画 */
@keyframes cardSlideIn { @keyframes cardSlideIn {
from { from {
@ -418,6 +371,229 @@
.record-card:nth-child(4) { animation-delay: 0.25s; } .record-card:nth-child(4) { animation-delay: 0.25s; }
.record-card:nth-child(5) { animation-delay: 0.3s; } .record-card:nth-child(5) { animation-delay: 0.3s; }
/* ========== 弹窗样式(适配新增标题字段) ========== */
.plan-popup {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
display: flex;
align-items: flex-end;
}
.popup-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.4);
animation: fadeIn 0.2s ease;
}
/* 弹窗内容 */
.popup-content {
position: relative;
width: 100%;
background-color: #ffffff;
border-radius: 32rpx 32rpx 0 0;
box-shadow: 0 -8rpx 40rpx rgba(74, 124, 255, 0.12);
animation: slideUp 0.3s cubic-bezier(0.2, 0.6, 0.4, 1);
max-height: 80vh;
display: flex;
flex-direction: column;
}
/* 弹窗头部 */
.popup-header {
padding: 30rpx 40rpx;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 2rpx solid #F0F7FF;
background: linear-gradient(90deg, #F8FBFF, #ffffff);
border-top-left-radius: 30rpx;
border-top-right-radius: 30rpx;
}
.popup-title {
font-size: 36rpx;
font-weight: 700;
color: #1A1A1A;
background: linear-gradient(135deg, #4A7CFF 0%, #8CB4FF 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
letter-spacing: 1rpx;
}
.popup-close {
width: 48rpx;
height: 48rpx;
line-height: 48rpx;
text-align: center;
font-size: 36rpx;
color: #999;
background: #F5F9FF;
border-radius: 50%;
transition: all 0.2s;
}
.popup-close:active {
background: #E6ECFF;
color: #4A7CFF;
}
/* 表单滚动区 */
.popup-form {
flex: 1;
padding: 30rpx 40rpx 20rpx;
box-sizing: border-box;
max-height: 60vh;
}
.form-item {
margin-bottom: 36rpx;
position: relative;
}
.item-label-wrapper {
display: flex;
align-items: center;
margin-bottom: 12rpx;
}
.item-label {
font-size: 30rpx;
font-weight: 600;
color: #333;
}
.required-star {
color: #FF6B6B;
margin-left: 6rpx;
font-size: 28rpx;
}
.optional-tip {
color: #999;
font-size: 26rpx;
margin-left: 12rpx;
font-weight: 400;
}
.item-input {
width: 100%;
height: 88rpx;
background: #F9FAFF;
border: 2rpx solid #E6ECFF;
border-radius: 20rpx;
padding: 0 28rpx;
font-size: 30rpx;
color: #1A1A1A;
box-sizing: border-box;
transition: border 0.2s;
}
.item-input:focus {
border-color: #4A7CFF;
}
.item-input.disabled {
background: #F0F2F6;
color: #666;
border-color: #DDD;
}
.item-textarea {
width: 100%;
background: #F9FAFF;
border: 2rpx solid #E6ECFF;
border-radius: 20rpx;
padding: 24rpx 28rpx;
font-size: 30rpx;
color: #1A1A1A;
line-height: 1.6;
min-height: 160rpx;
box-sizing: border-box;
}
.word-count {
position: absolute;
right: 16rpx;
bottom: 5rpx;
font-size: 24rpx;
color: #AAA;
background: #F9FAFF;
padding: 0 8rpx;
z-index: 2;
}
/* 弹窗底部按钮 */
.popup-footer {
padding: 24rpx 40rpx 40rpx;
display: flex;
gap: 24rpx;
border-top: 2rpx solid #F0F7FF;
background: #ffffff;
}
.btn-cancel, .btn-submit {
flex: 1;
height: 88rpx;
border-radius: 44rpx;
font-size: 32rpx;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
}
.btn-cancel {
background: #F5F9FF;
color: #666;
border: none;
}
.btn-cancel:active {
background: #E6ECFF;
}
.btn-submit {
background: linear-gradient(135deg, #6D9EFF 0%, #4A7CFF 100%);
color: #FFFFFF;
border: none;
}
.btn-submit:active {
opacity: 0.9;
transform: scale(0.98);
}
/* placeholder样式 */
.placeholder-style {
color: #B0B8C5;
font-size: 28rpx;
}
/* 动画定义 */
@keyframes slideUp {
from {
transform: translateY(100%);
}
to {
transform: translateY(0);
}
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
/* 响应式适配 */ /* 响应式适配 */
@media screen and (min-width: 768px) { @media screen and (min-width: 768px) {
.record-card { .record-card {

8
utils/api.js

@ -140,6 +140,12 @@ function shareAdd(params) {
} }
// 制定方案新增
function fazdAdd(params) {
http('/vet/plan', 'post', params)
}
@ -172,5 +178,5 @@ export default { // 暴露接口
login,carousel,getPhoneNumber,article,articleDetails,articleZd,wzd,wzdAdd,shareAdd, login,carousel,getPhoneNumber,article,articleDetails,articleZd,wzd,wzdAdd,shareAdd,
areaChildren,userCode,UserInfo,videoList,videoZd,videoDetails,forumList,forumAdd,forumDetails, areaChildren,userCode,UserInfo,videoList,videoZd,videoDetails,forumList,forumAdd,forumDetails,
forumReply,commentReply,experience,experiencezd,experienceDetails,realName,revise,feedback, forumReply,commentReply,experience,experiencezd,experienceDetails,realName,revise,feedback,
today,carouselDetail,videoAdd,articleAdd,wzdxq
today,carouselDetail,videoAdd,articleAdd,wzdxq,fazdAdd
} }
Loading…
Cancel
Save