pet/pages/pets/add-pet.vue

597 lines
12 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-pet-container page-container-with-bg">
<!-- 页面标题 -->
<view class="page-header">
<view class="header-title">
<text class="title-icon">🐾</text>
<text class="title-text">添加新宠物</text>
</view>
<text class="header-subtitle">为您的爱宠建立专属档案</text>
</view>
<!-- 头像上传区域 -->
<view class="avatar-card card">
<view class="avatar-section">
<view class="avatar-container" @click="chooseAvatar">
<image
v-if="petForm.avatar"
:src="petForm.avatar"
class="pet-avatar"
mode="aspectFill"
/>
<view v-else class="avatar-placeholder">
<text class="avatar-icon">📷</text>
<text class="avatar-text">添加照片</text>
</view>
<view class="avatar-overlay">
<text class="overlay-icon">✏️</text>
</view>
</view>
<text class="avatar-tip">点击上传宠物照片</text>
</view>
</view>
<!-- 基本信息表单 -->
<view class="form-card card">
<view class="card-header">
<text class="card-title">基本信息</text>
</view>
<view class="form-content">
<!-- 宠物姓名 -->
<view class="input-container">
<text class="input-label">宠物姓名 <text class="required-star">*</text></text>
<input
class="input-field"
v-model="petForm.name"
placeholder="给您的宠物起个好听的名字"
maxlength="20"
/>
</view>
<!-- 品种 -->
<view class="input-container">
<text class="input-label">品种 <text class="required-star">*</text></text>
<input
class="input-field"
v-model="petForm.breed"
placeholder="如:金毛、英短、布偶猫等"
maxlength="30"
/>
</view>
<!-- 性别选择 -->
<view class="input-container">
<text class="input-label">性别 <text class="required-star">*</text></text>
<view class="gender-options">
<view
class="gender-option"
:class="{ active: petForm.gender === '公' }"
@click="petForm.gender = '公'"
>
<u-icon name="man" size="20" color="#666"></u-icon>
<text class="gender-text">公</text>
</view>
<view
class="gender-option"
:class="{ active: petForm.gender === '母' }"
@click="petForm.gender = '母'"
>
<u-icon name="woman" size="20" color="#666"></u-icon>
<text class="gender-text">母</text>
</view>
</view>
</view>
<!-- 生日 -->
<view class="input-container">
<text class="input-label">生日 <text class="required-star">*</text></text>
<view class="date-input" @click="showDatePicker = true">
<text class="date-text" :class="{ placeholder: !petForm.birthday }">
{{ petForm.birthday || '请选择宠物生日' }}
</text>
<text class="date-icon">📅</text>
</view>
</view>
<!-- 体重 -->
<view class="input-container">
<text class="input-label">体重</text>
<input
class="input-field"
v-model="petForm.weight"
placeholder="如4.5kg(可选填)"
maxlength="10"
/>
</view>
</view>
</view>
<!-- 备注信息 -->
<view class="notes-card card">
<view class="card-header">
<text class="card-title">备注信息</text>
</view>
<view class="notes-content">
<textarea
class="notes-textarea"
v-model="petForm.notes"
placeholder="记录一些特殊信息,如:性格特点、喜好、注意事项等..."
maxlength="200"
/>
<view class="char-count">
<text class="count-text">{{ petForm.notes?.length || 0 }}/200</text>
</view>
</view>
</view>
<!-- 提交按钮 -->
<view class="submit-section">
<button class="submit-btn btn-primary" @click="submitForm" :disabled="loading">
<text v-if="loading" class="loading-icon">⏳</text>
<text class="btn-text">{{ loading ? '保存中...' : '保存宠物信息' }}</text>
</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 {
loading: false,
showDatePicker: false,
selectedDate: new Date().getTime(),
petForm: {
name: '',
breed: '',
gender: '公',
birthday: '',
weight: '',
notes: '',
avatar: ''
},
rules: {
name: [
{
required: true,
message: '请输入宠物姓名',
trigger: 'blur'
}
],
breed: [
{
required: true,
message: '请输入宠物品种',
trigger: 'blur'
}
],
gender: [
{
required: true,
message: '请选择宠物性别',
trigger: 'change'
}
],
birthday: [
{
required: true,
message: '请选择宠物生日',
trigger: 'blur'
}
]
}
}
},
methods: {
chooseAvatar() {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
this.petForm.avatar = res.tempFilePaths[0]
},
fail: (err) => {
console.error('选择图片失败', err)
}
})
},
confirmDate(e) {
const date = new Date(e.value)
this.petForm.birthday = `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`
this.showDatePicker = false
},
submitForm() {
this.$refs.petFormRef.validate().then(valid => {
if (valid) {
this.savePet()
}
}).catch(errors => {
console.log('表单验证失败', errors)
})
},
savePet() {
this.loading = true
// 计算陪伴天数
const birthday = new Date(this.petForm.birthday)
const today = new Date()
const companionDays = Math.floor((today - birthday) / (1000 * 60 * 60 * 24))
// 计算年龄
const age = Math.floor(companionDays / 365)
const petData = {
...this.petForm,
id: Date.now(), // 简单的ID生成
age: age,
companionDays: companionDays,
createTime: new Date().toISOString()
}
// 模拟保存到本地存储
setTimeout(() => {
try {
let pets = uni.getStorageSync('pets') || []
pets.push(petData)
uni.setStorageSync('pets', pets)
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-pet-container {
padding-bottom: 120rpx;
}
/* 页面标题 */
.page-header {
text-align: center;
padding: 40rpx 30rpx 30rpx;
.header-title {
display: flex;
align-items: center;
justify-content: center;
gap: 12rpx;
margin-bottom: 12rpx;
.title-icon {
font-size: 36rpx;
}
.title-text {
font-size: 36rpx;
font-weight: 700;
color: white;
text-shadow: 0 2rpx 8rpx rgba(255, 138, 128, 0.3);
}
}
.header-subtitle {
font-size: 24rpx;
color: rgba(255, 255, 255, 0.9);
text-shadow: 0 1rpx 4rpx rgba(255, 138, 128, 0.2);
}
}
/* 头像卡片 */
.avatar-card {
margin: 0 30rpx 24rpx;
.avatar-section {
display: flex;
flex-direction: column;
align-items: center;
padding: 20rpx 0;
.avatar-container {
position: relative;
width: 160rpx;
height: 160rpx;
border-radius: 50%;
overflow: hidden;
margin-bottom: 16rpx;
cursor: pointer;
.pet-avatar {
width: 100%;
height: 100%;
border-radius: 50%;
}
.avatar-placeholder {
width: 100%;
height: 100%;
background: linear-gradient(135deg, #FFE0DD, #FFF0F0);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border: 3rpx dashed rgba(255, 138, 128, 0.3);
.avatar-icon {
font-size: 48rpx;
margin-bottom: 8rpx;
opacity: 0.6;
}
.avatar-text {
font-size: 22rpx;
color: #999;
}
}
.avatar-overlay {
position: absolute;
bottom: 0;
right: 0;
width: 48rpx;
height: 48rpx;
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 12rpx rgba(255, 138, 128, 0.3);
.overlay-icon {
font-size: 20rpx;
color: white;
}
}
}
.avatar-tip {
font-size: 24rpx;
color: #666;
}
}
}
/* 表单卡片 */
.form-card, .notes-card {
margin: 0 30rpx 24rpx;
padding: 32rpx;
.card-header {
padding-bottom: 20rpx;
border-bottom: 1rpx solid rgba(255, 138, 128, 0.1);
margin-bottom: 24rpx;
.card-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
display: flex;
align-items: center;
&::before {
content: '';
width: 6rpx;
height: 24rpx;
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
border-radius: 3rpx;
margin-right: 12rpx;
}
}
}
.form-content {
.input-container {
margin-bottom: 36rpx;
&:last-child {
margin-bottom: 0;
}
.input-label {
display: block;
font-size: 28rpx;
color: #333;
margin-bottom: 12rpx;
font-weight: 600;
.required-star {
color: #FF8A80;
font-weight: 600;
}
}
.input-field {
width: 100%;
height: 88rpx;
padding: 0 24rpx;
border: 2rpx solid rgba(255, 138, 128, 0.2);
border-radius: 16rpx;
background: rgba(255, 255, 255, 0.9);
font-size: 28rpx;
color: #333;
transition: all 0.3s ease;
box-sizing: border-box;
line-height: 84rpx;
&:focus {
border-color: #FF8A80;
background: rgba(255, 255, 255, 1);
box-shadow: 0 0 0 4rpx rgba(255, 138, 128, 0.1);
}
&::placeholder {
color: #999;
}
}
}
}
}
/* 性别选择 */
.gender-options {
display: flex;
gap: 16rpx;
.gender-option {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 8rpx;
height: 88rpx;
border: 2rpx solid rgba(255, 138, 128, 0.2);
border-radius: 16rpx;
background: rgba(255, 255, 255, 0.9);
transition: all 0.3s ease;
cursor: pointer;
box-sizing: border-box;
&.active {
border-color: #FF8A80;
background: linear-gradient(135deg, #FF8A80, #FFB6C1);
.gender-text {
color: white;
font-weight: 600;
}
:deep(.u-icon) {
color: white !important;
}
}
.gender-text {
font-size: 28rpx;
color: #333;
}
}
}
/* 日期输入 */
.date-input {
display: flex;
align-items: center;
justify-content: space-between;
height: 88rpx;
padding: 0 24rpx;
border: 2rpx solid rgba(255, 138, 128, 0.2);
border-radius: 16rpx;
background: rgba(255, 255, 255, 0.9);
cursor: pointer;
box-sizing: border-box;
.date-text {
font-size: 28rpx;
color: #333;
&.placeholder {
color: #999;
}
}
.date-icon {
font-size: 24rpx;
opacity: 0.6;
}
}
/* 备注区域 */
.notes-content {
.notes-textarea {
width: 100%;
min-height: 200rpx;
padding: 24rpx;
border: 2rpx solid rgba(255, 138, 128, 0.2);
border-radius: 16rpx;
background: rgba(255, 255, 255, 0.9);
font-size: 28rpx;
color: #333;
line-height: 1.6;
resize: none;
box-sizing: border-box;
&:focus {
border-color: #FF8A80;
background: rgba(255, 255, 255, 1);
box-shadow: 0 0 0 4rpx rgba(255, 138, 128, 0.1);
}
&::placeholder {
color: #999;
}
}
.char-count {
text-align: right;
margin-top: 8rpx;
.count-text {
font-size: 22rpx;
color: #999;
}
}
}
/* 提交区域 */
.submit-section {
padding: 40rpx 30rpx;
.submit-btn {
width: 100%;
padding: 24rpx;
border-radius: 28rpx;
font-size: 32rpx;
font-weight: 600;
border: none;
display: flex;
align-items: center;
justify-content: center;
gap: 12rpx;
&:disabled {
opacity: 0.7;
}
.loading-icon {
font-size: 28rpx;
}
.btn-text {
color: white;
}
}
}
</style>