feat:【antd】【mall】 优化积分商城活动表单
This commit is contained in:
@@ -5,7 +5,7 @@ import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
|||||||
import type { MallCategoryApi } from '#/api/mall/product/category';
|
import type { MallCategoryApi } from '#/api/mall/product/category';
|
||||||
import type { MallSpuApi } from '#/api/mall/product/spu';
|
import type { MallSpuApi } from '#/api/mall/product/spu';
|
||||||
|
|
||||||
import { computed, onMounted, ref } from 'vue';
|
import { computed, nextTick, onMounted, ref } from 'vue';
|
||||||
|
|
||||||
import { useVbenModal } from '@vben/common-ui';
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
import { handleTree } from '@vben/utils';
|
import { handleTree } from '@vben/utils';
|
||||||
@@ -86,34 +86,21 @@ function selectSku(val: MallSpuApi.Sku[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 处理 SPU 选择变化 */
|
/** 处理 SPU 选择变化 */
|
||||||
function selectSpu(val: MallSpuApi.Spu[]) {
|
function selectSpu(row: MallSpuApi.Spu) {
|
||||||
if (val.length === 0) {
|
if (!row) {
|
||||||
selectedSpuId.value = 0;
|
selectedSpuId.value = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 只选择一个
|
selectedSpuId.value = row.id!;
|
||||||
const firstId = val[0]?.id;
|
|
||||||
if (firstId !== undefined) {
|
|
||||||
selectedSpuId.value = firstId;
|
|
||||||
}
|
|
||||||
// 切换选择 spu 如果有选择的 sku 则清空,确保选择的 sku 是对应的 spu 下面的
|
// 切换选择 spu 如果有选择的 sku 则清空,确保选择的 sku 是对应的 spu 下面的
|
||||||
if (selectedSkuIds.value.length > 0) {
|
if (selectedSkuIds.value.length > 0) {
|
||||||
selectedSkuIds.value = [];
|
selectedSkuIds.value = [];
|
||||||
}
|
}
|
||||||
// 如果大于1个
|
|
||||||
if (val.length > 1) {
|
|
||||||
// 清空选择
|
|
||||||
gridApi.grid.clearCheckboxRow();
|
|
||||||
// 变更为最后一次选择的
|
|
||||||
const lastRow = val.pop();
|
|
||||||
if (lastRow) {
|
|
||||||
gridApi.grid.setCheckboxRow(lastRow, true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 自动展开选中的 SPU
|
// 自动展开选中的 SPU
|
||||||
if (props.isSelectSku && val[0]) {
|
if (props.isSelectSku) {
|
||||||
expandChange(val[0], [val[0]]);
|
expandChange(row, [row]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,33 +168,20 @@ async function expandChange(
|
|||||||
isExpand.value = true;
|
isExpand.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 确认选择时的触发事件 */
|
|
||||||
function confirm() {
|
|
||||||
if (selectedSpuId.value === 0) {
|
|
||||||
message.warning('没有选择任何商品');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (props.isSelectSku && selectedSkuIds.value.length === 0) {
|
|
||||||
message.warning('没有选择任何商品属性');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 返回各自 id 列表
|
|
||||||
props.isSelectSku
|
|
||||||
? emit('confirm', selectedSpuId.value, selectedSkuIds.value)
|
|
||||||
: emit('confirm', selectedSpuId.value);
|
|
||||||
// 关闭弹窗
|
|
||||||
modalApi.close();
|
|
||||||
selectedSpuId.value = 0;
|
|
||||||
selectedSkuIds.value = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 搜索表单 Schema */
|
/** 搜索表单 Schema */
|
||||||
const formSchema = computed(() => useGridFormSchema(categoryTreeList));
|
const formSchema = computed(() => useGridFormSchema(categoryTreeList));
|
||||||
|
|
||||||
/** 表格列配置 */
|
/** 表格列配置 */
|
||||||
const gridColumns = computed<VxeTableGridOptions['columns']>(() =>
|
const gridColumns = computed<VxeTableGridOptions['columns']>(() => {
|
||||||
useGridColumns(props.isSelectSku),
|
const columns = useGridColumns(props.isSelectSku);
|
||||||
);
|
// 将 checkbox 替换为 radio
|
||||||
|
return columns?.map((col) => {
|
||||||
|
if (col.type === 'checkbox') {
|
||||||
|
return { ...col, type: 'radio' };
|
||||||
|
}
|
||||||
|
return col;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
/** 初始化列表 */
|
/** 初始化列表 */
|
||||||
const [Grid, gridApi] = useVbenVxeGrid({
|
const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
@@ -218,10 +192,11 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||||||
},
|
},
|
||||||
gridOptions: {
|
gridOptions: {
|
||||||
columns: gridColumns.value,
|
columns: gridColumns.value,
|
||||||
height: 500,
|
height: 800,
|
||||||
border: true,
|
border: true,
|
||||||
checkboxConfig: {
|
radioConfig: {
|
||||||
reserve: true,
|
reserve: true,
|
||||||
|
highlight: true,
|
||||||
},
|
},
|
||||||
rowConfig: {
|
rowConfig: {
|
||||||
keyField: 'id',
|
keyField: 'id',
|
||||||
@@ -247,8 +222,8 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
gridEvents: {
|
gridEvents: {
|
||||||
checkboxChange: ({ records }: { records: unknown[] }) => {
|
radioChange: ({ row }: { row: MallSpuApi.Spu }) => {
|
||||||
selectSpu(records as MallSpuApi.Spu[]);
|
selectSpu(row);
|
||||||
},
|
},
|
||||||
toggleRowExpand: ({
|
toggleRowExpand: ({
|
||||||
row,
|
row,
|
||||||
@@ -269,15 +244,27 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||||||
/** 初始化弹窗 */
|
/** 初始化弹窗 */
|
||||||
const [Modal, modalApi] = useVbenModal({
|
const [Modal, modalApi] = useVbenModal({
|
||||||
destroyOnClose: true,
|
destroyOnClose: true,
|
||||||
onConfirm: confirm,
|
onConfirm: () => {
|
||||||
|
if (selectedSpuId.value === 0) {
|
||||||
|
message.warning('没有选择任何商品');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (props.isSelectSku && selectedSkuIds.value.length === 0) {
|
||||||
|
message.warning('没有选择任何商品属性');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 返回各自 id 列表
|
||||||
|
props.isSelectSku
|
||||||
|
? emit('confirm', selectedSpuId.value, selectedSkuIds.value)
|
||||||
|
: emit('confirm', selectedSpuId.value);
|
||||||
|
|
||||||
|
// 重置选中状态
|
||||||
|
selectedSpuId.value = 0;
|
||||||
|
selectedSkuIds.value = [];
|
||||||
|
modalApi.close();
|
||||||
|
},
|
||||||
async onOpenChange(isOpen: boolean) {
|
async onOpenChange(isOpen: boolean) {
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
await gridApi.grid.clearCheckboxRow();
|
|
||||||
// 关闭所有展开的行
|
|
||||||
const tableData = gridApi.grid.getTableData().fullData;
|
|
||||||
tableData.forEach((row: MallSpuApi.Spu) => {
|
|
||||||
gridApi.grid.setRowExpand(row, false);
|
|
||||||
});
|
|
||||||
selectedSpuId.value = 0;
|
selectedSpuId.value = 0;
|
||||||
selectedSkuIds.value = [];
|
selectedSkuIds.value = [];
|
||||||
spuData.value = undefined;
|
spuData.value = undefined;
|
||||||
@@ -285,8 +272,11 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
isExpand.value = false;
|
isExpand.value = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 打开时查询数据
|
// 等待 Grid 组件完全初始化后再查询数据
|
||||||
await gridApi.query();
|
await nextTick();
|
||||||
|
if (gridApi.grid) {
|
||||||
|
await gridApi.query();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ export function useFormSchema(): VbenFormSchema[] {
|
|||||||
placeholder: '请输入排序',
|
placeholder: '请输入排序',
|
||||||
class: '!w-full',
|
class: '!w-full',
|
||||||
},
|
},
|
||||||
|
defaultValue: 0,
|
||||||
rules: 'required',
|
rules: 'required',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { MallSpuApi } from '#/api/mall/product/spu';
|
||||||
import type { MallPointActivityApi } from '#/api/mall/promotion/point';
|
import type { MallPointActivityApi } from '#/api/mall/promotion/point';
|
||||||
import type {
|
import type {
|
||||||
RuleConfig,
|
RuleConfig,
|
||||||
@@ -8,7 +9,7 @@ import type {
|
|||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
|
|
||||||
import { useVbenModal } from '@vben/common-ui';
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
import { convertToInteger, formatToFraction } from '@vben/utils';
|
import { cloneDeep, convertToInteger, formatToFraction } from '@vben/utils';
|
||||||
|
|
||||||
import { Button, InputNumber, message } from 'ant-design-vue';
|
import { Button, InputNumber, message } from 'ant-design-vue';
|
||||||
|
|
||||||
@@ -73,14 +74,12 @@ const ruleConfig: RuleConfig[] = [
|
|||||||
},
|
},
|
||||||
]; // SKU 规则配置
|
]; // SKU 规则配置
|
||||||
|
|
||||||
const spuList = ref<any[]>([]); // 选择的 SPU 列表
|
const spuList = ref<MallSpuApi.Spu[]>([]); // 选择的 SPU 列表
|
||||||
// TODO @puhui999:有问题
|
const spuPropertyList = ref<SpuProperty<MallSpuApi.Spu>[]>([]); // SPU 属性列表
|
||||||
const spuPropertyList = ref<SpuProperty<any>[]>([]); // SPU 属性列表
|
|
||||||
|
|
||||||
/** 打开商品选择器 */
|
/** 打开商品选择器 */
|
||||||
// TODO @puhui999:spuSkuSelectRef.value.open is not a function
|
|
||||||
function openSpuSelect() {
|
function openSpuSelect() {
|
||||||
spuSkuSelectRef.value.open();
|
spuSkuSelectRef.value?.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 选择商品后的回调 */
|
/** 选择商品后的回调 */
|
||||||
@@ -108,7 +107,7 @@ async function getSpuDetails(
|
|||||||
? res.skus
|
? res.skus
|
||||||
: res.skus?.filter((sku) => skuIds.includes(sku.id!));
|
: res.skus?.filter((sku) => skuIds.includes(sku.id!));
|
||||||
// 为每个 SKU 配置积分商城相关的配置
|
// 为每个 SKU 配置积分商城相关的配置
|
||||||
selectSkus?.forEach((sku: any) => {
|
selectSkus?.forEach((sku) => {
|
||||||
let config: MallPointActivityApi.PointProduct = {
|
let config: MallPointActivityApi.PointProduct = {
|
||||||
skuId: sku.id!,
|
skuId: sku.id!,
|
||||||
stock: 0,
|
stock: 0,
|
||||||
@@ -124,22 +123,26 @@ async function getSpuDetails(
|
|||||||
}
|
}
|
||||||
config = product || config;
|
config = product || config;
|
||||||
}
|
}
|
||||||
sku.productConfig = config;
|
// 动态添加 productConfig 属性到 SKU
|
||||||
|
(
|
||||||
|
sku as MallSpuApi.Sku & {
|
||||||
|
productConfig: MallPointActivityApi.PointProduct;
|
||||||
|
}
|
||||||
|
).productConfig = config;
|
||||||
});
|
});
|
||||||
res.skus = selectSkus;
|
res.skus = selectSkus;
|
||||||
|
|
||||||
// TODO @puhui999:有问题
|
// 构建 SPU 属性列表
|
||||||
// const spuProperties: SpuProperty[] = [];
|
const spuProperties: SpuProperty<MallSpuApi.Spu>[] = [
|
||||||
const spuProperties: any[] = [];
|
{
|
||||||
spuProperties.push({
|
spuId: res.id!,
|
||||||
spuId: res.id!,
|
spuDetail: res,
|
||||||
spuDetail: res,
|
propertyList: getPropertyList(res),
|
||||||
propertyList: getPropertyList(res),
|
},
|
||||||
});
|
];
|
||||||
|
|
||||||
// TODO @puhui999:貌似直接 = 下面的,不用 push?
|
// 直接赋值,因为每次只选择一个 SPU
|
||||||
spuList.value.push(res);
|
spuList.value = [res];
|
||||||
// TODO @puhui999:貌似直接 = 下面的,不用 push?
|
|
||||||
spuPropertyList.value = spuProperties;
|
spuPropertyList.value = spuProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,9 +156,10 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
}
|
}
|
||||||
modalApi.lock();
|
modalApi.lock();
|
||||||
try {
|
try {
|
||||||
// 获取积分商城商品配置
|
// 获取积分商城商品配置(深拷贝避免直接修改原对象)
|
||||||
const products: MallPointActivityApi.PointProduct[] =
|
const products: MallPointActivityApi.PointProduct[] = cloneDeep(
|
||||||
spuAndSkuListRef.value?.getSkuConfigs('productConfig') || [];
|
spuAndSkuListRef.value?.getSkuConfigs('productConfig') || [],
|
||||||
|
);
|
||||||
// 价格需要转为分
|
// 价格需要转为分
|
||||||
products.forEach((item) => {
|
products.forEach((item) => {
|
||||||
item.price = convertToInteger(item.price);
|
item.price = convertToInteger(item.price);
|
||||||
@@ -182,11 +186,22 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
spuPropertyList.value = [];
|
spuPropertyList.value = [];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 加载数据
|
// 重置表单数据(新增和编辑模式都需要)
|
||||||
|
formData.value = undefined;
|
||||||
|
spuList.value = [];
|
||||||
|
spuPropertyList.value = [];
|
||||||
|
// 加载数据(仅编辑模式)
|
||||||
const data = modalApi.getData<MallPointActivityApi.PointActivity>();
|
const data = modalApi.getData<MallPointActivityApi.PointActivity>();
|
||||||
if (!data || !data.id) {
|
if (!data || !data.id) {
|
||||||
|
// 新增模式:重置表单字段
|
||||||
|
await formApi.setValues({
|
||||||
|
sort: 0,
|
||||||
|
remark: '',
|
||||||
|
spuId: undefined,
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 编辑模式:加载数据
|
||||||
modalApi.lock();
|
modalApi.lock();
|
||||||
try {
|
try {
|
||||||
formData.value = await getPointActivity(data.id);
|
formData.value = await getPointActivity(data.id);
|
||||||
@@ -216,11 +231,10 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
|
|
||||||
<!-- SPU 和 SKU 列表展示 -->
|
<!-- SPU 和 SKU 列表展示 -->
|
||||||
<SpuAndSkuList
|
<SpuAndSkuList
|
||||||
v-if="spuList.length > 0"
|
|
||||||
ref="spuAndSkuListRef"
|
ref="spuAndSkuListRef"
|
||||||
:rule-config="ruleConfig"
|
:rule-config="ruleConfig"
|
||||||
:spu-list="spuList"
|
:spu-list="spuList"
|
||||||
:spu-property-list="spuPropertyList"
|
:spu-property-list-p="spuPropertyList"
|
||||||
class="mt-4"
|
class="mt-4"
|
||||||
>
|
>
|
||||||
<!-- 扩展列:积分商城特有配置 -->
|
<!-- 扩展列:积分商城特有配置 -->
|
||||||
|
|||||||
Reference in New Issue
Block a user