dev #8

Merged
hy merged 45 commits from dev into master 2025-08-26 19:03:29 +08:00
8 changed files with 179 additions and 315 deletions
Showing only changes of commit 69ebb99616 - Show all commits

View File

@ -6,13 +6,34 @@ import { Res } from "@/utils/http/types";
* @description
* @return {object}
*/
export function ImportExamInfo(id: number, file: File) {
export function ImportTeacher(file: File) {
let formData = new FormData();
formData.append("eId", id.toString());
formData.append("file", file);
return http.request<any>(
"post",
`ExamClassInfo/Import`,
`Student/ImportTeacher`,
{
data: formData
},
{
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
responseType: "blob"
}
);
}
/**
* @description
* @return {object}
*/
export function ImportStudent(file: File) {
let formData = new FormData();
formData.append("file", file);
return http.request<any>(
"post",
`Student/Import`,
{
data: formData
},
@ -36,7 +57,7 @@ export function EditStudent(data) {
}
/**
* @description
* @description PageList
* @return {object}
*/
export function PageList(data) {
@ -45,7 +66,7 @@ export function PageList(data) {
});
}
/**
* @description
* @description StudentInfo
* @return {object}
*/
export function StudentInfo(uid) {

View File

@ -9,7 +9,7 @@ import { ruleRequired } from "@/utils/rules";
const ControllerName = "classes";
defineOptions({
name: ControllerName
name: ControllerName,
});
const SchoolApi = new hTableAPI("usercenter/back/schools");
@ -28,7 +28,7 @@ const tableData: TableConfig = {
PageSize: 20,
OrderBy: "CreateTime", //
defaultConditions: [], //
Conditions: []
Conditions: [],
},
operationColumn: true, //
operationColumnData: [
@ -36,7 +36,7 @@ const tableData: TableConfig = {
//
topBtn: false, //
label: "修改",
btnType: "edit" // add edit del custom
btnType: "edit", // add edit del custom
},
{
topBtn: true, //
@ -48,16 +48,16 @@ const tableData: TableConfig = {
title: "新增班级", // title
src: "class/edit", //
width: "550px", //
height: "520px" //
}
height: "520px", //
},
},
{
topBtn: false, //
show: true,
label: "删除",
btnType: "del", // add edit del
btnStyle: "danger" // topBtn: true success danger
}
btnStyle: "danger", // topBtn: true success danger
},
],
column: {
//
@ -66,7 +66,7 @@ const tableData: TableConfig = {
search: true,
add: false, //
edit: false, //
width: "150px"
width: "150px",
},
schoolId: {
label: "学校",
@ -76,7 +76,7 @@ const tableData: TableConfig = {
type: "dropdown",
add: true, //
edit: true, //
setting: {}
setting: {},
},
name: {
label: "名称",
@ -85,43 +85,43 @@ const tableData: TableConfig = {
search: true,
searchType: ConditionalType.Like, //
add: true, //
edit: true //
edit: true, //
},
Grade: {
label: "年级",
rules: ruleRequired,
width: "180px",
type: "dropdown",
custom: row => `${row.grade ?? ""}`,
custom: (row) => `${row.grade ?? ""}`,
// `${row.grade ?? ""} ${row.gradeLevel + row.graduationYear}`,
search: true,
setting: {},
add: true, //
edit: false //
},
GradeLevel: {
label: "年级",
search: false,
type: "dropdown",
searchType: ConditionalType.Like,
add: true, //
edit: true, //
width: "70px",
setting: {
datasource: [
{ text: "初", value: "初" },
{ text: "高", value: "高" },
{ text: "小", value: "小" }
]
}
},
GraduationYear: {
label: "届",
search: false,
add: true, //
edit: true, //
width: "80px"
edit: false, //
},
// GradeLevel: {
// label: "",
// search: false,
// type: "dropdown",
// searchType: ConditionalType.Like,
// add: true, //
// edit: true, //
// width: "70px",
// setting: {
// datasource: [
// { text: "", value: "" },
// { text: "", value: "" },
// { text: "", value: "" }
// ]
// }
// },
// GraduationYear: {
// label: "",
// search: false,
// add: true, //
// edit: true, //
// width: "80px"
// },
type: {
label: "类型",
rules: ruleRequired,
@ -130,8 +130,8 @@ const tableData: TableConfig = {
search: true,
add: true, //
edit: true, //
setting: {}
}
setting: {},
},
// createTime: {
// label: "",
// width: "180px",
@ -151,9 +151,9 @@ const tableData: TableConfig = {
},
data: [],
pageData: {
total: 0
total: 0,
},
selectRows: []
selectRows: [],
};
const showTable = ref(false);
@ -172,11 +172,9 @@ onMounted(async () => {
{ text: "三年级", value: "三年级" },
{ text: "四年级", value: "四年级" },
{ text: "五年级", value: "五年级" },
{ text: "六年级", value: "六年级" }
{ text: "六年级", value: "六年级" },
];
tableData.column.type.setting.datasource = (
await getenum("ClassTypeEnum")
).data;
tableData.column.type.setting.datasource = (await getenum("ClassTypeEnum")).data;
tableData.column.schoolId.setting.datasource = (
await SchoolApi.querycombo({ TextName: "Name", ValueName: "Id" })
).data;

View File

@ -60,7 +60,7 @@
</el-col>
</el-row>
<el-row v-show="form.userType === 1">
<el-row v-show="form.userType === 1" class="pb-4.5">
<el-col :span="24">
<div style="display: flex; gap: 10px">
<label for="Level" class="el-form-item__label" style="width: 120px"
@ -117,6 +117,9 @@
</el-col>
</el-row>
<el-form-item label="备注:" prop="remark">
<el-input v-model="form.remark" maxlength="500" type="textarea" />
</el-form-item>
<el-row>
<el-col :span="12"> </el-col>
</el-row>
@ -197,6 +200,7 @@ import { ComboModel } from "@/components/hTable/hTable";
interface FormData {
id: number;
uId?: number;
account: string;
userType: number;
level: number;
@ -322,9 +326,10 @@ const userLevel2subject = (str: string) => {
const name = str.match(/[0-9]+/)?.[0] || "";
return subjectLEnum.value[name];
};
const emit = defineEmits(["handlePagedCallback"]);
const handlePagedCallback = () => {
// Emit event to parent if needed
emit("handlePagedCallback");
};
const handleSubmitForm = () => {
@ -332,7 +337,7 @@ const handleSubmitForm = () => {
if (valid) {
loading.value = true;
const formData = {
id: form.value.id || 0,
id: form.value.uId || 0,
userType: form.value.userType || 1,
level: form.value.level || 0,
account: form.value.account || "",
@ -408,6 +413,7 @@ const fetchFormData = async () => {
let sInfo = await StudentInfo(props.id);
Object.assign(form.value, {
id: res.data.id,
uId: res.data.id,
userType: res.data.userType,
level: res.data.level,
account: res.data.account,

View File

@ -112,11 +112,11 @@
<!-- 按钮组 -->
<el-button type="success" @click="importData">导入用户</el-button>
<el-button type="default" @click="downLoadImportUsersTemplate"
>下载导入用户模板</el-button
>下载学生模板</el-button
>
<el-button title="根据当前筛选条件导出" type="success" @click="exportUser"
<!-- <el-button title="根据当前筛选条件导出" type="primary" @click="exportUser"
>导出用户</el-button
>
> -->
</div>
<div class="toolbar-container" v-show="!selectUser">
<!-- 按钮组 -->
@ -184,6 +184,7 @@
<span v-else>退出</span>
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" />
</el-table>
<el-pagination
style="display: flex; justify-content: center; padding-top: 10px"
@ -239,7 +240,7 @@ import {
Star,
} from "@element-plus/icons-vue";
import { ComboModel } from "@/components/hTable/hTable";
import { PageList } from "@/api/student";
import { ImportStudent, PageList } from "@/api/student";
const classAPI = new hTableAPI("usercenter/back/classes");
const schoolsAPI = new hTableAPI("usercenter/back/schools");
@ -714,37 +715,38 @@ const handleEditSubjectLevelCallback = () => {
};
const importData = () => {
// const fileE = document.createElement("input");
// fileE.type = "file";
// const formData = new FormData();
// fileE.onchange = async function () {
// formData.append("File", fileE.files![0]);
// const res = await ImporExportTemplate(formData);
// if (res.type === "application/json") {
// const json = await readerBlob(res);
// if (json !== undefined && json.code !== 200) {
// return ElMessage.error(json.Message);
// } else {
// return ElMessage.success(",");
// }
// } else if (res === undefined || res.size === 0) {
// ElMessage.success(",");
// return;
// }
// const url = res && window.URL.createObjectURL(res);
// const link = document.createElement("a");
// link.href = url;
// link.setAttribute("download", ".xlsx");
// document.body.appendChild(link);
// link.click();
// document.body.removeChild(link);
// ElMessage.success(",");
// };
// try {
// fileE.click();
// } catch (error) {
// console.error(error);
// }
console.log("批量导入");
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]);
if (res.code != undefined) {
if (res.code !== 200) return ElMessage.error(res.message);
else return ElMessage.success("所有数据录入成功");
} else if (res.type === "application/json") {
let json = await res.text();
if (json !== undefined && json.Code !== 200) {
return ElMessage.error(json.Message);
} else {
return ElMessage.success("操所有数据录入成功作成功");
}
} else if (res === undefined || res.size === 0)
return ElMessage.success("所有数据录入成功");
const url = res && window.URL.createObjectURL(res);
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", "未成功导入的考试信息数据" + ".xlsx");
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
ElMessage.success("导入失败,已导出错误数据");
};
try {
fileE.click();
} catch (error) {}
};
const readerBlob = (data: Blob): Promise<any> => {
@ -759,7 +761,8 @@ const readerBlob = (data: Blob): Promise<any> => {
};
const downLoadImportUsersTemplate = () => {
window.open(excelImportUsersUrl, "_blank");
let impUrl = import.meta.env.VITE_API_BASEURL + "/Student/DwImportTemplate";
window.open(impUrl, "_blank");
};
onMounted(async () => {

View File

@ -21,120 +21,21 @@
</el-row>
<el-row>
<!-- <el-col :span="12">
<el-form-item label="所属云校" prop="cloudSchoolId">
<el-select
v-model="form.cloudSchoolId"
filterable
style="width: 180px"
>
<el-option
v-for="(item, i) in CloudSchoolArr"
:key="i"
<el-col :span="12">
<el-form-item label="职务:" prop="studentId">
<el-input
type="text"
v-model="form.studentId"
autocomplete="off"
:label="item.text"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
</el-col> -->
</el-row>
<el-row v-show="form.userType === 1">
<el-col :span="24">
<div style="display: flex; gap: 10px">
<label for="Level" class="el-form-item__label" style="width: 120px"
>新高考</label
>
<el-select
v-model="form.gLSubject"
filterable
placeholder="历史/地理"
style="width: 180px"
>
<el-option
v-for="(item, i) in subject1"
:key="i"
autocomplete="off"
:label="item.text"
:value="item.value"
>
</el-option>
</el-select>
<el-select
v-model="form.gSubject1"
filterable
placeholder="小学科"
style="width: 180px"
>
<el-option
v-for="(item, i) in subject2"
:key="i"
autocomplete="off"
:label="item.text"
:value="item.value"
>
</el-option>
</el-select>
<el-select
v-model="form.gSubject2"
filterable
placeholder="小学科"
style="width: 180px"
>
<el-option
v-for="(item, i) in subject2"
:key="i"
autocomplete="off"
:label="item.text"
:value="item.value"
>
</el-option>
</el-select>
</div>
</el-col>
</el-row>
<el-row v-if="form.userType === 1">
<el-col :span="24">
<el-form-item label="学生层次:" prop="level">
<el-radio-group v-model="form.subjectLevel.Level">
<el-radio v-for="(item, i) in userLevelList" :key="i" :label="item.value">{{
item.text
}}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="form.userType === 1">
<el-col :span="24">
<el-form-item label="科目层次:">
<ul class="userform_ul">
<li v-for="(value, i) in getUserSubjectLevel(form.subjectLevel)" :key="i">
{{ userLevel2subject(value[0]) }}:
<el-radio-group v-model="form.subjectLevel[value[0]]">
<el-radio
v-for="(level, j) in userLevelList"
:key="j"
:label="level.value"
>{{ level.text }}</el-radio
>
</el-radio-group>
</li>
</ul>
maxlength="16"
:show-word-limit="true"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12"> </el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="职位" prop="positionIds" :rules="ruleRequired">
<el-form-item label="任教信息:" prop="positionIds" :rules="ruleRequired">
<el-button type="success" @click="CheckPosition()">分配职位</el-button>
</el-form-item>
</el-col>
@ -145,29 +46,18 @@
:key="index"
style="padding-left: 120px; padding-bottom: 20px"
>
<div class="subjectTagEnableDiv" v-if="position.enable === false">
<el-tag type="info">{{ "禁用" }}</el-tag>
<el-tag type="info">{{ position.schoolName || "-" }}</el-tag>
<el-tag type="info">{{
position.graduationYear ? position.graduationYear + "届" : "-"
}}</el-tag>
<el-tag type="info">{{ position.grade || "-" }}</el-tag>
<el-tag type="info">{{ position.className || "-" }}</el-tag>
<el-tag type="info">{{ position.subjectName || "-" }}</el-tag>
<el-tag type="info">{{ position.name || "-" }}</el-tag>
<el-tag type="info">{{ position.endTime }}</el-tag>
</div>
<div class="subjectTagEnableDiv" v-else>
<div class="subjectTagEnableDiv">
<el-tag v-if="!position.enable" type="info">已禁用</el-tag>
<el-tag>{{ position.schoolName || "-" }}</el-tag>
<el-tag type="warning">{{
position.graduationYear ? position.graduationYear + "届" : "-"
}}</el-tag>
<el-tag type="success">{{ position.grade || "-" }}</el-tag>
<el-tag type="primary" class="classTag">{{
position.className || "-"
<el-tag type="success" v-show="position.grade">{{ position.grade }}</el-tag>
<el-tag type="primary" v-show="position.className" class="classTag">{{
position.className
}}</el-tag>
<el-tag type="info" class="subjectTag">{{
position.subjectName || "-"
<el-tag type="info" v-show="position.subjectName" class="subjectTag">{{
position.subjectName
}}</el-tag>
<el-tag type="danger">{{ position.name || "-" }}</el-tag>
</div>
@ -263,6 +153,7 @@ const subject2 = ref<ComboModel[]>([
{ value: 7, text: "政治" },
]);
const emit = defineEmits(["handlePagedCallback"]);
const userTypeList = ref<ComboModel[]>([]);
const userLevelList = ref<ComboModel[]>([]);
const subjectLEnum = ref<Record<string, string>>({});
@ -335,7 +226,7 @@ const userLevel2subject = (str: string) => {
};
const handlePagedCallback = () => {
// Emit event to parent if needed
emit("handlePagedCallback");
};
const userEditForm = ref<FormInstance>();
const handleSubmitForm = () => {
@ -345,8 +236,6 @@ const handleSubmitForm = () => {
const formData = {
...form.value,
account: form.value.phone || "",
subjectLevels: form.value.subjectLevels || [],
subjectLevel: form.value.subjectLevel || { ...defaultSubjectLevel },
positionIds: form.value.positionIds || [],
};
@ -361,6 +250,7 @@ const handleSubmitForm = () => {
});
}
});
// Form validation and submission logic
};
@ -460,7 +350,10 @@ const CheckPosition = () => {
const handleCheckCallback = (checkPosition: Position[]) => {
dialog.visible = false;
positionList.value = checkPosition;
positionList.value = checkPosition.map((s) => {
s.enable = true;
return s;
});
form.value.positionIds = positionList.value.map((w) => w.id);
};

View File

@ -114,9 +114,9 @@
<el-button type="default" @click="downLoadImportUsersTemplate"
>下载导入用户模板</el-button
>
<el-button title="根据当前筛选条件导出" type="success" @click="exportUser"
<!-- <el-button title="根据当前筛选条件导出" type="primary" @click="exportUser"
>导出用户</el-button
>
> -->
</div>
<div class="toolbar-container" v-show="!selectUser">
<!-- 按钮组 -->
@ -156,7 +156,9 @@
<!-- <el-table-column prop="studentId" label="学号" width="120" />
<el-table-column prop="gKSubject" label="新高考学科" width="150" /> -->
<el-table-column label="职位">
<el-table-column prop="studentId" label="职务" width="120" />
<el-table-column label="任教信息">
<template #default="scope">
<div
v-for="(position, index) in scope.row.positions"
@ -258,6 +260,7 @@ import {
Star,
} from "@element-plus/icons-vue";
import { ComboModel } from "@/components/hTable/hTable";
import { ImportTeacher } from "@/api/student";
const classAPI = new hTableAPI("usercenter/back/classes");
const schoolsAPI = new hTableAPI("usercenter/back/schools");
@ -579,57 +582,6 @@ const handleSelectionChange = (selection: UserDetail[]) => {
table.selectRows = selection;
};
const handleDelete = () => {
// if (table.selectRows.length === 0) {
// ElMessage.warning("");
// return;
// }
// const ids: number[] = [];
// table.selectRows.forEach(it => {
// ids.push(it.Id);
// });
// ElMessageBox.confirm(", ?", "", {
// confirmButtonText: "",
// cancelButtonText: "",
// type: "warning"
// }).then(() => {
// delUser(ids).then(res => {
// if (res.code === 200) {
// handleReloadPaged();
// ElMessage.success("");
// } else {
// ElMessage.error(res.Message);
// }
// });
// });
};
const handleRestPass = async () => {
// if (table.selectRows.length === 0) {
// ElMessage.warning("");
// } else {
// const ids: number[] = [];
// table.selectRows.forEach(it => {
// ids.push(it.Id);
// });
// try {
// await ElMessageBox.confirm("?", "", {
// confirmButtonText: "",
// cancelButtonText: "",
// type: "warning"
// });
// const res = await restUserPass(ids);
// if (res.code === 200) {
// ElMessage.success("");
// } else {
// ElMessage.error("");
// }
// } catch (error) {
// // User cancelled
// }
// }
};
const getUserTypeTag = (type: number) => {
return type === 1 ? "info" : "warning";
};
@ -732,51 +684,43 @@ const handleEditSubjectLevelCallback = () => {
};
const importData = () => {
// const fileE = document.createElement("input");
// fileE.type = "file";
// const formData = new FormData();
// fileE.onchange = async function () {
// formData.append("File", fileE.files![0]);
// const res = await ImporExportTemplate(formData);
// if (res.type === "application/json") {
// const json = await readerBlob(res);
// if (json !== undefined && json.code !== 200) {
// return ElMessage.error(json.Message);
// } else {
// return ElMessage.success(",");
// }
// } else if (res === undefined || res.size === 0) {
// ElMessage.success(",");
// return;
// }
// const url = res && window.URL.createObjectURL(res);
// const link = document.createElement("a");
// link.href = url;
// link.setAttribute("download", ".xlsx");
// document.body.appendChild(link);
// link.click();
// document.body.removeChild(link);
// ElMessage.success(",");
// };
// try {
// fileE.click();
// } catch (error) {
// console.error(error);
// }
};
console.log("批量导入");
const readerBlob = (data: Blob): Promise<any> => {
return new Promise((resolve) => {
const reader = new FileReader();
reader.readAsText(data, "utf-8");
reader.onload = function () {
const dd = JSON.parse(reader.result as string);
resolve(dd);
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 ImportTeacher(fileE.files[0]);
if (res.code != undefined) {
if (res.code !== 200) return ElMessage.error(res.message);
else return ElMessage.success("所有数据录入成功");
} else if (res.type === "application/json") {
let json = await res.text();
if (json !== undefined && json.Code !== 200) {
return ElMessage.error(json.Message);
} else {
return ElMessage.success("操所有数据录入成功作成功");
}
} else if (res === undefined || res.size === 0)
return ElMessage.success("所有数据录入成功");
const url = res && window.URL.createObjectURL(res);
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", "未成功导入的老师信息数据" + ".xlsx");
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
ElMessage.success("导入失败,已导出错误数据");
};
});
try {
fileE.click();
} catch (error) {}
};
const downLoadImportUsersTemplate = () => {
const baseUrl = import.meta.env.VITE_API_BASEURL;
const excelImportUsersUrl = `${baseUrl}/Student/DwImportTeacherTemplate`;
window.open(excelImportUsersUrl, "_blank");
};

View File

@ -423,7 +423,6 @@ const fetchPagedData = async () => {
table.data = res.data;
tableExpandRowKeys.value = [];
tableExpandRowKeys.value = table.data.map((s) => s.id.toString());
debugger;
tableExpandRowKeys.value.push(
res.data.find((s) => s.id == 1).children.map((s) => s.id.toString())
);

View File

@ -88,7 +88,7 @@
<el-button type="info" @click="downLoadTpl">下载模版</el-button>
</div>
<!-- 表格区域 -->
<el-table :data="listData" style="width: 100%">
<el-table :data="listData" style="width: 100%" :max-height="500">
<el-table-column label="操作" width="200">
<template #default="{ row }">
<!-- <el-button size="small" type="danger" plain @click="onDelete(row)"