董国庆
2025-05-29 dc4d15425d544301129eaf4410f18d6c11bed8a5
菌种库,中台样式和角色权限
12个文件已添加
7个文件已修改
671 ■■■■■ 已修改文件
culture/package.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/assets/login/cardBg.png 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/assets/login/img1.png 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/assets/login/img2.png 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/assets/login/img3.png 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/assets/login/img4.png 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/assets/login/mi.png 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/assets/login/midBg.png 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/assets/login/notice.png 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/assets/login/rili.png 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/assets/login/time.png 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/router/index.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/middleground/index.vue 577 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/middleground/service.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/system/role/detail.vue 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/system/role/edit.vue 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/system/role/index.vue 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/system/role/service.js 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
laboratory/src/views/system/role/index.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/package.json
@@ -2,7 +2,7 @@
  "name": "appointment",
  "version": "0.1.0",
  "private": true,
  "scripts": {
  "scripts": {
    "serve:dev": "cross-env VUE_APP_ENV=development vue-cli-service serve --port 8087",
    "serve:prod": "cross-env VUE_APP_ENV=production vue-cli-service serve",
    "build:dev": "cross-env VUE_APP_ENV=development vue-cli-service build",
culture/src/assets/login/cardBg.png
culture/src/assets/login/img1.png
culture/src/assets/login/img2.png
culture/src/assets/login/img3.png
culture/src/assets/login/img4.png
culture/src/assets/login/mi.png
culture/src/assets/login/midBg.png
culture/src/assets/login/notice.png
culture/src/assets/login/rili.png
culture/src/assets/login/time.png
culture/src/router/index.js
@@ -38,6 +38,15 @@
    component: () => import("../views/login"),
  },
  {
    path: "/middleground",
    meta: {
        title: "中台",
        middleground: true,
        // hide: true,
    },
    component: () => import("../views/middleground"),
},
  {
    path: "/projectList",
    meta: {
      title: "项目组管理",
culture/src/views/middleground/index.vue
New file
@@ -0,0 +1,577 @@
<template>
  <div class="login-page">
    <div class="top-nav">
      <HeaderNav class="header-main" :logo="true" />
    </div>
    <div class="middleground" :class="windowWidth<1240 ? 'column' : ''">
      <!-- 左侧模块区域 -->
      <div class="left-modules">
        <!-- 这里将放置四个模块 -->
        <div class="module-item">
          <!-- 模块内容,例如图标和文字 -->
          <div class="module-icon"></div>
          <div class="module-text">实验室运行模块</div>
        </div>
        <div class="module-item">
          <div class="module-icon"></div>
          <div class="module-text">专业报告库</div>
        </div>
        <div class="module-item">
          <div class="module-icon"></div>
          <div class="module-text">化验师QA专题报告库</div>
        </div>
        <div class="module-item">
          <div class="module-icon"></div>
          <div class="module-text">评定模块</div>
        </div>
      </div>
      <!-- 右侧日历和待办事项区域 -->
      <div class="right-content">
        <!-- 日历 -->
        <div class="calendar-section">
          <!-- <h3>日历</h3> -->
          <el-calendar v-model="date" />
        </div>
        <!-- 待办事项 -->
        <div class="todo-list-section">
          <div class="title">待办事项</div>
          <!-- 待办事项列表将放置在这里 -->
          <div class="todo-list">
            <div class="todo-item" v-for="i in 6" :key="i">
              <div class="todo-details">
                <div class="notice-card">
                  <div class="todo-icon">
                  </div>
                  <div class="red-notice"></div>
                </div>
                <span class="todo-title">您有 [1] 条 【项目课题方案】 等待审批</span>
              </div>
              <div class="todo-meta">
                <div class="me"></div>
                <span class="todo-submitter">提交人: 王晓晓</span>
                <div class="time"></div>
                <span class="todo-submitter">2023.12.10 08:00</span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import { loginReq } from './service'
import HeaderNav from '../../layouts/components/HeaderNav.vue'
import { mapState } from 'vuex'
// 引入 Element UI 的日历组件
// import { ElCalendar } from 'element-ui';
export default {
  name: 'Login',
  components: {
    HeaderNav,
    // ElCalendar // 注册 ElCalendar 组件
  },
  data() {
    return {
      windowWidth: window.innerWidth,
      loginForm: {
        username: '',
        password: ''
      },
      date: new Date(),
      viewWidth: '',
      scale: 1
    }
  },
  // computed: {},
  computed: {
    ...mapState(['tagList', 'isFold'])
  },
  created() {
    // 初始化时检查窗口大小
    this.handleResize();
  },
  mounted() {
     // 监听窗口大小变化
     window.addEventListener("resize", this.handleResize);
   },
  methods: {
    handleResize() {
      // if (window.innerWidth < 1000) {
      //   this.$store.commit("SET_ISFOLD", true);
      // } else if (window.innerWidth >= 1000 && this.isFold) {
      //   this.$store.commit("SET_ISFOLD", false);
      // }
      this.windowWidth = window.innerWidth;
    },
    // ...mapActions(['setIsFold']),
    handleKeyDown(event) {
      if (event.key === 'Enter') {
        this.login()
      }
    },
    // 添加处理窗口大小变化的方法
    handleResize() {
      this.viewWidth = window.innerWidth
    },
    login() {
      if (this.loginForm.username == '') {
        this.$message.warning('请输入账号')
        return
      }
      if (this.loginForm.password == '') {
        this.$message.warning('请输入密码')
        return
      }
      loginReq(this.loginForm).then(res => {
        sessionStorage.setItem('token', res.token)
        sessionStorage.setItem('userInfo', JSON.stringify(res.userInfo.user))
        this.$router.push('/system')
      })
    }
  }
}
</script>
<style scoped lang="less">
.flex {
  display: flex;
}
.j-between {
  justify-content: space-between;
}
.mt-40 {
  margin-top: 40px;
}
.login-page {
  width: 100vw;
  min-height: 100vh;
  /* 确保页面至少和视口一样高,并随内容扩展 */
  background: url('../../assets/login/midBg.png') no-repeat center center;
  background-size: cover;
  display: flex;
  flex-direction: column;
  // background-attachment: fixed;
  // display: flex;
  // justify-content: center;
  // align-items: center;
  .top-nav {
    display: flex;
    // justify-content: space-between;
    width: 100%;
    display: flex;
    flex-direction: column;
    transition: width 0.3s ease-in-out;
    height: 70px;
    .header-main {
      height: 70px;
      min-width: 200px;
    }
  }
  .middleground {
    flex: 1;
    height: calc(100% - 70px);
    display: flex;
    // flex-wrap: wrap;
    justify-content: flex-start;
    /* 左侧内容靠左对齐 */
    padding: 20px 20px 20px 108px;
    /* 调整左右内边距 */
    gap: 40px;
    /* 添加左右间距 */
    .left-modules {
      align-items: center;
      padding: 40px 0;
      display: flex;
      flex-wrap: wrap;
      box-sizing: content-box;
      justify-content: center;
      /* 模块之间水平分散对齐 */
      /* 水平居中 */
      align-items: flex-start;
      /* 模块垂直靠上对齐 */
      /* 垂直居中 */
      flex-grow: 1;
      /* 左侧宽度自适应 */
      align-content: flex-start;
      /* 多行模块垂直靠上对齐 */
      gap: 20px;
      /* 添加模块之间的垂直间距 */
      padding-right: 20px;
      /* 给左侧模块区域右侧添加一些间距,避免紧贴右侧内容 */
    }
    .module-item {
      // width: 37%;
      // height: 30%;
      width: 307px;
      height: 307px;
      background-color: red;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: space-between;
      background: url('../../assets/login/cardBg.png');
      /* 设置模块背景图 */
      background-size: cover;
      /* 背景图覆盖整个元素 */
      background-position: center top;
      /* 调整背景图位置:顶部居中 */
      .module-icon {
        width: 80px;
        height: 80px;
        // background-color: #eee; /* Placeholder for icon */
        z-index: 1;
        /* 确保图标在背景之上 */
        background-size: contain;
        /* 图标背景图包含在元素内 */
        background-repeat: no-repeat;
        /* 不重复 */
        background-position: 100% 100%;
        /* 图标背景图居中 */
      }
      /* 为每个模块图标设置特定的背景图片 */
      &:nth-child(1) .module-icon {
        background-image: url('../../assets/login/img1.png');
      }
      &:nth-child(2) .module-icon {
        background-image: url('../../assets/login/img2.png');
      }
      &:nth-child(3) .module-icon {
        background-image: url('../../assets/login/img3.png');
      }
      &:nth-child(4) .module-icon {
        background-image: url('../../assets/login/img4.png');
      }
      .module-text {
        font-size: 16px;
        font-weight: bold;
        position: relative;
        /* 为下划线定位 */
        z-index: 1;
        /* 确保文字在背景之上 */
        margin-bottom: 50px;
        &::after {
          content: '';
          position: absolute;
          left: 50%;
          /* 从文字中间开始 */
          bottom: -5px;
          /* 调整下划线位置 */
          transform: translateX(-50%);
          /* 使下划线居中 */
          width: 50%;
          /* 调整下划线宽度 */
          height: 2px;
          /* 调整下划线粗细 */
          background-color: #007bff;
          /* 示例下划线颜色 */
        }
      }
      &:nth-of-type(2n+1) {
        margin-right: 0;
      }
      &:nth-child(odd) {
        margin-right: 0px;
      }
    }
    .right-content {
      width: 870px;
      /* 固定右侧宽度 */
      flex-shrink: 0;
      /* 防止右侧被压缩 */
      padding: 20px;
      border-radius: 8px;
      // background-color: #fff;
      // box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
      display: flex;
      /* 使日历和待办事项垂直排列 */
      flex-direction: column;
      .calendar-section {
        margin-bottom: 20px;
        box-sizing: border-box;
        /* 日历下方间距 */
        height: 595px;
        padding: 20px;
        border-radius: 14px;
        background: url(../../assets/login/rili.png) no-repeat center;
        h3 {
          margin-top: 0;
          margin-bottom: 10px;
          font-size: 18px;
          color: #333;
        }
        .calendar {
          height: 100% !important;
          width: 100% !important;
          box-sizing: border-box;
        }
        /* 尝试调整 Element UI 日历的样式 */
        ::v-deep .el-calendar {
          height: 100%;
          width: 100%;
          background: none !important;
          box-sizing: border-box;
          .el-calendar__header {
            padding: 12px 0;
            box-sizing: border-box;
          }
          .el-calendar__body {
            padding: 0;
          }
          .el-calendar-table {
            thead th {
              padding: 5px 0;
              box-sizing: border-box;
              font-weight: normal;
            }
            tbody td {
              border: none;
              .el-calendar-day {
                /* 调整日期单元格高度 */
                display: flex;
                justify-content: center;
                align-items: center;
                border-radius: 4px;
                box-sizing: border-box;
                /* 圆角 */
                margin: 8px;
                /* 单元格间距 */
                cursor: pointer;
                // max-width: 90px;
                max-height: 61px;
                background: #FFFFFF;
                border-radius: 8px;
                border: 1px solid #EDEDED;
                &:hover {
                  background-color: #f0f0f0;
                }
              }
              /* 当前日期样式 */
              &.is-selected .el-calendar-day {
                background-color: #007bff;
                /* 示例选中颜色 */
                color: #fff;
              }
            }
          }
        }
      }
      .todo-list-section {
        flex: 1;
        border-radius: 14px;
        background-color: rgba(255, 255, 255, 1);
        // overflow: auto;
        padding: 24px 34px;
        display: flex;
        flex-direction: column;
        .title {
          height: 22px;
          font-family: SourceHanSansCN, SourceHanSansCN;
          font-weight: bold;
          font-size: 18px;
          color: #222222;
          line-height: 22px;
          margin-bottom: 20px;
        }
        .todo-list {
          flex: 1;
          height: 100%;
          overflow: auto;
        }
        /* 待办事项列表样式 */
        .todo-item {
          display: flex;
          align-items: center;
          justify-content: space-between;
          margin-bottom: 20PX;
          /* 分隔线 */
          &:first-child {
            margin-top: 3px;
          }
          .todo-details {
            display: flex;
            align-content: center;
          }
          .notice-card {
            position: relative;
            margin-right: 12px;
          }
          .todo-icon {
            position: relative;
            width: 24px;
            height: 24px;
            flex-shrink: 0;
            background: url('../../assets//login/notice.png') no-repeat center;
            background-position: center;
            background-size: 100% 100%;
          }
          .red-notice {
            position: absolute;
            top: -3px;
            right: -3px;
            width: 6px;
            height: 6px;
            border-radius: 50%;
            background: rgba(235, 65, 65, 1);
          }
          .todo-title {
            font-family: SourceHanSansCN, SourceHanSansCN;
            font-weight: 500;
            font-size: 14px;
            color: #303133;
            line-height: 24px;
          }
          .todo-meta {
            display: flex;
            align-items: center;
          }
          .time {
            width: 14px;
            height: 14px;
            margin-right: 6px;
            margin-left: 20px;
            flex-shrink: 0;
            background: url('../../assets//login/time.png') no-repeat center;
            background-position: center;
            background-size: 100% 100%;
          }
          .me {
            width: 14px;
            height: 14px;
            margin-right: 6px;
            flex-shrink: 0;
            background: url('../../assets//login/mi.png') no-repeat center;
            background-position: center;
            background-size: 100% 100%;
          }
          .todo-submitter {
            font-family: SourceHanSansCN, SourceHanSansCN;
            font-weight: 400;
            font-size: 12px;
            color: #909399;
            // line-height: 18px;
          }
        }
      }
    }
  }
  .column {
    flex-direction: column;
    /* 改为上下布局 */
    padding: 20px;
    /* 调整内边距 */
    gap: 20px;
    /* 调整上下间距 */
    height: auto;
    /* 高度自适应内容 */
    padding: 20px 20px 20px 18px !important;
  }
  // Tablet layout
  @media screen and (max-width: 768px) {
    .login-page {
      .middleground {
        flex-direction: column;
        /* 改为上下布局 */
        padding: 20px;
        /* 调整内边距 */
        gap: 20px;
        /* 调整上下间距 */
        height: auto;
        /* 高度自适应内容 */
        padding: 20px 20px 20px 18px !important;
        .left-modules {
          width: 100%;
          /* 左侧宽度占满 */
          justify-content: center;
          /* 在上下布局中水平居中模块 */
          padding: 0;
          /* 移除 padding */
          gap: 20px;
          /* 上下布局时模块之间的间距 */
          padding-right: 0;
          /* 移除右侧间距 */
        }
        .module-item {
          width: 307px;
          /* 模块宽度固定 */
          height: 307px;
          /* 模块高度固定 */
          margin-right: 0 !important;
          /* 移除桌面布局的右侧间距 */
        }
        .right-content {
          width: 100%;
          /* 右侧宽度占满 */
          height: auto;
          /* 高度自适应 */
          padding: 15px;
          /* 调整内边距 */
        }
      }
    }
  }
}
</style>
culture/src/views/middleground/service.js
New file
@@ -0,0 +1,6 @@
import axios from '@/utils/request';
// 登录
export const loginReq = (data) => {
    return axios.post('/login', { ...data })
}
culture/src/views/system/role/detail.vue
@@ -66,12 +66,12 @@
            <el-form-item label="人员搜索">
              <el-input v-model="nickNameOrPhone" placeholder="请输入姓名/联系电话"></el-input>
            </el-form-item>
            <el-form-item label="所属部门">
            <!-- <el-form-item label="所属部门">
              <el-select v-model="deptId" placeholder="请选择(多选)" multiple>
                <el-option v-for="item in deptList" :key="item.id" :label="item.deptName" :value="item.id">
                </el-option>
              </el-select>
            </el-form-item>
            </el-form-item> -->
            <el-form-item label="登陆状态">
              <el-select v-model="status" placeholder="请选择">
                <el-option
@@ -82,7 +82,7 @@
            </el-form-item>
            <el-form-item>
              <el-button @click="reset">重置</el-button>
              <el-button type="primary" @click="onSubmit">查询</el-button>
              <el-button type="primary" @click="onSubmit" style="margin-left: 10px;">查询</el-button>
            </el-form-item>
          </div>
        </el-form>
@@ -93,11 +93,6 @@
          </el-table-column>
          <el-table-column prop="nickName" label="姓名"></el-table-column>
          <el-table-column prop="phonenumber" label="联系电话">
          </el-table-column>
          <el-table-column prop="deptList" label="所属部门">
            <template slot-scope="{ row }">
              <el-tag v-for="(item, index) in row.deptList" :key="index">{{ item }}</el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="roleName" label="角色">
          </el-table-column>
@@ -162,16 +157,16 @@
  created() {
    roleInfoFromUserId({ userId: 1 }).then(res => {
      getRoleInfo({ roleId: this.$route.query.roleId }).then(resp => {
        this.menu = this.setSelectedIds(res.data.data, resp.data.data.menus);
        this.menu = this.setSelectedIds(res, resp.menus);
        this.form = {
          roleName: resp.data.data.roleName,
          remark: resp.data.data.remark,
          roleName: resp.roleName,
          remark: resp.remark,
        }
      })
    })
    this.getListData()
    getDeptList().then((res) => {
      this.deptList = res.data.data
      this.deptList = res
    })
  },
  mounted() { },
@@ -180,14 +175,16 @@
      let obj = {
        ...this.pagination,
        nickNameOrPhone: this.nickNameOrPhone,
        deptIds: this.deptId,
        // deptIds: this.deptId,
        status: this.status,
        roleIds: [this.$route.query.roleId]
      }
      this.listLoading = true
      const { data: { data: { records, total } } } = await getUserList(obj)
      this.data = records
      this.pagination.total = total
      getUserList(obj).then(res => {
        this.data = res.records
        this.pagination.total = res.total
      })
    },
    setSelectedIds(arr, selectKeyList) {
      function traverse(item) {
culture/src/views/system/role/edit.vue
@@ -119,15 +119,15 @@
    roleInfoFromUserId({ userId: 1 }).then(res => {
      if (this.$route.query.roleId) {
        getRoleInfo({ roleId: this.$route.query.roleId }).then(resp => {
          this.menu = this.setSelectedIds(res.data.data, resp.data.data.menus || []);
          this.menu = this.setSelectedIds(res, resp.menus || []);
          this.form = {
            roleName: resp.data.data.roleName,
            remark: resp.data.data.remark,
            roleId: resp.data.data.roleId
            roleName: resp.roleName,
            remark: resp.remark,
            roleId: resp.roleId
          }
        })
      } else {
        this.menu = res.data.data
        this.menu = res
      }
    })
  },
culture/src/views/system/role/index.vue
@@ -1,7 +1,7 @@
<template>
  <div class="list">
    <TableCustom :queryForm="pagination" :tableData="data" :total="pagination.total" @currentChange="handleCurrentChange"
      @sizeChange="handleSizeChange">
    <TableCustom :queryForm="pagination" :tableData="data" :total="pagination.total" @handleCurrentChange="handleCurrentChange"
      @handleSizeChange="handleSizeChange" :height="null">
      <template #search>
        <el-form inline>
          <el-form-item label="角色名称">
@@ -9,17 +9,17 @@
          </el-form-item>
          <el-form-item style="margin-left: 63px;">
            <el-button @click="reset">重置</el-button>
            <el-button type="primary" @click="onSubmit">查询</el-button>
            <el-button type="primary" @click="onSubmit" style="margin-left: 10px;">查询</el-button>
          </el-form-item>
        </el-form>
      </template>
      <template #setting>
      <!-- <template #setting>
        <el-button icon="el-icon-plus" @click="add" type="primary">添加角色</el-button>
      </template>
      </template> -->
      <template #table>
        <el-table-column type="index" width="55" label="序号"></el-table-column>
        <el-table-column prop="roleName" label="角色名称"></el-table-column>
        <el-table-column prop="roleNum" label="角色人数"></el-table-column>
        <el-table-column prop="userCount" label="角色人数"></el-table-column>
        <el-table-column prop="remark" label="备注"></el-table-column>
        <el-table-column prop="createTime" label="创建时间"></el-table-column>
        <el-table-column label="操作" width="300">
@@ -27,9 +27,9 @@
            <div>
              <el-button type="text"
                @click="$router.push(`/system/detail-role?roleId=${row.roleId}`)">详情</el-button>
              <el-button v-if="row.roleId != 1" type="text"
              <!-- <el-button v-if="row.roleId != 1" type="text"
                @click="$router.push(`/system/edit-role?roleId=${row.roleId}`)">编辑</el-button>
              <el-button v-if="row.roleId != 1" type="text" @click="del(row)">删除</el-button>
              <el-button v-if="row.roleId != 1" type="text" @click="del(row)">删除</el-button> -->
            </div>
          </template>
        </el-table-column>
@@ -63,7 +63,7 @@
  },
  watch: {},
  created() {
    // this.getListData()
    this.getListData()
  },
  mounted() { },
  methods: {
@@ -89,9 +89,11 @@
        pageSize: this.pagination.pageSize
      }
      this.listLoading = true
      const { data: { data: { records, total } } } = await getList(obj)
      this.data = records
      this.pagination.total = total
      getList(obj).then(res=>{
        this.data = res.records
      this.pagination.total = res.total
      })
    },
    reset() {
      this.roleName = ''
culture/src/views/system/role/service.js
@@ -12,7 +12,7 @@
// 编辑
export const edit = (data) => {
  return axios.put('/system/role', { ...data })
  return axios.put('/api/system/role', { ...data })
}
// 删除
@@ -36,6 +36,6 @@
  return axios.post('/system/user/list', { ...data })
}
export const getDeptList = (params) => {
  return axios.post('/t-dept/listAll')
}
// export const getDeptList = (params) => {
//   return axios.post('/t-dept/listAll')
// }
laboratory/src/views/system/role/index.vue
@@ -26,9 +26,9 @@
          <template slot-scope="{row}">
            <div>
              <el-button type="text" @click="$router.push(`/system/detail-role?roleId=${row.roleId}`)">详情</el-button>
              <el-button v-if="row.roleId != 1" type="text"
              <!-- <el-button v-if="row.roleId != 1" type="text"
                @click="$router.push(`/system/edit-role?roleId=${row.roleId}`)">编辑</el-button>
              <el-button v-if="row.roleId != 1" type="text" @click="del(row)">删除</el-button>
              <el-button v-if="row.roleId != 1" type="text" @click="del(row)">删除</el-button> -->
            </div>
          </template>
        </el-table-column>