review:【antd/ele】【mall】营销模块的迁移

This commit is contained in:
YunaiV
2025-12-15 19:29:47 +08:00
parent ef0f0a9a9d
commit 4ec82f0fd0
50 changed files with 317 additions and 263 deletions

View File

@@ -7,6 +7,31 @@ import { getDictOptions } from '@vben/hooks';
import { z } from '#/adapter/form';
import { getSimpleSeckillConfigList } from '#/api/mall/promotion/seckill/seckillConfig';
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {
return [
{
fieldName: 'name',
label: '活动名称',
component: 'Input',
componentProps: {
placeholder: '请输入活动名称',
clearable: true,
},
},
{
fieldName: 'status',
label: '活动状态',
component: 'Select',
componentProps: {
placeholder: '请选择活动状态',
clearable: true,
options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'),
},
},
];
}
/** 新增/编辑的表单 */
export function useFormSchema(): VbenFormSchema[] {
return [
@@ -115,31 +140,6 @@ export function useFormSchema(): VbenFormSchema[] {
];
}
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {
return [
{
fieldName: 'name',
label: '活动名称',
component: 'Input',
componentProps: {
placeholder: '请输入活动名称',
clearable: true,
},
},
{
fieldName: 'status',
label: '活动状态',
component: 'Select',
componentProps: {
placeholder: '请选择活动状态',
clearable: true,
options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'),
},
},
];
}
/** 列表的字段 */
export function useGridColumns(): VxeTableGridOptions['columns'] {
return [

View File

@@ -9,7 +9,7 @@ export function setConfigList(list: any[]) {
}
/** 格式化配置名称 */
export function formatConfigNames(configId: number): string {
export function formatConfigNames(configId: number | string): string {
const config = configList.find((item) => item.id === configId);
return config === null || config === undefined
? ''
@@ -27,8 +27,11 @@ export function formatSeckillPrice(products: any[]): string {
/** 格式化活动时间范围 */
export function formatTimeRange(
startTime: Date | string,
endTime: Date | string,
startTime: Date | string | undefined,
endTime: Date | string | undefined,
): string {
return `${formatDate(startTime, 'YYYY-MM-DD')} ~ ${formatDate(endTime, 'YYYY-MM-DD')}`;
if (startTime && endTime) {
return `${formatDate(startTime, 'YYYY-MM-DD')} ~ ${formatDate(endTime, 'YYYY-MM-DD')}`;
}
return '';
}

View File

@@ -84,6 +84,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
},
},
},
// TODO @puhui999antd 没有,是不是要统一哈。
cellConfig: {
height: 250,
},
@@ -164,6 +165,7 @@ onMounted(async () => {
link: true,
auth: ['promotion:seckill-activity:close'],
ifShow: row.status === 0,
// TODO @puhui999antd 这里是 popConfirm看看要不要统一
onClick: handleClose.bind(null, row),
},
{

View File

@@ -27,15 +27,19 @@ const getTitle = computed(() => {
: $t('ui.actionTitle.create', ['秒杀活动']);
});
// ================= 商品选择相关 =================
const spuId = ref<number>();
const spuName = ref<string>('');
const skuTableData = ref<any[]>([]);
const spuSkuSelectRef = ref();
const spuSkuSelectRef = ref(); // 商品选择弹窗 Ref
/** 打开商品选择弹窗 */
const handleSelectProduct = () => {
spuSkuSelectRef.value?.open();
};
/** 选择商品后的回调 */
async function handleSpuSelected(selectedSpuId: number, skuIds?: number[]) {
const spu = await getSpu(selectedSpuId);
if (!spu) return;
@@ -43,6 +47,7 @@ async function handleSpuSelected(selectedSpuId: number, skuIds?: number[]) {
spuId.value = spu.id;
spuName.value = spu.name || '';
// 筛选指定的 SKU
const selectedSkus = skuIds
? spu.skus?.filter((sku) => skuIds.includes(sku.id!))
: spu.skus;
@@ -58,6 +63,8 @@ async function handleSpuSelected(selectedSpuId: number, skuIds?: number[]) {
})) || [];
}
// ================= end =================
const [Form, formApi] = useVbenForm({
commonConfig: {
componentProps: {
@@ -77,6 +84,7 @@ const [Modal, modalApi] = useVbenModal({
return;
}
// 验证商品和 SKU 配置
if (!spuId.value) {
ElMessage.error('请选择秒杀商品');
return;
@@ -85,6 +93,7 @@ const [Modal, modalApi] = useVbenModal({
ElMessage.error('请至少配置一个 SKU');
return;
}
// 验证 SKU 配置
const hasInvalidSku = skuTableData.value.some(
(sku) => sku.stock < 1 || sku.seckillPrice < 0.01,
);
@@ -93,6 +102,7 @@ const [Modal, modalApi] = useVbenModal({
return;
}
// 提交表单
modalApi.lock();
try {
const values = await formApi.getValues();
@@ -102,12 +112,13 @@ const [Modal, modalApi] = useVbenModal({
products: skuTableData.value.map((sku) => ({
skuId: sku.skuId,
stock: sku.stock,
seckillPrice: Math.round(sku.seckillPrice * 100),
seckillPrice: Math.round(sku.seckillPrice * 100), // 转换为分
})),
};
await (formData.value?.id
? updateSeckillActivity(data)
: createSeckillActivity(data));
// 关闭并提示
await modalApi.close();
emit('success');
ElMessage.success($t('ui.actionMessage.operationSuccess'));
@@ -123,6 +134,8 @@ const [Modal, modalApi] = useVbenModal({
skuTableData.value = [];
return;
}
// 加载数据
const data = modalApi.getData<MallSeckillActivityApi.SeckillActivity>();
if (!data || !data.id) {
return;
@@ -130,12 +143,16 @@ const [Modal, modalApi] = useVbenModal({
modalApi.lock();
try {
formData.value = await getSeckillActivity(data.id);
// TODO @puhui999这里需要 nextTick 么?因为 antd 有
await formApi.setValues(formData.value);
// 加载商品和 SKU 信息
// TODO @puhui999if return 简化括号层级
if (formData.value.spuId) {
const spu = await getSpu(formData.value.spuId);
if (spu) {
spuId.value = spu.id;
spuName.value = spu.name || '';
// 回填 SKU 配置
const products = formData.value.products || [];
skuTableData.value =
spu.skus
@@ -148,7 +165,7 @@ const [Modal, modalApi] = useVbenModal({
picUrl: sku.picUrl || spu.picUrl || '',
price: sku.price || 0,
stock: product?.stock || 0,
seckillPrice: (product?.seckillPrice || 0) / 100,
seckillPrice: (product?.seckillPrice || 0) / 100, // 分转元
};
}) || [];
}
@@ -164,9 +181,12 @@ const [Modal, modalApi] = useVbenModal({
<Modal class="w-4/5" :title="getTitle">
<div class="mx-4">
<Form />
<!-- 商品选择区域 -->
<div class="mt-4">
<div class="mb-2 flex items-center">
<span class="text-sm font-medium">秒杀活动商品:</span>
<!-- TODO @puhui999使用 ElButton 这种哈 -->
<el-button class="ml-2" type="primary" @click="handleSelectProduct">
选择商品
</el-button>
@@ -174,7 +194,10 @@ const [Modal, modalApi] = useVbenModal({
已选择: {{ spuName }}
</span>
</div>
<!-- SKU 配置表格 -->
<div v-if="skuTableData.length > 0" class="mt-4">
<!-- TODO @puhui999Grid或者 VXETable -->
<table class="w-full border-collapse border border-gray-300">
<thead>
<tr class="bg-gray-100">
@@ -225,6 +248,8 @@ const [Modal, modalApi] = useVbenModal({
</div>
</div>
</Modal>
<!-- 商品选择器弹窗 -->
<SpuSkuSelect
ref="spuSkuSelectRef"
:is-select-sku="true"

View File

@@ -110,7 +110,6 @@ function emitActivityChange() {
>
<ElTooltip :content="activity.name">
<div class="relative h-full w-full">
<!-- TODO @芋艿 -->
<ElImage
:src="activity.picUrl"
class="h-full w-full rounded-lg object-cover"