review:【antd】【mall】商品发布的迁移

This commit is contained in:
YunaiV
2025-11-26 10:21:19 +08:00
parent 58e8a71936
commit 2401559fa5
9 changed files with 30 additions and 49 deletions

View File

@@ -16,7 +16,6 @@ export function useFormSchema(): VbenFormSchema[] {
show: () => false, show: () => false,
}, },
}, },
// TODO @puhui999商品的选择
{ {
fieldName: 'spuId', fieldName: 'spuId',
label: '商品', label: '商品',
@@ -24,11 +23,9 @@ export function useFormSchema(): VbenFormSchema[] {
componentProps: { componentProps: {
placeholder: '请选择商品', placeholder: '请选择商品',
}, },
renderComponentContent: () => ({
default: () => null,
}),
rules: 'required', rules: 'required',
}, },
// TODO @puhui999商品的选择上面 spuId 可以选择了,下面的 skuId 打开后,没商品。
{ {
fieldName: 'skuId', fieldName: 'skuId',
label: '商品规格', label: '商品规格',
@@ -40,9 +37,6 @@ export function useFormSchema(): VbenFormSchema[] {
triggerFields: ['spuId'], triggerFields: ['spuId'],
show: (values) => !!values.spuId, show: (values) => !!values.spuId,
}, },
renderComponentContent: () => ({
default: () => null,
}),
rules: 'required', rules: 'required',
}, },
{ {

View File

@@ -48,6 +48,7 @@ const [Form, formApi] = useVbenForm({
const skuTableSelectRef = ref<InstanceType<typeof SkuTableSelect>>(); const skuTableSelectRef = ref<InstanceType<typeof SkuTableSelect>>();
const selectedSku = ref<MallSpuApi.Sku>(); const selectedSku = ref<MallSpuApi.Sku>();
/** 处理商品的选择变化 */
async function handleSpuChange(spu?: MallSpuApi.Spu | null) { async function handleSpuChange(spu?: MallSpuApi.Spu | null) {
// 处理商品选择:如果 spu 为 null 或 id 为 0表示清空选择 // 处理商品选择:如果 spu 为 null 或 id 为 0表示清空选择
const spuId = spu?.id && spu.id ? spu.id : undefined; const spuId = spu?.id && spu.id ? spu.id : undefined;
@@ -59,6 +60,7 @@ async function handleSpuChange(spu?: MallSpuApi.Spu | null) {
await formApi.setFieldValue('skuId', undefined); await formApi.setFieldValue('skuId', undefined);
} }
/** 打开商品规格的选择弹框 */
async function openSkuSelect() { async function openSkuSelect() {
const currentValues = const currentValues =
(await formApi.getValues()) as Partial<MallCommentApi.Comment>; (await formApi.getValues()) as Partial<MallCommentApi.Comment>;
@@ -70,6 +72,7 @@ async function openSkuSelect() {
skuTableSelectRef.value?.open({ spuId: currentSpuId }); skuTableSelectRef.value?.open({ spuId: currentSpuId });
} }
/** 处理商品规格的选择 */
async function handleSkuSelected(sku: MallSpuApi.Sku) { async function handleSkuSelected(sku: MallSpuApi.Sku) {
selectedSku.value = sku; selectedSku.value = sku;
formData.value.skuId = sku.id; formData.value.skuId = sku.id;
@@ -98,6 +101,7 @@ const [Modal, modalApi] = useVbenModal({
async onOpenChange(isOpen: boolean) { async onOpenChange(isOpen: boolean) {
if (!isOpen) { if (!isOpen) {
// 重置表单数据 // 重置表单数据
// TODO @puhui999105 到 108 的代码,不需要的呀?(可以测试下)
formData.value = { formData.value = {
descriptionScores: 5, descriptionScores: 5,
benefitScores: 5, benefitScores: 5,
@@ -108,6 +112,7 @@ const [Modal, modalApi] = useVbenModal({
// 加载数据 // 加载数据
const data = modalApi.getData<MallCommentApi.Comment>(); const data = modalApi.getData<MallCommentApi.Comment>();
if (!data || !data.id) { if (!data || !data.id) {
// TODO @puhui999115 到 121 的代码,不需要的呀?(可以测试下)
// 新建模式:重置表单 // 新建模式:重置表单
formData.value = { formData.value = {
descriptionScores: 5, descriptionScores: 5,
@@ -123,7 +128,7 @@ const [Modal, modalApi] = useVbenModal({
formData.value = await getComment(data.id); formData.value = await getComment(data.id);
// 设置到 values // 设置到 values
await formApi.setValues(formData.value); await formApi.setValues(formData.value);
// 回显已选规格 // 回显已选的商品规格
if (formData.value?.spuId && formData.value?.skuId) { if (formData.value?.spuId && formData.value?.skuId) {
const spu = await getSpu(formData.value.spuId); const spu = await getSpu(formData.value.spuId);
const sku = spu.skus?.find((item) => item.id === formData.value!.skuId); const sku = spu.skus?.find((item) => item.id === formData.value!.skuId);
@@ -166,9 +171,8 @@ const [Modal, modalApi] = useVbenModal({
selectedSku.properties.length > 0 selectedSku.properties.length > 0
" "
> >
已选:{{ 已选:
selectedSku.properties.map((p: any) => p.valueName).join('/') {{ selectedSku.properties.map((p: any) => p.valueName).join('/') }}
}}
</span> </span>
<span v-else-if="selectedSku">已选:{{ selectedSku.id }}</span> <span v-else-if="selectedSku">已选:{{ selectedSku.id }}</span>
</div> </div>

View File

@@ -2,7 +2,7 @@
import type { MallSpuApi } from '#/api/mall/product/spu'; import type { MallSpuApi } from '#/api/mall/product/spu';
import type { PropertyAndValues } from '#/views/mall/product/spu/components/type'; import type { PropertyAndValues } from '#/views/mall/product/spu/components/type';
/** 获得商品的规格列表 - 商品相关的公共函数(被其模块如 promotion 使用) */ /** 获得商品的规格列表 - 商品相关的公共函数(被其模块如 promotion 使用) */
const getPropertyList = (spu: MallSpuApi.Spu): PropertyAndValues[] => { const getPropertyList = (spu: MallSpuApi.Spu): PropertyAndValues[] => {
// 直接拿返回的 skus 属性逆向生成出 propertyList // 直接拿返回的 skus 属性逆向生成出 propertyList
const properties: PropertyAndValues[] = []; const properties: PropertyAndValues[] = [];

View File

@@ -78,6 +78,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
enabled: false, enabled: false,
}, },
proxyConfig: { proxyConfig: {
// TODO @puhui999看看注释的部分后续要不要删除
// autoLoad: false, // 禁用自动加载,手动触发查询 // autoLoad: false, // 禁用自动加载,手动触发查询
ajax: { ajax: {
query: async () => { query: async () => {
@@ -121,6 +122,7 @@ async function openModal(data?: SpuData) {
} }
spuId.value = data.spuId; spuId.value = data.spuId;
visible.value = true; visible.value = true;
// TODO @puhui999看看注释的部分后续要不要删除
// // 等待弹窗和 Grid 组件完全渲染后再查询数据 // // 等待弹窗和 Grid 组件完全渲染后再查询数据
// await nextTick(); // await nextTick();
// if (gridApi.grid) { // if (gridApi.grid) {

View File

@@ -45,6 +45,7 @@ const expandRowKeys = ref<string[]>([]); // 控制展开行需要设置 row-key
function getSkuConfigs(extendedAttribute: string) { function getSkuConfigs(extendedAttribute: string) {
// 验证 SKU 数据(如果有 ref 的话) // 验证 SKU 数据(如果有 ref 的话)
if (skuListRef.value) { if (skuListRef.value) {
// TODO @puhui999这里有个 linter 错误;
try { try {
skuListRef.value.validateSku(); skuListRef.value.validateSku();
} catch (error) { } catch (error) {
@@ -64,8 +65,7 @@ function getSkuConfigs(extendedAttribute: string) {
return seckillProducts; return seckillProducts;
} }
// 暴露出给表单提交时使用 defineExpose({ getSkuConfigs }); // 暴露出给表单提交时使用
defineExpose({ getSkuConfigs });
/** 多选时可以删除 SPU */ /** 多选时可以删除 SPU */
async function deleteSpu(spuId: number) { async function deleteSpu(spuId: number) {
@@ -77,9 +77,7 @@ async function deleteSpu(spuId: number) {
} }
} }
/** /** 将传进来的值赋值给 spuData */
* 将传进来的值赋值给 spuData
*/
watch( watch(
() => props.spuList, () => props.spuList,
(data) => { (data) => {
@@ -92,9 +90,7 @@ watch(
}, },
); );
/** /** 将传进来的值赋值给 spuPropertyList */
* 将传进来的值赋值给 spuPropertyList
*/
watch( watch(
() => props.spuPropertyListP, () => props.spuPropertyListP,
(data) => { (data) => {

View File

@@ -6,13 +6,9 @@ import type { MallCategoryApi } from '#/api/mall/product/category';
import { computed } from 'vue'; import { computed } from 'vue';
import { formatToFraction } from '@vben/utils';
import { getRangePickerDefaultProps } from '#/utils'; import { getRangePickerDefaultProps } from '#/utils';
/** /** 列表的搜索表单 */
* @description: 列表的搜索表单
*/
export function useGridFormSchema( export function useGridFormSchema(
categoryTreeList: Ref<MallCategoryApi.Category[] | unknown[]>, categoryTreeList: Ref<MallCategoryApi.Category[] | unknown[]>,
): VbenFormSchema[] { ): VbenFormSchema[] {
@@ -55,9 +51,7 @@ export function useGridFormSchema(
]; ];
} }
/** /** 列表的字段 */
* @description: 列表的字段
*/
export function useGridColumns( export function useGridColumns(
isSelectSku: boolean, isSelectSku: boolean,
): VxeTableGridOptions['columns'] { ): VxeTableGridOptions['columns'] {
@@ -95,10 +89,7 @@ export function useGridColumns(
title: '商品售价', title: '商品售价',
minWidth: 90, minWidth: 90,
align: 'center', align: 'center',
formatter: ({ cellValue }) => { formatter: 'formatAmount2',
// 格式化价格显示(价格以分为单位存储)
return formatToFraction(cellValue);
},
}, },
{ {
field: 'salesCount', field: 'salesCount',

View File

@@ -104,7 +104,7 @@ async function expandChange(
expandedRows?: MallSpuApi.Spu[], expandedRows?: MallSpuApi.Spu[],
) { ) {
// 判断需要展开的 spuId === 选择的 spuId。如果选择了 A 就展开 A 的 skuList。如果选择了 A 手动展开 B 则阻断 // 判断需要展开的 spuId === 选择的 spuId。如果选择了 A 就展开 A 的 skuList。如果选择了 A 手动展开 B 则阻断
// 目的防止误选 sku // 目的防止误选 sku
if (selectedSpuId.value !== 0) { if (selectedSpuId.value !== 0) {
if (row.id !== selectedSpuId.value) { if (row.id !== selectedSpuId.value) {
message.warning('你已选择商品请先取消'); message.warning('你已选择商品请先取消');
@@ -138,8 +138,6 @@ async function expandChange(
return; return;
} }
const res = (await getSpu(row.id)) as MallSpuApi.Spu; const res = (await getSpu(row.id)) as MallSpuApi.Spu;
// 注意API 返回的价格应该已经是分为单位,无需转换
// 如果 API 返回的是元,则需要转换为分:
res.skus?.forEach((item) => { res.skus?.forEach((item) => {
if (typeof item.price === 'number') { if (typeof item.price === 'number') {
item.price = Math.round(item.price * 100); item.price = Math.round(item.price * 100);
@@ -162,10 +160,7 @@ async function expandChange(
isExpand.value = true; isExpand.value = true;
} }
/** 搜索表单 Schema */ const formSchema = computed(() => useGridFormSchema(categoryTreeList)); // 搜索表单 Schema
const formSchema = computed(() => useGridFormSchema(categoryTreeList));
/** 表格列配置 */
const gridColumns = computed<VxeTableGridOptions['columns']>(() => { const gridColumns = computed<VxeTableGridOptions['columns']>(() => {
const columns = useGridColumns(props.isSelectSku); const columns = useGridColumns(props.isSelectSku);
// 将 checkbox 替换为 radio // 将 checkbox 替换为 radio
@@ -175,9 +170,8 @@ const gridColumns = computed<VxeTableGridOptions['columns']>(() => {
} }
return col; return col;
}); });
}); }); // 表格列配置
/** 初始化列表 */
const [Grid, gridApi] = useVbenVxeGrid({ const [Grid, gridApi] = useVbenVxeGrid({
formOptions: { formOptions: {
schema: formSchema.value, schema: formSchema.value,
@@ -196,6 +190,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
keyField: 'id', keyField: 'id',
isHover: true, isHover: true,
}, },
// TODO @puhui999貌似直接 { trigger: 'row', reserve: true } 就可以了?不会影响 radio 的哈。(可以测试下。)
expandConfig: props.isSelectSku expandConfig: props.isSelectSku
? { ? {
trigger: 'row', trigger: 'row',
@@ -240,8 +235,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
}, },
}); });
/** 弹窗显示状态 */ const visible = ref(false); // 弹窗显示状态
const visible = ref(false);
/** 打开弹窗 */ /** 打开弹窗 */
async function openModal() { async function openModal() {

View File

@@ -215,10 +215,9 @@ function handleConfirm() {
closeModal(); closeModal();
} }
/** 对外暴露的方法 */
defineExpose({ defineExpose({
open: openModal, open: openModal,
}); }); // 对外暴露的方法
/** 初始化分类数据 */ /** 初始化分类数据 */
onMounted(async () => { onMounted(async () => {

View File

@@ -132,14 +132,13 @@ async function getSpuDetails(
}); });
res.skus = selectSkus; res.skus = selectSkus;
// 构建 SPU 属性列表
const spuProperties: SpuProperty<MallSpuApi.Spu>[] = [ const spuProperties: SpuProperty<MallSpuApi.Spu>[] = [
{ {
spuId: res.id!, spuId: res.id!,
spuDetail: res, spuDetail: res,
propertyList: getPropertyList(res), propertyList: getPropertyList(res),
}, },
]; ]; // 构建 SPU 属性列表
// 直接赋值,因为每次只选择一个 SPU // 直接赋值,因为每次只选择一个 SPU
spuList.value = [res]; spuList.value = [res];
@@ -187,13 +186,15 @@ const [Modal, modalApi] = useVbenModal({
return; return;
} }
// 重置表单数据(新增和编辑模式都需要) // 重置表单数据(新增和编辑模式都需要)
// TODO @puhui999这里的重置是不是在 183 到 185 已经处理了呀。
formData.value = undefined; formData.value = undefined;
spuList.value = []; spuList.value = [];
spuPropertyList.value = []; spuPropertyList.value = [];
// 加载数据(仅编辑模式) // 加载数据
const data = modalApi.getData<MallPointActivityApi.PointActivity>(); const data = modalApi.getData<MallPointActivityApi.PointActivity>();
if (!data || !data.id) { if (!data || !data.id) {
// 新增模式:重置表单字段 // 新增模式:重置表单字段
// TODO @puhui999197 到 201 这块的 setValues 的设置,是不是必要哈。可以看看。
await formApi.setValues({ await formApi.setValues({
sort: 0, sort: 0,
remark: '', remark: '',
@@ -201,7 +202,7 @@ const [Modal, modalApi] = useVbenModal({
}); });
return; return;
} }
// 编辑模式:加载数据 // 加载数据
modalApi.lock(); modalApi.lock();
try { try {
formData.value = await getPointActivity(data.id); formData.value = await getPointActivity(data.id);