fix sku style

This commit is contained in:
Timi
2026-09-21 23:07:14 +08:00
parent 6b63b4372b
commit 0f0b3a2821
+131 -178
View File
@@ -18,84 +18,75 @@
@left-button-click="close" @left-button-click="close"
> >
<div class="popup"> <div class="popup">
<div class="products"> <div class="search-wrap">
<div class="search-wrap"> <t-input v-model="keyword" class="search" borderless placeholder="搜索产品名称或编码" />
<t-input v-model="keyword" class="search" borderless placeholder="搜索产品名称或编码" /> </div>
</div> <div class="items">
<div class="items"> <t-collapse
<t-collapse v-if="visibleProductList.length"
v-if="visibleProductList.length" v-model="expandedProductKeyList"
v-model="expandedProductKeyList" class="collapse"
class="collapse" theme="card"
theme="card" :expand-mutex="true"
:expand-mutex="true" @change="handleProductChange"
@change="handleProductChange" >
<t-collapse-panel
class="item"
v-for="(product, productIndex) in visibleProductList"
:key="getProductKey(product, productIndex)"
:value="getProductKey(product, productIndex)"
placement="bottom"
> >
<t-collapse-panel <template #header>
v-for="(product, productIndex) in visibleProductList" <div class="header">
:key="getProductKey(product, productIndex)" <t-image
:value="getProductKey(product, productIndex)" v-if="getProductPhotoURL(product)"
class="panel" :src="getProductPhotoURL(product)"
placement="bottom" :alt="product.name || '产品图片'"
> fit="cover"
<template #header> class="avatar"
<div class="product-header"> />
<t-image <div v-else class="avatar fallback" v-text="(product.name || product.code || '产').slice(0, 1)" />
v-if="getProductPhotoURL(product)" <strong class="clip-text" v-text="product.name || '未命名产品'" />
:src="getProductPhotoURL(product)"
:alt="product.name || '产品图片'"
fit="cover"
class="avatar"
/>
<div v-else class="avatar fallback" v-text="(product.name || product.code || '产').slice(0, 1)" />
<div class="product-info">
<strong v-text="product.name || '未命名产品'" />
<span v-text="`${product.code || '-'} · ${product.skuList?.length || 0} 个 SKU`" />
</div>
</div>
</template>
<div v-if="isExpandedProduct(product, productIndex)" class="selection">
<div v-if="specList.length" class="specs">
<div v-for="spec in specList" :key="spec.id || spec.name" class="spec">
<strong v-text="spec.name" />
<div class="values">
<t-button
v-for="value in enabledValues(spec)"
:key="value.id"
size="extra-small"
:theme="selectedSpecValueMap[spec.id || ''] === value.id ? 'primary' : 'default'"
:variant="selectedSpecValueMap[spec.id || ''] === value.id ? 'base' : 'outline'"
:content="value.name"
@click="selectSpecValue(spec.id || '', value.id || '')"
/>
</div>
</div>
</div>
<div v-if="matchedSku" class="sku-card">
<div class="sku-title">
<strong v-text="matchedSku.name || matchedSku.specSummary || '默认 SKU'" />
<span v-if="matchedSku.code" v-text="matchedSku.code" />
</div>
<div class="units">
<t-button
v-for="unit in saleableUnits(matchedSku)"
:key="unit.id"
size="small"
:theme="props.modelValue?.skuId === matchedSku.id && props.modelValue?.skuUnitId === unit.id ? 'primary' : 'default'"
:variant="props.modelValue?.skuId === matchedSku.id && props.modelValue?.skuUnitId === unit.id ? 'base' : 'outline'"
@click="selectUnit(matchedSku, unit.id || '')"
>
<span v-text="unit.name" />
<span v-if="unit.salePrice !== null && unit.salePrice !== undefined" class="price" v-text="`¥${formatProductAmount(unit.salePrice)}`" />
</t-button>
</div>
</div>
<div v-else class="empty" v-text="specList.length ? '请选择每个规格项的规格值' : '暂无可售 SKU'" />
</div> </div>
</t-collapse-panel> </template>
</t-collapse> <div v-if="isExpandedProduct(product, productIndex)" class="selection">
<div v-else class="empty" v-text="loading ? '正在加载可售产品' : '暂无可售产品'" /> <div v-if="specList.length" class="specs">
</div> <div v-for="spec in specList" :key="spec.id || spec.name" class="spec">
<strong v-text="spec.name" />
<div class="values">
<t-button
v-for="value in enabledValues(spec)"
:key="value.id"
size="extra-small"
:theme="selectedSpecValueMap[spec.id || ''] === value.id ? 'primary' : 'default'"
:variant="selectedSpecValueMap[spec.id || ''] === value.id ? 'base' : 'outline'"
:content="value.name"
@click="selectSpecValue(spec.id || '', value.id || '')"
/>
</div>
</div>
</div>
<div v-if="matchedSku" class="sku-card">
<div class="units">
<t-button
v-for="unit in saleableUnits(matchedSku)"
:key="unit.id"
size="small"
:theme="props.modelValue?.skuId === matchedSku.id && props.modelValue?.skuUnitId === unit.id ? 'primary' : 'default'"
:variant="props.modelValue?.skuId === matchedSku.id && props.modelValue?.skuUnitId === unit.id ? 'base' : 'outline'"
@click="selectUnit(matchedSku, unit.id || '')"
>
<span v-text="unit.name" />
<span v-if="unit.salePrice !== null && unit.salePrice !== undefined" class="price" v-text="`¥${formatProductAmount(unit.salePrice)}`" />
</t-button>
</div>
</div>
<div v-else class="empty" v-text="specList.length ? '请选择每个规格项的规格值' : '暂无可售 SKU'" />
</div>
</t-collapse-panel>
</t-collapse>
<div v-else class="empty" v-text="loading ? '正在加载可售产品' : '暂无可售产品'" />
</div> </div>
</div> </div>
</bottom-popup> </bottom-popup>
@@ -253,128 +244,90 @@ function selectUnit(sku: ProductSku, skuUnitId: string): void {
.popup { .popup {
height: 100%; height: 100%;
min-height: 0;
padding: 1rem 0; padding: 1rem 0;
overflow: hidden;
display: flex; display: flex;
overflow: hidden;
min-height: 0;
flex-direction: column; flex-direction: column;
.selection { .search-wrap {
overflow-y: auto; z-index: 1;
padding: 0 0 .75rem;
.specs { .search {
gap: 1rem; --td-input-vertical-padding: 8px 14px;
display: flex;
flex-direction: column;
.spec { margin: 0 1rem;
gap: .5rem; border: 1px solid var(--td-component-border);
display: flex;
flex-direction: column;
.values,
.units {
gap: .5rem;
display: flex;
flex-wrap: wrap;
}
}
}
.sku-card {
padding: .75rem;
background: var(--td-bg-color-secondarycontainer);
border-radius: .875rem; border-radius: .875rem;
.sku-title {
gap: .5rem;
display: flex;
align-items: baseline;
justify-content: space-between;
span {
color: var(--td-text-color-secondary);
font-size: .75rem;
}
}
.units {
gap: .5rem;
display: flex;
margin-top: .75rem;
flex-wrap: wrap;
.price {
margin-left: .25rem;
font-size: .75rem;
}
}
} }
} }
.products { .items {
height: 100%; flex: 1;
min-height: 0; min-height: 0;
display: flex; overflow-y: auto;
flex-direction: column; padding-bottom: env(safe-area-inset-bottom, 0);
.search-wrap { .collapse {
z-index: 1; margin: 0;
padding: 0 0 .75rem;
.search { .item {
--td-input-vertical-padding: 8px 14px; --td-collapse-content-padding: .25rem 1rem .75rem 1rem;
margin: 0 1rem; .header {
border: 1px solid var(--td-component-border); gap: .75rem;
border-radius: .875rem;
}
}
.items {
flex: 1;
min-height: 0;
overflow-y: auto;
padding-bottom: env(safe-area-inset-bottom, 0);
.collapse {
margin: 0;
}
.product-header {
gap: .75rem;
display: flex;
min-width: 0;
align-items: center;
.avatar {
width: 3.5rem;
height: 3.5rem;
flex: 0 0 auto;
}
.product-info {
gap: .25rem;
display: flex; display: flex;
min-width: 0; min-width: 0;
flex: 1; align-items: center;
flex-direction: column;
strong, .avatar {
span { flex: 0 0 auto;
overflow: hidden; width: 2.5rem;
white-space: nowrap; height: 2.5rem;
text-overflow: ellipsis; border-radius: .75rem !important;
}
span {
color: var(--td-text-color-secondary);
font-size: .75rem;
} }
} }
&:active { .selection {
opacity: .7; overflow-y: auto;
.specs {
gap: .5rem;
display: flex;
flex-direction: column;
.spec {
gap: .5rem;
display: flex;
flex-direction: column;
.values,
.units {
gap: .5rem;
display: flex;
flex-wrap: wrap;
}
}
}
.sku-card {
padding: .5rem;
border: 1px dashed var(--td-brand-color);
margin-top: .5rem;
border-radius: .875rem;
.units {
gap: .5rem;
display: flex;
flex-wrap: wrap;
.price {
margin-left: .25rem;
font-size: .75rem;
}
}
}
} }
} }
} }