style(project): format product detail split modules
This commit is contained in:
@@ -69,7 +69,7 @@ function ensureProductDetailRoute(
|
|||||||
path: PRODUCT_DETAIL_PATH,
|
path: PRODUCT_DETAIL_PATH,
|
||||||
component: '/views/product/detail/index.vue',
|
component: '/views/product/detail/index.vue',
|
||||||
meta: {
|
meta: {
|
||||||
...(listMeta ?? {}),
|
...listMeta,
|
||||||
title: '商品详情',
|
title: '商品详情',
|
||||||
hideInMenu: true,
|
hideInMenu: true,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
|
|
||||||
|
import type { ProductDetailFormState } from '../../types';
|
||||||
|
|
||||||
import type { ProductPickerItemDto } from '#/api/product';
|
import type { ProductPickerItemDto } from '#/api/product';
|
||||||
|
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
import { searchProductPickerApi } from '#/api/product';
|
import { searchProductPickerApi } from '#/api/product';
|
||||||
|
|
||||||
import type { ProductDetailFormState } from '../../types';
|
|
||||||
|
|
||||||
interface CreateProductDetailComboActionsOptions {
|
interface CreateProductDetailComboActionsOptions {
|
||||||
comboPickerCurrentGroupIndex: Ref<number>;
|
comboPickerCurrentGroupIndex: Ref<number>;
|
||||||
comboPickerKeyword: Ref<string>;
|
comboPickerKeyword: Ref<string>;
|
||||||
@@ -51,7 +51,9 @@ export function createProductDetailComboActions(
|
|||||||
|
|
||||||
function removeComboGroup(groupIndex: number) {
|
function removeComboGroup(groupIndex: number) {
|
||||||
if (groupIndex < 0 || groupIndex >= form.comboGroups.length) return;
|
if (groupIndex < 0 || groupIndex >= form.comboGroups.length) return;
|
||||||
form.comboGroups = form.comboGroups.filter((_, index) => index !== groupIndex);
|
form.comboGroups = form.comboGroups.filter(
|
||||||
|
(_, index) => index !== groupIndex,
|
||||||
|
);
|
||||||
form.comboGroups.forEach((group, index) => {
|
form.comboGroups.forEach((group, index) => {
|
||||||
group.sortOrder = index + 1;
|
group.sortOrder = index + 1;
|
||||||
});
|
});
|
||||||
@@ -90,7 +92,11 @@ export function createProductDetailComboActions(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setComboItemQuantity(groupIndex: number, itemIndex: number, value: number) {
|
function setComboItemQuantity(
|
||||||
|
groupIndex: number,
|
||||||
|
itemIndex: number,
|
||||||
|
value: number,
|
||||||
|
) {
|
||||||
const group = form.comboGroups[groupIndex];
|
const group = form.comboGroups[groupIndex];
|
||||||
if (!group) return;
|
if (!group) return;
|
||||||
const item = group.items[itemIndex];
|
const item = group.items[itemIndex];
|
||||||
@@ -117,7 +123,9 @@ export function createProductDetailComboActions(
|
|||||||
keyword: comboPickerKeyword.value.trim() || undefined,
|
keyword: comboPickerKeyword.value.trim() || undefined,
|
||||||
limit: 100,
|
limit: 100,
|
||||||
});
|
});
|
||||||
comboPickerProducts.value = products.filter((item) => item.id !== form.id);
|
comboPickerProducts.value = products.filter(
|
||||||
|
(item) => item.id !== form.id,
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
comboPickerProducts.value = [];
|
comboPickerProducts.value = [];
|
||||||
@@ -153,7 +161,9 @@ export function createProductDetailComboActions(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentItemMap = new Map(group.items.map((item) => [item.productId, item]));
|
const currentItemMap = new Map(
|
||||||
|
group.items.map((item) => [item.productId, item]),
|
||||||
|
);
|
||||||
|
|
||||||
const selectedProducts = comboPickerSelectedProducts.value;
|
const selectedProducts = comboPickerSelectedProducts.value;
|
||||||
group.items = selectedProducts.map((product, index) => {
|
group.items = selectedProducts.map((product, index) => {
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
import type { Router } from 'vue-router';
|
import type { Router } from 'vue-router';
|
||||||
|
|
||||||
|
import type {
|
||||||
|
ProductDetailCategoryOption,
|
||||||
|
ProductDetailFormState,
|
||||||
|
} from '../../types';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ProductAddonGroupDto,
|
ProductAddonGroupDto,
|
||||||
ProductDetailDto,
|
ProductDetailDto,
|
||||||
@@ -22,11 +27,6 @@ import {
|
|||||||
saveProductApi,
|
saveProductApi,
|
||||||
} from '#/api/product';
|
} from '#/api/product';
|
||||||
|
|
||||||
import type {
|
|
||||||
ProductDetailCategoryOption,
|
|
||||||
ProductDetailFormState,
|
|
||||||
} from '../../types';
|
|
||||||
|
|
||||||
import { DEFAULT_PRODUCT_DETAIL_FORM } from './constants';
|
import { DEFAULT_PRODUCT_DETAIL_FORM } from './constants';
|
||||||
import {
|
import {
|
||||||
buildLocalSkuCode,
|
buildLocalSkuCode,
|
||||||
@@ -91,10 +91,10 @@ export function createProductDetailDataActions(
|
|||||||
form.description = data.description;
|
form.description = data.description;
|
||||||
form.sortWeight = Math.max(0, Number(data.sortWeight || 0));
|
form.sortWeight = Math.max(0, Number(data.sortWeight || 0));
|
||||||
|
|
||||||
form.imageUrls = dedupeTextList([...(data.imageUrls || []), data.imageUrl]).slice(
|
form.imageUrls = dedupeTextList([
|
||||||
0,
|
...(data.imageUrls || []),
|
||||||
5,
|
data.imageUrl,
|
||||||
);
|
]).slice(0, 5);
|
||||||
|
|
||||||
form.price = Number(data.price || 0);
|
form.price = Number(data.price || 0);
|
||||||
form.originalPrice =
|
form.originalPrice =
|
||||||
@@ -178,7 +178,9 @@ export function createProductDetailDataActions(
|
|||||||
|
|
||||||
function removeImage(index: number) {
|
function removeImage(index: number) {
|
||||||
if (index < 0 || index >= form.imageUrls.length) return;
|
if (index < 0 || index >= form.imageUrls.length) return;
|
||||||
form.imageUrls = form.imageUrls.filter((_, itemIndex) => itemIndex !== index);
|
form.imageUrls = form.imageUrls.filter(
|
||||||
|
(_, itemIndex) => itemIndex !== index,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setPrimaryImage(index: number) {
|
function setPrimaryImage(index: number) {
|
||||||
@@ -197,7 +199,8 @@ export function createProductDetailDataActions(
|
|||||||
|
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
try {
|
try {
|
||||||
const [detailData, categories, specs, addons, labels] = await Promise.all([
|
const [detailData, categories, specs, addons, labels] = await Promise.all(
|
||||||
|
[
|
||||||
getProductDetailApi({
|
getProductDetailApi({
|
||||||
storeId: storeId.value,
|
storeId: storeId.value,
|
||||||
productId: productId.value,
|
productId: productId.value,
|
||||||
@@ -206,7 +209,8 @@ export function createProductDetailDataActions(
|
|||||||
getProductSpecListApi({ storeId: storeId.value }),
|
getProductSpecListApi({ storeId: storeId.value }),
|
||||||
getProductAddonGroupListApi({ storeId: storeId.value }),
|
getProductAddonGroupListApi({ storeId: storeId.value }),
|
||||||
getProductLabelListApi({ storeId: storeId.value }),
|
getProductLabelListApi({ storeId: storeId.value }),
|
||||||
]);
|
],
|
||||||
|
);
|
||||||
|
|
||||||
detail.value = detailData;
|
detail.value = detailData;
|
||||||
categoryOptions.value = categories.map((item) => ({
|
categoryOptions.value = categories.map((item) => ({
|
||||||
@@ -319,7 +323,10 @@ export function createProductDetailDataActions(
|
|||||||
: null,
|
: null,
|
||||||
stock: Math.max(0, Math.floor(Number(item.stock || 0))),
|
stock: Math.max(0, Math.floor(Number(item.stock || 0))),
|
||||||
isEnabled: item.isEnabled,
|
isEnabled: item.isEnabled,
|
||||||
sortOrder: Math.max(1, Math.floor(Number(item.sortOrder || index + 1))),
|
sortOrder: Math.max(
|
||||||
|
1,
|
||||||
|
Math.floor(Number(item.sortOrder || index + 1)),
|
||||||
|
),
|
||||||
attributes: item.attributes.map((attr) => ({
|
attributes: item.attributes.map((attr) => ({
|
||||||
templateId: attr.templateId,
|
templateId: attr.templateId,
|
||||||
optionId: attr.optionId,
|
optionId: attr.optionId,
|
||||||
@@ -329,8 +336,14 @@ export function createProductDetailDataActions(
|
|||||||
form.kind === 'combo'
|
form.kind === 'combo'
|
||||||
? form.comboGroups.map((group, groupIndex) => ({
|
? form.comboGroups.map((group, groupIndex) => ({
|
||||||
name: group.name.trim(),
|
name: group.name.trim(),
|
||||||
minSelect: Math.max(1, Math.floor(Number(group.minSelect || 1))),
|
minSelect: Math.max(
|
||||||
maxSelect: Math.max(1, Math.floor(Number(group.maxSelect || 1))),
|
1,
|
||||||
|
Math.floor(Number(group.minSelect || 1)),
|
||||||
|
),
|
||||||
|
maxSelect: Math.max(
|
||||||
|
1,
|
||||||
|
Math.floor(Number(group.maxSelect || 1)),
|
||||||
|
),
|
||||||
sortOrder: Math.max(
|
sortOrder: Math.max(
|
||||||
1,
|
1,
|
||||||
Math.floor(Number(group.sortOrder || groupIndex + 1)),
|
Math.floor(Number(group.sortOrder || groupIndex + 1)),
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
|
|
||||||
import type { ProductSpecDto } from '#/api/product';
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ProductDetailFormState,
|
ProductDetailFormState,
|
||||||
ProductDetailSkuBatchState,
|
ProductDetailSkuBatchState,
|
||||||
ProductDetailSkuRowState,
|
ProductDetailSkuRowState,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
|
|
||||||
|
import type { ProductSpecDto } from '#/api/product';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
buildLocalSkuCode,
|
buildLocalSkuCode,
|
||||||
buildSkuCombinations,
|
buildSkuCombinations,
|
||||||
@@ -42,7 +42,10 @@ export function createProductDetailSkuActions(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSkuAttrOptionId(row: ProductDetailSkuRowState, templateId: string) {
|
function getSkuAttrOptionId(
|
||||||
|
row: ProductDetailSkuRowState,
|
||||||
|
templateId: string,
|
||||||
|
) {
|
||||||
return row.attributes.find((item) => item.templateId === templateId)
|
return row.attributes.find((item) => item.templateId === templateId)
|
||||||
?.optionId;
|
?.optionId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import type {
|
|||||||
import { computed, reactive, ref, watch } from 'vue';
|
import { computed, reactive, ref, watch } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { DEFAULT_PRODUCT_DETAIL_FORM } from './product-detail-page/constants';
|
|
||||||
import { createProductDetailComboActions } from './product-detail-page/combo-actions';
|
import { createProductDetailComboActions } from './product-detail-page/combo-actions';
|
||||||
|
import { DEFAULT_PRODUCT_DETAIL_FORM } from './product-detail-page/constants';
|
||||||
import { createProductDetailDataActions } from './product-detail-page/data-actions';
|
import { createProductDetailDataActions } from './product-detail-page/data-actions';
|
||||||
import { createProductDetailSkuActions } from './product-detail-page/sku-actions';
|
import { createProductDetailSkuActions } from './product-detail-page/sku-actions';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user