| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667 |
- <template>
- <div class="dia_box" v-loading="boxLoading">
- <div class="dia_box_item">
- <div class="addcla_box_item">
- <span class="addcla_box_item_span">{{ lang.ssTargetClass }}</span>
- <el-cascader
- :options="cascaderData"
- v-model="cascaderDataPath"
- @change="handleChangecascader"
- 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>
- <div class="addcla_box_item" style="position: relative">
- <span class="addcla_box_item_span">{{ lang.ssSearchStuLbl }}</span>
- <el-input
- v-model.trim="searchStuName"
- :placeholder="lang.ssEnterStuNameMul"
- slot="reference"
- @change="searchStu"
- @focus="popoverVisible = true"
- ></el-input>
- <div
- class="search_stu_box"
- v-if="popoverVisible"
- v-loading="editTabloading"
- >
- <div class="search_stu_box_content">
- <el-tag
- v-for="item in searchStuData"
- :key="item.userid"
- closable
- :type="item.acc"
- @close="handleClose(item)"
- >
- <el-tooltip
- class="item"
- effect="dark"
- :content="item.acc"
- placement="top-start"
- >
- <span>{{ item.username }}</span>
- </el-tooltip>
- </el-tag>
- </div>
- <div class="search_stu_box_footer">
- <div>{{ lang.ssInputStuCnt.replace(/\*/g, searchStuData.length) }}</div>
- <div class="dialog-footer">
- <!-- <el-button size="small" @click="selectNoneStu">取消</el-button> -->
- <div @click="selectNoneStu" class="kbtn">{{ lang.Cancel }}</div>
- <div @click="selectStu" class="kbtn" style="background: #3681FC; color: #E3EDFF;">{{ lang.Confirm }}</div>
- <!-- <el-button size="small" type="primary" @click="selectStu"
- >确认</el-button
- > -->
- </div>
- </div>
- </div>
- </div>
- <div class="addcla_box_item">
- <span class="addcla_box_item_span">{{ lang.Selected }}:</span>
- <div class="selected_stu_box">
- <el-tag
- v-for="(item, index) in selectedStuData"
- :key="index"
- closable
- :type="item.acc"
- @close="handleSelectedStuClose(item)"
- >
- <el-tooltip
- class="item"
- effect="dark"
- :content="item.acc"
- placement="top-start"
- >
- <span>{{ item.username }}</span>
- </el-tooltip>
- </el-tag>
- </div>
- </div>
- <div style="width: 100%">{{ lang.ssSelectStuTip }}</div>
- <el-table
- :data="allClaAllStuData"
- ref="tableData"
- style="width: 100%"
- :header-cell-style="{ background: '#E7EAF0' }"
- height="300px"
- :show-header="false"
- class="tableList"
- v-loading="tableLoading || confirmLoading"
- @selection-change="handleInterestClaSelectionChange"
- >
- <el-table-column
- type="selection"
- :selectable="checkSelectable"
- width="55px"
- >
- </el-table-column>
- <el-table-column
- v-for="(item, index) in allClaColumns"
- :key="index"
- :label="item.label"
- :min-width="item.width"
- >
- <template slot-scope="scope">
- <div v-if="item.label == lang.Account">
- <span>{{ scope.row.acc.split("@")[0] }}</span>
- </div>
- <div class="cla_box" v-else-if="item.label == lang.Class">
- <span
- class="cla_span"
- v-for="(cla, ind) in scope.row.classname.split('/')"
- :key="ind + 'cla'"
- >
- {{ cla }}
- </span>
- </div>
- <div v-else>
- <span>{{ scope.row[item.prop] }}</span>
- </div>
- </template>
- </el-table-column>
- </el-table>
- <div class="page_box">
- <div>
- {{ lang.ssPageInfoL
- .replace(/\*/g, (page - 1) * pageSize + 1)
- .replace(/\#/g, page * pageSize)
- .replace(/\$/g, total)
- }}
- </div>
- <el-pagination
- background
- @current-change="handlePageChange"
- :current-page.sync="page"
- :page-size="pageSize"
- layout="prev, pager, next"
- :total="total"
- >
- </el-pagination>
- </div>
- </div>
- <div class="dialog-footer">
- <div class="kbtn" @click="closeAllClaAddStu">{{ lang.Cancel }}</div>
- <div @click="confirmAllClaAddStu" class="kbtn" style="background: #3681FC; color: #E3EDFF;">{{ lang.Confirm }}</div>
- </div>
- <div class="pop-upBox">
- <el-dialog
- :visible.sync="popBoxdia"
- width="480px"
- append-to-body
- class="upBox"
- :show-close="false"
- >
- <div class="msgCon">
- <img style="width: 20px;" src="../../../../assets/stuImg/duil.svg" alt="">
- <div class="msgContxt" v-if="selectedStuData.length">
- {{ selectedStuData[0].username + lang.ssAddStuSucc.replace(/\*/g, selectedStuData.length) }}
- </div>
- </div>
- <span slot="footer" class="dialog-footer">
-
- <el-button type="primary"
- class="btnpop"
- @click="confirmDelStu"
- >{{ lang.Confirm }}</el-button
- >
- </span>
- </el-dialog>
- </div>
- </div>
- </template>
- <script>
- import { myMixin } from "@/mixins/mixin.js"
- export default {
- mixins: [ myMixin ],
- name: "allClaAddStu",
- props: {
- classInfo: {
- type: Object,
- default: () => {},
- },
- },
- data() {
- return {
- userid: this.$route.query.userid,
- org: this.$route.query.org,
- oid: this.$route.query.oid,
- role: this.$route.query.role,
- boxLoading: false,
- tableLoading: false,
- editTabloading: false,
- confirmLoading: false,
- cascaderDataPath: [],
- cascaderData: [],
- searchStuName: "",
- searchStuData: [],
- selectedStuData: [],
- popoverVisible: false,
- allClaAllStuData: [],
- page: 1,
- popBoxdia:false,
- total: 0,
- pageSize: 10,
- allClaColumns: [
- {
- label: this.lang.StudentName,
- prop: "username",
- width: "30%",
- },
- {
- label: this.lang.Account,
- prop: "acc",
- width: "30%",
- },
- {
- label: this.lang.Class,
- prop: "classname",
- width: "40%",
- },
- ],
- };
- },
- methods: {
- clearData(){
- this.cascaderDataPath = [];
- this.searchStuName="";
- this.searchStuData= [];
- this.selectedStuData= [];
- this.allClaAllStuData=[];
- this.page= 1;
- this.total=0;
- this.pageSize= 10;
- },
- confirmDelStu(){
- this.$refs.tableData.clearSelection();
- this.selectedStuData = [];
- this.popBoxdia = false;
- },
- // 删除已选择学生
- handleSelectedStuClose(item) {
- // 从已选择数据中移除
- this.selectedStuData = this.selectedStuData.filter(
- (e) => e.userid !== item.userid
- );
- // 如果该学生在当前页的表格中,取消其选中状态
- this.$nextTick(() => {
- if (this.$refs.tableData) {
- const row = this.allClaAllStuData.find(
- (row) => row.userid === item.userid
- );
- if (row) {
- this.$refs.tableData.toggleRowSelection(row, false);
- }
- }
- });
- },
- closeAllClaAddStu() {
- this.$emit("closeAllClaAddStu");
- },
- confirmAllClaAddStu() {
- if (this.confirmLoading) {
- this.$message.warning(this.lang.ssUploading);
- return;
- }
- if (this.selectedStuData.length === 0) {
- this.$message({
- message: this.lang.ssSelectStu,
- type: "error",
- });
- return;
- }
- console.log("上传学生数据");
- this.confirmLoading = true;
- const promises2 = this.selectedStuData.map((item) => {
- let box = [...item.classid.split(","), this.classInfo.id];
- box = box.filter((item) => item != "");
- return this.moveClassStudentPromise(item, box.join(","));
- });
- Promise.all(promises2)
- .then(() => {
- this.popBoxdia = true
- this.$emit("getStudent");
- if (this.cascaderDataPath.length > 0) {
- this.getdata(this.cascaderDataPath[1]);
- }
- this.addOp3('1', "", { type: "student_move" }, "success")
- })
- .catch((err) => {
- console.error(err);
- this.$message({
- message: this.lang.ssMoveStuFail,
- type: "error",
- });
- this.addOp3('1', "", { type: "student_move" }, err)
- })
- .finally(() => {
- this.confirmLoading = false;
- });
- },
- 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);
- });
- });
- },
- handleChangecascader(val) {
- console.log(val);
- this.getdata(val[1]);
- },
- selectNoneStu() {
- this.popoverVisible = false;
- this.searchStuName = "";
- this.searchStuData = [];
- },
- searchStu() {
- if (!this.searchStuName) {
- this.$message({
- message: this.lang.enterstuname,
- type: "error",
- });
- return;
- }
- this.editTabloading = true;
- // 处理输入:去除多余空格,确保逗号分隔格式正确
- let inpValue = this.searchStuName
- .split(",")
- .map((name) => name.trim())
- .filter((name) => name)
- .join(",");
- console.log('inpValue',inpValue);
- let params = [{
- oid: this.oid,
- inp: inpValue,
- }];
- this.ajax
- .post(this.$store.state.api + "selectchStu", params)
- .then((res) => {
- console.log(res.data[0], "res");
- let box = res.data[0].filter(
- (item) => item.classid.indexOf(this.classInfo.id) == -1
- );
- this.searchStuData = box;
- this.editTabloading = false;
- })
- .catch((err) => {
- this.editTabloading = false;
- console.error(err);
- });
- },
- handleClose(item) {
- this.searchStuData = this.searchStuData.filter((e) => e !== item);
- },
- selectStu() {
- this.popoverVisible = false;
- const existingIds = new Set(
- this.selectedStuData.map((item) => item.userid)
- );
- // 过滤掉重复的,只添加新的学生
- const newStuData = this.searchStuData.filter(
- (item) => !existingIds.has(item.userid)
- );
- this.selectedStuData.push(...newStuData);
- this.handleSelectedStuData(this.selectedStuData);
- this.searchStuData = [];
- this.searchStuName = "";
- },
- handleInterestClaSelectionChange(val) {
- const currentPageIds = new Set(
- (this.allClaAllStuData || []).map((row) => row.userid)
- );
- const otherPageSelected = (this.selectedStuData || []).filter(
- (item) => !currentPageIds.has(item.userid)
- );
- this.selectedStuData = [...otherPageSelected, ...val];
- },
- checkSelectable(row) {
- return row.classid.indexOf(this.classInfo.id) == -1; // 状态为disabled的行禁用选择
- },
- handlePageChange(val) {
- this.page = val;
- this.getdata(this.cascaderDataPath[1]);
- },
- //获取年级列表
- getGrade() {
- this.boxLoading = true;
- let params = {
- oid: this.oid,
- };
- this.ajax
- .get(this.$store.state.api + "selectGradeNew", params)
- .then((res) => {
- this.boxLoading = false;
- let box3 = JSON.parse(JSON.stringify(res.data[0]));
- let box4 = JSON.parse(JSON.stringify(res.data[1]));
- box3.forEach((e) => {
- e.children = [];
- e.children = box4.filter((item) => item.pid == e.id);
- });
- this.cascaderData = box3;
- })
- .catch((err) => {
- this.boxLoading = false;
- console.error(err);
- });
- },
- getdata(cid) {
- this.tableLoading = true;
- let params = {
- oid: this.oid,
- cid: cid,
- inp: "",
- page: this.page,
- num: this.pageSize,
- };
- this.ajax
- .get(this.$store.state.api + "selectStudentManage", params)
- .then((res) => {
- this.total = res.data[0].length > 0 ? res.data[0][0].num : 0;
- this.allClaAllStuData = res.data[0];
- this.tableLoading = false;
- this.handleSelectedStuData(this.selectedStuData);
- })
- .catch((err) => {
- this.tableLoading = false;
- console.error(err);
- });
- },
- // 恢复表格选中状态
- handleSelectedStuData(val) {
- this.$nextTick(() => {
- if (this.$refs.tableData && val.length > 0) {
- const selectedIds = new Set(val.map((item) => item.userid));
- this.allClaAllStuData.forEach((row) => {
- if (selectedIds.has(row.userid)) {
- this.$refs.tableData.toggleRowSelection(row, true);
- }
- });
- }
- });
- },
- },
- mounted() {
- this.getGrade();
- },
- };
- </script>
- <style>
- .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;
- }
- .myCascader .el-cascader-panel{
- width: 670px !important;
- }
- .myCascader .el-cascader-menu__list{
- width: 335px;
- }
- </style>
- <style scoped>
- .upBox >>> .el-dialog{
- border-radius: 8px !important;
- margin-top: 30vh !important;
- }
- .upBox >>> .el-dialog__body{
- padding: 10px 23px;
- }
- .dia_box_item {
- display: flex;
- align-items: center;
- gap: 10px;
- }
- .dia_box_item {
- display: flex;
- flex-direction: column;
- gap: 10px;
- }
- .addcla_box_item {
- min-height: 35px;
- /* line-height: 30px; */
- width: 100%;
- 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 > .addcla_box_item_span {
- width: 80px;
- flex-shrink: 0;
- text-align: right;
- }
- .tableList >>> .el-table__body-wrapper {
- height: 350px;
- }
- .cla_span {
- background: #e8f3ff;
- color: #0052d9;
- padding: 5px 10px;
- border-radius: 5px;
- box-sizing: border-box;
- }
- .search_stu_box {
- width: 670px;
- position: absolute;
- display: flex;
- flex-direction: column;
- top: 100%;
- left: 90px;
- z-index: 1000;
- min-height: 110px;
- background: #fff;
- border: 1px solid #e8f3ff;
- box-sizing: border-box;
- border-radius: 2px;
- box-shadow: 0px 5px 5px -3px rgba(0,0,0,0.1), 0px 8px 10px 1px rgba(0,0,0,0.06), 0px 3px 14px 2px rgba(0,0,0,0.05);
- }
- .search_stu_box_content {
- display: flex;
- gap: 10px;
- flex: 1;
- padding: 10px;
- flex-wrap: wrap;
- box-sizing: border-box;
- }
- .selected_stu_box_item {
- background: #e8f3ff;
- padding: 0px 10px;
- height: 30px;
- line-height: 30px;
- border-radius: 5px;
- box-sizing: border-box;
- }
- .search_stu_box_footer {
- display: flex;
- height: 40px;
- padding: 0 10px;
- box-sizing: border-box;
- justify-content: space-between;
- align-items: center;
- box-sizing: border-box;
- border-top: 1px #e7e7e7 solid;
- }
- .selected_stu_box {
- display: flex;
- flex-wrap: wrap;
- gap: 10px;
- }
- .page_box {
- display: flex;
- gap: 10px;
- width: 100%;
- align-items: center;
- }
- .cla_box {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: 5px;
- }
- .dialog-footer {
- display: flex;
- justify-content: flex-end;
- gap: 10px;
- }
- .msgCon{
- display: flex;
- gap: 10px;
- align-items: flex-start;
- box-sizing: border-box;
- }
- .msgContxt{
- display: flex;
- flex-direction: column;
- gap: 10px;
- font-size: 16px;
- color: #000000;
- }
- .btnpop{
- width: 60px !important;
- height: 32px !important;
- display: flex;
- align-items: center;
- justify-content: center;
- background: #3681FC;
- }
- .kbtn{
- text-align: center;
- padding: 8px 14px;
- cursor: pointer;
- border-radius: 3px;
- box-sizing: border-box;
- font-size: 14px;
- }
- .dialog-footer {
- display: flex;
- justify-content: flex-end;
- gap: 10px;
- }
- </style>
|