Files
frontend/apps/web-ele/src/views/mall/promotion/combination/components/table-select.vue

286 lines
7.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 拼团活动选择弹窗组件 -->
<script lang="ts" setup>
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeGridProps } from '#/adapter/vxe-table';
import type { MallCategoryApi } from '#/api/mall/product/category';
import type { MallCombinationActivityApi } from '#/api/mall/promotion/combination/combinationActivity';
import { computed, onMounted, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { fenToYuan, formatDate, handleTree } from '@vben/utils';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { getCategoryList } from '#/api/mall/product/category';
import { getCombinationActivityPage } from '#/api/mall/promotion/combination/combinationActivity';
interface CombinationTableSelectProps {
multiple?: boolean; // 是否多选true - checkboxfalse - radio
}
const props = withDefaults(defineProps<CombinationTableSelectProps>(), {
multiple: false,
});
const emit = defineEmits<{
change: [
activity:
| MallCombinationActivityApi.CombinationActivity
| MallCombinationActivityApi.CombinationActivity[],
];
}>();
const categoryList = ref<MallCategoryApi.Category[]>([]); // 分类列表
const categoryTreeList = ref<any[]>([]); // 分类树
/** 单选:处理选中变化 */
function handleRadioChange() {
const selectedRow =
gridApi.grid.getRadioRecord() as MallCombinationActivityApi.CombinationActivity;
if (selectedRow) {
emit('change', selectedRow);
modalApi.close();
}
}
/**
* 格式化拼团价格
* @param products
*/
const formatCombinationPrice = (
products: MallCombinationActivityApi.CombinationProduct[],
) => {
if (!products || products.length === 0) return '-';
const combinationPrice = Math.min(
...products.map((item) => item.combinationPrice || 0),
);
return `${fenToYuan(combinationPrice)}`;
};
/** 搜索表单 Schema */
const formSchema = computed<VbenFormSchema[]>(() => [
{
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'),
},
},
]);
/** 表格列配置 */
const gridColumns = computed<VxeGridProps['columns']>(() => {
const columns: VxeGridProps['columns'] = [];
if (props.multiple) {
columns.push({ type: 'checkbox', width: 55 });
} else {
columns.push({ type: 'radio', width: 55 });
}
columns.push(
{
field: 'id',
title: '活动编号',
minWidth: 80,
},
{
field: 'name',
title: '活动名称',
minWidth: 140,
},
{
field: 'activityTime',
title: '活动时间',
minWidth: 210,
formatter: ({ row }) => {
return `${formatDate(row.startTime, 'YYYY-MM-DD')} ~ ${formatDate(row.endTime, 'YYYY-MM-DD')}`;
},
},
{
field: 'picUrl',
title: '商品图片',
width: 100,
cellRender: {
name: 'CellImage',
},
},
{
field: 'spuName',
title: '商品标题',
minWidth: 300,
},
{
field: 'marketPrice',
title: '原价',
minWidth: 100,
formatter: ({ cellValue }) => {
return cellValue ? `${fenToYuan(cellValue)}` : '-';
},
},
{
field: 'products',
title: '拼团价',
minWidth: 100,
formatter: ({ cellValue }) => {
return formatCombinationPrice(cellValue);
},
},
{
field: 'groupCount',
title: '开团组数',
minWidth: 100,
},
{
field: 'groupSuccessCount',
title: '成团组数',
minWidth: 100,
},
{
field: 'recordCount',
title: '购买次数',
minWidth: 100,
},
{
field: 'status',
title: '活动状态',
minWidth: 100,
cellRender: {
name: 'CellDict',
props: { type: DICT_TYPE.COMMON_STATUS },
},
},
{
field: 'createTime',
title: '创建时间',
width: 180,
formatter: 'formatDateTime',
},
);
return columns;
});
const [Grid, gridApi] = useVbenVxeGrid({
formOptions: {
schema: formSchema.value,
layout: 'horizontal',
collapsed: false,
},
gridOptions: {
columns: gridColumns.value,
height: 500,
border: true,
checkboxConfig: {
reserve: true,
},
radioConfig: {
reserve: true,
},
rowConfig: {
keyField: 'id',
isHover: true,
},
proxyConfig: {
ajax: {
async query({ page }: any, formValues: any) {
return await getCombinationActivityPage({
pageNo: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
},
},
},
},
gridEvents: {
radioChange: handleRadioChange,
},
});
const [Modal, modalApi] = useVbenModal({
destroyOnClose: true,
showConfirmButton: props.multiple, // 特殊radio 单选情况下,走 handleRadioChange 处理。
onConfirm: () => {
const selectedRows =
gridApi.grid.getCheckboxRecords() as MallCombinationActivityApi.CombinationActivity[];
emit('change', selectedRows);
modalApi.close();
},
async onOpenChange(isOpen: boolean) {
if (!isOpen) {
gridApi.grid.clearCheckboxRow();
gridApi.grid.clearRadioRow();
return;
}
// 1. 先查询数据
await gridApi.query();
// 2. 设置已选中行
const data = modalApi.getData<
| MallCombinationActivityApi.CombinationActivity
| MallCombinationActivityApi.CombinationActivity[]
>();
if (props.multiple && Array.isArray(data) && data.length > 0) {
setTimeout(() => {
const tableData = gridApi.grid.getTableData().fullData;
data.forEach((activity) => {
const row = tableData.find(
(item: MallCombinationActivityApi.CombinationActivity) =>
item.id === activity.id,
);
if (row) {
gridApi.grid.setCheckboxRow(row, true);
}
});
}, 300);
} else if (!props.multiple && data && !Array.isArray(data)) {
setTimeout(() => {
const tableData = gridApi.grid.getTableData().fullData;
const row = tableData.find(
(item: MallCombinationActivityApi.CombinationActivity) =>
item.id === data.id,
);
if (row) {
gridApi.grid.setRadioRow(row);
}
}, 300);
}
},
});
/** 对外暴露的方法 */
defineExpose({
open: (
data?:
| MallCombinationActivityApi.CombinationActivity
| MallCombinationActivityApi.CombinationActivity[],
) => {
modalApi.setData(data).open();
},
});
/** 初始化分类数据 */
onMounted(async () => {
categoryList.value = await getCategoryList({});
categoryTreeList.value = handleTree(categoryList.value, 'id', 'parentId');
});
</script>
<template>
<Modal title="选择活动" class="w-[950px]">
<Grid />
</Modal>
</template>