673 lines
16 KiB
Vue
673 lines
16 KiB
Vue
<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>
|