fix ProductSkuEditor.vue style

This commit is contained in:
Timi
2026-09-07 13:26:46 +08:00
parent 62cedb406a
commit 7c685c856e
2 changed files with 144 additions and 232 deletions
+2 -45
View File
@@ -136,7 +136,7 @@
/> />
</template> </template>
</t-cell> </t-cell>
<t-cell title="生成"> <t-cell title="生成 SKU">
<template #note> <template #note>
<t-button <t-button
theme="primary" theme="primary"
@@ -292,7 +292,7 @@ const skuCombinationCount = computed(() => {
return valueCountList.reduce((total, count) => total * count, 1); return valueCountList.reduce((total, count) => total * count, 1);
}); });
const canGenerateSku = computed(() => 0 < skuCombinationCount.value); const canGenerateSku = computed(() => 0 < skuCombinationCount.value);
const generateSkuButtonText = computed(() => `根据规格组合生成 SKU(${skuCombinationCount.value} 个)`); const generateSkuButtonText = computed(() => `根据规格组合生成(${skuCombinationCount.value} 个)`);
const specValueDraftMap = reactive<Record<string, string>>({}); const specValueDraftMap = reactive<Record<string, string>>({});
const unitEditorVisible = ref(false); const unitEditorVisible = ref(false);
const editingSku = ref<SkuForm>(); const editingSku = ref<SkuForm>();
@@ -1107,49 +1107,6 @@ onUnmounted(() => navBarStore.clearRight());
} }
} }
.sku-list {
overflow: hidden;
}
.card-header,
.value-row {
gap: .5rem;
display: flex;
align-items: center;
}
.card-header {
padding: 0 .75rem .5rem;
justify-content: space-between;
}
.value-list {
gap: .5rem;
display: flex;
padding: .25rem .75rem .75rem;
flex-direction: column;
}
.small-button {
align-self: flex-start;
}
.sku-toolbar {
gap: .5rem;
display: flex;
padding: 0 1rem .75rem;
color: var(--td-text-color-secondary);
align-items: center;
justify-content: space-between;
.sku-actions {
gap: .5rem;
display: flex;
align-items: center;
justify-content: flex-end;
flex-wrap: wrap;
}
}
.file-input { .file-input {
display: none; display: none;
} }
+142 -187
View File
@@ -3,15 +3,14 @@
<t-cell role="button" tabindex="0" arrow @click="openEditor"> <t-cell role="button" tabindex="0" arrow @click="openEditor">
<template #title> <template #title>
<div class="title"> <div class="title">
<span class="code gray" v-text="sku.code" /> <t-tag size="small" variant="light" :content="sku.code"/>
<strong class="clip-text" v-text="skuTitle" /> <strong class="title clip-text" v-text="skuTitle" />
<t-tag v-if="sku.id" size="small" variant="light-outline" :content="sku.status === 'ACTIVE' ? '已建立' : '已停用'" />
</div> </div>
</template> </template>
<template #note> <template #note>
<t-tag <t-tag
size="small" size="small"
variant="light-outline" variant="light"
:theme="sku.status === 'ACTIVE' ? 'success' : 'warning'" :theme="sku.status === 'ACTIVE' ? 'success' : 'warning'"
:content="sku.status === 'ACTIVE' ? '启用' : '停用'" :content="sku.status === 'ACTIVE' ? '启用' : '停用'"
/> />
@@ -22,6 +21,8 @@
v-for="entry in skuSpecEntries" v-for="entry in skuSpecEntries"
:key="`${entry.specName}-${entry.valueName}`" :key="`${entry.specName}-${entry.valueName}`"
size="small" size="small"
theme="primary"
variant="light-outline"
:content="entry.valueName" :content="entry.valueName"
/> />
<t-tag <t-tag
@@ -33,7 +34,6 @@
<t-tag <t-tag
v-for="unit in sku.unitList" v-for="unit in sku.unitList"
:key="unit.clientKey" :key="unit.clientKey"
class="description-tag"
size="small" size="small"
:content="unit.name || '未命名单位'" :content="unit.name || '未命名单位'"
/> />
@@ -59,28 +59,28 @@
@right-button-click="closeEditor" @right-button-click="closeEditor"
> >
<div class="sku-popup"> <div class="sku-popup">
<div class="sku-popup-header"> <div class="header">
<div class="sku-heading"> <span class="index" v-text="String(props.skuIndex + 1).padStart(2, '0')" />
<span class="sku-index" v-text="String(props.skuIndex + 1).padStart(2, '0')" /> <strong v-text="skuTitle" />
<strong v-text="skuTitle" />
</div>
</div> </div>
<div class="hero">
<div class="sku-spec-panel"> <div class="title">
<div class="section-title">
<strong>销售规格</strong> <strong>销售规格</strong>
<span v-if="sku.specSummary" v-text="`摘要:${sku.specSummary}`" /> <span v-if="sku.specSummary" v-text="`摘要:${sku.specSummary}`" />
</div> </div>
<div v-if="skuSpecEntries.length" class="sku-spec-list"> <div v-if="skuSpecEntries.length" class="spec-list">
<div v-for="entry in skuSpecEntries" :key="`${entry.specName}-${entry.valueName}`" class="sku-spec-item"> <div
<span class="spec-name" v-text="entry.specName" /> v-for="entry in skuSpecEntries"
<strong v-text="entry.valueName" /> :key="`${entry.specName}-${entry.valueName}`"
class="item"
>
<span class="name" v-text="entry.specName" />
<strong class="value clip-text" v-text="entry.valueName" />
</div> </div>
</div> </div>
<div v-else class="sku-spec-empty" v-text="props.specList.length ? '请重新生成 SKU 明细以匹配规格项和规格值' : '无多规格产品,使用默认 SKU'" /> <div v-else class="sku-spec-empty" v-text="props.specList.length ? '请重新生成 SKU 明细以匹配规格项和规格值' : '无多规格产品,使用默认 SKU'" />
</div> </div>
<t-form class="form" label-align="left" label-width="5rem">
<t-form class="sku-form" label-align="left" label-width="5rem">
<t-form-item label="SKU 编码" required-mark help="门店内唯一;已有 SKU 修改失败时请保留原编码"> <t-form-item label="SKU 编码" required-mark help="门店内唯一;已有 SKU 修改失败时请保留原编码">
<t-input v-model.trim="sku.code" borderless maxlength="64" placeholder="如 TSHIRT-RED-M" /> <t-input v-model.trim="sku.code" borderless maxlength="64" placeholder="如 TSHIRT-RED-M" />
</t-form-item> </t-form-item>
@@ -90,10 +90,6 @@
<t-form-item label="SKU 条码"> <t-form-item label="SKU 条码">
<t-input v-model.trim="sku.barcode" borderless maxlength="64" placeholder="选填" /> <t-input v-model.trim="sku.barcode" borderless maxlength="64" placeholder="选填" />
</t-form-item> </t-form-item>
<div class="section-title setting-title">
<strong>库存设置</strong>
<span>每条 SKU 明细独立生效</span>
</div>
<t-form-item label="库存管理" content-align="right"> <t-form-item label="库存管理" content-align="right">
<t-switch v-model="sku.stockEnabled" size="small" :disabled="props.productType === 'SERVICE'" /> <t-switch v-model="sku.stockEnabled" size="small" :disabled="props.productType === 'SERVICE'" />
</t-form-item> </t-form-item>
@@ -109,28 +105,39 @@
<t-form-item label="备注"> <t-form-item label="备注">
<t-input v-model.trim="sku.remark" borderless maxlength="255" placeholder="选填" /> <t-input v-model.trim="sku.remark" borderless maxlength="255" placeholder="选填" />
</t-form-item> </t-form-item>
<div class="photo-wrap">
<photo-scroller
:model-value="photoUrlList"
v-model:photo-items="sku.photoItemList"
title="SKU 图片(选填)"
:edit-mode="true"
:upload="uploadPhotoList"
/>
</div>
</t-form> </t-form>
<div class="unit">
<photo-scroller <div class="header">
:model-value="photoUrlList"
v-model:photo-items="sku.photoItemList"
title="SKU 图片(选填)"
:edit-mode="true"
:upload="uploadPhotoList"
/>
<div class="unit-section">
<div class="unit-heading">
<strong>销售单位</strong> <strong>销售单位</strong>
<span>采购、销售和库存操作共用</span> <span>采购、销售和库存操作共用</span>
</div> </div>
<div class="unit-summary-list"> <div class="items">
<div v-for="unit in sku.unitList" :key="unit.clientKey" class="unit-summary"> <div
v-for="unit in sku.unitList"
:key="unit.clientKey"
class="item"
>
<strong v-text="unit.name || '未命名单位'" /> <strong v-text="unit.name || '未命名单位'" />
<span v-text="getUnitSummary(unit)" /> <span v-text="getUnitSummary(unit)" />
</div> </div>
</div> </div>
<t-button class="unit-button" variant="dashed" size="small" content="配置销售单位" @click="requestConfigureUnits" /> <t-button
class="cell-button"
variant="dashed"
theme="light"
size="small"
content="配置销售单位"
@click="requestConfigureUnits"
/>
</div> </div>
</div> </div>
</bottom-popup> </bottom-popup>
@@ -199,65 +206,39 @@ function getUnitSummary(unit: ProductSkuUnitForm): string {
.sku-cell { .sku-cell {
.title { .title {
}
.cell-title {
gap: .5rem; gap: .5rem;
min-width: 0;
display: flex; display: flex;
align-items: center;
justify-content: space-between;
strong { .title {
min-width: 0; font-size: .875rem;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
} }
} }
.description-tags { .tags {
gap: .375rem; gap: .5rem;
margin-top: .5rem;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
} }
.description-tag {
max-width: 100%;
}
.delete-action {
width: 4.5rem;
height: 100%;
border-radius: 0;
}
} }
.sku-popup { .sku-popup {
max-height: 100%;
padding: 1rem 0 calc(1rem + env(safe-area-inset-bottom, 0px)); padding: 1rem 0 calc(1rem + env(safe-area-inset-bottom, 0px));
max-height: 100%;
overflow-y: auto; overflow-y: auto;
.sku-popup-header { .header {
gap: .5rem; gap: .5rem;
display: flex; display: flex;
padding: 0 1rem .75rem; padding: 0 1rem .75rem;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
}
.sku-heading { .index {
gap: .5rem; flex: none;
min-width: 0;
display: flex;
align-items: center;
.sku-index {
width: 1.75rem; width: 1.75rem;
height: 1.75rem; height: 1.75rem;
color: var(--td-brand-color); color: var(--td-brand-color);
flex: none;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -268,139 +249,113 @@ function getUnitSummary(unit: ProductSkuUnitForm): string {
} }
} }
.sku-spec-panel { .hero {
margin: 0 .75rem .75rem; margin: 0 .75rem .75rem;
padding: .75rem; padding: .75rem;
background: var(--td-bg-color-secondarycontainer); background: var(--td-bg-color-secondarycontainer);
border-radius: .875rem; border-radius: .875rem;
}
.section-title { .title {
gap: .5rem; gap: .5rem;
display: flex; display: flex;
align-items: baseline; align-items: baseline;
justify-content: space-between; justify-content: space-between;
span { span {
color: var(--td-text-color-secondary); color: var(--td-text-color-secondary);
font-size: .75rem; font-size: .75rem;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
}
}
.spec-list {
gap: .5rem;
display: grid;
margin-top: .625rem;
grid-template-columns: repeat(3, minmax(0, 1fr));
.item {
gap: .375rem;
min-width: 0;
display: flex;
padding: .25rem .5rem;
align-items: baseline;
background: var(--td-bg-color-container);
border-radius: .625rem;
.name {
flex: none;
color: var(--td-text-color-secondary);
font-size: .75rem;
}
.value {
font-size: .875rem;
}
}
} }
} }
.sku-spec-list { .form {
gap: .5rem;
display: grid;
margin-top: .625rem;
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.sku-spec-item { .photo-wrap {
gap: .375rem; margin: .5rem 0 0 .75rem;
min-width: 0;
display: flex;
padding: .5rem .625rem;
align-items: baseline;
background: var(--td-bg-color-container);
border-radius: .625rem;
.spec-name {
color: var(--td-text-color-secondary);
font-size: .75rem;
flex: none;
}
strong {
min-width: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
} }
} }
.sku-spec-empty { .unit {
margin-top: .5rem; margin-top: 1rem;
color: var(--td-text-color-secondary);
font-size: .75rem;
}
.sku-form { .header {
margin: 0 .75rem; gap: .5rem;
display: flex;
padding: .75rem 1rem .5rem;
align-items: baseline;
justify-content: space-between;
.setting-title { span {
margin-top: .5rem; color: var(--td-text-color-secondary);
padding: .75rem 0 .25rem; font-size: .75rem;
border-top: 1px solid var(--td-component-border); text-align: right;
} }
}
:deep(.t-form-item) {
padding-right: 0;
padding-left: 0;
}
:deep(.photo-scroller) {
margin: .5rem .75rem 0;
}
.unit-section {
margin-top: .75rem;
border-top: 1px solid var(--td-component-border);
}
.unit-heading {
gap: .5rem;
display: flex;
padding: .75rem 1rem .5rem;
align-items: baseline;
justify-content: space-between;
span {
color: var(--td-text-color-secondary);
font-size: .75rem;
text-align: right;
}
}
.unit-summary-list {
gap: .5rem;
display: flex;
padding: 0 1rem .5rem;
flex-direction: column;
}
.unit-summary {
gap: .5rem;
min-width: 0;
display: flex;
padding: .625rem .75rem;
align-items: center;
background: var(--td-bg-color-secondarycontainer);
border-radius: .75rem;
justify-content: space-between;
strong {
max-width: 5rem;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
} }
span { .items {
min-width: 0; gap: .5rem;
color: var(--td-text-color-secondary); display: flex;
font-size: .75rem; padding: 0 1rem .5rem;
text-align: right; flex-direction: column;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.unit-button { .item {
margin: 0 1rem .75rem; gap: .5rem;
min-width: 0;
display: flex;
padding: .625rem .75rem;
align-items: center;
background: var(--td-bg-color-secondarycontainer);
border-radius: .75rem;
justify-content: space-between;
strong {
max-width: 5rem;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
span {
min-width: 0;
color: var(--td-text-color-secondary);
font-size: .75rem;
text-align: right;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
} }
} }