20260808172946
This commit is contained in:
1 parent
4fbfea82f2
commit
d72ca4193d
293 files changed
+37523
-73467
No files matched your search
@@ -87,23 +87,23 @@ watch(
|
||||
.slide-enter-active,
|
||||
.slide-leave-active {
|
||||
transition:
|
||||
opacity 0.24s ease,
|
||||
transform 0.24s ease;
|
||||
opacity 180ms cubic-bezier(0.22, 1, 0.36, 1),
|
||||
transform 180ms cubic-bezier(0.22, 1, 0.36, 1);
|
||||
}
|
||||
|
||||
.slide-enter-from {
|
||||
opacity: 0;
|
||||
transform: translateX(18px);
|
||||
transform: translateY(6px);
|
||||
}
|
||||
|
||||
.slide-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(-18px);
|
||||
transform: translateY(-3px);
|
||||
}
|
||||
|
||||
.slide-enter-to,
|
||||
.slide-leave-from {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
transform: translateY(0);
|
||||
}
|
||||
</style>
|
||||
@@ -1,25 +1,39 @@
|
||||
<template>
|
||||
<el-sub-menu v-if="hasChildren" :index="menuIndex" :class="levelClass">
|
||||
<el-sub-menu
|
||||
v-if="hasChildren"
|
||||
:index="item.id"
|
||||
class="g3-sub-menu"
|
||||
:class="{
|
||||
'level-0': props.level === 0,
|
||||
}"
|
||||
:style="
|
||||
props.level > 0
|
||||
? {
|
||||
'--g3-indent': `${props.level * 20}px`,
|
||||
}
|
||||
: {}
|
||||
"
|
||||
>
|
||||
<template #title>
|
||||
<el-icon v-if="item.icon">
|
||||
<G3Icon :icon="item.icon" />
|
||||
</el-icon>
|
||||
<span class="menu-label">{{ item.label }}</span>
|
||||
</template>
|
||||
|
||||
<MenuItem
|
||||
v-for="(child, idx) in item.children"
|
||||
:key="child.path || idx"
|
||||
v-for="child in item.children"
|
||||
:key="child.id"
|
||||
:item="child"
|
||||
:parent-index="menuIndex + '-' + idx"
|
||||
:parent-index="child.id"
|
||||
:level="props.level + 1"
|
||||
/>
|
||||
</el-sub-menu>
|
||||
|
||||
<el-menu-item
|
||||
v-else
|
||||
:index="item.path"
|
||||
:route="{
|
||||
path: item.path,
|
||||
:index="item.id"
|
||||
class="g3-menu-item"
|
||||
:style="{
|
||||
'--g3-indent': `${props.level * 20}px`,
|
||||
}"
|
||||
>
|
||||
<el-icon v-if="item.icon">
|
||||
@@ -28,7 +42,6 @@
|
||||
<span class="menu-label">{{ item.label }}</span>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
|
||||
<script setup lang="js">
|
||||
import { computed } from "vue";
|
||||
import G3Icon from "@/components/g3-icon/index.vue";
|
||||
@@ -36,36 +49,14 @@ import G3Icon from "@/components/g3-icon/index.vue";
|
||||
const props = defineProps({
|
||||
item: { type: Object, required: true },
|
||||
parentIndex: { type: String, default: "0" },
|
||||
level: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const hasChildren = props.item.children && props.item.children.length > 0;
|
||||
|
||||
// 父菜单没有 path,用索引生成唯一 index,子菜单 path 就用真实路由
|
||||
const menuIndex = props.item.path || props.parentIndex;
|
||||
|
||||
// 一级、二级 class
|
||||
const levelClass = computed(() => {
|
||||
if (!hasChildren) return "";
|
||||
|
||||
const level = props.parentIndex.split("-").length;
|
||||
|
||||
// 一级菜单
|
||||
if (level === 1) {
|
||||
// 判断子节点是否还有 children
|
||||
const childHasChildren = props.item.children.some(
|
||||
(child) => child.children && child.children.length > 0,
|
||||
);
|
||||
|
||||
// 子节点都是叶子节点,才加 g3level1
|
||||
return childHasChildren ? "" : "g3level1";
|
||||
}
|
||||
|
||||
// 二级菜单,只要有子菜单就加 g3level2
|
||||
if (level === 2) {
|
||||
return "g3level2";
|
||||
}
|
||||
|
||||
return "";
|
||||
const hasChildren = computed(() => {
|
||||
return props.item.children && props.item.children.length > 0;
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -79,4 +70,14 @@ const levelClass = computed(() => {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
:deep(.g3-sub-menu > .el-sub-menu__title) {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
:deep(.g3-sub-menu:not(.level-0) > .el-sub-menu__title) {
|
||||
padding-left: calc(30px + var(--g3-indent)) !important;
|
||||
}
|
||||
:deep(.el-menu-item.g3-menu-item) {
|
||||
padding-left: calc(30px + var(--g3-indent)) !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<!-- <el-sub-menu v-if="hasChildren" :index="menuIndex" :class="levelClass"> -->
|
||||
<el-sub-menu v-if="hasChildren" :index="menuIndex">
|
||||
<template #title>
|
||||
<el-icon v-if="item.icon">
|
||||
<G3Icon :icon="item.icon" />
|
||||
</el-icon>
|
||||
<span class="menu-label">{{ item.label }}</span>
|
||||
</template>
|
||||
|
||||
<MenuItem
|
||||
v-for="(child, idx) in item.children"
|
||||
:key="child.path || idx"
|
||||
:item="child"
|
||||
:parent-index="menuIndex + '-' + idx"
|
||||
/>
|
||||
</el-sub-menu>
|
||||
|
||||
<el-menu-item
|
||||
v-else
|
||||
:index="item.path"
|
||||
:route="{
|
||||
path: item.path,
|
||||
}"
|
||||
>
|
||||
<el-icon v-if="item.icon">
|
||||
<G3Icon :icon="item.icon" />
|
||||
</el-icon>
|
||||
<span class="menu-label">{{ item.label }}</span>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
|
||||
<script setup lang="js">
|
||||
import { computed } from "vue";
|
||||
import G3Icon from "@/components/g3-icon/index.vue";
|
||||
|
||||
const props = defineProps({
|
||||
item: { type: Object, required: true },
|
||||
parentIndex: { type: String, default: "0" },
|
||||
});
|
||||
|
||||
const hasChildren = props.item.children && props.item.children.length > 0;
|
||||
|
||||
// 父菜单没有 path,用索引生成唯一 index,子菜单 path 就用真实路由
|
||||
const menuIndex = props.item.path || props.parentIndex;
|
||||
|
||||
// 一级、二级 class
|
||||
const levelClass = computed(() => {
|
||||
if (!hasChildren) return "";
|
||||
|
||||
const level = props.parentIndex.split("-").length;
|
||||
|
||||
// 一级菜单
|
||||
if (level === 1) {
|
||||
// 判断子节点是否还有 children
|
||||
const childHasChildren = props.item.children.some(
|
||||
(child) => child.children && child.children.length > 0,
|
||||
);
|
||||
|
||||
// 子节点都是叶子节点,才加 g3level1
|
||||
return childHasChildren ? "" : "g3level1";
|
||||
}
|
||||
|
||||
// 二级菜单,只要有子菜单就加 g3level2
|
||||
if (level === 2) {
|
||||
return "g3level2";
|
||||
}
|
||||
|
||||
return "";
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.menu-label {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
:deep(.el-icon svg) {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<el-sub-menu v-if="hasChildren" :index="item.id">
|
||||
<template #title>
|
||||
<el-icon v-if="item.icon">
|
||||
<G3Icon :icon="item.icon" />
|
||||
</el-icon>
|
||||
<span class="menu-label">{{ item.label }}</span>
|
||||
</template>
|
||||
|
||||
<MenuItem
|
||||
v-for="child in item.children"
|
||||
:key="child.id"
|
||||
:item="child"
|
||||
:parent-index="child.id"
|
||||
/>
|
||||
</el-sub-menu>
|
||||
|
||||
<el-menu-item v-else :index="item.id">
|
||||
<el-icon v-if="item.icon">
|
||||
<G3Icon :icon="item.icon" />
|
||||
</el-icon>
|
||||
<span class="menu-label">{{ item.label }}</span>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
|
||||
<script setup lang="js">
|
||||
import { computed } from "vue";
|
||||
import G3Icon from "@/components/g3-icon/index.vue";
|
||||
|
||||
const props = defineProps({
|
||||
item: { type: Object, required: true },
|
||||
parentIndex: { type: String, default: "0" },
|
||||
});
|
||||
|
||||
const hasChildren = props.item.children?.length > 0;
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.menu-label {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
:deep(.el-icon svg) {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,13 +1,16 @@
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import axios from "@/utils/axios";
|
||||
import G3Icon from "@/components/g3-icon/index.vue";
|
||||
import MenuItem from "./menu-item.vue";
|
||||
import { getDataBySql } from "@/utils/doSql";
|
||||
import { useUserStore } from "@/store/user";
|
||||
import { useMenuStore } from "@/store/menu";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const userStore = useUserStore();
|
||||
/*
|
||||
const props = defineProps({
|
||||
collapse: {
|
||||
type: Boolean,
|
||||
@@ -17,136 +20,172 @@ const props = defineProps({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
}); */
|
||||
const props = defineProps({
|
||||
item: { type: Object, required: true },
|
||||
parentIndex: { type: String, default: "0" },
|
||||
});
|
||||
|
||||
const emits = defineEmits(["collapse"]);
|
||||
|
||||
const title = ref("G3后台管理系统");
|
||||
|
||||
// 方便以后根据不同的权限显示不同的菜单
|
||||
const selectedMenuKey = computed(() => route.fullPath);
|
||||
// 首页
|
||||
const homeobj = {
|
||||
id: "__home__",
|
||||
label: "首页",
|
||||
path: "/home",
|
||||
icon: "svghome",
|
||||
};
|
||||
|
||||
// 业务管理
|
||||
const bsobj = {
|
||||
label: "业务管理",
|
||||
icon: "ri:folder-chart-line",
|
||||
children: [
|
||||
{ label: "业务管理", path: "/business" },
|
||||
{ label: "排车列表", path: "/business/listcontainer" },
|
||||
],
|
||||
};
|
||||
// 财务管理
|
||||
const cwobj = {
|
||||
label: "财务管理",
|
||||
icon: "ri:wallet-line",
|
||||
children: [
|
||||
{
|
||||
label: "应收管理",
|
||||
children: [
|
||||
{ label: "应收费用列表", path: "/cw/ys/list" },
|
||||
{ label: "应收账单", path: "/cw/ys/listbill" },
|
||||
{ label: "应收发票", path: "/cw/ys/listinvoice" },
|
||||
{ label: "收款管理", path: "/cw/ys/listskd" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "应付管理",
|
||||
children: [
|
||||
{ label: "应付费用列表", path: "/cw/yf/list" },
|
||||
{ label: "应付账单", path: "/cw/yf/listbill" },
|
||||
{ label: "应付发票", path: "/cw/yf/listinvoice" },
|
||||
{ label: "付款管理", path: "/cw/yf/listfkd" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "财务辅助",
|
||||
children: [
|
||||
{ label: "日常费用", path: "/cw/assistance/daily-expenses" },
|
||||
{ label: "收付账户", path: "/cw/assistance/payment-account" },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
const tjobj = {
|
||||
label: "统计分析",
|
||||
icon: "ri:bar-chart-box-line",
|
||||
children: [
|
||||
{
|
||||
label: "收款统计分析",
|
||||
children: [
|
||||
{ label: "应收未收明细", path: "/tj/ystj/tj_nots" },
|
||||
{ label: "应收未收按单位汇总", path: "/tj/ystj/tj_notsbydw" },
|
||||
{ label: "未收款按业务员汇总", path: "/tj/ystj/tj_notsbysales" },
|
||||
{ label: "收款明细统计", path: "/tj/ystj/tj_cwskxz" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "付款统计分析",
|
||||
children: [
|
||||
{ label: "应付未付明细", path: "/tj/yftj/tj_alone_notf" },
|
||||
{ label: "应付未付按单位汇总", path: "/tj/yftj/tj_notfbydw" },
|
||||
{ label: "付款明细统计", path: "/tj/yftj/tj_cwfkxz" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "利润统计分析",
|
||||
children: [
|
||||
{ label: "利润分析单票明细", path: "/tj/lrtj/tj_lr_module_id" },
|
||||
{ label: "利润分析按业务员", path: "/tj/lrtj/tj_lrbysales" },
|
||||
{ label: "利润分析按客户", path: "/tj/lrtj/tj_lrbycustomer" },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
const mgobj = {
|
||||
label: "管理中心",
|
||||
icon: "ri:government-line",
|
||||
children: [
|
||||
{ label: "审批中心", path: "/shcenter" },
|
||||
{ label: "合同管理", path: "/partners/khht" },
|
||||
{ label: "运费模版", path: "/pricelist/list" },
|
||||
{ label: "企业公告", path: "/system/oa-management/companyAnnouncement" },
|
||||
{ label: "提醒设置", path: "/system/oa-management/userReminder" },
|
||||
{ label: "结算汇率", path: "/partners/hl" },
|
||||
{ label: "审批设置", path: "/system/approvalSettings" },
|
||||
],
|
||||
};
|
||||
const baseobj = {
|
||||
label: "基础数据",
|
||||
icon: "ri:database-line",
|
||||
children: [
|
||||
{ label: "合作伙伴", path: "/partners" },
|
||||
{ label: "联系人", path: "/partners/contact" },
|
||||
{ label: "其他数据", path: "/base/other" },
|
||||
],
|
||||
};
|
||||
const sysobj = {
|
||||
label: "系统管理",
|
||||
icon: "ri:settings-line",
|
||||
children: [{ label: "权限管理", path: "/system/permission" }],
|
||||
};
|
||||
|
||||
const g3modobj = {
|
||||
id: "sys_module",
|
||||
label: "模块设置",
|
||||
icon: "ri:settings-line",
|
||||
expanded: false,
|
||||
children: [
|
||||
{ id: "sys_moduleset", label: "模块设置", path: "/system/moduleSettings" },
|
||||
{ id: "sys_field", label: "字段配置", path: "/system/field" },
|
||||
{ id: "sys_Settings", label: "查询设置", path: "/system/statisticalSettings" },
|
||||
{ id: "sys_mappingConfig", label: "映射配置", path: "/system/mappingConfig" },
|
||||
{ id: "sys_autoId", label: "自动编码", path: "/system/autoId" },
|
||||
{ id: "sys_reminder", label: "提醒设置", path: "/system/oa-management/userReminder" },
|
||||
{ id: "sys_logdatas", label: "数据日志", path: "/system/logdatas" },
|
||||
{ id: "sys_loginrecords", label: "登陆日志", path: "/system/loginrecords" },
|
||||
],
|
||||
};
|
||||
|
||||
// 根据当前路由在菜单树中找到对应节点 id,用于 el-menu 的 default-active 高亮
|
||||
const selectedMenuKey = computed(() => {
|
||||
// 1) 优先通过 path 精确匹配
|
||||
let node = findNodeByPath(menuList.value, route.path);
|
||||
if (node?.id) return node.id;
|
||||
// 2) fallback: /tj 等通用路由,通过 query.moduleid 匹配
|
||||
if (route.query.moduleid) {
|
||||
node = findNodeByModuleId(menuList.value, route.query.moduleid);
|
||||
if (node?.id) return node.id;
|
||||
}
|
||||
return "";
|
||||
});
|
||||
|
||||
const menuList = ref([
|
||||
// 首页
|
||||
{
|
||||
label: "首页",
|
||||
path: "/home",
|
||||
icon: "svghome",
|
||||
},
|
||||
homeobj,
|
||||
// 业务管理
|
||||
{
|
||||
label: "业务管理",
|
||||
icon: "ri:folder-chart-line",
|
||||
children: [
|
||||
{ label: "业务管理", path: "/business" },
|
||||
{ label: "排车列表", path: "/business/listcontainer" },
|
||||
],
|
||||
},
|
||||
// bsobj,
|
||||
// 财务管理
|
||||
{
|
||||
label: "财务管理",
|
||||
icon: "ri:wallet-line",
|
||||
children: [
|
||||
{
|
||||
label: "应收管理",
|
||||
children: [
|
||||
{ label: "应收费用列表", path: "/cw/ys/list" },
|
||||
{ label: "应收账单", path: "/cw/ys/listbill" },
|
||||
{ label: "应收发票", path: "/cw/ys/listinvoice" },
|
||||
{ label: "收款管理", path: "/cw/ys/listskd" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "应付管理",
|
||||
children: [
|
||||
{ label: "应付费用列表", path: "/cw/yf/list" },
|
||||
{ label: "应付账单", path: "/cw/yf/listbill" },
|
||||
{ label: "应付发票", path: "/cw/yf/listinvoice" },
|
||||
{ label: "付款管理", path: "/cw/yf/listfkd" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "日常费用",
|
||||
children: [
|
||||
{ label: "日常费用", path: "/cw/assistance/daily-expenses" },
|
||||
{ label: "收付账户", path: "/cw/assistance/payment-account" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
// cwobj,
|
||||
// 统计分析
|
||||
{
|
||||
label: "统计分析",
|
||||
icon: "ri:bar-chart-box-line",
|
||||
children: [
|
||||
{
|
||||
label: "收款统计分析",
|
||||
children: [
|
||||
{ label: "应收未收明细", path: "/tj/ystj/tj_nots" },
|
||||
{ label: "应收未收按单位汇总", path: "/tj/ystj/tj_notsbydw" },
|
||||
{ label: "未收款按业务员汇总", path: "/tj/ystj/tj_notsbysales" },
|
||||
{ label: "收款明细统计", path: "/tj/ystj/tj_cwskxz" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "付款统计分析",
|
||||
children: [
|
||||
{ label: "应付未付明细", path: "/tj/yftj/tj_alone_notf" },
|
||||
{ label: "应付未付按单位汇总", path: "/tj/yftj/tj_notfbydw" },
|
||||
{ label: "付款明细统计", path: "/tj/yftj/tj_cwfkxz" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "利润统计分析",
|
||||
children: [
|
||||
{ label: "利润分析单票明细", path: "/tj/lrtj/tj_lr_module_id" },
|
||||
{ label: "利润分析按业务员", path: "/tj/lrtj/tj_lrbysales" },
|
||||
{ label: "利润分析按客户", path: "/tj/lrtj/tj_lrbycustomer" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
// 审批中心
|
||||
{
|
||||
label: "管理中心",
|
||||
icon: "ri:government-line",
|
||||
children: [
|
||||
{ label: "审批中心", path: "/shcenter" },
|
||||
{ label: "合同管理", path: "/partners/khht" },
|
||||
{ label: "运费模版", path: "/pricelist/list" },
|
||||
{
|
||||
label: "企业公告",
|
||||
path: "/system/oa-management/companyAnnouncement",
|
||||
},
|
||||
{ label: "审批设置", path: "/system/approvalSettings" },
|
||||
{ label: "提醒设置", path: "/system/oa-management/userReminder" },
|
||||
{ label: "结算汇率", path: "/partners/hl" },
|
||||
],
|
||||
},
|
||||
// tjobj,
|
||||
// 管理中心
|
||||
// mgobj,
|
||||
// 基础数据
|
||||
{
|
||||
label: "基础数据",
|
||||
icon: "ri:database-line",
|
||||
children: [
|
||||
{ label: "合作伙伴", path: "/partners" },
|
||||
{ label: "联系人", path: "/partners/contact" },
|
||||
{ label: "其他数据", path: "/base/other" },
|
||||
],
|
||||
},
|
||||
// baseobj,
|
||||
// 系统管理
|
||||
{
|
||||
label: "系统管理",
|
||||
icon: "ri:settings-line",
|
||||
children: [
|
||||
{ label: "权限管理", path: "/system/permission" },
|
||||
{ label: "字段配置", path: "/system/field" },
|
||||
{ label: "查询设置", path: "/system/statisticalSettings" },
|
||||
{ label: "映射配置", path: "/system/mappingConfig" },
|
||||
{ label: "模块设置", path: "/system/moduleSettings" },
|
||||
{ label: "自动编码", path: "/system/autoId" },
|
||||
],
|
||||
},
|
||||
// sysobj,
|
||||
g3modobj,
|
||||
// 系统帮助
|
||||
{
|
||||
/* {
|
||||
label: "系统帮助",
|
||||
icon: "ri:question-line",
|
||||
children: [
|
||||
@@ -159,27 +198,177 @@ const menuList = ref([
|
||||
label: "功能测试",
|
||||
icon: "ri:bug-line",
|
||||
children: [{ label: "测试页面", path: "/test/test" }],
|
||||
},
|
||||
}, */
|
||||
]);
|
||||
|
||||
/*
|
||||
function handleSelect(val) {
|
||||
router.push(val);
|
||||
console.log(val)
|
||||
// router.push(val);
|
||||
router.push({
|
||||
path: val.path,
|
||||
query: {
|
||||
moduleid: val.moduleid
|
||||
}
|
||||
})
|
||||
} */
|
||||
const activeMenuId = computed(() => {
|
||||
return findNodeByPath(menuList.value, route.path)?.id || "";
|
||||
});
|
||||
function handleSelect(menuId) {
|
||||
// console.log('index:', index); // '/tj/ystj/tj_nots'
|
||||
// console.log('indexPath:', indexPath); // ['4', 'TJ_ystj', 'TJ_ystj_01']
|
||||
// 从 menuList 里找到完整节点
|
||||
const node = findNodeById(menuList.value, menuId);
|
||||
if (!node || !node.path) return;
|
||||
|
||||
router.push({
|
||||
path: node.path,
|
||||
query: node.moduleid ? { moduleid: node.moduleid } : {},
|
||||
});
|
||||
}
|
||||
|
||||
function findNodeById(tree, id) {
|
||||
for (const node of tree) {
|
||||
if (node.id === id) return node;
|
||||
if (node.children) {
|
||||
const found = findNodeById(node.children, id);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function findNodeByPath(tree, path) {
|
||||
for (const node of tree) {
|
||||
if (node.path === path) return node;
|
||||
if (node.children) {
|
||||
const found = findNodeByPath(node.children, path);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function findNodeByModuleId(tree, moduleid) {
|
||||
for (const node of tree) {
|
||||
if (node.moduleid === moduleid) return node;
|
||||
if (node.children) {
|
||||
const found = findNodeByModuleId(node.children, moduleid);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function handleCollapse() {
|
||||
emits("collapse");
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
let searchsql = `select * from s_keyvalue where b_key='bodycaption'`;
|
||||
const response = await axios.get("/selectlistbysql", {
|
||||
params: { sql: searchsql },
|
||||
});
|
||||
if (response.data?.success) {
|
||||
const records = response.data.data.records || [];
|
||||
if (records.length > 0) {
|
||||
title.value = records[0].b_value;
|
||||
const js_1_icon = [
|
||||
{ b_id: "HY", icon: "ri:folder-chart-line" },
|
||||
{ b_id: "CK", icon: "ri:folder-chart-line" },
|
||||
{ b_id: "gjqy", icon: "ri:folder-chart-line" },
|
||||
{ b_id: "CW", icon: "ri:wallet-line" },
|
||||
{ b_id: "glzx", icon: "ri:government-line" },
|
||||
{ b_id: "TJ", icon: "ri:bar-chart-box-line" },
|
||||
{ b_id: "base", icon: "ri:database-line" },
|
||||
{ b_id: "sys", icon: "ri:settings-line" },
|
||||
];
|
||||
const iconMap = new Map(js_1_icon.map((item) => [item.b_id, item.icon]));
|
||||
function buildModuleTree(records) {
|
||||
const mainTree = [];
|
||||
// ✅ 首页 默认添加
|
||||
mainTree.push(homeobj);
|
||||
records.forEach((row) => {
|
||||
const js = Number(row.js);
|
||||
const bid = row.b_id;
|
||||
const moduleid = row.b_moduleid;
|
||||
const bname = row.mc_b;
|
||||
const bpath = row.b_path || "";
|
||||
|
||||
const node = {
|
||||
label: bname,
|
||||
id: bid,
|
||||
...(js === 1 ? { icon: iconMap.get(bid) || "" } : {}),
|
||||
...(bpath ? { path: bpath } : {}),
|
||||
...(moduleid ? { moduleid: moduleid } : {}),
|
||||
};
|
||||
|
||||
if (js === 1) {
|
||||
mainTree.push(node);
|
||||
}
|
||||
|
||||
if (js === 2) {
|
||||
const p1 = mainTree.find((p) => p.id === row.bm_1_b);
|
||||
if (p1) {
|
||||
if (!p1.children) p1.children = [];
|
||||
p1.children.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (js === 3) {
|
||||
const p1 = mainTree.find((p) => p.id === row.bm_1_b);
|
||||
const p2 = p1?.children?.find((c) => c.id === row.bm_2_b);
|
||||
if (p2) {
|
||||
if (!p2.children) p2.children = [];
|
||||
p2.children.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (js === 4) {
|
||||
const p1 = mainTree.find((p) => p.id === row.bm_1_b);
|
||||
const p2 = p1?.children?.find((c) => c.id === row.bm_2_b);
|
||||
const p3 = p2?.children?.find((c) => c.id === row.bm_3_b);
|
||||
if (p3) {
|
||||
if (!p3.children) p3.children = [];
|
||||
p3.children.push(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
// ✅ g3soft 特殊节点:循环结束后再追加
|
||||
if (userStore.getUserId() === "g3soft") {
|
||||
mainTree.push(g3modobj);
|
||||
}
|
||||
return mainTree;
|
||||
}
|
||||
|
||||
async function getmodulebmfl() {
|
||||
let searchsql = `select * from s_module_bmfl where b_canmenu='1' order by js,b_xh`;
|
||||
let datas = await getDataBySql(searchsql);
|
||||
if (!datas.records || datas.records.length === 0) {
|
||||
//=== 树形菜单 没有设置 默认有首页,g3soft账号有模块设置
|
||||
const mainTree = [];
|
||||
// ✅ 首页 默认添加
|
||||
mainTree.push(homeobj);
|
||||
// ✅ g3soft 特殊节点:循环结束后再追加
|
||||
if (userStore.getUserId() === "g3soft") {
|
||||
mainTree.push(g3modobj);
|
||||
}
|
||||
menuList.value = mainTree;
|
||||
} else {
|
||||
menuList.value = buildModuleTree(datas.records);
|
||||
}
|
||||
// 将菜单树中的 moduleid→节点 映射存入 menuStore,供 router 动态获取 title
|
||||
const menuStore = useMenuStore();
|
||||
menuStore.setModuleMap(menuList.value);
|
||||
console.log("menuList.value=-=-==-==-");
|
||||
console.log(menuList.value);
|
||||
}
|
||||
async function getbodycaption() {
|
||||
let searchsql = `select * from s_keyvalue where b_key='bodycaption'`;
|
||||
|
||||
let datas = await getDataBySql(searchsql);
|
||||
|
||||
if (!datas.records || datas.records.length === 0) {
|
||||
return;
|
||||
}
|
||||
title.value = datas.records[0].b_value;
|
||||
}
|
||||
onMounted(async () => {
|
||||
try {
|
||||
getbodycaption();
|
||||
getmodulebmfl();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
ElMessage.warning(err.message || "没有查询语句");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -195,7 +384,7 @@ onMounted(async () => {
|
||||
"
|
||||
>
|
||||
<img src="@/assets/g3logo.png" alt="Logo" class="logo" />
|
||||
<div v-show="!props.collapse" class="title">{{ title }}</div>
|
||||
<!-- <div v-show="!props.collapse" class="title">{{ title }}</div> -->
|
||||
</div>
|
||||
<div class="menu-container">
|
||||
<el-menu
|
||||
@@ -206,10 +395,11 @@ onMounted(async () => {
|
||||
@select="handleSelect"
|
||||
>
|
||||
<MenuItem
|
||||
v-for="(item, idx) in menuList"
|
||||
:key="item.path || idx"
|
||||
v-for="item in menuList"
|
||||
:key="item.id"
|
||||
:item="item"
|
||||
:parent-index="idx.toString()"
|
||||
:index="item.id"
|
||||
:level="0"
|
||||
/>
|
||||
</el-menu>
|
||||
</div>
|
||||
@@ -228,7 +418,8 @@ onMounted(async () => {
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: #f8f8f8;
|
||||
// background-color: #f8f8f8;
|
||||
background-color: #003152;
|
||||
overflow: hidden;
|
||||
transition: background-color 0.3s ease;
|
||||
|
||||
@@ -281,7 +472,7 @@ onMounted(async () => {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
background-color: #f8f8f8;
|
||||
background-color: #003152;
|
||||
.menu-inner {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -319,7 +510,7 @@ onMounted(async () => {
|
||||
height: 28px !important;
|
||||
line-height: 28px !important;
|
||||
box-sizing: border-box;
|
||||
color: #525252;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
font-family:
|
||||
"InterVariable", "Inter", "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto",
|
||||
@@ -330,7 +521,7 @@ onMounted(async () => {
|
||||
height: 28px !important;
|
||||
line-height: 28px !important;
|
||||
box-sizing: border-box;
|
||||
color: #525252;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
font-family:
|
||||
"InterVariable", "Inter", "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto",
|
||||
@@ -343,7 +534,7 @@ onMounted(async () => {
|
||||
}
|
||||
}
|
||||
:deep(.el-menu-item:hover) {
|
||||
background-color: #f3f3f3;
|
||||
background-color: #03273f;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
@@ -358,41 +549,25 @@ onMounted(async () => {
|
||||
}
|
||||
:deep(.el-sub-menu),
|
||||
:deep(.el-menu) {
|
||||
background-color: #f8f8f8 !important;
|
||||
background-color: #003152;
|
||||
}
|
||||
:deep(.el-sub-menu.is-active .el-sub-menu__title) {
|
||||
border-bottom-color: #525252;
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
:deep(.el-sub-menu__title:hover) {
|
||||
background-color: #f3f3f3;
|
||||
background-color: #03273f;
|
||||
}
|
||||
:deep(.menu-container .el-menu-item.is-active) {
|
||||
color: #525252;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
background: rgba(255, 255, 255, 1);
|
||||
background: #093e63;
|
||||
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
}
|
||||
:deep(.menu-container .el-sub-menu.is-active > .el-sub-menu__title) {
|
||||
color: #525252;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
}
|
||||
:deep(.g3level1 .el-menu) {
|
||||
margin-left: 30px;
|
||||
}
|
||||
:deep(.g3level1 .el-menu .el-menu-item) {
|
||||
padding: 0px 20px 0px 20px !important;
|
||||
}
|
||||
:deep(.g3level2 .el-sub-menu__title) {
|
||||
margin-left: 30px;
|
||||
padding: 0px 20px 0px 20px !important;
|
||||
}
|
||||
:deep(.g3level2 .el-menu) {
|
||||
margin-left: 42px;
|
||||
}
|
||||
:deep(.g3level2 .el-menu .el-menu-item) {
|
||||
padding: 0px 20px 0px 20px !important;
|
||||
}
|
||||
|
||||
.menu-footer {
|
||||
display: flex;
|
||||
@@ -405,6 +580,7 @@ onMounted(async () => {
|
||||
padding-right: 12px;
|
||||
overflow: hidden;
|
||||
transition: padding-right 0.3s ease;
|
||||
color: #fff;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
|
||||
+95
-15
@@ -1,9 +1,9 @@
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import axios from "@/utils/axios";
|
||||
import G3Icon from "@/components/g3-icon/index.vue";
|
||||
import MenuItem from "./menu-item.vue";
|
||||
import { getDataBySql } from "@/utils/doSql";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
@@ -30,7 +30,7 @@ const menuList = ref([
|
||||
{
|
||||
label: "首页",
|
||||
path: "/home",
|
||||
icon: "mdi:home",
|
||||
icon: "svghome",
|
||||
},
|
||||
// 业务管理
|
||||
{
|
||||
@@ -41,6 +41,27 @@ const menuList = ref([
|
||||
{ label: "排车列表", path: "/business/listcontainer" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "仓库管理",
|
||||
icon: "ri:folder-chart-line",
|
||||
children: [
|
||||
{ label: "入库管理", path: "/ck/in/list" },
|
||||
{ label: "出库管理", path: "/ck/out/list" },
|
||||
{
|
||||
label: "统计报表",
|
||||
children: [
|
||||
{ label: "入库查询", path: "/ck/tj/listin" },
|
||||
{ label: "出库查询", path: "/ck/tj/listout" },
|
||||
{ label: "库存查询", path: "/ck/tj/listkc" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "国际汽运",
|
||||
icon: "ri:folder-chart-line",
|
||||
children: [{ label: "国际汽运", path: "/Intlroad" }],
|
||||
},
|
||||
// 财务管理
|
||||
{
|
||||
label: "财务管理",
|
||||
@@ -143,6 +164,8 @@ const menuList = ref([
|
||||
{ label: "映射配置", path: "/system/mappingConfig" },
|
||||
{ label: "模块设置", path: "/system/moduleSettings" },
|
||||
{ label: "自动编码", path: "/system/autoId" },
|
||||
{ label: "登陆日志", path: "/system/loginrecords" },
|
||||
{ label: "数据日志", path: "/system/logdatas" },
|
||||
],
|
||||
},
|
||||
// 系统帮助
|
||||
@@ -163,6 +186,8 @@ const menuList = ref([
|
||||
]);
|
||||
|
||||
function handleSelect(val) {
|
||||
console.log(val);
|
||||
|
||||
router.push(val);
|
||||
}
|
||||
|
||||
@@ -171,15 +196,18 @@ function handleCollapse() {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
let searchsql = `select * from s_keyvalue where b_key='bodycaption'`;
|
||||
const response = await axios.get("/selectlistbysql", {
|
||||
params: { sql: searchsql },
|
||||
});
|
||||
if (response.data?.success) {
|
||||
const records = response.data.data.records || [];
|
||||
if (records.length > 0) {
|
||||
title.value = records[0].b_value;
|
||||
try {
|
||||
let searchsql = `select * from s_keyvalue where b_key='bodycaption'`;
|
||||
|
||||
let datas = await getDataBySql(searchsql);
|
||||
|
||||
if (!datas.records || datas.records.length === 0) {
|
||||
return;
|
||||
}
|
||||
title.value = datas.records[0].b_value;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
ElMessage.warning(err.message || "没有查询语句");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -228,7 +256,7 @@ onMounted(async () => {
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: white;
|
||||
background-color: #f8f8f8;
|
||||
overflow: hidden;
|
||||
transition: background-color 0.3s ease;
|
||||
|
||||
@@ -281,6 +309,7 @@ onMounted(async () => {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
background-color: #f8f8f8;
|
||||
.menu-inner {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -315,15 +344,25 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
:deep(.el-sub-menu__title) {
|
||||
height: 42px !important;
|
||||
line-height: 42px !important;
|
||||
height: 28px !important;
|
||||
line-height: 28px !important;
|
||||
box-sizing: border-box;
|
||||
color: #525252;
|
||||
font-size: 13px;
|
||||
font-family:
|
||||
"InterVariable", "Inter", "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto",
|
||||
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
:deep(.el-menu-item) {
|
||||
height: 42px !important;
|
||||
line-height: 42px !important;
|
||||
height: 28px !important;
|
||||
line-height: 28px !important;
|
||||
box-sizing: border-box;
|
||||
color: #525252;
|
||||
font-size: 13px;
|
||||
font-family:
|
||||
"InterVariable", "Inter", "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto",
|
||||
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
|
||||
&.is-active {
|
||||
background-color: var(--el-color-primary-light-9);
|
||||
@@ -331,6 +370,10 @@ onMounted(async () => {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
:deep(.el-menu-item:hover) {
|
||||
background-color: #f3f3f3;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
:deep(.el-sub-menu) {
|
||||
&.is-active {
|
||||
@@ -341,6 +384,43 @@ onMounted(async () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.el-sub-menu),
|
||||
:deep(.el-menu) {
|
||||
background-color: #f8f8f8 !important;
|
||||
}
|
||||
:deep(.el-sub-menu.is-active .el-sub-menu__title) {
|
||||
border-bottom-color: #525252;
|
||||
}
|
||||
:deep(.el-sub-menu__title:hover) {
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
:deep(.menu-container .el-menu-item.is-active) {
|
||||
color: #525252;
|
||||
font-weight: 500;
|
||||
background: rgba(255, 255, 255, 1);
|
||||
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
}
|
||||
:deep(.menu-container .el-sub-menu.is-active > .el-sub-menu__title) {
|
||||
color: #525252;
|
||||
font-weight: 500;
|
||||
}
|
||||
:deep(.g3level1 .el-menu) {
|
||||
margin-left: 30px;
|
||||
}
|
||||
:deep(.g3level1 .el-menu .el-menu-item) {
|
||||
padding: 0px 20px 0px 20px !important;
|
||||
}
|
||||
:deep(.g3level2 .el-sub-menu__title) {
|
||||
margin-left: 30px;
|
||||
padding: 0px 20px 0px 20px !important;
|
||||
}
|
||||
:deep(.g3level2 .el-menu) {
|
||||
margin-left: 42px;
|
||||
}
|
||||
:deep(.g3level2 .el-menu .el-menu-item) {
|
||||
padding: 0px 20px 0px 20px !important;
|
||||
}
|
||||
|
||||
.menu-footer {
|
||||
display: flex;
|
||||
@@ -0,0 +1,603 @@
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import G3Icon from "@/components/g3-icon/index.vue";
|
||||
import MenuItem from "./menu-item.vue";
|
||||
import { getDataBySql } from "@/utils/doSql";
|
||||
import { useUserStore } from "@/store/user";
|
||||
import { useMenuStore } from "@/store/menu";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
/*
|
||||
const props = defineProps({
|
||||
collapse: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
animating: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
}); */
|
||||
const props = defineProps({
|
||||
item: { type: Object, required: true },
|
||||
parentIndex: { type: String, default: "0" },
|
||||
});
|
||||
|
||||
const emits = defineEmits(["collapse"]);
|
||||
|
||||
const title = ref("G3后台管理系统");
|
||||
|
||||
// 首页
|
||||
const homeobj = {
|
||||
id: "__home__",
|
||||
label: "首页",
|
||||
path: "/home",
|
||||
icon: "svghome",
|
||||
};
|
||||
|
||||
// 业务管理
|
||||
const bsobj = {
|
||||
label: "业务管理",
|
||||
icon: "ri:folder-chart-line",
|
||||
children: [
|
||||
{ label: "业务管理", path: "/business" },
|
||||
{ label: "排车列表", path: "/business/listcontainer" },
|
||||
],
|
||||
};
|
||||
// 财务管理
|
||||
const cwobj = {
|
||||
label: "财务管理",
|
||||
icon: "ri:wallet-line",
|
||||
children: [
|
||||
{
|
||||
label: "应收管理",
|
||||
children: [
|
||||
{ label: "应收费用列表", path: "/cw/ys/list" },
|
||||
{ label: "应收账单", path: "/cw/ys/listbill" },
|
||||
{ label: "应收发票", path: "/cw/ys/listinvoice" },
|
||||
{ label: "收款管理", path: "/cw/ys/listskd" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "应付管理",
|
||||
children: [
|
||||
{ label: "应付费用列表", path: "/cw/yf/list" },
|
||||
{ label: "应付账单", path: "/cw/yf/listbill" },
|
||||
{ label: "应付发票", path: "/cw/yf/listinvoice" },
|
||||
{ label: "付款管理", path: "/cw/yf/listfkd" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "财务辅助",
|
||||
children: [
|
||||
{ label: "日常费用", path: "/cw/assistance/daily-expenses" },
|
||||
{ label: "收付账户", path: "/cw/assistance/payment-account" },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
const tjobj = {
|
||||
label: "统计分析",
|
||||
icon: "ri:bar-chart-box-line",
|
||||
children: [
|
||||
{
|
||||
label: "收款统计分析",
|
||||
children: [
|
||||
{ label: "应收未收明细", path: "/tj/ystj/tj_nots" },
|
||||
{ label: "应收未收按单位汇总", path: "/tj/ystj/tj_notsbydw" },
|
||||
{ label: "未收款按业务员汇总", path: "/tj/ystj/tj_notsbysales" },
|
||||
{ label: "收款明细统计", path: "/tj/ystj/tj_cwskxz" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "付款统计分析",
|
||||
children: [
|
||||
{ label: "应付未付明细", path: "/tj/yftj/tj_alone_notf" },
|
||||
{ label: "应付未付按单位汇总", path: "/tj/yftj/tj_notfbydw" },
|
||||
{ label: "付款明细统计", path: "/tj/yftj/tj_cwfkxz" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "利润统计分析",
|
||||
children: [
|
||||
{ label: "利润分析单票明细", path: "/tj/lrtj/tj_lr_module_id" },
|
||||
{ label: "利润分析按业务员", path: "/tj/lrtj/tj_lrbysales" },
|
||||
{ label: "利润分析按客户", path: "/tj/lrtj/tj_lrbycustomer" },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
const mgobj = {
|
||||
label: "管理中心",
|
||||
icon: "ri:government-line",
|
||||
children: [
|
||||
{ label: "审批中心", path: "/shcenter" },
|
||||
{ label: "合同管理", path: "/partners/khht" },
|
||||
{ label: "运费模版", path: "/pricelist/list" },
|
||||
{ label: "企业公告", path: "/system/oa-management/companyAnnouncement" },
|
||||
{ label: "提醒设置", path: "/system/oa-management/userReminder" },
|
||||
{ label: "结算汇率", path: "/partners/hl" },
|
||||
{ label: "审批设置", path: "/system/approvalSettings" },
|
||||
],
|
||||
};
|
||||
const baseobj = {
|
||||
label: "基础数据",
|
||||
icon: "ri:database-line",
|
||||
children: [
|
||||
{ label: "合作伙伴", path: "/partners" },
|
||||
{ label: "联系人", path: "/partners/contact" },
|
||||
{ label: "其他数据", path: "/base/other" },
|
||||
],
|
||||
};
|
||||
const sysobj = {
|
||||
label: "系统管理",
|
||||
icon: "ri:settings-line",
|
||||
children: [{ label: "权限管理", path: "/system/permission" }],
|
||||
};
|
||||
|
||||
const g3modobj = {
|
||||
id: "sys_module",
|
||||
label: "模块设置",
|
||||
icon: "ri:settings-line",
|
||||
expanded: false,
|
||||
children: [
|
||||
{ id: "sys_moduleset", label: "模块设置", path: "/system/moduleSettings" },
|
||||
{ id: "sys_logdatas", label: "数据日志", path: "/system/logdatas" },
|
||||
{ label: "字段配置", path: "/system/field" },
|
||||
{ label: "自动编码", path: "/system/autoId" },
|
||||
{ label: "查询设置", path: "/system/statisticalSettings" },
|
||||
{ label: "映射配置", path: "/system/mappingConfig" },
|
||||
{ label: "登陆日志", path: "/system/loginrecords" },
|
||||
],
|
||||
};
|
||||
|
||||
// 根据当前路由在菜单树中找到对应节点 id,用于 el-menu 的 default-active 高亮
|
||||
const selectedMenuKey = computed(() => {
|
||||
// 1) 优先通过 path 精确匹配
|
||||
let node = findNodeByPath(menuList.value, route.path);
|
||||
if (node?.id) return node.id;
|
||||
// 2) fallback: /tj 等通用路由,通过 query.moduleid 匹配
|
||||
if (route.query.moduleid) {
|
||||
node = findNodeByModuleId(menuList.value, route.query.moduleid);
|
||||
if (node?.id) return node.id;
|
||||
}
|
||||
return "";
|
||||
});
|
||||
|
||||
const menuList = ref([
|
||||
// 首页
|
||||
homeobj,
|
||||
// 业务管理
|
||||
// bsobj,
|
||||
// 财务管理
|
||||
// cwobj,
|
||||
// 统计分析
|
||||
// tjobj,
|
||||
// 管理中心
|
||||
// mgobj,
|
||||
// 基础数据
|
||||
// baseobj,
|
||||
// 系统管理
|
||||
// sysobj,
|
||||
g3modobj,
|
||||
// 系统帮助
|
||||
/* {
|
||||
label: "系统帮助",
|
||||
icon: "ri:question-line",
|
||||
children: [
|
||||
{ label: "帮助文档", path: "/help" },
|
||||
{ label: "操作视频", path: "/videos" },
|
||||
],
|
||||
},
|
||||
// 功能测试
|
||||
{
|
||||
label: "功能测试",
|
||||
icon: "ri:bug-line",
|
||||
children: [{ label: "测试页面", path: "/test/test" }],
|
||||
}, */
|
||||
]);
|
||||
/*
|
||||
function handleSelect(val) {
|
||||
console.log(val)
|
||||
// router.push(val);
|
||||
router.push({
|
||||
path: val.path,
|
||||
query: {
|
||||
moduleid: val.moduleid
|
||||
}
|
||||
})
|
||||
} */
|
||||
const activeMenuId = computed(() => {
|
||||
return findNodeByPath(menuList.value, route.path)?.id || "";
|
||||
});
|
||||
function handleSelect(menuId) {
|
||||
// console.log('index:', index); // '/tj/ystj/tj_nots'
|
||||
// console.log('indexPath:', indexPath); // ['4', 'TJ_ystj', 'TJ_ystj_01']
|
||||
// 从 menuList 里找到完整节点
|
||||
const node = findNodeById(menuList.value, menuId);
|
||||
if (!node || !node.path) return;
|
||||
|
||||
router.push({
|
||||
path: node.path,
|
||||
query: node.moduleid ? { moduleid: node.moduleid } : {},
|
||||
});
|
||||
}
|
||||
|
||||
function findNodeById(tree, id) {
|
||||
for (const node of tree) {
|
||||
if (node.id === id) return node;
|
||||
if (node.children) {
|
||||
const found = findNodeById(node.children, id);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function findNodeByPath(tree, path) {
|
||||
for (const node of tree) {
|
||||
if (node.path === path) return node;
|
||||
if (node.children) {
|
||||
const found = findNodeByPath(node.children, path);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function findNodeByModuleId(tree, moduleid) {
|
||||
for (const node of tree) {
|
||||
if (node.moduleid === moduleid) return node;
|
||||
if (node.children) {
|
||||
const found = findNodeByModuleId(node.children, moduleid);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function handleCollapse() {
|
||||
emits("collapse");
|
||||
}
|
||||
|
||||
const js_1_icon = [
|
||||
{ b_id: "HY", icon: "ri:folder-chart-line" },
|
||||
{ b_id: "CK", icon: "ri:folder-chart-line" },
|
||||
{ b_id: "gjqy", icon: "ri:folder-chart-line" },
|
||||
{ b_id: "CW", icon: "ri:wallet-line" },
|
||||
{ b_id: "glzx", icon: "ri:government-line" },
|
||||
{ b_id: "TJ", icon: "ri:bar-chart-box-line" },
|
||||
{ b_id: "base", icon: "ri:database-line" },
|
||||
{ b_id: "sys", icon: "ri:settings-line" },
|
||||
];
|
||||
const iconMap = new Map(js_1_icon.map((item) => [item.b_id, item.icon]));
|
||||
function buildModuleTree(records) {
|
||||
const mainTree = [];
|
||||
// ✅ 首页 默认添加
|
||||
mainTree.push(homeobj);
|
||||
records.forEach((row) => {
|
||||
const js = Number(row.js);
|
||||
const bid = row.b_id;
|
||||
const moduleid = row.b_moduleid;
|
||||
const bname = row.mc_b;
|
||||
const bpath = row.b_path || "";
|
||||
|
||||
const node = {
|
||||
label: bname,
|
||||
id: bid,
|
||||
...(js === 1 ? { icon: iconMap.get(bid) || "" } : {}),
|
||||
...(bpath ? { path: bpath } : {}),
|
||||
...(moduleid ? { moduleid: moduleid } : {}),
|
||||
};
|
||||
|
||||
if (js === 1) {
|
||||
mainTree.push(node);
|
||||
}
|
||||
|
||||
if (js === 2) {
|
||||
const p1 = mainTree.find((p) => p.id === row.bm_1_b);
|
||||
if (p1) {
|
||||
if (!p1.children) p1.children = [];
|
||||
p1.children.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (js === 3) {
|
||||
const p1 = mainTree.find((p) => p.id === row.bm_1_b);
|
||||
const p2 = p1?.children?.find((c) => c.id === row.bm_2_b);
|
||||
if (p2) {
|
||||
if (!p2.children) p2.children = [];
|
||||
p2.children.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (js === 4) {
|
||||
const p1 = mainTree.find((p) => p.id === row.bm_1_b);
|
||||
const p2 = p1?.children?.find((c) => c.id === row.bm_2_b);
|
||||
const p3 = p2?.children?.find((c) => c.id === row.bm_3_b);
|
||||
if (p3) {
|
||||
if (!p3.children) p3.children = [];
|
||||
p3.children.push(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
// ✅ g3soft 特殊节点:循环结束后再追加
|
||||
if (userStore.getUserId() === "g3soft") {
|
||||
mainTree.push(g3modobj);
|
||||
}
|
||||
return mainTree;
|
||||
}
|
||||
|
||||
async function getmodulebmfl() {
|
||||
let searchsql = `select * from s_module_bmfl where b_canmenu='1' order by js,b_xh`;
|
||||
let datas = await getDataBySql(searchsql);
|
||||
if (!datas.records || datas.records.length === 0) {
|
||||
//=== 树形菜单 没有设置 默认有首页,g3soft账号有模块设置
|
||||
const mainTree = [];
|
||||
// ✅ 首页 默认添加
|
||||
mainTree.push(homeobj);
|
||||
// ✅ g3soft 特殊节点:循环结束后再追加
|
||||
if (userStore.getUserId() === "g3soft") {
|
||||
mainTree.push(g3modobj);
|
||||
}
|
||||
menuList.value = mainTree;
|
||||
} else {
|
||||
menuList.value = buildModuleTree(datas.records);
|
||||
}
|
||||
// 将菜单树中的 moduleid→节点 映射存入 menuStore,供 router 动态获取 title
|
||||
const menuStore = useMenuStore();
|
||||
menuStore.setModuleMap(menuList.value);
|
||||
}
|
||||
async function getbodycaption() {
|
||||
let searchsql = `select * from s_keyvalue where b_key='bodycaption'`;
|
||||
|
||||
let datas = await getDataBySql(searchsql);
|
||||
|
||||
if (!datas.records || datas.records.length === 0) {
|
||||
return;
|
||||
}
|
||||
title.value = datas.records[0].b_value;
|
||||
}
|
||||
onMounted(async () => {
|
||||
try {
|
||||
getbodycaption();
|
||||
getmodulebmfl();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
ElMessage.warning(err.message || "没有查询语句");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-menu" :class="{ collapse: props.collapse, 'is-animating': props.animating }">
|
||||
<div
|
||||
class="menu-logo"
|
||||
@click="
|
||||
() => {
|
||||
router.push('/home');
|
||||
}
|
||||
"
|
||||
>
|
||||
<img src="@/assets/g3logo.png" alt="Logo" class="logo" />
|
||||
<!-- <div v-show="!props.collapse" class="title">{{ title }}</div> -->
|
||||
</div>
|
||||
<div class="menu-container">
|
||||
<el-menu
|
||||
:collapse="props.collapse"
|
||||
:collapse-transition="false"
|
||||
class="menu-inner"
|
||||
:default-active="selectedMenuKey"
|
||||
@select="handleSelect"
|
||||
>
|
||||
<MenuItem v-for="item in menuList" :key="item.id" :item="item" :index="item.id" />
|
||||
</el-menu>
|
||||
</div>
|
||||
<div class="menu-footer">
|
||||
<div @click="handleCollapse()">
|
||||
<G3Icon :icon="props.collapse ? 'ri:menu-fold-4-line' : 'ri:menu-fold-3-line'" :size="20" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.app-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: #f8f8f8;
|
||||
overflow: hidden;
|
||||
transition: background-color 0.3s ease;
|
||||
|
||||
&.collapse {
|
||||
.menu-logo .logo {
|
||||
width: 46px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.menu-footer {
|
||||
justify-content: center;
|
||||
padding-right: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-animating {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 42px;
|
||||
padding: 19px 0px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
transition: padding 0.3s ease;
|
||||
|
||||
.logo {
|
||||
width: 80px;
|
||||
height: 24px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-left: 10px;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #70cfb1;
|
||||
white-space: nowrap;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-container {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
background-color: #f8f8f8;
|
||||
.menu-inner {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
min-width: 64px;
|
||||
box-sizing: border-box;
|
||||
width: 100% !important;
|
||||
border-right: none !important;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #cfd3dc transparent;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: #cfd3dc;
|
||||
border-radius: 999px;
|
||||
|
||||
&:hover {
|
||||
background-color: #a8abb2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-sub-menu__title) {
|
||||
height: 28px !important;
|
||||
line-height: 28px !important;
|
||||
box-sizing: border-box;
|
||||
color: #525252;
|
||||
font-size: 13px;
|
||||
font-family:
|
||||
"InterVariable", "Inter", "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto",
|
||||
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
:deep(.el-menu-item) {
|
||||
height: 28px !important;
|
||||
line-height: 28px !important;
|
||||
box-sizing: border-box;
|
||||
color: #525252;
|
||||
font-size: 13px;
|
||||
font-family:
|
||||
"InterVariable", "Inter", "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto",
|
||||
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
|
||||
&.is-active {
|
||||
background-color: var(--el-color-primary-light-9);
|
||||
color: var(--el-color-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
:deep(.el-menu-item:hover) {
|
||||
background-color: #f3f3f3;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
:deep(.el-sub-menu) {
|
||||
&.is-active {
|
||||
> .el-sub-menu__title {
|
||||
color: var(--el-color-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.el-sub-menu),
|
||||
:deep(.el-menu) {
|
||||
background-color: #f8f8f8 !important;
|
||||
}
|
||||
:deep(.el-sub-menu.is-active .el-sub-menu__title) {
|
||||
border-bottom-color: #525252;
|
||||
}
|
||||
:deep(.el-sub-menu__title:hover) {
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
:deep(.menu-container .el-menu-item.is-active) {
|
||||
color: #525252;
|
||||
font-weight: 500;
|
||||
background: rgba(255, 255, 255, 1);
|
||||
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
}
|
||||
:deep(.menu-container .el-sub-menu.is-active > .el-sub-menu__title) {
|
||||
color: #525252;
|
||||
font-weight: 500;
|
||||
}
|
||||
:deep(.g3level1 .el-menu) {
|
||||
margin-left: 30px;
|
||||
}
|
||||
:deep(.g3level1 .el-menu .el-menu-item) {
|
||||
padding: 0px 20px 0px 20px !important;
|
||||
}
|
||||
:deep(.g3level2 .el-sub-menu__title) {
|
||||
margin-left: 30px;
|
||||
padding: 0px 20px 0px 20px !important;
|
||||
}
|
||||
:deep(.g3level2 .el-menu) {
|
||||
margin-left: 42px;
|
||||
}
|
||||
:deep(.g3level2 .el-menu .el-menu-item) {
|
||||
padding: 0px 20px 0px 20px !important;
|
||||
}
|
||||
|
||||
.menu-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
box-sizing: border-box;
|
||||
padding: 8px 0px 8px 0px;
|
||||
padding-right: 12px;
|
||||
overflow: hidden;
|
||||
transition: padding-right 0.3s ease;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(45, 140, 240, 0.1);
|
||||
color: rgba(45, 140, 240, 0.8);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,608 @@
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import G3Icon from "@/components/g3-icon/index.vue";
|
||||
import MenuItem from "./menu-item.vue";
|
||||
import { getDataBySql } from "@/utils/doSql";
|
||||
import { useUserStore } from "@/store/user";
|
||||
import { useMenuStore } from "@/store/menu";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
/*
|
||||
const props = defineProps({
|
||||
collapse: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
animating: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
}); */
|
||||
const props = defineProps({
|
||||
item: { type: Object, required: true },
|
||||
parentIndex: { type: String, default: "0" },
|
||||
});
|
||||
|
||||
const emits = defineEmits(["collapse"]);
|
||||
|
||||
const title = ref("G3后台管理系统");
|
||||
|
||||
// 首页
|
||||
const homeobj = {
|
||||
id: "__home__",
|
||||
label: "首页",
|
||||
path: "/home",
|
||||
icon: "svghome",
|
||||
};
|
||||
|
||||
// 业务管理
|
||||
const bsobj = {
|
||||
label: "业务管理",
|
||||
icon: "ri:folder-chart-line",
|
||||
children: [
|
||||
{ label: "业务管理", path: "/business" },
|
||||
{ label: "排车列表", path: "/business/listcontainer" },
|
||||
],
|
||||
};
|
||||
// 财务管理
|
||||
const cwobj = {
|
||||
label: "财务管理",
|
||||
icon: "ri:wallet-line",
|
||||
children: [
|
||||
{
|
||||
label: "应收管理",
|
||||
children: [
|
||||
{ label: "应收费用列表", path: "/cw/ys/list" },
|
||||
{ label: "应收账单", path: "/cw/ys/listbill" },
|
||||
{ label: "应收发票", path: "/cw/ys/listinvoice" },
|
||||
{ label: "收款管理", path: "/cw/ys/listskd" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "应付管理",
|
||||
children: [
|
||||
{ label: "应付费用列表", path: "/cw/yf/list" },
|
||||
{ label: "应付账单", path: "/cw/yf/listbill" },
|
||||
{ label: "应付发票", path: "/cw/yf/listinvoice" },
|
||||
{ label: "付款管理", path: "/cw/yf/listfkd" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "财务辅助",
|
||||
children: [
|
||||
{ label: "日常费用", path: "/cw/assistance/daily-expenses" },
|
||||
{ label: "收付账户", path: "/cw/assistance/payment-account" },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
const tjobj = {
|
||||
label: "统计分析",
|
||||
icon: "ri:bar-chart-box-line",
|
||||
children: [
|
||||
{
|
||||
label: "收款统计分析",
|
||||
children: [
|
||||
{ label: "应收未收明细", path: "/tj/ystj/tj_nots" },
|
||||
{ label: "应收未收按单位汇总", path: "/tj/ystj/tj_notsbydw" },
|
||||
{ label: "未收款按业务员汇总", path: "/tj/ystj/tj_notsbysales" },
|
||||
{ label: "收款明细统计", path: "/tj/ystj/tj_cwskxz" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "付款统计分析",
|
||||
children: [
|
||||
{ label: "应付未付明细", path: "/tj/yftj/tj_alone_notf" },
|
||||
{ label: "应付未付按单位汇总", path: "/tj/yftj/tj_notfbydw" },
|
||||
{ label: "付款明细统计", path: "/tj/yftj/tj_cwfkxz" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "利润统计分析",
|
||||
children: [
|
||||
{ label: "利润分析单票明细", path: "/tj/lrtj/tj_lr_module_id" },
|
||||
{ label: "利润分析按业务员", path: "/tj/lrtj/tj_lrbysales" },
|
||||
{ label: "利润分析按客户", path: "/tj/lrtj/tj_lrbycustomer" },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
const mgobj = {
|
||||
label: "管理中心",
|
||||
icon: "ri:government-line",
|
||||
children: [
|
||||
{ label: "审批中心", path: "/shcenter" },
|
||||
{ label: "合同管理", path: "/partners/khht" },
|
||||
{ label: "运费模版", path: "/pricelist/list" },
|
||||
{ label: "企业公告", path: "/system/oa-management/companyAnnouncement" },
|
||||
{ label: "提醒设置", path: "/system/oa-management/userReminder" },
|
||||
{ label: "结算汇率", path: "/partners/hl" },
|
||||
{ label: "审批设置", path: "/system/approvalSettings" },
|
||||
],
|
||||
};
|
||||
const baseobj = {
|
||||
label: "基础数据",
|
||||
icon: "ri:database-line",
|
||||
children: [
|
||||
{ label: "合作伙伴", path: "/partners" },
|
||||
{ label: "联系人", path: "/partners/contact" },
|
||||
{ label: "其他数据", path: "/base/other" },
|
||||
],
|
||||
};
|
||||
const sysobj = {
|
||||
label: "系统管理",
|
||||
icon: "ri:settings-line",
|
||||
children: [{ label: "权限管理", path: "/system/permission" }],
|
||||
};
|
||||
|
||||
const g3modobj = {
|
||||
id: "sys_module",
|
||||
label: "模块设置",
|
||||
icon: "ri:settings-line",
|
||||
expanded: false,
|
||||
children: [
|
||||
{ id: "sys_moduleset", label: "模块设置", path: "/system/moduleSettings" },
|
||||
{ id: "sys_field", label: "字段配置", path: "/system/field" },
|
||||
{ id: "sys_Settings", label: "查询设置", path: "/system/statisticalSettings" },
|
||||
{ id: "sys_mappingConfig", label: "映射配置", path: "/system/mappingConfig" },
|
||||
{ id: "sys_autoId", label: "自动编码", path: "/system/autoId" },
|
||||
{ id: "sys_reminder", label: "提醒设置", path: "/system/oa-management/userReminder" },
|
||||
{ id: "sys_logdatas", label: "数据日志", path: "/system/logdatas" },
|
||||
{ id: "sys_loginrecords", label: "登陆日志", path: "/system/loginrecords" },
|
||||
],
|
||||
};
|
||||
|
||||
// 根据当前路由在菜单树中找到对应节点 id,用于 el-menu 的 default-active 高亮
|
||||
const selectedMenuKey = computed(() => {
|
||||
// 1) 优先通过 path 精确匹配
|
||||
let node = findNodeByPath(menuList.value, route.path);
|
||||
if (node?.id) return node.id;
|
||||
// 2) fallback: /tj 等通用路由,通过 query.moduleid 匹配
|
||||
if (route.query.moduleid) {
|
||||
node = findNodeByModuleId(menuList.value, route.query.moduleid);
|
||||
if (node?.id) return node.id;
|
||||
}
|
||||
return "";
|
||||
});
|
||||
|
||||
const menuList = ref([
|
||||
// 首页
|
||||
homeobj,
|
||||
// 业务管理
|
||||
// bsobj,
|
||||
// 财务管理
|
||||
// cwobj,
|
||||
// 统计分析
|
||||
// tjobj,
|
||||
// 管理中心
|
||||
// mgobj,
|
||||
// 基础数据
|
||||
// baseobj,
|
||||
// 系统管理
|
||||
// sysobj,
|
||||
g3modobj,
|
||||
// 系统帮助
|
||||
/* {
|
||||
label: "系统帮助",
|
||||
icon: "ri:question-line",
|
||||
children: [
|
||||
{ label: "帮助文档", path: "/help" },
|
||||
{ label: "操作视频", path: "/videos" },
|
||||
],
|
||||
},
|
||||
// 功能测试
|
||||
{
|
||||
label: "功能测试",
|
||||
icon: "ri:bug-line",
|
||||
children: [{ label: "测试页面", path: "/test/test" }],
|
||||
}, */
|
||||
]);
|
||||
/*
|
||||
function handleSelect(val) {
|
||||
console.log(val)
|
||||
// router.push(val);
|
||||
router.push({
|
||||
path: val.path,
|
||||
query: {
|
||||
moduleid: val.moduleid
|
||||
}
|
||||
})
|
||||
} */
|
||||
const activeMenuId = computed(() => {
|
||||
return findNodeByPath(menuList.value, route.path)?.id || "";
|
||||
});
|
||||
function handleSelect(menuId) {
|
||||
// console.log('index:', index); // '/tj/ystj/tj_nots'
|
||||
// console.log('indexPath:', indexPath); // ['4', 'TJ_ystj', 'TJ_ystj_01']
|
||||
// 从 menuList 里找到完整节点
|
||||
const node = findNodeById(menuList.value, menuId);
|
||||
if (!node || !node.path) return;
|
||||
|
||||
router.push({
|
||||
path: node.path,
|
||||
query: node.moduleid ? { moduleid: node.moduleid } : {},
|
||||
});
|
||||
}
|
||||
|
||||
function findNodeById(tree, id) {
|
||||
for (const node of tree) {
|
||||
if (node.id === id) return node;
|
||||
if (node.children) {
|
||||
const found = findNodeById(node.children, id);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function findNodeByPath(tree, path) {
|
||||
for (const node of tree) {
|
||||
if (node.path === path) return node;
|
||||
if (node.children) {
|
||||
const found = findNodeByPath(node.children, path);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function findNodeByModuleId(tree, moduleid) {
|
||||
for (const node of tree) {
|
||||
if (node.moduleid === moduleid) return node;
|
||||
if (node.children) {
|
||||
const found = findNodeByModuleId(node.children, moduleid);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function handleCollapse() {
|
||||
emits("collapse");
|
||||
}
|
||||
|
||||
const js_1_icon = [
|
||||
{ b_id: "HY", icon: "ri:folder-chart-line" },
|
||||
{ b_id: "CK", icon: "ri:folder-chart-line" },
|
||||
{ b_id: "gjqy", icon: "ri:folder-chart-line" },
|
||||
{ b_id: "CW", icon: "ri:wallet-line" },
|
||||
{ b_id: "glzx", icon: "ri:government-line" },
|
||||
{ b_id: "TJ", icon: "ri:bar-chart-box-line" },
|
||||
{ b_id: "base", icon: "ri:database-line" },
|
||||
{ b_id: "sys", icon: "ri:settings-line" },
|
||||
];
|
||||
const iconMap = new Map(js_1_icon.map((item) => [item.b_id, item.icon]));
|
||||
function buildModuleTree(records) {
|
||||
const mainTree = [];
|
||||
// ✅ 首页 默认添加
|
||||
mainTree.push(homeobj);
|
||||
records.forEach((row) => {
|
||||
const js = Number(row.js);
|
||||
const bid = row.b_id;
|
||||
const moduleid = row.b_moduleid;
|
||||
const bname = row.mc_b;
|
||||
const bpath = row.b_path || "";
|
||||
|
||||
const node = {
|
||||
label: bname,
|
||||
id: bid,
|
||||
...(js === 1 ? { icon: iconMap.get(bid) || "" } : {}),
|
||||
...(bpath ? { path: bpath } : {}),
|
||||
...(moduleid ? { moduleid: moduleid } : {}),
|
||||
};
|
||||
|
||||
if (js === 1) {
|
||||
mainTree.push(node);
|
||||
}
|
||||
|
||||
if (js === 2) {
|
||||
const p1 = mainTree.find((p) => p.id === row.bm_1_b);
|
||||
if (p1) {
|
||||
if (!p1.children) p1.children = [];
|
||||
p1.children.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (js === 3) {
|
||||
const p1 = mainTree.find((p) => p.id === row.bm_1_b);
|
||||
const p2 = p1?.children?.find((c) => c.id === row.bm_2_b);
|
||||
if (p2) {
|
||||
if (!p2.children) p2.children = [];
|
||||
p2.children.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (js === 4) {
|
||||
const p1 = mainTree.find((p) => p.id === row.bm_1_b);
|
||||
const p2 = p1?.children?.find((c) => c.id === row.bm_2_b);
|
||||
const p3 = p2?.children?.find((c) => c.id === row.bm_3_b);
|
||||
if (p3) {
|
||||
if (!p3.children) p3.children = [];
|
||||
p3.children.push(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
// ✅ g3soft 特殊节点:循环结束后再追加
|
||||
if (userStore.getUserId() === "g3soft") {
|
||||
mainTree.push(g3modobj);
|
||||
}
|
||||
return mainTree;
|
||||
}
|
||||
|
||||
async function getmodulebmfl() {
|
||||
let searchsql = `select * from s_module_bmfl where b_canmenu='1' order by js,b_xh`;
|
||||
let datas = await getDataBySql(searchsql);
|
||||
if (!datas.records || datas.records.length === 0) {
|
||||
//=== 树形菜单 没有设置 默认有首页,g3soft账号有模块设置
|
||||
const mainTree = [];
|
||||
// ✅ 首页 默认添加
|
||||
mainTree.push(homeobj);
|
||||
// ✅ g3soft 特殊节点:循环结束后再追加
|
||||
if (userStore.getUserId() === "g3soft") {
|
||||
mainTree.push(g3modobj);
|
||||
}
|
||||
menuList.value = mainTree;
|
||||
} else {
|
||||
menuList.value = buildModuleTree(datas.records);
|
||||
}
|
||||
// 将菜单树中的 moduleid→节点 映射存入 menuStore,供 router 动态获取 title
|
||||
const menuStore = useMenuStore();
|
||||
menuStore.setModuleMap(menuList.value);
|
||||
console.log("menuList.value=-=-==-==-");
|
||||
console.log(menuList.value);
|
||||
}
|
||||
async function getbodycaption() {
|
||||
let searchsql = `select * from s_keyvalue where b_key='bodycaption'`;
|
||||
|
||||
let datas = await getDataBySql(searchsql);
|
||||
|
||||
if (!datas.records || datas.records.length === 0) {
|
||||
return;
|
||||
}
|
||||
title.value = datas.records[0].b_value;
|
||||
}
|
||||
onMounted(async () => {
|
||||
try {
|
||||
getbodycaption();
|
||||
getmodulebmfl();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
ElMessage.warning(err.message || "没有查询语句");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-menu" :class="{ collapse: props.collapse, 'is-animating': props.animating }">
|
||||
<div
|
||||
class="menu-logo"
|
||||
@click="
|
||||
() => {
|
||||
router.push('/home');
|
||||
}
|
||||
"
|
||||
>
|
||||
<img src="@/assets/g3logo.png" alt="Logo" class="logo" />
|
||||
<!-- <div v-show="!props.collapse" class="title">{{ title }}</div> -->
|
||||
</div>
|
||||
<div class="menu-container">
|
||||
<el-menu
|
||||
:collapse="props.collapse"
|
||||
:collapse-transition="false"
|
||||
class="menu-inner"
|
||||
:default-active="selectedMenuKey"
|
||||
@select="handleSelect"
|
||||
>
|
||||
<MenuItem v-for="item in menuList" :key="item.id" :item="item" :index="item.id" />
|
||||
</el-menu>
|
||||
</div>
|
||||
<div class="menu-footer">
|
||||
<div @click="handleCollapse()">
|
||||
<G3Icon :icon="props.collapse ? 'ri:menu-fold-4-line' : 'ri:menu-fold-3-line'" :size="20" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.app-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
// background-color: #f8f8f8;
|
||||
background-color: #003152;
|
||||
overflow: hidden;
|
||||
transition: background-color 0.3s ease;
|
||||
|
||||
&.collapse {
|
||||
.menu-logo .logo {
|
||||
width: 46px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.menu-footer {
|
||||
justify-content: center;
|
||||
padding-right: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-animating {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 42px;
|
||||
padding: 19px 0px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
transition: padding 0.3s ease;
|
||||
|
||||
.logo {
|
||||
width: 80px;
|
||||
height: 24px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-left: 10px;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #70cfb1;
|
||||
white-space: nowrap;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-container {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
background-color: #003152;
|
||||
.menu-inner {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
min-width: 64px;
|
||||
box-sizing: border-box;
|
||||
width: 100% !important;
|
||||
border-right: none !important;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #cfd3dc transparent;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: #cfd3dc;
|
||||
border-radius: 999px;
|
||||
|
||||
&:hover {
|
||||
background-color: #a8abb2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-sub-menu__title) {
|
||||
height: 28px !important;
|
||||
line-height: 28px !important;
|
||||
box-sizing: border-box;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
font-family:
|
||||
"InterVariable", "Inter", "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto",
|
||||
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
:deep(.el-menu-item) {
|
||||
height: 28px !important;
|
||||
line-height: 28px !important;
|
||||
box-sizing: border-box;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
font-family:
|
||||
"InterVariable", "Inter", "-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto",
|
||||
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
|
||||
&.is-active {
|
||||
background-color: var(--el-color-primary-light-9);
|
||||
color: var(--el-color-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
:deep(.el-menu-item:hover) {
|
||||
background-color: #03273f;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
:deep(.el-sub-menu) {
|
||||
&.is-active {
|
||||
> .el-sub-menu__title {
|
||||
color: var(--el-color-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.el-sub-menu),
|
||||
:deep(.el-menu) {
|
||||
background-color: #003152;
|
||||
}
|
||||
:deep(.el-sub-menu.is-active .el-sub-menu__title) {
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
:deep(.el-sub-menu__title:hover) {
|
||||
background-color: #03273f;
|
||||
}
|
||||
:deep(.menu-container .el-menu-item.is-active) {
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
background: #093e63;
|
||||
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
}
|
||||
:deep(.menu-container .el-sub-menu.is-active > .el-sub-menu__title) {
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
}
|
||||
:deep(.g3level1 .el-menu) {
|
||||
margin-left: 30px;
|
||||
}
|
||||
:deep(.g3level1 .el-menu .el-menu-item) {
|
||||
padding: 0px 20px 0px 20px !important;
|
||||
}
|
||||
:deep(.g3level2 .el-sub-menu__title) {
|
||||
margin-left: 30px;
|
||||
padding: 0px 20px 0px 20px !important;
|
||||
}
|
||||
:deep(.g3level2 .el-menu) {
|
||||
margin-left: 42px;
|
||||
}
|
||||
:deep(.g3level2 .el-menu .el-menu-item) {
|
||||
padding: 0px 20px 0px 20px !important;
|
||||
}
|
||||
|
||||
.menu-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
box-sizing: border-box;
|
||||
padding: 8px 0px 8px 0px;
|
||||
padding-right: 12px;
|
||||
overflow: hidden;
|
||||
transition: padding-right 0.3s ease;
|
||||
color: #fff;
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(45, 140, 240, 0.1);
|
||||
color: rgba(45, 140, 240, 0.8);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -2,9 +2,9 @@
|
||||
import { ArrowDown } from "@element-plus/icons-vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { onMounted, ref } from "vue";
|
||||
import axios from "@/utils/axios";
|
||||
import updatePassword from "@/views/user-center/updatepassword.vue";
|
||||
import { useTabStore, useUserStore } from "@/store";
|
||||
import { getDataBySql } from "@/utils/doSql";
|
||||
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
@@ -42,13 +42,18 @@ function logout() {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
let searchsql = `select * from s_keyvalue where b_key='maincaption'`;
|
||||
const response = await axios.get("/selectlistbysql", { params: { sql: searchsql } });
|
||||
if (response.data?.success) {
|
||||
const records = response.data.data.records || [];
|
||||
if (records.length > 0) {
|
||||
title.value = records[0].b_value;
|
||||
try {
|
||||
let searchsql = `select * from s_keyvalue where b_key='bodycaption'`;
|
||||
|
||||
let datas = await getDataBySql(searchsql);
|
||||
|
||||
if (!datas.records || datas.records.length === 0) {
|
||||
return;
|
||||
}
|
||||
title.value = datas.records[0].b_value;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
ElMessage.warning(err.message || "没有查询语句");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -65,10 +70,7 @@ onMounted(async () => {
|
||||
|
||||
<el-dropdown placement="bottom-end">
|
||||
<div class="user-card">
|
||||
<img
|
||||
class="avatar"
|
||||
src="https://api.dicebear.com/9.x/initials/svg?seed=User&backgroundColor=e5e7eb&fontColor=6b7280"
|
||||
/>
|
||||
<img class="avatar" src="/avatar.jpeg" />
|
||||
<div class="name">{{ userStore.userInfo.userid || "未登录" }}</div>
|
||||
<el-icon :size="14">
|
||||
<arrow-down />
|
||||
@@ -78,10 +80,7 @@ onMounted(async () => {
|
||||
<template #dropdown>
|
||||
<div class="user-dropdown">
|
||||
<div class="user-info">
|
||||
<img
|
||||
class="avatar"
|
||||
src="https://api.dicebear.com/9.x/initials/svg?seed=User&backgroundColor=e5e7eb&fontColor=6b7280"
|
||||
/>
|
||||
<img class="avatar" src="/avatar.jpeg" />
|
||||
<div>
|
||||
<div class="name">{{ userStore.userInfo.userid || "未登录" }}</div>
|
||||
<div class="orgid">
|
||||
@@ -284,4 +283,4 @@ onMounted(async () => {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
Reference in new issue
Block a user