dev #33

Merged
hy merged 2 commits from dev into staging 2025-11-27 17:07:46 +08:00
4 changed files with 151 additions and 77 deletions

View File

@ -82,3 +82,24 @@ export function PosititonIds(data:any[]) {
data
});
}
/**
* @description
* @return {object}
*/
export function ImportUpdateStudent(file: File) {
let formData = new FormData();
formData.append("file", file);
return http.request<any>(
"post",
`Student/ImportUpdateStudent`,
{
data: formData
},
{
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
responseType: "blob"
}
);
}

View File

@ -117,7 +117,7 @@ const tableData: TableConfig = intTableData({
selectRows: [],
});
async function deleteInfo(o, row, c) {
async function deleteInfo(o, row, baseRefresh) {
try {
await ElMessageBox.confirm("是否删除考试信息?", "提示", {
confirmButtonText: "确定",
@ -125,11 +125,12 @@ async function deleteInfo(o, row, c) {
type: "warning",
});
await DeleteExamInfo({ examId: row[0].examId, classId: row[0].classId });
baseRefresh();
} catch (error) {
ElMessage.info("取消删除");
}
}
async function reloadImportInfo(o, row, c) {
async function reloadImportInfo(o, row, baseRefresh) {
try {
await ElMessageBox.confirm("是否重新录入考试信息?", "提示", {
confirmButtonText: "确定",
@ -138,6 +139,7 @@ async function reloadImportInfo(o, row, c) {
});
await DeleteExamInfo({ examId: row[0].examId, classId: row[0].classId });
entryExamInfo(row[0].examId);
baseRefresh();
} catch (error) {
ElMessage.info("取消重新录入");
}

View File

@ -42,12 +42,7 @@
</el-form-item>
<el-form-item v-show="search.schoolId" style="width: 100px">
<el-select
v-model="search.classId"
placeholder="班级"
clearable
filterable
>
<el-select v-model="search.classId" placeholder="班级" clearable filterable>
<el-option
v-for="item in classList"
:key="item.value"
@ -75,6 +70,9 @@
<!-- <el-button title="根据当前筛选条件导出" type="primary" @click="exportUser"
>导出用户</el-button
> -->
<el-button type="success" @click="importUpdateStudent"
>使用Excel模板更新用户</el-button
>
</div>
<div v-show="!selectUser" class="toolbar-container">
<!-- 按钮组 -->
@ -99,26 +97,17 @@
</el-table-column>
<el-table-column label="学生信息" width="450">
<template #default="scope">
<el-tooltip
:content="`id ` + scope.row.id"
placement="top"
effect="light"
>
<el-tooltip :content="`id ` + scope.row.id" placement="top" effect="light">
<div>
<span :tips="scope.row.id">{{ scope.row.realName }}</span>
<div
v-for="(position, index) in scope.row.positions"
v-show="
index < 3 ||
(index >= 3 && showAllPosition.includes(scope.row))
"
v-show="index < 3 || (index >= 3 && showAllPosition.includes(scope.row))"
:key="'Position' + index"
class="inline-block"
>
<div class="subjectTagEnableDiv">
<el-tag v-if="position.enable === false" type="info"
>已禁用</el-tag
>
<el-tag v-if="position.enable === false" type="info">已禁用</el-tag>
<el-tag>{{ position.schoolName || "-" }}</el-tag>
<el-tag type="success">{{
position.graduationYear
@ -146,8 +135,9 @@
<template #default="scope">
<span v-if="!scope.row.reliefApplication">未申请</span>
<span v-else
>{{ scope.row.reliefSubTime }}申请{{ scope.row.amountRelief }}
<br />{{ scope.row.reliefType }}
>{{ scope.row.reliefSubTime }}申请{{ scope.row.amountRelief }} <br />{{
scope.row.reliefType
}}
</span>
</template>
</el-table-column>
@ -199,7 +189,7 @@ import {
getSubjectData,
getPageUserList,
UserDetail,
Position
Position,
} from "@/api/userCenter";
import { getenum } from "@/api/enum";
import { hTableAPI } from "@/api/hTable";
@ -211,10 +201,10 @@ import {
Message,
ArrowDownBold,
Search,
Star
Star,
} from "@element-plus/icons-vue";
import { ComboModel, gradeComboModel } from "@/components/hTable/hTable";
import { ImportStudent, PageList } from "@/api/student";
import { ImportStudent, ImportUpdateStudent, PageList } from "@/api/student";
const classAPI = new hTableAPI("usercenter/back/classes");
const schoolsAPI = new hTableAPI("usercenter/back/schools");
@ -281,20 +271,20 @@ interface DialogData {
const props = defineProps({
selectUser: {
type: Boolean,
default: false
default: false,
},
selectCallBack: {
type: Function,
default: () => {}
default: () => {},
},
maxTableHeight: {
type: Number,
default: 580
default: 580,
},
searchData: {
type: Object as () => SearchParams,
default: undefined
}
default: undefined,
},
});
const baseUrl = import.meta.env.VITE_APP_BASE_API;
@ -315,13 +305,13 @@ const search = reactive<SearchParams>({
grade: "",
classId: "",
subjectId: "",
positionId: ""
positionId: "",
});
const userTypeList = ref<ComboModel[]>([
{ value: 1, text: "学生" },
{ value: 2, text: "教师" },
{ value: 3, text: "管理员" }
{ value: 3, text: "管理员" },
]);
const userLevelList = ref<ComboModel[]>([]);
@ -335,13 +325,13 @@ const table = reactive<TableData>({
data: [],
selectRows: [],
sort: "",
border: true
border: true,
});
const pagination = reactive<PaginationData>({
index: 1,
size: 10,
total: 0
total: 0,
});
const dialog = reactive<DialogData>({
@ -349,32 +339,32 @@ const dialog = reactive<DialogData>({
update: {
title: "",
visible: false,
width: "1000px"
width: "1000px",
},
editLevel: {
userIds: [],
title: "",
visible: false,
width: "400px"
width: "400px",
},
editSubjectLevel: {
userIds: [],
title: "",
visible: false,
width: "450px"
width: "450px",
},
bindUser: {
title: "分配权限码",
visible: false,
width: "1150px",
height: ""
height: "",
},
userBindInfo: {
title: "用户权限码",
visible: false,
width: "1150px",
height: ""
}
height: "",
},
});
const checkUserBindInfo = () => {
@ -437,7 +427,7 @@ const exportUser = async () => {
SubjectId: search.subjectId || 0,
PositionId: search.positionId || 0,
PageIndex: pagination.index,
PageSize: pagination.size
PageSize: pagination.size,
};
// const res = await exportUserApi(data);
@ -498,9 +488,9 @@ const getClass = () => {
const data = {
schoolId: search.schoolId || 0,
graduationYear: search.graduationYear || 0,
grade: search.grade
grade: search.grade,
};
getClassCombo(data).then(res => {
getClassCombo(data).then((res) => {
if (res.code === 200) {
classList.value = res.data;
}
@ -520,12 +510,12 @@ const fetchPagedData = (searchUnUse = false) => {
PositionId: search.positionId || 0,
PageIndex: pagination.index,
PageSize: pagination.size,
UnUsed: searchUnUse
UnUsed: searchUnUse,
};
PageList(data).then(res => {
PageList(data).then((res) => {
if (res.code === 200) {
pagination.total = res.data.total;
res.data.data.forEach(item => {
res.data.data.forEach((item) => {
if (item.positions) {
item.positions = PositionsSort(item.positions);
}
@ -603,14 +593,14 @@ const getUserLevelTag = (level: number) => {
return level === 0
? "info"
: level === 1
? "success"
: level === 2
? "warning"
: "error";
? "success"
: level === 2
? "warning"
: "error";
};
const getUserLevelText = (level: number) => {
const r = userLevelList.value.filter(w => w.value === level);
const r = userLevelList.value.filter((w) => w.value === level);
if (r.length > 0) {
return r[0].text;
}
@ -627,7 +617,7 @@ const PositionsSort = (arr: Position[]) => {
return 1;
}
});
return arr.filter(s => s.enable);
return arr.filter((s) => s.enable);
};
const handleReloadPaged = (event?: any, searchUnUse?: boolean) => {
@ -673,7 +663,7 @@ const handleEditLevel = () => {
return;
}
dialog.editLevel.title = "修改学生层次";
dialog.editLevel.userIds = table.selectRows.map(w => w.id);
dialog.editLevel.userIds = table.selectRows.map((w) => w.id);
dialog.editLevel.visible = true;
};
@ -688,7 +678,7 @@ const handleEditSubjectLevel = () => {
return;
}
dialog.editSubjectLevel.title = "修改学生科目层次";
dialog.editSubjectLevel.userIds = table.selectRows.map(w => w.id);
dialog.editSubjectLevel.userIds = table.selectRows.map((w) => w.id);
dialog.editSubjectLevel.visible = true;
};
@ -697,15 +687,18 @@ const handleEditSubjectLevelCallback = () => {
handleReloadPaged();
};
const importData = () => {
const importUpdateStudent = () => {
importData(ImportUpdateStudent);
};
const importData = (api = null) => {
console.log("批量导入");
api = api ?? ImportStudent;
let fileE = document.createElement("input");
fileE.type = "file";
var formData = new window.FormData();
fileE.onchange = async function () {
formData.append("file", fileE.files[0]);
let res = await ImportStudent(fileE.files[0]);
let res = await api(fileE.files[0]);
if (res.code != undefined) {
if (res.code !== 200) return ElMessage.error(res.message);
else return ElMessage.success("所有数据录入成功");
@ -734,7 +727,7 @@ const importData = () => {
};
const readerBlob = (data: Blob): Promise<any> => {
return new Promise(resolve => {
return new Promise((resolve) => {
const reader = new FileReader();
reader.readAsText(data, "utf-8");
reader.onload = function () {

View File

@ -29,7 +29,31 @@
{{ safeDetail.schoolName || safeDetail.school || "-" }}
</el-descriptions-item>
<el-descriptions-item label="年级">
{{ safeDetail.gradeLevel + safeDetail.gradeYear }}
<span v-show="!isDetail">
<el-select
v-model="safeDetail.gradeLevel"
placeholder="请年级"
clearable
style="width: 120px"
>
<el-option
v-for="g in gradeOptions"
:key="g.value"
:label="g.label"
:value="g.value"
/>
</el-select>
<el-input-number
style="width: 120px"
v-model="safeDetail.gradeYear"
:min="2020"
:max="2100"
/>
</span>
<span v-show="isDetail">
{{ safeDetail.gradeLevel || "-" }}{{ safeDetail.gradeYear || "-" }}
</span>
</el-descriptions-item>
<el-descriptions-item label="赴校人员">
{{
@ -51,26 +75,50 @@
<el-descriptions title="基础工作" :column="1" border>
<el-descriptions-item label="座谈">
<el-tag
:type="safeDetail.isDiscussion ? 'success' : 'info'"
style="margin-right: 8px"
>
{{ safeDetail.isDiscussion ? "已开展" : "未开展" }}
</el-tag>
<span class="inline-block max-w-[500px]!">{{
safeDetail.discussion || "-"
}}</span>
<div v-if="!isDetail" class="flexCenterWrap">
<el-tag :type="safeDetail.isDiscussion ? 'success' : 'info'">
{{ safeDetail.isDiscussion ? "已开展" : "未开展" }}
</el-tag>
<el-radio-group :disabled="isDetail" v-model="safeDetail.isDiscussion">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
<el-input
:maxlength="500"
type="textarea"
:rows="3"
v-model="safeDetail.discussion"
:disabled="!safeDetail.isDiscussion"
placeholder="请输入座谈情况"
/>
</div>
<div v-else>
{{ safeDetail.isDiscussion ? safeDetail.discussion : "未开展" }}
</div>
</el-descriptions-item>
<el-descriptions-item label="班会">
<el-tag
:type="safeDetail.isClassMeeting ? 'success' : 'info'"
style="margin-right: 8px"
>
{{ safeDetail.isClassMeeting ? "已开展" : "未开展" }}
</el-tag>
<span class="inline-block max-w-[500px]!">{{
safeDetail.classMeeting || "-"
}}</span>
<div v-if="!isDetail" class="flexCenterWrap">
<el-tag :type="safeDetail.isClassMeeting ? 'success' : 'info'">
{{ safeDetail.isClassMeeting ? "已开展" : "未开展" }}
</el-tag>
<el-radio-group :disabled="isDetail" v-model="safeDetail.isClassMeeting">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
<el-input
:maxlength="500"
type="textarea"
:rows="3"
v-model="safeDetail.classMeeting"
:disabled="isDetail || !safeDetail.isClassMeeting"
placeholder="请输入班会情况"
/>
</div>
<div v-else>
{{ safeDetail.isDiscussion ? safeDetail.discussion : "未开展" }}
</div>
</el-descriptions-item>
</el-descriptions>
<el-divider />
@ -578,6 +626,7 @@ function onClickCancel() {
function onClickSave() {
console.log("保存", props.detailData);
let copyParams = JSON.parse(JSON.stringify(props.detailData));
copyParams.grade = `${copyParams.gradeLevel}${copyParams.gradeYear}`;
delete copyParams.solutionEnd;
addOrEditApi(copyParams).then((res) => {
if (res.code === 200) {
@ -633,4 +682,13 @@ function onClickSave() {
text-decoration: underline;
user-select: none;
}
.flexCenterWrap {
gap: 4px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-content: center;
align-items: center;
justify-content: flex-start;
}
</style>