From 13660d1a8c90fe0ecf757f95f9a94ec31240303a Mon Sep 17 00:00:00 2001 From: huliyong <2783385703@qq.com> Date: Wed, 4 Jun 2025 13:47:57 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E8=AE=A2=E5=8D=95=E7=AE=A1=E7=90=86):=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=AE=A0=E7=89=A9=E6=A1=A3=E6=A1=88=E8=B7=B3?= =?UTF-8?q?=E8=BD=AC=E7=BC=BA=E5=B0=91=E8=AE=A2=E5=8D=95ID=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复订单详情页跳转宠物档案页面时未传递orderId参数的问题 ``` ```msg refactor(认证考试): 重构考试答案提交逻辑 将单个题目提交改为批量提交,优化考试流程: 1. 基础考试和培训考试都改为最后统一提交答案 2. 添加加载状态提示 3. 使用Promise.all处理并发请求 ``` ```msg fix(认证考试): 修复考试完成状态判断逻辑 修改answeBaseIsFinish和answeTrainIsFinish接口的返回判断逻辑,从检查code改为检查data字段 ``` ```msg feat(认证考试): 新增重新考试和成为伴宠师接口 1. 添加retakeExam和appletUsersTeacher接口 2. 在错误详情页添加重新考试功能 3. 在考试完成页添加成为伴宠师功能 ``` ```msg style(时间轴组件): 优化操作按钮布局 1. 添加按钮间距(gap) 2. 使用flex:1使按钮等宽 3. 根据状态显示不同按钮文本 4. 添加serviceBtn属性控制档案按钮显示 ``` ```msg refactor(订单弹窗): 重构服务档案弹窗组件 1. 使用timelineService组件替代原有实现 2. 简化数据结构处理 3. 添加状态判断逻辑 4. 优化弹窗标题和样式 ``` ```msg fix(表单验证): 添加认证考试结束页表单验证 1. 添加姓名、电话、地址的必填验证 2. 添加格式验证(电话格式、姓名格式) 3. 添加长度验证 4. 添加错误状态样式 5. 优化错误提示体验 ``` ```msg refactor(工作台): 重构伴宠师申请流程 1. 优化申请条件判断逻辑 2. 添加用户状态检查 3. 完善考试状态跳转逻辑 4. 统一使用store获取用户信息 --- api/examination/index.js | 35 ++- .../authentication/components/questionCard.vue | 24 +- otherPages/authentication/examination/base.vue | 58 ++++- otherPages/authentication/examination/end.vue | 154 +++++++++++- .../authentication/examination/errorDetail.vue | 24 +- otherPages/authentication/examination/train.vue | 27 +- otherPages/orderTakingManage/detail/index.vue | 2 +- .../components/petServicePopup - 副本.vue | 277 +++++++++++++++++++++ .../myOrdersManage/components/petServicePopup.vue | 225 ++--------------- pages/myOrdersManage/components/systemOrder.vue | 37 ++- .../myOrdersManage/components/timelineService.vue | 22 +- pages/workbenchManage/index.vue | 98 +++++--- 12 files changed, 695 insertions(+), 288 deletions(-) create mode 100644 pages/myOrdersManage/components/petServicePopup - 副本.vue diff --git a/api/examination/index.js b/api/examination/index.js index 82876d5..ef3a46f 100644 --- a/api/examination/index.js +++ b/api/examination/index.js @@ -133,14 +133,14 @@ export const answeTrainByQuestionId = (params) => { // 伴宠师工作台-查询用户基本考核是否完成 export const answeBaseIsFinish = (params) => { return request({ - url: '/applet/examination/answeBaseIsFinish', + url: '/applet/examination/answeBaseIsFinishV2', headers: { isToken: true }, method: "get", params }).then(res => { - return res.code == 200 + return res.data == 1 }) } @@ -148,13 +148,40 @@ export const answeBaseIsFinish = (params) => { // 伴宠师工作台-查询用户培训考核是否完成 export const answeTrainIsFinish = (params) => { return request({ - url: '/applet/examination/answeTrainIsFinish', + url: '/applet/examination/answeTrainIsFinishV2', headers: { isToken: true }, method: "get", params }).then(res => { - return res.code == 200 + return res.data == 1 }) } + + +// 伴宠师工作台-成为伴宠师 +export const appletUsersTeacher = (params) => { + return request({ + url: '/applet/examination/appletUsersTeacher', + headers: { + isToken: true + }, + method: "get", + params + }) +} + + +// 伴宠师工作台-重新考试 +export const retakeExam = (params) => { + return request({ + url: '/applet/examination/retakeExam', + headers: { + isToken: true + }, + method: "get", + params + }) +} + diff --git a/otherPages/authentication/components/questionCard.vue b/otherPages/authentication/components/questionCard.vue index 542df0b..0a42e10 100644 --- a/otherPages/authentication/components/questionCard.vue +++ b/otherPages/authentication/components/questionCard.vue @@ -103,18 +103,18 @@ const onChange = (val) => { value.value = val - const data = { - userId: userId.value, - questionId: props.data.id, - } - - if (props.type === '基本') { - data.answerId = val - addBaseAnswer(data) - } else if (props.type === '培训') { - data.answer = val - addTrainAnswer(data) - } + // const data = { + // userId: userId.value, + // questionId: props.data.id, + // } + + // if (props.type === '基本') { + // data.answerId = val + // addBaseAnswer(data) + // } else if (props.type === '培训') { + // data.answer = val + // addTrainAnswer(data) + // } } diff --git a/otherPages/authentication/examination/base.vue b/otherPages/authentication/examination/base.vue index 89a87dc..b67c281 100644 --- a/otherPages/authentication/examination/base.vue +++ b/otherPages/authentication/examination/base.vue @@ -40,6 +40,17 @@ import { ref, computed } from 'vue' import { onShow } from '@dcloudio/uni-app' import { getQuestionList, getQuestionOptions } from '@/api/examination' + import { + addBaseAnswer, + addTrainAnswer + } from '@/api/examination' + import { + store + } from '@/store' + + const userId = computed(() => { + return store.state.user.userInfo.userId + }) import questionCard from '../components/questionCard.vue'; @@ -50,13 +61,21 @@ const total = ref(0) const initQuestion = async () => { try { - let questions = (await getQuestionList({ type: TYPE })).map(item => ({ id: item.id, title: item.title, value: null })) + let questions = (await getQuestionList({ type: TYPE })).map(item => ({ + id: item.id, + title: item.title, + value: null, + answerList : item.answerList, + })) // todo: 替换成批量查询接口 for (let i = 0; i < questions.length; i++) { - const options = (await getQuestionOptions({ questionId: questions[i].id })).map(item => ({ id: item.id, title: item.title})) + // const options = (await getQuestionOptions({ questionId: questions[i].id })).map(item => ({ id: item.id, title: item.title})) - questions[i].options = options + // questions[i].options = options + + questions[i].options = questions[i].answerList + } list.value = questions @@ -87,7 +106,38 @@ const progress = computed(() => { return Math.floor(answered.value / total.value * 100) }) -const toNext = () => { +const toNext = async () => { + + const data = [] + + uni.showLoading({ + title: '提交中...' + }) + + list.value.forEach(n => { + data.push(addBaseAnswer({ + userId: userId.value, + questionId: n.id, + answerId : n.value, + })) + }) + + await Promise.all(data) + + uni.hideLoading() + + // list.value.forEach(n => { + // data.push({ + // userId: userId.value, + // questionId: n.id, + // answerId : n.value, + // }) + // }) + + // await addBaseAnswer({ + // list : JSON.stringify(data) + // }) + uni.navigateTo({ url: "/otherPages/authentication/examination/baseCompleted" }) diff --git a/otherPages/authentication/examination/end.vue b/otherPages/authentication/examination/end.vue index bc88d67..834cd02 100644 --- a/otherPages/authentication/examination/end.vue +++ b/otherPages/authentication/examination/end.vue @@ -114,19 +114,31 @@ 姓名: - + 电话: - + 地址: - + @@ -170,6 +182,7 @@ udpateUser, getUserOne } from '@/api/userTeacher' +import { appletUsersTeacher } from '@/api/examination' import stepProgress from '../components/stepProgress.vue'; @@ -192,8 +205,20 @@ latitude: null, longitude: null, address: null, + phone: null, }) + // 添加错误状态管理 + const formErrors = reactive({ + name: false, + phone: false, + address: false + }) + + // 清除单个字段错误状态 + const clearFieldError = (field) => { + formErrors[field] = false + } const initData = async () => { console.log('--initData') @@ -257,8 +282,101 @@ }) } + const validateForm = () => { + const { name, phone, address } = form + let hasError = false + + // 重置错误状态 + Object.keys(formErrors).forEach(key => { + formErrors[key] = false + }) + + // 必填字段验证 + if (!name || name.trim() === '') { + formErrors.name = true + hasError = true + uni.showToast({ + title: '请输入姓名', + icon: 'none' + }) + return false + } + + if (!phone || phone.trim() === '') { + formErrors.phone = true + hasError = true + uni.showToast({ + title: '请输入电话号码', + icon: 'none' + }) + return false + } + + if (!address || address.trim() === '') { + formErrors.address = true + hasError = true + uni.showToast({ + title: '请输入收货地址', + icon: 'none' + }) + return false + } + + // 姓名长度验证 + if (name.trim().length < 2 || name.trim().length > 10) { + formErrors.name = true + hasError = true + uni.showToast({ + title: '姓名长度应在2-10个字符之间', + icon: 'none' + }) + return false + } + + // 电话号码格式验证 + const phoneRegex = /^1[3-9]\d{9}$/ + if (!phoneRegex.test(phone.trim())) { + formErrors.phone = true + hasError = true + uni.showToast({ + title: '请输入正确的手机号码', + icon: 'none' + }) + return false + } + + // 地址长度验证 + if (address.trim().length < 5 || address.trim().length > 100) { + formErrors.address = true + hasError = true + uni.showToast({ + title: '地址长度应在5-100个字符之间', + icon: 'none' + }) + return false + } + + // 姓名格式验证(只允许中文、英文字母) + const nameRegex = /^[\u4e00-\u9fa5a-zA-Z\s]+$/ + if (!nameRegex.test(name.trim())) { + formErrors.name = true + hasError = true + uni.showToast({ + title: '姓名只能包含中文和英文字母', + icon: 'none' + }) + return false + } + + return true + } + const onSave = async () => { try { + // 先进行表单验证 + if (!validateForm()) { + return + } const { area, @@ -274,13 +392,20 @@ area, latitude, longitude, - address, - name, - phone, + address: address.trim(), + name: name.trim(), + phone: phone.trim(), } await udpateUser(data) + //成为伴宠师 + await appletUsersTeacher({ + userId : userId.value + }) + + store.dispatch('getUserInfo') + uni.showToast({ title: '提交成功!', icon: "none" @@ -293,7 +418,11 @@ }, 1000) } catch (err) { - + uni.showToast({ + title: '提交失败,请重试', + icon: 'none' + }) + console.error('提交失败:', err) } } @@ -478,4 +607,15 @@ .highlight { color: #FFBF60; } + + // 添加输入框错误状态样式 + .input-error { + border: 1px solid #ff4757 !important; + background-color: #fff5f5 !important; + color: #ff4757 !important; + } + + .input-error::placeholder { + color: #ff9999 !important; + } \ No newline at end of file diff --git a/otherPages/authentication/examination/errorDetail.vue b/otherPages/authentication/examination/errorDetail.vue index 1681ca1..4a50de4 100644 --- a/otherPages/authentication/examination/errorDetail.vue +++ b/otherPages/authentication/examination/errorDetail.vue @@ -34,9 +34,9 @@ \ No newline at end of file diff --git a/pages/myOrdersManage/components/petServicePopup.vue b/pages/myOrdersManage/components/petServicePopup.vue index d777f10..753c881 100644 --- a/pages/myOrdersManage/components/petServicePopup.vue +++ b/pages/myOrdersManage/components/petServicePopup.vue @@ -1,44 +1,16 @@