dev #8

Merged
hy merged 45 commits from dev into master 2025-08-26 19:03:29 +08:00
3 changed files with 234 additions and 238 deletions
Showing only changes of commit 26a1b003cd - Show all commits

53
src/api/student.ts Normal file
View File

@ -0,0 +1,53 @@
import { http } from "@/utils/http";
import { Res } from "@/utils/http/types";
// import type { Res } from "@/utils/http/types";
/**
* @description
* @return {object}
*/
export function ImportExamInfo(id: number, file: File) {
let formData = new FormData();
formData.append("eId", id.toString());
formData.append("file", file);
return http.request<any>(
"post",
`ExamClassInfo/Import`,
{
data: formData
},
{
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
responseType: "blob"
}
);
}
/**
* @description
* @return {object}
*/
export function EditStudent(data) {
return http.request<Res<any>>("post", `Student/EditInfo`, {
data
});
}
/**
* @description
* @return {object}
*/
export function PageList(data) {
return http.request<Res<any>>("post", `Student/PageList`, {
data
});
}
/**
* @description
* @return {object}
*/
export function StudentInfo(uid) {
return http.request<Res<any>>("get", `Student/Info?uid=${uid}`);
}

View File

@ -1,31 +1,6 @@
<template> <template>
<div> <div>
<el-form <el-form ref="userEditForm" :model="form" :label-width="formLabelWidth" clearable>
ref="userEditForm"
:model="form"
:label-width="formLabelWidth"
clearable
>
<el-row>
<el-col :span="12">
<el-form-item label="账号:" prop="Account">
<el-input
type="text"
v-model="form.account"
autocomplete="off"
minlength="6"
maxlength="33"
:show-word-limit="true"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="电话号码" :rules="rulePhone" prop="phone">
<el-input type="text" v-model="form.phone" />
</el-form-item>
</el-col>
</el-row>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="姓名:" prop="realName" :rules="ruleRequired"> <el-form-item label="姓名:" prop="realName" :rules="ruleRequired">
@ -39,20 +14,47 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="所属云校" prop="cloudSchoolId"> <el-form-item label="家长电话" prop="phone">
<el-input type="text" v-model="form.phone" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="入班时间:" prop="joinTime">
<el-date-picker v-model="form.joinTime" type="date" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="退出时间:" prop="exitTime">
<el-date-picker v-model="form.exitTime" type="date" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="减免金额(元)" prop="amountRelief">
<el-input-number
v-model="form.amountRelief"
:precision="2"
:step="0.1"
:max="10"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="当前状态:" prop="status">
<el-select <el-select
v-model="form.cloudSchoolId" v-model="form.status"
filterable filterable
placeholder="就读/退出"
style="width: 180px" style="width: 180px"
> >
<el-option <el-option key="1" label="未录入" :value="0" />
v-for="(item, i) in CloudSchoolArr" <el-option key="2" label="就读" :value="1" />
:key="i" <el-option key="3" label="退出" :value="10" />
autocomplete="off"
:label="item.text"
:value="item.value"
>
</el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -62,7 +64,7 @@
<el-col :span="24"> <el-col :span="24">
<div style="display: flex; gap: 10px"> <div style="display: flex; gap: 10px">
<label for="Level" class="el-form-item__label" style="width: 120px" <label for="Level" class="el-form-item__label" style="width: 120px"
>新高考</label >选修方向</label
> >
<el-select <el-select
v-model="form.gLSubject" v-model="form.gLSubject"
@ -115,52 +117,13 @@
</el-col> </el-col>
</el-row> </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>
</el-form-item>
</el-col>
</el-row>
<el-row> <el-row>
<el-col :span="12"> </el-col> <el-col :span="12"> </el-col>
</el-row> </el-row>
<el-row> <el-row class="pt-4">
<el-col :span="24"> <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 type="success" @click="CheckPosition()">分配职位</el-button>
>分配职位</el-button
>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -188,9 +151,7 @@
position.graduationYear ? position.graduationYear + "届" : "-" position.graduationYear ? position.graduationYear + "届" : "-"
}}</el-tag> }}</el-tag>
<el-tag type="success">{{ position.grade || "-" }}</el-tag> <el-tag type="success">{{ position.grade || "-" }}</el-tag>
<el-tag type="primary" class="classTag">{{ <el-tag type="primary" class="classTag">{{ position.className || "-" }}</el-tag>
position.className || "-"
}}</el-tag>
<el-tag type="info" class="subjectTag">{{ <el-tag type="info" class="subjectTag">{{
position.subjectName || "-" position.subjectName || "-"
}}</el-tag> }}</el-tag>
@ -226,17 +187,12 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onMounted } from "vue"; import { ref, reactive, onMounted } from "vue";
import {} from "@/api/user"; import { EditStudent, StudentInfo } from "@/api/student";
import { import { cloudSchoolCombo, getUserInfo, editUser, Position } from "@/api/userCenter";
cloudSchoolCombo,
getUserInfo,
editUser,
Position
} from "@/api/userCenter";
import PositionForm from "../teacher/positionForm.vue"; import PositionForm from "../teacher/positionForm.vue";
import { getenum, getenumDic } from "@/api/enum"; import { getenum, getenumDic } from "@/api/enum";
import { ruleRequired, rulePhone } from "@/utils/rules"; import { ruleRequired, rulePhone } from "@/utils/rules";
import { ElMessage } from "element-plus"; import { ElMessage, FormInstance } from "element-plus";
import { ComboModel } from "@/components/hTable/hTable"; import { ComboModel } from "@/components/hTable/hTable";
interface FormData { interface FormData {
@ -258,7 +214,11 @@ interface FormData {
gSubject1?: number; gSubject1?: number;
gSubject2?: number; gSubject2?: number;
idCard?: string; idCard?: string;
pointPenSN?: string; exitTime?: string;
joinTime?: string;
remark?: string;
status?: string;
amountRelief?: number;
} }
interface DialogConfig { interface DialogConfig {
@ -268,9 +228,10 @@ interface DialogConfig {
width: string; width: string;
} }
defineOptions({ defineOptions({
name: "UserEditForm" name: "UserEditForm",
}); });
const userEditForm = ref<FormInstance>();
const props = defineProps<{ const props = defineProps<{
id: number; id: number;
}>(); }>();
@ -281,14 +242,14 @@ const loading = ref(false);
const subject1 = ref<ComboModel[]>([ const subject1 = ref<ComboModel[]>([
{ value: 4, text: "物理" }, { value: 4, text: "物理" },
{ value: 8, text: "历史" } { value: 8, text: "历史" },
]); ]);
const subject2 = ref<ComboModel[]>([ const subject2 = ref<ComboModel[]>([
{ value: 5, text: "化学" }, { value: 5, text: "化学" },
{ value: 6, text: "生物" }, { value: 6, text: "生物" },
{ value: 9, text: "地理" }, { value: 9, text: "地理" },
{ value: 7, text: "政治" } { value: 7, text: "政治" },
]); ]);
const userTypeList = ref<ComboModel[]>([]); const userTypeList = ref<ComboModel[]>([]);
@ -311,7 +272,7 @@ const defaultSubjectLevel = reactive({
Subject7: 0, Subject7: 0,
Subject8: 0, Subject8: 0,
Subject9: 0, Subject9: 0,
CreatePositionId: 1 CreatePositionId: 1,
}); });
const form = ref<FormData>({ const form = ref<FormData>({
@ -328,14 +289,14 @@ const form = ref<FormData>({
subjectLevels: [], subjectLevels: [],
subjectLevel: { ...defaultSubjectLevel }, subjectLevel: { ...defaultSubjectLevel },
positionIds: [], positionIds: [],
positionFormIds: [] positionFormIds: [],
}); });
const dialog = reactive<DialogConfig>({ const dialog = reactive<DialogConfig>({
close: false, close: false,
title: "", title: "",
visible: false, visible: false,
width: "1200px" width: "1200px",
}); });
const customeRules = reactive({ const customeRules = reactive({
@ -344,9 +305,9 @@ const customeRules = reactive({
{ {
pattern: /^1[3456789]\d{9}$/, pattern: /^1[3456789]\d{9}$/,
message: "手机号码格式不正确", message: "手机号码格式不正确",
trigger: "blur" trigger: "blur",
} },
] ],
}); });
const getUserSubjectLevel = (obj: Record<string, any>) => { const getUserSubjectLevel = (obj: Record<string, any>) => {
@ -354,7 +315,7 @@ const getUserSubjectLevel = (obj: Record<string, any>) => {
form.value.subjectLevel = { ...defaultSubjectLevel }; form.value.subjectLevel = { ...defaultSubjectLevel };
obj = form.value.subjectLevel; obj = form.value.subjectLevel;
} }
return Object.entries(obj).filter(s => s[0].includes("Subject")); return Object.entries(obj).filter((s) => s[0].includes("Subject"));
}; };
const userLevel2subject = (str: string) => { const userLevel2subject = (str: string) => {
@ -367,38 +328,52 @@ const handlePagedCallback = () => {
}; };
const handleSubmitForm = () => { const handleSubmitForm = () => {
// Form validation and submission logic userEditForm.value.validate(async (valid) => {
loading.value = true; if (valid) {
const formData = { loading.value = true;
id: form.value.id || 0, const formData = {
userType: form.value.userType || 1, id: form.value.id || 0,
level: form.value.level || 0, userType: form.value.userType || 1,
account: form.value.account || "", level: form.value.level || 0,
// PassWord: form.value.id === 0 ? md5(form.value.PassWord).toUpperCase() : "", account: form.value.account || "",
realName: form.value.realName || "", // PassWord: form.value.id === 0 ? md5(form.value.PassWord).toUpperCase() : "",
studentId: form.value.studentId || "", realName: form.value.realName || "",
templateId: form.value.templateId || 0, studentId: form.value.studentId || "",
subjectLevels: form.value.subjectLevels || [], templateId: form.value.templateId || 0,
subjectLevel: form.value.subjectLevel || { ...defaultSubjectLevel }, subjectLevels: form.value.subjectLevels || [],
positionIds: form.value.positionIds || [], subjectLevel: form.value.subjectLevel || { ...defaultSubjectLevel },
gLSubject: form.value.gLSubject, positionIds: form.value.positionIds || [],
gSubject1: form.value.gSubject1, gLSubject: form.value.gLSubject,
gSubject2: form.value.gSubject2, gSubject1: form.value.gSubject1,
idCard: form.value.idCard, gSubject2: form.value.gSubject2,
cloudSchoolId: form.value.cloudSchoolId, idCard: form.value.idCard,
phone: form.value.phone, cloudSchoolId: form.value.cloudSchoolId,
pointPenSN: form.value.pointPenSN phone: form.value.phone,
}; };
editUser(formData).then(res => { let res = await editUser(formData);
loading.value = false;
if (res.code === 200) { if (res.code !== 200) {
loading.value = false;
ElMessage.error(res.message);
return;
}
res = await EditStudent({
...form.value,
userCenterId: res.data,
});
if (res.code !== 200) {
loading.value = false;
ElMessage.error(res.message);
return;
}
loading.value = false;
ElMessage.success("操作成功"); ElMessage.success("操作成功");
handlePagedCallback(); handlePagedCallback();
} else { //edit info
ElMessage.error(res.message);
} }
}); });
// Form validation and submission logic
}; };
const handleResetForm = () => { const handleResetForm = () => {
@ -416,67 +391,49 @@ const handleResetForm = () => {
idCard: "", idCard: "",
phone: "", phone: "",
cloudSchoolId: "", cloudSchoolId: "",
pointPenSN: "" pointPenSN: "",
}); });
positionList.value = []; positionList.value = [];
}; };
const fetchInitData = async () => { const fetchInitData = async () => {};
//
const levelRes = await getenum("StudentLevelEnum");
userLevelList.value = levelRes.data;
const typeRes = await getenum("UserTypeEnum"); const fetchFormData = async () => {
userTypeList.value = typeRes.data;
//
const schoolRes = await cloudSchoolCombo();
if (schoolRes.code === 200) {
CloudSchoolArr.value = schoolRes.data;
}
const enumDicRes = await getenumDic("SubjectEnum");
subjectLEnum.value = enumDicRes.data;
};
const fetchFormData = () => {
handleResetForm(); handleResetForm();
if (props.id !== 0) { if (props.id !== 0) {
getUserInfo(props.id).then(res => { let res = await getUserInfo(props.id);
if (res.code === 200) { if (res.data.SubjectLevel && res.data.SubjectLevel.CreatePositionId) {
if (res.data.SubjectLevel && res.data.SubjectLevel.CreatePositionId) { delete res.data.SubjectLevel.CreatePositionId;
delete res.data.SubjectLevel.CreatePositionId; }
} let sInfo = await StudentInfo(props.id);
Object.assign(form.value, {
Object.assign(form.value, { id: res.data.id,
id: res.data.id, userType: res.data.userType,
userType: res.data.userType, level: res.data.level,
level: res.data.level, account: res.data.account,
account: res.data.account, passWord: res.data.passWord,
passWord: res.data.passWord, realName: res.data.realName,
realName: res.data.realName, studentId: res.data.studentId,
studentId: res.data.studentId, templateId: res.data.templateId,
templateId: res.data.templateId, subjectLevels: res.data.subjectLevels,
subjectLevels: res.data.subjectLevels, subjectLevel: res.data.subjectLevel,
subjectLevel: res.data.subjectLevel, positionIds: res.data.positions
positionIds: res.data.positions .filter((s: any) => s.enable !== false)
.filter((s: any) => s.enable !== false) .map((w: any) => w.id),
.map((w: any) => w.id), gLSubject: res.data.gLSubject,
gLSubject: res.data.gLSubject, gSubject1: res.data.gSubject1,
gSubject1: res.data.gSubject1, gSubject2: res.data.gSubject2,
gSubject2: res.data.gSubject2, idCard: res.data.idCard,
idCard: res.data.idCard, phone: res.data.phone,
phone: res.data.phone, cloudSchoolId: res.data.cloudSchoolId,
cloudSchoolId: res.data.cloudSchoolId, pointPenSN: res.data.pointPenSN,
pointPenSN: res.data.pointPenSN ...sInfo.data,
});
positionList.value = res.data.positions;
PositionFormIds.value = res.data.positions
.filter((s: any) => s.Enable !== false)
.map((s: any) => s.id);
}
}); });
positionList.value = res.data.positions;
PositionFormIds.value = res.data.positions
.filter((s: any) => s.Enable !== false)
.map((s: any) => s.id);
} }
}; };
@ -491,14 +448,14 @@ const CheckPosition = () => {
dialog.title = "选择职位"; dialog.title = "选择职位";
dialog.visible = true; dialog.visible = true;
PositionFormIds.value = positionList.value PositionFormIds.value = positionList.value
.filter(s => s.enable !== false) .filter((s) => s.enable !== false)
.map(s => s.id); .map((s) => s.id);
}; };
const handleCheckCallback = (checkPosition: Position[]) => { const handleCheckCallback = (checkPosition: Position[]) => {
dialog.visible = false; dialog.visible = false;
positionList.value = checkPosition; positionList.value = checkPosition;
form.value.positionIds = positionList.value.map(w => w.id); form.value.positionIds = positionList.value.map((w) => w.id);
}; };
onMounted(async () => { onMounted(async () => {

View File

@ -139,69 +139,54 @@
> >
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="学生信息" width="450">
<el-table-column prop="id" label="用户Id" width="100" />
<el-table-column label="用户信息" width="200">
<template #default="scope"> <template #default="scope">
<el-tag :type="getUserTypeTag(scope.row.userType)" style="margin-right: 5px">{{ <el-tooltip :content="`id ` + scope.row.id" placement="top" effect="light">
userTypeList.find((s) => s.value == scope.row.userType)?.text <div>
}}</el-tag> <span :tips="scope.row.id">{{ scope.row.realName }}</span>
<span>{{ scope.row.realName }} </span> <div
class="inline-block"
v-for="(position, index) in scope.row.positions"
:key="'Position' + index"
v-show="index < 3 || (index >= 3 && showAllPosition.includes(scope.row))"
>
<div class="subjectTagEnableDiv">
<el-tag v-if="position.enable === false" 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>
</div>
</div>
</div>
</el-tooltip>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="account" label="账号" width="120" /> <el-table-column prop="phone" label="家长电话" width="150" />
<el-table-column prop="phone" label="手机号" width="120" /> <el-table-column prop="gkSubject" label="选修" width="140" />
<el-table-column prop="joinTime" label="入班时间" width="100" />
<!-- <el-table-column prop="studentId" label="学号" width="120" /> <el-table-column prop="exitTime" label="退出时间" width="100" />
<el-table-column prop="gKSubject" label="新高考学科" width="150" /> --> <el-table-column label="减免情况(元)" width="150">
<el-table-column label="所属班级">
<template #default="scope"> <template #default="scope">
<div <span v-if="scope.row.amountRelief == 0">未申请</span>
v-for="(position, index) in scope.row.positions" <span v-else>{{ scope.row.amountRelief }}</span>
:key="'Position' + index" </template>
v-show="index < 3 || (index >= 3 && showAllPosition.includes(scope.row))" </el-table-column>
> <el-table-column label="状态">
<div v-if="position.enable === false"> <template #default="scope">
<el-tag type="info">{{ position.schoolName || "-" }}</el-tag> <span v-if="scope.row.status == 0">未录入</span>
<el-tag type="info">{{ <span v-else-if="scope.row.status == 1">就读</span>
position.graduationYear ? position.graduationYear + "届" : "-" <span v-else>退出</span>
}}</el-tag>
<el-tag type="info">{{ position.grade || "-" }}</el-tag>
<el-tag type="info">{{ position.className || "-" }}</el-tag>
<el-tag type="info">{{ position.name || "-" }}</el-tag>
</div>
<div class="subjectTagEnableDiv" v-else>
<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>
<el-tag type="danger">{{ position.name || "-" }}</el-tag>
</div>
</div>
<div
v-if="scope.row.positions != undefined && scope.row.positions.length > 3"
@click="showPosition(scope.row)"
class="userTagRow"
>
<el-icon
title="折叠职位"
class="userTagRowItop"
v-if="showAllPosition.includes(scope.row)"
><ArrowDownBold
/></el-icon>
<el-icon v-else title="展开更多职位"><ArrowDownBold /></el-icon>
</div>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<el-pagination <el-pagination
style="display: flex; justify-content: center" style="display: flex; justify-content: center; padding-top: 10px"
@size-change="pageSizeChange" @size-change="pageSizeChange"
@current-change="pageIndexChange" @current-change="pageIndexChange"
:current-page="pagination.total + 1" :current-page="pagination.total + 1"
@ -254,6 +239,7 @@ import {
Star, Star,
} from "@element-plus/icons-vue"; } from "@element-plus/icons-vue";
import { ComboModel } from "@/components/hTable/hTable"; import { ComboModel } from "@/components/hTable/hTable";
import { PageList } from "@/api/student";
const classAPI = new hTableAPI("usercenter/back/classes"); const classAPI = new hTableAPI("usercenter/back/classes");
const schoolsAPI = new hTableAPI("usercenter/back/schools"); const schoolsAPI = new hTableAPI("usercenter/back/schools");
@ -558,7 +544,7 @@ const fetchPagedData = (searchUnUse = false) => {
PageSize: pagination.size, PageSize: pagination.size,
UnUsed: searchUnUse, UnUsed: searchUnUse,
}; };
getPageUserList(data).then((res) => { PageList(data).then((res) => {
if (res.code === 200) { if (res.code === 200) {
pagination.total = res.data.total; pagination.total = res.data.total;
res.data.data.forEach((item) => { res.data.data.forEach((item) => {