Răsfoiți Sursa

添加编号对应页面内容

lm 1 lună în urmă
părinte
comite
97c6a33078

+ 67 - 0
src/api/numberMappingComponent.ts

@@ -0,0 +1,67 @@
+import request from '../utils/request.js'
+let teacherPrefix = import.meta.env.VITE_API_TEACHER_PRE 
+
+// 查询可选班级列表数据
+export const getAlternativeClassDataApi = (data:any) => {
+    return request({
+        url: `${teacherPrefix}/api/v1/codeBind/queryClassData`,
+        method: 'post',
+        data
+    })
+}
+
+
+// 查询班级编号对应表格数据
+export const getClassNumberMappingDataApi = (data:any) => {
+    return request({
+        url: `${teacherPrefix}/api/v1/codeBind/queryCodeBindData`,
+        method: 'post',
+        data
+    })
+}
+
+// 添加编号对应的单元格数据
+export const setClassNumberMappingDataApi = (data:any) => {
+    return request({
+        url: `${teacherPrefix}/api/v1/codeBind/setCodeBindData`,
+        method: 'post',
+        data
+    })
+}
+
+// 删除一行班级数据
+export const deleteRowClassNumberMappingDataApi = (data:any) => {
+    return request({
+        url: `${teacherPrefix}/api/v1/codeBind/deleteCodeBindByCode`,
+        method: 'post',
+        data
+    })
+}
+
+
+// 增加一行班级编号数据
+export const addRowClassNumberMappingDataApi = (data:any) => {
+    return request({
+        url: `${teacherPrefix}/api/v1/codeBind/addCustomClass`,
+        method: 'post',
+        data
+    })
+}
+
+// 编号对应完成操作
+export const finishNumberMappingDataApi = (evaluationId:any) => {
+    return request({
+        url: `${teacherPrefix}/api/v1/codeBind/finishCodeBind/${evaluationId}`,
+        method: 'get',
+    })
+}
+
+
+
+// 删除编号对应关系中的一个班级数据
+export const deleteCodeMappinClassApi = (id:any) => {
+    return request({
+        url: `${teacherPrefix}/api/v1/codeBind/deleteCodeBindData/${id}`,
+        method: 'get',
+    })
+}

+ 0 - 3
src/components/ReviewManagementDetailSideBar.vue

@@ -133,9 +133,6 @@ const stepMsgs = computed(()=>[
       'generateReviewCode',
     ],
     isFinish:store.state.evaluationManageStepData.isFinishReviewAccount,
-
-
-    
     isGenerateReviewCode:store.state.evaluationManageStepData.isGenerateReviewCode,  //是否已生成评价码
   },
   // ^^^^^ =========================

+ 14 - 15
src/views/reviewManagement/ReviewManagementDetail.vue

@@ -21,7 +21,7 @@ import GenerateReviewCode from './stepComponent/reviewAccountComponent/GenerateR
 import ParameterSettingComponent from './stepComponent/parameterSettingComponent/ParameterSettingComponent.vue';
 import EvaluationProgressComponent from './stepComponent/evaluationProgressComponent/EvaluationProgressComponent.vue';
 import GenerateAnalysisComponent from './stepComponent/generateAnalysisComponent/GenerateAnalysisComponent.vue';
-
+import NumberMappingComponent from './stepComponent/numberMappingComponent/NumberMappingComponent.vue';
 
 
 const route = useRoute()
@@ -29,30 +29,29 @@ const router = useRouter()
 
 const curentComponent = computed(()=>{
   switch(route.params.stepRoute){
-    case 'evaluationData':
+    case 'evaluationData':  //评价数据
       return EvaluationDataComponent
-    case 'teachingRelationship':
+    case 'teachingRelationship':   //授课关系
       return TeachingRelationshipComponent
-    case 'questionnaireTemplate':
+    case 'questionnaireTemplate':    //问卷模板
       return QuestionnaireTemplateComponent
-    case 'reviewAccount':
+    case 'reviewAccount':   //评价账号
       return ReviewAccountComponent
-    case 'generateReviewCode':
+    case 'generateReviewCode':  // 评价账号生成
       return GenerateReviewCode
-    case 'parameterSetting':
+    case 'parameterSetting':    //参数设置
       return ParameterSettingComponent
-    case 'evaluationProgress':
+    case 'evaluationProgress':   //评价进度
       return EvaluationProgressComponent
-    case 'generateAnalysis':
+    case 'generateAnalysis':  //生成分析
       return GenerateAnalysisComponent
-      
-    case 'numberMapping':
-      break
-    case 'templateSetting':
+    case 'numberMapping':  //编号对应
+      return NumberMappingComponent
+    case 'templateSetting':   //模板设置
       break
-    case 'scoreSetting':
+    case 'scoreSetting':    // 分数设置
       break
-    case 'scanQuestionnaire':
+    case 'scanQuestionnaire':   // 扫描问卷
       break
     default:
       router.replace('/login')

+ 514 - 0
src/views/reviewManagement/stepComponent/numberMappingComponent/NumberMappingComponent.vue

@@ -0,0 +1,514 @@
+<template>
+
+    <div class="page_item  page_search number_mapping_content">
+        <div class="search_content">
+            <!--  班级类型切换 -->
+            <div class="content_left">
+            <TabSearch 
+                class="grade_tab"
+                tabType="box" 
+                :tabList="gradeList" 
+                :defaultTabKey="defaultTabkey"
+                @tabChange="(val)=>HandleTabChange(val)">
+            </TabSearch>
+            </div>
+            <div class="content_right">
+            <el-button class="button_background" @click="FinishNumberMapping">完成</el-button>
+            </div>
+        </div>
+        
+        <div class="page_jg_20"></div>
+
+        <div class="main_content">
+            <div class="container_left">
+                <div class="search_content">
+                    <div class="content_left">
+                        <div class="grade_title">可选班级</div>
+                    </div>
+                </div>
+                <div class="page_jg_20"></div>
+
+            
+              <Table 
+                  :hidePagination="true"
+                  class="teacher_table"
+                  :currentPage="1" :totalNum="0" 
+                  :pageSize="200" :tableColumns="classTableColumns" 
+                  :tableData="classList"
+                  :tableRowClassName="tableRowClassName"
+                  @rowClick="HandleSelectRowClass"
+                  ></Table>
+            </div>
+            <div class="container_right">
+            
+            <div class="search_content">
+                <div class="content_left">
+                  <div  class="grade_title">班级编号对应表</div>
+                </div>
+                <div class="content_right">
+                  <span v-if="isConfigMode" class="config_switch_desc">
+                    {{ selectedClassItm?.id ? `当前选中的班级:${selectedClassItm.gradeName } ${selectedClassItm.className}` : '暂无选中的班级' }}
+                  </span>
+                  <el-switch v-model="isConfigMode" 
+                    style="--el-switch-on-color: #2E64FA"
+                    active-text="选中班级配置编号关系" />
+                    <el-button class="button_border" @click="AddOneRowClassCode">新增班级编号</el-button>
+                </div>
+            </div>
+
+            <div class="page_jg_20"></div>
+
+            <div class="end_item">
+                <Table  :currentPage="1" :pageSize="2"
+                    :tableColumns="filterNumberMappingTableColumns" 
+                    :tableData="administrativeClassTableData" 
+                    :hidePagination="true"
+                    :totalNum="0">
+                  
+                    <template v-for="column in filterNumberMappingTableColumns.slice(1,-1)" :key="column.name"   v-slot:[column.name]="{row}"> 
+                      <div class="cell_container" @click="HandleAddClassBindCode(row, column.name)">
+                        <template v-if="row?.[column.name] && row?.[column.name]?.length > 0">
+                            <div v-for="(classItm, idx) in row?.[column.name]" :key="classItm.id">
+                                <el-tooltip
+                                effect="dark"
+                                :content="`${classItm.gradeName} ${classItm.className}`"
+                                placement="top-start"
+                                >
+                                <div v-if="isConfigMode" class="teacher_tag">
+                                    <span :title="classItm.className">{{ classItm.className }}</span>
+                                    <el-icon class="delete_icon" @click.stop="HandleRemoveCodeMappinClass(row, column.name, idx)"><Close /></el-icon>
+                                </div>
+                                <div v-else class="disabled_teacher">
+                                    <span :title="classItm.className">{{ classItm.className }}</span>
+                                </div>
+                                </el-tooltip>
+                            </div>
+                          </template>
+                          <template v-else>
+                          <span v-if="isConfigMode" class="placeholder_text" >请选择班级</span>
+                          <span v-else>-</span>
+                          </template>
+                      </div>
+                    </template>
+
+                    <template #operation="{row,currentIndex}">
+                      <div class="table_row_option">
+                        <span 
+                          :class="[administrativeClassTableData?.length === currentIndex ? 'el_button_delete' : 'editor_disable']" 
+                          @click="administrativeClassTableData?.length === currentIndex ? HandleDeleteRowClassCode(row) : ''">删除</span>
+                      </div>
+                    </template>
+                </Table>
+            </div>
+            </div>
+        </div>
+
+  </div>
+</template>
+
+
+<script setup lang="ts">
+import { ref, onMounted, computed } from 'vue';
+import { useRoute } from 'vue-router';
+import { useStore } from 'vuex';
+
+import { Close } from '@element-plus/icons-vue';
+import Table from '@/baseComponents/Table.vue';
+import TabSearch from '@/baseComponents/TabSearch.vue';
+import {
+  getAlternativeClassDataApi,
+  getClassNumberMappingDataApi,
+  setClassNumberMappingDataApi,
+  deleteRowClassNumberMappingDataApi,
+  addRowClassNumberMappingDataApi,
+  finishNumberMappingDataApi,
+  deleteCodeMappinClassApi,
+} from '@/api/numberMappingComponent'
+
+import {numberMappingTableColumns,classTableColumns,} from './table'
+import { ElMessage } from 'element-plus';
+import router from '@/router';
+
+const route = useRoute()
+const store = useStore()
+
+// 配置模式开关
+const isConfigMode = ref(true);
+
+
+// 查询参数
+const searchParmams = ref({
+  subjectId: '0',   //科目ID
+  // "classCode": 0,
+  type: 0           //类型,0-行政班,1-教学班
+})
+
+const  defaultTabkey = computed(()=>{
+  return JSON.stringify({
+    subjectId: searchParmams.value.subjectId,  // 科目id
+    type:searchParmams.value.type  //  类型,0-行政班,1-教学班
+  })
+})
+// 年级列表
+interface GradeItm {
+  label:string,
+  key:string
+}
+const gradeList = ref<GradeItm[]>([])
+
+
+// 获取班级类型列表信息
+const GetClassTypeList = async(subjectData)=>{
+  if(subjectData?.length >0){
+    gradeList.value = subjectData.map((item,index)=>{
+      return {
+        label:item.name,
+        key:JSON.stringify({
+          subjectId: item.subjectId,  // 科目id
+          type:item.type     //  类型,0-行政班,1-教学班
+        }),  
+      }
+    }) || []
+
+    // 待确认——————
+    searchParmams.value.type = JSON.parse(gradeList.value[0].key).type
+    searchParmams.value.subjectId = JSON.parse(gradeList.value[0].key).subjectId     
+  }
+}
+
+
+// 2. 班级列表数据
+interface ClassItm {
+  id: string
+  className: string
+  gradeName: string
+}
+const classList = ref<ClassItm[]>([]);
+// 选中的班级ID
+const selectedClassItm = ref()
+// 获取可选班级列表数据
+const GetClassTableData = async ()=>{
+  let params = {
+    evaluationId: route.query.id,
+    subjectId:searchParmams.value.subjectId,
+    type:searchParmams.value.type
+  }
+
+  let res = await getAlternativeClassDataApi(params)
+  if(res?.code == 200){
+    classList.value = res.data || []
+  }
+}
+// 行选中 选择班级
+const HandleSelectRowClass = (classItm) => {
+  selectedClassItm.value = {
+    id:classItm.id,
+    className:classItm.className,
+    gradeName:classItm.gradeName,
+  };
+};
+// 设置表行选中 样式
+const tableRowClassName = ({row,rowIndex})=>{
+  if(row.id == selectedClassItm.value?.id){
+    return 'active_row'
+  }
+}
+
+
+// 3. 班级编号对应  关系数据 
+const filterNumberMappingTableColumns = ref([...numberMappingTableColumns.value])  //表头
+const administrativeClassTableData = ref([]); // 行政班 班级编号对应 关系数据
+// 获取表格授课关系配置数据
+const GetTeachingRelationshipData = async ()=>{
+  administrativeClassTableData.value = []
+
+  let params = {
+    evaluationId: route.query.id,
+    subjectId:searchParmams.value.subjectId,
+    type:searchParmams.value.type
+  }
+
+  let res = await getClassNumberMappingDataApi(params)
+  if(res?.code == 200){
+    const {    
+          gradeData,subjectData,tableData    
+        } = res.data
+
+    
+        GetClassTypeList(subjectData)
+        
+      // 班级编号对应表  数据渲染
+      let dynamicGradeHeaderColumn = gradeData.map(item=>{
+        return {
+          name: item.id,
+          label: item.gradeName,
+          width: '140',
+          custom: true, 
+          fixed:'',
+          hidden: false,
+          align:'center',
+        }
+      })
+      filterNumberMappingTableColumns.value = [numberMappingTableColumns.value[0],...dynamicGradeHeaderColumn,numberMappingTableColumns.value[1]] 
+      
+
+      administrativeClassTableData.value = tableData.map(item=>{
+        let classOpt = {}
+        item.gradeData.map(grade=>{
+          classOpt[grade.evaluationGradeId] = grade.classData
+        })
+        return {
+          classCode:item.classCode,
+          ...classOpt
+        }
+      })
+  }
+}
+
+// 添加班级绑定编号
+const HandleAddClassBindCode = async (row, cell) => {
+  if (!isConfigMode.value) return;
+  if (!selectedClassItm.value) return;
+
+  let teacherMsg = { 
+    id: selectedClassItm.value?.id, 
+    className: selectedClassItm.value?.className,
+    gradeName:selectedClassItm.value?.gradeName 
+  }
+
+  // 行政班
+  if (!row[cell]) {
+    row[cell] = [];
+  }
+
+  let params = {
+    id: selectedClassItm.value?.id,   //班级id
+    classCode: row.classCode,
+    evaluationGradeId: cell,
+    subjectId:searchParmams.value.subjectId,
+    type:searchParmams.value.type
+  }
+
+  let res = await setClassNumberMappingDataApi(params)
+  if(res?.code == 200){
+    ElMessage.success(res?.msg)
+    row[cell].push({...teacherMsg,id:res?.data});
+    await GetClassTableData()
+  }
+};
+
+// 删除编号对应关系中的某个班级
+const HandleRemoveCodeMappinClass = async (row, cell, index) => {
+  if (!isConfigMode.value) return;
+  let id = null
+  let res = undefined
+  id = row[cell][index].id
+  res = await deleteCodeMappinClassApi(id)
+  if(res?.code == 200){
+    ElMessage.success(res?.msg)
+    row[cell].splice(index, 1);
+    await GetClassTableData()
+  }
+};
+
+// 删除一行班级编号 及对应数据
+const HandleDeleteRowClassCode =async (row)=>{
+  let params = {
+    subjectId:searchParmams.value.subjectId,
+    evaluationId: route.query.id,
+    classCode: row.classCode,
+    type:searchParmams.value.type
+  }
+
+  let res = await deleteRowClassNumberMappingDataApi(params)
+  if(res?.code == 200){
+    ElMessage.success(res?.msg)
+    await reloadData()
+  }
+}
+
+// 新增班级编号
+const AddOneRowClassCode = async ()=>{
+  let params = {
+    subjectId:searchParmams.value.subjectId,
+    evaluationId: route.query.id,
+    type:searchParmams.value.type
+  }
+  let res = await addRowClassNumberMappingDataApi(params)
+  if(res?.code == 200){
+    await GetTeachingRelationshipData()
+  }
+}
+
+// 4 综合. 
+// 标签切换处理   年级/班级类型
+const HandleTabChange = async (val) => {
+  console.log('当前选中的tab',val)
+  searchParmams.value.subjectId = JSON.parse(val).subjectId
+  searchParmams.value.type = JSON.parse(val).type
+  await reloadData()
+};
+
+
+// 5. 完成编号对应关系
+const FinishNumberMapping = async ()=>{
+  let res = await finishNumberMappingDataApi(route.query.id)
+  if(res?.code == 200){
+    // 更新全局状态 
+    store.dispatch('updateEvaluationManageStepData',route.query.id)
+     //更新全局活跃路由
+    store.commit('updateEvaluationManageStepData',{currentActiveStepName:'templateSetting'}) 
+    //跳转到下一步 
+    router.push(`templateSetting?id=${route.query.id}`)
+  }
+}
+
+
+
+// 重新加载页面数据
+const reloadData =async ()=>{
+   // 查询可选班级数据
+   await GetClassTableData()
+    // 查询 现有的 班级编号对应关系
+   await GetTeachingRelationshipData()
+
+}
+
+onMounted( async ()=>{
+  //  await GetClassTableData()
+  //  await GetTeachingRelationshipData()
+  HandleTabChange(defaultTabkey.value)
+})
+
+</script>
+
+
+
+<style lang="scss" scoped>
+
+.number_mapping_content{
+    height: 100%;
+    overflow: auto;
+
+    .grade_tab{
+      gap:10px;
+      :deep(> span){
+        border: 1px solid  #dcdfe6 !important; 
+        border-radius: 6px;
+      }
+    }
+
+}
+
+.main_content {
+    overflow: auto;
+    height: calc(100% - 56px);
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: flex-start;
+    gap:20px;
+
+  .container_left {
+    height: 100%;
+    flex-shrink: 0;
+    width: 200px;
+    overflow-y: auto;
+    .search_content{
+      height: 36px;
+    }
+    .teacher_table{
+      :deep(.el-table__body){
+        tr.active_row td
+        {
+          background-color: rgba(46, 100, 250,0.1) !important;
+          border:none;
+          color: #2e64fa;
+        }
+      }
+    }
+  }
+
+  .container_right {
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+
+    .config_switch_desc{
+      font-size: 14px;
+
+    }
+    .end_item{
+      overflow-y: auto;
+    }
+  }
+}
+
+/* 单元格内部组件样式 */
+.cell_container {
+  text-align: center;
+  display: flex;
+  justify-content: flex-start;
+  flex-wrap: wrap;
+  align-items: center;
+  padding: 8px;
+  gap: 8px;
+
+  &.teaching_cell_container{
+    flex-wrap: nowrap;
+    .class_name{
+      word-break: keep-all;
+    }
+  }
+
+  .teaching_teacher_list{
+    display: flex;
+    justify-content: flex-start;
+    flex-wrap: wrap;
+    align-items: center;
+    gap: 8px;
+  }
+
+  .disabled_teacher,
+  .placeholder_text {
+    width: 90px;
+    height: 36px;
+    font-weight: 400;
+    font-size: 14px;
+    color: #CCCCCC;
+    text-align: center;
+    line-height: 36px;
+    background-color: #f3f3f3;
+    border-radius: 4px;
+    cursor: pointer;
+  }
+
+  .disabled_teacher{
+    color:#666666;
+  }
+
+  .teacher_tag {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 0 8px;
+
+    min-width: 90px;
+    height: 36px;
+    font-weight: 400;
+    font-size: 14px;
+    color: #2E64FA;
+    text-align: center;
+    line-height: 36px;
+    background: rgba(46, 100, 250, 0.1);
+    border-radius: 4px;
+
+    .delete_icon {
+      cursor: pointer;
+      font-size: 12px;
+    }
+  }
+}
+</style>
+

+ 48 - 0
src/views/reviewManagement/stepComponent/numberMappingComponent/table.ts

@@ -0,0 +1,48 @@
+import { ref } from "vue"
+
+//  班级编号对应表列配置 —— 此数据不变,需要用其他变量处理增删
+export const numberMappingTableColumns = ref([
+    {
+        name: 'classCode',
+        label: '班级编号',
+        width: '140',
+        custom: false, 
+        fixed:'left',
+        hidden: false,
+        align:'center',
+    }, 
+
+    // 中间是动态表头变量_
+
+    {
+        name: 'operation',
+        label: '操作',
+        width: '140',
+        custom: true, 
+        fixed:'right',
+        hidden: false,
+        align:'center',
+    }, 
+
+
+
+]);
+
+
+// 可选班级 表列配置
+export const classTableColumns = ref([
+    {
+        name: 'gradeName',
+        label: '年级',
+        width: '80',
+        custom: false, 
+        align:'center',
+    },
+    {
+        name: 'className',
+        label: '班级',
+        width: '80',
+        custom: false, 
+        align:'center',
+    },
+])

+ 1 - 2
src/views/reviewManagement/stepComponent/teachingRelationshipComponent/TeachingRelationshipComponent.vue

@@ -539,7 +539,6 @@ onMounted( async ()=>{
 <style lang="scss" scoped>
 
 .step_2_content {
-  width: calc(100vw - 200px);
   height: calc(100%);
   display: flex;
   flex-direction: row;
@@ -549,6 +548,7 @@ onMounted( async ()=>{
   overflow: hidden;
 
   .container_left {
+    flex-shrink: 0;
     width: 200px;
     overflow-y: auto;
     .teacher_table{
@@ -565,7 +565,6 @@ onMounted( async ()=>{
   }
 
   .container_right {
-    width: calc(100% - 200px);
     height: 100%;
     display: flex;
     flex-direction: column;