11wqe1 1 день назад
Родитель
Сommit
8a65d5286a

+ 10 - 0
src/assets/stuImg/Search.svg

@@ -0,0 +1,10 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_7785_15590)">
+<path d="M13.0233 11.0238C15.1067 8.94111 15.1067 5.56411 13.0233 3.48144C10.9407 1.39844 7.56401 1.39844 5.48101 3.48144C3.39834 5.56411 3.39834 8.94111 5.48101 11.0238C7.56401 13.1064 10.9407 13.1064 13.0233 11.0238ZM13.0233 11.0238L15.852 13.8521" stroke="#4E5969" stroke-width="1.33333"/>
+</g>
+<defs>
+<clipPath id="clip0_7785_15590">
+<rect width="16" height="16" fill="white"/>
+</clipPath>
+</defs>
+</svg>

+ 3 - 0
src/assets/stuImg/act.svg

@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M7.5 13C7.10217 13 6.72064 12.842 6.43934 12.5607C6.15804 12.2794 6 11.8978 6 11.5C6 11.1022 6.15804 10.7206 6.43934 10.4393C6.72064 10.158 7.10217 10 7.5 10C7.89782 10 8.27936 10.158 8.56066 10.4393C8.84196 10.7206 9 11.1022 9 11.5C9 11.8978 8.84196 12.2794 8.56066 12.5607C8.27936 12.842 7.89782 13 7.5 13ZM11.7857 13C11.3879 13 11.0064 12.842 10.7251 12.5607C10.4437 12.2794 10.2857 11.8978 10.2857 11.5C10.2857 11.1022 10.4437 10.7206 10.7251 10.4393C11.0064 10.158 11.3879 10 11.7857 10C12.1835 10 12.5651 10.158 12.8464 10.4393C13.1277 10.7206 13.2857 11.1022 13.2857 11.5C13.2857 11.8978 13.1277 12.2794 12.8464 12.5607C12.5651 12.842 12.1835 13 11.7857 13ZM16.0714 13C15.6736 13 15.2921 12.842 15.0108 12.5607C14.7295 12.2794 14.5714 11.8978 14.5714 11.5C14.5714 11.1022 14.7295 10.7206 15.0108 10.4393C15.2921 10.158 15.6736 10 16.0714 10C16.4693 10 16.8508 10.158 17.1321 10.4393C17.4134 10.7206 17.5714 11.1022 17.5714 11.5C17.5714 11.8978 17.4134 12.2794 17.1321 12.5607C16.8508 12.842 16.4693 13 16.0714 13Z" fill="#1D2129"/>
+</svg>

+ 3 - 0
src/assets/stuImg/cz.svg

@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M9.89819 1.49976C11.541 1.49976 13.0415 2.10242 14.2039 3.09546V2.89331C14.204 2.45164 14.562 2.09361 15.0037 2.09351C15.4454 2.09351 15.8034 2.45157 15.8035 2.89331V5.29761C15.8035 5.66065 15.5587 5.97821 15.2078 6.07104C14.857 6.16356 14.4877 6.00851 14.3083 5.69312C13.4227 4.1364 11.7752 3.09937 9.89819 3.09937C7.09796 3.09965 4.80357 5.41456 4.80347 8.29956C4.80347 11.1847 7.09789 13.4995 9.89819 13.4998C11.7714 13.4998 13.4156 12.4671 14.3025 10.9158C14.5217 10.5323 15.0108 10.3989 15.3943 10.6179C15.7778 10.8372 15.9114 11.3261 15.6921 11.7097C14.5369 13.7307 12.3782 15.0994 9.89819 15.0994C6.18769 15.0991 3.20386 12.0415 3.20386 8.29956C3.20396 4.55768 6.18776 1.50004 9.89819 1.49976Z" fill="#222222"/>
+</svg>

+ 14 - 0
src/assets/stuImg/del.svg

@@ -0,0 +1,14 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_7785_15803)">
+<path d="M5.75 6.16669V20.3334H18.25V6.16669H5.75Z" stroke="black" stroke-opacity="0.9" stroke-width="1.5" stroke-linejoin="round"/>
+<path d="M10.3333 10.3333V15.75" stroke="black" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M13.6667 10.3333V15.75" stroke="black" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M3.66666 6.16669H20.3333" stroke="black" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M8.66666 6.16669L10.0371 3.66669H13.9904L15.3333 6.16669H8.66666Z" stroke="black" stroke-opacity="0.9" stroke-width="1.5" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_7785_15803">
+<rect width="20" height="20" fill="white" transform="translate(2 2)"/>
+</clipPath>
+</defs>
+</svg>

+ 4 - 0
src/assets/stuImg/edit.svg

@@ -0,0 +1,4 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M4.91666 19.5H19.9167" stroke="black" stroke-opacity="0.9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M6.58334 13.1333V16.1667H9.63218L18.25 7.54504L15.2063 4.5L6.58334 13.1333Z" stroke="black" stroke-opacity="0.9" stroke-width="1.5" stroke-linejoin="round"/>
+</svg>

BIN
src/assets/stuImg/fjia.png


+ 3 - 0
src/assets/stuImg/inf.svg

@@ -0,0 +1,3 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M12.7031 2.20001C13.3241 2.20001 13.8301 2.70488 13.8301 3.32599V3.89728C13.8299 4.19821 13.5852 4.4422 13.2842 4.4422C12.9834 4.44199 12.7394 4.19808 12.7393 3.89728V3.32599C12.7393 3.30605 12.7231 3.28986 12.7031 3.28986H3.12695C3.10701 3.28986 3.09082 3.30605 3.09082 3.32599V12.9109C3.09082 12.9309 3.10701 12.9471 3.12695 12.9471H5.58789C5.88893 12.9471 6.13281 13.1919 6.13281 13.493C6.13248 13.7937 5.88875 14.0378 5.58789 14.0379H3.12695C2.50584 14.0379 2 13.5321 2 12.9109V3.32599C2 2.70488 2.50584 2.20001 3.12695 2.20001H12.7031ZM10.1348 4.20782C11.7758 4.20794 13.1111 5.54338 13.1113 7.18439C13.1113 8.29862 12.4946 9.26994 11.5859 9.78009C12.0599 9.97198 12.4957 10.2582 12.8682 10.6307C13.5982 11.3608 14 12.3316 14 13.3641C13.9999 13.6651 13.7561 13.9089 13.4551 13.909C13.154 13.909 12.9102 13.6651 12.9102 13.3641C12.9102 11.8339 11.6651 10.5888 10.1348 10.5887C8.60436 10.5887 7.35938 11.8337 7.35938 13.3641C7.3593 13.665 7.11533 13.9088 6.81445 13.909C6.51341 13.909 6.26863 13.6651 6.26855 13.3641C6.26855 12.3316 6.67124 11.3608 7.40137 10.6307C7.7735 10.2586 8.20819 9.97197 8.68164 9.78009C7.77362 9.26973 7.1582 8.29806 7.1582 7.18439C7.15845 5.54331 8.49363 4.20782 10.1348 4.20782ZM10.1348 5.29865C9.09465 5.29865 8.24805 6.14511 8.24805 7.18536C8.24825 8.2253 9.09478 9.07111 10.1348 9.07111C11.1747 9.07099 12.0203 8.22537 12.0205 7.18536C12.0205 6.14532 11.1749 5.29876 10.1348 5.29865Z" fill="#86909C"/>
+</svg>

+ 4 - 0
src/assets/stuImg/jia.svg

@@ -0,0 +1,4 @@
+<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M10.0252 4.16669L10.01 15.8334" stroke="#0052D9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M4.16666 10H15.8333" stroke="#0052D9" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

Разница между файлами не показана из-за своего большого размера
+ 2 - 0
src/assets/stuImg/per.svg


Разница между файлами не показана из-за своего большого размера
+ 1 - 0
src/assets/stuImg/riqi.svg


+ 12 - 0
src/assets/stuImg/share.svg

@@ -0,0 +1,12 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_7785_15599)">
+<path d="M11.3334 2H16V6.66667" stroke="#333333" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M16 9.82457V13C16 13.5523 15.5523 14 15 14H5C4.44772 14 4 13.5523 4 13V3C4 2.44772 4.44772 2 5 2H8" stroke="#333333" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M10.6 7.40005L15.7 2.30005" stroke="#333333" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_7785_15599">
+<rect width="16" height="16" fill="white"/>
+</clipPath>
+</defs>
+</svg>

+ 1 - 1
src/components/pages/studentManage/class.vue

@@ -266,7 +266,7 @@
         </el-form-item>
         <el-form-item :label="lang.StudentAccount" :label-width="formLabelWidth">
           <span>
-            <el-input :placeholder="lang.enterstuacc" clearable v-model="userinfo.un" class="add_input"></el-input>
+            <el-input disabled :placeholder="lang.enterstuacc" clearable v-model="userinfo.un" class="add_input"></el-input>
           </span>
         </el-form-item>
         <el-form-item :label="lang.AffiliatedSchool" :label-width="formLabelWidth">

+ 1 - 1
src/components/pages/studentManage/student.vue

@@ -229,7 +229,7 @@
         </el-form-item> -->
         <el-form-item :label="lang.StudentAccount" :label-width="formLabelWidth">
           <span>
-            <el-input :placeholder="lang.enterstuacc" clearable v-model="userinfo.un" class="add_input"></el-input>
+            <el-input :placeholder="lang.enterstuacc" disabled clearable v-model="userinfo.un" class="add_input"></el-input>
           </span>
         </el-form-item>
         <el-form-item :label="lang.AffiliatedSchool" :label-width="formLabelWidth">

+ 44 - 0
src/components/pages/studentManageNew/component/dia.vue

@@ -0,0 +1,44 @@
+<template>
+  <div class="dia_box">
+    <el-dialog :title="title" :visible.sync="visible" width="500px">
+      <div class="dia_box_item">
+        <span>班级名称</span>
+        <el-input v-model="classname" placeholder="请输入班级名称"></el-input>
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="visible = false">取消</el-button>
+        <el-button type="primary" @click="confirm">确定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+<script>
+export default {
+  name: "dia",
+  data() {
+    return {
+      title: "",
+      visible: false,
+      classname: '',
+    };
+  },
+  methods: {
+    confirm() {
+      this.visible = false;
+    },
+  },
+};
+</script>
+
+<style scoped>
+.dia_box_item {
+    display: flex;
+    align-items: center;
+    gap: 10px;
+}
+.dia_box_item span {
+  width: 80px;
+  flex-shrink: 0;
+  text-align: right;
+}
+</style>

+ 1473 - 0
src/components/pages/studentManageNew/component/table.vue

@@ -0,0 +1,1473 @@
+<template>
+  <div class="tabbox">
+    <div class="topbox">
+      <template>
+        <div class="topbox_area" v-if="boxType == 0">
+          <span>{{ activeinfo.name }}</span>
+          <span>学生列表</span>
+          <el-tooltip content="编辑" placement="top">
+            <img
+              src="../../../../assets/stuImg/edit.svg"
+              alt=""
+              @click="editCla(activeinfo)"
+              class="xk_img"
+            />
+          </el-tooltip>
+          <el-tooltip content="删除" placement="top">
+            <img
+              src="../../../../assets/stuImg/del.svg"
+              alt=""
+              @click="deleteCla(activeId)"
+              class="xk_img"
+            />
+          </el-tooltip>
+        </div>
+        <div class="topbox_area" v-if="boxType == 1">
+          <span>兴趣班列表</span>
+        </div>
+        <div class="topbox_area" v-if="boxType == 2">
+          <span>学生列表</span>
+          <span>{{ total }}人</span>
+        </div>
+      </template>
+
+      <!-- 右边区域 -->
+      <div class="topbox_area">
+        <el-input
+          placeholder="搜索学生..."
+          v-model="inp"
+          @blur="refresh"
+          v-if="boxType == 0 || boxType == 2"
+        >
+          <i slot="prefix" class="el-input__icon el-icon-search"></i>
+        </el-input>
+        <div @click="refresh" v-if="!selectedData.length" class="action_btn">
+          <img
+            src="../../../../assets/stuImg/cz.svg"
+            alt="刷新"
+            class="action_img"
+          />
+          刷新
+        </div>
+
+        <!-- 处理学生相关操作 -->
+        <template v-if="boxType == 0">
+          <div @click="exportStudent" class="action_btn">
+            <img
+              src="../../../../assets/stuImg/share.svg"
+              alt="导出"
+              class="action_img"
+            />
+            导出
+          </div>
+          <template v-if="selectedData.length">
+            <div class="action_btn action_btn2" @click="resetPassword">
+              <i class="el-icon-lock"></i>
+              重置密码
+            </div>
+            <div class="action_btn action_btn2" @click="moveSelStu">
+              <i class="el-icon-rank"></i>
+              移动
+            </div>
+            <div
+              class="action_btn"
+              style="background: #ff4d4f; color: #fff"
+              @click="removeSelStu"
+            >
+            <i class="el-icon-remove-outline"></i>
+              移除
+            </div>
+          </template>
+        </template>
+        <div
+          @click="addStudent"
+          v-if="!selectedData.length && (boxType == 0 || boxType == 2)"
+          class="action_btn"
+        >
+          <i class="el-icon-plus"></i>
+          添加学生
+        </div>
+
+        <!-- 处理兴趣班相关操作 -->
+        <div
+          @click="editInterestCla(0)"
+          v-if="boxType == 1"
+          class="action_btn"
+        >
+          <i class="el-icon-plus"></i>
+          添加学生
+        </div>
+      </div>
+    </div>
+    <div class="tabList" v-loading="isLoading">
+      <el-table
+        :data="tableData"
+        ref="tableData"
+        style="width: 100%"
+        :header-cell-style="{ background: '#E7EAF0' }"
+        :key="boxType"
+        height="100%"
+        class="tableList"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" v-if="boxType == 0" width="55px">
+        </el-table-column>
+        <el-table-column
+          v-for="(item, index) in tableColumns"
+          :key="index"
+          :label="item.label"
+        >
+          <template slot-scope="scope">
+            <div class="cla_box" v-if="item.label == '班级' && boxType == 0">
+              <span
+                class="cla_span"
+                v-for="(cla, ind) in scope.row.classname"
+                :key="ind + 'cla'"
+              >
+                {{ cla }}
+              </span>
+            </div>
+            <div v-else-if="item.label == '账号' && boxType == 0">
+              <span>{{ scope.row.acc.split("@")[0] }}</span>
+            </div>
+            <div v-else>
+              <span>{{ scope.row[item.prop] }}</span>
+            </div>
+          </template>
+        </el-table-column>
+
+        <!-- 操作列 -->
+        <el-table-column width="100px" label="">
+          <template slot-scope="scope">
+            <div>
+              <el-popover
+                placement="bottom-end"
+                width="60"
+                trigger="hover"
+                popper-class="student-manage-action-popover"
+              >
+                <div class="action_box">
+                  <template v-if="boxType == 0 || boxType == 2">
+                    <div @click="editStudent(scope.row)">编辑</div>
+                    <div @click="deleteStudentL(scope.row, scope.row.state)">
+                      删除
+                    </div>
+                  </template>
+                  <template v-if="boxType == 1">
+                    <div @click="editInterestCla(1,scope.row)">编辑</div>
+                    <div @click="deleteCla(scope.row.id)">删除</div>
+                  </template>
+                  
+                </div>
+                <img
+                  src="../../../../assets/stuImg/act.svg"
+                  slot="reference"
+                  alt="编辑"
+                  class="action_img"
+                  style="cursor: pointer"
+                />
+              </el-popover>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="page_box" v-if="boxType == 2 || boxType == 1">
+        <el-pagination
+          background
+          @size-change="handleSizeChange"
+          @current-change="handlePageChange"
+          :current-page.sync="page"
+          :page-sizes="[10, 15, 20, 25]"
+          :page-size="pageSize"
+          layout="sizes, prev, pager, next"
+          :total="total"
+        >
+        </el-pagination>
+      </div>
+      <div class="page_box" v-if="boxType == 0 && selectedData.length">
+        <div class="page_box_area">
+          <div style="display: flex; align-items: center; gap: 10px;">
+            <el-checkbox @change="handleCheckedAllSelection" v-model="checkedAllSelection"></el-checkbox>
+            <div @click="cancelAllSelection" class="action_btn">取消全选</div>
+          </div>
+
+          <div
+            @click="deleteSelectionStudent"
+            class="action_btn"
+            style="background: #ff4d4f; color: #fff"
+          >
+            删除
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <!-- 编辑兴趣班弹框 -->
+    <el-dialog :visible.sync="InterestClaEditvisible" width="700px">
+      <template slot="title">
+        <div class="dia_title_box">
+          <span>{{ interIsAdd == 0 ? '添加学生' : '编辑兴趣班' }}</span>
+        </div>
+      </template>
+      <div class="dia_box_item">
+       
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="InterestClaEditvisible = false">取消</el-button>
+        <el-button type="primary" @click="confirmInterestClaEdit">确定</el-button>
+      </div>
+    </el-dialog>
+    <!-- 移动班级学生弹框 -->
+    <el-dialog :visible.sync="moveClaVisible" width="500px">
+      <template slot="title">
+        <div class="dia_title_box">
+          <span>移动班级学生</span>
+        </div>
+      </template>
+      <el-cascader
+        :options="cascaderData"
+        v-model="moveClaCascaderDataPath"
+        @change="handlemoveChangecascader"
+        popper-class="myCascader"
+        :props="{
+          label: 'name',
+          value: 'id',
+          children: 'children',
+        }"
+      >
+        <template slot-scope="{ data, node }">
+          <!-- 一级选项(年级) -->
+          <span v-if="node.level === 1">{{ data.name }}</span>
+          <!-- 二级选项(班级)- 可以自定义显示 -->
+          <span v-else-if="node.level === 2" class="cascader-class-item">
+            <span>{{ data.name }}</span>
+          </span>
+          <!-- 其他级别(兜底) -->
+          <span v-else>{{ data.name }}</span>
+        </template>
+      </el-cascader>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="moveClaVisible = false">取消</el-button>
+        <el-button type="primary" @click="confirmMoveClaEdit">确定</el-button>
+      </div>
+    </el-dialog>
+    <!-- 修改班级名称弹框 -->
+    <el-dialog :visible.sync="ClaEditvisible" width="500px">
+      <template slot="title">
+        <div class="dia_title_box">
+          <span>修改班级名称</span>
+        </div>
+      </template>
+      <div class="dia_box_item">
+        <div class="addcla_box_item">
+          <span>班级名称:</span>
+          <el-input
+            v-model="ClaEditInfo.name"
+            placeholder="请输入班级名称"
+          ></el-input>
+        </div>
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="ClaEditvisible = false">取消</el-button>
+        <el-button type="primary" @click="confirmClaEdit">确定</el-button>
+      </div>
+    </el-dialog>
+    <!-- 编辑信息 -->
+    <el-dialog :visible.sync="stuEditvisible" width="500px">
+      <template slot="title">
+        <div class="dia_title_box">
+          <span>编辑信息</span>
+          <span @click="inPassword">重置密码</span>
+        </div>
+      </template>
+      <div class="dia_box_item">
+        <div class="addcla_box_item">
+          <span>姓名:</span>
+          <el-input
+            v-model="stuEditInfo.username"
+            placeholder="请输入姓名"
+          ></el-input>
+        </div>
+        <div class="addcla_box_item">
+          <span>账号:</span>
+          <div>{{ stuEditInfo.acc }}</div>
+        </div>
+        <div class="addcla_box_item">
+          <span>班级:</span>
+          <el-cascader
+            :options="cascaderData"
+            v-model="cascaderDataPath"
+            @change="handleChangecascader"
+            popper-class="myCascader"
+            :props="{
+              label: 'name',
+              value: 'id',
+              children: 'children',
+              multiple: true,
+            }"
+          >
+            <template slot-scope="{ data, node }">
+              <!-- 一级选项(年级) -->
+              <span v-if="node.level === 1">{{ data.name }}</span>
+              <!-- 二级选项(班级)- 可以自定义显示 -->
+              <span v-else-if="node.level === 2" class="cascader-class-item">
+                <span>{{ data.name }}</span>
+              </span>
+              <!-- 其他级别(兜底) -->
+              <span v-else>{{ data.name }}</span>
+            </template>
+          </el-cascader>
+        </div>
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="closeEditStu">取消</el-button>
+        <el-button type="primary" @click="confirmEditStu">确定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    GrapTableData: {
+      type: Array,
+      default: () => [],
+    },
+    activeId: {
+      type: String,
+      default: "",
+    },
+    activeinfo: {
+      type: Object,
+      default: () => {},
+    },
+    boxType: {
+      type: Number,
+      default: 0,
+    },
+  },
+  data() {
+    return {
+      userid: this.$route.query.userid,
+      org: this.$route.query.org,
+      oid: this.$route.query.oid,
+      role: this.$route.query.role,
+
+      cascaderData: [], // 班级级联数据
+      cascaderDataPath: [], // 班级级联选中数据路径
+
+      checkedAllSelection: false, // 全选
+
+      stuEditvisible: false,
+      stuEditInfo: {}, // 学生编辑信息
+      ClaEditvisible: false, // 班级编辑信息
+      ClaEditInfo: {}, // 班级编辑信息
+
+      moveClaVisible: false, // 移动班级学生弹框
+      moveClaInfo: {}, // 移动班级学生信息
+      moveClaCascaderDataPath: [], // 移动班级学生级联选中数据路径
+
+      InterestClaEditInfo: {}, // 兴趣班编辑信息
+      InterestClaEditvisible: false, // 兴趣班编辑信息
+      interIsAdd: 0, // 0 添加 1 编辑
+
+      tableData: [], //表格数据
+      selectedData: [], //选中数据
+
+      page: 1,
+      total: 0,
+      pageSize: 10,
+      isLoading: false,
+      inp: "",
+
+      tableColumns: [
+        {
+          label: "学生信息",
+          prop: "username",
+        },
+        {
+          label: "账号",
+          prop: "acc",
+        },
+        {
+          label: "班级",
+          prop: "classname",
+        },
+      ],
+      studentColumns: [
+        {
+          label: "学生信息",
+          prop: "username",
+        },
+        {
+          label: "账号",
+          prop: "acc",
+        },
+        {
+          label: "班级",
+          prop: "classname",
+        },
+      ],
+      // 兴趣班表格列
+      tableInterestClaColumns: [
+        {
+          label: "班级信息",
+          prop: "name",
+        },
+        {
+          label: "学生人数",
+          prop: "pnum",
+        },
+        {
+          label: "创建时间",
+          prop: "create_at",
+        },
+      ],
+    };
+  },
+  watch: {
+    GrapTableData: {
+      handler(newVal) {
+        this.cascaderData = newVal;
+        // console.log(newVal);
+      },
+      immediate: true,
+    },
+    activeId(newVal) {
+      this.inp = "";
+      this.refresh();
+    },
+  },
+  methods: {
+    handleCheckedAllSelection(val) {
+      if (val) {
+        // 全选所有表格数据
+        this.tableData.forEach(row => {
+          this.$refs.tableData.toggleRowSelection(row, true);
+        });
+      } else {
+        // 取消全选
+        this.$refs.tableData.clearSelection();
+      }
+    },
+    editInterestCla(type,row) {
+      this.InterestClaEditvisible = true;
+      this.InterestClaEditInfo = row;
+      this.interIsAdd = type;
+    },
+    // 编辑兴趣班确定
+    confirmInterestClaEdit() {
+      this.InterestClaEditvisible = false;
+      this.InterestClaEditInfo = {};
+    },
+    // 删除班级
+    deleteCla(cid) {
+      let params = {
+        id: cid,
+      };
+      if (this.time()) {
+        this.$confirm("此操作将删除该班级,及班级所有已产生的授课数据, 是否继续?", "", {
+          cancelButtonText: "取消",
+          confirmButtonText: "确定",
+          showClose: false,
+          type: "warning",
+          customClass: "student-manage-delete-msgbox",
+        })
+          .then(() => {
+            this.ajax
+              .get(this.$store.state.api + "deleteClass", params)
+              .then((res) => {
+                this.$message({
+                  message: "删除成功",
+                  type: "success",
+                });
+                this.$emit("getGrade");
+              })
+              .catch((err) => {
+                this.$message.error("删除失败");
+                console.error(err);
+              });
+          })
+          .catch(() => {});
+      }
+    },
+    // 移动班级学生
+    moveSelStu() {
+      console.log("this.selectedData", this.selectedData);
+      // 先移除班级
+      let box = this.cascaderData
+        .flatMap((item) => item.children)
+        .find((item) => item.id == this.activeId);
+      this.moveClaCascaderDataPath = [box.pid, this.activeId];
+      console.log(this.moveClaCascaderDataPath, "this.moveClaCascaderDataPath");
+      this.moveClaVisible = true;
+    },
+    confirmMoveClaEdit() {
+      if (this.moveClaCascaderDataPath.length === 0) {
+        this.$message({
+          message: "请选择班级",
+          type: "error",
+        });
+        return;
+      }
+      this.$confirm("确定要移动该班级吗?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          // 先移出班级
+          const promises = this.selectedData.map((item) => {
+            item.classid = item.classid
+              .split(",")
+              .filter((item) => item != this.activeId)
+              .join(",");
+            return this.deleteClassStudent(item.userid);
+          });
+          Promise.all(promises)
+            .then(() => {
+              console.log("移除成功");
+
+              // 再移入班级
+              const promises2 = this.selectedData.map((item) => {
+                let box = [
+                  ...item.classid.split(","),
+                  this.moveClaCascaderDataPath[1],
+                ];
+                return this.moveClassStudentPromise(item, box.join(","));
+              });
+              Promise.all(promises2)
+                .then(() => {
+                  this.$message({
+                    message: "移动成功",
+                    type: "success",
+                  });
+                  this.moveClaVisible = false;
+                  this.moveClaCascaderDataPath = [];
+                  this.$emit("getGrade");
+                  this.refresh();
+                })
+                .catch((err) => {
+                  console.error(err);
+                  this.$message({
+                    message: "移动失败",
+                    type: "error",
+                  });
+                });
+            })
+            .catch(() => {});
+        })
+        .catch(() => {});
+    },
+    // 移动班级学生级联选中数据路径改变
+    handlemoveChangecascader(val) {
+      console.log(val);
+    },
+    moveClassStudentPromise(item, cid) {
+      return new Promise((resolve, reject) => {
+        let params = [
+          {
+            userid: item.userid,
+            username: item.acc,
+            alias: item.username,
+            ph: item.phonenumber,
+            sid: item.studentid,
+            cid: cid,
+          },
+        ];
+        console.log(params);
+
+        this.ajax
+          .post(this.$store.state.api + "updateStudentInfo", params)
+          .then((res) => {
+            resolve(res);
+          })
+          .catch((err) => {
+            console.error(err);
+            reject(err);
+          });
+      });
+    },
+    // 移除班级学生
+    removeSelStu() {
+      this.$confirm("确定要移除该班级吗?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          const promises = this.selectedData.map((item) => {
+            return this.deleteClassStudent(item.userid);
+          });
+          Promise.all(promises)
+            .then(() => {
+              this.$message({
+                message: "移除成功",
+                type: "success",
+              });
+              this.refresh();
+            })
+            .catch((err) => {
+              console.error(err);
+              this.$message({
+                message: "移除失败",
+                type: "error",
+              });
+              this.refresh();
+            });
+        })
+        .catch(() => {});
+    },
+    // 移除班级学生Promise
+    deleteClassStudent(id) {
+      return new Promise((resolve, reject) => {
+        let params = [{ uid: id, cid: this.activeId }];
+        this.ajax
+          .post(this.$store.state.api + "deleteClassStudent", params)
+          .then((res) => {
+            console.log("res", res);
+            resolve(res);
+          })
+          .catch((err) => {
+            console.error(err);
+            resolve(err);
+          });
+      });
+    },
+
+    // 修改班级名称弹框
+    editCla(row) {
+      this.ClaEditvisible = true;
+      this.ClaEditInfo = row;
+    },
+    // 修改班级确定
+    confirmClaEdit() {
+      let params = {
+        id: this.ClaEditInfo.id,
+        n: this.ClaEditInfo.name,
+        oid: this.oid,
+      };
+      this.ajax
+        .get(this.$store.state.api + "updateClass", params)
+        .then((res) => {
+          if (res.data[0] && res.data[0][0].classname == 1) {
+            this.$message({
+              message: this.lang.Cannotsameothercla,
+              type: "error",
+            });
+          } else {
+            this.$message({
+              message: this.lang.Editsuccessful,
+              type: "success",
+            });
+            this.$emit("getGrade");
+            this.ClaEditvisible = false;
+            this.ClaEditInfo = {};
+          }
+        })
+        .catch((err) => {
+          this.$message({
+            message: this.lang.Modificationfailed,
+            type: "error",
+          });
+          console.error(err);
+        });
+    },
+    // 修改学生信息
+    confirmEditStu() {
+      // this.stuEditvisible = false;
+      console.log(this.cascaderDataPath);
+      if (this.stuEditInfo.username === "") {
+        this.$message({
+          message: "请输入姓名",
+          type: "error",
+        });
+        return;
+      }
+      if (this.cascaderDataPath.length === 0) {
+        this.$message({
+          message: "请选择班级",
+          type: "error",
+        });
+        return;
+      }
+
+      let box = this.cascaderDataPath.map((item) => item[1]).join(",");
+      console.log(box);
+
+      console.log("this.stuEditInfo", this.stuEditInfo);
+
+      this.$confirm(
+        `确定要修改 ${this.stuEditInfo.username} 的学生信息吗?`,
+        "提示",
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        }
+      )
+        .then(() => {
+          this.update_Student(box);
+        })
+        .catch(() => {
+          return;
+        });
+    },
+    // 修改学生信息
+    update_Student(cid) {
+      let params = [
+        {
+          userid: this.stuEditInfo.userid,
+          username: this.stuEditInfo.acc,
+          alias: this.stuEditInfo.username,
+          ph: this.stuEditInfo.phonenumber,
+          sid: this.stuEditInfo.studentid,
+          cid: cid,
+        },
+      ];
+      // return console.log(params);
+      this.ajax
+        .post(this.$store.state.api + "updateStudentInfo", params)
+        .then((res) => {
+          this.$message({
+            message: this.lang.Editsuccessful,
+            type: "success",
+          });
+          this.stuEditvisible = false;
+          this.refresh();
+          this.stuEditInfo = {};
+          this.cascaderDataPath = [];
+        })
+        .catch((err) => {
+          this.isLoading = false;
+          this.$message({
+            message: this.lang.Modificationfailed,
+            type: "error",
+          });
+          console.error(err);
+        });
+    },
+    editStudent(row) {
+      this.stuEditvisible = true;
+      this.stuEditInfo = { ...row };
+      // 根据 classid 找到对应的路径数组(多选模式需要二维数组)
+      this.cascaderDataPath = row.classid
+        ? this.findCascaderPath(row.classid, this.cascaderData)
+        : [];
+    },
+    handleChangecascader(val) {
+      console.log(val);
+    },
+
+    findCascaderPath(classid, cascaderData) {
+      if (!classid || !cascaderData || cascaderData.length === 0) {
+        return [];
+      }
+      console.log("666");
+
+      // 解析逗号分隔的 classid 字符串
+      const classIds = classid
+        .split(",")
+        .map((id) => id.trim())
+        .filter((id) => id);
+      const result = [];
+
+      // 递归查找每个 classid 的完整路径
+      const findPath = (targetId, options, path = []) => {
+        for (let option of options) {
+          const currentPath = [...path, option.id];
+          // 如果是二级选项(班级),检查是否匹配
+          if (option.children && option.children.length > 0) {
+            for (let child of option.children) {
+              if (child.id === targetId) {
+                return [...currentPath, child.id];
+              }
+            }
+            // 递归查找子选项
+            const found = findPath(targetId, option.children, currentPath);
+            if (found) {
+              return found;
+            }
+          }
+        }
+        return null;
+      };
+
+      // 为每个 classid 查找路径
+      classIds.forEach((classId) => {
+        const path = findPath(classId, cascaderData);
+        if (path) {
+          result.push(path);
+        }
+      });
+
+      return result;
+    },
+
+    // 删除选中学生
+    deleteSelectionStudent() {
+      this.$confirm(
+        `确定要删除 ${this.selectedData.length} 个学生吗?`,
+        "提示",
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        }
+      )
+        .then(() => {
+          const promises = this.selectedData.map((item) => {
+            return this.deleteStudentPromise(item.userid, item.state);
+          });
+          Promise.all(promises)
+            .then(() => {
+              this.refresh();
+              this.cancelAllSelection();
+              this.$emit("getGrade");
+              this.$message({
+                message: "删除成功",
+                type: "error",
+              });
+            })
+            .catch((err) => {
+              console.error(err);
+              this.$message({
+                message: "部分删除失败,请重试",
+                type: "error",
+              });
+            });
+        })
+        .catch(() => {});
+    },
+    // 删除学生Promise
+    deleteStudentPromise(id, state) {
+      return new Promise((resolve, reject) => {
+        state = 0;
+        let params = [{ uid: id, state: state }];
+        this.ajax
+          .post(this.$store.state.api + "deleteStudent", params)
+          .then((res) => {
+            resolve(res);
+          })
+          .catch((err) => {
+            console.error(err);
+            reject(err);
+          });
+      });
+    },
+    // 删除学生
+    deleteStudentL(row, state) {
+      this.$confirm(`确定要删除 ${row.username} 吗?`, "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          state = 0;
+          let params = [{ uid: row.userid, state: state }];
+          this.ajax
+            .post(this.$store.state.api + "deleteStudent", params)
+            .then((res) => {
+              this.getAllStudent();
+              this.$message({
+                message: "删除成功",
+                type: "success",
+              });
+            })
+            .catch((err) => {
+              console.error(err);
+              this.$message({
+                message: "删除失败",
+                type: "error",
+              });
+            });
+        })
+        .catch(() => {});
+    },
+    // 刷新
+    refresh() {
+      this.page = 1;
+      this.pageSize = 10;
+      this.total = 0;
+      this.tableData = [];
+      if (this.boxType == 0) {
+        // 清除选中数据
+        this.cancelAllSelection();
+        this.getStudent();
+      } else if (this.boxType == 1) {
+        this.getInterestClass();
+      } else if (this.boxType == 2) {
+        this.getAllStudent();
+      }
+    },
+    // 重置密码
+    resetPassword() {
+      // return this.msgbox();
+      this.$confirm(
+        `确定要重置 ${this.selectedData.length} 个学生的密码吗?`,
+        "提示",
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        }
+      )
+        .then(() => {
+          const promises = this.selectedData.map((item) => {
+            return this.doResetPassword(item.userid);
+          });
+          Promise.all(promises)
+            .then(() => {
+              this.msgbox();
+              this.cancelAllSelection();
+            })
+            .catch((err) => {
+              console.error(err);
+              this.$message({
+                message: "部分密码重置失败,请重试",
+                type: "error",
+              });
+            });
+        })
+        .catch(() => {});
+    },
+    msgbox() {
+      const h = this.$createElement;
+      const password = "Coco1234";
+      const copyPassword = () => {
+        var textarea = document.createElement("textarea");
+        // 保存当前焦点元素
+        var currentFocus = document.activeElement;
+        // 将textarea添加到body中
+        document.body.appendChild(textarea);
+        // 设置textarea的值为传入的文本
+        textarea.value = "Coco1234";
+        // 让textarea获得焦点
+        textarea.focus();
+        // 为textarea设置选择范围,兼容性处理
+        if (textarea.setSelectionRange) {
+          textarea.setSelectionRange(0, textarea.value.length);
+        } else {
+          textarea.select();
+        }
+        // 尝试执行复制命令
+        try {
+          var flag = document.execCommand("copy");
+        } catch (eo) {
+          var flag = false;
+        }
+        // 移除textarea元素
+        document.body.removeChild(textarea);
+        // 将焦点返回之前的元素
+        currentFocus.focus();
+        // 返回复制是否成功
+        this.$message({
+          message: "密码已复制到剪贴板",
+          type: "success",
+        });
+        return flag;
+      };
+      this.$msgbox({
+        title: "",
+        message: h("div", { style: "padding-left: 30px;" }, [
+          h(
+            "p",
+            { style: "margin-bottom: 2px;" },
+            `对${this.selectedData.length}个账户重置密码成功!`
+          ),
+          h("p", { style: "margin: 0; display: flex; align-items: center;" }, [
+            h("span", null, "默认密码为:"),
+            h(
+              "span",
+              { style: "color: teal; font-weight: bold; margin: 0 8px;" },
+              password
+            ),
+            h(
+              "button",
+              {
+                on: {
+                  click: copyPassword,
+                },
+                style:
+                  "padding: 4px 8px; background: #409EFF; color: #fff; border: none; border-radius: 4px; cursor: pointer; font-size: 12px; display: inline-flex; align-items: center; gap: 4px;",
+              },
+              [h("i", { class: "el-icon-document-copy" })]
+            ),
+          ]),
+        ]),
+        showCancelButton: false,
+        showClose: false,
+        confirmButtonText: "确定",
+        type: "success",
+        customClass: "student-manage-reset-password-msgbox",
+      })
+        .then(() => {
+          // this.$message({
+          //   type: 'info',
+          //   message: 'action: ' + action
+          // });
+        })
+        .catch(() => {});
+    },
+    // 执行重置密码操作(返回Promise)
+    doResetPassword(id) {
+      return new Promise((resolve, reject) => {
+        let params = [
+          {
+            uid: id,
+            pa: "Coco1234",
+          },
+        ];
+        this.ajax
+          .post(this.$store.state.api + "iniPassword", params)
+          .then((res) => {
+            resolve(res);
+          })
+          .catch((err) => {
+            console.error(err);
+            reject(err);
+          });
+      });
+    },
+    inPassword() {
+      this.$confirm(
+        `确定要重置 ${this.stuEditInfo.username} 的密码吗?`,
+        "提示",
+        {
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+          type: "warning",
+        }
+      )
+        .then(() => {
+          let params = [
+            {
+              uid: this.stuEditInfo.userid,
+              pa: "Coco1234",
+            },
+          ];
+          this.ajax
+            .post(this.$store.state.api + "iniPassword", params)
+            .then((res) => {
+              this.$message({
+                message: "密码重置成功",
+                type: "success",
+              });
+            })
+            .catch((err) => {
+              this.$message({
+                message: "密码重置失败",
+                type: "error",
+              });
+            });
+        })
+        .catch(() => {});
+    },
+    // 导出学生
+    exportStudent() {
+      var res = this.selectedData;
+      //如果value的json字段的key值和想要的headers值不一致时,可做如下更改
+      //将和下面的Object.fromEntries结合,将json字段的key值改变为要求的excel的header值
+      var array = [];
+      for (var i = 0; i < res.length; i++) {
+        var _json = {};
+        _json["学生信息"] = res[i].username;
+        _json["账号"] = res[i].acc;
+        _json["班级"] = res[i].classname;
+        array.push(_json);
+      }
+
+      var XLSX = require("xlsx");
+      const workbook = XLSX.utils.book_new(); //创建一个新的工作簿对象
+      let ws = XLSX.utils.json_to_sheet(array); //将json对象数组转化成工作表
+      ws["!cols"] = [
+        //设置每一列的宽度
+        { wch: 20 },
+        { wch: 20 },
+        { wch: 20 },
+      ];
+      XLSX.utils.book_append_sheet(workbook, ws, "sheet1"); //把sheet添加到workbook里,第三个参数是sheet名
+      XLSX.writeFile(workbook, this.activeinfo.name + "学生列表.xlsx");
+      // const wopts = { bookType: "xlsx", bookSST: false, type: "array" };//写入的样式bookType:输出的文件类型,type:输出的数据类型,bookSST: 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
+      // const wbout = XLSX.write(workbook, wopts);// 浏览器端和node共有的API,实际上node可以直接使用xlsx.writeFile来写入文件,但是浏览器没有该API
+      // FileSaver.saveAs(new Blob([wbout], { type: "application/octet-stream" }), `${title} demo.xlsx`);//保存文件
+      this.$message({
+        message: "导出成功",
+        type: "success",
+      });
+      this.cancelAllSelection();
+    },
+    // 全选
+    handleSelectionChange(val) {
+      this.selectedData = val;
+      // 同步全选复选框状态:当选中数量等于表格数据数量时,全选复选框应该被选中
+      this.checkedAllSelection = val.length > 0 && val.length === this.tableData.length;
+    },
+
+    cancelAllSelection() {
+      this.$refs.tableData.clearSelection();
+      this.selectedData = [];
+      this.checkedAllSelection = false;
+    },
+    addStudent() {
+      console.log("添加学生");
+    },
+    closeEditStu() {
+      this.stuEditvisible = false;
+      this.stuEditInfo = {};
+    },
+    handlePageChange(val) {
+      console.log(`当前页: ${val}`);
+      this.page = val;
+      this.refresh();
+    },
+    handleSizeChange(val) {
+      console.log(`每页条数: ${val}`);
+      this.pageSize = val;
+      this.page = 1;
+      if (this.boxType == 0) {
+        this.getStudent();
+      } else if (this.boxType == 1) {
+        this.getInterestClass();
+      } else if (this.boxType == 2) {
+        this.getAllStudent();
+      }
+    },
+    getStudent() {
+      this.isLoading = true;
+      this.tableColumns = [];
+      this.tableColumns = this.studentColumns;
+      let params = {
+        oid: this.oid,
+        claid: this.activeId,
+        inp: this.inp,
+      };
+      this.ajax
+        .get(this.$store.state.api + "selectclaStu", params)
+        .then((res) => {
+          this.isLoading = false;
+          let box1 = res.data[0];
+          box1.forEach((e) => {
+            // e.acc = e.acc.split("@")[0];
+            if (e.classname && e.classname != "null") {
+              e.classname = e.classname.split("/");
+            } else {
+              e.classname = [];
+            }
+          });
+          this.tableData = res.data[0];
+        })
+        .catch((err) => {
+          this.isLoading = false;
+          console.error(err);
+        });
+    },
+    // 获取兴趣班
+    getInterestClass() {
+      this.isLoading = true;
+      this.tableColumns = this.tableInterestClaColumns;
+      let params = {
+        oid: this.oid,
+        inp: "",
+        page: this.page,
+        pageSize: this.pageSize,
+      };
+      this.ajax
+        .get(this.$store.state.api + "selectInterestcla", params)
+        .then((res) => {
+          this.isLoading = false;
+          this.total = res.data[0].length > 0 ? res.data[0][0].num : 0;
+          this.tableData = res.data[0];
+        })
+        .catch((err) => {
+          this.isLoading = false;
+          console.error(err);
+        });
+    },
+    // 学生管理全部学生
+    getAllStudent() {
+      this.isLoading = true;
+      this.cancelAllSelection();
+      this.tableColumns = this.studentColumns;
+      let params = {
+        oid: this.oid,
+        cid: "",
+        inp: this.inp,
+        page: this.page,
+        num: this.pageSize,
+      };
+      this.ajax
+        .get(this.$store.state.api + "selectStudentManage", params)
+        .then((res) => {
+          this.isLoading = false;
+          this.total = res.data[0].length > 0 ? res.data[0][0].num : 0;
+          let box1 = res.data[0];
+          box1.forEach((e) => {
+            if (e.classname && e.classname != "null") {
+              e.classname =
+                (e.gname !== null && e.gname !== undefined ? e.gname : "") +
+                e.classname;
+            } else {
+              e.classname = "-";
+            }
+          });
+          this.tableData = res.data[0];
+        })
+        .catch((err) => {
+          this.isLoading = false;
+          console.error(err);
+        });
+    },
+    time() {
+      if (!this.now) {
+        this.now = new Date().getTime();
+        return true;
+      } else {
+        let time = new Date().getTime();
+        if (time - this.now > 3000) {
+          this.now = time;
+          return true;
+        } else {
+          return false;
+        }
+      }
+    },
+  },
+};
+</script>
+
+<style>
+/* 学生管理表格操作弹窗样式 - 全局样式(Element UI popover 挂载到 body,需要全局样式) */
+.student-manage-action-popover {
+  width: 70px !important;
+  min-width: 60px !important;
+  padding: 0 !important;
+}
+
+.student-manage-action-popover .action_box > div {
+  padding: 8px 15px;
+  cursor: pointer;
+  font-size: 14px;
+  text-align: center;
+}
+.student-manage-action-popover .action_box > div:hover {
+  background: #e8f3ff;
+  color: #0052d9;
+}
+/* 学生管理重置密码消息框样式 - 全局样式(Element UI msgbox 挂载到 body,需要全局样式) */
+.student-manage-reset-password-msgbox .el-message-box__status {
+  top: 0 !important;
+  transform: none !important;
+  align-self: flex-start !important;
+}
+.student-manage-reset-password-msgbox .el-message-box__message {
+  padding-left: 0 !important;
+  display: flex !important;
+  align-items: flex-start !important;
+}
+.student-manage-reset-password-msgbox .el-message-box__message > p {
+  margin-top: 0 !important;
+}
+.student-manage-reset-password-msgbox .el-message-box__btns {
+  text-align: right !important;
+}
+.student-manage-reset-password-msgbox
+  .el-message-box__btns
+  .el-button--primary {
+  background-color: #409eff !important;
+  border-color: #409eff !important;
+  color: #fff !important;
+}
+.student-manage-reset-password-msgbox
+  .el-message-box__btns
+  .el-button--primary:hover {
+  background-color: #66b1ff !important;
+  border-color: #66b1ff !important;
+}
+/* 学生管理删除确认对话框样式 - 按钮右对齐 */
+.student-manage-delete-msgbox .el-message-box__btns {
+  text-align: right !important;
+}
+.myCascader
+  .el-cascader-panel
+  .el-cascader-menu:first-child
+  .el-scrollbar__wrap
+  ul
+  li
+  label,
+.myCascader
+  .el-cascader-panel
+  .el-cascader-menu:first-child
+  .el-scrollbar__wrap
+  ul
+  li
+  .el-checkbox {
+  display: none !important;
+}
+</style>
+
+<style scoped>
+.tabbox {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+}
+.topbox {
+  background: #fff;
+  height: 60px;
+  width: 100%;
+  background: #ffffff;
+  border-radius: 8px 8px 8px 8px;
+  padding: 5px 10px;
+  box-sizing: border-box;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+.topbox_area {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+.xk_img {
+  width: 20px;
+  height: 20px;
+  cursor: pointer;
+}
+.topbox_area >>> .el-input {
+  width: 150px;
+}
+.topbox_area >>> .el-input__inner {
+  height: 30px;
+  line-height: 30px;
+  width: 150px;
+}
+.topbox_area >>> .el-input__icon {
+  line-height: 30px;
+}
+.tabList {
+  flex: 1;
+  overflow: auto;
+  border-radius: 0 0 8px 8px;
+  display: flex;
+  flex-direction: column;
+  background: #fff;
+}
+.tableList >>> .has-gutter .gutter {
+  background: #e7eaf0 !important;
+}
+.tableList >>> .el-table__header-wrapper .el-checkbox {
+  display: none;
+}
+.cla_box {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+.cla_span {
+  background: #e8f3ff;
+  color: #0052d9;
+  padding: 0px 25px;
+  border-radius: 5px;
+  box-sizing: border-box;
+}
+.action_btn {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 5px;
+  cursor: pointer;
+  background: #f6f6f6;
+  padding: 7px 15px;
+  box-sizing: border-box;
+  font-size: 14px;
+  border-radius: 5px;
+}
+.action_btn2 {
+  background: #0052d9;
+  color: #fff;
+}
+.page_box {
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+  padding: 10px;
+  box-sizing: border-box;
+}
+.page_box_area {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  width: 100%;
+  /* padding: 0 10px; */
+  box-sizing: border-box;
+}
+.dia_box_item {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+.addcla_box_item {
+  min-height: 35px;
+  /* line-height: 30px; */
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+.addcla_box_item >>> .el-cascader {
+  width: 100%;
+}
+.addcla_box_item >>> .el-select {
+  width: 100%;
+}
+.addcla_box_item >>> .el-input__inner {
+  width: 100%;
+}
+.addcla_box_item >>> .el-input__icon {
+  width: 100%;
+}
+.addcla_box_item span {
+  width: 80px;
+  flex-shrink: 0;
+  text-align: right;
+}
+.tabbox >>> .el-dialog {
+  border-radius: 10px !important;
+}
+.dia_title_box {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+.dia_title_box span:nth-child(1) {
+  font-size: 16px;
+}
+.dia_title_box span:nth-child(2) {
+  font-size: 12px;
+  color: #689ce9;
+  cursor: pointer;
+  border-bottom: 1px solid #689ce9;
+}
+.cascader-class-item {
+  display: flex;
+  align-items: center;
+  gap: 5px;
+}
+.class-student-count {
+  color: #86909c;
+  font-size: 12px;
+}
+/* 隐藏一级选项(年级)的多选按钮 */
+.addcla_box_item
+  >>> .el-cascader-panel
+  .el-cascader-menu
+  .el-cascader-menu__wrap
+  .el-checkbox {
+  display: none !important;
+}
+.addcla_box_item >>> .el-cascader-menu:first-child .el-cascader-menu__item {
+  padding-left: 20px !important;
+}
+</style>

+ 358 - 0
src/components/pages/studentManageNew/index.vue

@@ -0,0 +1,358 @@
+<template>
+  <div class="box">
+    <div class="rigbox">
+      <div class="centerCss">
+        <img src="../../../assets/stuImg/riqi.svg" alt="" />
+        <span style="color: #86909c; font-size: 12px">年级管理</span>
+      </div>
+      <div class="Clabtn" @click="openaddClass">
+        <img src="../../../assets/stuImg/jia.svg" alt="" />
+        <span>新班级</span>
+      </div>
+
+      <el-menu
+        :default-active="activeId"
+        class="el-menu-vertical-demo"
+        v-loading="boxLoading"
+      >
+        <el-submenu v-for="item in tableData" :index="item.id" :key="item.id">
+          <template slot="title">
+            <span>{{ item.name }}</span>
+          </template>
+          <el-menu-item-group
+            v-for="k in item.children"
+            :key="k.id"
+            :title="k.name"
+          >
+            <el-menu-item :index="k.id" @click="handleClick(k.id, 0,k)">
+              <span>{{ k.name }}</span>
+              <span>({{ k.pnum }}人)</span>
+            </el-menu-item>
+          </el-menu-item-group>
+        </el-submenu>
+      </el-menu>
+      <div class="line"></div>
+      <div class="centerCss">
+        <img src="../../../assets/stuImg/inf.svg" alt="" />
+        <span style="color: #86909c; font-size: 12px">年级管理</span>
+      </div>
+      <div
+        class="por"
+        :class="{ active: boxType == 1 }"
+        @click="handleClick('1', 1)"
+      >
+        兴趣班
+      </div>
+      <div class="line"></div>
+      <div class="centerCss">
+        <img src="../../../assets/stuImg/per.svg" alt="" />
+        <span style="color: #86909c; font-size: 12px">学生管理</span>
+      </div>
+      <div
+        class="por"
+        :class="{ active: boxType == 2 }"
+        @click="handleClick('2', 2)"
+      >
+        学生列表
+      </div>
+    </div>
+    <div class="leftbox">
+      <tableL
+        :activeId="activeId"
+        :boxType="boxType"
+        :GrapTableData="cascaderData"
+        :activeinfo="activeinfo"
+        @getGrade="getGrade"
+      ></tableL>
+    </div>
+
+    <!-- 新增班级  -->
+    <el-dialog
+      title="添加班级"
+      :visible.sync="addClassVisible"
+      width="500px"
+      class="addClassDialog"
+    >
+      <div class="addcla_box">
+        <div class="addcla_box_item">
+          <span>所属年级:</span>
+          <el-select v-model="addclaGrade" placeholder="请选择年级">
+            <el-option
+              v-for="item in tableData"
+              :key="item.id"
+              :label="item.name"
+              :value="item.id"
+            ></el-option>
+          </el-select>
+        </div>
+        <div class="addcla_box_item">
+          <span>班级名称:</span>
+          <el-input
+            v-model="addclaName"
+            placeholder="请输入班级名称"
+          ></el-input>
+        </div>
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="addClassVisible = false">取 消</el-button>
+        <el-button type="primary" @click="addClass">确 定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import tableL from "./component/table.vue";
+export default {
+  components: {
+    tableL,
+  },
+  data() {
+    return {
+      userid: this.$route.query.userid,
+      org: this.$route.query.org,
+      oid: this.$route.query.oid,
+      role: this.$route.query.role,
+      boxLoading: false,
+      addClassVisible: false,
+
+      addclaName: "", // 新增班级名称
+      addclaGrade: "", // 新增班级所属年级
+
+      tableData: [],
+      cascaderData: [],
+
+      activeId: "", // 当前选中的班级id
+      activeinfo: {}, // 当前选中的班级信息
+
+      boxType: 0, // 0:年级, 1:兴趣班, 2:学生
+    };
+  },
+  methods: {
+    //获取年级列表
+    getGrade() {
+      this.boxLoading = true;
+      let params = {
+        oid: this.oid,
+      };
+      this.ajax
+        .get(this.$store.state.api + "selectGradeNew", params)
+        .then((res) => {
+          this.boxLoading = false;
+          let box1 = JSON.parse(JSON.stringify(res.data[0]));
+          let box2 = JSON.parse(JSON.stringify(res.data[1]));
+          let box3 = JSON.parse(JSON.stringify(res.data[0]));
+          let box4 = JSON.parse(JSON.stringify(res.data[1]));
+
+          box1.forEach((e) => {
+            e.children = [];
+            e.children = box2.filter((item) => item.pid == e.id);
+          });
+          if (box2.length) {
+            let box = ['1','2'];
+            if(this.activeId == '' || (this.activeId && box.indexOf(this.activeId) == -1)){
+              console.log('111');
+              
+              this.activeId = box2[0].id;
+              this.activeinfo = box2[0];
+            }
+          }
+
+          box3.push({id:0,name:"兴趣班",children:[]});
+          // 获取所有年级的id列表(不包括兴趣班id:0)
+          const gradeIds = box3.filter(e => e.id !== 0).map(e => e.id);
+          box3.forEach((e) => {
+            e.children = [];
+            e.children = box4.filter((item) => item.pid == e.id);
+            if (e.id === 0) {
+              e.children = box4.filter((item) => !gradeIds.includes(item.pid));
+            }
+          });
+
+          this.cascaderData = box3;
+          this.tableData = box1;
+        })
+        .catch((err) => {
+          this.boxLoading = false;
+          console.error(err);
+        });
+    },
+
+    openaddClass() {
+      this.addClassVisible = true;
+    },
+    // 新增班级
+    addClass() {
+      if (!this.addclaName) {
+        this.$message({
+          message: "请输入班级名称",
+          type: "error",
+        });
+        return;
+      }
+      //新增班级
+      let params = [
+        {
+          claName: this.addclaName,
+          gid: this.addclaGrade,
+          oid: this.oid,
+          uid: this.userid,
+        },
+      ];
+      console.log(params);
+
+      this.ajax
+        .post(this.$store.state.api + "addClassgra", params)
+        .then((res) => {
+          if (res.data[0] && res.data[0][0].classname == 1) {
+            this.$message({
+              message: this.lang.Cannotsameothercla,
+              type: "error",
+            });
+          } else {
+            this.$message({
+              message: this.lang.AddSuccessful,
+              type: "success",
+            });
+            this.addClassVisible = false;
+            this.addclaName = "";
+            this.addclaGrade = "";
+            this.getGrade();
+          }
+        })
+        .catch((err) => {
+          this.$message({
+            message: this.lang.Additionfailed,
+            type: "error",
+          });
+          console.error(err);
+        });
+    },
+
+    // 切换班级
+    handleClick(id, index,item = {}) {
+      this.boxType = index;
+      this.activeId = id;
+      this.activeinfo = item;
+    },
+  },
+  mounted() {
+    this.getGrade();
+  },
+};
+</script>
+
+<style scoped>
+.box {
+  padding: 15px;
+  box-sizing: border-box;
+  background: #e7eaf0;
+  display: flex;
+  gap: 15px;
+  width: 100%;
+  height: 100%;
+}
+.rigbox {
+  background: #fff;
+  height: 100%;
+  width: 166px;
+  background: #ffffff;
+  border-radius: 8px 8px 8px 8px;
+  padding: 10px;
+  flex-shrink: 0;
+  box-sizing: border-box;
+  display: flex;
+  flex-direction: column;
+  gap: 15px;
+  overflow: auto;
+}
+.leftbox {
+  flex: 1;
+}
+.centerCss {
+  display: flex;
+  align-items: center;
+  gap: 5px;
+}
+.Clabtn {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 3px;
+  color: #0052d9;
+  background: #e8f3ff;
+  border-radius: 3px;
+  padding: 5px 0;
+  cursor: pointer;
+}
+.rigbox >>> .el-menu {
+  border: none;
+}
+.rigbox >>> .el-menu {
+  border: none;
+}
+.rigbox >>> .el-menu-item-group__title {
+  display: none;
+}
+.rigbox >>> .el-menu li {
+  padding: 0 !important;
+}
+.rigbox >>> .el-submenu .el-menu-item {
+  min-width: 146px !important;
+  max-width: 146px;
+  height: 35px;
+  display: flex;
+  align-items: center;
+  padding-left: 30px !important;
+}
+.rigbox >>> .el-menu-item.is-active {
+  color: #fff;
+  background: #0052d9;
+  border-radius: 5px;
+}
+.rigbox >>> .el-submenu__title {
+  height: 35px;
+  display: flex;
+  align-items: center;
+}
+.el-menu-item:focus,
+.el-menu-item:hover {
+  background: none;
+}
+.line {
+  height: 1px;
+  background: #e6eaf0;
+  margin: 5px 0;
+}
+.por {
+  cursor: pointer;
+  padding: 5px;
+  box-sizing: border-box;
+}
+.active {
+  background: #0052d9;
+  border-radius: 5px;
+  color: #fff;
+}
+.addcla_box {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+.addcla_box_item {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+.addcla_box_item >>> .el-select {
+  width: 100%;
+}
+.addcla_box_item span {
+  width: 80px;
+  flex-shrink: 0;
+  text-align: right;
+}
+.addClassDialog >>> .el-dialog {
+  border-radius: 10px !important;
+}
+</style>

+ 9 - 0
src/router/index.js

@@ -155,6 +155,7 @@ import teacherDevelop from '@/components/pages/liyuan/teacherDevelop'
 import userInfoL from '@/components/pages/liyuan/page/userInfoL'
 import examineL from '@/components/pages/liyuan/page/examine'
 import examineperson from "@/components/pages/liyuan/page/examineperson";
+import studentManageNew from '@/components/pages/studentManageNew'
 
 import portraitL from '@/components/pages/liyuan/page/portrait'
 import teadTest from '@/components/pages/liyuan/page/teadTest'
@@ -223,6 +224,14 @@ export default new Router({
     meta: {
       requireAuth: ''
     }
+  },
+    {
+    path: '/studentManageNew',
+    name: 'studentManageNew',
+    component: studentManageNew,
+    meta: {
+      requireAuth: '' // 是否需要判断是否登录,这里是需要判断
+    }
   },
   {
     path: '/teacherType',

Некоторые файлы не были показаны из-за большого количества измененных файлов