|
|
@@ -2,6 +2,8 @@
|
|
|
import { nextTick, ref, useTemplateRef } from 'vue';
|
|
|
import { NButton, NImage, NTag } from 'naive-ui';
|
|
|
import {
|
|
|
+ fetchAddCategory,
|
|
|
+ fetchDeleteCategory,
|
|
|
fetchGategoryImport,
|
|
|
fetchGetAllStoreList,
|
|
|
fetchGetDeskCategoryList,
|
|
|
@@ -56,69 +58,16 @@ const [registerSearchForm, { getFieldsValue: getSearchForm, setFieldsValue }] =
|
|
|
collapsedRows: 1
|
|
|
});
|
|
|
const importTemplateRef = useTemplateRef('importTemplateRef');
|
|
|
-const tableColumns: NaiveUI.TableColumn<Api.goods.ShopCategory>[] = [
|
|
|
- {
|
|
|
- title: '分类名称',
|
|
|
- key: 'name'
|
|
|
- },
|
|
|
- {
|
|
|
- title: '分类图标',
|
|
|
- key: 'icon',
|
|
|
- render(row) {
|
|
|
- return <NImage src={row.icon} class="h-[40px] w-[40px]" />;
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- title: '关联商品',
|
|
|
- key: 'prodCount',
|
|
|
- render: row => {
|
|
|
- return row.level == 3 ? `${row.prodCount}个商品` : '';
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- title: '标签',
|
|
|
- key: 'labelName',
|
|
|
- render: row => {
|
|
|
- return row.labelName ? <NTag> {row.labelName} </NTag> : '';
|
|
|
- }
|
|
|
- },
|
|
|
- {
|
|
|
- title: '排序',
|
|
|
- key: 'num'
|
|
|
- },
|
|
|
- {
|
|
|
- title: '操作',
|
|
|
- key: 'op',
|
|
|
- fixed: 'right',
|
|
|
- align: 'center',
|
|
|
- render: row => (
|
|
|
- <div class="flex-center gap-8px">
|
|
|
- {
|
|
|
- <NButton type="primary" size="small" quaternary onClick={() => edit(row)}>
|
|
|
- 编辑
|
|
|
- </NButton>
|
|
|
- }
|
|
|
- {row.level == 3 && (
|
|
|
- <NButton
|
|
|
- type="primary"
|
|
|
- size="small"
|
|
|
- quaternary
|
|
|
- onClick={() => relatedGoodsModalRef.value?.handleOpenModal(row)}
|
|
|
- >
|
|
|
- 关联商品
|
|
|
- </NButton>
|
|
|
- )}
|
|
|
- </div>
|
|
|
- )
|
|
|
- }
|
|
|
-];
|
|
|
+
|
|
|
const [
|
|
|
registerModalForm,
|
|
|
{
|
|
|
openModal: openModalForm,
|
|
|
setFieldsValue: setModalFormValue,
|
|
|
getFieldsValue: getModalFormValue,
|
|
|
- closeModal: closeModalForm
|
|
|
+ closeModal: closeModalForm,
|
|
|
+ setModalProps,
|
|
|
+ setSubLoading
|
|
|
}
|
|
|
] = useModalFrom({
|
|
|
modalConfig: {
|
|
|
@@ -129,13 +78,26 @@ const [
|
|
|
schemas: [
|
|
|
{ label: '', field: 'id', show: false, component: 'NInput' },
|
|
|
{ label: '', field: 'level', show: false, component: 'NInput' },
|
|
|
+ { label: '', field: 'pid', show: false, component: 'NInput' },
|
|
|
+ { label: '', field: 'parentCode', show: false, component: 'NInput' },
|
|
|
+ {
|
|
|
+ label: '所属二级分类',
|
|
|
+ field: 'BreadName',
|
|
|
+ component: 'NGradientText',
|
|
|
+ render({ model, field }) {
|
|
|
+ return <div> {model[field]} </div>;
|
|
|
+ },
|
|
|
+ ifShow({ model, field }) {
|
|
|
+ return model[field];
|
|
|
+ }
|
|
|
+ },
|
|
|
{
|
|
|
label: '分类名称',
|
|
|
field: 'name',
|
|
|
component: 'NInput',
|
|
|
required: true,
|
|
|
- componentProps: {
|
|
|
- disabled: true
|
|
|
+ ifShow({ model }) {
|
|
|
+ return model.level == 3;
|
|
|
}
|
|
|
},
|
|
|
{
|
|
|
@@ -148,7 +110,10 @@ const [
|
|
|
aspectRatioH: 1,
|
|
|
max: 1
|
|
|
},
|
|
|
- required: true
|
|
|
+ required: true,
|
|
|
+ ifShow({ model }) {
|
|
|
+ return model.level != 3;
|
|
|
+ }
|
|
|
},
|
|
|
{
|
|
|
label: '标签',
|
|
|
@@ -184,6 +149,69 @@ const [
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
+const tableColumns: NaiveUI.TableColumn<Api.goods.ShopCategory>[] = [
|
|
|
+ {
|
|
|
+ title: '分类名称',
|
|
|
+ key: 'name'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '分类图标',
|
|
|
+ key: 'icon',
|
|
|
+ render(row) {
|
|
|
+ return <NImage src={row.icon} class="h-[40px] w-[40px]" />;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '关联商品',
|
|
|
+ key: 'prodCount',
|
|
|
+ render: row => {
|
|
|
+ return row.level == 3 ? `${row.prodCount}个商品` : '';
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '标签',
|
|
|
+ key: 'labelName',
|
|
|
+ render: row => {
|
|
|
+ return row.labelName ? <NTag> {row.labelName} </NTag> : '';
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '排序',
|
|
|
+ key: 'num'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '操作',
|
|
|
+ key: 'op',
|
|
|
+ fixed: 'right',
|
|
|
+ align: 'center',
|
|
|
+ width: 230,
|
|
|
+ render: row => (
|
|
|
+ <div class="flex-center gap-8px">
|
|
|
+ {row.level == 2 && (
|
|
|
+ <NButton type="primary" size="small" quaternary onClick={() => add(row)}>
|
|
|
+ 添加三级分类
|
|
|
+ </NButton>
|
|
|
+ )}
|
|
|
+ {row.level == 3 && (
|
|
|
+ <NButton type="primary" size="small" quaternary onClick={() => handleOpenRelatedGoods(row)}>
|
|
|
+ 关联商品
|
|
|
+ </NButton>
|
|
|
+ )}
|
|
|
+ {
|
|
|
+ <NButton type="primary" size="small" quaternary onClick={() => edit(row)}>
|
|
|
+ 编辑
|
|
|
+ </NButton>
|
|
|
+ }
|
|
|
+
|
|
|
+ {row.level == 3 && (
|
|
|
+ <NButton type="primary" size="small" quaternary onClick={() => del(row)}>
|
|
|
+ 删除
|
|
|
+ </NButton>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+ }
|
|
|
+];
|
|
|
const failColumns: NaiveUI.TableColumn<Api.goods.ShopCategoryLogVO>[] = [
|
|
|
{
|
|
|
key: 'index',
|
|
|
@@ -263,25 +291,58 @@ async function handleSubmit(file: File) {
|
|
|
}
|
|
|
importTemplateRef.value?.setSubLoading(false);
|
|
|
}
|
|
|
-function edit(row: Recordable) {
|
|
|
+function edit(row: Api.goods.ShopCategory) {
|
|
|
openModalForm(row);
|
|
|
+ setModalProps({ title: `修改${row.level}级分类` });
|
|
|
setModalFormValue({ ...row, label: row.label });
|
|
|
}
|
|
|
-
|
|
|
+function add(row: Api.goods.ShopCategory) {
|
|
|
+ const { ancestors, current } = getRowHierarchyInfo(row, deskData.value);
|
|
|
+ const level1Name = ancestors[0].name;
|
|
|
+ const level2Name = current.name;
|
|
|
+ openModalForm();
|
|
|
+ setModalProps({ title: `新增三级分类` });
|
|
|
+ setModalFormValue({ level: 3, pid: row.id, parentCode: row.code, BreadName: `${level1Name} > ${level2Name}` });
|
|
|
+}
|
|
|
+function del(row: Api.goods.ShopCategory) {
|
|
|
+ window.$dialog?.info({
|
|
|
+ title: '删除分类',
|
|
|
+ content: '你确定要删除吗?',
|
|
|
+ positiveText: '确定',
|
|
|
+ negativeText: '取消',
|
|
|
+ onPositiveClick: async () => {
|
|
|
+ const { error } = await fetchDeleteCategory(row.id);
|
|
|
+ if (!error) {
|
|
|
+ getData();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+}
|
|
|
async function getData() {
|
|
|
const { data, error } = await fetchGetDeskCategoryList(getSearchForm());
|
|
|
+
|
|
|
if (!error) {
|
|
|
deskData.value = buildTree(data).sort((a, b) => b.num - a.num);
|
|
|
console.log(deskData.value);
|
|
|
}
|
|
|
}
|
|
|
+function handleOpenRelatedGoods(row: Api.goods.ShopCategory) {
|
|
|
+ const { ancestors, current } = getRowHierarchyInfo(row, deskData.value);
|
|
|
+ const level1Name = ancestors[0].name;
|
|
|
+ const level2Name = ancestors[0].name;
|
|
|
+ const level3Name = current.name;
|
|
|
+ relatedGoodsModalRef.value?.handleOpenModal({ ...row, level1Name, level2Name, level3Name });
|
|
|
+}
|
|
|
async function handleSubmitForm() {
|
|
|
const form = await getModalFormValue();
|
|
|
- const { error } = await fetchUpdateCategory(form);
|
|
|
+ const level = form.level;
|
|
|
+ const { error } =
|
|
|
+ level != 3 ? await fetchUpdateCategory(form) : await fetchAddCategory({ ...form, shopId: getSearchForm().shopId });
|
|
|
if (!error) {
|
|
|
closeModalForm();
|
|
|
getData();
|
|
|
}
|
|
|
+ setSubLoading(false);
|
|
|
}
|
|
|
|
|
|
function handleOpen() {
|
|
|
@@ -345,6 +406,74 @@ function buildTree<T>(items: T[], options: BuildTreeOptions = {}): T[] {
|
|
|
|
|
|
return tree;
|
|
|
}
|
|
|
+function getRowHierarchyInfo(
|
|
|
+ row: Api.goods.ShopCategory,
|
|
|
+ allData: Api.goods.ShopCategory[]
|
|
|
+): {
|
|
|
+ current: Api.goods.ShopCategory;
|
|
|
+ parent: Api.goods.ShopCategory | null;
|
|
|
+ children: Api.goods.ShopCategory[];
|
|
|
+ ancestors: Api.goods.ShopCategory[];
|
|
|
+ descendants: Api.goods.ShopCategory[];
|
|
|
+} {
|
|
|
+ // 查找父节点
|
|
|
+ const findParent = (data: Api.goods.ShopCategory[], targetPid: number): Api.goods.ShopCategory | null => {
|
|
|
+ for (const item of data) {
|
|
|
+ if (item.id === targetPid) {
|
|
|
+ return item;
|
|
|
+ }
|
|
|
+ if (item.children && item.children.length > 0) {
|
|
|
+ const found = findParent(item.children, targetPid);
|
|
|
+ if (found) return found;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 查找所有祖先节点
|
|
|
+ const findAncestors = (data: Api.goods.ShopCategory[], targetPid: number): Api.goods.ShopCategory[] => {
|
|
|
+ const ancestors: Api.goods.ShopCategory[] = [];
|
|
|
+ let currentPid = targetPid;
|
|
|
+
|
|
|
+ while (currentPid !== 0) {
|
|
|
+ const parent = findParent(data, currentPid);
|
|
|
+ if (parent) {
|
|
|
+ ancestors.unshift(parent); // 添加到数组开头以保持层级顺序
|
|
|
+ currentPid = parent.pid;
|
|
|
+ } else {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return ancestors;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 获取所有子孙节点
|
|
|
+ const getAllDescendants = (node: Api.goods.ShopCategory): Api.goods.ShopCategory[] => {
|
|
|
+ let descendants: Api.goods.ShopCategory[] = [];
|
|
|
+
|
|
|
+ if (node.children && node.children.length > 0) {
|
|
|
+ node.children.forEach(child => {
|
|
|
+ descendants.push(child);
|
|
|
+ descendants = descendants.concat(getAllDescendants(child));
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ return descendants;
|
|
|
+ };
|
|
|
+
|
|
|
+ const parent = row.pid === 0 ? null : findParent(allData, row.pid);
|
|
|
+ const ancestors = findAncestors(allData, row.pid);
|
|
|
+ const descendants = getAllDescendants(row);
|
|
|
+
|
|
|
+ return {
|
|
|
+ current: row,
|
|
|
+ parent,
|
|
|
+ children: row.children || [],
|
|
|
+ ancestors,
|
|
|
+ descendants
|
|
|
+ };
|
|
|
+}
|
|
|
</script>
|
|
|
|
|
|
<template>
|