Commit 40699575 authored by 张九刚's avatar 张九刚

feat: backup

parent 2f99e2c5
......@@ -161,7 +161,14 @@ const onAdd = () => {
modifyState()
break;
case '3':
if (getCurrentPages().length > 1) {
uni.navigateBack()
} else {
uni.reLaunch({
url: '/pages/index/index'
})
}
break;
default:
break;
......
......@@ -417,33 +417,68 @@
</view>
</uni-popup>
<popupTip v-if="isTip" type="1" @statusChange="onPopupTipBabyChange" @close="isTip = false"></popupTip>
<popupTip v-if="isTip" type="1" @statusChange="onPopupTipBabyChange" @afterPhone="isShowRegisterLayer = true"
:isNotLogin="isNotLogin" @close="isTip = false"></popupTip>
<RegisterLayer v-model="isShowRegisterLayer" @confirm="onRegisterConfirm" />
</template>
<script setup>
import { ref, computed, onMounted, onUnmounted, getCurrentInstance } from 'vue'
import { onShow, onLoad, onHide,onShareAppMessage,onShareTimeline } from '@dcloudio/uni-app'
import BabySwitchPopup from '@/components/BabySwitchPopup.vue'
import popupTip from '../../components/popup-tip/popup-tip.vue'
import { fetchFeedingJSON, feedingHome, feedingRecords, feedingFoodsCustom, feedingFoodsCustomAdd, feedingFoodsCustomDelete, feedingTimerStart, feedingTimerStop, feedingVoiceUpload, feedingVoiceResult } from '@/api/feeding.js'
import { useUserStore } from '@/stores/user.js'
import { jump, JumpType, showLoading } from '../../utils'
import { getHealthField } from "@/api/common";
import md from '../../md'
// 弹窗引用
const addFoodPopup = ref(null)
const successPopup = ref(null)
const { proxy } = getCurrentInstance();
const $baseUrl = proxy.$baseUrl;
const version = 'v1'
// 计时器上限时间(秒)
const TIMER_MAX_DURATION = 3600
const feedingIndexRes = {
import {
ref,
computed,
onMounted,
onUnmounted,
getCurrentInstance
} from 'vue'
import {
onShow,
onLoad,
onHide,
onShareAppMessage,
onShareTimeline
} from '@dcloudio/uni-app'
import BabySwitchPopup from '@/components/BabySwitchPopup.vue'
import RegisterLayer from '@/components/RegisterLayer.vue'
import popupTip from '../../components/popup-tip/popup-tip.vue'
import {
fetchFeedingJSON,
feedingHome,
feedingRecords,
feedingFoodsCustom,
feedingFoodsCustomAdd,
feedingFoodsCustomDelete,
feedingTimerStart,
feedingTimerStop,
feedingVoiceUpload,
feedingVoiceResult
} from '@/api/feeding.js'
import {
useUserStore
} from '@/stores/user.js'
import {
jump,
JumpType,
showLoading
} from '../../utils'
import {
getHealthField
} from "@/api/common";
import md from '../../md'
// 弹窗引用
const addFoodPopup = ref(null)
const successPopup = ref(null)
const {
proxy
} = getCurrentInstance();
const $baseUrl = proxy.$baseUrl;
const version = 'v1'
// 计时器上限时间(秒)
const TIMER_MAX_DURATION = 3600
const feedingIndexRes = {
// 轮播图
banner: $baseUrl + `feedingIndex/${version}/banner.png`,
......@@ -512,26 +547,26 @@ const feedingIndexRes = {
// 识别成功弹窗
icon_btn_confirm: $baseUrl + `feedingIndex/${version}/icon_btn_confirm.png`,
icon_btn_cancel: $baseUrl + `feedingIndex/${version}/icon_btn_cancel.png`,
}
}
const swiperData = ref([
const swiperData = ref([
]);
const indicatorStyle = `height: 40px; border: none;`
]);
const indicatorStyle = `height: 40px; border: none;`
// 当前时间,使用 home 接口的 timestamp
const currentTime = ref(null)
// 当前时间,使用 home 接口的 timestamp
const currentTime = ref(null)
// 日期范围限制
const earliestDateString = ref('2020-01-01')
const latestDateString = ref('2030-12-31')
// 日期范围限制
const earliestDateString = ref('2020-01-01')
const latestDateString = ref('2030-12-31')
// 时间选择器引用
const timePickerRef = ref(null)
const voiceTimePickerRef = ref(null)
// 时间选择器引用
const timePickerRef = ref(null)
const voiceTimePickerRef = ref(null)
// 接口返回的数据
const homeData = ref({
// 接口返回的数据
const homeData = ref({
timestamp: null,
lastRecordType: 0,
lastBreastMilkVolume: 0,
......@@ -540,12 +575,12 @@ const homeData = ref({
leftTimerDuration: 0,
rightTimerRunning: false,
rightTimerDuration: 0
})
})
// 记录相关数据
const currentRecordId = ref(null) // 当前记录ID,用于区分新增和修改
const isSubmitting = ref(false) // 提交状态
const bannerHandler = (item) => {
// 记录相关数据
const currentRecordId = ref(null) // 当前记录ID,用于区分新增和修改
const isSubmitting = ref(false) // 提交状态
const bannerHandler = (item) => {
// 检查是否正在录音
if (recordingState.value.isRecording || voiceRecognitionState.value.isRecording) {
uni.showToast({
......@@ -562,41 +597,60 @@ const bannerHandler = (item) => {
});
console.log(item);
jump({ type: item.jumpType, url: item.url, extra: item.extra })
}
jump({
type: item.jumpType,
url: item.url,
extra: item.extra
})
}
const showTimePicker = () => {
const showTimePicker = () => {
md.sensorLogTake({
xcxClick: "小程序页面点击事件",
pageName: "喂养工具首页",
buttonName: "选择喂养时间",
});
}
}
const feedingTypes = ref([
{ value: 'breastfeeding', label: '母乳亲喂', icon: feedingIndexRes.icon_muruqinwei },
{ value: 'bottle', label: '母乳瓶喂', icon: feedingIndexRes.icon_murupinwei },
{ value: 'formula', label: '奶粉喂养', icon: feedingIndexRes.icon_naifen },
{ value: 'food', label: '辅食', icon: feedingIndexRes.icon_fushi }
])
const feedingTypes = ref([{
value: 'breastfeeding',
label: '母乳亲喂',
icon: feedingIndexRes.icon_muruqinwei
},
{
value: 'bottle',
label: '母乳瓶喂',
icon: feedingIndexRes.icon_murupinwei
},
{
value: 'formula',
label: '奶粉喂养',
icon: feedingIndexRes.icon_naifen
},
{
value: 'food',
label: '辅食',
icon: feedingIndexRes.icon_fushi
}
])
// 根据接口数据初始化选中的喂养类型
const selectedType = ref('breastfeeding')
// 根据接口数据初始化选中的喂养类型
const selectedType = ref('breastfeeding')
// 为每种喂养方式设置独立的记录方法
const recordMethods = ref({
// 为每种喂养方式设置独立的记录方法
const recordMethods = ref({
breastfeeding: 'manual',
bottle: 'manual',
formula: 'manual',
food: 'manual'
})
const isRecording = ref(false)
const isLeftTimerRunning = ref(false)
const isRightTimerRunning = ref(false)
})
const isRecording = ref(false)
const isLeftTimerRunning = ref(false)
const isRightTimerRunning = ref(false)
// 辅食数据结构 - 使用接口数据
const foodCategories = ref({
// 辅食数据结构 - 使用接口数据
const foodCategories = ref({
主食: {
items: [],
customItems: [],
......@@ -617,21 +671,21 @@ const foodCategories = ref({
customItems: [],
expanded: false
}
})
})
// 辅食ID映射,用于删除操作
const foodIdMap = ref(new Map())
// 辅食ID映射,用于删除操作
const foodIdMap = ref(new Map())
// 辅食类型映射
const foodTypeMap = {
// 辅食类型映射
const foodTypeMap = {
1: '主食',
2: '蔬菜',
3: '水果',
4: '其他'
}
}
// 辅食选择状态
const foodSelectionState = ref({
// 辅食选择状态
const foodSelectionState = ref({
isEditMode: false, // 是否处于编辑模式
showAddPopup: false, // 是否显示添加弹窗
currentCategory: '', // 当前添加的分类
......@@ -640,12 +694,12 @@ const foodSelectionState = ref({
originalFoodData: null, // 保存原始辅食数据,用于恢复
isAddingFood: false, // 添加辅食防连点状态
isDeletingFood: false // 删除辅食防连点状态
})
})
// 记录成功弹窗状态 - 已移除,改用 .open() 和 .close() 方法
// 记录成功弹窗状态 - 已移除,改用 .open() 和 .close() 方法
// 语音识别状态
const voiceRecognitionState = ref({
// 语音识别状态
const voiceRecognitionState = ref({
isRecording: false, // 是否正在录音
showResultPage: false, // 是否显示识别结果页面
recognizedText: '', // 识别结果文本
......@@ -660,22 +714,23 @@ const voiceRecognitionState = ref({
recordDate: '', // 记录日期
recordTime: '', // 记录时间
voiceDateTime: '' // 完整的日期时间字符串
})
// 录音管理器
const recorderManager = uni.getRecorderManager()
})
// 全局状态管理
const userStore = useUserStore()
const babyId = computed(() => userStore.babyInfo?.content?.id)
// 录音管理器
const recorderManager = uni.getRecorderManager()
// 宝宝切换相关状态
const showBabySwitchPopup = ref(false)
// 全局状态管理
const userStore = useUserStore()
const babyId = computed(() => userStore.babyInfo?.content?.id)
const isTip = ref(true)
// 宝宝切换相关状态
const showBabySwitchPopup = ref(false)
// 为每种喂养方式设置独立的数据 - 根据接口数据初始化
const feedingData = ref({
const isTip = ref(true)
const isNotLogin = ref(false)
const isShowRegisterLayer = ref(false)
// 为每种喂养方式设置独立的数据 - 根据接口数据初始化
const feedingData = ref({
breastfeeding: {
leftDuration: 5,
rightDuration: 5
......@@ -689,37 +744,42 @@ const feedingData = ref({
food: {
selectedItems: []
}
})
})
// 刻度标记数组 (0-500ml,每5ml一个刻度)
const scaleMarks = ref([0, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500])
// 刻度标记数组 (0-500ml,每5ml一个刻度)
const scaleMarks = ref([0, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500])
// picker-view相关数据
const pickerAmounts = ref([0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, 170, 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230, 235, 240, 245, 250, 255, 260, 265, 270, 275, 280, 285, 290, 295, 300, 305, 310, 315, 320, 325, 330, 335, 340, 345, 350, 355, 360, 365, 370, 375, 380, 385, 390, 395, 400, 405, 410, 415, 420, 425, 430, 435, 440, 445, 450, 455, 460, 465, 470, 475, 480, 485, 490, 495, 500])
// picker-view相关数据
const pickerAmounts = ref([0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110,
115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, 170, 175, 180, 185, 190, 195, 200, 205, 210, 215,
220, 225, 230, 235, 240, 245, 250, 255, 260, 265, 270, 275, 280, 285, 290, 295, 300, 305, 310, 315, 320,
325, 330, 335, 340, 345, 350, 355, 360, 365, 370, 375, 380, 385, 390, 395, 400, 405, 410, 415, 420, 425,
430, 435, 440, 445, 450, 455, 460, 465, 470, 475, 480, 485, 490, 495, 500
])
// 滑动相关状态
const isDragging = ref(false)
const startY = ref(0)
const startAmount = ref(0)
// 滑动相关状态
const isDragging = ref(false)
const startY = ref(0)
const startAmount = ref(0)
// 计时器数据 - 根据接口数据初始化
const timerData = ref({
// 计时器数据 - 根据接口数据初始化
const timerData = ref({
leftDuration: 0,
rightDuration: 0
})
})
// 计时器间隔ID
let leftTimerInterval = null
let rightTimerInterval = null
// 计时器间隔ID
let leftTimerInterval = null
let rightTimerInterval = null
// 计算属性 - 判断是否显示表单
const shouldShowForm = computed(() => {
// 计算属性 - 判断是否显示表单
const shouldShowForm = computed(() => {
const currentMethod = recordMethods.value[selectedType.value]
return currentMethod === 'manual' // 只有手动模式显示表单
})
})
// 计算属性 - 同步picker-view的值
const pickerValue = computed({
// 计算属性 - 同步picker-view的值
const pickerValue = computed({
get() {
const currentAmount = feedingData.value[selectedType.value].amount
const index = pickerAmounts.value.indexOf(currentAmount)
......@@ -728,28 +788,28 @@ const pickerValue = computed({
set(value) {
// 这个setter不会被直接调用,但需要保持响应式
}
})
})
// 计算属性 - 判断是否为语音模式(辅食除外)
const isVoiceMode = computed(() => {
// 计算属性 - 判断是否为语音模式(辅食除外)
const isVoiceMode = computed(() => {
return recordMethods.value[selectedType.value] === 'voice' && selectedType.value !== 'food'
})
})
// 计算属性 - 获取宝宝信息(只显示已出生的宝宝)
const babyList = computed(() => {
// 计算属性 - 获取宝宝信息(只显示已出生的宝宝)
const babyList = computed(() => {
const allBabies = userStore.babyInfo?.allBabyBaseInfo || []
// 只返回已出生的宝宝(babyStage === 2)
return allBabies.filter(baby => baby.babyStage === 2)
})
const currentBabyIndex = computed(() => {
})
const currentBabyIndex = computed(() => {
if (!babyList.value || !currentBaby.value) return 0
return babyList.value.findIndex(baby => baby.id === currentBaby.value.id)
})
const currentBaby = computed(() => userStore.babyInfo?.content)
const currentBabyId = computed(() => userStore.babyInfo?.content?.id)
})
const currentBaby = computed(() => userStore.babyInfo?.content)
const currentBabyId = computed(() => userStore.babyInfo?.content?.id)
// 页面加载时获取数据
onMounted(async () => {
// 页面加载时获取数据
onMounted(async () => {
md.sensorLogTake({
xcxPage: "小程序页面浏览事件",
pageName: "喂养工具首页",
......@@ -760,18 +820,26 @@ onMounted(async () => {
// 初始化录音管理器
initializeRecorderManager()
})
})
const onRegisterConfirm = async () => {
isShowRegisterLayer.value = false;
await loadBabyInfo()
loadFoodsData()
// 初始化录音管理器
initializeRecorderManager()
}
const onPopupTipBabyChange = async () => {
const onPopupTipBabyChange = async () => {
isTip.value = false
console.log('onPopupTipBabyChange', isTip.value)
// showBabySwitchPopup.value = true
await loadBabyInfo()
loadHomeData()
}
}
// 页面显示时刷新数据
onShow(async () => {
// 页面显示时刷新数据
onShow(async () => {
console.log('页面显示,刷新数据...')
if (!babyId.value) {
......@@ -807,10 +875,10 @@ onShow(async () => {
restoreUnfinishedEdit()
}, 500)
}
})
})
// 页面隐藏时同步计时器状态
onHide(() => {
// 页面隐藏时同步计时器状态
onHide(() => {
console.log('页面隐藏,处理录音状态...')
// 如果正在录音,停止录音并重置状态
......@@ -829,10 +897,10 @@ onHide(() => {
console.log('页面隐藏时同步右侧计时器状态')
// 这里可以选择是否调用后端接口同步状态
}
})
})
// 页面卸载时清理计时器
onUnmounted(() => {
// 页面卸载时清理计时器
onUnmounted(() => {
console.log('页面卸载,清理资源...')
// 清理左侧计时器
......@@ -866,10 +934,10 @@ onUnmounted(() => {
} catch (error) {
console.warn('页面卸载时清理录音管理器回调出错:', error)
}
})
})
// 页面参数接收
onLoad(async (options) => {
// 页面参数接收
onLoad(async (options) => {
console.log('页面参数:', options)
// 如果是修改记录,接收记录ID
......@@ -894,18 +962,18 @@ onLoad(async (options) => {
}
selectedType.value = typeMap[options.feedingType] || 'breastfeeding'
}
})
})
function getCurrentTime() {
function getCurrentTime() {
const now = new Date()
const hours = String(now.getHours()).padStart(2, '0')
const minutes = String(now.getMinutes()).padStart(2, '0')
return `${hours}:${minutes}`
}
}
// 根据记录数据设置表单
function setFormDataFromRecord(recordData) {
// 根据记录数据设置表单
function setFormDataFromRecord(recordData) {
// 设置喂养类型
const typeMap = {
1: 'breastfeeding',
......@@ -937,11 +1005,19 @@ function setFormDataFromRecord(recordData) {
}
// 不清除记录方法,保持用户的选择
}
}
// 获取宝宝信息
async function loadBabyInfo() {
// 获取宝宝信息
async function loadBabyInfo() {
try {
isNotLogin.value = false;
await userStore.loadUserInfo()
if (
userStore?.userInfo?.memberId &&
userStore?.userInfo?.memberId == "not_login" || !userStore.userInfo
) {
isNotLogin.value = true;
}
console.log('开始加载宝宝信息...')
if (userStore.babyInfo?.babyStage != 2) {
isTip.value = true
......@@ -977,10 +1053,10 @@ async function loadBabyInfo() {
icon: 'none'
})
}
}
}
// 获取首页数据
async function loadHomeData() {
// 获取首页数据
async function loadHomeData() {
if (!babyId.value) {
isTip.value = true
return
......@@ -1035,7 +1111,8 @@ async function loadHomeData() {
const feedingResponse = await fetchFeedingJSON()
console.log('轮播图数据:', feedingResponse)
if (feedingResponse && feedingResponse.data && feedingResponse.data.swiperData && feedingResponse.data.swiperData.length > 0) {
if (feedingResponse && feedingResponse.data && feedingResponse.data.swiperData && feedingResponse.data
.swiperData.length > 0) {
swiperData.value = feedingResponse.data.swiperData
}
} catch (error) {
......@@ -1043,10 +1120,10 @@ async function loadHomeData() {
// 使用默认的轮播图数据作为fallback
swiperData.value = []
}
}
}
// 根据接口数据初始化页面状态
function initializePageData() {
// 根据接口数据初始化页面状态
function initializePageData() {
const data = homeData.value
// 设置当前时间,优先使用 home 接口的 timestamp
......@@ -1112,10 +1189,10 @@ function initializePageData() {
// 重置计时器状态,确保状态和实际运行状态保持一致
resetTimerStatus()
}
}
// 重置计时器状态
function resetTimerStatus() {
// 重置计时器状态
function resetTimerStatus() {
// 如果状态显示计时器在运行,但实际没有定时器在运行,则重置状态
if (isLeftTimerRunning.value && !leftTimerInterval) {
console.log('重置左侧计时器状态:状态为运行但实际已停止')
......@@ -1125,10 +1202,10 @@ function resetTimerStatus() {
console.log('重置右侧计时器状态:状态为运行但实际已停止')
isRightTimerRunning.value = false
}
}
}
// 方法
function selectType(type) {
// 方法
function selectType(type) {
// 检查是否正在录音
if (recordingState.value.isRecording || voiceRecognitionState.value.isRecording) {
uni.showToast({
......@@ -1198,12 +1275,12 @@ function selectType(type) {
});
}
selectedType.value = type
}
}
// 清空之前的状态
function clearPreviousState() {
// 清空之前的状态
function clearPreviousState() {
// 清理轮询定时器
clearPollingInterval()
......@@ -1246,10 +1323,10 @@ function clearPreviousState() {
isDragging.value = false
startY.value = 0
startAmount.value = 0
}
}
// 清空喂养数据(保存成功后调用)
function clearFeedingData() {
// 清空喂养数据(保存成功后调用)
function clearFeedingData() {
// 清空所有喂养方式的数据
feedingData.value.breastfeeding.leftDuration = 5
feedingData.value.breastfeeding.rightDuration = 5
......@@ -1316,9 +1393,9 @@ function clearFeedingData() {
}
console.log('喂养数据已清空')
}
}
function adjustDuration(side, value) {
function adjustDuration(side, value) {
const currentData = feedingData.value.breastfeeding
if (side === 'left') {
......@@ -1365,26 +1442,26 @@ function adjustDuration(side, value) {
currentData.rightDuration = newValue
}
}
}
}
function adjustAmount(value) {
function adjustAmount(value) {
const currentType = selectedType.value
if (currentType === 'bottle' || currentType === 'formula') {
const currentData = feedingData.value[currentType]
currentData.amount = Math.max(0, Math.min(500, currentData.amount + value))
}
}
}
// 滑动选择相关方法
function onTouchStart(e) {
// 滑动选择相关方法
function onTouchStart(e) {
isDragging.value = true
startY.value = e.touches[0].clientY
startAmount.value = feedingData.value[selectedType.value].amount
}
}
function onTouchMove(e) {
function onTouchMove(e) {
if (!isDragging.value) return
const currentY = e.touches[0].clientY
......@@ -1398,26 +1475,26 @@ function onTouchMove(e) {
const adjustedAmount = Math.round(newAmount / 5) * 5
feedingData.value[selectedType.value].amount = adjustedAmount
}
}
function onTouchEnd() {
function onTouchEnd() {
isDragging.value = false
}
}
function getSliderPosition() {
function getSliderPosition() {
const currentAmount = feedingData.value[selectedType.value].amount
// 将0-500ml映射到0-100%的位置
return 100 - (currentAmount / 500) * 100
}
}
// picker-view选择事件
function onPickerChange(e) {
// picker-view选择事件
function onPickerChange(e) {
const index = e.detail.value[0]
const selectedAmount = pickerAmounts.value[index]
feedingData.value[selectedType.value].amount = selectedAmount
}
}
function setRecordMethod(method) {
function setRecordMethod(method) {
// 手动记录、计时器记录、语音记录
......@@ -1489,7 +1566,8 @@ function setRecordMethod(method) {
}
// 母乳亲喂计时器运行时阻止切换记录方式
if (selectedType.value === 'breastfeeding' && ((isLeftTimerRunning.value && leftTimerInterval) || (isRightTimerRunning.value && rightTimerInterval))) {
if (selectedType.value === 'breastfeeding' && ((isLeftTimerRunning.value && leftTimerInterval) || (
isRightTimerRunning.value && rightTimerInterval))) {
uni.showToast({
title: '计时器正在运行,请先停止计时',
icon: 'none'
......@@ -1522,15 +1600,15 @@ function setRecordMethod(method) {
if (method === 'voice') {
checkVoicePermission()
}
}
}
function toggleRecording() {
function toggleRecording() {
isRecording.value = !isRecording.value
}
}
async function toggleTimer(side) {
async function toggleTimer(side) {
const currentBabyId = babyId.value
if (side === 'left') {
......@@ -1646,9 +1724,9 @@ async function toggleTimer(side) {
}
}
}
}
}
function startLeftTimer() {
function startLeftTimer() {
// 开始左侧计时
console.log('开始左侧计时')
// 如果已经有计时器在运行,先停止
......@@ -1667,18 +1745,18 @@ function startLeftTimer() {
autoStopLeftTimer()
}
}, 1000) // 每秒增加1秒
}
}
function stopLeftTimer() {
function stopLeftTimer() {
// 停止左侧计时
console.log('停止左侧计时')
if (leftTimerInterval) {
clearInterval(leftTimerInterval)
leftTimerInterval = null
}
}
}
function startRightTimer() {
function startRightTimer() {
// 开始右侧计时
console.log('开始右侧计时')
// 如果已经有计时器在运行,先停止
......@@ -1697,19 +1775,19 @@ function startRightTimer() {
autoStopRightTimer()
}
}, 1000) // 每秒增加1秒
}
}
function stopRightTimer() {
function stopRightTimer() {
// 停止右侧计时
console.log('停止右侧计时')
if (rightTimerInterval) {
clearInterval(rightTimerInterval)
rightTimerInterval = null
}
}
}
// 自动停止左侧计时器(调用后端接口)
async function autoStopLeftTimer() {
// 自动停止左侧计时器(调用后端接口)
async function autoStopLeftTimer() {
const currentBabyId = babyId.value
if (!currentBabyId) {
console.warn('没有选择宝宝,无法停止计时器')
......@@ -1727,10 +1805,10 @@ async function autoStopLeftTimer() {
console.error('自动停止左侧计时器失败:', error)
// 不显示错误提示,因为这是自动停止
}
}
}
// 自动停止右侧计时器(调用后端接口)
async function autoStopRightTimer() {
// 自动停止右侧计时器(调用后端接口)
async function autoStopRightTimer() {
const currentBabyId = babyId.value
if (!currentBabyId) {
console.warn('没有选择宝宝,无法停止计时器')
......@@ -1748,10 +1826,10 @@ async function autoStopRightTimer() {
console.error('自动停止右侧计时器失败:', error)
// 不显示错误提示,因为这是自动停止
}
}
}
// 停止所有计时器
async function stopAllTimers() {
// 停止所有计时器
async function stopAllTimers() {
const currentBabyId = babyId.value
if (!currentBabyId) {
console.warn('没有选择宝宝,无法停止计时器')
......@@ -1787,10 +1865,10 @@ async function stopAllTimers() {
// 不显示错误提示,因为这是正常的保存流程
// 即使计时器停止失败,也要继续保存记录
}
}
}
// 完成记录
async function completeRecord() {
// 完成记录
async function completeRecord() {
// 防止重复提交
......@@ -1907,20 +1985,26 @@ async function completeRecord() {
isSubmitting.value = false
}, 2000)
}
}
}
// 验证记录数据
function validateRecordData() {
// 验证记录数据
function validateRecordData() {
const currentBaby = userStore.babyInfo?.content
// 验证宝宝信息
if (!currentBaby || !currentBaby.id) {
return { valid: false, message: '请选择宝宝' }
return {
valid: false,
message: '请选择宝宝'
}
}
// 验证喂养时间
if (!currentTime.value) {
return { valid: false, message: '请选择喂养时间' }
return {
valid: false,
message: '请选择喂养时间'
}
}
// 根据喂养类型和记录方式验证具体数据
......@@ -1933,19 +2017,28 @@ function validateRecordData() {
const leftDuration = feedingData.value.breastfeeding.leftDuration
const rightDuration = feedingData.value.breastfeeding.rightDuration
if (leftDuration === 0 && rightDuration === 0) {
return { valid: false, message: '还没有输入喂养信息哦~' }
return {
valid: false,
message: '还没有输入喂养信息哦~'
}
}
} else if (currentMethod === 'timer') {
// 计时器模式:验证计时器状态
const leftDuration = timerData.value.leftDuration
const rightDuration = timerData.value.rightDuration
if (leftDuration === 0 && rightDuration === 0) {
return { valid: false, message: '还没有输入喂养信息哦~' }
return {
valid: false,
message: '还没有输入喂养信息哦~'
}
}
} else if (currentMethod === 'voice') {
// 语音模式:验证语音识别结果
if (!voiceRecognitionState.value.recognizedText.trim()) {
return { valid: false, message: '还没有输入喂养信息哦~' }
return {
valid: false,
message: '还没有输入喂养信息哦~'
}
}
}
break
......@@ -1958,12 +2051,18 @@ function validateRecordData() {
// 手动模式:验证喂养量
const amount = feedingData.value[selectedType.value].amount
if (amount === 0) {
return { valid: false, message: '还没有输入喂养信息哦~' }
return {
valid: false,
message: '还没有输入喂养信息哦~'
}
}
} else if (currentMethod2 === 'voice') {
// 语音模式:验证语音识别结果
if (!voiceRecognitionState.value.recognizedText.trim()) {
return { valid: false, message: '还没有输入喂养信息哦~' }
return {
valid: false,
message: '还没有输入喂养信息哦~'
}
}
}
break
......@@ -1972,16 +2071,21 @@ function validateRecordData() {
// 辅食只有手动选择模式
const selectedItems = feedingData.value.food.selectedItems
if (selectedItems.length === 0) {
return { valid: false, message: '还没有输入喂养信息哦~' }
return {
valid: false,
message: '还没有输入喂养信息哦~'
}
}
break
}
return { valid: true }
}
return {
valid: true
}
}
// 构建记录数据
function buildRecordData() {
// 构建记录数据
function buildRecordData() {
const currentBaby = userStore.babyInfo?.content
// 判断是否为语音模式,如果是则使用弹窗中的日期和时间
......@@ -2020,7 +2124,8 @@ function buildRecordData() {
feedingType: 1, // 母乳亲喂
durationLeftSeconds: feedingData.value.breastfeeding.leftDuration * 60, // 转换为秒
durationRightSeconds: feedingData.value.breastfeeding.rightDuration * 60,
totalDurationSeconds: (feedingData.value.breastfeeding.leftDuration + feedingData.value.breastfeeding.rightDuration) * 60
totalDurationSeconds: (feedingData.value.breastfeeding.leftDuration + feedingData.value
.breastfeeding.rightDuration) * 60
}
} else if (currentMethod === 'timer') {
// 计时器模式:使用计时器的实际时长
......@@ -2091,13 +2196,13 @@ function buildRecordData() {
}
return baseData
}
}
function goBack() {
function goBack() {
uni.navigateBack()
}
}
function goToFeedingRecord() {
function goToFeedingRecord() {
// 检查是否正在录音
if (recordingState.value.isRecording || voiceRecognitionState.value.isRecording) {
uni.showToast({
......@@ -2116,15 +2221,15 @@ function goToFeedingRecord() {
uni.navigateTo({
url: '/pages/feedingRecord/feedingRecord'
})
}
}
// 时间选择器相关方法
function onTimeChange(value) {
// 时间选择器相关方法
function onTimeChange(value) {
currentTime.value = value
}
}
// 语音识别时间选择器显示
function showVoiceTimePicker() {
// 语音识别时间选择器显示
function showVoiceTimePicker() {
// 使用与 formatCurrentTime() 一致的默认时间
if (!voiceRecognitionState.value.voiceDateTime) {
const defaultTimeString = formatCurrentTime()
......@@ -2136,10 +2241,10 @@ function showVoiceTimePicker() {
}
}
voiceTimePickerRef.value.show()
}
}
// 语音识别时间选择
function onVoiceTimeChange(value) {
// 语音识别时间选择
function onVoiceTimeChange(value) {
// 设置完整的日期时间字符串
voiceRecognitionState.value.voiceDateTime = value
......@@ -2154,10 +2259,10 @@ function onVoiceTimeChange(value) {
// 设置分离的日期和时间
voiceRecognitionState.value.recordDate = `${year}-${month}-${day}`
voiceRecognitionState.value.recordTime = `${hours}:${minutes}`
}
}
// 格式化语音识别时间显示
function formatVoiceDateTime() {
// 格式化语音识别时间显示
function formatVoiceDateTime() {
if (voiceRecognitionState.value.voiceDateTime) {
const date = new Date(voiceRecognitionState.value.voiceDateTime)
const year = date.getFullYear()
......@@ -2169,10 +2274,10 @@ function formatVoiceDateTime() {
return `${year}-${month}-${day} ${hours}:${minutes}`
}
return ''
}
}
// 关闭语音识别结果弹窗
function closeVoiceResult() {
// 关闭语音识别结果弹窗
function closeVoiceResult() {
voiceRecognitionState.value.showResultPage = false
voiceRecognitionState.value.recognizedText = ''
voiceRecognitionState.value.recordDate = ''
......@@ -2181,9 +2286,9 @@ function closeVoiceResult() {
// 重置防连点状态,确保用户可以重新录音
resetRecordingCooldown()
}
}
function formatCurrentTime() {
function formatCurrentTime() {
if (!currentTime.value) {
// 如果当前时间未设置,返回当前时间
const now = new Date()
......@@ -2202,9 +2307,9 @@ function formatCurrentTime() {
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}`
}
}
function getTabImage() {
function getTabImage() {
const currentMethod = recordMethods.value[selectedType.value]
if (currentMethod === 'manual') {
return feedingIndexRes.Tab_bottom_write
......@@ -2213,35 +2318,35 @@ function getTabImage() {
} else {
return feedingIndexRes.Tab_bottom_voice
}
}
}
function getTabImage2() {
function getTabImage2() {
const currentMethod = recordMethods.value[selectedType.value]
if (currentMethod === 'manual') {
return feedingIndexRes.Tab_bottom_muruandnaifen_write
} else {
return feedingIndexRes.Tab_bottom_muruandnaifen_voice
}
}
}
// 格式化时间显示 (MM:SS)
function formatTime(seconds) {
// 格式化时间显示 (MM:SS)
function formatTime(seconds) {
const minutes = Math.floor(seconds / 60)
const remainingSeconds = seconds % 60
return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`
}
}
// 格式化总时长显示 (HH:MM:SS)
function formatTotalDuration() {
// 格式化总时长显示 (HH:MM:SS)
function formatTotalDuration() {
const totalSeconds = timerData.value.leftDuration + timerData.value.rightDuration
const hours = Math.floor(totalSeconds / 3600)
const minutes = Math.floor((totalSeconds % 3600) / 60)
const seconds = totalSeconds % 60
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`
}
}
// 辅食选择相关方法
function toggleFoodSelection(item) {
// 辅食选择相关方法
function toggleFoodSelection(item) {
// 在编辑模式时不允许选择
if (foodSelectionState.value.isEditMode) {
return
......@@ -2257,9 +2362,9 @@ function toggleFoodSelection(item) {
// 如果未选中,则添加选中
selectedItems.push(item)
}
}
}
function enterEditMode() {
function enterEditMode() {
if (foodSelectionState.value.isEditMode) {
// 如果已经在编辑模式,则取消编辑
cancelEditMode()
......@@ -2287,9 +2392,9 @@ function enterEditMode() {
// 清空待删除列表
foodSelectionState.value.pendingDeletes = []
}
}
}
function cancelEditMode() {
function cancelEditMode() {
// 恢复原始辅食数据,保持原有顺序
if (foodSelectionState.value.originalFoodData) {
feedingData.value.food.selectedItems = [...foodSelectionState.value.originalFoodData.selectedItems]
......@@ -2329,9 +2434,9 @@ function cancelEditMode() {
foodSelectionState.value.isEditMode = false
// 清理原始数据
foodSelectionState.value.originalFoodData = null
}
}
async function exitEditMode() {
async function exitEditMode() {
md.sensorLogTake({
xcxClick: "小程序页面点击事件",
pageName: "喂养工具首页",
......@@ -2381,7 +2486,8 @@ async function exitEditMode() {
if (foodSelectionState.value.originalFoodData) {
// 恢复原始辅食数据
Object.keys(foodCategories.value).forEach(categoryName => {
const originalCategory = foodSelectionState.value.originalFoodData.categories[categoryName]
const originalCategory = foodSelectionState.value.originalFoodData.categories[
categoryName]
if (originalCategory) {
foodCategories.value[categoryName].items = [...originalCategory.items]
foodCategories.value[categoryName].customItems = [...originalCategory.customItems]
......@@ -2404,9 +2510,9 @@ async function exitEditMode() {
// 立即重置防连点状态
foodSelectionState.value.isDeletingFood = false
console.log('防连点:重置删除完成状态为false')
}
}
function showAddFoodPopup(categoryName) {
function showAddFoodPopup(categoryName) {
md.sensorLogTake({
xcxClick: "小程序页面点击事件",
pageName: "喂养工具首页",
......@@ -2456,17 +2562,17 @@ function showAddFoodPopup(categoryName) {
foodSelectionState.value.isAddingFood = false
console.log('防连点:重置添加辅食状态为false')
}, 100)
}
}
// 切换分类展开/缩起状态
function toggleCategoryExpansion(categoryName) {
// 切换分类展开/缩起状态
function toggleCategoryExpansion(categoryName) {
const category = foodCategories.value[categoryName]
if (category) {
category.expanded = !category.expanded
}
}
}
function cancelAddFood() {
function cancelAddFood() {
addFoodPopup.value.close()
foodSelectionState.value.newFoodItem = ''
md.sensorPopLogTake({
......@@ -2475,9 +2581,9 @@ function cancelAddFood() {
popName: "新增辅食弹窗",
buttonName: "取消"
});
}
}
function confirmAddFood() {
function confirmAddFood() {
if (foodSelectionState.value.isAddingFood) {
console.log('防连点:添加辅食按钮被阻止')
return
......@@ -2511,9 +2617,9 @@ function confirmAddFood() {
foodSelectionState.value.isAddingFood = false
console.log('防连点:重置添加辅食状态为false')
}, 2000)
}
}
async function addCustomFoodItem(categoryName, itemName) {
async function addCustomFoodItem(categoryName, itemName) {
// 检查字数限制
if (itemName.length > 10) {
uni.showToast({
......@@ -2583,9 +2689,9 @@ async function addCustomFoodItem(categoryName, itemName) {
// 失败时重置防连点状态
foodSelectionState.value.isAddingFood = false
}
}
}
function removeFoodItem(categoryName, itemName) {
function removeFoodItem(categoryName, itemName) {
// 获取foodId
const foodId = foodIdMap.value.get(itemName)
......@@ -2632,10 +2738,10 @@ function removeFoodItem(categoryName, itemName) {
})
console.log('添加到待删除列表:', itemName, '原始位置:', originalIndex, '当前待删除:', foodSelectionState.value.pendingDeletes)
}
}
// 语音识别相关方法
function checkVoicePermission() {
// 语音识别相关方法
function checkVoicePermission() {
// 检查录音权限
uni.getSetting({
success: (res) => {
......@@ -2662,13 +2768,16 @@ function checkVoicePermission() {
// 打开设置页面
uni.openSetting({
success: (settingRes) => {
console.log('设置页面结果:', settingRes)
if (settingRes.authSetting['scope.record']) {
console.log('设置页面结果:',
settingRes)
if (settingRes.authSetting[
'scope.record']) {
console.log('录音权限已开启')
}
},
fail: (err) => {
console.error('打开设置页面失败:', err)
console.error('打开设置页面失败:',
err)
}
})
}
......@@ -2688,10 +2797,10 @@ function checkVoicePermission() {
})
}
})
}
}
// 录音状态管理
const recordingState = ref({
// 录音状态管理
const recordingState = ref({
isInitialized: false, // 是否已初始化录音管理器
isRecording: false, // 是否正在录音
recordingStartTime: null, // 录音开始时间
......@@ -2699,10 +2808,10 @@ const recordingState = ref({
recordingTimer: null, // 录音时长定时器
lastStopTime: 0, // 上次停止录音的时间戳
canStartRecording: true // 是否可以开始录音(防连点)
})
})
// 初始化录音管理器(只初始化一次)
function initializeRecorderManager() {
// 初始化录音管理器(只初始化一次)
function initializeRecorderManager() {
if (recordingState.value.isInitialized) {
console.log('录音管理器已初始化,跳过')
return
......@@ -2745,7 +2854,8 @@ function initializeRecorderManager() {
// 启动录音时长定时器
recordingState.value.recordingTimer = setInterval(() => {
if (recordingState.value.isRecording && recordingState.value.recordingStartTime) {
const duration = Math.floor((Date.now() - recordingState.value.recordingStartTime) / 1000)
const duration = Math.floor((Date.now() - recordingState.value.recordingStartTime) /
1000)
recordingState.value.recordingDuration = duration
voiceRecognitionState.value.recordingDuration = duration
}
......@@ -2830,10 +2940,10 @@ function initializeRecorderManager() {
recordingState.value.isInitialized = true
console.log('录音管理器初始化完成')
}
}
// 重置录音状态
function resetRecordingState() {
// 重置录音状态
function resetRecordingState() {
console.log('重置录音状态')
// 清理录音定时器
......@@ -2855,26 +2965,26 @@ function resetRecordingState() {
// 注意:这里不调用 recorderManager.stop(),因为调用方会处理
// 避免重复调用导致的问题
}
}
// 重置防连点状态(立即恢复)
function resetRecordingCooldown() {
// 重置防连点状态(立即恢复)
function resetRecordingCooldown() {
recordingState.value.canStartRecording = true
console.log('立即重置录音冷却状态')
}
}
// 检查录音管理器状态
function checkRecorderStatus() {
// 检查录音管理器状态
function checkRecorderStatus() {
console.log('检查录音管理器状态:', {
isRecording: recordingState.value.isRecording,
voiceIsRecording: voiceRecognitionState.value.isRecording,
recognitionStatus: voiceRecognitionState.value.recognitionStatus,
canStartRecording: recordingState.value.canStartRecording
})
}
}
// 强制重置录音管理器状态
function forceResetRecorderManager() {
// 强制重置录音管理器状态
function forceResetRecorderManager() {
console.log('强制重置录音管理器状态')
// 重置录音状态
......@@ -2902,10 +3012,10 @@ function forceResetRecorderManager() {
// 检查重置后的状态
checkRecorderStatus()
}, 300)
}
}
// 开始录音
async function startRecording() {
// 开始录音
async function startRecording() {
if (!recordingState.value.isRecording) {
md.sensorLogTake({
xcxClick: "小程序页面点击事件",
......@@ -3008,10 +3118,10 @@ async function startRecording() {
})
}
})
}
}
// 停止录音
async function stopRecording() {
// 停止录音
async function stopRecording() {
console.log('停止录音请求...')
......@@ -3076,10 +3186,10 @@ async function stopRecording() {
// 即使停止失败,也要强制重置录音管理器状态
forceResetRecorderManager()
}
}
}
// 处理语音文件
async function processVoiceFile(tempFilePath) {
// 处理语音文件
async function processVoiceFile(tempFilePath) {
try {
// 显示加载提示
uni.showLoading({
......@@ -3097,10 +3207,10 @@ async function processVoiceFile(tempFilePath) {
} catch (error) {
handleVoiceRecognitionError(error)
}
}
}
// 上传语音文件
async function uploadVoiceFile(tempFilePath) {
// 上传语音文件
async function uploadVoiceFile(tempFilePath) {
return new Promise((resolve, reject) => {
// 检查文件路径
if (!tempFilePath || typeof tempFilePath !== 'string') {
......@@ -3144,38 +3254,50 @@ async function uploadVoiceFile(tempFilePath) {
encoding: 'base64',
success: async (res) => {
try {
console.log('语音文件读取成功,base64长度:', res.data.length, '字符')
console.log('语音文件读取成功,base64长度:',
res.data.length, '字符')
// 检查base64数据是否有效
if (!res.data || res.data.length < 100) {
console.error('base64数据无效,长度:', res.data?.length)
reject(new Error('语音文件数据无效,请重新录音'))
if (!res.data || res.data.length <
100) {
console.error('base64数据无效,长度:',
res.data?.length)
reject(new Error(
'语音文件数据无效,请重新录音'))
return
}
// 验证base64格式
if (!/^[A-Za-z0-9+/]*={0,2}$/.test(res.data)) {
if (!/^[A-Za-z0-9+/]*={0,2}$/.test(
res.data)) {
console.error('base64格式无效')
reject(new Error('语音文件格式无效,请重新录音'))
reject(new Error(
'语音文件格式无效,请重新录音'))
return
}
console.log('base64数据验证通过,开始上传')
// 添加base64格式头
const base64WithHeader = `data:audio/mp3;base64,${res.data}`
const base64WithHeader =
`data:audio/mp3;base64,${res.data}`
// 调用上传接口,传递带格式头的base64数据
const response = await feedingVoiceUpload({
const response =
await feedingVoiceUpload({
audioData: base64WithHeader
})
console.log('上传接口返回:', response)
if (response && response.data && response.data.taskId) {
if (response && response.data &&
response.data.taskId) {
resolve(response.data)
} else {
reject(new Error('上传失败:未获取到taskId,返回数据:' + JSON.stringify(response)))
reject(new Error(
'上传失败:未获取到taskId,返回数据:' +
JSON.stringify(
response)))
}
} catch (error) {
console.error('上传过程中发生错误:', error)
......@@ -3184,7 +3306,8 @@ async function uploadVoiceFile(tempFilePath) {
},
fail: (err) => {
console.error('读取语音文件失败:', err)
reject(new Error('读取语音文件失败:' + err.errMsg))
reject(new Error('读取语音文件失败:' + err
.errMsg))
}
})
},
......@@ -3200,10 +3323,10 @@ async function uploadVoiceFile(tempFilePath) {
}
})
})
}
}
// 开始轮询识别结果
async function startPollingRecognitionResult(taskId) {
// 开始轮询识别结果
async function startPollingRecognitionResult(taskId) {
console.log('开始轮询识别结果,taskId:', taskId)
voiceRecognitionState.value.taskId = taskId
......@@ -3266,7 +3389,8 @@ async function startPollingRecognitionResult(taskId) {
voiceRecognitionState.value.recordDate = `${year}-${month}-${day}`
voiceRecognitionState.value.recordTime = `${hours}:${minutes}`
voiceRecognitionState.value.voiceDateTime = `${year}-${month}-${day} ${hours}:${minutes}:00`
voiceRecognitionState.value.voiceDateTime =
`${year}-${month}-${day} ${hours}:${minutes}:00`
}
voiceRecognitionState.value.showResultPage = true
md.sensorPopLogTake({
......@@ -3340,10 +3464,10 @@ async function startPollingRecognitionResult(taskId) {
})
}
}, 30000)
}
}
// 清理轮询定时器
function clearPollingInterval() {
// 清理轮询定时器
function clearPollingInterval() {
console.log('清理轮询定时器')
if (voiceRecognitionState.value.pollingInterval) {
......@@ -3369,10 +3493,10 @@ function clearPollingInterval() {
// 重置防连点状态,确保用户可以重新录音
resetRecordingCooldown()
}
}
// 处理语音识别错误
function handleVoiceRecognitionError(error) {
// 处理语音识别错误
function handleVoiceRecognitionError(error) {
console.error('语音识别错误:', error)
clearPollingInterval()
uni.hideLoading()
......@@ -3401,9 +3525,9 @@ function handleVoiceRecognitionError(error) {
title: errorMessage,
icon: 'none'
})
}
}
function getFeedingTypeLabel() {
function getFeedingTypeLabel() {
const typeMap = {
breastfeeding: '母乳亲喂',
bottle: '母乳瓶喂',
......@@ -3411,10 +3535,10 @@ function getFeedingTypeLabel() {
food: '辅食'
}
return typeMap[selectedType.value] || '未知'
}
}
// 格式化录音时长显示
function formatRecordingDuration(seconds) {
// 格式化录音时长显示
function formatRecordingDuration(seconds) {
if (!seconds || seconds <= 0) return '0秒'
const minutes = Math.floor(seconds / 60)
......@@ -3425,9 +3549,9 @@ function formatRecordingDuration(seconds) {
} else {
return `${remainingSeconds}秒`
}
}
}
function reRecognize() {
function reRecognize() {
console.log('重新识别...')
md.sensorPopLogTake({
xcxPopClick: "true",
......@@ -3454,9 +3578,9 @@ function reRecognize() {
voiceRecognitionState.value.recordDate = ''
voiceRecognitionState.value.recordTime = ''
voiceRecognitionState.value.voiceDateTime = ''
}
}
async function completeVoiceRecord() {
async function completeVoiceRecord() {
// 防止重复提交
if (isSubmitting.value) {
return
......@@ -3542,12 +3666,12 @@ async function completeVoiceRecord() {
isSubmitting.value = false
}, 2000)
}
}
}
// 记录成功弹窗相关方法
async function onSuccessJump() {
// 记录成功弹窗相关方法
async function onSuccessJump() {
// 检查是否正在录音
if (recordingState.value.isRecording || voiceRecognitionState.value.isRecording) {
uni.showToast({
......@@ -3567,7 +3691,13 @@ async function onSuccessJump() {
return;
}
const { sign, timestamp, appId, partnerUserId, env } = res.data;
const {
sign,
timestamp,
appId,
partnerUserId,
env
} = res.data;
jump({
type: JumpType.MINI,
......@@ -3580,8 +3710,7 @@ async function onSuccessJump() {
timestamp, // 参考 4.请求参数
appId, // 参考 4.请求参数
partnerUserId, // 参考 4.请求参数
targetApp:
"/h5/partner/shining-like-a-start/landing-free-consult?sysType=CRF",
targetApp: "/h5/partner/shining-like-a-start/landing-free-consult?sysType=CRF",
},
},
}); // 关闭弹窗
......@@ -3592,9 +3721,9 @@ async function onSuccessJump() {
popName: "添加成功弹窗",
buttonName: "咨询专家"
});
}
}
function onSuccessClose() {
function onSuccessClose() {
// 关闭弹窗
successPopup.value.close()
md.sensorPopLogTake({
......@@ -3607,15 +3736,15 @@ function onSuccessClose() {
uni.navigateTo({
url: '/pages/feedingRecord/feedingRecord'
})
}
}
// 检查是否有未完成的编辑操作
function hasUnfinishedEdit() {
// 检查是否有未完成的编辑操作
function hasUnfinishedEdit() {
return foodSelectionState.value.isEditMode && foodSelectionState.value.pendingDeletes.length > 0
}
}
// 恢复未完成的编辑操作
function restoreUnfinishedEdit() {
// 恢复未完成的编辑操作
function restoreUnfinishedEdit() {
if (hasUnfinishedEdit()) {
console.log('恢复未完成的辅食删除操作')
// 显示提示
......@@ -3636,10 +3765,10 @@ function restoreUnfinishedEdit() {
}
})
}
}
}
// 宝宝切换相关方法
function showBabySwitch() {
// 宝宝切换相关方法
function showBabySwitch() {
// 检查是否正在录音
if (recordingState.value.isRecording || voiceRecognitionState.value.isRecording) {
uni.showToast({
......@@ -3658,9 +3787,9 @@ function showBabySwitch() {
});
showBabySwitchPopup.value = true
}
}
}
async function onBabyChange(baby, index) {
async function onBabyChange(baby, index) {
// 切换宝宝
await userStore.changeBabySelected(baby.id)
console.log('切换到宝宝:', baby.babyName, '索引:', index)
......@@ -3670,17 +3799,23 @@ async function onBabyChange(baby, index) {
// 清空当前状态,避免数据混乱
clearPreviousState()
}
}
// 获取辅食列表数据
async function loadFoodsData() {
// 获取辅食列表数据
async function loadFoodsData() {
try {
const response = await feedingFoodsCustom()
console.log('辅食列表数据:', response)
if (response && response.data) {
const foodsList = response.data
//未登录情况下这里是个object{error_msg:'404 Route Not Found'}
if (foodsList instanceof Array) {
processFoodsData(foodsList)
} else {
processFoodsData([])
}
} else {
// 如果没有数据,使用默认数据
loadDefaultFoodsData()
......@@ -3691,10 +3826,10 @@ async function loadFoodsData() {
// 使用默认数据作为fallback
loadDefaultFoodsData()
}
}
}
// 处理辅食数据
function processFoodsData(foodsList) {
// 处理辅食数据
function processFoodsData(foodsList) {
// 清空现有数据
Object.keys(foodCategories.value).forEach(category => {
foodCategories.value[category].items = []
......@@ -3719,10 +3854,10 @@ function processFoodsData(foodsList) {
console.log('处理后的辅食数据:', foodCategories.value)
console.log('辅食ID映射:', foodIdMap.value)
}
}
// 加载默认辅食数据(fallback)
function loadDefaultFoodsData() {
// 加载默认辅食数据(fallback)
function loadDefaultFoodsData() {
foodCategories.value = {
主食: {
items: [],
......@@ -3745,48 +3880,48 @@ function loadDefaultFoodsData() {
expanded: false
}
}
}
}
onShareAppMessage(() => {
onShareAppMessage(() => {
return {
title: "喂养记录:喂奶辅食轻松记录,喂养数据一目了然",
path: "/pages/feedingIndex/feedingIndex",
imageUrl: $baseUrl + "share/weiyang.png",
}
});
});
onShareTimeline(() => {
onShareTimeline(() => {
return {
title: "喂养记录:喂奶辅食轻松记录,喂养数据一目了然",
path: "/pages/feedingIndex/feedingIndex",
imageUrl: $baseUrl + "share/weiyang.png",
}
});
});
</script>
<style lang="scss" scoped>
/* ===== 页面整体布局 ===== */
.feeding-record-add-page {
/* ===== 页面整体布局 ===== */
.feeding-record-add-page {
background: #ffffff;
min-height: 100vh;
padding: 0;
position: relative;
}
/* ===== 可滚动内容区域 ===== */
// .scrollable-content {
// height: calc(100vh);
// // height: 100vh;
// background-color: #FFF8F1;
// /* 减去底部按钮的高度 */
// z-index: 200;
// position: absolute;
// width: 100vw;
// }
/* ===== 底部完成按钮 ===== */
.bottom_complete-btn {
}
/* ===== 可滚动内容区域 ===== */
// .scrollable-content {
// height: calc(100vh);
// // height: 100vh;
// background-color: #FFF8F1;
// /* 减去底部按钮的高度 */
// z-index: 200;
// position: absolute;
// width: 100vw;
// }
/* ===== 底部完成按钮 ===== */
.bottom_complete-btn {
// padding-top: 20rpx;
position: fixed;
bottom: 0rpx;
......@@ -3805,10 +3940,10 @@ onShareTimeline(() => {
height: 94rpx;
display: block;
}
}
}
/* ===== 广告横幅 ===== */
.banner-swiper {
/* ===== 广告横幅 ===== */
.banner-swiper {
position: relative;
top: 0;
left: 16rpx;
......@@ -3820,10 +3955,10 @@ onShareTimeline(() => {
height: 100%;
border-radius: 16rpx;
}
}
}
/* ===== 喂养时间区域 ===== */
.feeding-time {
/* ===== 喂养时间区域 ===== */
.feeding-time {
position: relative;
// margin-top: 174rpx;
left: 0;
......@@ -3908,10 +4043,10 @@ onShareTimeline(() => {
margin-top: 10rpx;
}
}
}
}
/* ===== 喂养记录链接 ===== */
.feeding-records {
/* ===== 喂养记录链接 ===== */
.feeding-records {
position: relative;
// margin-top: 270rpx;
left: 0;
......@@ -3937,12 +4072,12 @@ onShareTimeline(() => {
width: 11rpx;
height: 19rpx;
}
}
}
/* ===== 喂养类型选择 ===== */
.feeding-types {
/* ===== 喂养类型选择 ===== */
.feeding-types {
position: relative;
// margin-top: 320rpx;
left: 0;
......@@ -4007,10 +4142,10 @@ onShareTimeline(() => {
}
}
}
}
}
/* ===== 温馨提示 ===== */
.warm-tip {
/* ===== 温馨提示 ===== */
.warm-tip {
position: relative;
// margin-top: 20rpx;
left: 0;
......@@ -4023,10 +4158,10 @@ onShareTimeline(() => {
font-size: 24rpx;
color: #000;
}
}
}
/* ===== 表单区域 ===== */
.form-section {
/* ===== 表单区域 ===== */
.form-section {
position: absolute;
top: 80rpx;
left: 0;
......@@ -4036,10 +4171,10 @@ onShareTimeline(() => {
background-color: #fff;
// height: 300rpx;
z-index: 2;
}
}
/* ===== 母乳亲喂表单 ===== */
.breastfeeding-form {
/* ===== 母乳亲喂表单 ===== */
.breastfeeding-form {
.duration-controls {
display: flex;
......@@ -4124,10 +4259,10 @@ onShareTimeline(() => {
}
}
}
}
}
/* ===== 母乳瓶喂/奶粉喂养表单 ===== */
.bottle-form {
/* ===== 母乳瓶喂/奶粉喂养表单 ===== */
.bottle-form {
.bottle-graphic {
width: 100%;
height: 574rpx;
......@@ -4234,10 +4369,10 @@ onShareTimeline(() => {
}
}
}
}
/* ===== 辅食表单 ===== */
.food-form {
/* ===== 辅食表单 ===== */
.food-form {
margin-top: -80rpx;
.selected-items {
......@@ -4451,14 +4586,14 @@ onShareTimeline(() => {
}
}
}
}
}
/* ===== 添加辅食弹窗 ===== */
.add-food-popup-container {
/* ===== 添加辅食弹窗 ===== */
.add-food-popup-container {
z-index: 10003 !important;
}
}
.add-food-popup {
.add-food-popup {
background: white;
border-radius: 40rpx;
width: 654rpx;
......@@ -4531,12 +4666,12 @@ onShareTimeline(() => {
}
}
}
}
}
/* ===== 记录成功弹窗 ===== */
.success-popup {
/* ===== 记录成功弹窗 ===== */
.success-popup {
position: relative;
width: 654rpx;
height: 436rpx;
......@@ -4588,10 +4723,10 @@ onShareTimeline(() => {
}
}
}
}
/* ===== 记录方式选择 ===== */
.record-methods1 {
/* ===== 记录方式选择 ===== */
.record-methods1 {
position: absolute;
top: 570rpx;
left: 0;
......@@ -4625,10 +4760,10 @@ onShareTimeline(() => {
.right {
left: calc(50% + 78rpx);
}
}
}
/* ===== 记录方式选择 - 母乳瓶喂/奶粉喂养 ===== */
.record-methods2 {
/* ===== 记录方式选择 - 母乳瓶喂/奶粉喂养 ===== */
.record-methods2 {
position: absolute;
top: 570rpx;
left: 0;
......@@ -4680,10 +4815,10 @@ onShareTimeline(() => {
font-weight: bold;
}
}
}
}
/* ===== 语音控制区域 ===== */
.voice-controls {
/* ===== 语音控制区域 ===== */
.voice-controls {
position: absolute;
left: 0;
right: 0;
......@@ -4741,10 +4876,10 @@ onShareTimeline(() => {
color: #6f6d67;
}
}
}
}
/* ===== 计时器控制区域 ===== */
.timer-controls {
/* ===== 计时器控制区域 ===== */
.timer-controls {
position: absolute;
left: 0;
right: 0;
......@@ -4808,13 +4943,13 @@ onShareTimeline(() => {
}
}
}
}
}
/* ===== 下半部分背景区域 ===== */
.bottom-section {
/* ===== 下半部分背景区域 ===== */
.bottom-section {
position: relative;
left: 0;
right: 0;
......@@ -4834,37 +4969,37 @@ onShareTimeline(() => {
}
}
// uni-datetime-picker样式覆盖(与feedingRecord页面保持一致)
::v-deep .uni-datetime-picker--btn {
// uni-datetime-picker样式覆盖(与feedingRecord页面保持一致)
::v-deep .uni-datetime-picker--btn {
background-color: #D4A574 !important;
}
}
::v-deep .uni-calendar-item--checked {
::v-deep .uni-calendar-item--checked {
background-color: #D4A574 !important;
}
}
::v-deep .uni-datetime-picker-btn-text {
::v-deep .uni-datetime-picker-btn-text {
color: #D4A574 !important;
}
}
/* 全局时间选择器层级修复 */
::v-deep .uni-datetime-picker {
/* 全局时间选择器层级修复 */
::v-deep .uni-datetime-picker {
z-index: 999999 !important;
}
}
::v-deep .uni-datetime-picker__mask {
::v-deep .uni-datetime-picker__mask {
z-index: 999998 !important;
position: fixed !important;
top: 0 !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
}
}
::v-deep .uni-datetime-picker__popup {
::v-deep .uni-datetime-picker__popup {
z-index: 999999 !important;
position: fixed !important;
bottom: 218rpx !important;
......@@ -4874,66 +5009,66 @@ onShareTimeline(() => {
padding: 30px !important;
width: 270px !important;
background-color: #fff !important;
}
}
::v-deep .uni-datetime-picker__content {
::v-deep .uni-datetime-picker__content {
z-index: 999999 !important;
position: relative !important;
}
}
/* 确保时间选择器内部元素也有正确的层级 */
::v-deep .uni-datetime-picker__container {
/* 确保时间选择器内部元素也有正确的层级 */
::v-deep .uni-datetime-picker__container {
z-index: 999999 !important;
position: relative !important;
}
}
::v-deep .uni-datetime-picker__timebox {
::v-deep .uni-datetime-picker__timebox {
z-index: 999999 !important;
position: relative !important;
}
}
::v-deep .uni-datetime-picker__date {
::v-deep .uni-datetime-picker__date {
z-index: 999999 !important;
position: relative !important;
}
}
::v-deep .uni-datetime-picker__time {
::v-deep .uni-datetime-picker__time {
z-index: 999999 !important;
position: relative !important;
}
}
/* 修复时间选择器文本显示位置 */
::v-deep .uni-datetime-picker-text {
/* 修复时间选择器文本显示位置 */
::v-deep .uni-datetime-picker-text {
position: relative !important;
display: inline-block !important;
line-height: 50px !important;
font-size: 14px !important;
text-align: center !important;
vertical-align: middle !important;
}
}
/* 修复时间选择器内部布局 */
::v-deep .uni-datetime-picker__container-box {
/* 修复时间选择器内部布局 */
::v-deep .uni-datetime-picker__container-box {
position: relative !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
margin-top: 40px !important;
}
}
::v-deep .uni-datetime-picker-item {
::v-deep .uni-datetime-picker-item {
display: flex !important;
align-items: center !important;
justify-content: center !important;
height: 50px !important;
}
}
::v-deep .uni-datetime-picker-view {
::v-deep .uni-datetime-picker-view {
height: 150px !important;
}
}
/* ===== 语音识别结果弹窗 ===== */
.popup-mask {
/* ===== 语音识别结果弹窗 ===== */
.popup-mask {
position: fixed;
top: 0;
left: 0;
......@@ -4947,11 +5082,11 @@ onShareTimeline(() => {
overflow: hidden;
touch-action: none;
/* 为固定按钮留出空间 */
}
}
.popup-content {
.popup-content {
background: #f6f8fa;
width: 750rpx;
max-height: 80vh;
......@@ -5156,9 +5291,9 @@ onShareTimeline(() => {
padding-top: 20rpx !important;
border-top: 1rpx solid #e5e5e5 !important;
}
}
}
@keyframes slideUp {
@keyframes slideUp {
from {
transform: translateY(100%);
}
......@@ -5166,10 +5301,10 @@ onShareTimeline(() => {
to {
transform: translateY(0);
}
}
}
// 语音模式提示样式
.voice-mode-tip {
// 语音模式提示样式
.voice-mode-tip {
position: absolute;
top: -60rpx;
left: 50%;
......@@ -5181,15 +5316,15 @@ onShareTimeline(() => {
font-size: 24rpx;
white-space: nowrap;
z-index: 10;
}
}
.food-input::placeholder {
.food-input::placeholder {
color: #bbb;
line-height: 70rpx;
/* 或 110rpx,和上面保持一致 */
}
}
.uni-date {
.uni-date {
z-index: 999999 !important;
}
}
</style>
\ No newline at end of file
......@@ -114,7 +114,9 @@
</view>
<!-- 提示弹窗 -->
<popup-tip v-if="isTip" type="2" @statusChange="onBabyChange" @close="isTip = false"></popup-tip>
<popup-tip v-if="isTip" type="2" @statusChange="onBabyChange" @afterPhone="isShowRegisterLayer = true"
:isNotLogin="isNotLogin" @close="isTip = false"></popup-tip>
<RegisterLayer v-model="isShowRegisterLayer" @confirm="onRegisterConfirm" />
<!-- 使用封装后的日期选择器组件 -->
<DatePicker v-model:visible="visible" :default-date="time" @confirm="handleDateConfirm" />
......@@ -151,6 +153,7 @@ import {
} from '../../api/obstetric.js';
// 导入日期选择器组件
import DatePicker from '@/components/DatePicker.vue'
import RegisterLayer from '@/components/RegisterLayer.vue'
const {
proxy
} = getCurrentInstance();
......@@ -169,6 +172,8 @@ const isWxNotification = ref(true)
// 提示弹窗
const isTip = ref(false)
const isNotLogin = ref(false);
const isShowRegisterLayer = ref(false)
// 弹窗控制
const showPicker = ref(false)
......@@ -563,8 +568,19 @@ const onBabyChange = () => {
publicFn()
}
// 公共函数
const publicFn = () => {
console.log("🚀 ~ onShow ~ userStore:", userStore.babyInfo)
const publicFn =async () => {
await userStore.loadUserInfo()
console.log("🚀 ~ onShow ~ userStore:", userStore.userInfo)
isNotLogin.value = false;
if (
userStore?.userInfo?.memberId &&
userStore?.userInfo?.memberId == "not_login" || !userStore.userInfo
) {
isNotLogin.value = true;
}
const babyInfo = userStore.babyInfo
if (babyInfo && babyInfo.babyStage == 1) {
isTip.value = false
......@@ -578,6 +594,11 @@ const publicFn = () => {
isTip.value = true
}
}
const onRegisterConfirm = async () => {
isShowRegisterLayer.value = false;
await userStore.loadBabyInfo()
publicFn()
}
onShow(async () => {
await userStore.loadBabyInfo()
console.log('宝宝信息加载完成:', userStore.babyInfo)
......
......@@ -307,7 +307,7 @@
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ref, onMounted, getCurrentInstance } from 'vue'
import { onLoad, onShareAppMessage } from "@dcloudio/uni-app";
import { useShengzhangStore } from '../../stores/shengzhangResult.js';
import { formatDate, jump, JumpType } from '../../utils/index.js';
......@@ -320,7 +320,8 @@ import md from '../../md';
const isRecords = ref(false);
const shareText = ref('')
const { proxy } = getCurrentInstance();
const $baseUrl = proxy.$baseUrl;
onLoad((options) => {
isRecords.value = options.isRecords;
// activeTab.value = isRecords.value ? 'history' : 'latest';
......@@ -699,9 +700,9 @@ const backFailHandler = () => {
onShareAppMessage(() => {
return {
title: shareText.value,
title: shareText.value || "生长测评:精准评估宝宝发育水平",
path: `/pages/shengzhangTestResult/shengzhangTestResult`,
imageUrl: ''
imageUrl: $baseUrl + "share/shengzhang.png",
}
})
......@@ -713,6 +714,15 @@ onMounted(async () => {
xcxPage: "测评结果页",
pageName: "测评结果页"
});
const userStore = useUserStore();
console.log(userStore.babyInfo?.content?.id+'--------------------',shengzhangStore?.getGrowthCurveDataInfoHeight?.userDataPoints)
if(!userStore.babyInfo?.content?.id || !shengzhangStore?.getGrowthCurveDataInfoHeight?.userDataPoints){
jump({
type: JumpType.INNER,
url: "/pages/shengzhangTools/shengzhangTools"
})
return;
}
//获取历史记录
const historyListData = await getGrowthHistoryList();
......@@ -761,7 +771,7 @@ onMounted(async () => {
}
}
const userStore = useUserStore();
const babyId = userStore.babyInfo?.content?.id;
const babyDataHeight = {
......
......@@ -802,6 +802,7 @@ const babyRefresh = async () => {
const userStore = useUserStore();
const babyInfo = userStore.babyInfo;
isNotLogin.value = false;
isTip.value = false
if (
userStore?.userInfo?.memberId &&
userStore?.userInfo?.memberId == "not_login" || !userStore.userInfo
......@@ -809,7 +810,7 @@ const babyRefresh = async () => {
isNotLogin.value = true;
}
console.log(babyInfo?.babyStage+'--------------------',babyInfo)
if (babyInfo && babyInfo.babyStage == 2) {
isTip.value = false
await refreshBabyInfo();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment