学生请假调整

This commit is contained in:
hebo 2025-10-24 21:29:33 +08:00
parent 091411cda0
commit 409f9f5108
4 changed files with 245 additions and 62 deletions

View File

@ -52,7 +52,7 @@
</view> </view>
</view> </view>
</view> </view>
<!-- 抄送人 --> <!-- &lt;!&ndash; 抄送人 &ndash;&gt;
<view class="info-section csr" v-if="csrSpList.length > 0"> <view class="info-section csr" v-if="csrSpList.length > 0">
<view class="section-title">抄送人{{ csrSpList.length || 0 }}</view> <view class="section-title">抄送人{{ csrSpList.length || 0 }}</view>
<view class="sp-list"> <view class="sp-list">
@ -66,14 +66,14 @@
</view> </view>
</view> </view>
</view> </view>
<!-- 更多按钮 --> &lt;!&ndash; 更多按钮 &ndash;&gt;
<view v-if="csrSpList.length > 2" class="more-button" @click="toggleCsrExpanded"> <view v-if="csrSpList.length > 2" class="more-button" @click="toggleCsrExpanded">
<text class="more-text"> <text class="more-text">
{{ csrExpanded ? '收起' : `更多(${csrSpList.length - 2})` }} {{ csrExpanded ? '收起' : `更多(${csrSpList.length - 2})` }}
</text> </text>
<text class="more-icon" :class="{ expanded: csrExpanded }"></text> <text class="more-icon" :class="{ expanded: csrExpanded }"></text>
</view> </view>
</view> </view>-->
<!-- 操作记录 --> <!-- 操作记录 -->
<view class="info-section log" v-if="logList.length > 0"> <view class="info-section log" v-if="logList.length > 0">
<view class="section-title">操作记录{{ logList.length || 0 }}</view> <view class="section-title">操作记录{{ logList.length || 0 }}</view>

View File

@ -1,8 +1,47 @@
<template> <template>
<BasicLayout :fixed="false"> <BasicLayout :fixed="false">
<view class="p-15"> <view class="p-15">
<!-- 请假类型 -->
<BasicForm @register="register" /> <BasicForm @register="register" />
<!-- 间隔空白 -->
<view class="section-gap"></view>
<!-- 时间选择区域 -->
<view class="time-section">
<view class="time-item" @click="startTimePicker?.open()">
<text class="time-label">
<text class="required-star">*</text>
开始时间
</text>
<view class="time-value">
<text :class="{ placeholder: !formData.qjkstime }">{{ formData.qjkstime || "请选择开始时间" }}</text>
<uni-icons type="right" size="16" color="#999"></uni-icons>
</view>
</view>
<view class="time-item" @click="endTimePicker?.open()">
<text class="time-label">
<text class="required-star">*</text>
结束时间
</text>
<view class="time-value">
<text :class="{ placeholder: !formData.qjjstime }">{{ formData.qjjstime || "请选择结束时间" }}</text>
<uni-icons type="right" size="16" color="#999"></uni-icons>
</view>
</view>
<view class="time-item time-item-readonly">
<text class="time-label">请假时长</text>
<view class="time-value">
<text :class="{ placeholder: !formData.qjsc }">{{ formData.qjsc || "请输入选择开始时间和结束时间" }}</text>
</view>
</view>
</view>
<!-- 请假事由和是否离校 -->
<BasicForm @register="register2" />
<!-- 审批信息显示区域 --> <!-- 审批信息显示区域 -->
<view class="approver-section"> <view class="approver-section">
<view class="section-title">审批信息</view> <view class="section-title">审批信息</view>
@ -14,6 +53,9 @@
</view> </view>
</view> </view>
</view> </view>
<!-- 签名组件 -->
<BasicSign ref="signCompRef" title="家长签名"></BasicSign>
</view> </view>
<template #bottom> <template #bottom>
<view class="white-bg-color py-5"> <view class="white-bg-color py-5">
@ -33,6 +75,22 @@
</view> </view>
</view> </view>
</template> </template>
<!-- 自定义时间选择器 -->
<DatetimePicker
ref="startTimePicker"
:value="formData.qjkstime || new Date().getTime()"
mode="datetime"
title="选择开始时间"
@confirm="handleStartTimeConfirm"
/>
<DatetimePicker
ref="endTimePicker"
:value="formData.qjjstime || new Date().getTime()"
mode="datetime"
title="选择结束时间"
@confirm="handleEndTimeConfirm"
/>
</BasicLayout> </BasicLayout>
</template> </template>
@ -45,6 +103,12 @@ import dayjs from "dayjs";
import { useUserStore } from "@/store/modules/user"; import { useUserStore } from "@/store/modules/user";
import { useCommonStore } from "@/store/modules/common"; import { useCommonStore } from "@/store/modules/common";
import { useDebounce } from "@/utils/debounce"; import { useDebounce } from "@/utils/debounce";
import DatetimePicker from "@/components/BasicPicker/TimePicker/DatetimePicker.vue";
//
const emit = defineEmits<{
(e: 'submit-success'): void
}>();
const { getCurXs, getUser } = useUserStore(); const { getCurXs, getUser } = useUserStore();
const { findByPid } = useDicStore(); const { findByPid } = useDicStore();
@ -52,6 +116,14 @@ const commonStore = useCommonStore();
// isSubmitting useDebounce // isSubmitting useDebounce
const { isProcessing: isSubmitting, debounce } = useDebounce(2000); const { isProcessing: isSubmitting, debounce } = useDebounce(2000);
//
const startTimePicker = ref<any>(null);
const endTimePicker = ref<any>(null);
//
const signCompRef = ref<any>(null);
const signFile = ref<any>(null);
// //
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
data?: any data?: any
@ -67,7 +139,11 @@ const props = withDefaults(defineProps<{
}) })
}); });
let formData = ref<any>({}); let formData = ref<any>({
qjkstime: "",
qjjstime: "",
qjsc: ""
});
let approverName = ref<string>(''); // let approverName = ref<string>(''); //
const [register, { getValue, setValue }] = useForm({ const [register, { getValue, setValue }] = useForm({
@ -84,37 +160,11 @@ const [register, { getValue, setValue }] = useForm({
savaKey: "dictionaryCode", savaKey: "dictionaryCode",
}, },
}, },
{ interval: true }, ],
{ });
field: "qjkstime",
label: "开始时间", const [register2, { getValue: getValue2, setValue: setValue2 }] = useForm({
component: "BasicDateTimes", schema: [
required: true,
componentProps: {
type: 'datetime',
change: (e: string) => changeKsTime(e)
},
},
{
field: "qjjstime",
label: "结束时间",
component: "BasicDateTimes",
required: true,
componentProps: {
type: 'datetime',
change: (e: string) => changeJsTime(e)
},
},
{
field: "qjsc",
label: "请假时长",
component: "BasicInput",
componentProps: {
disabled: true,
placeholder: "请输入选择开始时间和结束时间"
},
},
{ interval: true },
{ {
field: "qjsy", field: "qjsy",
label: "请假事由", label: "请假事由",
@ -142,20 +192,11 @@ const [register, { getValue, setValue }] = useForm({
], ],
}, },
}, },
// {
// field: "qjtp",
// label: "",
// component: "BasicUpload",
// required: true,
// itemProps: {
// labelPosition: "top",
// },
// componentProps: {},
// },
], ],
}); });
setValue(props.data) setValue(props.data)
setValue2(props.data)
const goHome = () => { const goHome = () => {
uni.reLaunch({ uni.reLaunch({
@ -163,6 +204,30 @@ const goHome = () => {
}); });
}; };
//
const formatDate = (dateString: string | null): string | null => {
if (!dateString) return null;
const date = new Date(dateString);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
};
//
const handleStartTimeConfirm = (e: any) => {
formData.value.qjkstime = formatDate(e.value);
calculateDuration();
};
const handleEndTimeConfirm = (e: any) => {
formData.value.qjjstime = formatDate(e.value);
calculateDuration();
};
// //
onMounted(async () => { onMounted(async () => {
await getDefaultApprover(); await getDefaultApprover();
@ -180,25 +245,37 @@ const getDefaultApprover = async () => {
} }
}; };
const changeKsTime = (selectedTime?: string) => { //
if (!selectedTime) { const calculateDuration = () => {
const data = formData.value;
//
if (!data.qjkstime || !data.qjjstime) {
data.qjsc = "";
return; return;
} }
formData.value.qjkstime = selectedTime; // 使dayjs
validateTime(); const ksTime = dayjs(data.qjkstime).valueOf();
}; const jsTime = dayjs(data.qjjstime).valueOf();
if (ksTime > jsTime) {
const changeJsTime = (selectedTime?: string) => { uni.showToast({
if (!selectedTime) { title: "请假开始时间不能大于请假结束时间!",
icon: "none",
});
data.qjsc = "";
return; return;
} }
formData.value.qjjstime = selectedTime; //
validateTime(); data.qjsc = Math.round((jsTime - ksTime) / (1000 * 60 * 60)) + "小时";
}; }
//
const validateTime = () => { const validateTime = () => {
const data = formData.value; const data = formData.value;
if (!data.qjkstime || !data.qjjstime) { if (!data.qjkstime || !data.qjjstime) {
uni.showToast({
title: "请选择开始时间和结束时间",
icon: "none",
});
return false; return false;
} }
// 使dayjs // 使dayjs
@ -213,16 +290,40 @@ const validateTime = () => {
} }
// //
data.qjsc = Math.round((jsTime - ksTime) / (1000 * 60 * 60)) + "小时"; data.qjsc = Math.round((jsTime - ksTime) / (1000 * 60 * 60)) + "小时";
setValue({ qjsc: data.qjsc });
return true; return true;
} }
const submit = debounce(async () => { const submit = debounce(async () => {
const fd = await getValue();
if (!validateTime()) { if (!validateTime()) {
return; return;
} }
const params = { ...fd };
//
const signData = await signCompRef.value.getSyncSignature();
if (!signData) {
uni.showToast({
title: "请签名",
icon: "none",
});
return;
}
signFile.value = signData.base64;
const fd = await getValue();
const fd2 = await getValue2();
// njbc + "" + bjmc + ""
const bc = getCurXs.njbc ? `${getCurXs.njbc}${getCurXs.bjmc || ''}` : (getCurXs.bjmc || '');
const params = {
...fd,
...fd2,
qjkstime: formData.value.qjkstime,
qjjstime: formData.value.qjjstime,
qjsc: formData.value.qjsc,
signFile: signFile.value, //
bc: bc //
};
if (props.data && props.data.id) { if (props.data && props.data.id) {
params.id = props.data.id; params.id = props.data.id;
} else { } else {
@ -241,7 +342,8 @@ const submit = debounce(async () => {
setTimeout(() => { setTimeout(() => {
if (res.resultCode === 1) { if (res.resultCode === 1) {
showToast({ title: "提交成功", icon: "success" }); showToast({ title: "提交成功", icon: "success" });
goHome(); //
emit('submit-success');
} else { } else {
showToast({ title: res.message, icon: "error" }); showToast({ title: res.message, icon: "error" });
} }
@ -251,6 +353,78 @@ const submit = debounce(async () => {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.section-gap {
height: 12px;
}
.required-star {
color: #f56c6c;
margin-right: 4px;
font-size: 15px;
}
.time-section {
background-color: #ffffff;
border-radius: 8px;
margin-bottom: 12px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
.time-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 15px;
border-bottom: 1px solid #f0f0f0;
cursor: pointer;
transition: background-color 0.2s;
&:last-child {
border-bottom: none;
}
&:active {
background-color: #fafafa;
}
&.time-item-readonly {
cursor: default;
&:active {
background-color: transparent;
}
}
.time-label {
font-size: 15px;
color: #303133;
display: flex;
align-items: center;
}
.time-value {
display: flex;
align-items: center;
font-size: 15px;
color: #909399;
flex: 1;
justify-content: flex-end;
text {
margin-right: 5px;
color: #606266;
&.placeholder {
color: #c0c4cc;
}
}
.uni-icons {
color: #c0c4cc !important;
}
}
}
}
.approver-section { .approver-section {
margin: 20px 0; margin: 20px 0;
padding: 15px; padding: 15px;

View File

@ -6,7 +6,7 @@
:current="curTabIndex" @change="switchTab" :current="curTabIndex" @change="switchTab"
/> />
<view class="leave-edit" v-if="curTabIndex === 0"> <view class="leave-edit" v-if="curTabIndex === 0">
<XsQjEdit /> <XsQjEdit @submit-success="handleSubmitSuccess" />
</view> </view>
<view class="leave-list" v-else> <view class="leave-list" v-else>
<XsQjList /> <XsQjList />
@ -29,6 +29,11 @@ const curTabIndex = ref(0);
const switchTab = (index : number) => { const switchTab = (index : number) => {
curTabIndex.value = index; curTabIndex.value = index;
} }
const handleSubmitSuccess = () => {
// tab
curTabIndex.value = 1;
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -169,9 +169,13 @@ const courseDetail = computed(() => {
// //
const teacherInfo = computed(() => { const teacherInfo = computed(() => {
const data = (kcData.value as CourseData) || {}; const data = (kcData.value as CourseData) || {};
//
const teacherAvatars = data.jstx ? data.jstx.split(',').map((avatar: string) => avatar.trim()) : [];
return { return {
name: data.jsName || "暂无教师信息", name: data.jsName || "暂无教师信息",
avatar: imagUrl(data.jstx), // avatar: teacherAvatars.length > 0 ? imagUrl(teacherAvatars[0]) : '', //
introduction: data.kcjsms || "暂无教师介绍", introduction: data.kcjsms || "暂无教师介绍",
}; };
}); });