232 lines
7.4 KiB
TypeScript
232 lines
7.4 KiB
TypeScript
import { request } from '../../utils/request'
|
|
import { ClothesItem, PagedResult, UserInfo } from '../../types/models'
|
|
import { STORAGE_KEYS } from '../../utils/config'
|
|
import { normalizePaged, hasMorePaged } from '../../utils/paged'
|
|
import { navScroll } from '../../utils/nav'
|
|
import { logger } from '../../utils/logger'
|
|
|
|
// 日志模块名
|
|
const LOG = 'closet-share-create'
|
|
|
|
const CATEGORIES = [
|
|
{ name: '全部', value: '' },
|
|
{ name: '上装', value: '上装' },
|
|
{ name: '下装', value: '下装' },
|
|
{ name: '连衣裙', value: '连衣裙' },
|
|
{ name: '外套', value: '外套' },
|
|
{ name: '鞋', value: '鞋' },
|
|
{ name: '配饰', value: '配饰' },
|
|
]
|
|
|
|
const EXPIRE_OPTIONS = [
|
|
{ label: '1 天', days: 1 },
|
|
{ label: '7 天', days: 7 },
|
|
{ label: '30 天', days: 30 },
|
|
{ label: '长期有效', days: 0 },
|
|
]
|
|
|
|
const PAGE_SIZE = 50
|
|
|
|
Page({
|
|
data: {
|
|
view: 'config' as 'config' | 'select' | 'success',
|
|
shareType: 1,
|
|
expireDays: 7,
|
|
expireOptions: EXPIRE_OPTIONS,
|
|
selectedUuids: [] as string[],
|
|
categories: CATEGORIES,
|
|
activeCategory: 0,
|
|
allClothes: [] as ClothesItem[],
|
|
selectLoading: true,
|
|
loadingMore: false,
|
|
hasMore: true,
|
|
page: 1,
|
|
submitting: false,
|
|
shareUuid: '',
|
|
nickname: '微信用户',
|
|
avatar: '',
|
|
selectedCount: 0,
|
|
// 滚动收缩:由 utils/nav.ts 的共享 handler 驱动
|
|
navScrolled: false,
|
|
// 额度不足引导:v2 玻璃弹窗
|
|
quotaVisible: false,
|
|
quotaTitle: '衣柜分享额度不足',
|
|
quotaText: '购买额度包后可创建衣柜分享',
|
|
quotaButtons: [
|
|
{ text: '取消', value: '' },
|
|
{ text: '去购买', value: 'ok', type: 'main' },
|
|
],
|
|
},
|
|
|
|
// scroll-view 滚动 → 导航收缩为玻璃小标题
|
|
onNavScroll: navScroll,
|
|
|
|
onLoad() {
|
|
this.loadUserInfo()
|
|
},
|
|
|
|
loadUserInfo() {
|
|
const cached = wx.getStorageSync(STORAGE_KEYS.USER_INFO) as Record<string, any>
|
|
if (cached) {
|
|
this.setData({ nickname: cached.username || '微信用户', avatar: cached.avatar || '' })
|
|
}
|
|
// 头像为带时间戳的签名 URL,缓存可能过期,实时刷新并回写缓存。
|
|
request<UserInfo>({ url: '/user/info', showError: false })
|
|
.then((user) => {
|
|
logger.debug(LOG, '用户信息加载成功')
|
|
wx.setStorageSync(STORAGE_KEYS.USER_INFO, user)
|
|
this.setData({ nickname: user.username || '微信用户', avatar: user.avatar || '' })
|
|
})
|
|
.catch((e: any) => logger.warn(LOG, '用户信息加载失败(用缓存兜底), code=', e && e.code))
|
|
},
|
|
|
|
selectPartial() {
|
|
this.setData({ shareType: 1 })
|
|
},
|
|
selectFull() {
|
|
this.setData({ shareType: 2 })
|
|
},
|
|
selectExpire(e: WechatMiniprogram.TouchEvent) {
|
|
const days = Number(e.currentTarget.dataset.days)
|
|
this.setData({ expireDays: days })
|
|
},
|
|
|
|
openSelect() {
|
|
this.setData({ view: 'select', selectLoading: true, page: 1, hasMore: true })
|
|
this.fetchAllClothes(1)
|
|
},
|
|
|
|
fetchAllClothes(page = 1) {
|
|
const cat = CATEGORIES[this.data.activeCategory].value
|
|
const params: Record<string, any> = { page, page_size: PAGE_SIZE }
|
|
if (cat) params.category_main = cat
|
|
|
|
// 请求序号:切换分类时旧响应可能后到,序号不匹配直接丢弃
|
|
const seq = ((this as any).reqSeq || 0) + 1
|
|
;(this as any).reqSeq = seq
|
|
if (page > 1) this.setData({ loadingMore: true })
|
|
|
|
request<PagedResult<ClothesItem>>({ url: '/clothes', data: params })
|
|
.then((res) => {
|
|
if ((this as any).reqSeq !== seq) return
|
|
const { list: raw, total } = normalizePaged<ClothesItem>(res)
|
|
logger.debug(LOG, '衣物列表加载成功, 分类=', cat || '全部', 'page=', page, '条数=', raw && raw.length)
|
|
const list = raw.map((it) => ({
|
|
...it,
|
|
_selected: this.data.selectedUuids.indexOf(it.clothes_uuid) >= 0,
|
|
}))
|
|
const merged = page === 1 ? list : this.data.allClothes.concat(list)
|
|
this.setData({
|
|
allClothes: merged,
|
|
selectLoading: false,
|
|
loadingMore: false,
|
|
page,
|
|
hasMore: hasMorePaged(merged, total, PAGE_SIZE),
|
|
})
|
|
})
|
|
.catch((e: any) => {
|
|
if ((this as any).reqSeq !== seq) return
|
|
logger.warn(LOG, '衣物列表加载失败, page=', page, 'code=', e && e.code)
|
|
this.setData({ selectLoading: false, loadingMore: false })
|
|
})
|
|
},
|
|
|
|
onCategoryTap(e: WechatMiniprogram.TouchEvent) {
|
|
const index = Number(e.currentTarget.dataset.index)
|
|
if (index === this.data.activeCategory) return
|
|
this.setData({ activeCategory: index, selectLoading: true, page: 1, hasMore: true })
|
|
this.fetchAllClothes(1)
|
|
},
|
|
|
|
onReachBottom() {
|
|
if (this.data.view !== 'select') return
|
|
if (!this.data.hasMore || this.data.selectLoading || this.data.loadingMore) return
|
|
this.fetchAllClothes(this.data.page + 1)
|
|
},
|
|
|
|
onToggleSelect(e: WechatMiniprogram.CustomEvent) {
|
|
const item = e.detail.item as ClothesItem
|
|
const uuids = this.data.selectedUuids
|
|
const idx = uuids.indexOf(item.clothes_uuid)
|
|
if (idx >= 0) {
|
|
this.syncSelect(uuids.filter((u) => u !== item.clothes_uuid))
|
|
} else {
|
|
this.syncSelect([...uuids, item.clothes_uuid])
|
|
}
|
|
},
|
|
|
|
syncSelect(uuids: string[]) {
|
|
this.setData({
|
|
selectedUuids: uuids,
|
|
allClothes: this.data.allClothes.map((it) => ({
|
|
...it,
|
|
_selected: uuids.indexOf(it.clothes_uuid) >= 0,
|
|
})),
|
|
})
|
|
},
|
|
|
|
confirmSelect() {
|
|
this.setData({ view: 'config', selectedCount: this.data.selectedUuids.length })
|
|
},
|
|
|
|
backToConfig() {
|
|
this.setData({ view: 'config' })
|
|
},
|
|
|
|
onConfirm() {
|
|
if (this.data.submitting) return
|
|
const body: Record<string, any> = { share_type: this.data.shareType }
|
|
if (this.data.shareType === 1) {
|
|
if (!this.data.selectedUuids.length) {
|
|
wx.showToast({ title: '请选择要分享的衣物', icon: 'none' })
|
|
return
|
|
}
|
|
body.clothes_uuids = this.data.selectedUuids
|
|
}
|
|
const days = this.data.expireDays
|
|
body.expire_time = days > 0 ? Math.floor(Date.now() / 1000) + days * 86400 : 0
|
|
|
|
// 提交加锁:连点会重复创建分享、重复扣额度
|
|
this.setData({ submitting: true })
|
|
request<{ share_uuid: string }>({ url: '/closet-share', method: 'POST', data: body })
|
|
.then((res) => {
|
|
logger.info(LOG, '分享创建成功, uuid=', res.share_uuid)
|
|
this.setData({ shareUuid: res.share_uuid, view: 'success', submitting: false })
|
|
})
|
|
.catch((e: any) => {
|
|
logger.warn(LOG, '分享创建失败, code=', e && e.code)
|
|
this.setData({ submitting: false })
|
|
// 衣柜分享额度不足:弹窗引导购买
|
|
if (e && e.code === 80000) {
|
|
this.setData({ quotaVisible: true })
|
|
}
|
|
})
|
|
},
|
|
|
|
onViewShare() {
|
|
wx.redirectTo({
|
|
url: `/pages/closet-share-detail/closet-share-detail?uuid=${this.data.shareUuid}`,
|
|
fail: (e) => logger.warn(LOG, 'redirectTo 分享详情失败, err=', e && e.errMsg),
|
|
})
|
|
},
|
|
|
|
onDone() {
|
|
wx.navigateBack({
|
|
fail: (e) => logger.warn(LOG, 'navigateBack 失败, err=', e && e.errMsg),
|
|
})
|
|
},
|
|
|
|
onQuotaCancel() {
|
|
this.setData({ quotaVisible: false })
|
|
},
|
|
|
|
onQuotaConfirm(e: WechatMiniprogram.CustomEvent) {
|
|
this.setData({ quotaVisible: false })
|
|
if (e.detail.value !== 'ok') return
|
|
wx.navigateTo({
|
|
url: '/pages/mall/mall',
|
|
fail: (err) => logger.warn(LOG, 'navigateTo 商城失败, err=', err && err.errMsg),
|
|
})
|
|
},
|
|
})
|