feat:【ele】【mall】product/spu 的 components 迁移
This commit is contained in:
@@ -26,8 +26,8 @@ const props = withDefaults(defineProps<SpuShowcaseProps>(), {
|
|||||||
|
|
||||||
const emit = defineEmits(['update:modelValue', 'change']);
|
const emit = defineEmits(['update:modelValue', 'change']);
|
||||||
|
|
||||||
const productSpus = ref<MallSpuApi.Spu[]>([]);
|
const productSpus = ref<MallSpuApi.Spu[]>([]); // 已选择的商品列表
|
||||||
const spuTableSelectRef = ref<InstanceType<typeof SpuTableSelect>>();
|
const spuTableSelectRef = ref<InstanceType<typeof SpuTableSelect>>(); // 商品选择表格组件引用
|
||||||
const isMultiple = computed(() => props.limit !== 1); // 是否为多选模式
|
const isMultiple = computed(() => props.limit !== 1); // 是否为多选模式
|
||||||
|
|
||||||
/** 计算是否可以添加 */
|
/** 计算是否可以添加 */
|
||||||
@@ -47,12 +47,10 @@ watch(
|
|||||||
async (newValue) => {
|
async (newValue) => {
|
||||||
// eslint-disable-next-line unicorn/no-nested-ternary
|
// eslint-disable-next-line unicorn/no-nested-ternary
|
||||||
const ids = Array.isArray(newValue) ? newValue : newValue ? [newValue] : [];
|
const ids = Array.isArray(newValue) ? newValue : newValue ? [newValue] : [];
|
||||||
|
|
||||||
if (ids.length === 0) {
|
if (ids.length === 0) {
|
||||||
productSpus.value = [];
|
productSpus.value = [];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 只有商品发生变化时才重新查询
|
// 只有商品发生变化时才重新查询
|
||||||
if (
|
if (
|
||||||
productSpus.value.length === 0 ||
|
productSpus.value.length === 0 ||
|
||||||
@@ -103,16 +101,16 @@ function emitSpuChange() {
|
|||||||
<div
|
<div
|
||||||
v-for="(spu, index) in productSpus"
|
v-for="(spu, index) in productSpus"
|
||||||
:key="spu.id"
|
:key="spu.id"
|
||||||
class="spu-item group relative"
|
class="group relative h-[60px] w-[60px] overflow-hidden rounded-lg"
|
||||||
>
|
>
|
||||||
<Tooltip :title="spu.name">
|
<Tooltip :title="spu.name">
|
||||||
<div class="relative h-full w-full">
|
<div class="relative h-full w-full">
|
||||||
<Image
|
<Image
|
||||||
:src="spu.picUrl"
|
:src="spu.picUrl"
|
||||||
class="h-full w-full rounded-lg object-cover"
|
class="h-full w-full rounded-lg object-cover"
|
||||||
:preview="false"
|
|
||||||
/>
|
/>
|
||||||
<!-- 删除按钮 -->
|
<!-- 删除按钮 -->
|
||||||
|
<!-- TODO @AI:还是使用 IconifyIcon:使用自己的 + 图标 -->
|
||||||
<CloseCircleFilled
|
<CloseCircleFilled
|
||||||
v-if="!disabled"
|
v-if="!disabled"
|
||||||
class="absolute -right-2 -top-2 cursor-pointer text-xl text-red-500 opacity-0 transition-opacity hover:text-red-600 group-hover:opacity-100"
|
class="absolute -right-2 -top-2 cursor-pointer text-xl text-red-500 opacity-0 transition-opacity hover:text-red-600 group-hover:opacity-100"
|
||||||
@@ -125,9 +123,10 @@ function emitSpuChange() {
|
|||||||
<!-- 添加商品按钮 -->
|
<!-- 添加商品按钮 -->
|
||||||
<Tooltip v-if="canAdd" title="选择商品">
|
<Tooltip v-if="canAdd" title="选择商品">
|
||||||
<div
|
<div
|
||||||
class="spu-add-box hover:border-primary hover:bg-primary/5 flex cursor-pointer items-center justify-center rounded-lg border-2 border-dashed transition-colors"
|
class="hover:border-primary hover:bg-primary/5 flex h-[60px] w-[60px] cursor-pointer items-center justify-center rounded-lg border-2 border-dashed transition-colors"
|
||||||
@click="handleOpenSpuSelect"
|
@click="handleOpenSpuSelect"
|
||||||
>
|
>
|
||||||
|
<!-- TODO @AI:还是使用 IconifyIcon:使用自己的 + 图标 -->
|
||||||
<PlusOutlined class="text-xl text-gray-400" />
|
<PlusOutlined class="text-xl text-gray-400" />
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -140,17 +139,3 @@ function emitSpuChange() {
|
|||||||
@change="handleSpuSelected"
|
@change="handleSpuSelected"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.spu-item {
|
|
||||||
width: 60px;
|
|
||||||
height: 60px;
|
|
||||||
border-radius: 8px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.spu-add-box {
|
|
||||||
width: 60px;
|
|
||||||
height: 60px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { VbenFormSchema } from '#/adapter/form';
|
import type { VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||||
|
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, onMounted, ref } from 'vue';
|
||||||
@@ -15,7 +16,7 @@ import { getSpuPage } from '#/api/mall/product/spu';
|
|||||||
import { getRangePickerDefaultProps } from '#/utils';
|
import { getRangePickerDefaultProps } from '#/utils';
|
||||||
|
|
||||||
interface SpuTableSelectProps {
|
interface SpuTableSelectProps {
|
||||||
multiple?: boolean;
|
multiple?: boolean; // 是否单选:true - checkbox;false - radio
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<SpuTableSelectProps>(), {
|
const props = withDefaults(defineProps<SpuTableSelectProps>(), {
|
||||||
@@ -26,9 +27,17 @@ const emit = defineEmits<{
|
|||||||
change: [spu: MallSpuApi.Spu | MallSpuApi.Spu[]];
|
change: [spu: MallSpuApi.Spu | MallSpuApi.Spu[]];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// TODO @芋艿:要不要加类型;
|
const categoryList = ref<MallCategoryApi.Category[]>([]); // 分类列表
|
||||||
const categoryList = ref<any[]>([]);
|
const categoryTreeList = ref<any[]>([]); // 分类树
|
||||||
const categoryTreeList = ref<any[]>([]);
|
|
||||||
|
/** 单选:处理选中变化 */
|
||||||
|
function handleRadioChange() {
|
||||||
|
const selectedRow = gridApi.grid.getRadioRecord() as MallSpuApi.Spu;
|
||||||
|
if (selectedRow) {
|
||||||
|
emit('change', selectedRow);
|
||||||
|
modalApi.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 搜索表单 Schema */
|
/** 搜索表单 Schema */
|
||||||
const formSchema = computed<VbenFormSchema[]>(() => [
|
const formSchema = computed<VbenFormSchema[]>(() => [
|
||||||
@@ -45,8 +54,9 @@ const formSchema = computed<VbenFormSchema[]>(() => [
|
|||||||
fieldName: 'categoryId',
|
fieldName: 'categoryId',
|
||||||
label: '商品分类',
|
label: '商品分类',
|
||||||
component: 'TreeSelect',
|
component: 'TreeSelect',
|
||||||
|
// TODO @芋艿:可能要测试下;
|
||||||
componentProps: {
|
componentProps: {
|
||||||
treeData: categoryTreeList.value,
|
treeData: categoryTreeList,
|
||||||
fieldNames: {
|
fieldNames: {
|
||||||
label: 'name',
|
label: 'name',
|
||||||
value: 'id',
|
value: 'id',
|
||||||
@@ -121,74 +131,42 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||||||
columns: gridColumns.value,
|
columns: gridColumns.value,
|
||||||
height: 500,
|
height: 500,
|
||||||
border: true,
|
border: true,
|
||||||
showOverflow: true,
|
checkboxConfig: {
|
||||||
checkboxConfig: props.multiple
|
|
||||||
? {
|
|
||||||
reserve: true,
|
reserve: true,
|
||||||
}
|
},
|
||||||
: undefined,
|
radioConfig: {
|
||||||
radioConfig: props.multiple
|
|
||||||
? undefined
|
|
||||||
: {
|
|
||||||
reserve: true,
|
reserve: true,
|
||||||
},
|
},
|
||||||
|
rowConfig: {
|
||||||
|
keyField: 'id',
|
||||||
|
isHover: true,
|
||||||
|
},
|
||||||
proxyConfig: {
|
proxyConfig: {
|
||||||
ajax: {
|
ajax: {
|
||||||
async query({ page }: any, formValues: any) {
|
async query({ page }: any, formValues: any) {
|
||||||
// TODO @芋艿:怎么简化下。
|
return await getSpuPage({
|
||||||
const data = await getSpuPage({
|
|
||||||
pageNo: page.currentPage,
|
pageNo: page.currentPage,
|
||||||
pageSize: page.pageSize,
|
pageSize: page.pageSize,
|
||||||
tabType: 0,
|
tabType: 0,
|
||||||
name: formValues.name || undefined,
|
...formValues,
|
||||||
categoryId: formValues.categoryId || undefined,
|
|
||||||
createTime: formValues.createTime || undefined,
|
|
||||||
});
|
});
|
||||||
return {
|
|
||||||
items: data.list || [],
|
|
||||||
total: data.total || 0,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
gridEvents: props.multiple
|
gridEvents: {
|
||||||
? {
|
|
||||||
checkboxChange: handleCheckboxChange,
|
|
||||||
checkboxAll: handleCheckboxChange,
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
radioChange: handleRadioChange,
|
radioChange: handleRadioChange,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/** 多选:处理选中变化 */
|
|
||||||
// TODO @芋艿:要不要清理掉?
|
|
||||||
function handleCheckboxChange() {
|
|
||||||
// vxe-table 自动管理选中状态,无需手动处理
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 单选:处理选中变化 */
|
|
||||||
function handleRadioChange() {
|
|
||||||
const selectedRow = gridApi.grid.getRadioRecord() as MallSpuApi.Spu;
|
|
||||||
if (selectedRow) {
|
|
||||||
emit('change', selectedRow);
|
|
||||||
modalApi.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const [Modal, modalApi] = useVbenModal({
|
const [Modal, modalApi] = useVbenModal({
|
||||||
destroyOnClose: true,
|
destroyOnClose: true,
|
||||||
// TODO @芋艿:看看怎么简化
|
showConfirmButton: props.multiple, // 特殊:radio 单选情况下,走 handleRadioChange 处理。
|
||||||
onConfirm: props.multiple
|
onConfirm: () => {
|
||||||
? () => {
|
const selectedRows = gridApi.grid.getCheckboxRecords() as MallSpuApi.Spu[];
|
||||||
const selectedRows =
|
|
||||||
gridApi.grid.getCheckboxRecords() as MallSpuApi.Spu[];
|
|
||||||
emit('change', selectedRows);
|
emit('change', selectedRows);
|
||||||
modalApi.close();
|
modalApi.close();
|
||||||
}
|
},
|
||||||
: undefined,
|
|
||||||
// TODO @芋艿:看看怎么简化?
|
|
||||||
async onOpenChange(isOpen: boolean) {
|
async onOpenChange(isOpen: boolean) {
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
gridApi.grid.clearCheckboxRow();
|
gridApi.grid.clearCheckboxRow();
|
||||||
@@ -196,39 +174,52 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1. 先查询数据
|
||||||
|
await gridApi.query();
|
||||||
|
// 2. 设置已选中行
|
||||||
const data = modalApi.getData<MallSpuApi.Spu | MallSpuApi.Spu[]>();
|
const data = modalApi.getData<MallSpuApi.Spu | MallSpuApi.Spu[]>();
|
||||||
|
if (props.multiple && Array.isArray(data) && data.length > 0) {
|
||||||
if (props.multiple && Array.isArray(data)) {
|
|
||||||
// 等待数据加载完成后再设置选中状态
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
const tableData = gridApi.grid.getTableData().fullData;
|
||||||
data.forEach((spu) => {
|
data.forEach((spu) => {
|
||||||
gridApi.grid.setCheckboxRow(spu, true);
|
const row = tableData.find(
|
||||||
|
(item: MallSpuApi.Spu) => item.id === spu.id,
|
||||||
|
);
|
||||||
|
if (row) {
|
||||||
|
gridApi.grid.setCheckboxRow(row, true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}, 100);
|
}, 300);
|
||||||
} else if (!props.multiple && data && !Array.isArray(data)) {
|
} else if (!props.multiple && data && !Array.isArray(data)) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
gridApi.grid.setRadioRow(data);
|
const tableData = gridApi.grid.getTableData().fullData;
|
||||||
}, 100);
|
const row = tableData.find(
|
||||||
|
(item: MallSpuApi.Spu) => item.id === data.id,
|
||||||
|
);
|
||||||
|
if (row) {
|
||||||
|
gridApi.grid.setRadioRow(row);
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/** 初始化分类数据 */
|
|
||||||
onMounted(async () => {
|
|
||||||
categoryList.value = await getCategoryList({});
|
|
||||||
categoryTreeList.value = handleTree(categoryList.value, 'id', 'parentId');
|
|
||||||
});
|
|
||||||
|
|
||||||
/** 对外暴露的方法 */
|
/** 对外暴露的方法 */
|
||||||
defineExpose({
|
defineExpose({
|
||||||
open: (data?: MallSpuApi.Spu | MallSpuApi.Spu[]) => {
|
open: (data?: MallSpuApi.Spu | MallSpuApi.Spu[]) => {
|
||||||
modalApi.setData(data).open();
|
modalApi.setData(data).open();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** 初始化分类数据 */
|
||||||
|
onMounted(async () => {
|
||||||
|
categoryList.value = await getCategoryList({});
|
||||||
|
categoryTreeList.value = handleTree(categoryList.value, 'id', 'parentId');
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Modal :class="props.multiple ? 'w-[900px]' : 'w-[800px]'" title="选择商品">
|
<Modal title="选择商品" class="w-[950px]">
|
||||||
<Grid />
|
<Grid />
|
||||||
</Modal>
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export function getCategoryList(params: any) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获得商品分类列表
|
/** 获得商品分类列表 */
|
||||||
export function getCategorySimpleList() {
|
export function getCategorySimpleList() {
|
||||||
return requestClient.get<MallCategoryApi.Category[]>(
|
return requestClient.get<MallCategoryApi.Category[]>(
|
||||||
'/product/category/list',
|
'/product/category/list',
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
export { default as SkuTableSelect } from './sku-table-select.vue';
|
export { default as SkuTableSelect } from './sku-table-select.vue';
|
||||||
export { default as SpuShowcase } from './spu-showcase.vue';
|
export { default as SpuShowcase } from './spu-showcase.vue';
|
||||||
export { default as SpuTableSelect } from './spu-table-select.vue';
|
export { default as SpuTableSelect } from './spu-table-select.vue';
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,15 @@ const gridColumns = computed<VxeGridProps['columns']>(() => [
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
/** 处理选中 */
|
||||||
|
function handleRadioChange() {
|
||||||
|
const selectedRow = gridApi.grid.getRadioRecord() as MallSpuApi.Sku;
|
||||||
|
if (selectedRow) {
|
||||||
|
emit('change', selectedRow);
|
||||||
|
modalApi.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO @芋艿:要不要直接非 pager?
|
// TODO @芋艿:要不要直接非 pager?
|
||||||
const [Grid, gridApi] = useVbenVxeGrid({
|
const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
gridOptions: {
|
gridOptions: {
|
||||||
@@ -89,15 +98,6 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/** 处理选中 */
|
|
||||||
function handleRadioChange() {
|
|
||||||
const selectedRow = gridApi.grid.getRadioRecord() as MallSpuApi.Sku;
|
|
||||||
if (selectedRow) {
|
|
||||||
emit('change', selectedRow);
|
|
||||||
modalApi.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const [Modal, modalApi] = useVbenModal({
|
const [Modal, modalApi] = useVbenModal({
|
||||||
destroyOnClose: true,
|
destroyOnClose: true,
|
||||||
onOpenChange: async (isOpen: boolean) => {
|
onOpenChange: async (isOpen: boolean) => {
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ const props = withDefaults(defineProps<SpuShowcaseProps>(), {
|
|||||||
|
|
||||||
const emit = defineEmits(['update:modelValue', 'change']);
|
const emit = defineEmits(['update:modelValue', 'change']);
|
||||||
|
|
||||||
const productSpus = ref<MallSpuApi.Spu[]>([]);
|
const productSpus = ref<MallSpuApi.Spu[]>([]); // 已选择的商品列表
|
||||||
const spuTableSelectRef = ref<InstanceType<typeof SpuTableSelect>>();
|
const spuTableSelectRef = ref<InstanceType<typeof SpuTableSelect>>(); // 商品选择表格组件引用
|
||||||
const isMultiple = computed(() => props.limit !== 1); // 是否为多选模式
|
const isMultiple = computed(() => props.limit !== 1); // 是否为多选模式
|
||||||
|
|
||||||
/** 计算是否可以添加 */
|
/** 计算是否可以添加 */
|
||||||
@@ -101,7 +101,7 @@ function emitSpuChange() {
|
|||||||
<div
|
<div
|
||||||
v-for="(spu, index) in productSpus"
|
v-for="(spu, index) in productSpus"
|
||||||
:key="spu.id"
|
:key="spu.id"
|
||||||
class="spu-item group relative"
|
class="group relative h-[60px] w-[60px] overflow-hidden rounded-lg"
|
||||||
>
|
>
|
||||||
<ElTooltip :content="spu.name">
|
<ElTooltip :content="spu.name">
|
||||||
<div class="relative h-full w-full">
|
<div class="relative h-full w-full">
|
||||||
@@ -125,7 +125,7 @@ function emitSpuChange() {
|
|||||||
<!-- 添加商品按钮 -->
|
<!-- 添加商品按钮 -->
|
||||||
<ElTooltip v-if="canAdd" content="选择商品">
|
<ElTooltip v-if="canAdd" content="选择商品">
|
||||||
<div
|
<div
|
||||||
class="spu-add-box hover:border-primary hover:bg-primary/5 flex cursor-pointer items-center justify-center rounded-lg border-2 border-dashed transition-colors"
|
class="hover:border-primary hover:bg-primary/5 flex h-[60px] w-[60px] cursor-pointer items-center justify-center rounded-lg border-2 border-dashed transition-colors"
|
||||||
@click="handleOpenSpuSelect"
|
@click="handleOpenSpuSelect"
|
||||||
>
|
>
|
||||||
<IconifyIcon icon="ep:plus" class="text-xl text-gray-400" />
|
<IconifyIcon icon="ep:plus" class="text-xl text-gray-400" />
|
||||||
@@ -140,17 +140,3 @@ function emitSpuChange() {
|
|||||||
@change="handleSpuSelected"
|
@change="handleSpuSelected"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.spu-item {
|
|
||||||
width: 60px;
|
|
||||||
height: 60px;
|
|
||||||
border-radius: 8px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.spu-add-box {
|
|
||||||
width: 60px;
|
|
||||||
height: 60px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { VbenFormSchema } from '#/adapter/form';
|
import type { VbenFormSchema } from '#/adapter/form';
|
||||||
import type { VxeGridProps } from '#/adapter/vxe-table';
|
import type { VxeGridProps } from '#/adapter/vxe-table';
|
||||||
|
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, onMounted, ref } from 'vue';
|
||||||
@@ -15,7 +16,7 @@ import { getSpuPage } from '#/api/mall/product/spu';
|
|||||||
import { getRangePickerDefaultProps } from '#/utils';
|
import { getRangePickerDefaultProps } from '#/utils';
|
||||||
|
|
||||||
interface SpuTableSelectProps {
|
interface SpuTableSelectProps {
|
||||||
multiple?: boolean;
|
multiple?: boolean; // 是否单选:true - checkbox;false - radio
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<SpuTableSelectProps>(), {
|
const props = withDefaults(defineProps<SpuTableSelectProps>(), {
|
||||||
@@ -26,9 +27,17 @@ const emit = defineEmits<{
|
|||||||
change: [spu: MallSpuApi.Spu | MallSpuApi.Spu[]];
|
change: [spu: MallSpuApi.Spu | MallSpuApi.Spu[]];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// TODO @芋艿:要不要加类型;
|
const categoryList = ref<MallCategoryApi.Category[]>([]); // 分类列表
|
||||||
const categoryList = ref<any[]>([]);
|
const categoryTreeList = ref<any[]>([]); // 分类树
|
||||||
const categoryTreeList = ref<any[]>([]);
|
|
||||||
|
/** 单选:处理选中变化 */
|
||||||
|
function handleRadioChange() {
|
||||||
|
const selectedRow = gridApi.grid.getRadioRecord() as MallSpuApi.Spu;
|
||||||
|
if (selectedRow) {
|
||||||
|
emit('change', selectedRow);
|
||||||
|
modalApi.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 搜索表单 Schema */
|
/** 搜索表单 Schema */
|
||||||
const formSchema = computed<VbenFormSchema[]>(() => [
|
const formSchema = computed<VbenFormSchema[]>(() => [
|
||||||
@@ -38,24 +47,19 @@ const formSchema = computed<VbenFormSchema[]>(() => [
|
|||||||
component: 'Input',
|
component: 'Input',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
placeholder: '请输入商品名称',
|
placeholder: '请输入商品名称',
|
||||||
allowClear: true,
|
clearable: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldName: 'categoryId',
|
fieldName: 'categoryId',
|
||||||
label: '商品分类',
|
label: '商品分类',
|
||||||
component: 'TreeSelect',
|
component: 'ApiTreeSelect',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
treeData: categoryTreeList.value,
|
options: categoryTreeList,
|
||||||
fieldNames: {
|
props: { label: 'name', children: 'children' },
|
||||||
label: 'name',
|
nodeKey: 'id',
|
||||||
value: 'id',
|
|
||||||
},
|
|
||||||
treeCheckStrictly: true,
|
|
||||||
placeholder: '请选择商品分类',
|
placeholder: '请选择商品分类',
|
||||||
allowClear: true,
|
clearable: true,
|
||||||
showSearch: true,
|
|
||||||
treeNodeFilterProp: 'name',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -64,7 +68,7 @@ const formSchema = computed<VbenFormSchema[]>(() => [
|
|||||||
component: 'RangePicker',
|
component: 'RangePicker',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
...getRangePickerDefaultProps(),
|
...getRangePickerDefaultProps(),
|
||||||
allowClear: true,
|
clearable: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
@@ -121,15 +125,10 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||||||
columns: gridColumns.value,
|
columns: gridColumns.value,
|
||||||
height: 500,
|
height: 500,
|
||||||
border: true,
|
border: true,
|
||||||
showOverflow: true,
|
checkboxConfig: {
|
||||||
checkboxConfig: props.multiple
|
|
||||||
? {
|
|
||||||
reserve: true,
|
reserve: true,
|
||||||
}
|
},
|
||||||
: undefined,
|
radioConfig: {
|
||||||
radioConfig: props.multiple
|
|
||||||
? undefined
|
|
||||||
: {
|
|
||||||
reserve: true,
|
reserve: true,
|
||||||
},
|
},
|
||||||
rowConfig: {
|
rowConfig: {
|
||||||
@@ -149,43 +148,19 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
gridEvents: props.multiple
|
gridEvents: {
|
||||||
? {
|
|
||||||
checkboxChange: handleCheckboxChange,
|
|
||||||
checkboxAll: handleCheckboxChange,
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
radioChange: handleRadioChange,
|
radioChange: handleRadioChange,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/** 多选:处理选中变化 */
|
|
||||||
// TODO @芋艿:要不要清理掉?
|
|
||||||
function handleCheckboxChange() {
|
|
||||||
// vxe-table 自动管理选中状态,无需手动处理
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 单选:处理选中变化 */
|
|
||||||
function handleRadioChange() {
|
|
||||||
const selectedRow = gridApi.grid.getRadioRecord() as MallSpuApi.Spu;
|
|
||||||
if (selectedRow) {
|
|
||||||
emit('change', selectedRow);
|
|
||||||
modalApi.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const [Modal, modalApi] = useVbenModal({
|
const [Modal, modalApi] = useVbenModal({
|
||||||
destroyOnClose: true,
|
destroyOnClose: true,
|
||||||
// TODO @芋艿:看看怎么简化
|
showConfirmButton: props.multiple, // 特殊:radio 单选情况下,走 handleRadioChange 处理。
|
||||||
onConfirm: props.multiple
|
onConfirm: () => {
|
||||||
? () => {
|
const selectedRows = gridApi.grid.getCheckboxRecords() as MallSpuApi.Spu[];
|
||||||
const selectedRows =
|
|
||||||
gridApi.grid.getCheckboxRecords() as MallSpuApi.Spu[];
|
|
||||||
emit('change', selectedRows);
|
emit('change', selectedRows);
|
||||||
modalApi.close();
|
modalApi.close();
|
||||||
}
|
},
|
||||||
: undefined,
|
|
||||||
// TODO @芋艿:看看怎么简化?
|
|
||||||
async onOpenChange(isOpen: boolean) {
|
async onOpenChange(isOpen: boolean) {
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
gridApi.grid.clearCheckboxRow();
|
gridApi.grid.clearCheckboxRow();
|
||||||
@@ -193,18 +168,17 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = modalApi.getData<MallSpuApi.Spu | MallSpuApi.Spu[]>();
|
// 1. 先查询数据
|
||||||
|
|
||||||
// 先查询数据,确保表格已加载
|
|
||||||
await gridApi.query();
|
await gridApi.query();
|
||||||
|
// 2. 设置已选中行
|
||||||
|
const data = modalApi.getData<MallSpuApi.Spu | MallSpuApi.Spu[]>();
|
||||||
if (props.multiple && Array.isArray(data) && data.length > 0) {
|
if (props.multiple && Array.isArray(data) && data.length > 0) {
|
||||||
// 等待数据加载完成后再设置选中状态
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const tableData = gridApi.grid.getTableData().fullData;
|
const tableData = gridApi.grid.getTableData().fullData;
|
||||||
data.forEach((spu) => {
|
data.forEach((spu) => {
|
||||||
// 在表格数据中查找匹配的行
|
const row = tableData.find(
|
||||||
const row = tableData.find((item: MallSpuApi.Spu) => item.id === spu.id);
|
(item: MallSpuApi.Spu) => item.id === spu.id,
|
||||||
|
);
|
||||||
if (row) {
|
if (row) {
|
||||||
gridApi.grid.setCheckboxRow(row, true);
|
gridApi.grid.setCheckboxRow(row, true);
|
||||||
}
|
}
|
||||||
@@ -213,8 +187,9 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
} else if (!props.multiple && data && !Array.isArray(data)) {
|
} else if (!props.multiple && data && !Array.isArray(data)) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const tableData = gridApi.grid.getTableData().fullData;
|
const tableData = gridApi.grid.getTableData().fullData;
|
||||||
// 在表格数据中查找匹配的行
|
const row = tableData.find(
|
||||||
const row = tableData.find((item: MallSpuApi.Spu) => item.id === data.id);
|
(item: MallSpuApi.Spu) => item.id === data.id,
|
||||||
|
);
|
||||||
if (row) {
|
if (row) {
|
||||||
gridApi.grid.setRadioRow(row);
|
gridApi.grid.setRadioRow(row);
|
||||||
}
|
}
|
||||||
@@ -223,22 +198,22 @@ const [Modal, modalApi] = useVbenModal({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/** 初始化分类数据 */
|
|
||||||
onMounted(async () => {
|
|
||||||
categoryList.value = await getCategoryList({});
|
|
||||||
categoryTreeList.value = handleTree(categoryList.value, 'id', 'parentId');
|
|
||||||
});
|
|
||||||
|
|
||||||
/** 对外暴露的方法 */
|
/** 对外暴露的方法 */
|
||||||
defineExpose({
|
defineExpose({
|
||||||
open: (data?: MallSpuApi.Spu | MallSpuApi.Spu[]) => {
|
open: (data?: MallSpuApi.Spu | MallSpuApi.Spu[]) => {
|
||||||
modalApi.setData(data).open();
|
modalApi.setData(data).open();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** 初始化分类数据 */
|
||||||
|
onMounted(async () => {
|
||||||
|
categoryList.value = await getCategoryList({});
|
||||||
|
categoryTreeList.value = handleTree(categoryList.value, 'id', 'parentId');
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Modal :class="props.multiple ? 'w-[900px]' : 'w-[800px]'" title="选择商品">
|
<Modal title="选择商品" class="w-[950px]">
|
||||||
<Grid />
|
<Grid />
|
||||||
</Modal>
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ import { handleTree } from '@vben/utils';
|
|||||||
import { getCategoryList } from '#/api/mall/product/category';
|
import { getCategoryList } from '#/api/mall/product/category';
|
||||||
import { getRangePickerDefaultProps } from '#/utils';
|
import { getRangePickerDefaultProps } from '#/utils';
|
||||||
|
|
||||||
// TODO @霖:所有 mall 的 search 少了,请输入 xxx;表单也是类似
|
|
||||||
|
|
||||||
/** 列表的搜索表单 */
|
/** 列表的搜索表单 */
|
||||||
export function useGridFormSchema(): VbenFormSchema[] {
|
export function useGridFormSchema(): VbenFormSchema[] {
|
||||||
return [
|
return [
|
||||||
|
|||||||
Reference in New Issue
Block a user