第一次提交

This commit is contained in:
2025-07-04 10:37:02 +08:00
commit 5137a64cce
72 changed files with 15660 additions and 0 deletions

4
src/components/index.js Normal file
View File

@@ -0,0 +1,4 @@
import Layout from './layout/index'
export {
Layout
}

View File

@@ -0,0 +1,76 @@
<template>
<el-container>
<el-aside :width="leftMenuWidth">
<layout-aside />
</el-aside>
<el-container>
<!-- 头部 -->
<el-header>
<layout-header />
</el-header>
<!-- 主体 -->
<div class="app-main">
<router-view v-slot="{ Component }">
<transition name="router-fade" mode="out-in">
<keep-alive>
<component :is="Component" />
</keep-alive>
</transition>
</router-view>
</div>
</el-container>
</el-container>
</template>
<style lang="scss" scoped>
.el-aside {
background-color: #304156;
z-index: 2000;
}
.el-header {
background-color: rgba(0, 0, 0, .025);
padding: 0;
height: 80px;
}
.app-main {
height: -moz-calc(100vh - 80px);
height: -webkit-calc(100vh - 80px);
height: calc(100vh - 80px);
background-color: #eff2f9;
overflow: scroll;
}
</style>
<script>
import {
LayoutAside,
LayoutHeader
} from '@/components/layout/libs/index'
import {
mapState
} from 'vuex'
export default {
name: 'Layout',
components: {
'layout-aside': LayoutAside,
'layout-header': LayoutHeader
},
computed: {
...mapState('leftAside', {
leftMenuWidth: (state) => state.leftMenuWidth
}),
keyfull() {
return this.$route.fullPath
}
},
data() {
return {
key: this.$route.path,
keepAlivedComponents: {},
}
}
}
</script>

View File

@@ -0,0 +1,8 @@
import LayoutAside from './layout-aside/index.vue'
import LayoutHeader from './layout-header/index.vue'
import LayoutFooter from './layout-footer/index.vue'
export {
LayoutAside,
LayoutHeader,
LayoutFooter
}

View File

@@ -0,0 +1,82 @@
<template>
<div>
<div class="system-title" v-if="!isCollapse">
<img v-if="logo" src="@/assets/logo.png" class="sidebar-logo">
<span>{{ settingsTitle }}</span>
</div>
<div class="system-title" v-else>Cost</div>
<div></div>
<el-scrollbar>
<el-menu
:unique-opened="true"
:default-openeds="defaultOpeneds"
:default-active="defaultActive"
:collapse="isCollapse"
class="left-aside"
@select="handleSelect"
@open="handleOpen"
@close="handleClose"
background-color="rgb(48, 65, 86)"
text-color="#fff"
>
<aside-item v-for="(menu, idx) in menus" :key="idx" :item="menu" />
</el-menu>
</el-scrollbar>
</div>
</template>
<style lang="scss" scoped>
.system-title {
font-size: 14px;
font-weight: bold;
color: #fff;
text-align: center;
padding: 15px 0;
line-height:50px;
background-color:#4178D5;
}
.left-aside {
border-right: 0;
}
.left-aside:not(.el-menu--collapse) {
width: 200px;
}
.sidebar-logo{width: 32px; height: 32px; vertical-align: middle; margin-right: 12px;}
</style>
<script>
import { mapState } from 'vuex'
import AsideItem from './item'
import { title } from '@/settings'
export default {
components: {
'aside-item': AsideItem
},
data () {
return {
settingsTitle: title,
defaultOpeneds: [],
defaultActive: this.$route.name,
logo:true
}
},
computed: {
...mapState({
menus: (state) => state.routes.routes,
isCollapse: (state) => state.leftAside.isCollapse
})
},
watch: {
'$route' (to, from) {
const indexPath = this.$route.matched.map(v => v.name)
this.defaultActive = indexPath.pop()
this.defaultOpeneds = indexPath
}
},
mounted () { },
methods: {
handleSelect (index, indexPath) { },
handleOpen (index, indexPath) { },
handleClose (index, indexPath) { }
}
}
</script>

View File

@@ -0,0 +1,129 @@
<template>
<div v-if="!item.hidden">
<el-sub-menu v-if="showChildren(item)" :index="item.name">
<template #title>
<svg class="icon-font svg-icon-custom" aria-hidden="true" v-if="item.meta.icon" >
<use :xlink:href="item.meta.icon"></use>
</svg>
<!-- <i v-if="item.meta.icon" :class="item.meta.icon"></i> -->
<span>{{ item.meta.title }}</span>
</template>
<aside-item
v-for="(subItem, subIdx) in item.children"
:key="subIdx"
:item="subItem"
/>
</el-sub-menu>
<el-menu-item v-else :index="item.name" @click="handleOpenPage(item)" style="background-color:#1f2d3d">
<i :class="item.meta.icon"></i>
<template #title>{{ item.meta.title }}</template>
</el-menu-item>
</div>
<div v-else>
<aside-item
v-for="(subItem, subIdx) in item.children"
:key="subIdx"
:item="subItem"
/>
</div>
</template>
<style lang="css">
/* 该样式scoped下不生效为不污染全局固采用'>'选择器固定层级选取,不要删除 */
.el-menu--collapse
> div
> .el-submenu
> .el-submenu__title
> .el-submenu__icon-arrow.el-icon-arrow-right {
display: none;
}
</style>
<style lang="scss" scoped>
.el-menu--collapse .el-submenu__title span {
height: 0;
width: 0;
overflow: hidden;
visibility: hidden;
display: inline-block;
}
::v-deep([class*=" el-icon-"]),
::v-deep([class^="el-icon-"]) {
color: #fff;
}
::v-deep(.el-menu-item-group__title) {
// background-color: #38b48b;
color: #fff;
height: 38px;
font-size: 16px;
line-height: 38px;
}
::v-deep(.el-submenu__title) {
font-size: 16px;
height: 50px;
line-height: 50px;
}
::v-deep(.el-submenu .el-menu-item) {
padding-left: 40px !important;
background-color:#1f2d3d!important;
color:rgb(191, 203, 217);
}
::v-deep(.el-menu .el-menu-item:hover) {
padding-left: 40px !important;
background-color:#4178d5!important;
color:rgb(191, 203, 217);
}
::v-deep(.el-menu-item.submenu-title-noDropdown) {
padding-left: 20px !important;
}
::v-deep(.el-menu-item.is-active) {
color: #fff !important;
background-color: #4178d5 !important;
}
::v-deep(.el-sub-menu__title){
border-bottom: 1px solid #1f2d3d;
background-color:rgb(48, 65, 86)!important;
}
::v-deep(.el-sub-menu.is-active .el-sub-menu__title){
border-bottom: 1px solid #1f2d3d;
}
::v-deep(.is-active .el-sub-menu .el-menu){
background-color:rgb(48, 65, 86)!important;
}
</style>
<script>
export default {
name: 'AsideItem',
data () {
return {}
},
props: {
item: {
type: Object,
required: true,
default: () => {
return {}
}
}
},
methods: {
showChildren (menu) {
if (typeof menu.children === 'undefined' || menu.children.length <= 0) return false
if (menu.children.length === 1 && menu.children[0].hidden) return false
return true
},
submenuTitleNoDropdown (menu) {
if (typeof menu.children === 'undefined' || menu.children.length <= 0) return false
if (menu.children.length === 1 && menu.children[0].hidden) return true
return false
},
handleOpenPage (item) {
this.$router.push({
path: item.path
})
}
}
}
</script>

View File

@@ -0,0 +1,6 @@
<template>
<div>footer</div>
</template>
<script>
export default {}
</script>

View File

@@ -0,0 +1,319 @@
<template>
<el-row class="header-container">
<el-col :span="21" class="tags-container">
<div class="left-menu-collapse" @click="changeCollapse">
<i :class="isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold'"></i>
</div>
<div class="tags-box">
<el-tag
v-for="(tag, idx) in tags"
:key="idx"
:disable-transitions="false"
@click="handleClick(tag)"
@close="handleCloseTag(idx, tag.fullPath)"
:closable="tag.name !== 'Index' && tag.name !== 'ProductHomelist'"
:class="fullPath === tag.fullPath ? 'tag active' : 'tag'"
>{{ tag.meta.title }}</el-tag>
</div>
</el-col>
<el-col :span="3" class="text-r p-t-20">
<!-- <i class="el-icon-message f_18 m-r-38 position-r">
<span class="news-number">20</span>
</i>-->
<el-dropdown :hide-on-click="false">
<span class="el-dropdown-link">
<span class="f_14">{{ userInfo.staff_name }}</span>
<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="handleNavigatorPersonCenter">个人资料</el-dropdown-item>
<el-dropdown-item divided @click="handleSigninOut">
<i class="el-icon-switch-button"></i>
退出
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</el-col>
</el-row>
</template>
<style lang="scss" scoped>
.header-container {
height: 100%;
background-color: #304156;
padding-right: 20px;
}
.tags-container {
padding: 0 20px;
}
.left-menu-collapse {
position: absolute;
top: 50%;
left: 10px;
transform: translateY(-50%);
width: 33px;
height: 33px;
text-align: center;
line-height: 33px;
cursor: pointer;
color: #c0ccd8;
}
.tags-box {
position: absolute;
top: 50%;
left: 50px;
transform: translateY(-50%);
}
::v-deep(.tag) {
color: #c0ccd8;
border: 1px solid #293749;
margin-right: 10px;
background-color: #293749;
cursor: pointer;
padding: 0px 10px 0px 10px;
height: 38px !important;
line-height: 38px;
}
.tag.active {
background-color: #344964 !important;
color: FFF;
font-size: 14px;
border: 1px solid #4178d5;
}
::v-deep(.el-tag .el-icon-close) {
padding-left: 20px;
}
::v-deep(.el-tag .el-tag__close:hover) {
background-color: transparent !important;
}
// ::v-deep([class*=" el-icon-"]) {
// color: #555;
// }
::v-deep(.el-header) {
padding: 0px 0px 0px 20px;
}
.news-number {
position: absolute;
top: -50%;
left: 50%;
background-color: #fc8568;
padding: 2px 5px;
color: #fff;
font-size: 6px;
border-radius: 18px;
}
.el-dropdown {
color: #c0ccd8 !important;
}
.el-dropdown .el-dropdown-selfdefine {
line-height: 40px !important;
color: #c0ccd8 !important;
}
</style>
<script>
import { mapActions, mapState } from 'vuex'
import { setNotLoggedIn } from '@/utils/auth'
export default {
data() {
return {
fullPath: '/index',
tags: [
{
fullPath: '/index/oindex',
hash: '',
query: {},
name: 'OldCost',
path: '/index/oindex',
params: {},
matched: [
{
path: '/index',
redirect: '',
name: 'NewCost',
meta: {
title: 'OPD211',
permission: ['NewCost.OldCost', 'NewCost.NewCostFinance', 'NewCost.NewCostLog']
},
props: {
default: false
},
children: [
{
id: 641,
path: '/index/oindex',
name: 'OldCost',
meta: {
title: '老产品成本管理'
},
hidden: false,
redirect: ''
},
{
id: 619,
path: '/index/log',
name: 'NewCostLog',
meta: {
title: '日志管理'
},
hidden: true,
redirect: ''
}
],
instances: {},
leaveGuards: {
'Set(0)': []
},
updateGuards: {
'Set(0)': []
},
enterCallbacks: {},
components: {
default: {
name: 'Layout',
components: {
'layout-aside': {
components: {
'aside-item': {
name: 'AsideItem',
props: {
item: {
0: false,
1: true,
required: true
}
},
methods: {},
__scopeId: 'data-v-0705fa1e',
__file: 'src/components/layout/libs/layout-aside/item.vue',
__hmrId: '0705fa1e'
}
},
computed: {},
watch: {},
methods: {},
__scopeId: 'data-v-357d3738',
__file: 'src/components/layout/libs/layout-aside/index.vue',
__hmrId: '357d3738'
},
'layout-header': {
computed: {},
watch: {},
methods: {},
__scopeId: 'data-v-6c46a177',
__file: 'src/components/layout/libs/layout-header/index.vue',
__hmrId: '6c46a177'
}
},
computed: {},
__scopeId: 'data-v-dd2fd986',
__file: 'src/components/layout/index.vue',
__hmrId: 'dd2fd986'
}
}
},
{
path: '/index/oindex',
redirect: '',
name: 'OldCost',
meta: {
title: '老产品成本管理'
},
props: {
default: false
},
children: [],
instances: {},
leaveGuards: {
'Set(0)': []
},
updateGuards: {
'Set(0)': []
},
enterCallbacks: {},
components: {
default: {
computed: {},
methods: {},
__scopeId: 'data-v-1e7a7aba',
__file: 'src/views/index/oindex.vue',
__hmrId: '1e7a7aba'
}
}
}
],
meta: {
title: '老产品成本管理',
permission: ['NewCost.OldCost', 'NewCost.NewCostFinance', 'NewCost.NewCostLog']
},
redirectedFrom: {
fullPath: '/index/oindex',
hash: '',
query: {},
path: '/index/oindex',
params: {},
matched: [],
meta: {},
href: '/index/oindex'
},
href: '/index/oindex'
}
]
}
},
computed: {
...mapState({
// 取出页面标签
userInfo: state => state.user.userInfo,
// tags: state => state.topNavTag.tags,
isCollapse: state => state.leftAside.isCollapse
})
},
watch: {
// 监听路由变化
$route(to, from) {
this.fullPath = to.fullPath
}
},
created() {
this.fullPath = this.$route.fullPath
},
methods: {
...mapActions({
// 关闭标签及页面
handleCloseTag: 'topNavTag/removeNavTag',
// 展开收缩左侧菜单栏
changeCollapse: 'leftAside/changeCollapse'
}),
// 页面标签点击事件
handleClick(tag) {
this.$router.push(tag)
},
// 页面标签点击事件
// handleCloseTag(idx, url) {
// console.log(idx, url)
// },
// 个人中心
handleNavigatorPersonCenter() {
window.open(process.env.VUE_APP_SSO_BASEURL + 'user/index.html')
},
// 退出
handleSigninOut() {
this.$http.get('login/logout').then(r => {
if (r.errno === 0) {
setNotLoggedIn()
this.$store.replaceState({})
this.$router.push({
path: '/login'
})
}
})
}
}
}
</script>