pet/pages/pets/add-record-form.vue

673 lines
16 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="add-record-container page-container-with-bg">
<!-- 表单内容 -->
<view class="form-content">
<!-- 第一组基础信息 -->
<view class="form-group">
<!-- 记录宠物 -->
<view class="form-item" @click="selectPet">
<view class="form-label">记录宠物</view>
<view class="form-value">
<text class="value-text">{{ petInfo.name || '选择宠物' }}</text>
<u-icon name="arrow-right" size="14" color="#c0c4cc"></u-icon>
</view>
</view>
<view class="form-divider"></view>
<!-- 记录时间 -->
<view class="form-item" @click="showDatePicker = true">
<view class="form-label">记录时间</view>
<view class="form-value">
<text class="value-text">{{ recordForm.recordTime || '选择时间' }}</text>
<u-icon name="arrow-right" size="14" color="#c0c4cc"></u-icon>
</view>
</view>
</view>
<!-- 第二组记录详情 -->
<view class="form-group">
<!-- 记录类型 -->
<view class="form-item" @click="selectRecordType">
<view class="form-label">记录类型</view>
<view class="form-value">
<text class="value-text">{{ getTypeName(recordType) || '选择记录类型' }}</text>
<u-icon name="arrow-right" size="14" color="#c0c4cc"></u-icon>
</view>
</view>
<!-- 动态表单项 -->
<template v-if="recordType === 'weight'">
<view class="form-divider"></view>
<view class="form-item">
<view class="form-label">体重</view>
<view class="form-input">
<input
v-model="recordForm.weight"
placeholder="填写体重"
type="digit"
class="input-field"
/>
<text class="unit">kg</text>
</view>
</view>
</template>
<template v-if="recordType === 'food'">
<view class="form-divider"></view>
<view class="form-item">
<view class="form-label">食物类型</view>
<view class="form-input">
<input
v-model="recordForm.foodType"
placeholder="填写食物类型"
class="input-field"
/>
</view>
</view>
<view class="form-divider"></view>
<view class="form-item">
<view class="form-label">食量</view>
<view class="form-input">
<input
v-model="recordForm.amount"
placeholder="填写食量"
type="digit"
class="input-field"
/>
<text class="unit">g</text>
</view>
</view>
</template>
<template v-if="recordType === 'water'">
<view class="form-divider"></view>
<view class="form-item">
<view class="form-label">饮水量</view>
<view class="form-input">
<input
v-model="recordForm.waterAmount"
placeholder="填写饮水量"
type="digit"
class="input-field"
/>
<text class="unit">ml</text>
</view>
</view>
</template>
<template v-if="recordType === 'medicine'">
<view class="form-divider"></view>
<view class="form-item">
<view class="form-label">药物名称</view>
<view class="form-input">
<input
v-model="recordForm.medicineName"
placeholder="填写药物名称"
class="input-field"
/>
</view>
</view>
<view class="form-divider"></view>
<view class="form-item">
<view class="form-label">剂量</view>
<view class="form-input">
<input
v-model="recordForm.dosage"
placeholder="填写剂量"
class="input-field"
/>
</view>
</view>
</template>
</view>
<!-- 第三组:描述和媒体 -->
<view class="form-group description-group">
<view class="form-label">描述</view>
<view class="description-input">
<textarea
v-model="recordForm.content"
placeholder="请输入你想要记录的内容~"
class="textarea-field"
maxlength="500"
></textarea>
</view>
<!-- 媒体上传按钮 -->
<view class="media-upload">
<view class="media-item" @click="chooseImage">
<u-icon name="camera" size="24" color="#999"></u-icon>
</view>
<view class="media-item" @click="chooseVideo">
<u-icon name="play-circle" size="24" color="#999"></u-icon>
</view>
</view>
</view>
<!-- 第四组:分享设置 -->
<view class="form-group privacy-group">
<view class="privacy-item" @click="setShareLevel('public')">
<view class="radio-icon" :class="{ active: recordForm.shareLevel === 'public' }">
<view class="radio-inner" v-if="recordForm.shareLevel === 'public'"></view>
</view>
<text class="privacy-text">公开</text>
</view>
<view class="privacy-item" @click="setShareLevel('family')">
<view class="radio-icon" :class="{ active: recordForm.shareLevel === 'family' }">
<view class="radio-inner" v-if="recordForm.shareLevel === 'family'"></view>
</view>
<text class="privacy-text">家人可见</text>
</view>
<view class="privacy-item" @click="setShareLevel('private')">
<view class="radio-icon" :class="{ active: recordForm.shareLevel === 'private' }">
<view class="radio-inner" v-if="recordForm.shareLevel === 'private'"></view>
</view>
<text class="privacy-text">仅自己可见</text>
</view>
<text class="privacy-desc">{{ getShareLevelDesc() }}</text>
</view>
</view>
<!-- 保存按钮 -->
<view class="save-button-container">
<button class="save-button" @click="saveRecord">保存</button>
</view>
<!-- 日期时间选择器 -->
<u-datetime-picker
ref="datetimePicker"
v-model="showDatePicker"
mode="datetime"
@confirm="confirmDateTime"
@cancel="showDatePicker = false"
></u-datetime-picker>
</view>
</template>
<script>
export default {
data() {
return {
petId: '',
recordType: '',
showDatePicker: false,
petInfo: {},
recordForm: {
petId: '',
recordTime: '',
content: '',
photos: [],
videos: [],
shareLevel: 'family', // public, family, private
// 动态字段
weight: '',
foodType: '',
amount: '',
waterAmount: '',
toiletType: 'urine',
medicineName: '',
dosage: ''
},
typeNames: {
'daily-note': '随手记',
'milestone': '大事记',
'weight': '体重记录',
'toilet': '尿便记录',
'food': '饮食记录',
'water': '饮水记录',
'exercise': '运动记录',
'supplement': '保健品记录',
'abnormal': '异常记录',
'deworming': '驱虫记录',
'vaccine': '疫苗记录',
'antiparasitic': '抗体水平',
'checkup': '体检记录',
'illness': '看病记录',
'medicine': '用药记录',
'hospital': '住院记录',
'surgery': '手术记录',
'bath': '洗澡记录',
'nail-trim': '剪指甲',
'ear-clean': '洗耳朵',
'teeth-clean': '刷牙记录',
'hair-trim': '梳毛记录',
'hair-cut': '剃毛记录',
'beauty': '美容记录',
'anal-gland': '挤肛门腺',
'eye-clean': '擦眼屎',
'disinfect': '消毒记录',
'clean': '清洁记录',
'change-sand': '换猫砂',
'wash-litter': '洗猫砂盆',
'wash-food-bowl': '洗食盆',
'wash-water-bowl': '洗水盆',
'wash-toy': '洗玩具',
'wash-cage': '洗笼子',
'change-filter': '换滤芯',
'change-pad': '换干燥剂'
}
}
},
onLoad(options) {
this.petId = options.petId || '1'
this.recordType = options.type || 'daily-note'
this.recordForm.petId = this.petId
// 加载宠物信息
this.loadPetInfo()
// 设置默认时间为当前时间
const now = new Date()
this.recordForm.recordTime = this.formatDateTime(now)
},
methods: {
loadPetInfo() {
try {
const pets = uni.getStorageSync('pets') || []
this.petInfo = pets.find(pet => pet.id == this.petId) || { name: '未知宠物' }
} catch (error) {
console.error('加载宠物信息失败', error)
this.petInfo = { name: '未知宠物' }
}
},
getTypeName(type) {
return this.typeNames[type] || ''
},
selectPet() {
// 选择宠物功能
uni.showToast({
title: '选择宠物功能开发中',
icon: 'none'
})
},
selectRecordType() {
// 返回类型选择页面
uni.navigateBack()
},
formatDateTime(date) {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
return `${year}.${month}.${day} ${hours}:${minutes}`
},
confirmDateTime(e) {
this.recordForm.recordTime = this.formatDateTime(new Date(e.value))
this.showDatePicker = false
},
chooseImage() {
uni.chooseImage({
count: 9 - this.recordForm.photos.length,
sizeType: ['compressed'],
sourceType: ['camera', 'album'],
success: (res) => {
this.recordForm.photos.push(...res.tempFilePaths)
}
})
},
chooseVideo() {
uni.chooseVideo({
count: 1,
sourceType: ['camera', 'album'],
success: (res) => {
this.recordForm.videos.push(res.tempFilePath)
}
})
},
setShareLevel(level) {
this.recordForm.shareLevel = level
},
getShareLevelDesc() {
const descriptions = {
'public': '所有用户都可以看到这条记录',
'family': '仅家庭成员可以看到这条记录',
'private': '设置为仅自己可见后,本条记录对其家庭成员和朋友圈隐藏'
}
return descriptions[this.recordForm.shareLevel] || descriptions['family']
},
async saveRecord() {
// 简单验证
if (!this.recordForm.recordTime) {
uni.showToast({
title: '请选择记录时间',
icon: 'none'
})
return
}
if (!this.recordForm.content && !this.hasTypeSpecificData()) {
uni.showToast({
title: '请填写记录内容',
icon: 'none'
})
return
}
try {
// 构建记录数据
const recordData = {
id: Date.now(),
petId: this.recordForm.petId,
type: this.recordType,
recordTime: this.recordForm.recordTime,
content: this.recordForm.content,
photos: this.recordForm.photos,
videos: this.recordForm.videos,
shareLevel: this.recordForm.shareLevel,
createTime: new Date().toISOString(),
...this.getTypeSpecificData()
}
// 保存到本地存储
let records = uni.getStorageSync('petRecords') || []
records.unshift(recordData)
uni.setStorageSync('petRecords', records)
console.log('保存记录:', recordData)
uni.showToast({
title: '保存成功',
icon: 'success'
})
setTimeout(() => {
uni.navigateBack({
delta: 2 // 返回到宠物详情页
})
}, 1500)
} catch (error) {
console.error('保存记录失败:', error)
uni.showToast({
title: '保存失败',
icon: 'error'
})
}
},
hasTypeSpecificData() {
switch (this.recordType) {
case 'weight':
return !!this.recordForm.weight
case 'food':
return !!this.recordForm.foodType || !!this.recordForm.amount
case 'water':
return !!this.recordForm.waterAmount
case 'medicine':
return !!this.recordForm.medicineName || !!this.recordForm.dosage
default:
return false
}
},
getTypeSpecificData() {
const data = {}
switch (this.recordType) {
case 'weight':
data.weight = this.recordForm.weight
break
case 'food':
data.foodType = this.recordForm.foodType
data.amount = this.recordForm.amount
break
case 'water':
data.waterAmount = this.recordForm.waterAmount
break
case 'toilet':
data.toiletType = this.recordForm.toiletType
break
case 'medicine':
data.medicineName = this.recordForm.medicineName
data.dosage = this.recordForm.dosage
break
}
return data
}
}
}
</script>
<style lang="scss" scoped>
.add-record-container {
background: linear-gradient(135deg, #FF8A80 0%, #FFB6C1 25%, #FECFEF 50%, #F8BBD9 100%);
min-height: 100vh;
padding-bottom: 120rpx;
}
.form-content {
padding: 30rpx;
}
.form-group {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10rpx);
border-radius: 24rpx;
margin-bottom: 20rpx;
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.1);
overflow: hidden;
}
.form-item {
padding: 40rpx 30rpx;
display: flex;
align-items: center;
justify-content: space-between;
transition: all 0.3s ease;
&:active {
background: rgba(255, 138, 128, 0.05);
}
.form-label {
font-size: 32rpx;
color: #333333;
font-weight: 500;
}
.form-value {
display: flex;
align-items: center;
gap: 16rpx;
.value-text {
font-size: 32rpx;
color: #666666;
}
}
.form-input {
display: flex;
align-items: center;
gap: 16rpx;
flex: 1;
justify-content: flex-end;
.input-field {
text-align: right;
font-size: 32rpx;
color: #333333;
border: none;
outline: none;
background: transparent;
min-width: 200rpx;
&::placeholder {
color: #cccccc;
font-size: 32rpx;
}
}
.unit {
font-size: 32rpx;
color: #FF8A80;
font-weight: 500;
}
}
}
.form-divider {
height: 1rpx;
background: rgba(0, 0, 0, 0.05);
margin: 0 30rpx;
}
.description-group {
padding: 40rpx 30rpx;
.form-label {
font-size: 32rpx;
color: #333333;
font-weight: 500;
margin-bottom: 24rpx;
}
.description-input {
margin-bottom: 40rpx;
.textarea-field {
width: 100%;
min-height: 300rpx;
font-size: 32rpx;
color: #333333;
border: none;
outline: none;
background: transparent;
resize: none;
line-height: 1.6;
&::placeholder {
color: #cccccc;
font-size: 32rpx;
}
}
}
.media-upload {
display: flex;
gap: 40rpx;
.media-item {
width: 100rpx;
height: 100rpx;
background: rgba(255, 138, 128, 0.1);
border-radius: 20rpx;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
background: rgba(255, 138, 128, 0.2);
}
}
}
}
.privacy-group {
padding: 40rpx 30rpx;
.privacy-item {
display: flex;
align-items: center;
gap: 20rpx;
padding: 16rpx 0;
transition: all 0.3s ease;
&:active {
background: rgba(255, 138, 128, 0.05);
border-radius: 12rpx;
margin: 0 -16rpx;
padding: 16rpx;
}
.radio-icon {
width: 36rpx;
height: 36rpx;
border: 3rpx solid #ddd;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
&.active {
border-color: #FF8A80;
background: #FF8A80;
}
.radio-inner {
width: 12rpx;
height: 12rpx;
background: #ffffff;
border-radius: 50%;
}
}
.privacy-text {
font-size: 32rpx;
color: #333333;
font-weight: 500;
}
}
.privacy-desc {
font-size: 26rpx;
color: #999999;
line-height: 1.6;
margin-left: 56rpx;
margin-top: 16rpx;
padding: 20rpx;
background: rgba(255, 138, 128, 0.05);
border-radius: 12rpx;
}
}
.save-button-container {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 30rpx;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20rpx);
border-top: 1rpx solid rgba(255, 138, 128, 0.1);
.save-button {
width: 100%;
height: 96rpx;
background: linear-gradient(135deg, #FF8A80 0%, #FFB6C1 50%, #FECFEF 100%);
color: #ffffff;
font-size: 36rpx;
font-weight: 600;
border: none;
border-radius: 48rpx;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 32rpx rgba(255, 138, 128, 0.4);
transition: all 0.3s ease;
&:active {
transform: scale(0.98);
background: linear-gradient(135deg, #FF7043 0%, #FF8A65 50%, #FFAB91 100%);
box-shadow: 0 4rpx 16rpx rgba(255, 138, 128, 0.6);
}
}
}
</style>