| | |
| | | <template> |
| | | <div class="system-select-container"> |
| | | <div class="user-info-bar"> |
| | | <div class="user-left"></div> |
| | | <h3 class="user-details">欢迎访问多体系建设信息化系统</h3> |
| | | <div class="avatar-container"> |
| | | <el-dropdown @command="handleCommand" class="right-menu-item hover-effect" trigger="click"> |
| | | <div class="avatar-wrapper" style="display: flex;align-items: center"> |
| | | <div class="multi-system-dashboard"> |
| | | <!-- 头部 --> |
| | | <header> |
| | | <div class="header-container"> |
| | | <div class="system-title">欢迎进入多体系建设信息化系统</div> |
| | | |
| | | <!-- <div class="admin-info" @click="handleAdminClick" ref="adminInfoRef">--> |
| | | <!-- <div class="admin-icon">--> |
| | | <!-- <i class="fas fa-user-cog"></i>--> |
| | | <!-- </div>--> |
| | | <!-- <div class="admin-details">--> |
| | | <!-- <div class="admin-name">admin</div>--> |
| | | <!-- <div class="admin-role">系统管理员</div>--> |
| | | <!-- </div>--> |
| | | <!-- </div>--> |
| | | |
| | | <div class="admin-info"> |
| | | <div class="admin-icon"> |
| | | <img src="../assets/images/avator.png" class="user-avatar" /> |
| | | <span style="font-size: 16px">{{userName}}({{userTypeName}})</span> |
| | | <el-icon><caret-bottom /></el-icon> |
| | | </div> |
| | | <template #dropdown> |
| | | <el-dropdown-menu> |
| | | <el-dropdown-item command="password"> |
| | | <span>修改密码</span> |
| | | </el-dropdown-item> |
| | | <el-dropdown-item divided command="logout"> |
| | | <span>退出登录</span> |
| | | </el-dropdown-item> |
| | | </el-dropdown-menu> |
| | | </template> |
| | | </el-dropdown> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 重新布局的系统选择区域 --> |
| | | <div class="systems-container"> |
| | | <div class="layout-container"> |
| | | <!-- 左侧列 --> |
| | | <div class="left-column"> |
| | | <!-- 通知公告 --> |
| | | <div class="module-card notice-module"> |
| | | <div class="module-header"> |
| | | <h3>通知公告</h3> |
| | | <span class="more-link" @click="toNoticeMng">更多 ></span> |
| | | <el-dropdown @command="handleCommand" class="right-menu-item hover-effect" trigger="click"> |
| | | <div class="admin-details"> |
| | | <div class="admin-name">{{userName}}</div> |
| | | <div class="admin-role">{{userTypeName}}</div> |
| | | </div> |
| | | <div class="notice-list"> |
| | | <div class="notice-item" v-for="item in noticeList" :key="item"> |
| | | <span class="notice-title" @click="openNoticeFile(item.filePath)">{{item.content}}</span> |
| | | <span class="notice-date">{{item.publishDate}}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 流程中心 --> |
| | | <div class="module-card process-module"> |
| | | <div class="module-header"> |
| | | <h3>流程中心</h3> |
| | | <!-- <span class="more-link">更多 ></span>--> |
| | | </div> |
| | | <div class="process-list" v-if="flowList && flowList.length>0"> |
| | | <div class="process-item" v-for="process in flowList" :key="process.id"> |
| | | <div class="process-info"> |
| | | <span class="process-name">{{process.title}}</span> |
| | | <span class="process-status" :class="{processing: process.type == 1,pending: process.type == 2,success: process.type == 3,normal: process.type == 4}"> |
| | | {{process.type == 1? '内审实施计划':process.type == 2? '培训计划':process.type == 3? '项目评审':'年度检定计划'}} |
| | | </span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="process-list" v-else> |
| | | <span style="color: #999;font-size: 16px">暂无流程</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 备忘录 --> |
| | | <div class="module-card memo-module"> |
| | | <div class="module-header"> |
| | | <h3>备忘录</h3> |
| | | <el-button @click="addMemo" type="primary">保存</el-button> |
| | | </div> |
| | | <div class="memo-content"> |
| | | <div class="memo-input"> |
| | | <el-input |
| | | v-model="memo.content" |
| | | placeholder="添加新的备忘录..." |
| | | type="textarea" |
| | | :autosize="{ minRows: 6, maxRows: 10}" |
| | | > |
| | | </el-input> |
| | | <div class="memo-time" v-if="memo.updateTime">{{memo.updateTime}}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 右侧列 --> |
| | | <div class="right-column"> |
| | | <!-- 快捷入口 --> |
| | | <div class="module-card quick-access-module"> |
| | | <div class="module-header"> |
| | | <h3>快捷入口</h3> |
| | | <div class="pagination-controls" v-if="platformList.length > 9"> |
| | | <el-button |
| | | :icon="ArrowLeft" |
| | | @click="prevPage" |
| | | size="small" |
| | | :disabled="currentPage === 0" |
| | | circle |
| | | /> |
| | | <span class="page-info">{{ currentPage + 1 }}/{{ totalPages }}</span> |
| | | <el-button |
| | | :icon="ArrowRight" |
| | | @click="nextPage" |
| | | size="small" |
| | | :disabled="currentPage === totalPages - 1" |
| | | circle |
| | | /> |
| | | </div> |
| | | </div> |
| | | <div class="systems-grid-container"> |
| | | <div class="systems-grid"> |
| | | <div |
| | | v-for="(system, index) in displayedSystems" |
| | | :key="system.id" |
| | | class="system-card" |
| | | @mouseenter="handleCardEnter($event, system.id)" |
| | | @mousemove="handleCardMove($event, system.id)" |
| | | @mouseleave="handleCardLeave(system.id)" |
| | | @click="enterSystem(system.platformAddress, getActualIndex(index))" |
| | | :style="getCardStyle(system.id)" |
| | | > |
| | | <div class="card-content"> |
| | | <div class="system-icon"> |
| | | <el-image v-if="getActualIndex(index) == 0" :src="system.platformPic"/> |
| | | <el-image v-else :src="picUrl + system.platformPic"/> |
| | | </div> |
| | | <h3>{{ system.platformName }}</h3> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 填充空白格子 --> |
| | | <div |
| | | v-if="showEmptyCard && displayedSystems.length < 9" |
| | | class="system-card empty-card" |
| | | @click="openAdd('add',{})" |
| | | > |
| | | <div class="card-content"> |
| | | <div class="system-icon"> |
| | | <el-icon><Plus /></el-icon> |
| | | </div> |
| | | <h3>新增平台</h3> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 日历 --> |
| | | <div class="module-card calendar-module"> |
| | | <div class="module-header"> |
| | | <h3>日历</h3> |
| | | </div> |
| | | <div class="calendar-header"> |
| | | <div class="lunar-info"> |
| | | <span class="lunar-date-full">{{ currentLunarDate }}</span> |
| | | <span class="lunar-year">{{ currentLunarYear }}</span> |
| | | </div> |
| | | <div class="current-date-info"> |
| | | <div class="solar-date-large">{{ currentSolarDate }}</div> |
| | | <div class="week-day">{{ currentWeekDay }}</div> |
| | | </div> |
| | | <div class="calendar-actions"> |
| | | <el-button-group> |
| | | <el-button :icon="ArrowLeft" @click="prevMonth" size="small" /> |
| | | <el-button @click="goToday" size="small">今天</el-button> |
| | | <el-button :icon="ArrowRight" @click="nextMonth" size="small" /> |
| | | </el-button-group> |
| | | </div> |
| | | </div> |
| | | <div class="calendar-content"> |
| | | <el-calendar v-model="currentDate" ref="calendarRef"> |
| | | <template #header> |
| | | <!-- 隐藏默认header --> |
| | | <div style="display: none;"></div> |
| | | </template> |
| | | <template #date-cell="{ data }"> |
| | | <div class="calendar-date" :class="{ 'is-today': isToday(data.day), 'is-current-month': isCurrentMonth(data.day) }"> |
| | | <div class="solar-date">{{ getSolarDate(data.day) }}</div> |
| | | <div class="lunar-date">{{ getLunarDate(data.day) }}</div> |
| | | <div v-if="hasEvent(data.day)" class="calendar-event-dot"></div> |
| | | </div> |
| | | </template> |
| | | </el-calendar> |
| | | </div> |
| | | </div> |
| | | <template #dropdown> |
| | | <el-dropdown-menu> |
| | | <el-dropdown-item command="password"> |
| | | <span>修改密码</span> |
| | | </el-dropdown-item> |
| | | <el-dropdown-item divided command="logout"> |
| | | <span>退出登录</span> |
| | | </el-dropdown-item> |
| | | </el-dropdown-menu> |
| | | </template> |
| | | </el-dropdown> |
| | | </div> |
| | | </div> |
| | | </header> |
| | | |
| | | <!-- 主体内容 --> |
| | | <div class="menu-container"> |
| | | <section class="welcome-section"> |
| | | <div class="welcome-decoration"></div> |
| | | <h1 class="welcome-title">多体系建设信息化系统</h1> |
| | | <p class="welcome-subtitle"> |
| | | 本系统集成多个国际与国内管理体系标准,为企业提供全面、协同、高效的信息化管理平台。通过统一门户实现质量管理、信息安全、职业健康安全、项目管理等多体系的无缝集成与协同运作,助力企业标准化、数字化、智能化发展。 |
| | | </p> |
| | | </section> |
| | | |
| | | <section class="systems-grid"> |
| | | <!-- 使用v-for循环渲染系统卡片 --> |
| | | <div |
| | | v-for="(system, index) in systems" |
| | | :key="system.id" |
| | | class="system-card" |
| | | :class="`card-${index + 1}`" |
| | | @click="handleSystemLinkClick(system.id)" |
| | | @mouseenter="handleCardHover(system, true)" |
| | | @mouseleave="handleCardHover(system, false)" |
| | | ref="cardRefs" |
| | | > |
| | | <div class="card-decoration"></div> |
| | | <div class="system-header"> |
| | | <div class="system-icon-container"> |
| | | <div class="system-icon" ref="iconRefs"> |
| | | <img :src="system.icon"/> |
| | | </div> |
| | | <h3 class="system-name">{{ system.name }}</h3> |
| | | </div> |
| | | </div> |
| | | <p class="system-desc">{{ system.description }}</p> |
| | | <a |
| | | href="#" |
| | | class="system-link" |
| | | @click.stop="handleSystemLinkClick(system.id)" |
| | | > |
| | | 进入系统 <el-icon><Right /></el-icon> |
| | | </a> |
| | | </div> |
| | | </section> |
| | | </div> |
| | | |
| | | <!-- 底部 --> |
| | | <footer> |
| | | <div class="footer-decoration"></div> |
| | | <div class="footer-container"> |
| | | <div class="copyright-section"> |
| | | <div class="copyright"> |
| | | © 2025 多体系建设信息化系统 | 中国科学院苏州纳米技术与纳米仿生研究所 版权所有 |
| | | </div> |
| | | <div class="version">版本号 V1.0.0</div> |
| | | </div> |
| | | </div> |
| | | </footer> |
| | | <user-dialog ref="reviewRef"></user-dialog> |
| | | <edit-dialog ref="dialogRef" @getList=getPlatformList></edit-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {ref, onMounted, computed, reactive, toRefs, watch} from 'vue' |
| | | import { useRouter, useRoute } from 'vue-router' |
| | | import { getToken, removeToken } from "@/utils/auth"; |
| | | import Cookies from "js-cookie"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import { Plus, ArrowLeft, ArrowRight } from '@element-plus/icons-vue' |
| | | import useUserStore from '@/store/modules/user' |
| | | import { ref, onMounted, nextTick } from 'vue' |
| | | import {ElMessage, ElMessageBox} from "element-plus"; |
| | | import {getToken, removeToken} from "@/utils/auth"; |
| | | import userDialog from '@/views/build/conpanyFunctionConsult/staffManage/staffRegister/components/staffDialog.vue' |
| | | import editDialog from '@/views/build/conpanyFunctionConsult/infoPlatform/components/editDialog.vue' |
| | | import menu1 from '@/assets/icons/menu1.png' |
| | | import menu2 from '@/assets/icons/menu2.png' |
| | | import menu3 from '@/assets/icons/menu3.png' |
| | | import menu4 from '@/assets/icons/menu4.png' |
| | | import menu5 from '@/assets/icons/menu5.png' |
| | | import menu6 from '@/assets/icons/menu6.png' |
| | | import shield from '@/assets/icons/shield-alt.png' |
| | | import lock from '@/assets/icons/lock.png' |
| | | import hat from '@/assets/icons/hard-hat.png' |
| | | import diagram from '@/assets/icons/project-diagram.png' |
| | | import clipboard from '@/assets/icons/clipboard-check.png' |
| | | import chartLine from '@/assets/icons/chart-line.png' |
| | | |
| | | // 引入农历库 |
| | | import * as lunarCalendar from 'lunar-calendar' |
| | | import {getIndexTitle, getMemoList, listNotice, updateMemo} from "@/api/system/notice"; |
| | | import {renderAsync} from "docx-preview"; |
| | | import {getInfoPlatforms} from "@/api/staffManage/staff"; |
| | | import {getCompany} from "@/api/onlineEducation/company"; |
| | | import Cookies from "js-cookie"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import {useRouter} from "vue-router"; |
| | | |
| | | // 响应式数据 |
| | | const systems = ref([ |
| | | { |
| | | id: 1, |
| | | name: '国军标9001C质量管理体系', |
| | | description: '基于GJB9001C-2017标准,专为军工产品研制、生产、维修和服务单位设计。', |
| | | icon: shield, |
| | | color: '#1a56db' |
| | | }, |
| | | { |
| | | id: 2, |
| | | name: 'ISO27001信息安全体系', |
| | | description: '遵循ISO/IEC 27001:2022标准,帮助企业建立、实施、维护和持续改进信息安全管理体系。', |
| | | icon: lock, |
| | | color: '#0d9488' |
| | | }, |
| | | { |
| | | id: 3, |
| | | name: 'ISO45001安全体系', |
| | | description: '基于ISO45001:2018标准,系统化管理职业健康安全风险,预防工伤和健康损害。', |
| | | icon: hat, |
| | | color: '#10b981' |
| | | }, |
| | | { |
| | | id: 4, |
| | | name: '项目管理控制', |
| | | description: '集成PMBOK和PRINCE2最佳实践的项目管理平台,支持项目全生命周期管理。', |
| | | icon: diagram, |
| | | color: '#7c3aed' |
| | | }, |
| | | { |
| | | id: 5, |
| | | name: '承制评价系统', |
| | | description: '针对承制单位资格管理的综合系统,确保承制单位持续满足军用产品承制要求。', |
| | | icon: clipboard, |
| | | color: '#f97316' |
| | | }, |
| | | { |
| | | id: 6, |
| | | name: '新体系评价系统', |
| | | description: '面向新兴管理体系标准的评估与导入平台,支持新标准的适应性评估和实施规划。', |
| | | icon: chartLine, |
| | | color: '#ef4444' |
| | | } |
| | | ]) |
| | | |
| | | // Refs |
| | | const adminInfoRef = ref(null) |
| | | const cardRefs = ref([]) |
| | | const iconRefs = ref([]) |
| | | const router = useRouter() |
| | | const route = useRoute(); |
| | | const reviewRef = ref(); |
| | | const userInfo = ref(); |
| | | const userName = ref('') |
| | | const userTypeName = ref('') |
| | | const cardStates = ref({}) |
| | | const currentDate = ref(new Date()) |
| | | const newMemo = ref('') |
| | | const calendarRef = ref() |
| | | const dialogRef = ref() |
| | | const userStore = useUserStore() |
| | | const state = reactive({ |
| | | noticeParams: { |
| | | pageNum: 1, |
| | | pageSize: 6, |
| | | companyId: null |
| | | }, |
| | | platformParams: { |
| | | pageNum: 1, |
| | | pageSize: 99, |
| | | companyId: null |
| | | }, |
| | | noticeList: [], |
| | | platformList: [], |
| | | picUrl: import.meta.env.VITE_APP_BASE_API + '/', |
| | | isAdmin: false, |
| | | companyList: [], |
| | | flowList: [], |
| | | memo: {} |
| | | }) |
| | | const { noticeParams,platformParams, noticeList,platformList,picUrl,isAdmin,companyList,flowList,memo } = toRefs(state) |
| | | // 组件挂载时获取用户信息和系统列表 |
| | | onMounted(async () => { |
| | | if(getToken()){ |
| | | userInfo.value = JSON.parse(Cookies.get('userInfo')) |
| | | userName.value = userInfo.value.username |
| | | userTypeName.value = userInfo.value.userType == 0 ? '系统管理员' : (userInfo.value.userType == 1 || userInfo.value.userType == 2 || userInfo.value.userType == 3) ? '企业用户' :userInfo.value.userType == 6 ? '企业管理员' :userInfo.value.userType == 4 ? '其他' : '学员' |
| | | } |
| | | if(userStore.roles.includes('admin')){ |
| | | state.noticeParams.companyId = null |
| | | state.platformParams.companyId = null |
| | | state.isAdmin = true |
| | | }else{ |
| | | state.noticeParams.companyId = userStore.companyId |
| | | state.platformParams.companyId = userStore.companyId |
| | | state.isAdmin = false |
| | | } |
| | | await getNoticeList() |
| | | await getPlatformList() |
| | | await getFlowList() |
| | | await getMemo() |
| | | state.platformList.forEach(system => { |
| | | cardStates.value[system.id] = { |
| | | mouseX: 0, |
| | | mouseY: 0, |
| | | width: 0, |
| | | height: 0, |
| | | hover: false |
| | | } |
| | | }) |
| | | }) |
| | | |
| | | const toNoticeMng = ()=>{ |
| | | router.push({ path: "/work/noticeMng" }); |
| | | } |
| | | |
| | | function getNoticeList() { |
| | | listNotice(state.noticeParams).then(res => { |
| | | state.noticeList = res.data.list |
| | | }) |
| | | } |
| | | const getCompanyList = async ()=>{ |
| | | const queryParams = { |
| | | pageNum: 1, |
| | | pageSize: 999 |
| | | } |
| | | const res = await getCompany(queryParams) |
| | | if (res.code == 200) { |
| | | state.companyList = res.data.list?res.data.list:[] |
| | | } else { |
| | | ElMessage.warning(res.message) |
| | | } |
| | | } |
| | | |
| | | const getPlatformList = async () => { |
| | | const res = await getInfoPlatforms(state.platformParams) |
| | | if(res.code == 200){ |
| | | const originPlatform = { |
| | | id: 0, |
| | | platformName: '国军标9001C质量管理体系', |
| | | platformPic: menu1 |
| | | } |
| | | state.platformList = [originPlatform, ...(Array.isArray(res.data) ? res.data : [])] |
| | | }else{ |
| | | ElMessage.warning(res.message) |
| | | } |
| | | } |
| | | const openAdd = async (type, value) => { |
| | | await getCompanyList() |
| | | dialogRef.value.openDialog(type, value, state.platformParams.companyId, state.isAdmin, state.companyList ); |
| | | } |
| | | |
| | | const getFlowList = async () => { |
| | | const res = await getIndexTitle({pageNum: 1,pageSize: 99}) |
| | | if(res.code == 200){ |
| | | state.flowList = Array.isArray(res.data) ? res.data : [] |
| | | }else{ |
| | | ElMessage.warning(res.message) |
| | | } |
| | | } |
| | | |
| | | const getMemo = async () => { |
| | | const res = await getMemoList() |
| | | if(res.code == 200){ |
| | | state.memo = res.data ? res.data : {} |
| | | console.log(state.memo,'memo') |
| | | }else{ |
| | | ElMessage.warning(res.message) |
| | | } |
| | | } |
| | | |
| | | // 分页相关 |
| | | const currentPage = ref(0) |
| | | const pageSize = 9 // 九宫格,每页9个 |
| | | |
| | | // 计算总页数 |
| | | const totalPages = computed(() => { |
| | | return Math.ceil(state.platformList.length / pageSize) |
| | | }) |
| | | |
| | | // 获取当前页显示的系统列表 |
| | | const displayedSystems = computed(() => { |
| | | const start = currentPage.value * pageSize |
| | | const end = start + pageSize |
| | | return state.platformList.slice(start, end) |
| | | }) |
| | | |
| | | // 是否显示敬请期待的卡片(只在最后一页且系统总数不是9的倍数时显示) |
| | | const showEmptyCard = computed(() => { |
| | | // 如果是最后一页,并且系统总数不是9的倍数,且当前页显示的系统数量小于9 |
| | | const isLastPage = currentPage.value === totalPages.value - 1 |
| | | const totalCount = state.platformList.length |
| | | const currentCount = displayedSystems.value.length |
| | | |
| | | return isLastPage && (totalCount % pageSize !== 0) && currentCount < 9 |
| | | }) |
| | | |
| | | // 获取实际在原始数组中的索引 |
| | | const getActualIndex = (displayIndex) => { |
| | | return currentPage.value * pageSize + displayIndex |
| | | } |
| | | |
| | | // 分页方法 |
| | | const prevPage = () => { |
| | | if (currentPage.value > 0) { |
| | | currentPage.value-- |
| | | } |
| | | } |
| | | |
| | | const nextPage = () => { |
| | | if (currentPage.value < totalPages.value - 1) { |
| | | currentPage.value++ |
| | | } |
| | | } |
| | | |
| | | // 重置分页(当系统列表变化时) |
| | | watch(state.platformList, () => { |
| | | currentPage.value = 0 |
| | | }) |
| | | |
| | | const openNoticeFile = async(path)=>{ |
| | | const ext = path.split('.').pop().toLowerCase(); |
| | | if (ext === 'doc' || ext === 'xls' || ext === 'xlsx') { |
| | | ElMessageBox.confirm('暂不支持线上预览文件,是否下载查看?', '提示', { confirmButtonText: '确认', cancelButtonText: '取消', type: 'warning' }).then(() => { |
| | | window.open(`${import.meta.env.VITE_APP_BASE_API}/${path}`, '_blank'); |
| | | }).catch(() => { |
| | | console.log('取消预览') |
| | | }); |
| | | return |
| | | } |
| | | if(ext === 'pdf'){ |
| | | window.open(`${import.meta.env.VITE_APP_BASE_API}/${path}`, '_blank') |
| | | return |
| | | } |
| | | try { |
| | | // 1. 获取文件 |
| | | const response = await fetch(import.meta.env.VITE_APP_BASE_API + '/' + path); |
| | | const arrayBuffer = await response.arrayBuffer(); |
| | | // 2. 创建新窗口 |
| | | const win = window.open('', '_blank') |
| | | win.document.write(` |
| | | <!DOCTYPE html> |
| | | <html> |
| | | <head> |
| | | <title>预览</title> |
| | | <style> |
| | | body { margin: 20px; font-family: Arial; } |
| | | .docx-container { width: 100%; height: 100%; } |
| | | </style> |
| | | </head> |
| | | <body> |
| | | <div id="container" class="docx-container"></div> |
| | | </body> |
| | | </html> |
| | | `); |
| | | // 3. 渲染 DOCX |
| | | await renderAsync(arrayBuffer, win.document.getElementById('container')); |
| | | } catch (error) { |
| | | console.error('预览失败:', error); |
| | | alert(`预览失败: ${error.message}`); |
| | | } |
| | | } |
| | | // 十二生肖数组 |
| | | const zodiacAnimals = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪'] |
| | | |
| | | // 获取生肖年份 |
| | | const getZodiacYear = (lunarYear) => { |
| | | // 农历年份计算生肖:年份减去4后除以12取余数 |
| | | // 因为鼠年对应4,牛年对应5,以此类推 |
| | | const index = (lunarYear - 4) % 12 |
| | | return index >= 0 ? zodiacAnimals[index] : zodiacAnimals[index + 12] |
| | | } |
| | | |
| | | // 计算当前日期信息 |
| | | const currentWeekDay = computed(() => { |
| | | const days = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'] |
| | | return days[currentDate.value.getDay()] |
| | | }) |
| | | |
| | | const currentSolarDate = computed(() => { |
| | | const date = currentDate.value |
| | | return `${date.getMonth() + 1}月${date.getDate()}日` |
| | | }) |
| | | |
| | | const currentLunarDate = computed(() => { |
| | | try { |
| | | const date = currentDate.value |
| | | const year = date.getFullYear() |
| | | const month = date.getMonth() + 1 |
| | | const day = date.getDate() |
| | | |
| | | const lunar = lunarCalendar.solarToLunar(year, month, day) |
| | | if (lunar && lunar.lunarMonthName && lunar.lunarDayName) { |
| | | return `${lunar.lunarMonthName}${lunar.lunarDayName}` |
| | | } |
| | | return '' |
| | | } catch (error) { |
| | | console.error('获取农历日期错误:', error) |
| | | return '' |
| | | } |
| | | }) |
| | | |
| | | const currentLunarYear = computed(() => { |
| | | try { |
| | | const date = currentDate.value |
| | | const year = date.getFullYear() |
| | | const month = date.getMonth() + 1 |
| | | const day = date.getDate() |
| | | |
| | | const lunar = lunarCalendar.solarToLunar(year, month, day) |
| | | if (lunar && lunar.GanZhiYear) { |
| | | const zodiac = getZodiacYear(year) |
| | | return `${lunar.GanZhiYear}年【${zodiac}年】` |
| | | } |
| | | return '' |
| | | } catch (error) { |
| | | console.error('获取农历年份错误:', error) |
| | | return '' |
| | | } |
| | | }) |
| | | |
| | | // 月份导航方法 |
| | | const prevMonth = () => { |
| | | const date = new Date(currentDate.value) |
| | | date.setMonth(date.getMonth() - 1) |
| | | currentDate.value = date |
| | | } |
| | | |
| | | const nextMonth = () => { |
| | | const date = new Date(currentDate.value) |
| | | date.setMonth(date.getMonth() + 1) |
| | | currentDate.value = date |
| | | } |
| | | |
| | | const goToday = () => { |
| | | currentDate.value = new Date() |
| | | } |
| | | |
| | | // 添加备忘录 |
| | | const addMemo = async () => { |
| | | if (state.memo.content) { |
| | | const data = { |
| | | id: state.memo.id || null, |
| | | companyId: state.noticeParams.companyId, |
| | | content: state.memo.content, |
| | | createById: userStore.id |
| | | } |
| | | const res = await updateMemo(data) |
| | | if(res.code == 200){ |
| | | ElMessage.success('保存成功') |
| | | await getMemo() |
| | | }else{ |
| | | ElMessage.warning(res.message) |
| | | } |
| | | newMemo.value = '' |
| | | } |
| | | } |
| | | |
| | | // 获取公历日期(去掉前导零) |
| | | const getSolarDate = (dateString) => { |
| | | const date = new Date(dateString) |
| | | return date.getDate() |
| | | } |
| | | |
| | | // 获取农历日期 |
| | | const getLunarDate = (dateString) => { |
| | | try { |
| | | const date = new Date(dateString) |
| | | const year = date.getFullYear() |
| | | const month = date.getMonth() + 1 |
| | | const day = date.getDate() |
| | | |
| | | // 使用农历库获取农历信息 |
| | | const lunar = lunarCalendar.solarToLunar(year, month, day) |
| | | |
| | | if (lunar && lunar.lunarDayName) { |
| | | // 如果是初一,显示月份,否则显示日期 |
| | | if (lunar.lunarDay === 1) { |
| | | return lunar.lunarMonthName + '月' |
| | | } else { |
| | | // 简化显示,只显示数字日期 |
| | | const lunarDay = lunar.lunarDayName.replace('初', '').replace('十', '') |
| | | return lunarDay |
| | | // 方法 |
| | | const handleAdminClick = () => { |
| | | if (adminInfoRef.value) { |
| | | adminInfoRef.value.style.transform = 'scale(0.94)' |
| | | setTimeout(() => { |
| | | if (adminInfoRef.value) { |
| | | adminInfoRef.value.style.transform = '' |
| | | } |
| | | } |
| | | |
| | | return '' |
| | | } catch (error) { |
| | | console.error('获取农历日期错误:', error) |
| | | return '' |
| | | } |
| | | } |
| | | |
| | | // 检查日期是否有事件 |
| | | const hasEvent = (date) => { |
| | | const eventDates = [] |
| | | return eventDates.includes(date) |
| | | } |
| | | |
| | | // 检查是否是今天 |
| | | const isToday = (dateString) => { |
| | | const today = new Date().toISOString().split('T')[0] |
| | | return dateString === today |
| | | } |
| | | |
| | | // 检查是否是当前月份 |
| | | const isCurrentMonth = (dateString) => { |
| | | const date = new Date(dateString) |
| | | const current = new Date(currentDate.value) |
| | | return date.getMonth() === current.getMonth() && date.getFullYear() === current.getFullYear() |
| | | } |
| | | |
| | | const handleCardEnter = (event, id) => { |
| | | const card = event.currentTarget |
| | | cardStates.value[id] = { |
| | | ...cardStates.value[id], |
| | | width: card.offsetWidth, |
| | | height: card.offsetHeight, |
| | | hover: true |
| | | } |
| | | } |
| | | |
| | | const handleCardMove = (event, id) => { |
| | | if (!cardStates.value[id]?.hover) return |
| | | |
| | | const card = event.currentTarget |
| | | const rect = card.getBoundingClientRect() |
| | | |
| | | cardStates.value[id].mouseX = event.clientX - rect.left - cardStates.value[id].width / 2 |
| | | cardStates.value[id].mouseY = event.clientY - rect.top - cardStates.value[id].height / 2 |
| | | } |
| | | |
| | | const handleCardLeave = (id) => { |
| | | cardStates.value[id].hover = false; |
| | | cardStates.value[id].mouseX = 0; |
| | | cardStates.value[id].mouseY = 0; |
| | | } |
| | | |
| | | const getCardStyle = (id) => { |
| | | const state = cardStates.value[id] || {} |
| | | const mousePX = state.mouseX / (state.width || 1) |
| | | const mousePY = state.mouseY / (state.height || 1) |
| | | |
| | | const rX = mousePX * 20 |
| | | const rY = mousePY * -20 |
| | | |
| | | const tX = mousePX * -20 |
| | | const tY = mousePY * -20 |
| | | |
| | | return { |
| | | transform: `rotateY(${rX}deg) rotateX(${rY}deg)`, |
| | | '--bg-transform': `translateX(${tX}px) translateY(${tY}px)` |
| | | alert('管理员菜单已打开') |
| | | }, 150) |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | const enterSystem = (address,index) => { |
| | | if(index == 0){ |
| | | router.push({ path: "/learn/standardSysTemp/sysStandardModule"}) |
| | | const handleSystemLinkClick = (systemId) => { |
| | | if(systemId == 1){ |
| | | router.push({ path: "/menuIndex"}); |
| | | }else{ |
| | | window.open(address) |
| | | // ElMessage.warning('系统正在开发中...') |
| | | ElMessage.warning('系统正在开发中...') |
| | | } |
| | | } |
| | | |
| | | function getInfo() { |
| | | reviewRef.value.openDialog('view',userInfo.value) |
| | | } |
| | | |
| | | function editPsd() { |
| | | reviewRef.value.openDialog('pwd',userInfo.value) |
| | | } |
| | | |
| | | // 退出登录 |
| | | function logout() { |
| | | ElMessageBox.confirm('确定注销并退出系统吗?', '提示', { |
| | | confirmButtonText: '确定', |
| | |
| | | }).then(() => { |
| | | removeToken() |
| | | location.href = '/homePage'; |
| | | |
| | | }).catch(() => { }); |
| | | } |
| | | |
| | | const handleCardHover = (system, isEnter) => { |
| | | const cardIndex = systems.value.findIndex(s => s.id === system.id) |
| | | if (cardIndex !== -1 && iconRefs.value[cardIndex]) { |
| | | iconRefs.value[cardIndex].style.transform = isEnter ? 'scale(1.04)' : 'scale(1)' |
| | | iconRefs.value[cardIndex].style.transition = 'transform 0.3s ease' |
| | | } |
| | | } |
| | | |
| | | // 页面加载后计算高度并调整 |
| | | const adjustLayout = () => { |
| | | const bodyHeight = document.body.scrollHeight |
| | | const windowHeight = window.innerHeight |
| | | |
| | | // 获取DOM元素 |
| | | const welcomeSection = document.querySelector('.welcome-section') |
| | | const systemsGrid = document.querySelector('.systems-grid') |
| | | const footer = document.querySelector('footer') |
| | | |
| | | // 如果内容超过屏幕高度,进行微调 |
| | | if (bodyHeight > windowHeight) { |
| | | if (welcomeSection) welcomeSection.style.marginBottom = '1.5rem' |
| | | if (systemsGrid) { |
| | | systemsGrid.style.gap = '1.2rem' |
| | | systemsGrid.style.marginBottom = '2rem' |
| | | } |
| | | if (footer) footer.style.padding = '1.2rem 1.8rem' |
| | | if (welcomeSection) welcomeSection.style.padding = '1.8rem 1.5rem' |
| | | } |
| | | } |
| | | |
| | | // 生命周期钩子 |
| | | onMounted(() => { |
| | | if(getToken()){ |
| | | userInfo.value = JSON.parse(Cookies.get('userInfo')) |
| | | userName.value = userInfo.value.username |
| | | userTypeName.value = userInfo.value.userType == 0 ? '系统管理员' : (userInfo.value.userType == 1 || userInfo.value.userType == 2 || userInfo.value.userType == 3) ? '企业用户' :userInfo.value.userType == 6 ? '企业管理员' :userInfo.value.userType == 4 ? '其他' : '学员' |
| | | } |
| | | |
| | | const userStore = useUserStore() |
| | | userStore.roles = [] |
| | | // 等待DOM更新完成后执行 |
| | | nextTick(() => { |
| | | adjustLayout() |
| | | |
| | | // 渐显效果 |
| | | document.body.style.opacity = '0' |
| | | document.body.style.transition = 'opacity 0.5s ease' |
| | | |
| | | setTimeout(() => { |
| | | document.body.style.opacity = '1' |
| | | }, 100) |
| | | }) |
| | | |
| | | // 监听窗口大小变化 |
| | | window.addEventListener('resize', adjustLayout) |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .system-select-container { |
| | | <style lang="scss" scoped> |
| | | body { |
| | | background-color: #f8fafc; |
| | | color: #1f2937; |
| | | min-height: 100vh; |
| | | display: flex; |
| | | flex-direction: column; |
| | | overflow-y: auto; |
| | | } |
| | | |
| | | .multi-system-dashboard{ |
| | | width: 100%; |
| | | height: 100vh; |
| | | display: flex; |
| | | flex-direction: column; |
| | | background-color: #f5f7fa; |
| | | align-items: center; |
| | | |
| | | .menu-container { |
| | | flex: 1; |
| | | overflow-y: auto; |
| | | max-width: 1600px; |
| | | width: 100%; |
| | | margin: 1rem auto; |
| | | padding: 0 1.8rem; |
| | | scrollbar-width: none; /* Firefox */ |
| | | -ms-overflow-style: none; /* IE and Edge */ |
| | | } |
| | | } |
| | | |
| | | .user-info-bar { |
| | | /* 头部样式 - 更加紧凑 */ |
| | | header { |
| | | width: 100%; |
| | | background: linear-gradient(135deg, #1e3a8a 0%, #3b82f6 100%); |
| | | color: white; |
| | | padding: 0.8rem 1.8rem; |
| | | box-shadow: 0 3px 10px rgba(30, 58, 138, 0.12); |
| | | } |
| | | |
| | | .header-container { |
| | | max-width: 1600px; |
| | | margin: 0 auto; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | |
| | | .system-title { |
| | | font-size: 1.5rem; |
| | | font-weight: 700; |
| | | letter-spacing: 0.2px; |
| | | } |
| | | |
| | | .admin-info { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 10px; |
| | | background: rgba(255, 255, 255, 0.15); |
| | | padding: 8px 16px; |
| | | border-radius: 10px; |
| | | backdrop-filter: blur(4px); |
| | | border: 1px solid rgba(255, 255, 255, 0.2); |
| | | transition: all 0.3s ease; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .admin-info:hover { |
| | | background: rgba(255, 255, 255, 0.25); |
| | | } |
| | | |
| | | .admin-icon { |
| | | background: linear-gradient(135deg, #f59e0b, #f97316); |
| | | width: 36px; |
| | | height: 36px; |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | |
| | | img{ |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | } |
| | | |
| | | .admin-details { |
| | | display: flex; |
| | | flex-direction: column; |
| | | color: #fff; |
| | | } |
| | | |
| | | .admin-name { |
| | | font-weight: 600; |
| | | font-size: 0.95rem; |
| | | margin-bottom: 0.2rem; |
| | | } |
| | | |
| | | .admin-role { |
| | | font-size: 0.75rem; |
| | | opacity: 0.9; |
| | | } |
| | | |
| | | |
| | | .welcome-section { |
| | | position: relative; |
| | | text-align: center; |
| | | margin-bottom: 1rem; |
| | | padding: 2rem; |
| | | background: white; |
| | | border-radius: 16px; |
| | | box-shadow: 0 5px 15px -4px rgba(0, 0, 0, 0.07); |
| | | overflow: hidden; |
| | | border: 1px solid rgba(226, 232, 240, 0.8); |
| | | } |
| | | |
| | | .welcome-decoration { |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | width: 100%; |
| | | height: 3px; |
| | | background: linear-gradient(90deg, |
| | | #1a56db, |
| | | #0d9488, |
| | | #7c3aed, |
| | | #f97316 |
| | | ); |
| | | } |
| | | |
| | | .welcome-title { |
| | | font-size: 1.5rem; |
| | | margin: 0 0 0.8rem; |
| | | font-weight: 800; |
| | | color: #1a56db; |
| | | } |
| | | |
| | | .welcome-subtitle { |
| | | font-size: 0.95rem; |
| | | color: #4b5563; |
| | | max-width: 900px; |
| | | margin: 0 auto; |
| | | line-height: 1.5; |
| | | font-weight: 400; |
| | | } |
| | | |
| | | /* 系统入口网格 - 更加紧凑 */ |
| | | .systems-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(3, 1fr); |
| | | gap: 1rem; |
| | | margin-bottom: 2.5rem; |
| | | width: 100%; |
| | | } |
| | | |
| | | /* 为每个系统卡片分配不同的颜色主题 */ |
| | | .system-card.card-1 { --card-color: #1a56db; } |
| | | .system-card.card-2 { --card-color: #0d9488; } |
| | | .system-card.card-3 { --card-color: #10b981; } |
| | | .system-card.card-4 { --card-color: #7c3aed; } |
| | | .system-card.card-5 { --card-color: #f97316; } |
| | | .system-card.card-6 { --card-color: #ef4444; } |
| | | |
| | | .system-card { |
| | | background: white; |
| | | border-radius: 14px; |
| | | overflow: hidden; |
| | | box-shadow: 0 5px 15px -4px rgba(0, 0, 0, 0.07); |
| | | transition: all 0.3s ease; |
| | | cursor: pointer; |
| | | display: flex; |
| | | flex-direction: column; |
| | | height: 100%; |
| | | position: relative; |
| | | width: 100%; |
| | | } |
| | | |
| | | .system-card:hover { |
| | | transform: translateY(-4px); |
| | | box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .card-decoration { |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | width: 100%; |
| | | height: 3px; |
| | | background: linear-gradient(90deg, |
| | | var(--card-color), |
| | | color-mix(in srgb, var(--card-color) 70%, white) |
| | | ); |
| | | } |
| | | |
| | | .system-header { |
| | | padding: 0.8rem 1.5rem; |
| | | position: relative; |
| | | } |
| | | |
| | | .system-icon-container { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 14px; |
| | | |
| | | } |
| | | |
| | | .system-icon { |
| | | background: linear-gradient(135deg, var(--card-color), color-mix(in srgb, var(--card-color) 80%, white)); |
| | | width: 48px; |
| | | height: 48px; |
| | | border-radius: 12px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | color: white; |
| | | img{ |
| | | width: 24px; |
| | | height: 24px; |
| | | } |
| | | } |
| | | |
| | | .system-name { |
| | | font-size: 1.25rem; |
| | | font-weight: 700; |
| | | color: var(--card-color); |
| | | flex-grow: 1; |
| | | line-height: 1.25; |
| | | } |
| | | |
| | | .system-desc { |
| | | padding: 0 1.5rem 1.2rem; |
| | | flex-grow: 1; |
| | | color: #4b5563; |
| | | line-height: 1.5; |
| | | font-size: 0.9rem; |
| | | margin: 0; |
| | | } |
| | | |
| | | .system-link { |
| | | display: block; |
| | | padding: 0.8rem; |
| | | text-align: center; |
| | | background: linear-gradient(90deg, |
| | | var(--card-color), |
| | | color-mix(in srgb, var(--card-color) 80%, white) |
| | | ); |
| | | color: white; |
| | | font-weight: 600; |
| | | text-decoration: none; |
| | | transition: all 0.3s ease; |
| | | font-size: 0.95rem; |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | gap: 7px; |
| | | } |
| | | |
| | | .system-link:hover { |
| | | background: linear-gradient(90deg, |
| | | color-mix(in srgb, var(--card-color) 90%, black), |
| | | var(--card-color) |
| | | ); |
| | | } |
| | | |
| | | /* 底部样式 - 更加紧凑 */ |
| | | footer { |
| | | width: 100%; |
| | | height: 100px; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding: 10px 20px; |
| | | background-color: #ffffff; |
| | | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); |
| | | |
| | | .user-left{ |
| | | width: 20%; |
| | | } |
| | | |
| | | .user-details{ |
| | | width: 60%; |
| | | margin: 0; |
| | | color: #333; |
| | | text-align: center; |
| | | font-size: 28px; |
| | | letter-spacing: 2px; |
| | | } |
| | | |
| | | .avatar-container { |
| | | width: 20%; |
| | | display: flex; |
| | | justify-content: center; |
| | | |
| | | .avatar-wrapper { |
| | | position: relative; |
| | | |
| | | .user-avatar { |
| | | cursor: pointer; |
| | | width: 40px; |
| | | height: 40px; |
| | | border-radius: 10px; |
| | | margin-right: 15px; |
| | | } |
| | | |
| | | i { |
| | | cursor: pointer; |
| | | position: absolute; |
| | | right: -20px; |
| | | font-size: 12px; |
| | | } |
| | | } |
| | | } |
| | | background: linear-gradient(90deg, #111827 0%, #1f2937 100%); |
| | | color: white; |
| | | padding: 1.5rem 1.8rem; |
| | | margin-top: auto; |
| | | position: relative; |
| | | } |
| | | |
| | | .systems-container { |
| | | flex: 1; |
| | | padding: 20px; |
| | | overflow-y: auto; |
| | | .footer-decoration { |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | width: 100%; |
| | | height: 2px; |
| | | background: linear-gradient(90deg, |
| | | #1a56db, |
| | | #0d9488, |
| | | #7c3aed |
| | | ); |
| | | } |
| | | |
| | | .layout-container { |
| | | display: flex; |
| | | gap: 20px; |
| | | width: 100%; |
| | | height: 100%; |
| | | max-width: none; /* 移除最大宽度限制 */ |
| | | margin: 0; /* 移除居中margin */ |
| | | } |
| | | |
| | | // 左侧列 - 宽度占比2 |
| | | .left-column { |
| | | flex: 2; |
| | | .footer-container { |
| | | max-width: 1600px; |
| | | margin: 0 auto; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 20px; |
| | | min-width: 0; /* 防止内容溢出 */ |
| | | } |
| | | |
| | | // 右侧列 - 宽度占比1 |
| | | .right-column { |
| | | flex: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 20px; |
| | | min-width: 0; /* 防止内容溢出 */ |
| | | min-width: 400px; /* 设置最小宽度避免过窄 */ |
| | | } |
| | | |
| | | // 通用模块卡片样式 |
| | | .module-card { |
| | | background: #ffffff; |
| | | border-radius: 8px; |
| | | padding: 20px; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
| | | transition: box-shadow 0.3s ease; |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | |
| | | &:hover { |
| | | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); |
| | | } |
| | | } |
| | | |
| | | .module-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 16px; |
| | | padding-bottom: 12px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | flex-shrink: 0; /* 防止header被压缩 */ |
| | | gap: 0.8rem; |
| | | } |
| | | |
| | | h3 { |
| | | margin: 0; |
| | | color: #333; |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | } |
| | | .copyright-section { |
| | | text-align: center; |
| | | width: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 0.4rem; |
| | | } |
| | | |
| | | .more-link { |
| | | color: #409eff; |
| | | font-size: 14px; |
| | | cursor: pointer; |
| | | .copyright { |
| | | font-size: 0.9rem; |
| | | color: #d1d5db; |
| | | line-height: 1.3; |
| | | } |
| | | |
| | | &:hover { |
| | | color: #337ecc; |
| | | } |
| | | .version { |
| | | display: inline-block; |
| | | background: rgba(59, 130, 246, 0.2); |
| | | color: #60a5fa; |
| | | padding: 4px 12px; |
| | | border-radius: 16px; |
| | | font-size: 0.85rem; |
| | | font-weight: 600; |
| | | letter-spacing: 0.2px; |
| | | border: 1px solid rgba(96, 165, 250, 0.3); |
| | | } |
| | | |
| | | /* 响应式调整 */ |
| | | @media (max-width: 1300px) { |
| | | .systems-grid { |
| | | grid-template-columns: repeat(2, 1fr); |
| | | } |
| | | } |
| | | |
| | | // 通知公告模块 |
| | | .notice-module { |
| | | .notice-list { |
| | | flex: 1; |
| | | overflow-y: auto; |
| | | |
| | | .notice-item { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 12px 0; |
| | | border-bottom: 1px solid #f5f5f5; |
| | | |
| | | &:last-child { |
| | | border-bottom: none; |
| | | } |
| | | |
| | | .notice-title { |
| | | color: #333; |
| | | font-size: 16px; |
| | | cursor: pointer; |
| | | flex: 1; |
| | | margin-right: 12px; |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | |
| | | &:hover { |
| | | color: #409eff; |
| | | } |
| | | } |
| | | |
| | | .notice-date { |
| | | color: #999; |
| | | font-size: 14px; |
| | | flex-shrink: 0; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 流程中心模块 |
| | | .process-module { |
| | | .process-list { |
| | | flex: 1; |
| | | overflow-y: auto; |
| | | |
| | | .process-item { |
| | | margin-bottom: 16px; |
| | | |
| | | .process-info { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 8px; |
| | | |
| | | .process-name { |
| | | color: #333; |
| | | font-size: 14px; |
| | | flex: 1; |
| | | margin-right: 12px; |
| | | } |
| | | |
| | | .process-status { |
| | | font-size: 12px; |
| | | padding: 2px 8px; |
| | | border-radius: 4px; |
| | | flex-shrink: 0; |
| | | |
| | | &.processing { |
| | | background: #e6f7ff; |
| | | color: #1890ff; |
| | | } |
| | | |
| | | &.pending { |
| | | background: #fff7e6; |
| | | color: #fa8c16; |
| | | } |
| | | |
| | | &.success { |
| | | background: #f6ffed; |
| | | color: #52c41a; |
| | | } |
| | | |
| | | &.normal { |
| | | background: #ccc; |
| | | color: #333; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 备忘录模块 |
| | | .memo-module { |
| | | .memo-content { |
| | | flex: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | | |
| | | .memo-input { |
| | | flex: 1; |
| | | |
| | | .memo-time{ |
| | | color: #999; |
| | | font-size: 12px; |
| | | text-align: right; |
| | | margin-top: 10px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 快捷入口模块 |
| | | .quick-access-module { |
| | | .module-header { |
| | | .pagination-controls { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | |
| | | .page-info { |
| | | font-size: 12px; |
| | | color: #666; |
| | | min-width: 40px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .el-button { |
| | | width: 28px; |
| | | height: 28px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | } |
| | | @media (max-width: 900px) { |
| | | header { |
| | | padding: 0.7rem 1.5rem; |
| | | } |
| | | |
| | | .systems-grid-container { |
| | | flex: 1; |
| | | overflow: hidden; |
| | | .system-title { |
| | | font-size: 1.4rem; |
| | | } |
| | | |
| | | .menu-container { |
| | | padding: 0 1.5rem; |
| | | margin: 0.8rem auto; |
| | | } |
| | | |
| | | .welcome-section { |
| | | padding: 1.5rem; |
| | | margin-bottom: 0.8rem; |
| | | } |
| | | |
| | | .welcome-title { |
| | | font-size: 1.3rem; |
| | | } |
| | | |
| | | .welcome-subtitle { |
| | | font-size: 0.9rem; |
| | | } |
| | | |
| | | .systems-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(3, 1fr); |
| | | grid-template-rows: repeat(3, 1fr); |
| | | gap: 16px; |
| | | height: 100%; |
| | | min-height: 400px; // 确保有足够的高度显示九宫格 |
| | | perspective: 1000px; |
| | | gap: 1rem; |
| | | margin-bottom: 2rem; |
| | | } |
| | | |
| | | .system-card { |
| | | position: relative; |
| | | background-color: #ffffff; |
| | | border-radius: 4px; |
| | | transition: transform 1s cubic-bezier(0.23, 1, 0.32, 1), |
| | | box-shadow 0.5s cubic-bezier(0.23, 1, 0.32, 1); |
| | | transform-style: preserve-3d; |
| | | cursor: pointer; |
| | | overflow: hidden; |
| | | min-height: 100px; // 确保卡片有最小高度 |
| | | |
| | | // 空白卡片样式 |
| | | &.empty-card { |
| | | opacity: 0.6; |
| | | |
| | | .system-icon { |
| | | color: #ccc; |
| | | } |
| | | |
| | | h3 { |
| | | color: #999; |
| | | } |
| | | |
| | | &:hover { |
| | | transform: none; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
| | | |
| | | &::after { |
| | | border-color: transparent; |
| | | } |
| | | |
| | | &::before { |
| | | background: #fff; |
| | | } |
| | | } |
| | | } |
| | | |
| | | &:hover{ |
| | | border-radius: 8px; |
| | | } |
| | | |
| | | &::after { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 4px; |
| | | left: 4px; |
| | | right: 4px; |
| | | bottom: 4px; |
| | | border-radius: 4px; |
| | | border: 1px solid transparent; |
| | | transition: border-color 0.3s ease; |
| | | pointer-events: none; |
| | | z-index: 3; |
| | | } |
| | | |
| | | &::before { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | border-radius: 4px; |
| | | background: #fff; |
| | | transform: var(--bg-transform, translateX(0) translateY(0)); |
| | | transition: transform 0.5s cubic-bezier(0.23, 1, 0.32, 1); |
| | | z-index: 1; |
| | | } |
| | | |
| | | &:hover::after { |
| | | border-color: rgba(37,99,235,1); |
| | | border-radius: 6px; |
| | | box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.5); |
| | | } |
| | | |
| | | &:hover::before { |
| | | border-radius: 8px; |
| | | background: linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(20,20,20,0.05) 100%); |
| | | } |
| | | .system-header { |
| | | padding: 0.6rem 1.3rem; |
| | | } |
| | | |
| | | .system-card:hover { |
| | | box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15), |
| | | 0 0 0 1px rgba(255, 255, 255, 0.5) inset; |
| | | .system-desc { |
| | | padding: 0 1.3rem 1rem; |
| | | font-size: 0.85rem; |
| | | } |
| | | |
| | | .card-content { |
| | | position: relative; |
| | | height: 100%; |
| | | display: flex; |
| | | .system-link { |
| | | padding: 0.7rem; |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 700px) { |
| | | .systems-grid { |
| | | grid-template-columns: 1fr; |
| | | } |
| | | |
| | | .header-container { |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding: 12px; |
| | | z-index: 2; |
| | | transform-style: preserve-3d; |
| | | gap: 0.8rem; |
| | | text-align: center; |
| | | } |
| | | |
| | | .admin-info { |
| | | padding: 7px 14px; |
| | | } |
| | | |
| | | .welcome-title { |
| | | font-size: 1.2rem; |
| | | } |
| | | |
| | | .system-name { |
| | | font-size: 1.2rem; |
| | | } |
| | | |
| | | footer { |
| | | padding: 1.2rem 1.5rem; |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 480px) { |
| | | .menu-container { |
| | | padding: 0 1.2rem; |
| | | } |
| | | |
| | | .welcome-section { |
| | | padding: 1rem 1.2rem; |
| | | } |
| | | |
| | | .welcome-title { |
| | | font-size: 1rem; |
| | | } |
| | | |
| | | .system-header { |
| | | padding: 0.5rem 1.2rem; |
| | | } |
| | | |
| | | .system-icon { |
| | | margin-bottom: 8px; |
| | | |
| | | .el-image { |
| | | width: 40px; |
| | | height: 40px; |
| | | transition: transform 0.5s; |
| | | } |
| | | |
| | | .el-icon { |
| | | font-size: 40px; |
| | | color: #ccc; |
| | | } |
| | | width: 42px; |
| | | height: 42px; |
| | | } |
| | | |
| | | .system-card:hover .system-icon img { |
| | | transform: scale(1.2); |
| | | .system-name { |
| | | font-size: 1.15rem; |
| | | } |
| | | |
| | | .system-card h3 { |
| | | margin: 0; |
| | | color: #333; |
| | | font-size: 14px; |
| | | text-align: center; |
| | | transition: transform 0.3s; |
| | | line-height: 1.2; |
| | | font-weight: 500; |
| | | .copyright { |
| | | font-size: 0.85rem; |
| | | } |
| | | |
| | | .system-card:hover h3 { |
| | | transform: translateZ(10px); |
| | | } |
| | | } |
| | | // 日历模块 |
| | | .calendar-module { |
| | | .calendar-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding-bottom: 16px; |
| | | |
| | | .lunar-info { |
| | | width: 33.33%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | font-size: 16px; |
| | | .lunar-date-full { |
| | | color: #e6a23c; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .lunar-year { |
| | | color: #999; |
| | | } |
| | | } |
| | | |
| | | .current-date-info { |
| | | width: 33.33%; |
| | | font-size: 16px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | .solar-date-large { |
| | | color: #333; |
| | | font-weight: 600; |
| | | } |
| | | .week-day { |
| | | color: #666; |
| | | margin-bottom: 4px; |
| | | font-weight: 500; |
| | | } |
| | | } |
| | | |
| | | .calendar-actions { |
| | | display: flex; |
| | | justify-content: right; |
| | | width: 33.33%; |
| | | |
| | | .el-button-group { |
| | | display: flex; |
| | | gap: 1px; |
| | | |
| | | .el-button { |
| | | padding: 6px 12px; |
| | | border-radius: 4px; |
| | | |
| | | &:first-child { |
| | | border-top-right-radius: 0; |
| | | border-bottom-right-radius: 0; |
| | | } |
| | | |
| | | &:last-child { |
| | | border-top-left-radius: 0; |
| | | border-bottom-left-radius: 0; |
| | | } |
| | | |
| | | &:not(:first-child):not(:last-child) { |
| | | border-radius: 0; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .calendar-content { |
| | | flex: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | | |
| | | :deep(.el-calendar) { |
| | | border: none; |
| | | flex: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | | |
| | | .el-calendar__header { |
| | | padding: 0; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .el-calendar__body { |
| | | flex: 1; |
| | | } |
| | | |
| | | .el-calendar-table { |
| | | height: 100%; |
| | | |
| | | .el-calendar-day { |
| | | height: 60px; |
| | | padding: 2px; |
| | | text-align: center; |
| | | } |
| | | |
| | | td.is-selected { |
| | | background-color: transparent; |
| | | } |
| | | |
| | | .el-calendar-day:hover { |
| | | background-color: #f5f7fa; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .calendar-date { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: flex-start; |
| | | height: 100%; |
| | | position: relative; |
| | | padding-top: 4px; |
| | | |
| | | .solar-date { |
| | | font-size: 14px; |
| | | font-weight: 500; |
| | | color: #333; |
| | | margin-bottom: 2px; |
| | | } |
| | | |
| | | .lunar-date { |
| | | font-size: 10px; |
| | | color: #999; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .calendar-event-dot { |
| | | width: 4px; |
| | | height: 4px; |
| | | background: #409eff; |
| | | border-radius: 50%; |
| | | margin-bottom: 2px; |
| | | } |
| | | |
| | | .today-indicator { |
| | | position: absolute; |
| | | top: 2px; |
| | | right: 2px; |
| | | width: 16px; |
| | | height: 16px; |
| | | background: #409eff; |
| | | color: white; |
| | | border-radius: 50%; |
| | | font-size: 10px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | line-height: 1; |
| | | } |
| | | } |
| | | |
| | | // 今天日期的样式 |
| | | .calendar-date.is-today { |
| | | background-color: #ecf5ff; |
| | | .solar-date { |
| | | color: #409eff; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | &::before { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 2px; |
| | | left: 50%; |
| | | transform: translateX(-50%); |
| | | width: 24px; |
| | | height: 24px; |
| | | background: #409eff; |
| | | border-radius: 50%; |
| | | z-index: -1; |
| | | opacity: 0.1; |
| | | } |
| | | } |
| | | |
| | | .calendar-legend { |
| | | display: flex; |
| | | justify-content: center; |
| | | gap: 16px; |
| | | margin-top: 12px; |
| | | padding-top: 12px; |
| | | border-top: 1px solid #f0f0f0; |
| | | flex-shrink: 0; |
| | | |
| | | .legend-item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 6px; |
| | | |
| | | .legend-dot { |
| | | width: 8px; |
| | | height: 8px; |
| | | border-radius: 50%; |
| | | } |
| | | |
| | | .event-dot { |
| | | background: #409eff; |
| | | } |
| | | |
| | | .today-dot { |
| | | background: #409eff; |
| | | } |
| | | |
| | | span { |
| | | font-size: 12px; |
| | | color: #666; |
| | | } |
| | | } |
| | | } |
| | | .version { |
| | | font-size: 0.8rem; |
| | | } |
| | | } |
| | | |
| | | // 响应式设计 |
| | | @media (max-width: 1200px) { |
| | | .layout-container { |
| | | flex-direction: column; |
| | | /* 确保在一个屏幕内显示 */ |
| | | @media (min-height: 900px) { |
| | | .menu-container { |
| | | margin: 1rem auto; |
| | | } |
| | | |
| | | .left-column, |
| | | .right-column { |
| | | flex: 1; |
| | | min-width: auto; |
| | | } |
| | | } |
| | | |
| | | // 超大屏幕优化 |
| | | @media (min-width: 1920px) { |
| | | .systems-container { |
| | | padding: 30px 40px; |
| | | .welcome-section { |
| | | margin-bottom: 1rem; |
| | | padding: 2rem; |
| | | } |
| | | |
| | | .layout-container { |
| | | gap: 30px; |
| | | } |
| | | |
| | | .module-card { |
| | | padding: 25px; |
| | | } |
| | | |
| | | // 在超大屏幕上可以显示3列的系统卡片 |
| | | .quick-access-module .systems-grid { |
| | | grid-template-columns: repeat(3, 1fr); |
| | | .systems-grid { |
| | | gap: 1rem; |
| | | margin-bottom: 3rem; |
| | | } |
| | | } |
| | | </style> |