Merge branch 'main' of http://120.76.84.145:10101/gitblit/r/H5/leshan-laboratory
11个文件已修改
1 文件已重命名
12个文件已添加
| | |
| | | .DS_Store |
| | | node_modules |
| | | /dist |
| | | |
| | | package-lock.json |
| | | |
| | | # local env files |
| | | .env.local |
| | |
| | | |
| | | <script> |
| | | export default { |
| | | name: 'App', |
| | | data() { |
| | | return { |
| | | windowWidth: window.innerWidth, |
| | | isCollapse: false |
| | | } |
| | | }, |
| | | watch: { |
| | | windowWidth(newWidth) { |
| | | // 当窗口宽度小于某个值时,可以触发折叠 |
| | | if (newWidth < 1200 && !this.isCollapse) { |
| | | this.isCollapse = true |
| | | this.$store.commit('SET_ISFOLD', true) |
| | | } else if (newWidth >= 1200 && this.isCollapse) { |
| | | this.isCollapse = false |
| | | this.$store.commit('SET_ISFOLD', false) |
| | | } |
| | | } |
| | | }, |
| | | created() { |
| | | // 初始化时检查窗口大小 |
| | | this.handleResize() |
| | | }, |
| | | mounted() { |
| | | // 监听窗口大小变化 |
| | | window.addEventListener('resize', this.handleResize) |
| | | }, |
| | | beforeDestroy() { |
| | | // 移除监听 |
| | | window.removeEventListener('resize', this.handleResize) |
| | | }, |
| | | methods: { |
| | | handleResize() { |
| | | this.windowWidth = window.innerWidth |
| | | } |
| | | }, |
| | | } |
| | | </script> |
| | | |
| | | <style> |
| | | <style lang="less"> |
| | | ::-webkit-scrollbar { |
| | | display: none; |
| | | } |
| | | |
| | | html, |
| | | body, |
| | | #app { |
| | |
| | | padding: 0; |
| | | background-color: rgb(245, 245, 245); |
| | | } |
| | | |
| | | .selected { |
| | | color: #049C9A !important; |
| | | } |
| | | .el-button--primary { |
| | | background-color: #009688 !important; |
| | | border-color: #009688 !important; |
| | | } |
| | | .el-button--text { |
| | | color: #009688 !important; |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="card"> |
| | | <slot></slot> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | |
| | | } |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .card { |
| | | height: calc(100% - 110px); |
| | | overflow-y: auto; |
| | | padding: 30px 30px 59px 30px; |
| | | box-shadow: 0px 10px 19px 0px rgba(0, 0, 0, 0.06); |
| | | border-radius: 16px; |
| | | border: 4px solid #FFFFFF; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="table-container"> |
| | | <el-table border :data="tableData" :height="height"> |
| | | <slot></slot> |
| | | </el-table> |
| | | <div v-if="total > 0"> |
| | | <el-pagination layout="slot, prev, pager, next, sizes, jumper" :page-size="queryForm.pageSize" |
| | | :current-page="queryForm.pageNum" :total="total" @current-change="handleCurrentChange" |
| | | @size-change="handleSizeChange" class="pagination"> |
| | | <div class="pagination-info">第 {{ (queryForm.pageNum == 1) ? 1 : (queryForm.pageNum - 1) * |
| | | queryForm.pageSize + 1 }}-{{ |
| | | queryForm.pageNum * queryForm.pageSize }} 条/总共 {{ total }} 条</div> |
| | | </el-pagination> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | props: { |
| | | tableData: { |
| | | type: Array, |
| | | default: () => [] |
| | | }, |
| | | total: { |
| | | type: Number, |
| | | default: 20 |
| | | }, |
| | | queryForm: { |
| | | type: Object, |
| | | default: () => { |
| | | return { |
| | | pageSize: 10, |
| | | pageNum: 1 |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | computed: { |
| | | height() { |
| | | return this.$baseTableHeight() |
| | | }, |
| | | }, |
| | | methods: { |
| | | handleCurrentChange(page) { |
| | | this.$emit('handleCurrentChange', page) |
| | | }, |
| | | handleSizeChange(size) { |
| | | this.$emit('handleSizeChange', size) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .el-table--border, |
| | | .el-table--group { |
| | | border-radius: 8px 8px 0px 0px; |
| | | |
| | | ::v-deep thead { |
| | | tr { |
| | | th { |
| | | background: #FAFAFA !important; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .pagination { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | margin-top: 16px; |
| | | |
| | | .pagination-info { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: rgba(0, 0, 0, 0.88); |
| | | line-height: 24px; |
| | | } |
| | | |
| | | ::v-deep .el-pager li { |
| | | padding: 0 !important; |
| | | min-width: 24px !important; |
| | | height: 24px !important; |
| | | line-height: 24px !important; |
| | | |
| | | &:hover { |
| | | color: #049C9A !important; |
| | | } |
| | | } |
| | | |
| | | ::v-deep .el-pager .active { |
| | | color: #049C9A !important; |
| | | border-radius: 6px !important; |
| | | border: 1px solid #049C9A !important; |
| | | } |
| | | |
| | | ::v-deep .el-pagination__jump { |
| | | margin-left: 0 !important; |
| | | |
| | | .el-input__inner:focus { |
| | | border: 1px solid #049C9A !important; |
| | | } |
| | | } |
| | | |
| | | ::v-deep .el-pagination__sizes .el-input .el-input__inner { |
| | | color: #049C9A !important; |
| | | border-color: #049C9A !important; |
| | | |
| | | &:hover { |
| | | color: #049C9A !important; |
| | | border-color: #049C9A !important; |
| | | } |
| | | |
| | | &:focus { |
| | | color: #049C9A !important; |
| | | border-color: #049C9A !important; |
| | | } |
| | | } |
| | | |
| | | ::v-deep button:hover { |
| | | color: #049C9A !important; |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="table-slot"> |
| | | <div class="search"> |
| | | <slot name="search"></slot> |
| | | </div> |
| | | <div class="table"> |
| | | <slot name="setting"></slot> |
| | | <Table :tableData="tableData" :total="total" :queryForm="queryForm" @currentChange="handleCurrentChange" @sizeChange="handleSizeChange"> |
| | | <slot name="table"></slot> |
| | | </Table> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import Table from '../Table/index.vue' |
| | | export default { |
| | | components: { |
| | | Table, |
| | | }, |
| | | props: { |
| | | tableData: { |
| | | type: Array, |
| | | default: () => [] |
| | | }, |
| | | total: { |
| | | type: Number, |
| | | default: 0 |
| | | }, |
| | | queryForm: { |
| | | type: Object, |
| | | default: () => { |
| | | return { |
| | | pageSize: 10, |
| | | pageNum: 1 |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | handleCurrentChange(page) { |
| | | this.$emit('handleCurrentChange', page) |
| | | }, |
| | | handleSizeChange(size) { |
| | | this.$emit('handleSizeChange', size) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .table-slot { |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | .search { |
| | | padding: 34px 30px 15px 30px; |
| | | box-shadow: 0px 10px 19px 0px rgba(0, 0, 0, 0.06); |
| | | border-radius: 16px; |
| | | border: 4px solid #FFFFFF; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | margin-bottom: 30px; |
| | | } |
| | | |
| | | .table { |
| | | flex: 1; |
| | | padding: 20px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | box-shadow: 0px 10px 19px 0px rgba(0, 0, 0, 0.06); |
| | | border-radius: 16px; |
| | | border: 4px solid #FFFFFF; |
| | | } |
| | | </style> |
| | |
| | | :close-on-click-modal="false" width="433px"> |
| | | <div class="top-con a-center" slot="title"> |
| | | <div class="left"> |
| | | <img src="@/assets/notice@2x.png" style="width: 24px;height: 24px;margin-right: 14px;" /> |
| | | <img src="@/assets/public/notice@2x.png" style="width: 24px;height: 24px;margin-right: 14px;" /> |
| | | <div class="title">{{ title }}</div> |
| | | </div> |
| | | </div> |
| | |
| | | <template> |
| | | <div> |
| | | <div style="height: 100%;"> |
| | | <keep-alive :include="keepAliveList"> |
| | | <router-view /> |
| | | </keep-alive> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { mapState } from 'vuex' |
| | | export default { |
| | | name: 'AppContent', |
| | | data() { |
| | | return { |
| | | } |
| | | }, |
| | | computed: { |
| | | ...mapState(['keepAliveList']) |
| | | } |
| | | } |
| | | </script> |
| | |
| | | <template> |
| | | <!-- 判断当前页面是否显示,如果hide为true,则不渲染该菜单 --> |
| | | <div v-if="!item.meta.hide && menus.includes(item.meta.privilege)"> |
| | | <!-- <div v-if="!item.meta.hide"> --> |
| | | <!-- <div v-if="!item.meta.hide && menus.includes(item.meta.privilege)"> --> |
| | | <div v-if="!(item.meta && item.meta.hide)"> |
| | | <!-- 根菜单 --> |
| | | <MenuLink :to="resolvePath()" v-if="!item.children"> |
| | | <el-menu-item :index="resolvePath()"> |
| | | <i :class="item.meta.icon || ''"></i> |
| | | <span slot="title">{{ item.meta.title }}</span> |
| | | <i :class="(item.meta && item.meta.icon) || ''"></i> |
| | | <span slot="title">{{ (item.meta && item.meta.title) || '' }}</span> |
| | | </el-menu-item> |
| | | </MenuLink> |
| | | |
| | | <!-- 可展开菜单 --> |
| | | <el-submenu :index="resolvePath()" v-else> |
| | | <template slot="title"> |
| | | <i :class="item.meta.icon"></i> |
| | | <span slot="title">{{ item.meta.title }}</span> |
| | | <i :class="(item.meta && item.meta.icon) || ''"></i> |
| | | <span slot="title">{{ (item.meta && item.meta.title) || '' }}</span> |
| | | </template> |
| | | <!-- 这里递归去展示多级菜单 --> |
| | | <menu-item v-for="(route, index) in item.children" :key="index" :item="route" |
| | |
| | | }; |
| | | </script> |
| | | <style lang="less" scoped> |
| | | .is-active { |
| | | background-color: rgb(245, 245, 245); |
| | | ::v-deep .router-link-exact-active .is-active { |
| | | background: #EFF8FA; |
| | | border-radius: 8px; |
| | | font-weight: bold; |
| | | color: #000; |
| | | color: #05908E; |
| | | } |
| | | |
| | | .el-menu { |
| | | border-right: unset !important; |
| | | ::v-deep .el-menu-item, |
| | | ::v-deep .el-submenu__title { |
| | | border-radius: 8px; |
| | | height: 40px; |
| | | line-height: 40px; |
| | | } |
| | | |
| | | ::v-deep .el-menu-item:hover, |
| | | ::v-deep .el-submenu__title:hover { |
| | | background: #EFF8FA; |
| | | } |
| | | </style> |
| | |
| | | }; |
| | | }, |
| | | mounted() { |
| | | |
| | | // 获取所有定义的一级菜单和多级菜单 |
| | | this.routersList = routers.options.routes[0].children; |
| | | // 过滤掉登录路由,只获取主布局下的路由 |
| | | this.routersList = routers.options.routes.find(route => route.path === '/').children; |
| | | }, |
| | | }; |
| | | </script> |
| | |
| | | <div> |
| | | <!-- 右侧用户登录图标 --> |
| | | <div class="user-logininfo"> |
| | | <el-dropdown @command="clickmenu"> |
| | | <span class="el-dropdown-link right-userName"> |
| | | <div style="margin-left: 10px;">{{ userInfo.nickName }}</div> |
| | | </span> |
| | | <el-dropdown-menu slot="dropdown"> |
| | | <el-dropdown-item command="outlogin">退出登录</el-dropdown-item> |
| | | </el-dropdown-menu> |
| | | </el-dropdown> |
| | | <div class="user-logininfo-icon"> |
| | | <!-- 折叠 --> |
| | | <i @click="clickFold" class="el-icon-s-fold"></i> |
| | | <!-- 标签列表 --> |
| | | <div class="tag-list-container"> |
| | | <div class="tag-list" v-for="tag in tagList" :key="tag.name"> |
| | | <div @click="goTag(tag)" :class="{ 'activeTag': tag.path === $route.path }"> |
| | | {{ tag.meta.title }} |
| | | </div> |
| | | <i @click="closeTag(tag)" v-if="tagList.length > 1" class="el-icon-close"></i> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="user-info"> |
| | | <img src="@/assets/public/photo.png" /> |
| | | <div class="user-info-text">欢迎您,admin</div> |
| | | <div class="user-info-line"></div> |
| | | <div @click="outLogin" class="user-info-out"> |
| | | <img src="@/assets/public/logOut.png" /> |
| | | <div class="user-info-out-text">退出登录</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { mapState } from 'vuex' |
| | | export default { |
| | | data() { |
| | | return { |
| | | userInfo: '', |
| | | } |
| | | }, |
| | | computed: { |
| | | ...mapState(['tagList', 'isFold']) |
| | | }, |
| | | mounted() { |
| | | // 获取用户信息 |
| | | this.getUserInfo() |
| | | }, |
| | | methods: { |
| | | // 点击折叠按钮 |
| | | clickFold() { |
| | | this.$store.commit('SET_ISFOLD', !this.isFold) |
| | | }, |
| | | // 获取用户信息 |
| | | getUserInfo() { |
| | | this.userInfo = JSON.parse(localStorage.getItem('userInfo')) |
| | | }, |
| | | // 点击下拉菜单回调 |
| | | clickmenu(e) { |
| | | if (e === 'outlogin') { |
| | | this.outLogin() |
| | | } |
| | | }, |
| | | // 退出登录 |
| | | outLogin() { |
| | | localStorage.clear() |
| | | this.$router.replace({ path: "/" }); |
| | | }, |
| | | // 关闭标签 |
| | | closeTag(tag) { |
| | | this.$store.commit('SET_TAGLIST', this.tagList.filter(item => item.path !== tag.path)) |
| | | // 判断是否是当前标签 |
| | | if (tag.path === this.$route.path) { |
| | | // if (this.tagList.length > 1) { |
| | | this.$router.push(this.tagList[this.tagList.length - 1].path) |
| | | // } else { |
| | | // // this.$router.push('/welcome') |
| | | // } |
| | | } |
| | | }, |
| | | // 跳转标签 |
| | | goTag(tag) { |
| | | this.$router.push(tag.path) |
| | | } |
| | | }, |
| | | } |
| | | </script> |
| | |
| | | // 右侧用户头像 |
| | | .user-logininfo { |
| | | height: 100%; |
| | | padding-right: 40px; |
| | | cursor: pointer; |
| | | padding-left: 32px; |
| | | padding-right: 20px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: flex-end; |
| | | justify-content: space-between; |
| | | |
| | | .user-logininfo-icon { |
| | | flex: 1; |
| | | flex-shrink: 0; |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | i:first-child { |
| | | margin-right: 21px; |
| | | } |
| | | |
| | | i { |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .tag-list-container { |
| | | display: flex; |
| | | align-items: center; |
| | | overflow-x: auto; |
| | | |
| | | .tag-list { |
| | | flex-shrink: 0; |
| | | display: flex; |
| | | align-items: center; |
| | | cursor: pointer; |
| | | font-weight: 400; |
| | | font-size: 18px; |
| | | color: rgba(0, 0, 0, .6); |
| | | margin-right: 40px; |
| | | |
| | | div:hover { |
| | | font-weight: bold; |
| | | color: #049C9A; |
| | | } |
| | | |
| | | i { |
| | | margin-left: 10px; |
| | | |
| | | &:hover { |
| | | color: #049C9A; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .activeTag { |
| | | font-weight: bold; |
| | | color: #049C9A; |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | .right-userName { |
| | | .user-info { |
| | | flex-shrink: 0; |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | img { |
| | | width: 26px; |
| | | height: 26px; |
| | | border-radius: 50%; |
| | | } |
| | | |
| | | .user-info-text { |
| | | margin-left: 16px; |
| | | font-size: 14px; |
| | | color: #303133; |
| | | font-weight: 400; |
| | | } |
| | | |
| | | .user-info-line { |
| | | width: 1px; |
| | | height: 12px; |
| | | background-color: #979797; |
| | | margin: 0 20px; |
| | | } |
| | | |
| | | .user-info-out { |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 0 11px; |
| | | border-radius: 12px; |
| | | position: relative; |
| | | background: transparent; |
| | | cursor: pointer; |
| | | |
| | | &::before { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | border-radius: 12px; |
| | | padding: 1px; |
| | | background: linear-gradient(180deg, rgba(10, 203, 202, 1), rgba(4, 156, 154, 1)); |
| | | -webkit-mask: |
| | | linear-gradient(#fff 0 0) content-box, |
| | | linear-gradient(#fff 0 0); |
| | | -webkit-mask-composite: xor; |
| | | mask-composite: exclude; |
| | | } |
| | | |
| | | .user-info-out-text { |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: #049C9A; |
| | | line-height: 21px; |
| | | position: relative; |
| | | z-index: 1; |
| | | } |
| | | |
| | | img { |
| | | width: 14px; |
| | | height: 14px; |
| | | margin-right: 7px; |
| | | position: relative; |
| | | z-index: 1; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <!-- 判断是否在空白页打开 --> |
| | | <template v-if="!isOneself"> |
| | | <div class="app-wrapper"> |
| | | <div class="left"> |
| | | <div class="left" :style="{ width: isFold ? '0px' : '258px' }"> |
| | | <!-- 系统标题 --> |
| | | <div class="system-title"> |
| | | <div v-if="!isFold" class="system-title"> |
| | | <div class="image"> |
| | | <img src="../assets/logo.jpg" alt="" srcset="" /> |
| | | </div> |
| | | <div class="title">职评网管理系统</div> |
| | | <div class="title">实验室流程</div> |
| | | </div> |
| | | <!-- 左侧菜单 --> |
| | | <div class="sidebar-container"> |
| | | <div v-if="!isFold" class="sidebar-container"> |
| | | <ElMenu /> |
| | | </div> |
| | | <div v-if="!isFold" class="sidebar-left-bg"></div> |
| | | <div v-if="!isFold" class="sidebar-bottom-bg"></div> |
| | | </div> |
| | | <!-- 右侧展示内容 --> |
| | | <div class="main-container"> |
| | | <div class="main-container" :style="{ width: isFold ? '100%' : 'calc(100% - 258px)' }"> |
| | | <HeaderNav class="header-main" /> |
| | | <div v-if="nowRouteName" class="router_name">{{ nowRouteName }}</div> |
| | | <AppContent class="app-main" /> |
| | | </div> |
| | | </div> |
| | |
| | | import ElMenu from './components/ElMenu/index.vue' |
| | | import HeaderNav from './components/HeaderNav.vue' |
| | | import AppContent from './components/AppContent.vue' |
| | | import { mapState } from 'vuex' |
| | | export default { |
| | | data() { |
| | | return { |
| | |
| | | // 获取当前页面名称 |
| | | nowRouteName: '', |
| | | } |
| | | }, |
| | | computed: { |
| | | ...mapState(['isFold']) |
| | | }, |
| | | components: { |
| | | ElMenu, |
| | |
| | | height: 100%; |
| | | width: 100%; |
| | | display: flex; |
| | | background-image: url('../assets/public/layoutsBG.png'); |
| | | background-size: cover; |
| | | background-position: center; |
| | | |
| | | .left { |
| | | width: 200px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | position: relative; |
| | | background-color: white; |
| | | transition: width 0.3s ease-in-out; |
| | | |
| | | // 系统标题 |
| | | .system-title { |
| | | overflow: hidden; |
| | | white-space: nowrap; |
| | | display: flex; |
| | | justify-content: space-around; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | background-color: white; |
| | | height: 50px; |
| | | padding: 0px 10px; |
| | | height: 240px; |
| | | box-sizing: border-box; |
| | | |
| | | .image { |
| | | width: 40px; |
| | | height: 40px; |
| | | margin-top: 40px; |
| | | width: 100px; |
| | | height: 100px; |
| | | |
| | | img { |
| | | width: 100%; |
| | | height: 100%; |
| | | border-radius: 50%; |
| | | } |
| | | } |
| | | |
| | | .title { |
| | | font-weight: 700; |
| | | margin-top: 7px; |
| | | font-weight: bold; |
| | | line-height: 43px; |
| | | font-size: 25px; |
| | | } |
| | | } |
| | | |
| | | // 左侧菜单 |
| | | .sidebar-container { |
| | | z-index: 2; |
| | | padding: 0 19px; |
| | | overflow-y: auto; |
| | | flex: 1; |
| | | background-color: white; |
| | | box-shadow: 0px 3px 13px 0px rgba(94, 131, 245, 0.1); |
| | | |
| | | ::v-deep .el-menu { |
| | | border-right: unset !important; |
| | | } |
| | | } |
| | | |
| | | .sidebar-left-bg { |
| | | z-index: 1; |
| | | position: absolute; |
| | | top: 338px; |
| | | left: 0; |
| | | width: 183px; |
| | | height: 316px; |
| | | background: #FFFCE5; |
| | | opacity: 0.56; |
| | | filter: blur(76.141290103688px); |
| | | } |
| | | |
| | | .sidebar-bottom-bg { |
| | | z-index: 1; |
| | | position: absolute; |
| | | bottom: 0; |
| | | left: 0; |
| | | width: 129px; |
| | | height: 289px; |
| | | background: #66FFFF; |
| | | opacity: 0.4; |
| | | filter: blur(76.141290103688px); |
| | | } |
| | | } |
| | | |
| | | .main-container { |
| | | flex: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | | transition: width 0.3s ease-in-out; |
| | | |
| | | .header-main { |
| | | background-color: white; |
| | | height: 50px; |
| | | } |
| | | |
| | | .router_name { |
| | | padding-top: 8px; |
| | | padding-left: 23px; |
| | | font-size: 24px; |
| | | font-weight: bold; |
| | | height: 70px; |
| | | } |
| | | |
| | | .app-main { |
| | | height: calc(100% - 120px); |
| | | flex: 1; |
| | | overflow: auto; |
| | | border-radius: 10px; |
| | | margin: 16px 23px; |
| | | padding: 10px 21px 0 21px; |
| | | } |
| | | } |
| | | |
| | |
| | | import App from "./App.vue"; |
| | | import router from "./router"; |
| | | import store from './store' |
| | | import TableCustom from '@/components/TableSlot/index.vue' |
| | | import Card from '@/components/Card/index.vue' |
| | | import ShowDelConfirm from '@/components/showDelConfirm/index.vue' |
| | | |
| | | Vue.config.productionTip = false; |
| | | Vue.use(ElementUI, { size: 'small' }) |
| | | Vue.component('TableCustom', TableCustom) |
| | | Vue.component('Card', Card) |
| | | Vue.component('ShowDelConfirm', ShowDelConfirm) |
| | | |
| | | Vue.prototype.msgsuccess = function (msg) { |
| | | this.$message({ |
| | |
| | | this.$message.info(msg); |
| | | } |
| | | |
| | | Vue.prototype.$baseTableHeight = (formType) => { |
| | | let height = window.innerHeight |
| | | let paddingHeight = 400 |
| | | const formHeight = 50 |
| | | |
| | | if ('number' == typeof formType) { |
| | | height = height - paddingHeight - formHeight * formType |
| | | } else { |
| | | height = height - paddingHeight |
| | | } |
| | | return height |
| | | } |
| | | |
| | | new Vue({ |
| | | router, |
| | | store, |
| | |
| | | /** |
| | | * path: "/login", ------页面地址 |
| | | component: () => import("../views/login"), ------组件地址 |
| | | name: "Login", ------组件名称 缓存时需要 唯一性 |
| | | meta: { |
| | | title: "登录", ------页面标题 |
| | | icon: "el-icon-user-solid", ------菜单图标 |
| | | oneself: true, ------是否在单独页面打开 |
| | | hide: true, ------是否隐藏改菜单 |
| | | keepAlive: true, ------是否缓存 |
| | | } |
| | | */ |
| | | |
| | | const routes = [ |
| | | { |
| | | path: "", |
| | | redirect: "login", |
| | | component: Layouts, |
| | | children: [ |
| | | { |
| | | path: "/login", |
| | | meta: { |
| | | title: "登录", |
| | | oneself: true, |
| | | hide: true, |
| | | privilege: 'login' |
| | | }, |
| | | component: () => import("../views/login"), |
| | | }, |
| | | ], |
| | | },{ |
| | | path: "", |
| | | redirect: "dispatching", |
| | | { |
| | | path: "/", |
| | | component: Layouts, |
| | | children: [ |
| | | { |
| | | path: "", |
| | | redirect: "/projectList/list" |
| | | }, |
| | | { |
| | | path: "/projectList", |
| | | meta: { |
| | | title: "项目组管理", |
| | | }, |
| | | component: Parent, |
| | | children: [ |
| | | { |
| | | path: "list", |
| | | name: "ProjectList", |
| | | meta: { |
| | | title: "项目组管理", |
| | | }, |
| | | component: () => import("../views/projectList"), |
| | | }, |
| | | { |
| | | path: "addProject", |
| | | name: "AddProject", |
| | | meta: { |
| | | title: "新增项目组", |
| | | hide: true, |
| | | keepAlive: true, |
| | | }, |
| | | component: () => import("../views/projectList/addProject"), |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | path: "/dataManagement", |
| | | component: Parent, |
| | | meta: { |
| | | title: "实验室数据管理", |
| | | }, |
| | | children: [ |
| | | { |
| | | path: "/approvalPlan", |
| | | meta: { |
| | | title: "项目课题方案审批", |
| | | keepAlive: true, |
| | | }, |
| | | component: () => import("../views/dataManagement/approvalPlan/list.vue"), |
| | | }, |
| | | { |
| | | path: "/dispatching", |
| | | meta: { |
| | | title: "实验调度管理", |
| | | oneself: true, |
| | | hide: true, |
| | | privilege: 'dispatching' |
| | | keepAlive: true, |
| | | }, |
| | | component: () => import("../views/dispatching/list.vue"), |
| | | component: () => import("../views/dataManagement/dispatching/list.vue"), |
| | | }, |
| | | ], |
| | | } |
| | | ], |
| | | }, |
| | | ]; |
| | |
| | | // 前置路由拦截器 |
| | | router.beforeEach((to, from, next) => { |
| | | // 设置当前页签名称 |
| | | document.title = to.meta.title || '职评网管理系统'; |
| | | // 没有登录并且要去的页面不是登录页面,在强制跳转到登录 |
| | | if (to.path === "/login") { |
| | | localStorage.removeItem('userInfo') |
| | | next() |
| | | } else if (!localStorage.getItem('userInfo')) { |
| | | next('/login') |
| | | } else { |
| | | // 判断是否拥有要跳转菜单权限 |
| | | let menus = store.state.menus |
| | | document.title = to.meta.title || '实验室流程'; |
| | | |
| | | // console.log(store.state.menus); |
| | | // console.log(to.meta); |
| | | // console.log(to.meta.hasOwnProperty('privilege')); |
| | | // console.log(!menus.includes(to.meta.privilege)); |
| | | // 登录验证 |
| | | // if (to.path === "/login") { |
| | | // localStorage.removeItem('userInfo') |
| | | // next() |
| | | // } else if (!localStorage.getItem('userInfo')) { |
| | | // next('/login') |
| | | // } else { |
| | | // // 判断是否拥有要跳转菜单权限 |
| | | // let menus = store.state.menus |
| | | // if (to.meta.hasOwnProperty('privilege') && !menus.includes(to.meta.privilege)) { |
| | | // return |
| | | // } |
| | | |
| | | if (to.meta.hasOwnProperty('privilege') && !menus.includes(to.meta.privilege)) { |
| | | return |
| | | // 设置标签列表 |
| | | if (!to.meta.hide || !to.meta.oneself) { |
| | | let tagList = JSON.parse(localStorage.getItem('tagList') || '[]') |
| | | // 判断是否存在 |
| | | let isExist = tagList.some(item => item.path === to.path) |
| | | if (!isExist) { |
| | | // 只保存必要的信息 |
| | | const tagInfo = { |
| | | path: to.path, |
| | | name: to.name, |
| | | meta: to.meta |
| | | } |
| | | tagList.push(tagInfo) |
| | | localStorage.setItem('tagList', JSON.stringify(tagList)) |
| | | store.commit('SET_TAGLIST', tagList) |
| | | } |
| | | } |
| | | |
| | | // 判断是否需要缓存 |
| | | if (to.meta.keepAlive) { |
| | | let keepAliveList = JSON.parse(localStorage.getItem('keepAliveList') || '[]') |
| | | // 判断是否已经缓存 |
| | | let isExist = keepAliveList.includes(to.name) |
| | | if (!isExist) { |
| | | keepAliveList.push(to.name) |
| | | localStorage.setItem('keepAliveList', JSON.stringify(keepAliveList)) |
| | | store.commit('SET_KEEPALIVELIST', keepAliveList) |
| | | } |
| | | } |
| | | |
| | | next() |
| | | } |
| | | // } |
| | | }); |
| | | |
| | | export default router; |
| | |
| | | const store = new Vuex.Store({ |
| | | state: { |
| | | menus: localStorage.getItem('menuList') ? JSON.parse(localStorage.getItem('menuList')) : [], |
| | | keepAliveList: localStorage.getItem('keepAliveList') ? JSON.parse(localStorage.getItem('keepAliveList')) : [],//缓存页面 |
| | | tagList: localStorage.getItem('tagList') ? JSON.parse(localStorage.getItem('tagList')) : [],//标签列表 |
| | | isFold: false,//是否折叠 |
| | | }, |
| | | mutations: { |
| | | SET_MENUS(state, data) { |
| | | state.menus = data; |
| | | }, |
| | | SET_KEEPALIVELIST(state, data) { |
| | | state.keepAliveList = data; |
| | | localStorage.setItem('keepAliveList', JSON.stringify(data)); |
| | | }, |
| | | SET_TAGLIST(state, data) { |
| | | state.tagList = data; |
| | | localStorage.setItem('tagList', JSON.stringify(data)); |
| | | }, |
| | | SET_ISFOLD(state, data) { |
| | | state.isFold = data; |
| | | }, |
| | | }, |
| | | actions: { |
| | | setMenus({ commit }, data) { |
| | | commit('SET_MENUS', data); |
| | | }, |
| | | setKeepAliveList({ commit }, data) { |
| | | commit('SET_KEEPALIVELIST', data); |
| | | }, |
| | | setTagList({ commit }, data) { |
| | | commit('SET_TAGLIST', data); |
| | | }, |
| | | setIsFold({ commit }, data) { |
| | | commit('SET_ISFOLD', data); |
| | | } |
| | | } |
| | | }) |
New file |
| | |
| | | <template> |
| | | <div class="list"> |
| | | <TableCustom :queryForm="queryForm" :total="total" @currentChange="handleCurrentChange" @sizeChange="handleSizeChange"> |
| | | <template #search> |
| | | <el-form :model="form" label-width="140px" inline> |
| | | <el-form-item label="项目组名称:"> |
| | | <el-input v-model="form.name" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="项目负责人:"> |
| | | <el-input v-model="form.name" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="通创建日期:"> |
| | | <el-input v-model="form.name"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="" style="margin-left: 63px;"> |
| | | <el-button type="default">重置</el-button> |
| | | <el-button type="primary">查询</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </template> |
| | | <template #setting> |
| | | <el-button class="el-icon-plus" style="margin-bottom: 20px;" type="primary"> 新增项目组</el-button> |
| | | </template> |
| | | <template #table> |
| | | <el-table-column prop="name" label="项目组名称" /> |
| | | <el-table-column prop="age" label="项目负责人" /> |
| | | <el-table-column prop="age" label="项目组成员" /> |
| | | <el-table-column prop="age" label="项目创建时间" /> |
| | | <el-table-column prop="age" label="状态"> |
| | | <template #default="{ row }"> |
| | | <el-tag v-if="row.status == 1" type="success">正常运作</el-tag> |
| | | <el-tag v-else type="danger">已封存</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="age" label="操作"> |
| | | <template #default="{ row }"> |
| | | <el-button type="text" @click="handleChangeStatus(row, 1)">封存</el-button> |
| | | <el-button type="text" @click="handleChangeStatus(row, 0)">解封</el-button> |
| | | <el-button type="text">编辑</el-button> |
| | | <el-button type="text">详情</el-button> |
| | | <el-button type="text" @click="handleDel(row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </template> |
| | | </TableCustom> |
| | | <ShowDelConfirm :show="showDelConfirm" @close="showDelConfirm = false" @confirm="handleDelConfirm" /> |
| | | <ShowDelConfirm :title="changeStatusTitle" :tip="changeStatusTip" :show="changeStatus" @close="changeStatus = false" @confirm="handleChangeStatus" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: 'ProjectList', |
| | | data() { |
| | | return { |
| | | form: { |
| | | name: '' |
| | | }, |
| | | showDelConfirm: false, |
| | | rowId: '', |
| | | changeStatus: false, |
| | | changeStatusTitle: '', |
| | | changeStatusTip: '', |
| | | queryForm: { |
| | | pageSize: 10, |
| | | pageNum: 1 |
| | | }, |
| | | total: 0 |
| | | } |
| | | }, |
| | | methods: { |
| | | handleDel(row) { |
| | | this.showDelConfirm = true |
| | | this.rowId = row.id |
| | | }, |
| | | handleDelConfirm() { |
| | | this.showDelConfirm = false |
| | | this.msgsuccess('删除成功') |
| | | }, |
| | | handleChangeStatus(row, status) { |
| | | this.changeStatus = true |
| | | this.rowId = row.id |
| | | this.changeStatusTitle = status == 1 ? '确认要封存这个项目组吗?' : '确认要解封该项目组吗?' |
| | | this.changeStatusTip = status == 1 ? '封存后项目组内人员看不到数据,审批人仍然可见数据。' : '解封后项目组内人员数据恢复。' |
| | | }, |
| | | handleCurrentChange(page) { |
| | | this.queryForm.pageNum = page |
| | | }, |
| | | handleSizeChange(size) { |
| | | this.queryForm.pageSize = size |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .list { |
| | | height: 100%; |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="list"> |
| | | <TableCustom :queryForm="form" :tableData="tableData" :total="total"> |
| | | <template #search> |
| | | <el-form :model="form" label-width="140px" inline> |
| | | <el-form-item label="项目课题方案名称:"> |
| | | <el-input v-model="form.planName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="项目课题方案编号:"> |
| | | <el-input v-model="form.planCode" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="创建人:"> |
| | | <el-input v-model="form.creator" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="创建时间:"> |
| | | <el-date-picker |
| | | v-model="form.createTime" |
| | | type="daterange" |
| | | range-separator="至" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | value-format="yyyy-MM-dd" |
| | | ></el-date-picker> |
| | | </el-form-item> |
| | | <el-form-item label="审批人:"> |
| | | <el-input v-model="form.approver" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label=""> |
| | | <el-button type="default" @click="resetForm">重置</el-button> |
| | | <el-button type="primary" @click="handleSearch">查询</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </template> |
| | | <template #setting> |
| | | <div class="tableTitle"> |
| | | <div class="title">项目课题方案列表</div> |
| | | </div> |
| | | </template> |
| | | <template #table> |
| | | <el-table-column prop="planCode" label="项目课题方案编号"></el-table-column> |
| | | <el-table-column prop="planName" label="项目课题方案名称"></el-table-column> |
| | | <el-table-column prop="stage" label="项目阶段"></el-table-column> |
| | | <el-table-column prop="creator" label="创建人"></el-table-column> |
| | | <el-table-column prop="createTime" label="创建日期"></el-table-column> |
| | | <el-table-column prop="status" label="审批状态"> |
| | | <template slot-scope="scope"> |
| | | <el-tag :type="getStatusType(scope.row.status)"> |
| | | {{ getStatusText(scope.row.status) }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="approver" label="审批人"></el-table-column> |
| | | <el-table-column prop="approveTime" label="审批时间"></el-table-column> |
| | | <el-table-column label="操作" width="150"> |
| | | <template slot-scope="scope"> |
| | | <el-button |
| | | v-if="scope.row.status === 'pending'" |
| | | type="text" |
| | | @click="handleApprove(scope.row)" |
| | | >审批</el-button> |
| | | <el-button |
| | | type="text" |
| | | @click="handleDetail(scope.row)" |
| | | >详情</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </template> |
| | | </TableCustom> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: "ProjectList", |
| | | data() { |
| | | return { |
| | | form: { |
| | | planName: "", |
| | | planCode: "", |
| | | creator: "", |
| | | createTime: [], |
| | | approver: "", |
| | | status: "" |
| | | }, |
| | | tableData: [], |
| | | total: 0 |
| | | }; |
| | | }, |
| | | methods: { |
| | | resetForm() { |
| | | this.form = { |
| | | planName: "", |
| | | planCode: "", |
| | | creator: "", |
| | | createTime: [], |
| | | approver: "", |
| | | status: "" |
| | | }; |
| | | }, |
| | | handleSearch() { |
| | | // 实现查询逻辑 |
| | | console.log('查询条件:', this.form); |
| | | }, |
| | | getStatusType(status) { |
| | | const statusMap = { |
| | | pending: 'warning', |
| | | rejected: 'danger', |
| | | approved: 'success', |
| | | archived: 'info' |
| | | }; |
| | | return statusMap[status] || 'info'; |
| | | }, |
| | | getStatusText(status) { |
| | | const statusMap = { |
| | | pending: '待审批', |
| | | rejected: '已驳回', |
| | | approved: '已通过', |
| | | archived: '已封存' |
| | | }; |
| | | return statusMap[status] || '未知'; |
| | | }, |
| | | handleApprove(row) { |
| | | // 实现审批逻辑 |
| | | console.log('审批数据:', row); |
| | | }, |
| | | handleDetail(row) { |
| | | // 实现查看详情逻辑 |
| | | console.log('查看详情:', row); |
| | | } |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .list { |
| | | height: 100%; |
| | | } |
| | | .tableTitle { |
| | | display: flex; |
| | | padding-bottom: 20px; |
| | | .title { |
| | | background: #ffffff; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #049c9a; |
| | | padding: 16px 29px; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | color: #049c9a; |
| | | width: unset; |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <Card> |
| | | <template> |
| | | </template> |
| | | </Card> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: 'AddProject', |
| | | data() { |
| | | return { |
| | | |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style></style> |
New file |
| | |
| | | <template> |
| | | <div class="list"> |
| | | <TableCustom :queryForm="queryForm" :total="total" @currentChange="handleCurrentChange" |
| | | @sizeChange="handleSizeChange"> |
| | | <template #search> |
| | | <el-form :model="form" label-width="140px" inline> |
| | | <el-form-item label="项目组名称:"> |
| | | <el-input v-model="form.name" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="项目负责人:"> |
| | | <el-input v-model="form.name" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="通创建日期:"> |
| | | <el-input v-model="form.name"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="" style="margin-left: 63px;"> |
| | | <el-button type="default">重置</el-button> |
| | | <el-button type="primary">查询</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </template> |
| | | <template #setting> |
| | | <el-button @click="handleAddProject" class="el-icon-plus" style="margin-bottom: 20px;" type="primary"> |
| | | 新增项目组</el-button> |
| | | </template> |
| | | <template #table> |
| | | <el-table-column prop="name" label="项目组名称" /> |
| | | <el-table-column prop="age" label="项目负责人" /> |
| | | <el-table-column prop="age" label="项目组成员" /> |
| | | <el-table-column prop="age" label="项目创建时间" /> |
| | | <el-table-column prop="age" label="状态"> |
| | | <template #default="{ row }"> |
| | | <el-tag v-if="row.status == 1" type="success">正常运作</el-tag> |
| | | <el-tag v-else type="danger">已封存</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="age" label="操作"> |
| | | <template #default="{ row }"> |
| | | <el-button type="text" @click="handleChangeStatus(row, 1)">封存</el-button> |
| | | <el-button type="text" @click="handleChangeStatus(row, 0)">解封</el-button> |
| | | <el-button type="text">编辑</el-button> |
| | | <el-button type="text">详情</el-button> |
| | | <el-button type="text" @click="handleDel(row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </template> |
| | | </TableCustom> |
| | | <ShowDelConfirm :show="showDelConfirm" @close="showDelConfirm = false" @confirm="handleDelConfirm" /> |
| | | <ShowDelConfirm :title="changeStatusTitle" :tip="changeStatusTip" :show="changeStatus" |
| | | @close="changeStatus = false" @confirm="handleChangeStatusConfirm" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: 'ProjectList', |
| | | data() { |
| | | return { |
| | | form: { |
| | | name: '' |
| | | }, |
| | | showDelConfirm: false, |
| | | rowId: '', |
| | | changeStatus: false, |
| | | changeStatusTitle: '', |
| | | changeStatusTip: '', |
| | | queryForm: { |
| | | pageSize: 10, |
| | | pageNum: 1 |
| | | }, |
| | | total: 0 |
| | | } |
| | | }, |
| | | methods: { |
| | | handleAddProject() { |
| | | this.$router.push({ |
| | | path: '/projectList/addProject' |
| | | }) |
| | | }, |
| | | handleDel(row) { |
| | | this.rowId = row.id |
| | | this.showDelConfirm = true |
| | | }, |
| | | handleDelConfirm() { |
| | | this.showDelConfirm = false |
| | | this.msgsuccess('删除成功') |
| | | this.rowId = '' |
| | | this.getList() |
| | | }, |
| | | handleChangeStatus(row, status) { |
| | | this.rowId = row.id |
| | | this.changeStatusTitle = status == 1 ? '确认要封存这个项目组吗?' : '确认要解封该项目组吗?' |
| | | this.changeStatusTip = status == 1 ? '封存后项目组内人员看不到数据,审批人仍然可见数据。' : '解封后项目组内人员数据恢复。' |
| | | this.changeStatus = true |
| | | }, |
| | | handleChangeStatusConfirm() { |
| | | this.changeStatus = false |
| | | this.msgsuccess('操作成功') |
| | | this.rowId = '' |
| | | this.changeStatusTitle = '' |
| | | this.changeStatusTip = '' |
| | | this.getList() |
| | | }, |
| | | handleCurrentChange(page) { |
| | | this.queryForm.pageNum = page |
| | | this.getList() |
| | | }, |
| | | handleSizeChange(size) { |
| | | this.queryForm.pageSize = size |
| | | this.getList() |
| | | }, |
| | | getList() { |
| | | |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .list { |
| | | height: 100%; |
| | | } |
| | | </style> |