update product edit

This commit is contained in:
Timi
2026-10-05 15:37:40 +08:00
parent c8e0c554b3
commit f643656eb4
9 changed files with 158 additions and 38 deletions
+15
View File
@@ -62,6 +62,10 @@ async function disable(id: string): Promise<void> {
await axios.post(`${PRODUCT_URI}/disable`, undefined, { params: { id } }); await axios.post(`${PRODUCT_URI}/disable`, undefined, { params: { id } });
} }
async function remove(id: string): Promise<void> {
await axios.post(`${PRODUCT_URI}/delete`, undefined, { params: { id } });
}
async function skuDetail(id: string): Promise<ProductSku> { async function skuDetail(id: string): Promise<ProductSku> {
return await axios.post(`${PRODUCT_URI}/sku/detail`, undefined, { params: { id } }); return await axios.post(`${PRODUCT_URI}/sku/detail`, undefined, { params: { id } });
} }
@@ -86,10 +90,18 @@ async function specCreate(spec: ProductSpec): Promise<string> {
return await axios.post(`${PRODUCT_URI}/spec/create`, spec); return await axios.post(`${PRODUCT_URI}/spec/create`, spec);
} }
async function specUpdate(spec: ProductSpec): Promise<void> {
await axios.post(`${PRODUCT_URI}/spec/update`, spec);
}
async function specValueCreate(value: ProductSpecValue): Promise<string> { async function specValueCreate(value: ProductSpecValue): Promise<string> {
return await axios.post(`${PRODUCT_URI}/spec/value/create`, value); return await axios.post(`${PRODUCT_URI}/spec/value/create`, value);
} }
async function specValueUpdate(value: ProductSpecValue): Promise<void> {
await axios.post(`${PRODUCT_URI}/spec/value/update`, value);
}
async function sellableList(page: ProductPage): Promise<Product[]> { async function sellableList(page: ProductPage): Promise<Product[]> {
return await axios.post(`${PRODUCT_URI}/sellable/list`, withCurrentStoreId(page)); return await axios.post(`${PRODUCT_URI}/sellable/list`, withCurrentStoreId(page));
} }
@@ -155,13 +167,16 @@ export default {
create, create,
update, update,
disable, disable,
remove,
skuDetail, skuDetail,
skuCreate, skuCreate,
skuUpdate, skuUpdate,
skuDisable, skuDisable,
specList, specList,
specCreate, specCreate,
specUpdate,
specValueCreate, specValueCreate,
specValueUpdate,
sellableList, sellableList,
stockList, stockList,
stockProductList, stockProductList,
@@ -124,7 +124,15 @@
</t-form-item> </t-form-item>
</t-form> </t-form>
<t-popup v-model="pickerVisible" placement="bottom"> <t-popup v-model="pickerVisible" placement="bottom">
<t-date-time-picker v-model="draftTime" format="YYYY-MM-DD HH:mm" :mode="['date', 'minute']" title="履约时间" @cancel="pickerVisible = false" @confirm="confirmTime" /> <t-date-time-picker
v-if="pickerVisible"
v-model="draftTime"
format="YYYY-MM-DD HH:mm"
:mode="['date', 'minute']"
title="履约时间"
@cancel="pickerVisible = false"
@confirm="confirmTime"
/>
</t-popup> </t-popup>
<t-popup v-model="unitPickerVisible" placement="bottom"> <t-popup v-model="unitPickerVisible" placement="bottom">
<t-picker v-model="unitPickerDraft" :columns="unitPickerOptions" title="选择实际履约单位" @cancel="unitPickerVisible = false" @confirm="confirmUnitPicker" /> <t-picker v-model="unitPickerDraft" :columns="unitPickerOptions" title="选择实际履约单位" @cancel="unitPickerVisible = false" @confirm="confirmUnitPicker" />
+27
View File
@@ -184,6 +184,7 @@ const actionList = computed<NavBarAction[]>(() => {
if (product.value?.status === "ACTIVE") { if (product.value?.status === "ACTIVE") {
list.push({ key: "disable", text: "停用产品", icon: "close", theme: "danger", action: disable }); list.push({ key: "disable", text: "停用产品", icon: "close", theme: "danger", action: disable });
} }
list.push({ key: "remove", text: "移除产品", icon: "delete", theme: "danger", action: remove });
} }
return list; return list;
}); });
@@ -271,6 +272,32 @@ function disable(): void {
}); });
} }
function remove(): void {
const id = product.value?.id;
if (!id) {
return;
}
const dialog = DialogPlugin.confirm({
title: "移除产品",
content: "仅可移除没有订单、履约、库存流水、配置引用和库存余额的产品。确定提交移除?",
cancelBtn: "取消",
confirmBtn: { content: "移除", theme: "danger" },
onConfirm: async () => {
try {
await ProductAPI.remove(id);
emitListDataChanged(listDataEventKeys.productChanged, id);
emitListDataChanged(listDataEventKeys.productStockChanged, id);
Message.success("产品已移除");
await router.replace("/management/products");
} catch (error) {
Message.error(getErrorMessage(error, "产品移除失败"));
} finally {
dialog.destroy();
}
}
});
}
onMounted(async () => { onMounted(async () => {
navBarStore.clearRight(); navBarStore.clearRight();
navBarStore.setCustomRightVisible(actionList.value.length > 0); navBarStore.setCustomRightVisible(actionList.value.length > 0);
+78 -30
View File
@@ -66,7 +66,6 @@
v-model="spec.name" v-model="spec.name"
borderless borderless
maxlength="32" maxlength="32"
:readonly="!!spec.id"
placeholder="如 颜色、尺寸" placeholder="如 颜色、尺寸"
/> />
<t-button <t-button
@@ -85,10 +84,11 @@
:key="value.clientKey" :key="value.clientKey"
class="tag" class="tag"
variant="light-outline" variant="light-outline"
:content="value.name"
closable closable
@close="removeSpecValue(spec, spec.valueList.indexOf(value))" @close="removeSpecValue(spec, spec.valueList.indexOf(value))"
/> >
<t-input v-model.trim="value.name" class="value-name" borderless maxlength="32" />
</t-tag>
</div> </div>
</t-form-item> </t-form-item>
<t-form-item label="规格值" label-width="3.5rem"> <t-form-item label="规格值" label-width="3.5rem">
@@ -185,6 +185,7 @@
<product-sku-unit-batch-editor <product-sku-unit-batch-editor
v-model="batchUnitEditorVisible" v-model="batchUnitEditorVisible"
v-model:unit-list="batchUnitList" v-model:unit-list="batchUnitList"
v-model:base-unit-migration-ratio-text="batchBaseUnitMigrationRatioText"
:product-type="form.productType" :product-type="form.productType"
:sku-count="form.skuList.length" :sku-count="form.skuList.length"
@apply="applyBatchUnitTemplate" @apply="applyBatchUnitTemplate"
@@ -306,6 +307,7 @@ const unitEditorVisible = ref(false);
const editingSku = ref<SkuForm>(); const editingSku = ref<SkuForm>();
const batchUnitEditorVisible = ref(false); const batchUnitEditorVisible = ref(false);
const batchUnitList = ref<UnitForm[]>([]); const batchUnitList = ref<UnitForm[]>([]);
const batchBaseUnitMigrationRatioText = ref("");
const removedSkuKeySet = new Set<string>(); const removedSkuKeySet = new Set<string>();
const removedSkuMap = new Map<string, SkuForm>(); const removedSkuMap = new Map<string, SkuForm>();
@@ -326,6 +328,7 @@ function createUnit(unit?: Partial<ProductSkuUnit>, defaultName = "件"): UnitFo
function createSku(sku?: Partial<ProductSku>): SkuForm { function createSku(sku?: Partial<ProductSku>): SkuForm {
const sourceUnitList = sku?.unitList || []; const sourceUnitList = sku?.unitList || [];
const originalBaseUnitId = sourceUnitList.find(unit => unit.isBase)?.id;
const photoItemList = (sku?.attachmentList || []).filter(item => !!item.id).map(item => ({ const photoItemList = (sku?.attachmentList || []).filter(item => !!item.id).map(item => ({
attachment: item, attachment: item,
attachType: item.attachType || "PHOTO", attachType: item.attachType || "PHOTO",
@@ -344,6 +347,8 @@ function createSku(sku?: Partial<ProductSku>): SkuForm {
status: sku?.status || "ACTIVE", status: sku?.status || "ACTIVE",
minStockQuantityText: sku?.minStockQuantity === null || sku?.minStockQuantity === undefined ? "" : String(sku.minStockQuantity), minStockQuantityText: sku?.minStockQuantity === null || sku?.minStockQuantity === undefined ? "" : String(sku.minStockQuantity),
unitList: sourceUnitList.length ? sourceUnitList.map(unit => createUnit(unit)) : [createUnit({ isBase: true, baseQuantityPerUnit: "1" })], unitList: sourceUnitList.length ? sourceUnitList.map(unit => createUnit(unit)) : [createUnit({ isBase: true, baseQuantityPerUnit: "1" })],
originalBaseUnitId,
baseUnitMigrationRatioText: "",
photoItemList photoItemList
}; };
} }
@@ -354,7 +359,17 @@ function createSpec(spec?: Partial<ProductSpec>): SpecForm {
id: spec?.id, id: spec?.id,
clientKey: window.crypto.randomUUID(), clientKey: window.crypto.randomUUID(),
name: spec?.name || "", name: spec?.name || "",
valueList: (spec?.valueList || []).map(value => ({ ...value, id: value.id, clientKey: window.crypto.randomUUID(), name: value.name || "", enabled: value.enabled ?? true })) originalName: spec?.name || "",
originalSort: spec?.sort,
valueList: (spec?.valueList || []).map(value => ({
...value,
id: value.id,
clientKey: window.crypto.randomUUID(),
name: value.name || "",
originalName: value.name || "",
originalSort: value.sort,
enabled: value.enabled ?? true
}))
}; };
} }
@@ -385,7 +400,7 @@ function addSpecValue(spec: SpecForm): void {
Message.warning("同一规格项的规格值不能重复"); Message.warning("同一规格项的规格值不能重复");
return; return;
} }
spec.valueList.push({ clientKey: window.crypto.randomUUID(), name, enabled: true }); spec.valueList.push({ clientKey: window.crypto.randomUUID(), name, originalName: name, originalSort: spec.valueList.length, enabled: true });
specValueDraftMap[spec.clientKey] = ""; specValueDraftMap[spec.clientKey] = "";
} }
@@ -417,6 +432,7 @@ function openBatchUnitEditor(): void {
return; return;
} }
batchUnitList.value = sourceSku.unitList.map(unit => ({ ...unit, id: undefined, skuId: undefined, clientKey: window.crypto.randomUUID() })); batchUnitList.value = sourceSku.unitList.map(unit => ({ ...unit, id: undefined, skuId: undefined, clientKey: window.crypto.randomUUID() }));
batchBaseUnitMigrationRatioText.value = "";
batchUnitEditorVisible.value = true; batchUnitEditorVisible.value = true;
} }
@@ -426,16 +442,10 @@ function closeBatchUnitEditor(): void {
function applyBatchUnitTemplate(): void { function applyBatchUnitTemplate(): void {
const templateList = batchUnitList.value; const templateList = batchUnitList.value;
for (const sku of form.skuList) {
const templateNameSet = new Set(templateList.map(unit => unit.name.trim()));
if (sku.unitList.some(unit => !!unit.id && !templateNameSet.has(unit.name.trim()))) {
Message.warning("统一配置不能删除或重命名已保存单位,请在 SKU 明细中停售");
return;
}
}
form.skuList.forEach(sku => { form.skuList.forEach(sku => {
const oldUnitList = sku.unitList; const oldUnitList = sku.unitList;
const oldUnitMap = new Map(oldUnitList.filter(unit => !!unit.id).map(unit => [unit.name.trim(), unit])); const oldUnitMap = new Map(oldUnitList.filter(unit => !!unit.id).map(unit => [unit.name.trim(), unit]));
const oldBaseUnit = oldUnitList.find(unit => unit.isBase);
sku.unitList = templateList.map((unit, unitIndex) => ({ sku.unitList = templateList.map((unit, unitIndex) => ({
...unit, ...unit,
id: oldUnitMap.get(unit.name.trim())?.id, id: oldUnitMap.get(unit.name.trim())?.id,
@@ -443,6 +453,10 @@ function applyBatchUnitTemplate(): void {
clientKey: window.crypto.randomUUID(), clientKey: window.crypto.randomUUID(),
sort: unitIndex sort: unitIndex
})); }));
const newBaseUnit = sku.unitList.find(unit => unit.isBase);
if (oldBaseUnit?.id && newBaseUnit && oldBaseUnit.id !== newBaseUnit.id) {
sku.baseUnitMigrationRatioText = batchBaseUnitMigrationRatioText.value;
}
}); });
Message.success(`已为 ${form.skuList.length} 个 SKU 统一配置销售单位`); Message.success(`已为 ${form.skuList.length} 个 SKU 统一配置销售单位`);
} }
@@ -452,7 +466,7 @@ function removeSku(index: number): void {
if (!sku) { if (!sku) {
return; return;
} }
if (form.skuList.length < 2) { if (isCreateMode.value && form.skuList.length < 2) {
Message.warning("产品至少需要一个 SKU"); Message.warning("产品至少需要一个 SKU");
return; return;
} }
@@ -463,7 +477,7 @@ function removeSku(index: number): void {
} }
form.skuList.splice(index, 1); form.skuList.splice(index, 1);
if (sku.id) { if (sku.id) {
Message.success("SKU 已移除,保存后将停用"); Message.success("SKU 已移除,保存后由后端检查引用并处理");
} }
} }
@@ -867,7 +881,7 @@ function validate(): boolean {
return false; return false;
} }
} }
if (!form.skuList.length) { if (isCreateMode.value && !form.skuList.length) {
Message.warning("至少需要一个 SKU"); Message.warning("至少需要一个 SKU");
return false; return false;
} }
@@ -929,6 +943,16 @@ function validate(): boolean {
Message.warning("每个 SKU 必须且只能有一个基础单位"); Message.warning("每个 SKU 必须且只能有一个基础单位");
return false; return false;
} }
const selectedBaseUnit = sku.unitList.find(unit => unit.isBase);
const isBaseUnitChanged = !!sku.originalBaseUnitId && selectedBaseUnit?.id !== sku.originalBaseUnitId;
if (isBaseUnitChanged && !/^\d+(?:\.\d{1,6})?$/.test(sku.baseUnitMigrationRatioText.trim())) {
Message.warning("切换基础单位时,请填写有效的新旧基础单位换算比例,最多六位小数");
return false;
}
if (isBaseUnitChanged && !(0 < Number(sku.baseUnitMigrationRatioText))) {
Message.warning("新旧基础单位换算比例必须大于 0");
return false;
}
} }
return true; return true;
} }
@@ -958,7 +982,14 @@ function buildSkuPayload(sku: SkuForm, index: number): ProductSku {
allowPurchase: form.productType === "SERVICE" ? false : !!unit.allowPurchase, allowPurchase: form.productType === "SERVICE" ? false : !!unit.allowPurchase,
allowSale: !!unit.allowSale, allowSale: !!unit.allowSale,
sort: unitIndex sort: unitIndex
})) })),
baseUnitMigrationRequest: sku.id && sku.originalBaseUnitId && sku.unitList.find(unit => unit.isBase)?.id !== sku.originalBaseUnitId
? {
targetUnitId: sku.unitList.find(unit => unit.isBase)?.id,
targetUnitName: sku.unitList.find(unit => unit.isBase)?.name.trim(),
oldToNewBaseRatio: sku.baseUnitMigrationRatioText.trim()
}
: undefined
}; };
} }
@@ -973,11 +1004,18 @@ function buildProductPayload(skuList?: ProductSku[], includeSpecList = false): P
status: form.status, status: form.status,
remark: form.remark?.trim() || null, remark: form.remark?.trim() || null,
attachmentList: buildAttachmentList(), attachmentList: buildAttachmentList(),
specList: includeSpecList ? form.specList.map(spec => ({ specList: includeSpecList ? form.specList.map((spec, specIndex) => ({
...spec, id: spec.id,
productId: form.id, productId: form.id,
name: spec.name.trim(), name: spec.name.trim(),
valueList: spec.valueList.map(value => ({ ...value, name: value.name.trim() })) sort: specIndex,
valueList: spec.valueList.map((value, valueIndex) => ({
id: value.id,
specId: spec.id,
name: value.name.trim(),
enabled: value.enabled !== false,
sort: valueIndex
}))
})) : undefined, })) : undefined,
skuList skuList
}; };
@@ -987,11 +1025,23 @@ async function syncSpecs(productId: string): Promise<void> {
for (const [specIndex, spec] of form.specList.entries()) { for (const [specIndex, spec] of form.specList.entries()) {
if (!spec.id) { if (!spec.id) {
spec.id = await ProductAPI.specCreate({ productId, name: spec.name.trim(), sort: specIndex }); spec.id = await ProductAPI.specCreate({ productId, name: spec.name.trim(), sort: specIndex });
spec.originalName = spec.name.trim();
spec.originalSort = specIndex;
} else if (spec.name.trim() !== spec.originalName || specIndex !== spec.originalSort) {
await ProductAPI.specUpdate({ id: spec.id, productId, name: spec.name.trim(), sort: specIndex });
spec.originalName = spec.name.trim();
spec.originalSort = specIndex;
} }
for (const [valueIndex, value] of spec.valueList.entries()) { for (const [valueIndex, value] of spec.valueList.entries()) {
if (!value.id) { if (!value.id) {
value.specId = spec.id; value.specId = spec.id;
value.id = await ProductAPI.specValueCreate({ specId: spec.id, name: value.name.trim(), enabled: value.enabled !== false, sort: valueIndex }); value.id = await ProductAPI.specValueCreate({ specId: spec.id, name: value.name.trim(), enabled: value.enabled !== false, sort: valueIndex });
value.originalName = value.name.trim();
value.originalSort = valueIndex;
} else if (value.name.trim() !== value.originalName || valueIndex !== value.originalSort) {
await ProductAPI.specValueUpdate({ id: value.id, specId: spec.id, name: value.name.trim(), enabled: value.enabled !== false, sort: valueIndex });
value.originalName = value.name.trim();
value.originalSort = valueIndex;
} }
} }
} }
@@ -1018,23 +1068,17 @@ async function save(): Promise<void> {
await syncSpecs(productId!); await syncSpecs(productId!);
normalizeSkuSpecValueIds(); normalizeSkuSpecValueIds();
const latest = await ProductAPI.detail(productId!); const latest = await ProductAPI.detail(productId!);
const previousSkuIdSet = new Set((latest.skuList || []).map(sku => sku.id).filter((id): id is string => !!id));
if (form.specList.length) { if (form.specList.length) {
const defaultSku = latest.skuList?.find(sku => !sku.specValueIdList?.length); const defaultSku = latest.skuList?.find(sku => !sku.specValueIdList?.length);
if (defaultSku?.id && form.skuList[0] && !form.skuList[0].id) { if (defaultSku?.id && form.skuList[0] && !form.skuList[0].id) {
form.skuList[0].id = defaultSku.id; form.skuList[0].id = defaultSku.id;
} }
generateSkuList(latest.skuList || [], true); generateSkuList(latest.skuList || [], true);
} else if (!form.skuList.length) { } else if (form.skuList[0] && !form.skuList[0].id && latest.skuList?.[0]) {
form.skuList = [createSku(latest.skuList?.[0])];
} else if (!form.skuList[0]?.id && latest.skuList?.[0]) {
form.skuList[0].id = latest.skuList[0].id; form.skuList[0].id = latest.skuList[0].id;
} }
const payload = buildProductPayload(form.skuList.map(buildSkuPayload)); const payload = buildProductPayload(form.skuList.map(buildSkuPayload));
await ProductAPI.update(payload); await ProductAPI.update(payload);
const retainedSkuIdSet = new Set(form.skuList.map(sku => sku.id).filter((id): id is string => !!id));
const disabledSkuIdList = [...previousSkuIdSet].filter(id => !retainedSkuIdSet.has(id));
await Promise.all(disabledSkuIdList.map(async skuId => await ProductAPI.skuDisable(skuId)));
emitListDataChanged(listDataEventKeys.productChanged, productId); emitListDataChanged(listDataEventKeys.productChanged, productId);
emitListDataChanged(listDataEventKeys.productStockChanged, productId); emitListDataChanged(listDataEventKeys.productStockChanged, productId);
Message.success(isCreateMode.value ? "产品已创建" : "产品已保存"); Message.success(isCreateMode.value ? "产品已创建" : "产品已保存");
@@ -1173,12 +1217,16 @@ onUnmounted(() => navBarStore.clearRight());
} }
} }
.tags { .tags {
gap: .5rem; gap: .5rem;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
.value-name {
width: 5rem;
} }
} }
}
.add { .add {
--td-button-border-radius: 1rem; --td-button-border-radius: 1rem;
@@ -34,7 +34,7 @@
</t-cell> </t-cell>
<template #right> <template #right>
<t-button class="delete-action swipe-cell-button" theme="danger" @click.stop="requestRemove"> <t-button class="delete-action swipe-cell-button" theme="danger" @click.stop="requestRemove">
停用 移除
</t-button> </t-button>
</template> </template>
</t-swipe-cell> </t-swipe-cell>
@@ -14,6 +14,9 @@
<div class="editor-context"> <div class="editor-context">
<strong>批量配置销售单位</strong> <strong>批量配置销售单位</strong>
<span v-text="`以下单位将应用到全部 ${props.skuCount} 个 SKU 明细`" /> <span v-text="`以下单位将应用到全部 ${props.skuCount} 个 SKU 明细`" />
<t-form-item label="基础单位换算比例" help="切换已有 SKU 的基础单位时填写:1 个旧基础单位等于多少个新基础单位;最多六位小数">
<t-input v-model.trim="baseUnitMigrationRatioText" type="number" align="right" borderless placeholder="无需切换时留空" />
</t-form-item>
</div> </div>
<div class="unit-list"> <div class="unit-list">
@@ -71,6 +74,7 @@ const props = defineProps<{
}>(); }>();
const unitList = defineModel<ProductSkuUnitForm[]>("unitList", { required: true }); const unitList = defineModel<ProductSkuUnitForm[]>("unitList", { required: true });
const baseUnitMigrationRatioText = defineModel<string>("baseUnitMigrationRatioText", { default: "" });
const emit = defineEmits<{ const emit = defineEmits<{
"update:modelValue": [value: boolean]; "update:modelValue": [value: boolean];
apply: []; apply: [];
@@ -27,8 +27,7 @@
theme="danger" theme="danger"
variant="text" variant="text"
size="extra-small" size="extra-small"
:content="unit.id ? '停售' : '删除'" content="移除"
:disabled="!!unit.id && unit.allowSale === false && unit.allowPurchase === false"
@click="removeUnit(unitIndex)" @click="removeUnit(unitIndex)"
/> />
</div> </div>
@@ -39,6 +38,9 @@
<t-form-item label="基础单位" content-align="right"> <t-form-item label="基础单位" content-align="right">
<t-switch v-model="unit.isBase" size="small" :disabled="sku.unitList.length === 1" @change="setBaseUnit(unitIndex)" /> <t-switch v-model="unit.isBase" size="small" :disabled="sku.unitList.length === 1" @change="setBaseUnit(unitIndex)" />
</t-form-item> </t-form-item>
<t-form-item v-if="isBaseUnitMigrationRequired" label="新旧基础单位比例" help="填写 1 个旧基础单位等于多少个新基础单位;最多六位小数" required-mark>
<t-input v-model.trim="sku.baseUnitMigrationRatioText" type="number" align="right" borderless placeholder="例如 30" />
</t-form-item>
<t-form-item label="换算数量" help="1 个当前单位对应的基础单位数量" required-mark> <t-form-item label="换算数量" help="1 个当前单位对应的基础单位数量" required-mark>
<t-input v-model.trim="unit.baseQuantityPerUnit" type="number" align="right" borderless :disabled="unit.isBase" placeholder="1" /> <t-input v-model.trim="unit.baseQuantityPerUnit" type="number" align="right" borderless :disabled="unit.isBase" placeholder="1" />
</t-form-item> </t-form-item>
@@ -91,6 +93,12 @@ const visible = computed({
set: value => handleVisibleChange(value) set: value => handleVisibleChange(value)
}); });
const unitEditorZIndex = 12100; const unitEditorZIndex = 12100;
const isBaseUnitMigrationRequired = computed(() => {
if (!sku.value?.originalBaseUnitId) {
return false;
}
return sku.value.unitList.find(unit => unit.isBase)?.id !== sku.value.originalBaseUnitId;
});
function handleVisibleChange(value: boolean): void { function handleVisibleChange(value: boolean): void {
emit("update:modelValue", value); emit("update:modelValue", value);
@@ -135,10 +143,7 @@ function removeUnit(index: number): void {
} }
const unit = sku.value.unitList[index]; const unit = sku.value.unitList[index];
if (unit?.id) { if (unit?.id) {
unit.allowSale = false; Message.info("已移除单位将在保存时由后端检查引用后处理");
unit.allowPurchase = false;
Message.success("单位已停售并禁止采购,历史订单仍可履约");
return;
} }
const wasBase = sku.value.unitList[index]?.isBase; const wasBase = sku.value.unitList[index]?.isBase;
sku.value.unitList.splice(index, 1); sku.value.unitList.splice(index, 1);
+7
View File
@@ -51,6 +51,12 @@ export type ProductSkuUnit = {
sort?: number; sort?: number;
} & Model; } & Model;
export type ProductSkuBaseUnitMigrationRequest = {
targetUnitId?: string;
targetUnitName?: string;
oldToNewBaseRatio: number | string;
};
export type ProductSku = { export type ProductSku = {
storeId?: string; storeId?: string;
productId?: string; productId?: string;
@@ -67,6 +73,7 @@ export type ProductSku = {
updatedBy?: string; updatedBy?: string;
specValueIdList?: string[]; specValueIdList?: string[];
unitList?: ProductSkuUnit[]; unitList?: ProductSkuUnit[];
baseUnitMigrationRequest?: ProductSkuBaseUnitMigrationRequest;
attachmentList?: Attachment[]; attachmentList?: Attachment[];
} & Model; } & Model;
+6
View File
@@ -4,10 +4,14 @@ import type { Product, ProductAttachmentType, ProductSku, ProductSkuUnit, Produc
export type ProductSpecValueForm = ProductSpecValue & { export type ProductSpecValueForm = ProductSpecValue & {
clientKey: string; clientKey: string;
originalName: string;
originalSort?: number;
}; };
export type ProductSpecForm = Omit<ProductSpec, "valueList"> & { export type ProductSpecForm = Omit<ProductSpec, "valueList"> & {
clientKey: string; clientKey: string;
originalName: string;
originalSort?: number;
valueList: ProductSpecValueForm[]; valueList: ProductSpecValueForm[];
}; };
@@ -21,6 +25,8 @@ export type ProductSkuForm = Omit<ProductSku, "unitList"> & {
unitList: ProductSkuUnitForm[]; unitList: ProductSkuUnitForm[];
minStockQuantityText: string; minStockQuantityText: string;
photoItemList: PhotoItem[]; photoItemList: PhotoItem[];
originalBaseUnitId?: string;
baseUnitMigrationRatioText: string;
}; };
export type ProductForm = Omit<Product, "specList" | "skuList"> & { export type ProductForm = Omit<Product, "specList" | "skuList"> & {