Files
zt-closet-wxmini-frontend/miniprogram/pages/wardrobe/wardrobe.ts
T
2026-09-13 02:35:32 +08:00

148 lines
5.0 KiB
TypeScript

import { request, redirectToLogin } from '../../utils/request'
import * as auth from '../../utils/auth'
import { PagedResult, ClothesItem, QuotaItem } from '../../types/models'
import { QuotaType } from '../../utils/config'
import { normalizePaged, mergePaged, hasMorePaged } from '../../utils/paged'
import { setTabBarSelected } from '../../utils/tabbar'
import { logger } from '../../utils/logger'
// 日志模块名
const LOG = 'wardrobe'
const CATEGORIES = [
{ name: '全部', value: '' },
{ name: '上装', value: '上装' },
{ name: '下装', value: '下装' },
{ name: '连衣裙', value: '连衣裙' },
{ name: '外套', value: '外套' },
{ name: '鞋', value: '鞋' },
{ name: '配饰', value: '配饰' },
]
Page({
data: {
categories: CATEGORIES,
activeCategory: 0,
list: [] as ClothesItem[],
total: 0,
uploadRemain: 0,
loading: true,
refreshing: false,
loadingMore: false, // 上拉加载独立闸门,避免与首次 loading 互相干扰
page: 1,
pageSize: 20,
hasMore: true,
},
onShow() {
this.syncTabBar()
// 未登录直接回登录页(幂等跳转),不再发出必然 401 的请求
if (!auth.isLoggedIn()) {
redirectToLogin()
return
}
// 首帧渲染未结束就 setData 会触发「Expected updated data but get first rendering data」,
// 整个 webview 渲染失败,用户视觉上仍看到上一个页面(从 login switchTab 过来时表现为
// "卡在登录页")。把首次 onShow 的刷新延迟到下一帧,规避首帧冲突。
if (!(this as any).firstShown) {
;(this as any).firstShown = true
wx.nextTick(() => this.refresh())
return
}
logger.debug(LOG, 'onShow 触发刷新')
this.refresh()
},
syncTabBar() {
setTabBarSelected(0)
},
refresh() {
this.setData({ page: 1, hasMore: true, loading: this.data.list.length === 0 })
this.fetchList(1)
this.fetchQuota()
},
onRefresh() {
this.setData({ refreshing: true })
Promise.all([this.fetchList(1), this.fetchQuota()]).finally(() => {
this.setData({ refreshing: false })
})
},
onReachBottom() {
if (!this.data.hasMore || this.data.loading || this.data.loadingMore) return
this.fetchList(this.data.page + 1)
},
fetchList(page: number): Promise<void> {
const cat = CATEGORIES[this.data.activeCategory].value
const params: Record<string, any> = { page, page_size: this.data.pageSize }
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 })
return 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,
_statusText: !it.category_main && !it.processed_image ? 'AI 处理中' : '',
_statusType: 'blue',
}))
const merged = mergePaged(this.data.list, list, page === 1)
this.setData({
list: merged,
total,
hasMore: hasMorePaged(merged, total, this.data.pageSize),
loading: false,
loadingMore: false,
page,
})
})
.catch((e: any) => {
if ((this as any).reqSeq !== seq) return
logger.warn(LOG, '列表加载失败, page=', page, 'code=', e && e.code)
this.setData({ loading: false, loadingMore: false })
})
},
fetchQuota(): Promise<void> {
return request<{ quotas: QuotaItem[] }>({ url: '/quota/info', showError: false, silentAuth: true })
.then((res) => {
const upload = res.quotas.find((q) => q.quota_type === QuotaType.UPLOAD)
if (upload) this.setData({ uploadRemain: upload.remain })
logger.debug(LOG, '额度加载成功, 上传剩余=', upload ? upload.remain : 0)
})
.catch((e: any) => logger.warn(LOG, '额度加载失败(静默降级), code=', e && e.code))
},
onCategoryTap(e: WechatMiniprogram.TouchEvent) {
const index = Number(e.currentTarget.dataset.index)
if (index === this.data.activeCategory) return
this.setData({ activeCategory: index, list: [], loading: true })
this.refresh()
},
onClothesTap(e: WechatMiniprogram.CustomEvent) {
const item = e.detail.item as ClothesItem
logger.debug(LOG, '点击衣物, uuid=', item && item.clothes_uuid)
wx.navigateTo({
url: `/pages/clothes-detail/clothes-detail?uuid=${item.clothes_uuid}`,
fail: (err) => logger.warn(LOG, 'navigateTo 衣物详情失败, err=', err && err.errMsg),
})
},
onUpload() {
wx.navigateTo({
url: '/pages/upload/upload',
fail: (e) => logger.warn(LOG, 'navigateTo 上传页失败, err=', e && e.errMsg),
})
},
})