This commit is contained in:
2025-08-14 14:24:36 +08:00
parent 4d3a62d185
commit f071de4ead
18 changed files with 774 additions and 3774 deletions
+70 -1
View File
@@ -162,7 +162,76 @@
</template>
<script>
import adoptionManager from '@/utils/adoptionManager.js'
// 简化的领养管理器 - 从 utils/adoptionManager.js 移入
const adoptionManager = {
storageKey: 'adoption_pets',
getAdoptionPets() {
try {
return uni.getStorageSync(this.storageKey) || []
} catch (error) {
console.error('获取领养宠物数据失败:', error)
return []
}
},
getPetById(id) {
const pets = this.getAdoptionPets()
return pets.find(pet => pet.id == id)
},
getPetTypeName(type) {
const types = {
cat: '猫咪',
dog: '狗狗',
rabbit: '兔子',
other: '其他'
}
return types[type] || '未知类型'
},
getPetBreedName(type, breed) {
const breeds = {
cat: {
'british-shorthair': '英国短毛猫',
'american-shorthair': '美国短毛猫',
'persian': '波斯猫',
'ragdoll': '布偶猫',
'siamese': '暹罗猫',
'mixed': '混血猫'
},
dog: {
'golden-retriever': '金毛寻回犬',
'labrador': '拉布拉多',
'husky': '哈士奇',
'corgi': '柯基',
'shiba-inu': '柴犬',
'mixed': '混血犬'
}
}
return breeds[type]?.[breed] || '未知品种'
},
getLocationName(province, city, district) {
const regions = {
'beijing': '北京市',
'shanghai': '上海市',
'guangdong': '广东省',
'jiangsu': '江苏省'
}
return regions[province] || province
},
getStatusInfo(status) {
const statusMap = {
available: { name: '可领养', color: '#4CAF50', icon: '✅' },
reserved: { name: '已预约', color: '#FF9800', icon: '⏰' },
adopted: { name: '已领养', color: '#9E9E9E', icon: '❤️' },
pending: { name: '审核中', color: '#2196F3', icon: '📋' }
}
return statusMap[status] || { name: '未知状态', color: '#999999', icon: '❓' }
}
}
export default {
data() {
+340 -1
View File
@@ -285,7 +285,346 @@
</template>
<script>
import adoptionManager from '@/utils/adoptionManager.js'
// 宠物领养数据管理工具类 - 从 utils/adoptionManager.js 移入
class AdoptionManager {
constructor() {
this.storageKey = 'adoption_pets'
// 宠物类型配置
this.petTypes = {
cat: {
name: '猫咪',
icon: '🐱',
breeds: {
'british-shorthair': '英国短毛猫',
'american-shorthair': '美国短毛猫',
'persian': '波斯猫',
'ragdoll': '布偶猫',
'siamese': '暹罗猫',
'maine-coon': '缅因猫',
'scottish-fold': '苏格兰折耳猫',
'russian-blue': '俄罗斯蓝猫',
'bengal': '孟加拉猫',
'mixed': '混血猫',
'unknown': '品种不明'
}
},
dog: {
name: '狗狗',
icon: '🐶',
breeds: {
'golden-retriever': '金毛寻回犬',
'labrador': '拉布拉多',
'husky': '哈士奇',
'german-shepherd': '德国牧羊犬',
'poodle': '贵宾犬',
'chihuahua': '吉娃娃',
'bulldog': '斗牛犬',
'shiba-inu': '柴犬',
'corgi': '柯基',
'border-collie': '边境牧羊犬',
'mixed': '混血犬',
'unknown': '品种不明'
}
},
rabbit: {
name: '兔子',
icon: '🐰',
breeds: {
'holland-lop': '荷兰垂耳兔',
'mini-lop': '迷你垂耳兔',
'lionhead': '狮子头兔',
'dutch': '荷兰兔',
'angora': '安哥拉兔',
'mixed': '混血兔',
'unknown': '品种不明'
}
},
other: {
name: '其他',
icon: '🐾',
breeds: {
'hamster': '仓鼠',
'guinea-pig': '豚鼠',
'bird': '鸟类',
'turtle': '乌龟',
'fish': '鱼类',
'other': '其他'
}
}
}
// 地区数据(简化版三级联动)
this.regions = {
'beijing': {
name: '北京市',
cities: {
'beijing': {
name: '北京市',
districts: {
'chaoyang': '朝阳区',
'haidian': '海淀区',
'dongcheng': '东城区',
'xicheng': '西城区',
'fengtai': '丰台区',
'shijingshan': '石景山区'
}
}
}
},
'shanghai': {
name: '上海市',
cities: {
'shanghai': {
name: '上海市',
districts: {
'huangpu': '黄浦区',
'xuhui': '徐汇区',
'changning': '长宁区',
'jingan': '静安区',
'putuo': '普陀区',
'hongkou': '虹口区'
}
}
}
},
'guangdong': {
name: '广东省',
cities: {
'guangzhou': {
name: '广州市',
districts: {
'tianhe': '天河区',
'yuexiu': '越秀区',
'liwan': '荔湾区',
'haizhu': '海珠区',
'baiyun': '白云区',
'panyu': '番禺区'
}
},
'shenzhen': {
name: '深圳市',
districts: {
'futian': '福田区',
'luohu': '罗湖区',
'nanshan': '南山区',
'yantian': '盐田区',
'baoan': '宝安区',
'longgang': '龙岗区'
}
}
}
},
'jiangsu': {
name: '江苏省',
cities: {
'nanjing': {
name: '南京市',
districts: {
'xuanwu': '玄武区',
'qinhuai': '秦淮区',
'jianye': '建邺区',
'gulou': '鼓楼区',
'pukou': '浦口区',
'qixia': '栖霞区'
}
},
'suzhou': {
name: '苏州市',
districts: {
'gusu': '姑苏区',
'wuzhong': '吴中区',
'xiangcheng': '相城区',
'kunshan': '昆山市',
'changshu': '常熟市',
'zhangjiagang': '张家港市'
}
}
}
}
}
// 领养状态
this.adoptionStatus = {
available: { name: '可领养', color: '#4CAF50', icon: '✅' },
reserved: { name: '已预约', color: '#FF9800', icon: '⏰' },
adopted: { name: '已领养', color: '#9E9E9E', icon: '❤️' },
pending: { name: '审核中', color: '#2196F3', icon: '📋' }
}
}
// 获取所有领养宠物数据
getAdoptionPets() {
try {
let pets = uni.getStorageSync(this.storageKey) || []
// 如果没有数据,初始化一些测试数据
if (pets.length === 0) {
pets = this.initializeTestData()
uni.setStorageSync(this.storageKey, pets)
}
return pets
} catch (error) {
console.error('获取领养宠物数据失败:', error)
return this.initializeTestData()
}
}
// 初始化测试数据
initializeTestData() {
const testData = []
// 猫咪数据
testData.push({
id: Date.now() + 1,
name: '小橘',
type: 'cat',
breed: 'british-shorthair',
age: 2,
gender: 'male',
photos: ['https://images.unsplash.com/photo-1574158622682-e40e69881006?w=400&h=300&fit=crop', 'https://images.unsplash.com/photo-1592194996308-7b43878e84a6?w=400&h=300&fit=crop'],
description: '小橘是一只非常温顺的英国短毛猫,性格亲人,喜欢和人互动。已经完成绝育手术和疫苗接种,身体健康。适合有爱心的家庭领养,希望能给它一个温暖的家。',
personality: ['温顺', '亲人', '安静', '乖巧'],
health: '健康良好,已绝育,疫苗齐全',
location: {
province: 'beijing',
city: 'beijing',
district: 'chaoyang',
address: '朝阳区宠物救助中心'
},
status: 'available',
requirements: [
'有稳定收入',
'有养猫经验',
'家中无其他宠物',
'同意定期回访'
],
contact: {
name: '北京爱心救助站',
phone: '138****1234',
wechat: 'rescue_station_bj',
type: 'organization'
},
publishTime: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString()
})
// 更多测试数据...
return testData
}
// 搜索宠物
searchPets(keyword, pets = null) {
if (!pets) {
pets = this.getAdoptionPets()
}
if (!keyword) return pets
const lowerKeyword = keyword.toLowerCase()
return pets.filter(pet => {
return pet.name.toLowerCase().includes(lowerKeyword) ||
pet.description.toLowerCase().includes(lowerKeyword) ||
this.getPetTypeName(pet.type).includes(keyword) ||
this.getPetBreedName(pet.type, pet.breed).includes(keyword) ||
pet.personality.some(trait => trait.includes(keyword))
})
}
// 筛选宠物
filterPets(filters, pets = null) {
if (!pets) {
pets = this.getAdoptionPets()
}
return pets.filter(pet => {
// 宠物类型筛选
if (filters.type && pet.type !== filters.type) {
return false
}
// 品种筛选
if (filters.breed && pet.breed !== filters.breed) {
return false
}
// 地区筛选
if (filters.province && pet.location.province !== filters.province) {
return false
}
if (filters.city && pet.location.city !== filters.city) {
return false
}
if (filters.district && pet.location.district !== filters.district) {
return false
}
// 状态筛选
if (filters.status && pet.status !== filters.status) {
return false
}
// 性别筛选
if (filters.gender && pet.gender !== filters.gender) {
return false
}
// 年龄筛选
if (filters.ageRange) {
const [minAge, maxAge] = filters.ageRange
if (pet.age < minAge || pet.age > maxAge) {
return false
}
}
return true
})
}
// 获取宠物类型名称
getPetTypeName(type) {
return this.petTypes[type]?.name || '未知类型'
}
// 获取宠物品种名称
getPetBreedName(type, breed) {
return this.petTypes[type]?.breeds[breed] || '未知品种'
}
// 获取地区名称
getLocationName(province, city = null, district = null) {
let locationName = this.regions[province]?.name || province
if (city) {
const cityName = this.regions[province]?.cities[city]?.name
if (cityName) {
locationName += ' ' + cityName
}
}
if (district) {
const districtName = this.regions[province]?.cities[city]?.districts[district]
if (districtName) {
locationName += ' ' + districtName
}
}
return locationName
}
// 获取状态信息
getStatusInfo(status) {
return this.adoptionStatus[status] || {
name: '未知状态',
color: '#999999',
icon: '❓'
}
}
}
const adoptionManager = new AdoptionManager()
export default {
data() {
-52
View File
@@ -1,52 +0,0 @@
<template>
<view class="content page-container">
<image class="logo" src="/static/logo.png"></image>
<view class="text-area">
<text class="title">{{title}}</text>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: 'Hello'
}
},
onLoad() {
},
methods: {
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
</style>
-643
View File
@@ -1,643 +0,0 @@
<template>
<view class="add-record-container page-container-with-bg">
<u-navbar title="添加记录" left-icon="arrow-left" @left-click="goBack">
<template #right>
<u-text text="保存" color="#ff6b6b" @click="saveRecord"></u-text>
</template>
</u-navbar>
<u-form ref="recordFormRef" :model="recordForm" :rules="rules" label-width="80">
<!-- 记录类型选择 -->
<u-card title="记录类型" :padding="20" margin="20">
<u-radio-group v-model="recordForm.category" @change="onCategoryChange">
<view class="category-grid">
<view
class="category-item"
v-for="category in recordCategories"
:key="category.value"
@click="selectCategory(category.value)"
>
<view class="category-icon" :class="{ active: recordForm.category === category.value }">
<u-icon :name="category.icon" size="24" :color="recordForm.category === category.value ? '#ffffff' : '#666666'"></u-icon>
</view>
<u-text :text="category.label" size="12" :color="recordForm.category === category.value ? '#ff6b6b' : '#666666'"></u-text>
</view>
</view>
</u-radio-group>
</u-card>
<!-- 基础信息 -->
<u-card title="基础信息" :padding="20" margin="20">
<u-form-item label="记录时间" prop="recordTime">
<u-input
v-model="recordForm.recordTime"
placeholder="选择记录时间"
readonly
@click="showDatePicker = true"
></u-input>
</u-form-item>
<u-form-item label="记录内容" prop="content">
<u-textarea
v-model="recordForm.content"
placeholder="描述一下具体情况..."
maxlength="500"
count
></u-textarea>
</u-form-item>
</u-card>
<!-- 动态表单区域 -->
<u-card :title="currentCategoryInfo.title" :padding="20" margin="20" v-if="currentCategoryInfo.fields.length > 0">
<view v-for="field in currentCategoryInfo.fields" :key="field.key">
<!-- 数字输入 -->
<u-form-item :label="field.label" v-if="field.type === 'number'">
<u-input
v-model="recordForm.details[field.key]"
:placeholder="field.placeholder"
type="number"
>
<template #suffix v-if="field.unit">
<u-text :text="field.unit" size="14" color="#999"></u-text>
</template>
</u-input>
</u-form-item>
<!-- 选择器 -->
<u-form-item :label="field.label" v-if="field.type === 'select'">
<u-input
v-model="recordForm.details[field.key]"
:placeholder="field.placeholder"
readonly
@click="showPicker(field)"
></u-input>
</u-form-item>
<!-- 多选标签 -->
<u-form-item :label="field.label" v-if="field.type === 'tags'">
<view class="tags-container">
<u-tag
v-for="option in field.options"
:key="option.value"
:text="option.label"
:type="isTagSelected(field.key, option.value) ? 'primary' : 'info'"
size="mini"
@click="toggleTag(field.key, option.value)"
></u-tag>
</view>
</u-form-item>
<!-- 文本输入 -->
<u-form-item :label="field.label" v-if="field.type === 'text'">
<u-input
v-model="recordForm.details[field.key]"
:placeholder="field.placeholder"
></u-input>
</u-form-item>
</view>
</u-card>
<!-- 图片上传 -->
<u-card title="添加图片" :padding="20" margin="20">
<view class="photo-upload-area">
<view class="photo-grid">
<view class="photo-item" v-for="(photo, index) in recordForm.photos" :key="index">
<u-image :src="photo" width="80px" height="80px" border-radius="8px"></u-image>
<view class="photo-delete" @click="removePhoto(index)">
<u-icon name="close-circle-fill" size="16" color="#ff6b6b"></u-icon>
</view>
</view>
<view class="photo-add" @click="choosePhotos" v-if="recordForm.photos.length < 9">
<u-icon name="camera-fill" size="24" color="#cccccc"></u-icon>
<u-text text="添加图片" size="12" color="#cccccc"></u-text>
</view>
</view>
<u-text :text="`${recordForm.photos.length}/9`" size="12" color="#999" style="margin-top: 10px;"></u-text>
</view>
</u-card>
<!-- 分享设置 -->
<u-card title="分享设置" :padding="20" margin="20">
<u-radio-group v-model="recordForm.shareLevel">
<view class="share-options">
<view class="share-option" v-for="option in shareOptions" :key="option.value">
<u-radio :name="option.value" :disabled="false">
<template #icon="{ checked }">
<u-icon :name="checked ? 'checkmark-circle-fill' : 'circle'" :color="checked ? '#ff6b6b' : '#c8c9cc'" size="18"></u-icon>
</template>
</u-radio>
<view class="share-info">
<u-text :text="option.label" size="14" bold></u-text>
<u-text :text="option.desc" size="12" color="#999"></u-text>
</view>
</view>
</view>
</u-radio-group>
</u-card>
</u-form>
<!-- 日期选择器 -->
<u-datetime-picker
:show="showDatePicker"
v-model="selectedDate"
mode="datetime"
@confirm="confirmDate"
@cancel="showDatePicker = false"
></u-datetime-picker>
<!-- 选择器弹窗 -->
<u-picker
:show="showPickerModal"
:columns="pickerColumns"
@confirm="confirmPicker"
@cancel="showPickerModal = false"
></u-picker>
</view>
</template>
<script>
import { ref, reactive, computed, onMounted } from 'vue'
export default {
name: 'AddRecordEnhanced',
setup() {
// 响应式数据
const state = reactive({
petId: '',
showDatePicker: false,
showPickerModal: false,
selectedDate: new Date().getTime(),
currentPickerField: null,
pickerColumns: [],
recordForm: {
category: 'daily',
recordTime: formatDateTime(new Date()),
content: '',
details: {},
photos: [],
shareLevel: 'family'
}
})
// 记录分类配置
const recordCategories = [
{ value: 'daily', label: '随手记', icon: 'edit-pen' },
{ value: 'milestone', label: '大事记', icon: 'star' },
{ value: 'health', label: '健康记录', icon: 'heart' },
{ value: 'grooming', label: '洗护记录', icon: 'flower' },
{ value: 'cleaning', label: '清洁记录', icon: 'home' },
{ value: 'expense', label: '消费记录', icon: 'rmb-circle' }
]
// 分享选项
const shareOptions = [
{ value: 'public', label: '公开', desc: '所有用户可见' },
{ value: 'family', label: '家人', desc: '仅家庭成员可见' },
{ value: 'private', label: '私有', desc: '仅自己可见' }
]
// 记录类型字段配置
const categoryFields = {
daily: {
title: '随手记详情',
fields: []
},
milestone: {
title: '大事记详情',
fields: [
{
key: 'milestoneType',
label: '里程碑类型',
type: 'select',
placeholder: '选择里程碑类型',
options: [
{ label: '绝育', value: 'neuter' },
{ label: '第一次吃奶', value: 'first_milk' },
{ label: '第一次吃猫粮', value: 'first_food' },
{ label: '第一次用猫砂', value: 'first_litter' },
{ label: '第一次出门', value: 'first_outside' },
{ label: '生日', value: 'birthday' },
{ label: '到家纪念日', value: 'adoption_day' }
]
}
]
},
health: {
title: '健康记录详情',
fields: [
{
key: 'healthType',
label: '健康类型',
type: 'select',
placeholder: '选择健康记录类型',
options: [
{ label: '疫苗接种', value: 'vaccine' },
{ label: '驱虫', value: 'deworming' },
{ label: '体检', value: 'checkup' },
{ label: '看病', value: 'treatment' },
{ label: '给药', value: 'medication' },
{ label: '手术', value: 'surgery' }
]
},
{
key: 'weight',
label: '体重',
type: 'number',
placeholder: '输入体重',
unit: 'kg'
},
{
key: 'temperature',
label: '体温',
type: 'number',
placeholder: '输入体温',
unit: '°C'
},
{
key: 'symptoms',
label: '症状',
type: 'tags',
options: [
{ label: '食欲不振', value: 'loss_appetite' },
{ label: '精神萎靡', value: 'lethargy' },
{ label: '呕吐', value: 'vomiting' },
{ label: '腹泻', value: 'diarrhea' },
{ label: '发热', value: 'fever' },
{ label: '咳嗽', value: 'cough' }
]
}
]
},
grooming: {
title: '洗护记录详情',
fields: [
{
key: 'groomingType',
label: '洗护类型',
type: 'tags',
options: [
{ label: '洗澡', value: 'bath' },
{ label: '剪指甲', value: 'nail_trim' },
{ label: '洗耳朵', value: 'ear_clean' },
{ label: '刷牙', value: 'teeth_clean' },
{ label: '梳毛', value: 'brush' },
{ label: '美容', value: 'grooming' }
]
},
{
key: 'duration',
label: '耗时',
type: 'number',
placeholder: '输入耗时',
unit: '分钟'
}
]
},
cleaning: {
title: '清洁记录详情',
fields: [
{
key: 'cleaningType',
label: '清洁类型',
type: 'tags',
options: [
{ label: '换猫砂', value: 'litter_change' },
{ label: '洗猫砂盆', value: 'litter_box_clean' },
{ label: '洗食盆', value: 'food_bowl_clean' },
{ label: '洗水盆', value: 'water_bowl_clean' },
{ label: '清洁笼子', value: 'cage_clean' },
{ label: '消毒', value: 'disinfect' }
]
}
]
},
expense: {
title: '消费记录详情',
fields: [
{
key: 'amount',
label: '金额',
type: 'number',
placeholder: '输入消费金额',
unit: '元'
},
{
key: 'expenseType',
label: '消费类型',
type: 'select',
placeholder: '选择消费类型',
options: [
{ label: '食物', value: 'food' },
{ label: '医疗', value: 'medical' },
{ label: '用品', value: 'supplies' },
{ label: '服务', value: 'service' },
{ label: '其他', value: 'other' }
]
},
{
key: 'store',
label: '购买地点',
type: 'text',
placeholder: '输入购买地点'
}
]
}
}
// 计算属性
const currentCategoryInfo = computed(() => {
return categoryFields[state.recordForm.category] || { title: '', fields: [] }
})
// 表单验证规则
const rules = {
recordTime: [
{ required: true, message: '请选择记录时间', trigger: 'blur' }
],
content: [
{ required: true, message: '请输入记录内容', trigger: 'blur' }
]
}
// 生命周期
onMounted(() => {
initPage()
})
// 初始化页面
const initPage = () => {
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]
state.petId = currentPage.options.petId || '1'
}
// 选择记录类型
const selectCategory = (category) => {
state.recordForm.category = category
state.recordForm.details = {} // 清空详情数据
}
// 记录类型变化
const onCategoryChange = (value) => {
state.recordForm.details = {} // 清空详情数据
}
// 确认日期
const confirmDate = (e) => {
const date = new Date(e.value)
state.recordForm.recordTime = formatDateTime(date)
state.showDatePicker = false
}
// 显示选择器
const showPicker = (field) => {
state.currentPickerField = field
state.pickerColumns = [field.options.map(option => option.label)]
state.showPickerModal = true
}
// 确认选择器
const confirmPicker = (e) => {
if (state.currentPickerField) {
const selectedIndex = e.indexs[0]
const selectedOption = state.currentPickerField.options[selectedIndex]
state.recordForm.details[state.currentPickerField.key] = selectedOption.label
}
state.showPickerModal = false
}
// 标签选择
const isTagSelected = (fieldKey, value) => {
const currentValue = state.recordForm.details[fieldKey]
if (!currentValue) return false
return Array.isArray(currentValue) ? currentValue.includes(value) : currentValue === value
}
const toggleTag = (fieldKey, value) => {
if (!state.recordForm.details[fieldKey]) {
state.recordForm.details[fieldKey] = []
}
const currentValue = state.recordForm.details[fieldKey]
if (Array.isArray(currentValue)) {
const index = currentValue.indexOf(value)
if (index > -1) {
currentValue.splice(index, 1)
} else {
currentValue.push(value)
}
} else {
state.recordForm.details[fieldKey] = [value]
}
}
// 选择图片
const choosePhotos = () => {
const remainingCount = 9 - state.recordForm.photos.length
uni.chooseImage({
count: remainingCount,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
state.recordForm.photos.push(...res.tempFilePaths)
},
fail: (err) => {
console.error('选择图片失败', err)
uni.showToast({
title: '选择图片失败',
icon: 'error'
})
}
})
}
// 删除图片
const removePhoto = (index) => {
state.recordForm.photos.splice(index, 1)
}
// 保存记录
const saveRecord = () => {
// 表单验证
if (!state.recordForm.recordTime) {
uni.showToast({
title: '请选择记录时间',
icon: 'error'
})
return
}
if (!state.recordForm.content.trim()) {
uni.showToast({
title: '请输入记录内容',
icon: 'error'
})
return
}
// 构建记录数据
const recordData = {
id: Date.now().toString(),
petId: state.petId,
category: state.recordForm.category,
recordTime: state.recordForm.recordTime,
content: state.recordForm.content,
details: state.recordForm.details,
photos: state.recordForm.photos,
shareLevel: state.recordForm.shareLevel,
createTime: new Date().toISOString()
}
// 模拟保存到本地存储
try {
let records = uni.getStorageSync('petRecords') || []
records.unshift(recordData)
uni.setStorageSync('petRecords', records)
uni.showToast({
title: '保存成功',
icon: 'success'
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
} catch (error) {
console.error('保存记录失败', error)
uni.showToast({
title: '保存失败',
icon: 'error'
})
}
}
// 返回上一页
const goBack = () => {
uni.navigateBack()
}
return {
...state,
recordCategories,
shareOptions,
currentCategoryInfo,
rules,
selectCategory,
onCategoryChange,
confirmDate,
showPicker,
confirmPicker,
isTagSelected,
toggleTag,
choosePhotos,
removePhoto,
saveRecord,
goBack
}
}
}
// 工具函数
function formatDateTime(date) {
const year = date.getFullYear()
const month = (date.getMonth() + 1).toString().padStart(2, '0')
const day = date.getDate().toString().padStart(2, '0')
const hours = date.getHours().toString().padStart(2, '0')
const minutes = date.getMinutes().toString().padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}`
}
</script>
<style lang="scss" scoped>
.add-record-container {
background-color: #f8f9fa;
min-height: 100vh;
}
.category-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
margin-top: 10px;
}
.category-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
cursor: pointer;
}
.category-icon {
width: 50px;
height: 50px;
border-radius: 25px;
background-color: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
&.active {
background-color: #ff6b6b;
}
}
.tags-container {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 10px;
}
.photo-upload-area {
.photo-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
}
.photo-item {
position: relative;
.photo-delete {
position: absolute;
top: -5px;
right: -5px;
background-color: #ffffff;
border-radius: 50%;
}
}
.photo-add {
width: 80px;
height: 80px;
border: 2px dashed #cccccc;
border-radius: 8px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 5px;
}
}
.share-options {
.share-option {
display: flex;
align-items: center;
gap: 15px;
padding: 15px 0;
border-bottom: 1px solid #f0f0f0;
&:last-child {
border-bottom: none;
}
.share-info {
flex: 1;
}
}
}
</style>
-340
View File
@@ -1,340 +0,0 @@
<template>
<view class="add-record-container page-container-with-bg">
<u-navbar title="添加记录" left-icon="arrow-left" @left-click="goBack" bg-color="#FF8A80">
<template #right>
<u-text text="保存" color="#ffffff" @click="saveRecord"></u-text>
</template>
</u-navbar>
<view class="content-area">
<u-form ref="recordFormRef" :model="recordForm" :rules="rules" label-width="160rpx">
<!-- 记录类型选择 -->
<u-card title="记录类型" :padding="30" margin="20" :head-style="{ fontSize: '32rpx', fontWeight: 'bold' }">
<view class="category-grid">
<view
class="category-item"
v-for="category in recordCategories"
:key="category.value"
@click="selectCategory(category.value)"
>
<view class="category-icon" :class="{ active: recordForm.category === category.value }">
<u-icon :name="category.icon" size="24" :color="recordForm.category === category.value ? '#ffffff' : '#FF8A80'"></u-icon>
</view>
<u-text :text="category.label" size="12" :color="recordForm.category === category.value ? '#FF8A80' : '#666666'" bold></u-text>
</view>
</view>
</u-card>
<!-- 基础信息 -->
<u-card title="基础信息" :padding="30" margin="20" :head-style="{ fontSize: '32rpx', fontWeight: 'bold' }">
<u-form-item label="记录时间" prop="recordTime">
<u-input
v-model="recordForm.recordTime"
placeholder="选择记录时间"
readonly
@click="showDatePicker = true"
></u-input>
</u-form-item>
<u-form-item label="记录内容" prop="content">
<u-textarea
v-model="recordForm.content"
placeholder="描述一下具体情况..."
maxlength="500"
count
></u-textarea>
</u-form-item>
</u-card>
<!-- 图片上传 -->
<u-card title="添加图片" :padding="30" margin="20" :head-style="{ fontSize: '32rpx', fontWeight: 'bold' }">
<view class="photo-upload-area">
<view class="photo-grid">
<view class="photo-item" v-for="(photo, index) in recordForm.photos" :key="index">
<u-image :src="photo" width="140rpx" height="140rpx" border-radius="12rpx"></u-image>
<view class="photo-delete" @click="removePhoto(index)">
<u-icon name="close-circle-fill" size="16" color="#FF8A80"></u-icon>
</view>
</view>
<view class="photo-add" @click="choosePhotos" v-if="recordForm.photos.length < 9">
<u-icon name="camera-fill" size="24" color="#cccccc"></u-icon>
<u-text text="添加图片" size="12" color="#cccccc"></u-text>
</view>
</view>
<u-text :text="`${recordForm.photos.length}/9`" size="12" color="#999" style="margin-top: 20rpx;"></u-text>
</view>
</u-card>
<!-- 分享设置 -->
<u-card title="分享设置" :padding="30" margin="20" :head-style="{ fontSize: '32rpx', fontWeight: 'bold' }">
<u-radio-group v-model="recordForm.shareLevel">
<view class="share-options">
<view class="share-option" v-for="option in shareOptions" :key="option.value">
<u-radio :name="option.value" :disabled="false">
<template #icon="{ checked }">
<u-icon :name="checked ? 'checkmark-circle-fill' : 'circle'" :color="checked ? '#FF8A80' : '#c8c9cc'" size="18"></u-icon>
</template>
</u-radio>
<view class="share-info">
<u-text :text="option.label" size="14" bold></u-text>
<u-text :text="option.desc" size="12" color="#999"></u-text>
</view>
</view>
</view>
</u-radio-group>
</u-card>
</u-form>
</view>
<!-- 日期选择器 -->
<u-datetime-picker
:show="showDatePicker"
v-model="selectedDate"
mode="datetime"
@confirm="confirmDate"
@cancel="showDatePicker = false"
></u-datetime-picker>
</view>
</template>
<script>
export default {
name: 'AddRecordSimple',
data() {
return {
petId: '',
showDatePicker: false,
selectedDate: new Date().getTime(),
recordForm: {
category: 'daily',
recordTime: '',
content: '',
photos: [],
shareLevel: 'family'
},
rules: {
recordTime: [
{ required: true, message: '请选择记录时间', trigger: 'blur' }
],
content: [
{ required: true, message: '请输入记录内容', trigger: 'blur' }
]
},
recordCategories: [
{ value: 'daily', label: '随手记', icon: 'edit-pen' },
{ value: 'milestone', label: '大事记', icon: 'star' },
{ value: 'health', label: '健康记录', icon: 'heart' },
{ value: 'grooming', label: '洗护记录', icon: 'flower' },
{ value: 'cleaning', label: '清洁记录', icon: 'home' },
{ value: 'expense', label: '消费记录', icon: 'rmb-circle' }
],
shareOptions: [
{ value: 'public', label: '公开', desc: '所有用户可见' },
{ value: 'family', label: '家人', desc: '仅家庭成员可见' },
{ value: 'private', label: '私有', desc: '仅自己可见' }
]
}
},
onLoad(options) {
this.petId = options.petId || '1'
this.recordForm.recordTime = this.formatDateTime(new Date())
},
methods: {
formatDateTime(date) {
const year = date.getFullYear()
const month = (date.getMonth() + 1).toString().padStart(2, '0')
const day = date.getDate().toString().padStart(2, '0')
const hours = date.getHours().toString().padStart(2, '0')
const minutes = date.getMinutes().toString().padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}`
},
selectCategory(category) {
this.recordForm.category = category
},
confirmDate(e) {
const date = new Date(e.value)
this.recordForm.recordTime = this.formatDateTime(date)
this.showDatePicker = false
},
choosePhotos() {
const remainingCount = 9 - this.recordForm.photos.length
uni.chooseImage({
count: remainingCount,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
this.recordForm.photos.push(...res.tempFilePaths)
},
fail: (err) => {
console.error('选择图片失败', err)
uni.showToast({
title: '选择图片失败',
icon: 'error'
})
}
})
},
removePhoto(index) {
this.recordForm.photos.splice(index, 1)
},
saveRecord() {
// 表单验证
if (!this.recordForm.recordTime) {
uni.showToast({
title: '请选择记录时间',
icon: 'error'
})
return
}
if (!this.recordForm.content.trim()) {
uni.showToast({
title: '请输入记录内容',
icon: 'error'
})
return
}
// 构建记录数据
const recordData = {
id: Date.now().toString(),
petId: this.petId,
category: this.recordForm.category,
recordTime: this.recordForm.recordTime,
content: this.recordForm.content,
photos: this.recordForm.photos,
shareLevel: this.recordForm.shareLevel,
createTime: new Date().toISOString()
}
// 模拟保存到本地存储
try {
let records = uni.getStorageSync('petRecords') || []
records.unshift(recordData)
uni.setStorageSync('petRecords', records)
uni.showToast({
title: '保存成功',
icon: 'success'
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
} catch (error) {
console.error('保存记录失败', error)
uni.showToast({
title: '保存失败',
icon: 'error'
})
}
},
goBack() {
uni.navigateBack()
}
}
}
</script>
<style lang="scss" scoped>
.add-record-container {
background: linear-gradient(135deg, #FF8A80 0%, #FFB6C1 25%, #FECFEF 50%, #F8BBD9 100%);
min-height: 100vh;
}
.content-area {
padding-top: 20rpx;
padding-bottom: 40rpx;
}
.category-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20rpx;
}
.category-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 12rpx;
cursor: pointer;
transition: transform 0.2s ease;
&:active {
transform: scale(0.95);
}
}
.category-icon {
width: 80rpx;
height: 80rpx;
border-radius: 40rpx;
background: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
&.active {
background: #FF8A80;
}
}
.photo-upload-area {
.photo-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 15rpx;
}
.photo-item {
position: relative;
.photo-delete {
position: absolute;
top: -8rpx;
right: -8rpx;
background-color: #ffffff;
border-radius: 50%;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
}
.photo-add {
width: 140rpx;
height: 140rpx;
border: 2rpx dashed #cccccc;
border-radius: 12rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 8rpx;
}
}
.share-options {
.share-option {
display: flex;
align-items: center;
gap: 20rpx;
padding: 20rpx 0;
border-bottom: 1rpx solid #f0f0f0;
&:last-child {
border-bottom: none;
}
.share-info {
flex: 1;
}
}
}
</style>
-244
View File
@@ -1,244 +0,0 @@
<template>
<view class="add-record-container page-container-with-bg">
<u-navbar title="添加记录" left-icon="arrow-left" @left-click="goBack"></u-navbar>
<u-form :model="recordForm" ref="recordFormRef" :rules="rules" label-width="120">
<u-card :padding="20" margin="20">
<u-form-item label="记录类型" prop="type" required>
<u-radio-group v-model="recordForm.type" placement="row">
<u-radio label="日常" name="daily"></u-radio>
<u-radio label="喂食" name="feeding"></u-radio>
<u-radio label="健康" name="health"></u-radio>
<u-radio label="其他" name="other"></u-radio>
</u-radio-group>
</u-form-item>
<u-form-item label="记录日期" prop="date" required>
<u-input v-model="recordForm.date" placeholder="请选择日期" readonly @click="showDatePicker = true"></u-input>
</u-form-item>
<u-form-item label="记录内容" prop="content" required>
<u-textarea v-model="recordForm.content" placeholder="记录宠物的状态、行为或其他信息..." maxlength="500" :count="true"></u-textarea>
</u-form-item>
<u-form-item label="添加照片" prop="photos">
<view class="photo-section">
<view class="photo-list">
<view class="photo-item" v-for="(photo, index) in recordForm.photos" :key="index">
<image :src="photo" mode="aspectFill" @click="previewImage(photo)"></image>
<u-icon name="close-circle-fill" color="#ff4757" size="16" @click="removePhoto(index)"></u-icon>
</view>
<view class="add-photo-btn" @click="choosePhotos" v-if="recordForm.photos.length < 9">
<u-icon name="camera" size="24" color="#999"></u-icon>
<text class="add-text">添加照片</text>
</view>
</view>
</view>
</u-form-item>
</u-card>
</u-form>
<view class="submit-section">
<u-button type="primary" text="保存记录" @click="submitForm" :loading="loading"></u-button>
</view>
<!-- 日期选择器 -->
<u-datetime-picker
:show="showDatePicker"
v-model="selectedDate"
mode="date"
@confirm="confirmDate"
@cancel="showDatePicker = false">
</u-datetime-picker>
</view>
</template>
<script>
export default {
data() {
return {
petId: '',
loading: false,
showDatePicker: false,
selectedDate: new Date().getTime(),
recordForm: {
type: 'daily',
date: this.formatDate(new Date()),
content: '',
photos: []
},
rules: {
type: [
{
required: true,
message: '请选择记录类型',
trigger: 'change'
}
],
date: [
{
required: true,
message: '请选择记录日期',
trigger: 'blur'
}
],
content: [
{
required: true,
message: '请输入记录内容',
trigger: 'blur'
}
]
}
}
},
onLoad(options) {
this.petId = options.petId
},
methods: {
formatDate(date) {
return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`
},
goBack() {
uni.navigateBack()
},
confirmDate(e) {
const date = new Date(e.value)
this.recordForm.date = this.formatDate(date)
this.showDatePicker = false
},
choosePhotos() {
const remainingCount = 9 - this.recordForm.photos.length
uni.chooseImage({
count: remainingCount,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
this.recordForm.photos.push(...res.tempFilePaths)
},
fail: (err) => {
console.error('选择图片失败', err)
}
})
},
removePhoto(index) {
this.recordForm.photos.splice(index, 1)
},
previewImage(src) {
uni.previewImage({
urls: this.recordForm.photos,
current: src
})
},
submitForm() {
this.$refs.recordFormRef.validate().then(valid => {
if (valid) {
this.saveRecord()
}
}).catch(errors => {
console.log('表单验证失败', errors)
})
},
saveRecord() {
this.loading = true
const recordData = {
...this.recordForm,
id: Date.now(),
petId: this.petId,
createTime: new Date().toISOString()
}
// 模拟保存到本地存储
setTimeout(() => {
try {
let records = uni.getStorageSync('petRecords') || []
records.unshift(recordData) // 最新记录在前
uni.setStorageSync('petRecords', records)
this.loading = false
uni.showToast({
title: '保存成功',
icon: 'success'
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
} catch (error) {
this.loading = false
uni.showToast({
title: '保存失败',
icon: 'error'
})
}
}, 1000)
}
}
}
</script>
<style lang="scss" scoped>
.add-record-container {
background-color: #f8f9fa;
min-height: 100vh;
}
.photo-section {
.photo-list {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
.photo-item {
position: relative;
width: 150rpx;
height: 150rpx;
image {
width: 100%;
height: 100%;
border-radius: 10rpx;
}
:deep(.u-icon) {
position: absolute;
top: -8rpx;
right: -8rpx;
}
}
.add-photo-btn {
width: 150rpx;
height: 150rpx;
border: 2rpx dashed #ddd;
border-radius: 10rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 10rpx;
.add-text {
font-size: 24rpx;
color: #999;
}
}
}
}
.submit-section {
padding: 40rpx 30rpx;
}
:deep(.u-form-item) {
margin-bottom: 30rpx;
}
</style>
+98 -2
View File
@@ -210,8 +210,104 @@
</template>
<script>
import healthManager from '@/utils/healthManager.js'
import weightManager from '@/utils/weightManager.js'
// 简化的健康管理器 - 从 utils/healthManager.js 和 weightManager.js 移入
const healthManager = {
getHealthScore(petId) {
// 简化的健康评分计算
return Math.floor(Math.random() * 20) + 80 // 80-100分
},
getHealthSummary(petId) {
return {
overall: '良好',
weight: '正常',
vaccine: '已完成',
lastCheckup: '2024-01-15'
}
}
}
const weightManager = {
storageKey: 'pet_weight_records',
getWeightRecords(petId) {
try {
const allRecords = uni.getStorageSync(this.storageKey) || {}
let records = allRecords[petId] || []
if (records.length === 0) {
records = this.initializeTestData(petId)
allRecords[petId] = records
uni.setStorageSync(this.storageKey, allRecords)
}
return records
} catch (error) {
console.error('获取体重记录失败:', error)
return this.initializeTestData(petId)
}
},
initializeTestData(petId) {
const now = new Date()
const testData = []
const baseWeight = 3.8
for (let i = 90; i >= 0; i -= 7) {
const date = new Date(now.getTime() - i * 24 * 60 * 60 * 1000)
const weight = baseWeight + (Math.random() - 0.5) * 0.3
testData.push({
id: Date.now() + i,
petId: petId,
weight: parseFloat(weight.toFixed(1)),
date: date.toISOString().split('T')[0],
note: i === 0 ? '最新记录' : ''
})
}
return testData.reverse()
},
addWeightRecord(petId, weight, date, note = '') {
try {
const allRecords = uni.getStorageSync(this.storageKey) || {}
if (!allRecords[petId]) {
allRecords[petId] = []
}
const newRecord = {
id: Date.now(),
petId: petId,
weight: parseFloat(weight),
date: date,
note: note
}
allRecords[petId].push(newRecord)
allRecords[petId].sort((a, b) => new Date(a.date) - new Date(b.date))
uni.setStorageSync(this.storageKey, allRecords)
return true
} catch (error) {
console.error('添加体重记录失败:', error)
return false
}
},
getWeightTrend(petId) {
const records = this.getWeightRecords(petId)
if (records.length < 2) return 'stable'
const recent = records.slice(-3)
const avg = recent.reduce((sum, r) => sum + r.weight, 0) / recent.length
const prev = records[records.length - 4]?.weight || avg
if (avg > prev + 0.2) return 'increasing'
if (avg < prev - 0.2) return 'decreasing'
return 'stable'
}
}
export default {
data() {
+86 -2
View File
@@ -213,7 +213,91 @@
</template>
<script>
import recordManager from '@/utils/recordManager.js'
// 记录管理器 - 从 utils/recordManager.js 移入
const recordManager = {
storageKey: 'pet_records',
getRecords(petId) {
try {
const allRecords = uni.getStorageSync(this.storageKey) || {}
let records = allRecords[petId] || []
if (records.length === 0) {
records = this.initializeTestData(petId)
allRecords[petId] = records
uni.setStorageSync(this.storageKey, allRecords)
}
return records.sort((a, b) => new Date(b.date) - new Date(a.date))
} catch (error) {
console.error('获取记录失败:', error)
return []
}
},
initializeTestData(petId) {
const now = new Date()
return [
{
id: Date.now() + 1,
petId: petId,
type: 'health',
title: '健康检查',
content: '定期健康检查,一切正常',
date: new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0],
images: [],
createTime: new Date().toISOString()
},
{
id: Date.now() + 2,
petId: petId,
type: 'feeding',
title: '喂食记录',
content: '今天食欲很好,吃完了所有的猫粮',
date: new Date(now.getTime() - 1 * 24 * 60 * 60 * 1000).toISOString().split('T')[0],
images: [],
createTime: new Date().toISOString()
}
]
},
addRecord(petId, recordData) {
try {
const allRecords = uni.getStorageSync(this.storageKey) || {}
if (!allRecords[petId]) {
allRecords[petId] = []
}
const newRecord = {
id: Date.now(),
petId: petId,
...recordData,
createTime: new Date().toISOString()
}
allRecords[petId].push(newRecord)
uni.setStorageSync(this.storageKey, allRecords)
return true
} catch (error) {
console.error('添加记录失败:', error)
return false
}
},
deleteRecord(petId, recordId) {
try {
const allRecords = uni.getStorageSync(this.storageKey) || {}
if (allRecords[petId]) {
allRecords[petId] = allRecords[petId].filter(record => record.id !== recordId)
uni.setStorageSync(this.storageKey, allRecords)
}
return true
} catch (error) {
console.error('删除记录失败:', error)
return false
}
}
}
export default {
data() {
@@ -515,7 +599,7 @@ export default {
addRecord() {
uni.navigateTo({
url: `/pages/pets/add-record?petId=${this.petId}&petName=${this.petName}`
url: `/pages/pets/select-record-type?petId=${this.petId}&petName=${this.petName}`
})
}
}
+2 -2
View File
@@ -388,14 +388,14 @@ export default {
// 添加里程碑
const addMilestone = () => {
uni.navigateTo({
url: `/pages/pets/add-record-enhanced?petId=${state.petId}&category=milestone`
url: `/pages/pets/select-record-type?petId=${state.petId}&category=milestone`
})
}
// 添加记忆
const addMemory = () => {
uni.navigateTo({
url: `/pages/pets/add-record-enhanced?petId=${state.petId}&category=daily`
url: `/pages/pets/select-record-type?petId=${state.petId}&category=daily`
})
}
+62 -1
View File
@@ -199,7 +199,68 @@
</template>
<script>
import vaccineManager from '@/utils/vaccineManager.js'
// 疫苗管理器 - 从 utils/vaccineManager.js 移入
const vaccineManager = {
storageKey: 'pet_vaccine_records',
getVaccineRecords(petId) {
try {
const allRecords = uni.getStorageSync(this.storageKey) || {}
return allRecords[petId] || []
} catch (error) {
console.error('获取疫苗记录失败:', error)
return []
}
},
addVaccineRecord(petId, vaccineData) {
try {
const allRecords = uni.getStorageSync(this.storageKey) || {}
if (!allRecords[petId]) {
allRecords[petId] = []
}
const newRecord = {
id: Date.now(),
petId: petId,
...vaccineData,
createTime: new Date().toISOString()
}
allRecords[petId].push(newRecord)
allRecords[petId].sort((a, b) => new Date(a.date) - new Date(b.date))
uni.setStorageSync(this.storageKey, allRecords)
return true
} catch (error) {
console.error('添加疫苗记录失败:', error)
return false
}
},
deleteVaccineRecord(petId, recordId) {
try {
const allRecords = uni.getStorageSync(this.storageKey) || {}
if (allRecords[petId]) {
allRecords[petId] = allRecords[petId].filter(record => record.id !== recordId)
uni.setStorageSync(this.storageKey, allRecords)
}
return true
} catch (error) {
console.error('删除疫苗记录失败:', error)
return false
}
},
getVaccineTypes() {
return [
{ value: 'rabies', label: '狂犬疫苗', required: true },
{ value: 'dhpp', label: '四联疫苗', required: true },
{ value: 'feline', label: '猫三联', required: true },
{ value: 'other', label: '其他疫苗', required: false }
]
}
}
export default {
data() {
+55 -1
View File
@@ -126,7 +126,61 @@
</template>
<script>
import weightManager from '@/utils/weightManager.js'
// 体重管理器 - 从 utils/weightManager.js 移入
const weightManager = {
storageKey: 'pet_weight_records',
getWeightRecords(petId) {
try {
const allRecords = uni.getStorageSync(this.storageKey) || {}
return allRecords[petId] || []
} catch (error) {
console.error('获取体重记录失败:', error)
return []
}
},
addWeightRecord(petId, weight, date, note = '') {
try {
const allRecords = uni.getStorageSync(this.storageKey) || {}
if (!allRecords[petId]) {
allRecords[petId] = []
}
const newRecord = {
id: Date.now(),
petId: petId,
weight: parseFloat(weight),
date: date,
note: note,
createTime: new Date().toISOString()
}
allRecords[petId].push(newRecord)
allRecords[petId].sort((a, b) => new Date(a.date) - new Date(b.date))
uni.setStorageSync(this.storageKey, allRecords)
return true
} catch (error) {
console.error('添加体重记录失败:', error)
return false
}
},
deleteWeightRecord(petId, recordId) {
try {
const allRecords = uni.getStorageSync(this.storageKey) || {}
if (allRecords[petId]) {
allRecords[petId] = allRecords[petId].filter(record => record.id !== recordId)
uni.setStorageSync(this.storageKey, allRecords)
}
return true
} catch (error) {
console.error('删除体重记录失败:', error)
return false
}
}
}
export default {
data() {
+58 -1
View File
@@ -153,7 +153,64 @@
</template>
<script>
import recordManager from '@/utils/recordManager.js'
// 记录管理器 - 从 utils/recordManager.js 移入
const recordManager = {
storageKey: 'pet_records',
getRecordById(recordId) {
try {
const allRecords = uni.getStorageSync(this.storageKey) || {}
for (const petId in allRecords) {
const record = allRecords[petId].find(r => r.id == recordId)
if (record) return record
}
return null
} catch (error) {
console.error('获取记录失败:', error)
return null
}
},
updateRecord(recordId, updateData) {
try {
const allRecords = uni.getStorageSync(this.storageKey) || {}
for (const petId in allRecords) {
const recordIndex = allRecords[petId].findIndex(r => r.id == recordId)
if (recordIndex !== -1) {
allRecords[petId][recordIndex] = {
...allRecords[petId][recordIndex],
...updateData,
updateTime: new Date().toISOString()
}
uni.setStorageSync(this.storageKey, allRecords)
return true
}
}
return false
} catch (error) {
console.error('更新记录失败:', error)
return false
}
},
deleteRecord(recordId) {
try {
const allRecords = uni.getStorageSync(this.storageKey) || {}
for (const petId in allRecords) {
const recordIndex = allRecords[petId].findIndex(r => r.id == recordId)
if (recordIndex !== -1) {
allRecords[petId].splice(recordIndex, 1)
uni.setStorageSync(this.storageKey, allRecords)
return true
}
}
return false
} catch (error) {
console.error('删除记录失败:', error)
return false
}
}
}
export default {
data() {