|
@@ -1,179 +1,198 @@
|
|
|
<template>
|
|
<template>
|
|
|
<el-dialog :model-value="visible" @update:model-value="$emit('update:visible', $event)"
|
|
<el-dialog :model-value="visible" @update:model-value="$emit('update:visible', $event)"
|
|
|
- :title="isEdit ? '编辑宠物' : '新增宠物'" width="780px" destroy-on-close append-to-body class="add-pet-dialog">
|
|
|
|
|
|
|
+ :title="isEdit ? '编辑宠物' : '新增宠物'" width="880px" destroy-on-close append-to-body class="add-pet-dialog">
|
|
|
<div class="dialog-body">
|
|
<div class="dialog-body">
|
|
|
<!-- 头像区 -->
|
|
<!-- 头像区 -->
|
|
|
<div class="avatar-section">
|
|
<div class="avatar-section">
|
|
|
<el-upload class="avatar-uploader" action="#" :show-file-list="false" :auto-upload="false"
|
|
<el-upload class="avatar-uploader" action="#" :show-file-list="false" :auto-upload="false"
|
|
|
:on-change="handleUploadFile">
|
|
:on-change="handleUploadFile">
|
|
|
- <el-avatar v-if="avatarDisplayUrl" :src="avatarDisplayUrl" :size="88" class="avatar-preview" />
|
|
|
|
|
|
|
+ <el-avatar v-if="avatarDisplayUrl" :src="avatarDisplayUrl" :size="80" class="avatar-preview" />
|
|
|
<div v-else class="avatar-placeholder">
|
|
<div v-else class="avatar-placeholder">
|
|
|
- <el-icon :size="32"><Plus /></el-icon>
|
|
|
|
|
|
|
+ <el-icon :size="28">
|
|
|
|
|
+ <Plus />
|
|
|
|
|
+ </el-icon>
|
|
|
<span>上传头像</span>
|
|
<span>上传头像</span>
|
|
|
</div>
|
|
</div>
|
|
|
</el-upload>
|
|
</el-upload>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <el-form :model="form" label-width="90px" label-position="top" class="pet-form">
|
|
|
|
|
|
|
+ <el-form :model="form" label-position="top" class="pet-form">
|
|
|
<!-- 基本信息 -->
|
|
<!-- 基本信息 -->
|
|
|
- <div class="section">
|
|
|
|
|
- <div class="section-title">基本信息</div>
|
|
|
|
|
- <el-row :gutter="24">
|
|
|
|
|
- <el-col :span="8">
|
|
|
|
|
- <el-form-item label="宠物姓名" required><el-input v-model="form.name" placeholder="请输入宠物姓名" /></el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- <el-col :span="8">
|
|
|
|
|
- <el-form-item label="所属主人" required>
|
|
|
|
|
- <el-select v-model="form.userId" placeholder="选择主人" filterable :disabled="lockedOwner">
|
|
|
|
|
- <el-option v-for="user in userOptions" :key="user.id"
|
|
|
|
|
- :label="user.name + ' - ' + (user.phone || user.phoneNumber || '')" :value="user.id" />
|
|
|
|
|
- </el-select>
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- <el-col :span="8">
|
|
|
|
|
- <el-form-item label="性别">
|
|
|
|
|
- <el-select v-model="form.gender" placeholder="请选择">
|
|
|
|
|
- <el-option v-for="dict in sys_pet_gender" :key="dict.value" :label="dict.label"
|
|
|
|
|
- :value="parseInt(dict.value)" />
|
|
|
|
|
- </el-select>
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- <el-col :span="8">
|
|
|
|
|
- <el-form-item label="品种" required>
|
|
|
|
|
- <el-input v-model="form.breed" placeholder="请输入品种" />
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- <el-col :span="8">
|
|
|
|
|
- <el-form-item label="体型" required>
|
|
|
|
|
- <el-select v-model="form.size">
|
|
|
|
|
- <el-option v-for="dict in sys_pet_size" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
|
|
- </el-select>
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- <el-col :span="4">
|
|
|
|
|
- <el-form-item label="体重(kg)" required>
|
|
|
|
|
- <el-input-number v-model="form.weight" :min="0" :precision="1" controls-position="right" />
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- <el-col :span="4">
|
|
|
|
|
- <el-form-item label="年龄(岁)" required>
|
|
|
|
|
- <el-input-number v-model="form.age" :min="0" controls-position="right" />
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- </el-row>
|
|
|
|
|
- <el-row :gutter="24">
|
|
|
|
|
- <el-col :span="12">
|
|
|
|
|
- <el-form-item label="性格关键词">
|
|
|
|
|
- <el-input v-model="form.personality" placeholder="如:活泼、粘人" />
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- <el-col :span="12">
|
|
|
|
|
- <el-form-item label="宠物标签">
|
|
|
|
|
- <el-select v-model="form.tagIds" multiple placeholder="选择标签" collapse-tags collapse-tags-tooltip>
|
|
|
|
|
- <el-option v-for="tag in allPetTags" :key="tag.id" :label="tag.name" :value="tag.id">
|
|
|
|
|
- <el-tag :type="tag.colorType || 'info'" effect="light" size="small">{{ tag.name }}</el-tag>
|
|
|
|
|
- </el-option>
|
|
|
|
|
- </el-select>
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- </el-row>
|
|
|
|
|
- <el-form-item label="萌宠性格">
|
|
|
|
|
- <el-input v-model="form.cutePersonality" type="textarea" :rows="2" placeholder="详细描述萌宠的性格特点" />
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
|
|
+ <div class="section-heading">
|
|
|
|
|
+ <span class="section-line"></span>
|
|
|
|
|
+ <span class="section-text">基本信息</span>
|
|
|
|
|
+ <span class="section-line"></span>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <el-row :gutter="20">
|
|
|
|
|
+ <el-col :span="8">
|
|
|
|
|
+ <el-form-item label="宠物姓名" required><el-input v-model="form.name" placeholder="请输入" /></el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="8">
|
|
|
|
|
+ <el-form-item label="所属主人" required>
|
|
|
|
|
+ <el-select v-model="form.userId" placeholder="选择主人" filterable :disabled="lockedOwner">
|
|
|
|
|
+ <el-option v-for="user in userOptions" :key="user.id"
|
|
|
|
|
+ :label="user.name + ' - ' + (user.phone || user.phoneNumber || '')" :value="user.id" />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="8">
|
|
|
|
|
+ <el-form-item label="性别">
|
|
|
|
|
+ <el-select v-model="form.gender" placeholder="请选择">
|
|
|
|
|
+ <el-option v-for="dict in sys_pet_gender" :key="dict.value" :label="dict.label"
|
|
|
|
|
+ :value="parseInt(dict.value)" />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="8">
|
|
|
|
|
+ <el-form-item label="品种" required><el-input v-model="form.breed" placeholder="请输入" /></el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="8">
|
|
|
|
|
+ <el-form-item label="体型" required>
|
|
|
|
|
+ <el-select v-model="form.size">
|
|
|
|
|
+ <el-option v-for="dict in sys_pet_size" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="4">
|
|
|
|
|
+ <el-form-item label="体重(kg)" required>
|
|
|
|
|
+ <el-input-number v-model="form.weight" :min="0" :precision="1" controls-position="right" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="4">
|
|
|
|
|
+ <el-form-item label="年龄" required>
|
|
|
|
|
+ <el-input-number v-model="form.age" :min="0" controls-position="right" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="12">
|
|
|
|
|
+ <el-form-item label="性格关键词">
|
|
|
|
|
+ <el-input v-model="form.personality" placeholder="如:活泼、粘人" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="12">
|
|
|
|
|
+ <el-form-item label="宠物标签">
|
|
|
|
|
+ <el-select v-model="form.tagIds" multiple placeholder="选择标签" collapse-tags collapse-tags-tooltip>
|
|
|
|
|
+ <el-option v-for="tag in allPetTags" :key="tag.id" :label="tag.name" :value="tag.id">
|
|
|
|
|
+ <el-tag :type="tag.colorType || 'info'" effect="light" size="small">{{ tag.name }}</el-tag>
|
|
|
|
|
+ </el-option>
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="24">
|
|
|
|
|
+ <el-form-item label="萌宠性格">
|
|
|
|
|
+ <el-input v-model="form.cutePersonality" type="textarea" :rows="2" placeholder="详细描述萌宠的性格特点" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ </el-row>
|
|
|
|
|
|
|
|
<!-- 家庭信息 -->
|
|
<!-- 家庭信息 -->
|
|
|
- <div class="section">
|
|
|
|
|
- <div class="section-title">家庭信息</div>
|
|
|
|
|
- <el-row :gutter="24">
|
|
|
|
|
- <el-col :span="8">
|
|
|
|
|
- <el-form-item label="新来家庭时间">
|
|
|
|
|
- <el-date-picker v-model="form.arrivalTime" type="date" placeholder="选择日期" />
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- <el-col :span="8">
|
|
|
|
|
- <el-form-item label="家庭房屋类型" required>
|
|
|
|
|
- <el-select v-model="form.houseType" placeholder="请选择">
|
|
|
|
|
- <el-option v-for="dict in sys_house_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
|
|
- </el-select>
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- <el-col :span="8">
|
|
|
|
|
- <el-form-item label="入门方式" required>
|
|
|
|
|
- <el-select v-model="form.entryMethod" placeholder="请选择">
|
|
|
|
|
- <el-option v-for="dict in sys_entry_method" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
|
|
- </el-select>
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- <el-col :span="8" v-if="form.entryMethod === 'password'">
|
|
|
|
|
- <el-form-item label="门锁密码" required>
|
|
|
|
|
- <el-input v-model="form.entryPassword" placeholder="请输入门锁密码" />
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- <el-col :span="8" v-if="form.entryMethod === 'key'">
|
|
|
|
|
- <el-form-item label="钥匙位置" required>
|
|
|
|
|
- <el-input v-model="form.keyLocation" placeholder="如:地毯下" />
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- </el-row>
|
|
|
|
|
|
|
+ <div class="section-heading">
|
|
|
|
|
+ <span class="section-line"></span>
|
|
|
|
|
+ <span class="section-text">家庭信息</span>
|
|
|
|
|
+ <span class="section-line"></span>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <el-row :gutter="20">
|
|
|
|
|
+ <el-col :span="8">
|
|
|
|
|
+ <el-form-item label="新来家庭时间">
|
|
|
|
|
+ <el-date-picker v-model="form.arrivalTime" type="date" placeholder="选择日期" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="8">
|
|
|
|
|
+ <el-form-item label="家庭房屋类型" required>
|
|
|
|
|
+ <el-select v-model="form.houseType" placeholder="请选择">
|
|
|
|
|
+ <el-option v-for="dict in sys_house_type" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="8">
|
|
|
|
|
+ <el-form-item label="入门方式">
|
|
|
|
|
+ <el-select v-model="form.entryMethod" placeholder="请选择">
|
|
|
|
|
+ <el-option v-for="dict in sys_entry_method" :key="dict.value" :label="dict.label" :value="dict.value" />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="8" v-if="form.entryMethod === 'password'">
|
|
|
|
|
+ <el-form-item label="门锁密码" required>
|
|
|
|
|
+ <el-input v-model="form.entryPassword" placeholder="请输入门锁密码" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="8" v-if="form.entryMethod === 'key'">
|
|
|
|
|
+ <el-form-item label="钥匙位置" required>
|
|
|
|
|
+ <el-input v-model="form.keyLocation" placeholder="如:地毯下" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ </el-row>
|
|
|
|
|
|
|
|
<!-- 健康状况 -->
|
|
<!-- 健康状况 -->
|
|
|
- <div class="section">
|
|
|
|
|
- <div class="section-title">健康状况</div>
|
|
|
|
|
- <el-row :gutter="24">
|
|
|
|
|
- <el-col :span="6">
|
|
|
|
|
- <el-form-item label="健康状态" required>
|
|
|
|
|
- <el-select v-model="form.healthStatus" placeholder="请选择">
|
|
|
|
|
- <el-option value="健康" label="健康" />
|
|
|
|
|
- <el-option value="亚健康" label="亚健康" />
|
|
|
|
|
- <el-option value="疾病" label="疾病" />
|
|
|
|
|
- </el-select>
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- <el-col :span="6">
|
|
|
|
|
- <el-form-item label="攻击倾向" required>
|
|
|
|
|
- <el-switch v-model="form.aggression" active-text="是" inactive-text="否"
|
|
|
|
|
- :active-value="1" :inactive-value="0" />
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- <el-col :span="6">
|
|
|
|
|
- <el-form-item label="疫苗情况" required>
|
|
|
|
|
- <el-select v-model="form.vaccineStatus" placeholder="请选择">
|
|
|
|
|
- <el-option value="无" label="无" />
|
|
|
|
|
- <el-option value="已打1次" label="已打1次" />
|
|
|
|
|
- <el-option value="已打2次" label="已打2次" />
|
|
|
|
|
- <el-option value="已打3次" label="已打3次" />
|
|
|
|
|
- </el-select>
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- <el-col :span="6">
|
|
|
|
|
- <el-form-item label="疫苗凭证">
|
|
|
|
|
- <el-upload class="cert-uploader" action="#" :show-file-list="false" :auto-upload="false"
|
|
|
|
|
- :on-change="handleUploadVaccineCert">
|
|
|
|
|
- <img v-if="vaccineCertDisplayUrl" :src="vaccineCertDisplayUrl"
|
|
|
|
|
- class="cert-preview" />
|
|
|
|
|
- <div v-else class="cert-placeholder">
|
|
|
|
|
- <el-icon><Plus /></el-icon>
|
|
|
|
|
- <span>上传</span>
|
|
|
|
|
- </div>
|
|
|
|
|
- </el-upload>
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- </el-row>
|
|
|
|
|
- <el-row :gutter="24">
|
|
|
|
|
- <el-col :span="12">
|
|
|
|
|
- <el-form-item label="既往病史" required>
|
|
|
|
|
- <el-input v-model="form.medicalHistory" type="textarea" :rows="2" placeholder="如有病史请记录" />
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- <el-col :span="12">
|
|
|
|
|
- <el-form-item label="过敏史" required>
|
|
|
|
|
- <el-input v-model="form.allergies" type="textarea" :rows="2" placeholder="如有过敏源请记录" />
|
|
|
|
|
- </el-form-item>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- </el-row>
|
|
|
|
|
|
|
+ <div class="section-heading">
|
|
|
|
|
+ <span class="section-line"></span>
|
|
|
|
|
+ <span class="section-text">健康状况</span>
|
|
|
|
|
+ <span class="section-line"></span>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <el-row :gutter="20">
|
|
|
|
|
+ <el-col :span="showVaccineCert ? 6 : 8">
|
|
|
|
|
+ <el-form-item label="健康状态" required>
|
|
|
|
|
+ <el-select v-model="form.healthStatus" placeholder="请选择">
|
|
|
|
|
+ <el-option value="健康" label="健康" />
|
|
|
|
|
+ <el-option value="亚健康" label="亚健康" />
|
|
|
|
|
+ <el-option value="疾病" label="疾病" />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="showVaccineCert ? 6 : 8">
|
|
|
|
|
+ <el-form-item label="攻击倾向" required>
|
|
|
|
|
+ <el-switch v-model="form.aggression" active-text="是" inactive-text="否" :active-value="1"
|
|
|
|
|
+ :inactive-value="0" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="showVaccineCert ? 6 : 8">
|
|
|
|
|
+ <el-form-item label="疫苗情况" required>
|
|
|
|
|
+ <el-select v-model="form.vaccineStatus" placeholder="请选择">
|
|
|
|
|
+ <el-option value="无" label="无" />
|
|
|
|
|
+ <el-option value="已打1次" label="已打1次" />
|
|
|
|
|
+ <el-option value="已打2次" label="已打2次" />
|
|
|
|
|
+ <el-option value="已打3次" label="已打3次" />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col v-if="showVaccineCert" :span="6">
|
|
|
|
|
+ <el-form-item label="疫苗凭证">
|
|
|
|
|
+ <div class="cert-row">
|
|
|
|
|
+ <div class="cert-box" :class="{ 'has-image': vaccineCertDisplayUrl }">
|
|
|
|
|
+ <el-image v-if="vaccineCertDisplayUrl" :src="vaccineCertDisplayUrl" class="cert-thumb"
|
|
|
|
|
+ :preview-src-list="[vaccineCertDisplayUrl]" fit="cover" />
|
|
|
|
|
+ <el-icon v-else :size="18" class="cert-plus-icon">
|
|
|
|
|
+ <Plus />
|
|
|
|
|
+ </el-icon>
|
|
|
|
|
+ <div v-if="!vaccineCertDisplayUrl" class="cert-upload-mask" @click="triggerVaccineCertUpload" />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <el-upload ref="vaccineCertUploadRef" style="display:none" action="#" :show-file-list="false"
|
|
|
|
|
+ :auto-upload="false" :on-change="handleUploadVaccineCert" />
|
|
|
|
|
+ <div v-if="vaccineCertDisplayUrl" class="cert-actions">
|
|
|
|
|
+ <span class="cert-action-icon cert-action-edit" @click="triggerVaccineCertUpload">
|
|
|
|
|
+ <el-icon :size="14">
|
|
|
|
|
+ <Edit />
|
|
|
|
|
+ </el-icon>
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <span class="cert-action-icon cert-action-del" @click="removeVaccineCert">
|
|
|
|
|
+ <el-icon :size="14">
|
|
|
|
|
+ <Delete />
|
|
|
|
|
+ </el-icon>
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="12">
|
|
|
|
|
+ <el-form-item label="既往病史" required>
|
|
|
|
|
+ <el-input v-model="form.medicalHistory" type="textarea" :rows="2" placeholder="如有病史请记录" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <el-col :span="12">
|
|
|
|
|
+ <el-form-item label="过敏史" required>
|
|
|
|
|
+ <el-input v-model="form.allergies" type="textarea" :rows="2" placeholder="如有过敏源请记录" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ </el-row>
|
|
|
</el-form>
|
|
</el-form>
|
|
|
</div>
|
|
</div>
|
|
|
<template #footer>
|
|
<template #footer>
|
|
@@ -186,7 +205,7 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
|
-import { ref, reactive, watch, onMounted, getCurrentInstance, toRefs } from 'vue'
|
|
|
|
|
|
|
+import { ref, reactive, watch, onMounted, getCurrentInstance, toRefs, computed } from 'vue'
|
|
|
import { ElMessage } from 'element-plus'
|
|
import { ElMessage } from 'element-plus'
|
|
|
import { globalHeaders } from '@/utils/request'
|
|
import { globalHeaders } from '@/utils/request'
|
|
|
import { addPet, updatePet } from '@/api/archieves/pet'
|
|
import { addPet, updatePet } from '@/api/archieves/pet'
|
|
@@ -212,7 +231,6 @@ const submitLoading = ref(false)
|
|
|
const allPetTags = ref([])
|
|
const allPetTags = ref([])
|
|
|
const avatarDisplayUrl = ref('')
|
|
const avatarDisplayUrl = ref('')
|
|
|
const vaccineCertDisplayUrl = ref('')
|
|
const vaccineCertDisplayUrl = ref('')
|
|
|
-
|
|
|
|
|
const isEdit = ref(false)
|
|
const isEdit = ref(false)
|
|
|
|
|
|
|
|
const baseUrl = import.meta.env.VITE_APP_BASE_API
|
|
const baseUrl = import.meta.env.VITE_APP_BASE_API
|
|
@@ -235,7 +253,6 @@ watch(() => props.visible, (val) => {
|
|
|
submitLoading.value = false
|
|
submitLoading.value = false
|
|
|
avatarDisplayUrl.value = ''
|
|
avatarDisplayUrl.value = ''
|
|
|
vaccineCertDisplayUrl.value = ''
|
|
vaccineCertDisplayUrl.value = ''
|
|
|
-
|
|
|
|
|
if (props.petData) {
|
|
if (props.petData) {
|
|
|
isEdit.value = true
|
|
isEdit.value = true
|
|
|
const d = props.petData
|
|
const d = props.petData
|
|
@@ -260,9 +277,7 @@ watch(() => props.visible, (val) => {
|
|
|
isEdit.value = false
|
|
isEdit.value = false
|
|
|
Object.assign(form, defaultForm())
|
|
Object.assign(form, defaultForm())
|
|
|
form.userId = props.userId || undefined
|
|
form.userId = props.userId || undefined
|
|
|
- if (props.userId) {
|
|
|
|
|
- fetchAndFillOwnerInfo(props.userId)
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (props.userId) fetchAndFillOwnerInfo(props.userId)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
@@ -281,49 +296,46 @@ const fetchAndFillOwnerInfo = (userId) => {
|
|
|
if (!form.entryPassword) form.entryPassword = data.entryPassword || ''
|
|
if (!form.entryPassword) form.entryPassword = data.entryPassword || ''
|
|
|
if (!form.keyLocation) form.keyLocation = data.keyLocation || ''
|
|
if (!form.keyLocation) form.keyLocation = data.keyLocation || ''
|
|
|
}
|
|
}
|
|
|
- }).catch(() => {})
|
|
|
|
|
|
|
+ }).catch(() => { })
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const loadTags = () => {
|
|
|
|
|
- listAllTag({ category: 'pet', status: 0 }).then((res) => {
|
|
|
|
|
- allPetTags.value = res.data || []
|
|
|
|
|
- })
|
|
|
|
|
-}
|
|
|
|
|
|
|
+const loadTags = () => { listAllTag({ category: 'pet', status: 0 }).then(res => { allPetTags.value = res.data || [] }) }
|
|
|
|
|
|
|
|
const handleUploadFile = async (file) => {
|
|
const handleUploadFile = async (file) => {
|
|
|
- const fd = new FormData()
|
|
|
|
|
- fd.append('file', file.raw)
|
|
|
|
|
|
|
+ const fd = new FormData(); fd.append('file', file.raw)
|
|
|
try {
|
|
try {
|
|
|
const headers = globalHeaders()
|
|
const headers = globalHeaders()
|
|
|
const res = await fetch(uploadUrl, { method: 'POST', headers: { 'Authorization': headers.Authorization, 'clientid': headers.clientid }, body: fd })
|
|
const res = await fetch(uploadUrl, { method: 'POST', headers: { 'Authorization': headers.Authorization, 'clientid': headers.clientid }, body: fd })
|
|
|
const result = await res.json()
|
|
const result = await res.json()
|
|
|
- if (result.code === 200) {
|
|
|
|
|
- form.avatar = result.data.ossId
|
|
|
|
|
- avatarDisplayUrl.value = result.data.url
|
|
|
|
|
- } else {
|
|
|
|
|
- ElMessage.error(result.msg || '头像上传失败')
|
|
|
|
|
- }
|
|
|
|
|
- } catch (e) {
|
|
|
|
|
- ElMessage.error('头像上传失败')
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (result.code === 200) { form.avatar = result.data.ossId; avatarDisplayUrl.value = result.data.url }
|
|
|
|
|
+ else ElMessage.error(result.msg || '头像上传失败')
|
|
|
|
|
+ } catch (e) { ElMessage.error('头像上传失败') }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+const vaccineCertUploadRef = ref(null)
|
|
|
|
|
+
|
|
|
|
|
+const showVaccineCert = computed(() => form.vaccineStatus && form.vaccineStatus !== '无')
|
|
|
|
|
+
|
|
|
const handleUploadVaccineCert = async (file) => {
|
|
const handleUploadVaccineCert = async (file) => {
|
|
|
- const fd = new FormData()
|
|
|
|
|
- fd.append('file', file.raw)
|
|
|
|
|
|
|
+ const fd = new FormData(); fd.append('file', file.raw)
|
|
|
try {
|
|
try {
|
|
|
const headers = globalHeaders()
|
|
const headers = globalHeaders()
|
|
|
const res = await fetch(uploadUrl, { method: 'POST', headers: { 'Authorization': headers.Authorization, 'clientid': headers.clientid }, body: fd })
|
|
const res = await fetch(uploadUrl, { method: 'POST', headers: { 'Authorization': headers.Authorization, 'clientid': headers.clientid }, body: fd })
|
|
|
const result = await res.json()
|
|
const result = await res.json()
|
|
|
- if (result.code === 200) {
|
|
|
|
|
- form.vaccineCert = result.data.ossId
|
|
|
|
|
- vaccineCertDisplayUrl.value = result.data.url
|
|
|
|
|
- } else {
|
|
|
|
|
- ElMessage.error(result.msg || '疫苗凭证上传失败')
|
|
|
|
|
- }
|
|
|
|
|
- } catch (e) {
|
|
|
|
|
- ElMessage.error('疫苗凭证上传失败')
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (result.code === 200) { form.vaccineCert = result.data.ossId; vaccineCertDisplayUrl.value = result.data.url }
|
|
|
|
|
+ else ElMessage.error(result.msg || '疫苗凭证上传失败')
|
|
|
|
|
+ } catch (e) { ElMessage.error('疫苗凭证上传失败') }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const triggerVaccineCertUpload = () => {
|
|
|
|
|
+ const el = vaccineCertUploadRef.value?.$el || vaccineCertUploadRef.value
|
|
|
|
|
+ const input = el?.querySelector?.('input[type="file"]')
|
|
|
|
|
+ if (input) input.click()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const removeVaccineCert = () => {
|
|
|
|
|
+ form.vaccineCert = undefined
|
|
|
|
|
+ vaccineCertDisplayUrl.value = ''
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const saveData = () => {
|
|
const saveData = () => {
|
|
@@ -334,7 +346,6 @@ const saveData = () => {
|
|
|
if (form.weight === undefined || form.weight === null) return ElMessage.warning('请输入体重(kg)')
|
|
if (form.weight === undefined || form.weight === null) return ElMessage.warning('请输入体重(kg)')
|
|
|
if (form.age === undefined || form.age === null) return ElMessage.warning('请输入年龄(岁)')
|
|
if (form.age === undefined || form.age === null) return ElMessage.warning('请输入年龄(岁)')
|
|
|
if (!form.houseType) return ElMessage.warning('请选择家庭房屋类型')
|
|
if (!form.houseType) return ElMessage.warning('请选择家庭房屋类型')
|
|
|
- if (!form.entryMethod) return ElMessage.warning('请选择入门方式')
|
|
|
|
|
if (form.entryMethod === 'password' && !form.entryPassword) return ElMessage.warning('请输入门锁密码')
|
|
if (form.entryMethod === 'password' && !form.entryPassword) return ElMessage.warning('请输入门锁密码')
|
|
|
if (form.entryMethod === 'key' && !form.keyLocation) return ElMessage.warning('请输入钥匙存放位置')
|
|
if (form.entryMethod === 'key' && !form.keyLocation) return ElMessage.warning('请输入钥匙存放位置')
|
|
|
if (!form.healthStatus) return ElMessage.warning('请选择健康状态')
|
|
if (!form.healthStatus) return ElMessage.warning('请选择健康状态')
|
|
@@ -342,7 +353,6 @@ const saveData = () => {
|
|
|
if (!form.vaccineStatus) return ElMessage.warning('请选择疫苗情况')
|
|
if (!form.vaccineStatus) return ElMessage.warning('请选择疫苗情况')
|
|
|
if (!form.medicalHistory) return ElMessage.warning('请输入既往病史')
|
|
if (!form.medicalHistory) return ElMessage.warning('请输入既往病史')
|
|
|
if (!form.allergies) return ElMessage.warning('请输入过敏史')
|
|
if (!form.allergies) return ElMessage.warning('请输入过敏史')
|
|
|
-
|
|
|
|
|
submitLoading.value = true
|
|
submitLoading.value = true
|
|
|
const data = { ...form, aggression: Number(form.aggression) || 0 }
|
|
const data = { ...form, aggression: Number(form.aggression) || 0 }
|
|
|
const api = isEdit.value ? updatePet(data) : addPet(data)
|
|
const api = isEdit.value ? updatePet(data) : addPet(data)
|
|
@@ -350,31 +360,27 @@ const saveData = () => {
|
|
|
ElMessage.success(isEdit.value ? '宠物档案更新成功' : '宠物档案保存成功')
|
|
ElMessage.success(isEdit.value ? '宠物档案更新成功' : '宠物档案保存成功')
|
|
|
emit('success', res.data || data)
|
|
emit('success', res.data || data)
|
|
|
emit('update:visible', false)
|
|
emit('update:visible', false)
|
|
|
- }).finally(() => {
|
|
|
|
|
- submitLoading.value = false
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ }).finally(() => { submitLoading.value = false })
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-onMounted(() => {
|
|
|
|
|
- loadTags()
|
|
|
|
|
-})
|
|
|
|
|
|
|
+onMounted(() => { loadTags() })
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped>
|
|
<style scoped>
|
|
|
.add-pet-dialog :deep(.el-dialog__body) {
|
|
.add-pet-dialog :deep(.el-dialog__body) {
|
|
|
- padding: 0 24px 0;
|
|
|
|
|
|
|
+ padding: 0 36px 0;
|
|
|
max-height: 62vh;
|
|
max-height: 62vh;
|
|
|
overflow-y: auto;
|
|
overflow-y: auto;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.dialog-body {
|
|
.dialog-body {
|
|
|
- padding-top: 8px;
|
|
|
|
|
|
|
+ padding-top: 12px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.avatar-section {
|
|
.avatar-section {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
justify-content: center;
|
|
justify-content: center;
|
|
|
- margin-bottom: 20px;
|
|
|
|
|
|
|
+ margin-bottom: 24px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.avatar-uploader {
|
|
.avatar-uploader {
|
|
@@ -382,14 +388,14 @@ onMounted(() => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.avatar-preview {
|
|
.avatar-preview {
|
|
|
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
|
+ box-shadow: 0 2px 12px rgba(0, 0, 0, .1);
|
|
|
border: 3px solid #fff;
|
|
border: 3px solid #fff;
|
|
|
outline: 1px solid #e8e8e8;
|
|
outline: 1px solid #e8e8e8;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.avatar-placeholder {
|
|
.avatar-placeholder {
|
|
|
- width: 88px;
|
|
|
|
|
- height: 88px;
|
|
|
|
|
|
|
+ width: 80px;
|
|
|
|
|
+ height: 80px;
|
|
|
border-radius: 50%;
|
|
border-radius: 50%;
|
|
|
border: 2px dashed #dcdfe6;
|
|
border: 2px dashed #dcdfe6;
|
|
|
display: flex;
|
|
display: flex;
|
|
@@ -397,9 +403,9 @@ onMounted(() => {
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
justify-content: center;
|
|
|
color: #a8abb2;
|
|
color: #a8abb2;
|
|
|
- gap: 2px;
|
|
|
|
|
font-size: 12px;
|
|
font-size: 12px;
|
|
|
- transition: all 0.3s;
|
|
|
|
|
|
|
+ gap: 2px;
|
|
|
|
|
+ transition: all .3s;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.avatar-placeholder:hover {
|
|
.avatar-placeholder:hover {
|
|
@@ -408,62 +414,123 @@ onMounted(() => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.pet-form {
|
|
.pet-form {
|
|
|
- padding-bottom: 10px;
|
|
|
|
|
|
|
+ padding-bottom: 12px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.section-heading {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ margin: 32px 0 20px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.section {
|
|
|
|
|
- margin-bottom: 8px;
|
|
|
|
|
- padding: 16px 20px 4px;
|
|
|
|
|
- background: #fafbfc;
|
|
|
|
|
- border-radius: 8px;
|
|
|
|
|
- border: 1px solid #f0f0f0;
|
|
|
|
|
|
|
+.section-heading:first-of-type {
|
|
|
|
|
+ margin-top: 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.section-title {
|
|
|
|
|
|
|
+.section-line {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ height: 1px;
|
|
|
|
|
+ background: #e8e8e8;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.section-text {
|
|
|
|
|
+ padding: 0 20px;
|
|
|
font-size: 14px;
|
|
font-size: 14px;
|
|
|
font-weight: 600;
|
|
font-weight: 600;
|
|
|
color: #303133;
|
|
color: #303133;
|
|
|
- margin-bottom: 14px;
|
|
|
|
|
- padding-left: 10px;
|
|
|
|
|
- border-left: 3px solid #409eff;
|
|
|
|
|
|
|
+ white-space: nowrap;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.cert-uploader {
|
|
|
|
|
- cursor: pointer;
|
|
|
|
|
|
|
+.cert-row {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 10px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.cert-preview {
|
|
|
|
|
- width: 72px;
|
|
|
|
|
- height: 72px;
|
|
|
|
|
- object-fit: cover;
|
|
|
|
|
|
|
+.cert-box {
|
|
|
|
|
+ width: 32px;
|
|
|
|
|
+ height: 32px;
|
|
|
border-radius: 6px;
|
|
border-radius: 6px;
|
|
|
- border: 1px solid #e8e8e8;
|
|
|
|
|
|
|
+ border: 1.5px dashed #d0d5dd;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ transition: border-color .25s, box-shadow .25s;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.cert-placeholder {
|
|
|
|
|
- width: 72px;
|
|
|
|
|
- height: 72px;
|
|
|
|
|
- border-radius: 6px;
|
|
|
|
|
- border: 2px dashed #dcdfe6;
|
|
|
|
|
|
|
+.cert-box:hover {
|
|
|
|
|
+ border-color: #409eff;
|
|
|
|
|
+ box-shadow: 0 0 0 3px rgba(64, 158, 255, .08);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.cert-plus-icon {
|
|
|
|
|
+ color: #a0a5b0;
|
|
|
|
|
+ transition: color .25s;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.cert-box:hover .cert-plus-icon {
|
|
|
|
|
+ color: #409eff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.cert-upload-mask {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ inset: 0;
|
|
|
|
|
+ z-index: 1;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.cert-box.has-image {
|
|
|
|
|
+ border-style: solid;
|
|
|
|
|
+ border-color: #e4e7ed;
|
|
|
|
|
+ cursor: default;
|
|
|
|
|
+ box-shadow: 0 1px 4px rgba(0, 0, 0, .06);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.cert-box.has-image:hover {
|
|
|
|
|
+ border-color: #e4e7ed;
|
|
|
|
|
+ box-shadow: 0 1px 4px rgba(0, 0, 0, .06);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.cert-thumb {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.cert-actions {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
- flex-direction: column;
|
|
|
|
|
|
|
+ gap: 4px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.cert-action-icon {
|
|
|
|
|
+ width: 32px;
|
|
|
|
|
+ height: 32px;
|
|
|
|
|
+ border-radius: 6px;
|
|
|
|
|
+ display: inline-flex;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
justify-content: center;
|
|
|
- color: #a8abb2;
|
|
|
|
|
- font-size: 12px;
|
|
|
|
|
- gap: 2px;
|
|
|
|
|
- transition: all 0.3s;
|
|
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ transition: all .2s;
|
|
|
|
|
+ color: #606266;
|
|
|
|
|
+ background: #f5f6f8;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.cert-placeholder:hover {
|
|
|
|
|
- border-color: #409eff;
|
|
|
|
|
|
|
+.cert-action-icon:hover {
|
|
|
|
|
+ background: #ecf5ff;
|
|
|
color: #409eff;
|
|
color: #409eff;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+.cert-action-del:hover {
|
|
|
|
|
+ background: #fef0f0;
|
|
|
|
|
+ color: #f56c6c;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
.dialog-footer {
|
|
.dialog-footer {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
justify-content: flex-end;
|
|
justify-content: flex-end;
|
|
|
gap: 12px;
|
|
gap: 12px;
|
|
|
- padding-top: 8px;
|
|
|
|
|
|
|
+ padding-top: 12px;
|
|
|
}
|
|
}
|
|
|
</style>
|
|
</style>
|