提交 8221c4e2 authored 作者: 袁伟伟's avatar 袁伟伟

feat: 商城导航

上级 64d60edb
......@@ -67,8 +67,3 @@ export const batchUpdate = (entityList: Array<Goods>) =>
* 查询数量
*/
export const count = (params?: GoodsParams) => defHttp.get<Number>({ url: `${baseApi}/count`, params });
/**
* 产品线查询
*/
export const line = () => defHttp.get<Number>({ url: `/v1/system/third/get/product/line` });
......@@ -85,3 +85,12 @@ export const tree = (params) =>
url: `${baseApi}/tree`,
params,
});
/**
* 查询经销商分类树
*/
export const dealerTree = (params) =>
defHttp.get<DataItem[]>({
url: `${baseApi}/distributor/tree`,
params,
});
import { defHttp } from '/@/utils/http/axios';
const baseApi = '/v1/system/third';
/**
* 产品线查询
*/
export const line = () => defHttp.get<Number>({ url: `${baseApi}/get/product/line` });
import lodash from 'lodash';
import { reactive } from 'vue';
import * as goodsCategoryApi from '/@/api/product/goodsCategoryApi';
import { useUserStore } from '/@/store/modules/user';
const userStore = useUserStore();
const pagination = {
current: 1,
......@@ -28,3 +32,37 @@ export const usePagination = (fun: () => void) => {
};
return reactive(p);
};
const getNavTree = (navList, init?: Function, str) => {
goodsCategoryApi.dealerTree({ parentId: 0 }).then((res) => {
navList.value = res;
userStore.setUserNavList(navList.value);
if (init) {
if (str === 'getGrandsonList') {
init(navList.value);
} else {
init();
}
}
});
};
const navTree = (navList, init?: Function, str) => {
const navListStore = userStore.getNavList;
if (navListStore.length <= 0) {
getNavTree(navList, init, str);
} else {
navList.value = navListStore;
if (init) {
if (str === 'getGrandsonList') {
init(navList.value);
} else {
init();
}
}
}
};
export const useNavTree = () => {
return navTree;
};
......@@ -15,6 +15,8 @@ import { RouteRecordRaw } from 'vue-router';
import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
import { isArray } from '/@/utils/is';
import { h } from 'vue';
import { DataItem } from '/@/views/product/goods-category/type';
// import { useSocketStore } from './socket';
// import { useThingsBoard } from './thingsboard';
......@@ -25,6 +27,7 @@ interface UserState {
sessionTimeout?: boolean;
lastUpdateTime: number;
authorityList: Authority[];
navList: DataItem[];
}
export const useUserStore = defineStore({
......@@ -41,6 +44,7 @@ export const useUserStore = defineStore({
// Last fetch time
lastUpdateTime: 0,
authorityList: [],
navList: [],
}),
getters: {
getUserInfo(): User {
......@@ -73,6 +77,10 @@ export const useUserStore = defineStore({
getIsDistributor(): boolean {
return this.getDistributorId !== 0;
},
getNavList(): DataItem[] {
return this.navList;
},
},
actions: {
setToken(info: string | undefined) {
......@@ -192,6 +200,9 @@ export const useUserStore = defineStore({
},
});
},
setUserNavList(navList: DataItem[]) {
this.navList = navList;
},
},
});
......
......@@ -24,7 +24,7 @@
>禁用</a-button
>
<a-button type="link" v-else @click="handleChangeStatus(record.id, 'YES')">启用</a-button>
<a-button type="link">添加商品</a-button>
<a-button type="link" v-if="record.level === 5">添加商品</a-button>
<a-popconfirm
title="是否确认删除?"
ok-text="是"
......
......@@ -59,7 +59,7 @@
import { defineExpose, ref, reactive, defineEmits, watch, defineProps, onMounted } from 'vue';
import { message } from 'ant-design-vue';
import * as GoodsCategoryApi from '/@/api/product/goodsCategoryApi';
import * as GoodsApi from '/@/api/product/goodsApi';
import * as thirdApi from '/@/api/system/thirdApi';
import { DataItem } from '/@/views/product/goods-category/type';
import { GoodsCategory } from '/@/api/model/goodsCategory';
......@@ -113,7 +113,7 @@
};
const handleGetLineList = () => {
GoodsApi.line().then((res) => {
thirdApi.line().then((res) => {
thirdProductOption.value = res;
});
};
......
export interface DataItem {
children?: DataItem[];
name: string;
id: number;
disabled?: boolean;
}
......@@ -98,10 +98,20 @@
// 获取树结构
const getTreeData = () => {
GoodsCategoryApi.tree({ parentId: 0, status: 'YES' }).then((res: DataItem[]) => {
let idx = 0;
addDisabled(res, idx);
classifyTree.value = res;
});
};
const addDisabled = (arr: DataItem[], idx: number) => {
if (++idx === 5) return;
arr.forEach((item) => {
item.disabled = true;
if (item.children) addDisabled(item.children, idx);
});
};
const validate = () => {
formRef.value.validate().then(() => {
emits('handleSubmit');
......
<template>
<div class="nav">
<ul>
<li>产品线</li>
<template v-for="(item, index) in navList">
<li v-if="index !== 4">|</li>
<li class="title" :class="{ active: navActiveKey === item.id }" @click="handleChangeNav(item.id)">{{
item.name
}}</li>
</template>
</ul>
</div>
</template>
<script lang="ts" setup>
import { defineProps, defineEmits, createVNode } from 'vue';
import { Modal } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
const props = defineProps(['navList', 'navActiveKey']);
const emits = defineEmits(['handleChangeNavId', 'update:navActiveKey']);
const handleChangeNav = (id) => {
if (props.navActiveKey === id) return;
Modal.confirm({
title: '提示',
icon: createVNode(ExclamationCircleOutlined),
content: '你确定切换产品线吗?切换产品线会清空购物车!',
onOk() {
emits('update:navActiveKey', id);
},
onCancel() {},
});
};
</script>
<style lang="less" scoped>
.nav {
background: #f7f9fa;
text-align: center;
border-radius: 10px;
ul {
height: 50px;
padding: 5px;
li {
font-size: 20px;
height: 40px;
line-height: 40px;
display: inline-block;
margin: 0 15px;
}
.active {
color: #1890ff;
}
.title {
cursor: pointer;
}
}
}
</style>
<template>
<div class="searchWrap">
<a-input-search
v-model:value="searchInfo"
placeholder="请输入"
enter-button="搜索"
size="large"
@search="onSearch"
/>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
const searchInfo = ref('');
const onSearch = () => {};
</script>
<style lang="less" scoped>
.searchWrap {
width: 500px;
margin: 0 auto 30px;
}
</style>
<template> 111 </template>
<template>
<div class="containe">
<Search></Search>
<div class="contentWrap">
<div class="top">
<div class="title">{{ title }}</div>
<div class="wrap">
<Nav v-model:navList="navList" v-model:navActiveKey="navActiveKey" />
</div>
</div>
<div class="classify">
<div class="title">全部分类</div>
<div class="classifyWrap">
<ul class="classifyList">
<li class="item" @click="handleChangeLevelFour('all')" :class="{ active: levelFourActiveKey === 'all' }"
>全部</li
>
<li
class="item"
:class="{ active: levelFourActiveKey === item.id }"
v-for="item in levelFourTree"
@click="handleChangeLevelFour(item)"
>
{{ item.name }}
</li>
</ul>
<ul class="classifyList">
<li class="item" @click="handleChangeLevelFive('all')" :class="{ active: levelFiveActiveKey === 'all' }"
>全部</li
>
<li
class="item"
:class="{ active: levelFiveActiveKey === item.id }"
v-for="item in levelFiveTree"
@click="handleChangeLevelFive(item)"
>
{{ item.name }}
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script lang="ts"></script>
<script lang="ts" setup>
import { ref, onMounted, watch } from 'vue';
import { useRoute } from 'vue-router';
import Search from '../components/search.vue';
import Nav from '../components/nav.vue';
import { useGo } from '/@/hooks/web/usePage';
import { toNumber } from 'lodash';
import { useUserStore } from '/@/store/modules/user';
import { useNavTree } from '/@/hooks/myhooks/index';
import { DataItem } from '/@/views/product/goods-category/type';
<style lang="less" scoped></style>
const go = useGo();
const route = useRoute();
const navTree = useNavTree();
const query = route.query;
const navId = toNumber(query.nav); // 一级选择id
const tabId = toNumber(query.tab); // 二级选择id
const tabItemId = toNumber(query.tabItem); // 三级选择id
const navList = ref<DataItem[]>([]); // 菜单树
const navActiveKey = ref(navId); // 一级标签选择
const levelFourTree = ref<DataItem[]>([]); // 四级菜单树
const levelFourActiveKey = ref<string | number>('all');
const levelFiveTree = ref<DataItem[]>([]); // 五级菜单树
const levelFiveActiveKey = ref<string | number>('all');
const title = ref('');
const userStore = useUserStore();
navList.value = userStore.getNavList;
const getGrandsonList = (arr: DataItem[]) => {
arr.some((item) => {
if (item.id === navId || item.id === tabId) {
if (item.id === navId) title.value = item.name;
if (item.children) {
getGrandsonList(item.children);
return true;
}
} else if (item.id === tabItemId) {
levelFourTree.value = item.children;
return true;
}
});
};
const handleChangeLevelFour = (item: DataItem | string) => {
if (typeof item === 'string') {
levelFourActiveKey.value = 'all';
} else {
levelFiveTree.value = item.children;
levelFourActiveKey.value = item.id;
}
};
const handleChangeLevelFive = (item: DataItem | string) => {
if (typeof item === 'string') {
levelFiveActiveKey.value = 'all';
} else {
levelFiveActiveKey.value = item.id;
}
};
watch(
() => navActiveKey.value,
(n) => {
go('/main/store/home' + `?id=${n}`);
},
);
onMounted(() => {
navTree(navList, getGrandsonList, 'getGrandsonList');
});
</script>
<style lang="less" scoped>
.active {
color: #1890ff;
}
.containe {
padding: 30px;
.contentWrap {
padding: 30px;
background: #fff;
border-radius: 10px;
.top {
display: flex;
justify-content: space-between;
.title {
width: 25%;
background: #f7f9fa;
color: #1890ff;
border-radius: 10px;
text-align: center;
height: 50px;
padding: 5px;
line-height: 40px;
font-size: 20px;
}
.wrap {
width: 73%;
margin: 0;
}
}
.classify {
display: flex;
justify-content: flex-start;
margin: 30px 0 20px 60px;
.title {
height: 100px;
line-height: 100px;
padding-right: 40px;
margin-right: 20px;
font-size: 22px;
border-right: 1px solid rgb(214, 214, 214);
}
.classifyWrap {
flex: 1;
.classifyList {
border-bottom: 1px solid rgb(214, 214, 214);
padding-bottom: 10px;
display: flex;
justify-content: flex-start;
.item {
margin-right: 10px;
cursor: pointer;
&:hover {
color: rgb(129, 129, 129);
}
}
}
}
}
}
}
</style>
<template>
<div class="containe">
<div class="searchWrap">
<a-input-search
v-model:value="searchInfo"
placeholder="请输入"
enter-button="搜索"
size="large"
@search="onSearch"
/>
</div>
<Search></Search>
<div class="contentWrap">
<div class="top">
<div class="menu">
<a-tabs v-model:activeKey="activeKey" centered>
<a-tab-pane key="1" tab="器械">
<a-tabs v-model:activeKey="activeTabKey" centered>
<a-tab-pane :key="item.id" :tab="item.name" v-for="item in tabList">
<ul>
<li @click="handleGoGoodsList"><bank-outlined /> <span>单件器械-创伤-钉板</span></li>
<li><bank-outlined /> <span>单件器械-髓内钉</span></li>
<li><bank-outlined /> <span>手术动力</span></li>
<li><bank-outlined /> <span>成套器械</span></li>
</ul>
</a-tab-pane>
<a-tab-pane key="2" tab="产品">
<ul>
<li><bank-outlined /> <span>单件器械-创伤-钉板</span></li>
<li><bank-outlined /> <span>单件器械-髓内钉</span></li>
<li><bank-outlined /> <span>手术动力</span></li>
<li><bank-outlined /> <span>成套器械</span></li>
<li @click="handleGoGoodsList(el.id)" v-for="el in item.children"
><span>{{ el.name }}</span></li
>
</ul>
</a-tab-pane>
</a-tabs>
</div>
<dir class="wrap">
<div class="nav">
<ul>
<template v-for="(item, index) in navList">
<li class="title" :class="{ active: navActiveKey === index }" @click="handleChangeNav(index)">{{
item.title
}}</li>
<li v-if="index !== 4">|</li>
</template>
</ul>
</div>
<Nav v-model:navList="navList" v-model:navActiveKey="navActiveKey" />
<div class="bannerWrap">
<div class="banner">
<a-carousel arrows>
......@@ -133,25 +107,59 @@
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { BankOutlined, LeftCircleOutlined, RightCircleOutlined, UserOutlined } from '@ant-design/icons-vue';
import { navList } from './schema';
import { ref, onMounted, watch } from 'vue';
import { useRoute } from 'vue-router';
import { LeftCircleOutlined, RightCircleOutlined, UserOutlined } from '@ant-design/icons-vue';
import { useGo } from '/@/hooks/web/usePage';
import Search from '../components/search.vue';
import Nav from '../components/nav.vue';
import { toNumber } from 'lodash';
import { useNavTree } from '/@/hooks/myhooks/index';
import { DataItem } from '/@/views/product/goods-category/type';
const go = useGo();
const searchInfo = ref('');
const onSearch = () => {};
const activeKey = ref('1');
const navActiveKey = ref(1);
const handleChangeNav = (i) => {
if (i === 0) return;
navActiveKey.value = i;
const route = useRoute();
const navTree = useNavTree();
const navList = ref<DataItem[]>([]); // 菜单树
const navActiveKey = ref(); // 选中的一级菜单id
const tabList = ref<DataItem[]>([]); // 二级菜单树
const activeTabKey = ref(); // 选中的二级菜单id
const id = route.query.id; // 二次选择一级id
// 初始化选中状态
const init = (changeId?: number) => {
let idx = 0;
let findId = changeId ? changeId : id;
if (id || changeId) {
idx = navList.value.findIndex((item) => {
return item.id === toNumber(findId);
});
if (idx === -1) idx = 0;
}
if (navList.value.length > 0) {
tabList.value = navList.value[idx]?.children;
navActiveKey.value = navList.value[idx]?.id;
activeTabKey.value = navList.value[idx]?.children[0]?.id;
}
};
const handleGoGoodsList = () => {
go('/main/store/goods-classify');
const handleGoGoodsList = (id) => {
go('/main/store/goods-classify' + `?nav=${navActiveKey.value}&tab=${activeTabKey.value}&tabItem=${id}`);
};
watch(
() => navActiveKey.value,
(n) => {
init(n);
},
);
onMounted(() => {
navTree(navList, init, 'init');
});
</script>
<style lang="less" scoped>
......@@ -161,10 +169,6 @@
}
.containe {
padding: 30px;
.searchWrap {
width: 500px;
margin: 0 auto 30px;
}
.contentWrap {
padding: 30px;
......@@ -197,31 +201,6 @@
width: 73%;
margin: 0;
padding: 0;
.nav {
background: #f7f9fa;
text-align: center;
border-radius: 10px;
ul {
height: 50px;
padding: 5px;
li {
font-size: 20px;
height: 40px;
line-height: 40px;
display: inline-block;
margin: 0 15px;
}
.active {
color: #1890ff;
}
.title {
cursor: pointer;
}
}
}
.bannerWrap {
width: 100%;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论