chore: force category management to use real tenant APIs
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// Mock 数据入口,仅在开发环境下使用
|
||||
// 门店模块已切换真实 TenantApi,此处仅保留其他业务的 mock。
|
||||
// 门店模块与商品分类管理已切换真实 TenantApi,此处仅保留其他业务 mock。
|
||||
import './product';
|
||||
import './product-extensions';
|
||||
|
||||
console.warn('[Mock] 非门店模块 Mock 数据已启用');
|
||||
console.warn('[Mock] 已启用非门店/非分类管理 Mock 数据(分类管理强制走真实 API)');
|
||||
|
||||
@@ -150,6 +150,8 @@ const PRODUCT_SEEDS = [
|
||||
|
||||
const storeMap = new Map<string, ProductExtensionStoreState>();
|
||||
let idSeed = 10_000;
|
||||
const ENABLE_PRODUCT_CATEGORY_MOCK =
|
||||
import.meta.env.VITE_MOCK_PRODUCT_CATEGORY === 'true';
|
||||
|
||||
function parseUrlParams(url: string) {
|
||||
const parsed = new URL(url, 'http://localhost');
|
||||
@@ -592,287 +594,291 @@ function ensureStoreState(storeId = '') {
|
||||
return state;
|
||||
}
|
||||
|
||||
Mock.mock(
|
||||
/\/product\/category\/manage\/list(?:\?|$)/,
|
||||
'get',
|
||||
(options: MockRequestOptions) => {
|
||||
const params = parseUrlParams(options.url);
|
||||
const storeId = normalizeText(params.storeId);
|
||||
const keyword = normalizeText(params.keyword).toLowerCase();
|
||||
const status = normalizeText(params.status);
|
||||
const state = ensureStoreState(storeId);
|
||||
// 分类管理与商品选择器默认走真实 TenantApi,需手动开启才启用 mock。
|
||||
if (ENABLE_PRODUCT_CATEGORY_MOCK) {
|
||||
Mock.mock(
|
||||
/\/product\/category\/manage\/list(?:\?|$)/,
|
||||
'get',
|
||||
(options: MockRequestOptions) => {
|
||||
const params = parseUrlParams(options.url);
|
||||
const storeId = normalizeText(params.storeId);
|
||||
const keyword = normalizeText(params.keyword).toLowerCase();
|
||||
const status = normalizeText(params.status);
|
||||
const state = ensureStoreState(storeId);
|
||||
|
||||
const list = state.categories
|
||||
.toSorted((a, b) => a.sort - b.sort)
|
||||
.filter((item) => {
|
||||
if (status && item.status !== status) return false;
|
||||
if (!keyword) return true;
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.description.toLowerCase().includes(keyword)
|
||||
);
|
||||
})
|
||||
.map((item) => toCategoryManageItem(state, item));
|
||||
const list = state.categories
|
||||
.toSorted((a, b) => a.sort - b.sort)
|
||||
.filter((item) => {
|
||||
if (status && item.status !== status) return false;
|
||||
if (!keyword) return true;
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.description.toLowerCase().includes(keyword)
|
||||
);
|
||||
})
|
||||
.map((item) => toCategoryManageItem(state, item));
|
||||
|
||||
return { code: 200, data: list };
|
||||
},
|
||||
);
|
||||
return { code: 200, data: list };
|
||||
},
|
||||
);
|
||||
|
||||
Mock.mock(
|
||||
/\/product\/category\/manage\/save/,
|
||||
'post',
|
||||
(options: MockRequestOptions) => {
|
||||
const body = parseBody(options);
|
||||
const storeId = normalizeText(body.storeId);
|
||||
const id = normalizeText(body.id);
|
||||
const name = normalizeText(body.name);
|
||||
if (!storeId || !name) {
|
||||
return { code: 400, data: null, message: '参数不完整' };
|
||||
}
|
||||
Mock.mock(
|
||||
/\/product\/category\/manage\/save/,
|
||||
'post',
|
||||
(options: MockRequestOptions) => {
|
||||
const body = parseBody(options);
|
||||
const storeId = normalizeText(body.storeId);
|
||||
const id = normalizeText(body.id);
|
||||
const name = normalizeText(body.name);
|
||||
if (!storeId || !name) {
|
||||
return { code: 400, data: null, message: '参数不完整' };
|
||||
}
|
||||
|
||||
const state = ensureStoreState(storeId);
|
||||
const duplicate = state.categories.find(
|
||||
(item) => item.name === name && item.id !== id,
|
||||
);
|
||||
if (duplicate) {
|
||||
return { code: 400, data: null, message: '分类名称已存在' };
|
||||
}
|
||||
const state = ensureStoreState(storeId);
|
||||
const duplicate = state.categories.find(
|
||||
(item) => item.name === name && item.id !== id,
|
||||
);
|
||||
if (duplicate) {
|
||||
return { code: 400, data: null, message: '分类名称已存在' };
|
||||
}
|
||||
|
||||
const currentSortMax =
|
||||
state.categories.reduce((max, item) => Math.max(max, item.sort), 0) + 1;
|
||||
const existingIndex = state.categories.findIndex((item) => item.id === id);
|
||||
const currentSortMax =
|
||||
state.categories.reduce((max, item) => Math.max(max, item.sort), 0) +
|
||||
1;
|
||||
const existingIndex = state.categories.findIndex((item) => item.id === id);
|
||||
|
||||
const next =
|
||||
existingIndex === -1
|
||||
? {
|
||||
id: createId('cat', storeId),
|
||||
name,
|
||||
description: normalizeText(body.description),
|
||||
icon: normalizeText(body.icon, 'lucide:folder'),
|
||||
sort: normalizeInt(body.sort, currentSortMax, 1),
|
||||
status: normalizeSwitchStatus(body.status, 'enabled'),
|
||||
channels: normalizeChannels(body.channels, ['wm']),
|
||||
}
|
||||
: {
|
||||
...state.categories[existingIndex],
|
||||
name,
|
||||
description: normalizeText(
|
||||
body.description,
|
||||
state.categories[existingIndex].description,
|
||||
),
|
||||
icon: normalizeText(
|
||||
body.icon,
|
||||
state.categories[existingIndex].icon,
|
||||
),
|
||||
sort: normalizeInt(
|
||||
body.sort,
|
||||
state.categories[existingIndex].sort,
|
||||
1,
|
||||
),
|
||||
status: normalizeSwitchStatus(
|
||||
body.status,
|
||||
state.categories[existingIndex].status,
|
||||
),
|
||||
channels: normalizeChannels(
|
||||
body.channels,
|
||||
state.categories[existingIndex].channels,
|
||||
),
|
||||
};
|
||||
const next =
|
||||
existingIndex === -1
|
||||
? {
|
||||
id: createId('cat', storeId),
|
||||
name,
|
||||
description: normalizeText(body.description),
|
||||
icon: normalizeText(body.icon, 'lucide:folder'),
|
||||
sort: normalizeInt(body.sort, currentSortMax, 1),
|
||||
status: normalizeSwitchStatus(body.status, 'enabled'),
|
||||
channels: normalizeChannels(body.channels, ['wm']),
|
||||
}
|
||||
: {
|
||||
...state.categories[existingIndex],
|
||||
name,
|
||||
description: normalizeText(
|
||||
body.description,
|
||||
state.categories[existingIndex].description,
|
||||
),
|
||||
icon: normalizeText(
|
||||
body.icon,
|
||||
state.categories[existingIndex].icon,
|
||||
),
|
||||
sort: normalizeInt(
|
||||
body.sort,
|
||||
state.categories[existingIndex].sort,
|
||||
1,
|
||||
),
|
||||
status: normalizeSwitchStatus(
|
||||
body.status,
|
||||
state.categories[existingIndex].status,
|
||||
),
|
||||
channels: normalizeChannels(
|
||||
body.channels,
|
||||
state.categories[existingIndex].channels,
|
||||
),
|
||||
};
|
||||
|
||||
if (existingIndex === -1) {
|
||||
state.categories.push(next);
|
||||
} else {
|
||||
state.categories.splice(existingIndex, 1, next);
|
||||
}
|
||||
if (existingIndex === -1) {
|
||||
state.categories.push(next);
|
||||
} else {
|
||||
state.categories.splice(existingIndex, 1, next);
|
||||
}
|
||||
|
||||
return { code: 200, data: toCategoryManageItem(state, next) };
|
||||
},
|
||||
);
|
||||
return { code: 200, data: toCategoryManageItem(state, next) };
|
||||
},
|
||||
);
|
||||
|
||||
Mock.mock(
|
||||
/\/product\/category\/manage\/delete/,
|
||||
'post',
|
||||
(options: MockRequestOptions) => {
|
||||
const body = parseBody(options);
|
||||
const storeId = normalizeText(body.storeId);
|
||||
const categoryId = normalizeText(body.categoryId);
|
||||
if (!storeId || !categoryId) {
|
||||
return { code: 400, data: null, message: '参数不完整' };
|
||||
}
|
||||
Mock.mock(
|
||||
/\/product\/category\/manage\/delete/,
|
||||
'post',
|
||||
(options: MockRequestOptions) => {
|
||||
const body = parseBody(options);
|
||||
const storeId = normalizeText(body.storeId);
|
||||
const categoryId = normalizeText(body.categoryId);
|
||||
if (!storeId || !categoryId) {
|
||||
return { code: 400, data: null, message: '参数不完整' };
|
||||
}
|
||||
|
||||
const state = ensureStoreState(storeId);
|
||||
const hasProducts = state.products.some(
|
||||
(item) => item.categoryId === categoryId,
|
||||
);
|
||||
if (hasProducts) {
|
||||
return { code: 400, data: null, message: '分类下仍有商品,不能删除' };
|
||||
}
|
||||
const state = ensureStoreState(storeId);
|
||||
const hasProducts = state.products.some(
|
||||
(item) => item.categoryId === categoryId,
|
||||
);
|
||||
if (hasProducts) {
|
||||
return { code: 400, data: null, message: '分类下仍有商品,不能删除' };
|
||||
}
|
||||
|
||||
if (state.categories.length <= 1) {
|
||||
return { code: 400, data: null, message: '至少保留一个分类' };
|
||||
}
|
||||
if (state.categories.length <= 1) {
|
||||
return { code: 400, data: null, message: '至少保留一个分类' };
|
||||
}
|
||||
|
||||
state.categories = state.categories.filter(
|
||||
(item) => item.id !== categoryId,
|
||||
);
|
||||
return { code: 200, data: null };
|
||||
},
|
||||
);
|
||||
state.categories = state.categories.filter(
|
||||
(item) => item.id !== categoryId,
|
||||
);
|
||||
return { code: 200, data: null };
|
||||
},
|
||||
);
|
||||
|
||||
Mock.mock(
|
||||
/\/product\/category\/manage\/status/,
|
||||
'post',
|
||||
(options: MockRequestOptions) => {
|
||||
const body = parseBody(options);
|
||||
const storeId = normalizeText(body.storeId);
|
||||
const categoryId = normalizeText(body.categoryId);
|
||||
if (!storeId || !categoryId) {
|
||||
return { code: 400, data: null, message: '参数不完整' };
|
||||
}
|
||||
const state = ensureStoreState(storeId);
|
||||
const target = state.categories.find((item) => item.id === categoryId);
|
||||
if (!target) return { code: 404, data: null, message: '分类不存在' };
|
||||
target.status = normalizeSwitchStatus(body.status, target.status);
|
||||
return { code: 200, data: toCategoryManageItem(state, target) };
|
||||
},
|
||||
);
|
||||
Mock.mock(
|
||||
/\/product\/category\/manage\/status/,
|
||||
'post',
|
||||
(options: MockRequestOptions) => {
|
||||
const body = parseBody(options);
|
||||
const storeId = normalizeText(body.storeId);
|
||||
const categoryId = normalizeText(body.categoryId);
|
||||
if (!storeId || !categoryId) {
|
||||
return { code: 400, data: null, message: '参数不完整' };
|
||||
}
|
||||
const state = ensureStoreState(storeId);
|
||||
const target = state.categories.find((item) => item.id === categoryId);
|
||||
if (!target) return { code: 404, data: null, message: '分类不存在' };
|
||||
target.status = normalizeSwitchStatus(body.status, target.status);
|
||||
return { code: 200, data: toCategoryManageItem(state, target) };
|
||||
},
|
||||
);
|
||||
|
||||
Mock.mock(
|
||||
/\/product\/category\/manage\/sort/,
|
||||
'post',
|
||||
(options: MockRequestOptions) => {
|
||||
const body = parseBody(options);
|
||||
const storeId = normalizeText(body.storeId);
|
||||
const items = Array.isArray(body.items) ? body.items : [];
|
||||
if (!storeId) return { code: 400, data: null, message: '参数不完整' };
|
||||
Mock.mock(
|
||||
/\/product\/category\/manage\/sort/,
|
||||
'post',
|
||||
(options: MockRequestOptions) => {
|
||||
const body = parseBody(options);
|
||||
const storeId = normalizeText(body.storeId);
|
||||
const items = Array.isArray(body.items) ? body.items : [];
|
||||
if (!storeId) return { code: 400, data: null, message: '参数不完整' };
|
||||
|
||||
const sortMap = new Map<string, number>();
|
||||
for (const item of items) {
|
||||
if (!item || typeof item !== 'object') continue;
|
||||
const current = item as Record<string, unknown>;
|
||||
const id = normalizeText(current.categoryId);
|
||||
const sort = normalizeInt(current.sort, 0, 1);
|
||||
if (!id || sort <= 0) continue;
|
||||
sortMap.set(id, sort);
|
||||
}
|
||||
const sortMap = new Map<string, number>();
|
||||
for (const item of items) {
|
||||
if (!item || typeof item !== 'object') continue;
|
||||
const current = item as Record<string, unknown>;
|
||||
const id = normalizeText(current.categoryId);
|
||||
const sort = normalizeInt(current.sort, 0, 1);
|
||||
if (!id || sort <= 0) continue;
|
||||
sortMap.set(id, sort);
|
||||
}
|
||||
|
||||
const state = ensureStoreState(storeId);
|
||||
state.categories = state.categories
|
||||
.map((item) => ({
|
||||
...item,
|
||||
sort: sortMap.get(item.id) ?? item.sort,
|
||||
}))
|
||||
.toSorted((a, b) => a.sort - b.sort)
|
||||
.map((item, index) => ({ ...item, sort: index + 1 }));
|
||||
const state = ensureStoreState(storeId);
|
||||
state.categories = state.categories
|
||||
.map((item) => ({
|
||||
...item,
|
||||
sort: sortMap.get(item.id) ?? item.sort,
|
||||
}))
|
||||
.toSorted((a, b) => a.sort - b.sort)
|
||||
.map((item, index) => ({ ...item, sort: index + 1 }));
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: state.categories.map((item) => toCategoryManageItem(state, item)),
|
||||
};
|
||||
},
|
||||
);
|
||||
return {
|
||||
code: 200,
|
||||
data: state.categories.map((item) => toCategoryManageItem(state, item)),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
Mock.mock(
|
||||
/\/product\/category\/manage\/products\/bind/,
|
||||
'post',
|
||||
(options: MockRequestOptions) => {
|
||||
const body = parseBody(options);
|
||||
const storeId = normalizeText(body.storeId);
|
||||
const categoryId = normalizeText(body.categoryId);
|
||||
const productIds = normalizeIdList(body.productIds);
|
||||
if (!storeId || !categoryId || productIds.length === 0) {
|
||||
return { code: 400, data: null, message: '参数不完整' };
|
||||
}
|
||||
Mock.mock(
|
||||
/\/product\/category\/manage\/products\/bind/,
|
||||
'post',
|
||||
(options: MockRequestOptions) => {
|
||||
const body = parseBody(options);
|
||||
const storeId = normalizeText(body.storeId);
|
||||
const categoryId = normalizeText(body.categoryId);
|
||||
const productIds = normalizeIdList(body.productIds);
|
||||
if (!storeId || !categoryId || productIds.length === 0) {
|
||||
return { code: 400, data: null, message: '参数不完整' };
|
||||
}
|
||||
|
||||
const state = ensureStoreState(storeId);
|
||||
if (!hasCategory(state, categoryId)) {
|
||||
return { code: 404, data: null, message: '分类不存在' };
|
||||
}
|
||||
const state = ensureStoreState(storeId);
|
||||
if (!hasCategory(state, categoryId)) {
|
||||
return { code: 404, data: null, message: '分类不存在' };
|
||||
}
|
||||
|
||||
const idSet = new Set(productIds);
|
||||
let successCount = 0;
|
||||
for (const item of state.products) {
|
||||
if (!idSet.has(item.id)) continue;
|
||||
item.categoryId = categoryId;
|
||||
successCount += 1;
|
||||
}
|
||||
const idSet = new Set(productIds);
|
||||
let successCount = 0;
|
||||
for (const item of state.products) {
|
||||
if (!idSet.has(item.id)) continue;
|
||||
item.categoryId = categoryId;
|
||||
successCount += 1;
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
totalCount: productIds.length,
|
||||
successCount,
|
||||
failedCount: Math.max(productIds.length - successCount, 0),
|
||||
},
|
||||
};
|
||||
},
|
||||
);
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
totalCount: productIds.length,
|
||||
successCount,
|
||||
failedCount: Math.max(productIds.length - successCount, 0),
|
||||
},
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
Mock.mock(
|
||||
/\/product\/category\/manage\/products\/unbind/,
|
||||
'post',
|
||||
(options: MockRequestOptions) => {
|
||||
const body = parseBody(options);
|
||||
const storeId = normalizeText(body.storeId);
|
||||
const categoryId = normalizeText(body.categoryId);
|
||||
const productId = normalizeText(body.productId);
|
||||
if (!storeId || !categoryId || !productId) {
|
||||
return { code: 400, data: null, message: '参数不完整' };
|
||||
}
|
||||
Mock.mock(
|
||||
/\/product\/category\/manage\/products\/unbind/,
|
||||
'post',
|
||||
(options: MockRequestOptions) => {
|
||||
const body = parseBody(options);
|
||||
const storeId = normalizeText(body.storeId);
|
||||
const categoryId = normalizeText(body.categoryId);
|
||||
const productId = normalizeText(body.productId);
|
||||
if (!storeId || !categoryId || !productId) {
|
||||
return { code: 400, data: null, message: '参数不完整' };
|
||||
}
|
||||
|
||||
const state = ensureStoreState(storeId);
|
||||
const fallbackCategory = state.categories.find(
|
||||
(item) => item.id !== categoryId,
|
||||
);
|
||||
if (!fallbackCategory) {
|
||||
return { code: 400, data: null, message: '无可用目标分类' };
|
||||
}
|
||||
const state = ensureStoreState(storeId);
|
||||
const fallbackCategory = state.categories.find(
|
||||
(item) => item.id !== categoryId,
|
||||
);
|
||||
if (!fallbackCategory) {
|
||||
return { code: 400, data: null, message: '无可用目标分类' };
|
||||
}
|
||||
|
||||
const target = state.products.find((item) => item.id === productId);
|
||||
if (!target) return { code: 404, data: null, message: '商品不存在' };
|
||||
target.categoryId = fallbackCategory.id;
|
||||
const target = state.products.find((item) => item.id === productId);
|
||||
if (!target) return { code: 404, data: null, message: '商品不存在' };
|
||||
target.categoryId = fallbackCategory.id;
|
||||
|
||||
return { code: 200, data: target };
|
||||
},
|
||||
);
|
||||
return { code: 200, data: target };
|
||||
},
|
||||
);
|
||||
|
||||
Mock.mock(
|
||||
/\/product\/picker\/list(?:\?|$)/,
|
||||
'get',
|
||||
(options: MockRequestOptions) => {
|
||||
const params = parseUrlParams(options.url);
|
||||
const storeId = normalizeText(params.storeId);
|
||||
const keyword = normalizeText(params.keyword).toLowerCase();
|
||||
const categoryId = normalizeText(params.categoryId);
|
||||
const limit = Math.max(
|
||||
1,
|
||||
Math.min(500, normalizeInt(params.limit, 200, 1)),
|
||||
);
|
||||
const state = ensureStoreState(storeId);
|
||||
Mock.mock(
|
||||
/\/product\/picker\/list(?:\?|$)/,
|
||||
'get',
|
||||
(options: MockRequestOptions) => {
|
||||
const params = parseUrlParams(options.url);
|
||||
const storeId = normalizeText(params.storeId);
|
||||
const keyword = normalizeText(params.keyword).toLowerCase();
|
||||
const categoryId = normalizeText(params.categoryId);
|
||||
const limit = Math.max(
|
||||
1,
|
||||
Math.min(500, normalizeInt(params.limit, 200, 1)),
|
||||
);
|
||||
const state = ensureStoreState(storeId);
|
||||
|
||||
const list = state.products
|
||||
.filter((item) => {
|
||||
if (categoryId && item.categoryId !== categoryId) return false;
|
||||
if (!keyword) return true;
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.spuCode.toLowerCase().includes(keyword)
|
||||
);
|
||||
})
|
||||
.slice(0, limit)
|
||||
.map((item) => ({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
spuCode: item.spuCode,
|
||||
categoryId: item.categoryId,
|
||||
categoryName: getCategoryName(state, item.categoryId),
|
||||
price: item.price,
|
||||
status: item.status,
|
||||
}));
|
||||
const list = state.products
|
||||
.filter((item) => {
|
||||
if (categoryId && item.categoryId !== categoryId) return false;
|
||||
if (!keyword) return true;
|
||||
return (
|
||||
item.name.toLowerCase().includes(keyword) ||
|
||||
item.spuCode.toLowerCase().includes(keyword)
|
||||
);
|
||||
})
|
||||
.slice(0, limit)
|
||||
.map((item) => ({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
spuCode: item.spuCode,
|
||||
categoryId: item.categoryId,
|
||||
categoryName: getCategoryName(state, item.categoryId),
|
||||
price: item.price,
|
||||
status: item.status,
|
||||
}));
|
||||
|
||||
return { code: 200, data: list };
|
||||
},
|
||||
);
|
||||
return { code: 200, data: list };
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Mock.mock(
|
||||
/\/product\/spec\/list(?:\?|$)/,
|
||||
|
||||
@@ -296,6 +296,8 @@ const PRODUCT_SEEDS: ProductSeed[] = [
|
||||
];
|
||||
|
||||
const productStoreMap = new Map<string, ProductStoreState>();
|
||||
const ENABLE_PRODUCT_CATEGORY_MOCK =
|
||||
import.meta.env.VITE_MOCK_PRODUCT_CATEGORY === 'true';
|
||||
|
||||
/** 解析 URL 查询参数。 */
|
||||
function parseUrlParams(url: string) {
|
||||
@@ -540,20 +542,22 @@ function resolveStatusByShelfMode(
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/** 获取商品分类。 */
|
||||
Mock.mock(
|
||||
/\/product\/category\/list(?:\?|$)/,
|
||||
'get',
|
||||
(options: MockRequestOptions) => {
|
||||
const params = parseUrlParams(options.url);
|
||||
const storeId = String(params.storeId || '');
|
||||
const state = ensureStoreState(storeId);
|
||||
return {
|
||||
code: 200,
|
||||
data: buildCategoryList(state.products),
|
||||
};
|
||||
},
|
||||
);
|
||||
/** 获取商品分类(默认走真实 TenantApi,需手动开启才启用 mock)。 */
|
||||
if (ENABLE_PRODUCT_CATEGORY_MOCK) {
|
||||
Mock.mock(
|
||||
/\/product\/category\/list(?:\?|$)/,
|
||||
'get',
|
||||
(options: MockRequestOptions) => {
|
||||
const params = parseUrlParams(options.url);
|
||||
const storeId = String(params.storeId || '');
|
||||
const state = ensureStoreState(storeId);
|
||||
return {
|
||||
code: 200,
|
||||
data: buildCategoryList(state.products),
|
||||
};
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/** 获取商品列表。 */
|
||||
Mock.mock(/\/product\/list(?:\?|$)/, 'get', (options: MockRequestOptions) => {
|
||||
|
||||
Reference in New Issue
Block a user