feat: rebuild pet app and backend around core care flows
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
const { secure, upload, toast } = require("../../utils/api");
|
||||
Page({
|
||||
data: {
|
||||
id: "",
|
||||
name: "",
|
||||
breed: "柯基",
|
||||
gender: "male",
|
||||
birth_date: "",
|
||||
weight_kg: "",
|
||||
coat: "",
|
||||
allergies: "",
|
||||
care_notes: "",
|
||||
avatar_file_id: "",
|
||||
avatar_url: "",
|
||||
},
|
||||
onLoad(options) {
|
||||
if (options.id) {
|
||||
this.setData({ id: options.id });
|
||||
this.load(options.id);
|
||||
}
|
||||
},
|
||||
async load(id) {
|
||||
try {
|
||||
this.setData(await secure("/pets/" + id));
|
||||
} catch (e) {
|
||||
toast(e);
|
||||
}
|
||||
},
|
||||
field(e) {
|
||||
this.setData({ [e.currentTarget.dataset.key]: e.detail.value });
|
||||
},
|
||||
date(e) {
|
||||
this.setData({ birth_date: e.detail.value });
|
||||
},
|
||||
gender(e) {
|
||||
this.setData({ gender: e.detail.value });
|
||||
},
|
||||
async choose() {
|
||||
try {
|
||||
const r = await wx.chooseMedia({ count: 1, mediaType: ["image"] });
|
||||
const file = await upload(r.tempFiles[0].tempFilePath);
|
||||
this.setData({ avatar_file_id: file.id, avatar_url: file.url });
|
||||
} catch (e) {
|
||||
toast(e);
|
||||
}
|
||||
},
|
||||
async save() {
|
||||
if (!this.data.name.trim()) {
|
||||
wx.showToast({ title: "请输入名字", icon: "none" });
|
||||
return;
|
||||
}
|
||||
const body = {
|
||||
name: this.data.name,
|
||||
species: "dog",
|
||||
breed: this.data.breed,
|
||||
gender: this.data.gender,
|
||||
birth_date: this.data.birth_date || "",
|
||||
weight_kg: Number(this.data.weight_kg) || 0,
|
||||
coat: this.data.coat,
|
||||
allergies: this.data.allergies,
|
||||
care_notes: this.data.care_notes,
|
||||
avatar_file_id: this.data.avatar_file_id || null,
|
||||
};
|
||||
try {
|
||||
await secure(
|
||||
"/pets" + (this.data.id ? "/" + this.data.id : ""),
|
||||
this.data.id ? "PUT" : "POST",
|
||||
body,
|
||||
);
|
||||
wx.navigateBack();
|
||||
} catch (e) {
|
||||
toast(e);
|
||||
}
|
||||
},
|
||||
async archive() {
|
||||
const confirm = await wx.showModal({
|
||||
title: "归档宠物",
|
||||
content: "归档后不会再出现在遛狗和任务中。",
|
||||
});
|
||||
if (!confirm.confirm) return;
|
||||
try {
|
||||
await secure("/pets/" + this.data.id, "DELETE");
|
||||
wx.navigateBack();
|
||||
} catch (e) {
|
||||
toast(e);
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,64 @@
|
||||
<view class="screen">
|
||||
<view class="eyebrow">PET PROFILE</view>
|
||||
<view class="title">{{id?'编辑档案':'认识新朋友'}} 🐶</view>
|
||||
<view class="photo" bindtap="choose">
|
||||
<image wx:if="{{avatar_url}}" src="{{avatar_url}}" mode="aspectFill" />
|
||||
<text wx:else>🐕</text>
|
||||
<view>点击上传照片</view>
|
||||
</view>
|
||||
<view class="field">
|
||||
<view class="field-label">名字 *</view>
|
||||
<input
|
||||
placeholder="它叫什么名字?"
|
||||
value="{{name}}"
|
||||
data-key="name"
|
||||
bindinput="field"
|
||||
/>
|
||||
</view>
|
||||
<view class="field">
|
||||
<view class="field-label">品种</view>
|
||||
<input value="{{breed}}" data-key="breed" bindinput="field" />
|
||||
</view>
|
||||
<view class="field">
|
||||
<view class="field-label">性别</view>
|
||||
<radio-group bindchange="gender">
|
||||
<label>
|
||||
<radio value="male" checked="{{gender==='male'}}" color="#194f42" />
|
||||
男孩
|
||||
</label>
|
||||
<label>
|
||||
<radio value="female" checked="{{gender==='female'}}" color="#194f42" />
|
||||
女孩
|
||||
</label>
|
||||
</radio-group>
|
||||
</view>
|
||||
<view class="field">
|
||||
<view class="field-label">生日</view>
|
||||
<picker mode="date" value="{{birth_date}}" bindchange="date">
|
||||
<view class="picker">{{birth_date||'选择生日'}}</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="field">
|
||||
<view class="field-label">体重 kg</view>
|
||||
<input
|
||||
type="digit"
|
||||
value="{{weight_kg}}"
|
||||
data-key="weight_kg"
|
||||
bindinput="field"
|
||||
/>
|
||||
</view>
|
||||
<view class="field">
|
||||
<view class="field-label">毛色</view>
|
||||
<input value="{{coat}}" data-key="coat" bindinput="field" />
|
||||
</view>
|
||||
<view class="field">
|
||||
<view class="field-label">过敏提醒</view>
|
||||
<input value="{{allergies}}" data-key="allergies" bindinput="field" />
|
||||
</view>
|
||||
<view class="field">
|
||||
<view class="field-label">照顾备注</view>
|
||||
<textarea value="{{care_notes}}" data-key="care_notes" bindinput="field" />
|
||||
</view>
|
||||
<button class="primary" bindtap="save">保存档案</button>
|
||||
<button wx:if="{{id}}" class="archive" bindtap="archive">归档这只宠物</button>
|
||||
</view>
|
||||
@@ -0,0 +1,50 @@
|
||||
.photo {
|
||||
width: 190rpx;
|
||||
height: 190rpx;
|
||||
border-radius: 42rpx;
|
||||
background: #f2d5aa;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
margin: 0 auto 35rpx;
|
||||
position: relative;
|
||||
font-size: 80rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
.photo image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.photo view {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #194f42b5;
|
||||
color: white;
|
||||
text-align: center;
|
||||
font-size: 18rpx;
|
||||
padding: 6rpx;
|
||||
}
|
||||
.field radio-group {
|
||||
display: flex;
|
||||
gap: 30rpx;
|
||||
background: #fff;
|
||||
padding: 20rpx;
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
.field label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5rpx;
|
||||
}
|
||||
.picker {
|
||||
background: white;
|
||||
border-radius: 20rpx;
|
||||
padding: 22rpx;
|
||||
}
|
||||
.archive {
|
||||
background: transparent;
|
||||
color: #a66c5a;
|
||||
font-size: 24rpx;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
Reference in New Issue
Block a user