ソースを参照

新增绑定实验室人员审批菜单

stoney 1 週間 前
コミット
a1f2002889
共有4 個のファイルを変更した117 個の追加2 個の削除を含む
  1. 1 0
      prototype/css/styles.css
  2. 66 2
      prototype/index.html
  3. 37 0
      prototype/js/app.js
  4. 13 0
      prototype/js/data.js

+ 1 - 0
prototype/css/styles.css

@@ -286,6 +286,7 @@ html, body { height: 100%; font-family: 'PingFang SC', 'Microsoft YaHei', sans-s
 .stats-filter-row {
   display: flex; align-items: center; gap: 10px; margin-bottom: 12px; flex-wrap: wrap;
 }
+.reject-reason-text { font-size: 11px; color: #e84d5b; }
 
 /* Flow Page */
 .flow-page {

+ 66 - 2
prototype/index.html

@@ -19,7 +19,7 @@
           <span class="logo-text">安全教育与考试</span>
         </div>
         <ul class="nav-menu">
-          <li v-for="item in menuItems" :key="item.key"
+          <li v-for="item in visibleMenuItems" :key="item.key"
               :class="['nav-item', { active: activePage === item.key }]"
               @click="activePage = item.key">
             <i :class="item.icon"></i>
@@ -426,6 +426,60 @@
           </el-tabs>
         </main>
 
+        <!-- 人员审批页面 -->
+        <main class="content" v-if="activePage === 'approval'">
+          <div class="page-toolbar">
+            <h2 class="page-title">人员审批</h2>
+          </div>
+          <section class="stats-section">
+            <div class="stats-section-header">
+              <h3>实验室绑定申请</h3>
+              <div class="stats-section-actions">
+                <el-radio-group v-model="approvalFilter" size="mini">
+                  <el-radio-button label="all">全部</el-radio-button>
+                  <el-radio-button label="pending">待审批</el-radio-button>
+                  <el-radio-button label="approved">已通过</el-radio-button>
+                  <el-radio-button label="rejected">已驳回</el-radio-button>
+                </el-radio-group>
+              </div>
+            </div>
+            <el-table :data="filteredApprovalData" border size="small" style="width:100%">
+              <el-table-column prop="studentName" label="申请人" min-width="80"></el-table-column>
+              <el-table-column prop="studentCode" label="学号" min-width="110"></el-table-column>
+              <el-table-column prop="studentType" label="用户类型" min-width="100"></el-table-column>
+              <el-table-column prop="college" label="所属学院" min-width="130"></el-table-column>
+              <el-table-column label="申请实验室" min-width="160">
+                <template slot-scope="scope">{{ scope.row.labName }}({{ scope.row.labRoom }})</template>
+              </el-table-column>
+              <el-table-column label="分级" min-width="60">
+                <template slot-scope="scope">
+                  <el-tag :type="levelTagType(scope.row.labLevel)" size="mini">{{ scope.row.labLevel }}</el-tag>
+                </template>
+              </el-table-column>
+              <el-table-column prop="labCategory" label="分类" min-width="70"></el-table-column>
+              <el-table-column prop="reason" label="进入原因" min-width="140" show-overflow-tooltip></el-table-column>
+              <el-table-column prop="submitTime" label="提交时间" min-width="130"></el-table-column>
+              <el-table-column prop="autoApproveDate" label="通过时间" min-width="130"></el-table-column>
+              <el-table-column label="状态" min-width="80">
+                <template slot-scope="scope">
+                  <el-tag v-if="scope.row.status === 'pending'" type="warning" size="mini">待审批</el-tag>
+                  <el-tag v-if="scope.row.status === 'approved'" type="success" size="mini">已通过</el-tag>
+                  <el-tag v-if="scope.row.status === 'rejected'" type="danger" size="mini">已驳回</el-tag>
+                </template>
+              </el-table-column>
+              <el-table-column label="操作" min-width="140" fixed="right">
+                <template slot-scope="scope">
+                  <template v-if="scope.row.status === 'pending'">
+                    <el-button type="success" size="mini" @click="approveItem(scope.row)">通过</el-button>
+                    <el-button type="danger" size="mini" @click="openRejectDialog(scope.row)">驳回</el-button>
+                  </template>
+                  <span v-if="scope.row.status === 'rejected'" class="reject-reason-text">{{ scope.row.rejectReason }}</span>
+                </template>
+              </el-table-column>
+            </el-table>
+          </section>
+        </main>
+
         <!-- 系统配置页面 -->
         <main class="content" v-if="activePage === 'config'">
           <div class="page-toolbar">
@@ -453,7 +507,7 @@
         </main>
 
         <!-- 其他页面占位 -->
-        <main class="content" v-if="!['workbench','config','flow','prd','statistics'].includes(activePage)">
+        <main class="content" v-if="!['workbench','config','flow','prd','statistics','approval'].includes(activePage)">
           <div class="placeholder-page">
             <i class="el-icon-s-opportunity"></i>
             <p>{{ currentPageLabel }} - 功能开发中</p>
@@ -556,6 +610,16 @@
         <el-button type="primary" @click="showNoticeDetail = false">我已知晓</el-button>
       </span>
     </el-dialog>
+
+    <!-- 驳回原因弹窗 -->
+    <el-dialog title="驳回申请" :visible.sync="showRejectDialog" width="450px">
+      <p style="margin-bottom:12px;color:#60708a;font-size:13px">请填写驳回原因,将通知申请人:</p>
+      <el-input v-model="rejectReasonInput" type="textarea" :rows="3" placeholder="请输入驳回原因(必填)"></el-input>
+      <span slot="footer">
+        <el-button @click="showRejectDialog = false">取消</el-button>
+        <el-button type="danger" @click="confirmReject" :disabled="!rejectReasonInput.trim()">确认驳回</el-button>
+      </span>
+    </el-dialog>
   </div>
 
   <!-- Vendor Scripts (CDN - 生产环境应本地化) -->

+ 37 - 0
prototype/js/app.js

@@ -42,6 +42,12 @@ new Vue({
       hoursFilterKey: '',
       hoursPage: 1,
       hoursPageSize: 8,
+      // 人员审批
+      approvalList: JSON.parse(JSON.stringify(approvalData)),
+      approvalFilter: 'all',
+      showRejectDialog: false,
+      rejectReasonInput: '',
+      rejectingItem: null,
       // 配置表
       configTableData: [
         { level: 'Ⅰ', levelLabel: 'Ⅰ级(重大风险)', firstYear: levelHoursConfig['Ⅰ'].firstYear, annual: levelHoursConfig['Ⅰ'].annual },
@@ -109,6 +115,18 @@ new Vue({
   },
   computed: {
     currentRole: function() { return this.rolesData[this.activeRole]; },
+    visibleMenuItems: function() {
+      var isStaff = this.activeRole === 'newStaff' || this.activeRole === 'existingStaff';
+      return this.menuItems.filter(function(item) {
+        if (item.staffOnly) return isStaff;
+        return true;
+      });
+    },
+    filteredApprovalData: function() {
+      var filter = this.approvalFilter;
+      if (filter === 'all') return this.approvalList;
+      return this.approvalList.filter(function(d) { return d.status === filter; });
+    },
     currentPageLabel: function() {
       var p = this.activePage;
       var item = this.menuItems.find(function(m) { return m.key === p; });
@@ -493,6 +511,25 @@ new Vue({
         if (rowIndex % 3 === 0) return { rowspan: 3, colspan: 1 };
         return { rowspan: 0, colspan: 0 };
       }
+    },
+    approveItem: function(item) {
+      item.status = 'approved';
+      this.$message.success('已通过 ' + item.studentName + ' 的绑定申请');
+    },
+    openRejectDialog: function(item) {
+      this.rejectingItem = item;
+      this.rejectReasonInput = '';
+      this.showRejectDialog = true;
+    },
+    confirmReject: function() {
+      if (this.rejectingItem) {
+        this.rejectingItem.status = 'rejected';
+        this.rejectingItem.rejectReason = this.rejectReasonInput;
+        this.$message.warning('已驳回 ' + this.rejectingItem.studentName + ' 的绑定申请');
+      }
+      this.showRejectDialog = false;
+      this.rejectingItem = null;
+      this.rejectReasonInput = '';
     }
   },
   watch: {

+ 13 - 0
prototype/js/data.js

@@ -376,9 +376,22 @@ var videoData = {
 var menuItems = [
   { key: 'workbench', icon: 'el-icon-s-platform', label: '工作台' },
   { key: 'statistics', icon: 'el-icon-s-data', label: '数据统计' },
+  { key: 'approval', icon: 'el-icon-s-check', label: '人员审批', staffOnly: true },
   { key: 'config', icon: 'el-icon-setting', label: '系统配置' }
 ];
 
+// 人员审批 - Mock数据
+var approvalData = [
+  { id: 'AP001', studentName: '张明远', studentCode: '2025100001', studentType: '硕士研究生', college: '化学与化工学院', labName: '有机化学实验室', labRoom: 'A301', labLevel: 'Ⅱ', labCategory: '化学类', submitTime: '2025-09-02 14:30', status: 'pending', reason: '', rejectReason: '', autoApproveDate: '2025-09-09 14:30' },
+  { id: 'AP002', studentName: '赵雨晴', studentCode: '2025100023', studentType: '硕士研究生', college: '电气工程学院', labName: '电气工程实验室', labRoom: 'C102', labLevel: 'Ⅲ', labCategory: '机电类', submitTime: '2025-09-03 09:15', status: 'pending', reason: '', rejectReason: '', autoApproveDate: '2025-09-10 09:15' },
+  { id: 'AP003', studentName: '刘芳华', studentCode: '2025100078', studentType: '硕士研究生', college: '化学与化工学院', labName: '高分子化学实验室', labRoom: 'A402', labLevel: 'Ⅱ', labCategory: '化学类', submitTime: '2025-09-01 16:45', status: 'approved', reason: '', rejectReason: '', autoApproveDate: '2025-09-08 16:45' },
+  { id: 'AP004', studentName: '王浩然', studentCode: '2024100088', studentType: '硕士研究生', college: '物理学院', labName: '辐射防护实验室', labRoom: 'D401', labLevel: 'Ⅰ', labCategory: '辐射类', submitTime: '2025-08-30 10:20', status: 'approved', reason: '', rejectReason: '', autoApproveDate: '2025-09-06 10:20' },
+  { id: 'AP005', studentName: '陈志强', studentCode: '2024100056', studentType: '硕士研究生', college: '材料科学学院', labName: '材料力学实验室', labRoom: 'E203', labLevel: 'Ⅳ', labCategory: '机电类', submitTime: '2025-09-04 11:00', status: 'rejected', reason: '', rejectReason: '该实验室已满员,请联系导师更换实验室', autoApproveDate: '2025-09-11 11:00' },
+  { id: 'AP006', studentName: '李佳欣', studentCode: '2025200312', studentType: '本科生', college: '生命科学学院', labName: '分子生物学实验室', labRoom: 'B205', labLevel: 'Ⅰ', labCategory: '生物类', submitTime: '2025-09-05 08:30', status: 'pending', reason: '毕业论文需要进入该实验室开展分子克隆实验', rejectReason: '', autoApproveDate: '2025-09-12 08:30' },
+  { id: 'AP007', studentName: '周文博', studentCode: '2025100034', studentType: '硕士研究生', college: '自动化学院', labName: '智能控制实验室', labRoom: 'C305', labLevel: 'Ⅲ', labCategory: '机电类', submitTime: '2025-09-05 15:10', status: 'pending', reason: '', rejectReason: '', autoApproveDate: '2025-09-12 15:10' },
+  { id: 'AP008', studentName: '孙晓明', studentCode: '2023100091', studentType: '硕士研究生', college: '生命科学学院', labName: '微生物学实验室', labRoom: 'B308', labLevel: 'Ⅱ', labCategory: '生物类', submitTime: '2025-08-28 13:40', status: 'approved', reason: '', rejectReason: '', autoApproveDate: '2025-09-04 13:40' }
+];
+
 // 数据统计 - Mock数据
 var statisticsData = {
   colleges: ['化学与化工学院', '生命科学学院', '物理学院', '电气工程学院', '材料科学学院', '机械工程学院', '自动化学院', '资源环境学院'],