import { api } from '../../utils/api' import { BREED_OPTIONS } from '../../utils/constants' import { getPetEmoji } from '../../utils/format' import { AppGlobalData } from '../../types/index' const SPECIES_LABELS: Record = { dog: '狗狗', cat: '猫猫', other: '其他' } const PRESET_TAGS = ['活泼', '温顺', '黏人', '独立', '爱玩', '怕生', '聪明', '贪吃', '爱运动', '安静'] const app = getApp<{ globalData: AppGlobalData }>() // 根据已选标签数组生成 {tag: boolean} 映射,供 WXML 直接判断选中态 function buildTagSet(tags: string[]): Record { const set: Record = {} tags.forEach(t => { set[t] = true }) return set } Page({ data: { statusBarHeight: 0, navbarHeight: 44, navbarPaddingRight: 0, isEdit: false, petId: '', form: { name: '', species: 'dog' as 'dog' | 'cat' | 'other', breed: '', gender: 'female' as 'female' | 'male', birthday: '', bio: '', tags: [] as string[], emoji: '🐶', }, speciesLabel: '狗狗', // 品种 currentBreeds: BREED_OPTIONS['dog'], breedIndex: -1, // 标签 allTags: [...PRESET_TAGS] as string[], selectedTagSet: {} as Record, customTagInput: '', }, onLoad(query: { id?: string }) { const info = wx.getSystemInfoSync() const { statusBarHeight, navbarHeight, navbarPaddingRight } = app.globalData.navBarInfo this.setData({ statusBarHeight, navbarHeight, navbarPaddingRight, currentBreeds: BREED_OPTIONS['dog'], }) if (query.id) { this.setData({ isEdit: true, petId: query.id }) this.loadPet(query.id) } }, loadPet(id: string) { const user = app.globalData?.userInfo const pet = user?.pets?.find((p: any) => p._id === id) if (!pet) return const breeds = BREED_OPTIONS[pet.species] || BREED_OPTIONS['dog'] const breedIndex = breeds.indexOf(pet.breed) const petTags: string[] = pet.tags || [] // 把宠物已有的自定义标签合并进 allTags const merged = [...PRESET_TAGS] petTags.forEach(t => { if (!merged.includes(t)) merged.push(t) }) this.setData({ form: { name: pet.name, species: pet.species, breed: pet.breed, gender: pet.gender, birthday: pet.birthday || '', bio: pet.bio || '', tags: petTags, emoji: pet.emoji, }, speciesLabel: SPECIES_LABELS[pet.species] || '狗狗', currentBreeds: breeds, breedIndex, allTags: merged, selectedTagSet: buildTagSet(petTags), }) }, onField(e: WechatMiniprogram.CustomEvent) { const key = e.currentTarget.dataset.key as string this.setData({ [`form.${key}`]: e.detail.value }) }, onSpecies() { wx.showActionSheet({ itemList: ['狗狗', '猫猫', '其他'], success: res => { const species = (['dog', 'cat', 'other'] as const)[res.tapIndex] const breeds = BREED_OPTIONS[species] this.setData({ 'form.species': species, 'form.breed': '', 'form.emoji': getPetEmoji(species), speciesLabel: SPECIES_LABELS[species], currentBreeds: breeds, breedIndex: -1, }) }, }) }, // 品种 picker 选中回调 onBreedChange(e: WechatMiniprogram.CustomEvent) { const idx = Number(e.detail.value) const breed = this.data.currentBreeds[idx] this.setData({ breedIndex: idx, 'form.breed': breed, 'form.emoji': getPetEmoji(this.data.form.species, breed), }) }, onGender(e: WechatMiniprogram.CustomEvent) { this.setData({ 'form.gender': e.currentTarget.dataset.v }) }, onBirthday(e: WechatMiniprogram.CustomEvent) { const dob = e.detail.value as string const diffMs = Date.now() - new Date(dob).getTime() const years = Math.floor(diffMs / (365.25 * 24 * 3600 * 1000)) const months = Math.floor((diffMs % (365.25 * 24 * 3600 * 1000)) / (30.44 * 24 * 3600 * 1000)) const age = years > 0 ? `${years}岁${months > 0 ? months + '个月' : ''}` : `${months}个月` this.setData({ 'form.birthday': dob, 'form.age': age }) }, // 预设标签 — 点击切换 onTagToggle(e: WechatMiniprogram.CustomEvent) { const tag = e.currentTarget.dataset.tag as string const tags = [...this.data.form.tags] const idx = tags.indexOf(tag) if (idx >= 0) { tags.splice(idx, 1) } else { if (tags.length >= 8) { wx.showToast({ title: '最多选8个标签', icon: 'none' }) return } tags.push(tag) } this.setData({ 'form.tags': tags, selectedTagSet: buildTagSet(tags) }) }, // 自定义标签输入 onCustomTagInput(e: WechatMiniprogram.CustomEvent) { this.setData({ customTagInput: e.detail.value }) }, // 添加自定义标签 onAddCustomTag() { const raw = this.data.customTagInput.trim() if (!raw) return // 仅允许中英文和数字,最多5个字符 if ([...raw].length > 5) { wx.showToast({ title: '标签最多5个字', icon: 'none' }) return } if (!/^[一-龥a-zA-Z0-9]+$/.test(raw)) { wx.showToast({ title: '只能输入文字或字母', icon: 'none' }) return } const tags = [...this.data.form.tags] if (tags.includes(raw)) { this.setData({ customTagInput: '' }) return } if (tags.length >= 8) { wx.showToast({ title: '最多选8个标签', icon: 'none' }) return } tags.push(raw) const allTags = this.data.allTags.includes(raw) ? this.data.allTags : [...this.data.allTags, raw] this.setData({ 'form.tags': tags, selectedTagSet: buildTagSet(tags), allTags, customTagInput: '', }) }, async onChoosePhoto() { wx.chooseMedia({ count: 1, mediaType: ['image'], sourceType: ['album', 'camera'], success: async res => { const path = res.tempFiles[0].tempFilePath wx.showLoading({ title: '上传中...' }) try { const cloudPath = `pet-avatars/${Date.now()}.jpg` const r = await wx.cloud.uploadFile({ cloudPath, filePath: path }) this.setData({ 'form.avatarUrl': r.fileID }) wx.hideLoading() } catch { wx.hideLoading() wx.showToast({ title: '上传失败', icon: 'none' }) } }, }) }, async onSave() { const { form, isEdit, petId } = this.data if (!form.name.trim()) { wx.showToast({ title: '请填写宠物名字', icon: 'none' }) return } wx.showLoading({ title: '保存中...' }) try { const saved = await api.updatePet(isEdit ? { ...form, _id: petId } : form) // 同步本地缓存,让"我的"页面立即看到最新的宠物档案 const user = app.globalData.userInfo if (user) { const pets = Array.isArray(user.pets) ? [...user.pets] : [] const idx = pets.findIndex((p: any) => p._id === saved._id) if (idx >= 0) pets[idx] = saved else pets.push(saved) user.pets = pets } wx.hideLoading() wx.showToast({ title: '保存成功', icon: 'success' }) setTimeout(() => wx.navigateBack(), 800) } catch (e) { wx.hideLoading() const message = e instanceof Error ? e.message : '保存失败' wx.showToast({ title: message, icon: 'none' }) } }, onDelete() { const { petId } = this.data wx.showModal({ title: '删除宠物档案', content: '确定要删除吗?', confirmText: '删除', confirmColor: '#d4596a', success: res => { if (!res.confirm) return wx.showLoading({ title: '删除中...' }) api.deletePet(petId) .then(() => { const user = app.globalData.userInfo if (user && Array.isArray(user.pets)) { user.pets = user.pets.filter((p: any) => p._id !== petId) } wx.hideLoading() wx.showToast({ title: '已删除', icon: 'success' }) setTimeout(() => wx.navigateBack(), 800) }) .catch((e: unknown) => { wx.hideLoading() const message = e instanceof Error ? e.message : '删除失败' wx.showToast({ title: message, icon: 'none' }) }) }, }) }, onBack() { wx.navigateBack() }, })