feat:【mall】diy editor 的 hot-zone 代码优化(100%)完成商品分类的支持

This commit is contained in:
YunaiV
2025-10-28 23:21:07 +08:00
parent 05dc2c7eb2
commit fe7a69f570
4 changed files with 63 additions and 51 deletions

View File

@@ -3,32 +3,33 @@ import { computed, onMounted, ref } from 'vue';
import { handleTree } from '@vben/utils'; import { handleTree } from '@vben/utils';
import { ElTreeSelect } from 'element-plus';
import { getCategoryList } from '#/api/mall/product/category'; import { getCategoryList } from '#/api/mall/product/category';
/** 商品分类选择组件 */ /** 商品分类选择组件 */
defineOptions({ name: 'ProductCategorySelect' }); defineOptions({ name: 'ProductCategorySelect' });
const props = defineProps({ const props = defineProps({
// ID
modelValue: { modelValue: {
type: [Number, Array<Number>], type: [Number, Array<Number>],
default: undefined, default: undefined,
}, }, // ID
//
multiple: { multiple: {
type: Boolean, type: Boolean,
default: false, default: false,
}, }, //
//
parentId: { parentId: {
type: Number, type: Number,
default: undefined, default: undefined,
}, }, //
}); });
/** 分类选择 */ /** 分类选择 */
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
const categoryList = ref<any[]>([]); //
/** 选中的分类 ID */ /** 选中的分类 ID */
const selectCategoryId = computed({ const selectCategoryId = computed({
get: () => { get: () => {
@@ -40,7 +41,6 @@ const selectCategoryId = computed({
}); });
/** 初始化 */ /** 初始化 */
const categoryList = ref<any[]>([]); //
onMounted(async () => { onMounted(async () => {
const data = await getCategoryList({ const data = await getCategoryList({
parentId: props.parentId, parentId: props.parentId,
@@ -49,20 +49,19 @@ onMounted(async () => {
}); });
</script> </script>
<template> <template>
<el-tree-select <ElTreeSelect
v-model="selectCategoryId" v-model="selectCategoryId"
:data="categoryList" :data="categoryList"
node-key="id"
:props="{ :props="{
children: 'children', children: 'children',
label: 'name', label: 'name',
value: 'id',
isLeaf: 'leaf',
emitPath: false,
}" }"
:multiple="multiple" :multiple="multiple"
:show-checkbox="multiple" :show-checkbox="multiple"
class="w-1/1" check-strictly
node-key="id" default-expand-all
class="w-full"
placeholder="请选择商品分类" placeholder="请选择商品分类"
/> />
</template> </template>

View File

@@ -0,0 +1 @@
export { default as ProductCategorySelect } from './category-select.vue';

View File

@@ -8,9 +8,15 @@ import { nextTick, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui'; import { useVbenModal } from '@vben/common-ui';
import { getUrlNumberValue } from '@vben/utils'; import { getUrlNumberValue } from '@vben/utils';
import { ElButton, ElScrollbar, ElTooltip } from 'element-plus'; import {
ElButton,
ElForm,
ElFormItem,
ElScrollbar,
ElTooltip,
} from 'element-plus';
import ProductCategorySelect from '#/views/mall/product/category/components/product-category-select.vue'; import { ProductCategorySelect } from '#/views/mall/product/category/components/';
import { APP_LINK_GROUP_LIST, APP_LINK_TYPE_ENUM } from './data'; import { APP_LINK_GROUP_LIST, APP_LINK_TYPE_ENUM } from './data';
@@ -33,9 +39,7 @@ const groupBtnRefs = ref<ButtonInstance[]>([]); // 分组引用列表
const detailSelectDialog = ref<{ const detailSelectDialog = ref<{
id?: number; id?: number;
type?: APP_LINK_TYPE_ENUM; type?: APP_LINK_TYPE_ENUM;
visible: boolean;
}>({ }>({
visible: false,
id: undefined, id: undefined,
type: undefined, type: undefined,
}); // 详情选择对话框 }); // 详情选择对话框
@@ -48,6 +52,14 @@ const [Modal, modalApi] = useVbenModal({
}, },
}); });
const [DetailSelectModal, detailSelectModalApi] = useVbenModal({
onConfirm() {
detailSelectModalApi.close();
},
});
defineExpose({ open });
/** 打开弹窗 */ /** 打开弹窗 */
async function open(link: string) { async function open(link: string) {
activeAppLink.value.path = link; activeAppLink.value.path = link;
@@ -69,8 +81,6 @@ async function open(link: string) {
} }
} }
defineExpose({ open });
/** 处理 APP 链接选中 */ /** 处理 APP 链接选中 */
function handleAppLinkSelected(appLink: AppLink) { function handleAppLinkSelected(appLink: AppLink) {
if (!isSameLink(appLink.path, activeAppLink.value.path)) { if (!isSameLink(appLink.path, activeAppLink.value.path)) {
@@ -78,7 +88,6 @@ function handleAppLinkSelected(appLink: AppLink) {
} }
switch (appLink.type) { switch (appLink.type) {
case APP_LINK_TYPE_ENUM.PRODUCT_CATEGORY_LIST: { case APP_LINK_TYPE_ENUM.PRODUCT_CATEGORY_LIST: {
detailSelectDialog.value.visible = true;
detailSelectDialog.value.type = appLink.type; detailSelectDialog.value.type = appLink.type;
// 返显 // 返显
detailSelectDialog.value.id = detailSelectDialog.value.id =
@@ -86,6 +95,7 @@ function handleAppLinkSelected(appLink: AppLink) {
'id', 'id',
`http://127.0.0.1${activeAppLink.value.path}`, `http://127.0.0.1${activeAppLink.value.path}`,
) || undefined; ) || undefined;
detailSelectModalApi.open();
break; break;
} }
default: { default: {
@@ -144,41 +154,41 @@ function isSameLink(link1: string, link2: string) {
/** 处理详情选择 */ /** 处理详情选择 */
function handleProductCategorySelected(id: number) { function handleProductCategorySelected(id: number) {
// TODO @AI这里有点问题activeAppLink 地址; // 生成 activeAppLink
const url = new URL(activeAppLink.value.path, 'http://127.0.0.1'); const url = new URL(activeAppLink.value.path, 'http://127.0.0.1');
// 修改 id 参数
url.searchParams.set('id', `${id}`); url.searchParams.set('id', `${id}`);
// 排除域名
activeAppLink.value.path = `${url.pathname}${url.search}`; activeAppLink.value.path = `${url.pathname}${url.search}`;
// 关闭对话框
detailSelectDialog.value.visible = false; // 关闭对话框,并重置 id
// 重置 id detailSelectModalApi.close();
detailSelectDialog.value.id = undefined; detailSelectDialog.value.id = undefined;
} }
</script> </script>
<template> <template>
<Modal title="选择链接" class="w-[65%]"> <Modal title="选择链接" class="w-[65%]">
<div class="flex h-[500px] gap-2"> <div class="flex h-[500px] gap-2">
<!-- 左侧分组列表 --> <div class="flex flex-col">
<ElScrollbar <!-- 左侧分组列表 -->
wrap-class="h-full" <ElScrollbar
ref="groupScrollbar" wrap-class="h-full"
view-class="flex flex-col" ref="groupScrollbar"
class="border-r border-gray-200 pr-2" view-class="flex flex-col"
> class="border-r border-gray-200 pr-2"
<ElButton
v-for="(group, groupIndex) in APP_LINK_GROUP_LIST"
:key="groupIndex"
class="ml-0 mr-4 w-[90px] justify-start"
:class="[{ active: activeGroup === group.name }]"
ref="groupBtnRefs"
:text="activeGroup !== group.name"
:type="activeGroup === group.name ? 'primary' : 'default'"
@click="handleGroupSelected(group.name)"
> >
{{ group.name }} <ElButton
</ElButton> v-for="(group, groupIndex) in APP_LINK_GROUP_LIST"
</ElScrollbar> :key="groupIndex"
class="!ml-0 mb-1 mr-4 !justify-start"
:class="[{ active: activeGroup === group.name }]"
ref="groupBtnRefs"
:text="activeGroup !== group.name"
:type="activeGroup === group.name ? 'primary' : 'default'"
@click="handleGroupSelected(group.name)"
>
{{ group.name }}
</ElButton>
</ElScrollbar>
</div>
<!-- 右侧链接列表 --> <!-- 右侧链接列表 -->
<ElScrollbar <ElScrollbar
class="h-full flex-1 pl-2" class="h-full flex-1 pl-2"
@@ -219,9 +229,9 @@ function handleProductCategorySelected(id: number) {
</div> </div>
</Modal> </Modal>
<el-dialog v-model="detailSelectDialog.visible" title="" width="50%"> <DetailSelectModal title="选择分类" class="w-[65%]">
<el-form class="min-h-[200px]"> <ElForm class="min-h-[200px]">
<el-form-item <ElFormItem
label="选择分类" label="选择分类"
v-if=" v-if="
detailSelectDialog.type === APP_LINK_TYPE_ENUM.PRODUCT_CATEGORY_LIST detailSelectDialog.type === APP_LINK_TYPE_ENUM.PRODUCT_CATEGORY_LIST
@@ -232,7 +242,7 @@ function handleProductCategorySelected(id: number) {
:parent-id="0" :parent-id="0"
@update:model-value="handleProductCategorySelected" @update:model-value="handleProductCategorySelected"
/> />
</el-form-item> </ElFormItem>
</el-form> </ElForm>
</el-dialog> </DetailSelectModal>
</template> </template>

View File

@@ -167,11 +167,13 @@ const setHeight = (item: HotZoneItemProperty, height: number) => {
const activeHotZone = ref<HotZoneItemProperty>(); const activeHotZone = ref<HotZoneItemProperty>();
const appLinkDialogRef = ref(); const appLinkDialogRef = ref();
/** 显示 App 链接选择对话框 */
const handleShowAppLinkDialog = (hotZone: HotZoneItemProperty) => { const handleShowAppLinkDialog = (hotZone: HotZoneItemProperty) => {
activeHotZone.value = hotZone; activeHotZone.value = hotZone;
appLinkDialogRef.value.open(hotZone.url); appLinkDialogRef.value.open(hotZone.url);
}; };
/** 处理 App 链接选择变更 */
const handleAppLinkChange = (appLink: AppLink) => { const handleAppLinkChange = (appLink: AppLink) => {
if (!appLink || !activeHotZone.value) { if (!appLink || !activeHotZone.value) {
return; return;