wuzhen 更新假期住宿申请

This commit is contained in:
“wuzhen” committed 2026-08-20 15:17:40 +08:00
1 parent 1d67506451
commit 3518ea697e
35 files changed
+2173 -98

No files matched your search

@@ -84,6 +84,16 @@ export interface DormHygieneCheckVO {
*/
campusName: string;
/**
* 归属班级ID(宿舍扣分归属)
*/
classId?: string | number;
/**
* 归属班级名称
*/
className?: string;
/**
* 宿舍总分(0-100分)
*/
@@ -227,6 +237,16 @@ export interface DormHygieneCheckForm extends BaseEntity {
*/
campusName?: string;
/**
* 归属班级ID(宿舍扣分归属)
*/
classId?: string | number;
/**
* 归属班级名称
*/
className?: string;
/**
* 宿舍总分(0-100分)
*/
@@ -142,3 +142,57 @@ export const getBedOptions = (roomId?: string | number): AxiosPromise<any[]> =>
params: roomId ? { roomId } : undefined
});
};
/** 学生提交留宿申请 */
export const applyHolidayStay = (data: HolidayStayForm) => {
return request({
url: '/holidayStay/holidayStay/apply',
method: 'post',
data
});
};
/** 当前学生申请列表 */
export const listMyHolidayStay = (query?: HolidayStayQuery): AxiosPromise<HolidayStayVO[]> => {
return request({
url: '/holidayStay/holidayStay/myList',
method: 'get',
params: query
});
};
/** 班主任本班申请列表 */
export const listTeacherHolidayStay = (query?: HolidayStayQuery): AxiosPromise<HolidayStayVO[]> => {
return request({
url: '/holidayStay/holidayStay/teacherList',
method: 'get',
params: query
});
};
/** 班主任审批通过 */
export const approveHolidayStay = (data: { id: string | number; auditOpinion?: string }) => {
return request({
url: '/holidayStay/holidayStay/approve',
method: 'post',
data
});
};
/** 班主任驳回 */
export const rejectHolidayStay = (data: { id: string | number; auditOpinion?: string }) => {
return request({
url: '/holidayStay/holidayStay/reject',
method: 'post',
data
});
};
/** 班主任撤销已通过申请 */
export const revokeHolidayStay = (data: { id: string | number; revokeReason: string }) => {
return request({
url: '/holidayStay/holidayStay/revoke',
method: 'post',
data
});
};
@@ -173,6 +173,56 @@ export interface HolidayStayVO {
* 备注信息
*/
remark: string;
/**
* 申请状态(0草稿 1待审 2已通过 3已驳回 4已撤销)
*/
applyStatus?: string;
/**
* 提交申请时间
*/
applyTime?: string;
/**
* 审批人用户ID
*/
auditorId?: string | number;
/**
* 审批人姓名
*/
auditorName?: string;
/**
* 审批时间
*/
auditTime?: string;
/**
* 审批意见
*/
auditOpinion?: string;
/**
* 撤销人用户ID
*/
revokeBy?: string | number;
/**
* 撤销人姓名
*/
revokeByName?: string;
/**
* 撤销时间
*/
revokeTime?: string;
/**
* 撤销原因
*/
revokeReason?: string;
}
export interface HolidayStayForm extends BaseEntity {
@@ -350,6 +400,11 @@ export interface HolidayStayForm extends BaseEntity {
* 备注信息
*/
remark?: string;
/**
* 申请状态(0草稿 1待审 2已通过 3已驳回 4已撤销)
*/
applyStatus?: string;
}
export interface HolidayStayQuery extends PageQuery {
@@ -523,6 +578,11 @@ export interface HolidayStayQuery extends PageQuery {
*/
status?: string;
/**
* 申请状态(0草稿 1待审 2已通过 3已驳回 4已撤销)
*/
applyStatus?: string;
/**
* 日期范围参数
*/
@@ -57,6 +57,25 @@
</el-row>
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="归属班级" prop="classId">
<el-select
v-model="hygieneForm.classId"
:placeholder="classOptions.length ? '请选择归属班级' : '当前寝室无在住学生班级'"
style="width: 100%"
filterable
:disabled="!classOptions.length"
@change="handleClassChange"
>
<el-option
v-for="item in classOptions"
:key="String(item.classId)"
:label="item.className"
:value="item.classId"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="宿舍扣分" prop="totalScore">
<el-input-number
@@ -407,6 +426,8 @@ const hygieneForm = reactive({
campusName: '',
disciplineTypeId: null as number | null,
disciplineTypeName: '',
classId: undefined as string | number | undefined,
className: '',
totalScore: 0,
hygieneGrade: 'A',
checkRemarks: '',
@@ -418,6 +439,7 @@ const hygieneRules = reactive({
checkTitle: [{ required: true, message: '检查标题不能为空', trigger: 'blur' }],
checkDate: [{ required: true, message: '检查日期不能为空', trigger: 'change' }],
checkerName: [{ required: true, message: '检查员不能为空', trigger: 'blur' }],
classId: [{ required: true, message: '请选择归属班级', trigger: 'change' }],
totalScore: [
{
validator: (rule: any, value: any, callback: (error?: string | Error) => void) => {
@@ -440,6 +462,8 @@ const hygieneRules = reactive({
// 学生评分数据
const studentScores = ref<any[]>([]);
/** 本寝室在住学生班级(去重) */
const classOptions = ref<Array<{ classId: string | number; className: string }>>([]);
// 违纪记录数据(使用普通对象,避免 Map 变更无法触发 Vue 响应式更新)
const violationRecords = ref<Record<string, any[]>>({});
@@ -488,6 +512,41 @@ const handleDeductionTotalChange = (total: number) => {
hygieneForm.totalScore = total;
};
/** 从本房学生提取班级选项,并默认选中第一项(已选且仍有效则保留) */
const syncClassOptionsFromStudents = (students: any[], preferClassId?: string | number | null) => {
const map = new Map<string, { classId: string | number; className: string }>();
students.forEach((student) => {
if (student.classId == null || student.classId === '' || student.classId === 0 || student.classId === '0') {
return;
}
const key = String(student.classId);
if (!map.has(key)) {
map.set(key, {
classId: student.classId,
className: student.className || key
});
}
});
classOptions.value = Array.from(map.values());
if (!classOptions.value.length) {
hygieneForm.classId = undefined;
hygieneForm.className = '';
return;
}
const preferred = preferClassId ?? hygieneForm.classId;
const matched = preferred != null ? classOptions.value.find((item) => String(item.classId) === String(preferred)) : undefined;
const selected = matched || classOptions.value[0];
hygieneForm.classId = selected.classId;
hygieneForm.className = selected.className;
};
const handleClassChange = (classId: string | number) => {
const matched = classOptions.value.find((item) => String(item.classId) === String(classId));
hygieneForm.className = matched?.className || '';
};
// 上传配置
const uploadAction = computed(() => {
return (import.meta as any).env.VITE_APP_BASE_API + '/resource/oss/upload';
@@ -623,14 +682,38 @@ const loadStudentScores = async () => {
studentScores.value = scores;
console.log('学生评分数据加载成功:', scores.length, '条');
// 班级选项优先用评分中的班级;若缺失则从当前寝室在住学生补全
let classSource = scores;
const hasClass = scores.some(
(s: any) => s.classId != null && s.classId !== '' && s.classId !== 0 && s.classId !== '0'
);
if (!hasClass && hygieneForm.roomId) {
try {
const roomRes = await request({
url: '/dormBedStudent/dormBedStudent/getRoomStudents',
method: 'get',
params: { roomId: hygieneForm.roomId }
});
if (roomRes.code === 200 && roomRes.data) {
classSource = roomRes.data;
}
} catch (error) {
console.warn('加载寝室班级选项失败', error);
}
}
syncClassOptionsFromStudents(classSource, hygieneForm.classId);
await loadStudentLeaves();
} else {
studentScores.value = [];
syncClassOptionsFromStudents([], hygieneForm.classId);
}
} catch (error) {
console.error('加载学生评分数据失败:', error);
ElMessage.error('加载学生评分数据失败');
studentScores.value = [];
syncClassOptionsFromStudents([], hygieneForm.classId);
} finally {
studentsLoading.value = false;
}
@@ -1179,6 +1262,12 @@ const submitForm = async () => {
return;
}
if (!hygieneForm.classId) {
ElMessage.error('请选择归属班级(取自当前寝室在住学生)');
return;
}
handleClassChange(hygieneForm.classId);
buttonLoading.value = true;
// 提交前同步个人扣分为违纪合计
@@ -1194,8 +1283,11 @@ const submitForm = async () => {
studentId: student.studentId,
studentName: student.studentName,
studentNo: student.studentNo,
classId: student.classId,
className: student.className,
majorId: student.majorId,
majorName: student.majorName,
collegeId: student.collegeId,
collegeName: student.collegeName,
bedId: student.bedId,
bedCode: student.bedCode,
@@ -22,6 +22,25 @@
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="归属班级" prop="classId">
<el-select
v-model="hygieneForm.classId"
:placeholder="classOptions.length ? '请选择归属班级' : '当前寝室无在住学生班级'"
style="width: 100%"
filterable
:disabled="!classOptions.length"
@change="handleClassChange"
>
<el-option
v-for="item in classOptions"
:key="String(item.classId)"
:label="item.className"
:value="item.classId"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="宿舍扣分" prop="totalScore">
<el-input-number
@@ -336,6 +355,8 @@ const deductionItems = ref<HygieneDeductionItem[]>([]);
const hygieneForm = reactive({
disciplineTypeId: null as number | null,
disciplineTypeName: '',
classId: undefined as string | number | undefined,
className: '',
totalScore: 0,
hygieneGrade: 'A',
checkRemarks: '',
@@ -344,6 +365,7 @@ const hygieneForm = reactive({
// 表单验证规则
const hygieneRules = reactive({
classId: [{ required: true, message: '请选择归属班级', trigger: 'change' }],
totalScore: [
{
validator: (rule: any, value: any, callback: (error?: string | Error) => void) => {
@@ -366,6 +388,8 @@ const hygieneRules = reactive({
// 学生相关数据
const roomStudents = ref<any[]>([]);
/** 本寝室在住学生班级(去重) */
const classOptions = ref<Array<{ classId: string | number; className: string }>>([]);
const violationRecords = ref<Map<string | number, any[]>>(new Map());
const studentLeaves = ref<Map<string | number, any>>(new Map());
@@ -444,10 +468,48 @@ const handleDeductionTotalChange = (total: number) => {
hygieneForm.totalScore = total;
};
/** 从本房学生提取班级选项,并默认选中第一项(已选且仍有效则保留) */
const syncClassOptionsFromStudents = (students: any[], preferClassId?: string | number | null) => {
const map = new Map<string, { classId: string | number; className: string }>();
students.forEach((student) => {
const classId = student.classId;
const hasClassId = classId != null && classId !== '' && classId !== 0 && classId !== '0';
if (!hasClassId) {
return;
}
const key = String(classId);
if (!map.has(key)) {
map.set(key, {
classId,
className: (student.className || '').toString().trim() || key
});
}
});
classOptions.value = Array.from(map.values());
if (!classOptions.value.length) {
hygieneForm.classId = undefined;
hygieneForm.className = '';
return;
}
const preferred = preferClassId ?? hygieneForm.classId;
const matched = preferred != null ? classOptions.value.find((item) => String(item.classId) === String(preferred)) : undefined;
const selected = matched || classOptions.value[0];
hygieneForm.classId = selected.classId;
hygieneForm.className = selected.className;
};
const handleClassChange = (classId: string | number) => {
const matched = classOptions.value.find((item) => String(item.classId) === String(classId));
hygieneForm.className = matched?.className || '';
};
// 加载房间学生信息
const loadRoomStudents = async () => {
if (!props.roomInfo?.id) {
roomStudents.value = [];
syncClassOptionsFromStudents([]);
return;
}
@@ -467,16 +529,19 @@ const loadRoomStudents = async () => {
attendance_status: '1',
student_grade: 'A'
}));
syncClassOptionsFromStudents(roomStudents.value);
// 加载学生请假信息
await loadStudentLeaves();
} else {
roomStudents.value = [];
syncClassOptionsFromStudents([]);
}
} catch (error) {
console.error('加载房间学生信息失败:', error);
ElMessage.error('加载学生信息失败');
roomStudents.value = [];
syncClassOptionsFromStudents([]);
} finally {
studentsLoading.value = false;
}
@@ -878,6 +943,12 @@ const submitForm = async () => {
return;
}
if (!hygieneForm.classId) {
ElMessage.error('请选择归属班级(取自当前寝室在住学生)');
return;
}
handleClassChange(hygieneForm.classId);
buttonLoading.value = true;
syncStudentScoreFromViolations();
@@ -891,8 +962,11 @@ const submitForm = async () => {
studentId: student.studentId,
studentName: student.studentName,
studentNo: student.studentNo,
classId: student.classId,
className: student.className,
majorId: student.majorId,
majorName: student.majorName,
collegeId: student.collegeId,
collegeName: student.collegeName,
bedId: student.bedId,
bedCode: student.bedCode,
@@ -999,12 +1073,15 @@ const resetForm = () => {
Object.assign(hygieneForm, {
disciplineTypeId: null,
disciplineTypeName: '',
classId: undefined,
className: '',
totalScore: 0,
hygieneGrade: 'A',
checkRemarks: '',
attachmentIds: ''
});
deductionItems.value = [];
classOptions.value = [];
roomStudents.value = [];
violationRecords.value.clear();
@@ -105,6 +105,7 @@
</template>
</el-table-column>
<el-table-column label="房间名称" align="center" prop="roomName" />
<el-table-column label="归属班级" align="center" prop="className" min-width="140" show-overflow-tooltip />
<el-table-column label="宿舍楼名称" align="center" prop="buildingName" />
<el-table-column label="校区名称" align="center" prop="campusName" />
<el-table-column label="扣分项" align="center" prop="disciplineTypeName" min-width="160" show-overflow-tooltip />
@@ -16,6 +16,11 @@
<el-form-item label="学生姓名" prop="studentName">
<el-input v-model="queryParams.studentName" placeholder="请输入学生姓名" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="申请状态" prop="applyStatus">
<el-select v-model="queryParams.applyStatus" placeholder="请选择申请状态" clearable>
<el-option v-for="dict in xg_holiday_stay_apply_status" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
<el-option v-for="dict in xg_holiday_stay_status" :key="dict.value" :label="dict.label" :value="dict.value" />
@@ -223,6 +228,11 @@
<el-table-column label="扩展字段2" align="center" prop="extField2" v-if="false" />
<el-table-column label="扩展字段3" align="center" prop="extField3" v-if="false" />
<el-table-column label="备注信息" align="center" prop="remark" />
<el-table-column label="申请状态" align="center" prop="applyStatus" width="100">
<template #default="scope">
<dict-tag :options="xg_holiday_stay_apply_status" :value="scope.row.applyStatus" />
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status" width="90">
<template #default="scope">
<el-tag :type="getStatusType(scope.row)" size="small">
@@ -801,8 +811,8 @@ import {
} from '@/api/xg/xgss/holidayStay/holidayStay/types-sg';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { xg_holiday_type, xg_stay_reason_type, sys_yesno, xg_holiday_stay_status } = toRefs<any>(
proxy?.useDict('xg_holiday_type', 'xg_stay_reason_type', 'sys_yesno', 'xg_holiday_stay_status')
const { xg_holiday_type, xg_stay_reason_type, sys_yesno, xg_holiday_stay_status, xg_holiday_stay_apply_status } = toRefs<any>(
proxy?.useDict('xg_holiday_type', 'xg_stay_reason_type', 'sys_yesno', 'xg_holiday_stay_status', 'xg_holiday_stay_apply_status')
);
// 用户store - 用于获取当前登录用户信息,实现权限控制
@@ -920,6 +930,7 @@ const data = reactive<PageData<HolidayStayForm, HolidayStayQuery>>({
extField1: undefined,
extField2: undefined,
extField3: undefined,
applyStatus: undefined,
status: 'valid', // 默认展示有效状态的数据
params: {}
},
@@ -1210,15 +1221,22 @@ const handleDelete = async (row?: HolidayStayVO) => {
await getList();
};
/** 导出按钮操作 */
/** 导出按钮操作:未选申请状态时默认导出已通过名单 */
const handleExport = () => {
proxy?.download(
'holidayStay/holidayStay/export',
{
...queryParams.value
},
`holidayStay_${new Date().getTime()}.xlsx`
);
const exportParams: any = { ...queryParams.value };
if (!exportParams.applyStatus) {
exportParams.applyStatus = '2';
}
if (exportParams.status === 'valid' || exportParams.status === 'invalid') {
const currentTime = new Date().toISOString().slice(0, 19).replace('T', ' ');
exportParams.params = {
...exportParams.params,
statusType: exportParams.status,
currentTime
};
delete exportParams.status;
}
proxy?.download('holidayStay/holidayStay/export', exportParams, `holidayStay_${new Date().getTime()}.xlsx`);
};
/** 远程搜索学生 */
@@ -13,8 +13,13 @@
<el-form-item label="学生姓名" prop="studentName">
<el-input v-model="queryParams.studentName" placeholder="请输入学生姓名" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
<el-form-item label="申请状态" prop="applyStatus">
<el-select v-model="queryParams.applyStatus" placeholder="请选择申请状态" clearable>
<el-option v-for="dict in xg_holiday_stay_apply_status" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="有效期" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择有效期" clearable>
<el-option label="有效" value="valid" />
<el-option label="失效" value="invalid" />
</el-select>
@@ -157,9 +162,11 @@
>删除</el-button
>
</el-col> -->
<!-- <el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['holidayStay:holidayStay:export']">导出</el-button>
</el-col> -->
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['holidayStay:holidayStay:export']"
>导出留宿名单</el-button
>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
@@ -221,15 +228,47 @@
<el-table-column label="扩展字段2" align="center" prop="extField2" v-if="false" />
<el-table-column label="扩展字段3" align="center" prop="extField3" v-if="false" />
<el-table-column label="备注信息" align="center" prop="remark" />
<el-table-column label="状态" align="center" prop="status" width="90">
<el-table-column label="申请状态" align="center" prop="applyStatus" width="100">
<template #default="scope">
<dict-tag :options="xg_holiday_stay_apply_status" :value="scope.row.applyStatus" />
</template>
</el-table-column>
<el-table-column label="有效期" align="center" prop="status" width="90">
<template #default="scope">
<el-tag :type="getStatusType(scope.row)" size="small">
{{ getStatusText(scope.row) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="100">
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="220">
<template #default="scope">
<el-tooltip content="通过" placement="top" v-if="scope.row.applyStatus === '1'">
<el-button
link
type="success"
@click="openAuditDialog(scope.row, 'approve')"
v-hasPermi="['holidayStay:holidayStay:audit']"
>通过</el-button
>
</el-tooltip>
<el-tooltip content="驳回" placement="top" v-if="scope.row.applyStatus === '1'">
<el-button
link
type="warning"
@click="openAuditDialog(scope.row, 'reject')"
v-hasPermi="['holidayStay:holidayStay:audit']"
>驳回</el-button
>
</el-tooltip>
<el-tooltip content="撤销" placement="top" v-if="scope.row.applyStatus === '2'">
<el-button
link
type="danger"
@click="openAuditDialog(scope.row, 'revoke')"
v-hasPermi="['holidayStay:holidayStay:revoke']"
>撤销</el-button
>
</el-tooltip>
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['holidayStay:holidayStay:edit']"></el-button>
</el-tooltip>
@@ -553,6 +592,26 @@
</div>
</template>
</el-dialog>
<!-- 审批 / 撤销 -->
<el-dialog :title="auditDialog.title" v-model="auditDialog.visible" width="480px" append-to-body>
<el-form label-width="100px">
<el-form-item :label="auditDialog.mode === 'revoke' ? '撤销原因' : '审批意见'" :required="auditDialog.mode === 'revoke'">
<el-input
v-model="auditDialog.opinion"
type="textarea"
:rows="4"
:placeholder="auditDialog.mode === 'revoke' ? '请输入撤销原因(必填)' : '请输入审批意见(选填)'"
/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="auditDialog.loading" type="primary" @click="submitAudit">确 定</el-button>
<el-button @click="auditDialog.visible = false">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
@@ -565,9 +624,8 @@ import { UploadFilled, Document, Loading, Download, Delete } from '@element-plus
import { getToken } from '@/utils/auth';
import ImagePreview from '@/components/ImagePreview/index.vue';
import request from '@/utils/request';
import { useUserStore } from '@/store/modules/user';
import {
listHolidayStay,
listTeacherHolidayStay,
getHolidayStay,
delHolidayStay,
addHolidayStay,
@@ -577,7 +635,10 @@ import {
getAreaOptions,
getBuildingOptions,
getRoomOptions,
getBedOptions
getBedOptions,
approveHolidayStay,
rejectHolidayStay,
revokeHolidayStay
} from '@/api/xg/xgss/holidayStay/holidayStay';
import {
HolidayStayVO,
@@ -593,10 +654,9 @@ import {
} from '@/api/xg/xgss/holidayStay/holidayStay/types';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { xg_holiday_type, xg_stay_reason_type, sys_yesno } = toRefs<any>(proxy?.useDict('xg_holiday_type', 'xg_stay_reason_type', 'sys_yesno'));
// 用户store - 用于获取当前登录用户信息,实现权限控制
const userStore = useUserStore();
const { xg_holiday_type, xg_stay_reason_type, sys_yesno, xg_holiday_stay_apply_status } = toRefs<any>(
proxy?.useDict('xg_holiday_type', 'xg_stay_reason_type', 'sys_yesno', 'xg_holiday_stay_apply_status')
);
const holidayStayList = ref<HolidayStayVO[]>([]);
const buttonLoading = ref(false);
@@ -701,6 +761,7 @@ const data = reactive<PageData<HolidayStayForm, HolidayStayQuery>>({
extField1: undefined,
extField2: undefined,
extField3: undefined,
applyStatus: '1', // 班主任默认看待审
status: 'valid', // 默认显示有效状态的记录
params: {}
},
@@ -734,34 +795,23 @@ const uploadData = computed(() => {
};
});
/** 查询假期留宿管理列表 */
/** 查询假期留宿管理列表(班主任本班) */
const getList = async () => {
loading.value = true;
// 确保用户信息已加载
if (!userStore.userId) {
await userStore.getInfo();
}
// 处理状态过滤逻辑
const requestParams = { ...queryParams.value };
// 添加创建人过滤条件 - 班主任只能看到自己创建的数据
(requestParams as any).createBy = userStore.userId;
// 根据状态设置时间过滤条件
// 根据有效期设置时间过滤条件
if (requestParams.status) {
const currentTime = new Date().toISOString().slice(0, 19).replace('T', ' ');
if (requestParams.status === 'valid') {
// 查询有效状态:结束时间大于等于当前时间
requestParams.params = {
...requestParams.params,
statusType: 'valid',
currentTime: currentTime
};
} else if (requestParams.status === 'invalid') {
// 查询失效状态:结束时间小于当前时间
requestParams.params = {
...requestParams.params,
statusType: 'invalid',
@@ -769,11 +819,10 @@ const getList = async () => {
};
}
// 移除status参数,因为后端不需要这个字段
delete requestParams.status;
}
const res = await listHolidayStay(requestParams);
const res = await listTeacherHolidayStay(requestParams);
holidayStayList.value = res.rows;
total.value = res.total;
loading.value = false;
@@ -911,15 +960,64 @@ const handleDelete = async (row?: HolidayStayVO) => {
await getList();
};
/** 导出按钮操作 */
/** 导出按钮操作:默认导出已通过名单;若已选申请状态则按筛选导出 */
const handleExport = () => {
proxy?.download(
'holidayStay/holidayStay/export',
{
...queryParams.value
},
`holidayStay_${new Date().getTime()}.xlsx`
);
const exportParams: any = { ...queryParams.value };
if (!exportParams.applyStatus) {
exportParams.applyStatus = '2';
}
if (exportParams.status) {
const currentTime = new Date().toISOString().slice(0, 19).replace('T', ' ');
exportParams.params = {
...exportParams.params,
statusType: exportParams.status,
currentTime
};
delete exportParams.status;
}
proxy?.download('holidayStay/holidayStay/export', exportParams, `holidayStay_${new Date().getTime()}.xlsx`);
};
const auditDialog = reactive({
visible: false,
title: '',
mode: 'approve' as 'approve' | 'reject' | 'revoke',
rowId: undefined as string | number | undefined,
opinion: '',
loading: false
});
const openAuditDialog = (row: HolidayStayVO, mode: 'approve' | 'reject' | 'revoke') => {
auditDialog.mode = mode;
auditDialog.rowId = row.id;
auditDialog.opinion = '';
auditDialog.title = mode === 'approve' ? '审批通过' : mode === 'reject' ? '审批驳回' : '撤销留宿';
auditDialog.visible = true;
};
const submitAudit = async () => {
if (!auditDialog.rowId) return;
if (auditDialog.mode === 'revoke' && !auditDialog.opinion?.trim()) {
proxy?.$modal.msgWarning('请填写撤销原因');
return;
}
auditDialog.loading = true;
try {
if (auditDialog.mode === 'approve') {
await approveHolidayStay({ id: auditDialog.rowId, auditOpinion: auditDialog.opinion });
proxy?.$modal.msgSuccess('已通过');
} else if (auditDialog.mode === 'reject') {
await rejectHolidayStay({ id: auditDialog.rowId, auditOpinion: auditDialog.opinion });
proxy?.$modal.msgSuccess('已驳回');
} else {
await revokeHolidayStay({ id: auditDialog.rowId, revokeReason: auditDialog.opinion });
proxy?.$modal.msgSuccess('已撤销');
}
auditDialog.visible = false;
await getList();
} finally {
auditDialog.loading = false;
}
};
/** 远程搜索学生 */