feat:ui add
This commit is contained in:
@@ -6,24 +6,90 @@ import { logger } from '../../utils/logger'
|
||||
// 日志模块名
|
||||
const LOG = 'clothes-detail'
|
||||
|
||||
const ATTRS = [
|
||||
{ key: 'category_main', label: '大类', type: 'text' },
|
||||
{ key: 'category_sub', label: '小类', type: 'text' },
|
||||
{ key: 'style', label: '风格', type: 'text' },
|
||||
{ key: 'color_main', label: '主色', type: 'color' },
|
||||
{ key: 'color_sub', label: '副色', type: 'text' },
|
||||
{ key: 'thickness', label: '厚度', type: 'text' },
|
||||
{ key: 'version', label: '版型', type: 'text' },
|
||||
{ key: 'material', label: '材质', type: 'text' },
|
||||
{ key: 'pattern', label: '花纹', type: 'text' },
|
||||
{ key: 'sleeve_type', label: '袖型', type: 'text' },
|
||||
{ key: 'clothes_type', label: '衣长', type: 'text' },
|
||||
{ key: 'neckline_type', label: '领型', type: 'text' },
|
||||
{ key: 'formality', label: '正式程度', type: 'score' },
|
||||
{ key: 'occasions', label: '适用场合', type: 'text' },
|
||||
{ key: 'visual_impact', label: '视觉冲击力', type: 'score' },
|
||||
// 属性分组定义(对齐设计稿:基础属性 / 版型与材质 / 智能量化评估)
|
||||
const ATTR_GROUPS = [
|
||||
{
|
||||
title: '基础属性',
|
||||
attrs: [
|
||||
{ key: 'category_main', label: '大类', type: 'text' },
|
||||
{ key: 'category_sub', label: '小类', type: 'text' },
|
||||
{ key: 'style', label: '风格', type: 'text' },
|
||||
{ key: 'color_main', label: '主色', type: 'color' },
|
||||
{ key: 'color_sub', label: '副色', type: 'text' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: '版型与材质',
|
||||
attrs: [
|
||||
{ key: 'thickness', label: '厚度', type: 'text' },
|
||||
{ key: 'version', label: '版型', type: 'text' },
|
||||
{ key: 'material', label: '材质', type: 'text' },
|
||||
{ key: 'pattern', label: '花纹', type: 'text' },
|
||||
{ key: 'sleeve_type', label: '袖型', type: 'text' },
|
||||
{ key: 'clothes_type', label: '衣长', type: 'text' },
|
||||
{ key: 'neckline_type', label: '领型', type: 'text' },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: '智能量化评估',
|
||||
attrs: [
|
||||
{ key: 'formality', label: '正式程度', type: 'score' },
|
||||
{ key: 'occasions', label: '适用场合', type: 'multi' },
|
||||
{ key: 'visual_impact', label: '视觉冲击力', type: 'score' },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
// 属性快捷选项(选择面板内点选,仍支持自定义输入)
|
||||
const ATTR_OPTIONS: Record<string, string[]> = {
|
||||
category_main: ['上装', '下装', '连衣裙', '外套', '鞋', '配饰'],
|
||||
style: ['简约', '休闲', '通勤', '运动', '甜美', '复古'],
|
||||
thickness: ['薄', '适中', '厚'],
|
||||
version: ['宽松', '修身', '阔腿', '紧身', '常规合身'],
|
||||
material: ['纯棉', '牛仔布', '针织', '皮质', '羊毛', '涤纶'],
|
||||
pattern: ['纯色', '条纹', '格纹', '印花', '波点'],
|
||||
sleeve_type: ['无袖', '短袖', '长袖'],
|
||||
clothes_type: ['短款', '常规', '中长', '长款'],
|
||||
neckline_type: ['圆领', 'V领', '方领', '翻领', '高领'],
|
||||
occasions: ['休闲', '通勤', '约会', '运动', '聚会', '正式', '度假'],
|
||||
}
|
||||
|
||||
// 主色色板(名称 → 色值),供面板点选
|
||||
const COLOR_PRESETS = [
|
||||
{ name: '白色', value: '#FFFFFF' },
|
||||
{ name: '黑色', value: '#1C1C1E' },
|
||||
{ name: '灰色', value: '#8E8E93' },
|
||||
{ name: '红色', value: '#FF3B30' },
|
||||
{ name: '粉色', value: '#FF2D55' },
|
||||
{ name: '橙色', value: '#FF9500' },
|
||||
{ name: '黄色', value: '#FFCC00' },
|
||||
{ name: '绿色', value: '#34C759' },
|
||||
{ name: '蓝色', value: '#007AFF' },
|
||||
{ name: '紫色', value: '#5856D6' },
|
||||
{ name: '棕色', value: '#A2845E' },
|
||||
{ name: '米色', value: '#F5EFE0' },
|
||||
]
|
||||
|
||||
interface AttrMeta {
|
||||
key: string
|
||||
label: string
|
||||
type: string
|
||||
}
|
||||
|
||||
// 多值字段(适用场合)按分隔符拆分为标签
|
||||
function splitValues(v: string): string[] {
|
||||
if (!v) return []
|
||||
return v.split(/[、,,/|;;\s]+/).filter((s) => !!s)
|
||||
}
|
||||
|
||||
function findAttr(key: string): AttrMeta | null {
|
||||
for (const group of ATTR_GROUPS) {
|
||||
const hit = (group.attrs as AttrMeta[]).find((a) => a.key === key)
|
||||
if (hit) return hit
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// 将后端 image_process_status 映射为前端展示步骤:0=排队中 1=AI 抠图 2=智能分类
|
||||
function statusToStep(status: number): number {
|
||||
if (status === ProcessStatus.QUEUED) return 0
|
||||
@@ -35,7 +101,8 @@ function statusToStep(status: number): number {
|
||||
Page({
|
||||
data: {
|
||||
uuid: '',
|
||||
attrs: ATTRS,
|
||||
attrGroups: ATTR_GROUPS,
|
||||
colorPresets: COLOR_PRESETS,
|
||||
detail: {} as ClothesItem,
|
||||
formData: {} as ClothesItem,
|
||||
imageStatus: 0,
|
||||
@@ -44,6 +111,14 @@ Page({
|
||||
loading: true,
|
||||
editMode: false,
|
||||
notFound: false,
|
||||
// 底部属性选择面板
|
||||
sheetVisible: false,
|
||||
sheetKey: '',
|
||||
sheetLabel: '',
|
||||
sheetType: 'text',
|
||||
sheetOptions: [] as string[],
|
||||
sheetValue: '',
|
||||
sheetValues: [] as string[],
|
||||
},
|
||||
|
||||
onLoad(query: Record<string, string>) {
|
||||
@@ -124,7 +199,7 @@ Page({
|
||||
|
||||
onToggleEdit() {
|
||||
if (this.data.editMode) {
|
||||
this.setData({ editMode: false })
|
||||
this.setData({ editMode: false, sheetVisible: false })
|
||||
} else {
|
||||
this.setData({ editMode: true, formData: { ...this.data.detail } })
|
||||
}
|
||||
@@ -138,39 +213,70 @@ Page({
|
||||
this.setData({ 'formData.remark': e.detail.value })
|
||||
},
|
||||
|
||||
// 点击属性行:打开底部选择面板
|
||||
onAttrTap(e: WechatMiniprogram.TouchEvent) {
|
||||
if (!this.data.editMode) return
|
||||
const key = e.currentTarget.dataset.key as string
|
||||
const attr = ATTRS.find((a) => a.key === key)
|
||||
const attr = findAttr(key)
|
||||
if (!attr) return
|
||||
const current = (this.data.formData as any)[key] || ''
|
||||
|
||||
if (attr.type === 'score') {
|
||||
wx.showActionSheet({
|
||||
itemList: ['1', '2', '3', '4', '5'],
|
||||
success: (res) => {
|
||||
this.setData({ [`formData.${key}`]: String(res.tapIndex + 1) })
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
wx.showModal({
|
||||
title: `编辑${attr.label}`,
|
||||
editable: true,
|
||||
placeholderText: `请输入${attr.label}`,
|
||||
content: current,
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
this.setData({ [`formData.${key}`]: res.content })
|
||||
}
|
||||
},
|
||||
const current = (((this.data.formData as any)[key] || '') + '') as string
|
||||
logger.debug(LOG, '打开属性面板, key=', key, 'type=', attr.type)
|
||||
this.setData({
|
||||
sheetVisible: true,
|
||||
sheetKey: key,
|
||||
sheetLabel: attr.label,
|
||||
sheetType: attr.type,
|
||||
sheetOptions: ATTR_OPTIONS[key] || [],
|
||||
sheetValue: attr.type === 'multi' ? '' : current,
|
||||
sheetValues: attr.type === 'multi' ? splitValues(current) : [],
|
||||
})
|
||||
},
|
||||
|
||||
onSheetClose() {
|
||||
this.setData({ sheetVisible: false })
|
||||
},
|
||||
|
||||
onSheetInput(e: WechatMiniprogram.Input) {
|
||||
this.setData({ sheetValue: e.detail.value })
|
||||
},
|
||||
|
||||
// 单选快捷选项
|
||||
onSheetOptionTap(e: WechatMiniprogram.TouchEvent) {
|
||||
this.setData({ sheetValue: e.currentTarget.dataset.value as string })
|
||||
},
|
||||
|
||||
// 多选快捷选项(适用场合)
|
||||
onSheetValueTap(e: WechatMiniprogram.TouchEvent) {
|
||||
const value = e.currentTarget.dataset.value as string
|
||||
const list = this.data.sheetValues.slice()
|
||||
const idx = list.indexOf(value)
|
||||
if (idx >= 0) list.splice(idx, 1)
|
||||
else list.push(value)
|
||||
this.setData({ sheetValues: list })
|
||||
},
|
||||
|
||||
// 色板点选
|
||||
onSheetColorTap(e: WechatMiniprogram.TouchEvent) {
|
||||
this.setData({ sheetValue: e.currentTarget.dataset.name as string })
|
||||
},
|
||||
|
||||
// 评分点选
|
||||
onSheetScoreTap(e: WechatMiniprogram.TouchEvent) {
|
||||
this.setData({ sheetValue: String(e.currentTarget.dataset.value) })
|
||||
},
|
||||
|
||||
onSheetConfirm() {
|
||||
const { sheetKey, sheetType, sheetValue, sheetValues } = this.data
|
||||
if (!sheetKey) return
|
||||
const value = sheetType === 'multi' ? sheetValues.join('、') : (sheetValue || '').trim()
|
||||
logger.info(LOG, '属性更新, key=', sheetKey, 'value=', value)
|
||||
this.setData({ [`formData.${sheetKey}`]: value, sheetVisible: false })
|
||||
},
|
||||
|
||||
onSave() {
|
||||
const fd = this.data.formData as any
|
||||
const body: Record<string, any> = {}
|
||||
// 后端 ClothesUpdateByUUIDRequest.ClothesUUID 为必填(binding required),请求体需携带
|
||||
const body: Record<string, any> = { clothes_uuid: this.data.uuid }
|
||||
const fields: Array<[string, string]> = [
|
||||
['name', 'name'],
|
||||
['remark', 'remark'],
|
||||
|
||||
Reference in New Issue
Block a user