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

View File

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