学生请假调整

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

View File

@ -1,8 +1,47 @@
<template>
<BasicLayout :fixed="false">
<view class="p-15">
<!-- 请假类型 -->
<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="section-title">审批信息</view>
@ -14,6 +53,9 @@
</view>
</view>
</view>
<!-- 签名组件 -->
<BasicSign ref="signCompRef" title="家长签名"></BasicSign>
</view>
<template #bottom>
<view class="white-bg-color py-5">
@ -33,6 +75,22 @@
</view>
</view>
</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>
</template>
@ -45,6 +103,12 @@ import dayjs from "dayjs";
import { useUserStore } from "@/store/modules/user";
import { useCommonStore } from "@/store/modules/common";
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 { findByPid } = useDicStore();
@ -52,6 +116,14 @@ const commonStore = useCommonStore();
// isSubmitting useDebounce
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<{
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>(''); //
const [register, { getValue, setValue }] = useForm({
@ -84,37 +160,11 @@ const [register, { getValue, setValue }] = useForm({
savaKey: "dictionaryCode",
},
},
{ interval: true },
{
field: "qjkstime",
label: "开始时间",
component: "BasicDateTimes",
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 },
],
});
const [register2, { getValue: getValue2, setValue: setValue2 }] = useForm({
schema: [
{
field: "qjsy",
label: "请假事由",
@ -142,20 +192,11 @@ const [register, { getValue, setValue }] = useForm({
],
},
},
// {
// field: "qjtp",
// label: "",
// component: "BasicUpload",
// required: true,
// itemProps: {
// labelPosition: "top",
// },
// componentProps: {},
// },
],
});
setValue(props.data)
setValue2(props.data)
const goHome = () => {
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 () => {
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;
}
formData.value.qjkstime = selectedTime;
validateTime();
};
const changeJsTime = (selectedTime?: string) => {
if (!selectedTime) {
// 使dayjs
const ksTime = dayjs(data.qjkstime).valueOf();
const jsTime = dayjs(data.qjjstime).valueOf();
if (ksTime > jsTime) {
uni.showToast({
title: "请假开始时间不能大于请假结束时间!",
icon: "none",
});
data.qjsc = "";
return;
}
formData.value.qjjstime = selectedTime;
validateTime();
};
//
data.qjsc = Math.round((jsTime - ksTime) / (1000 * 60 * 60)) + "小时";
}
//
const validateTime = () => {
const data = formData.value;
if (!data.qjkstime || !data.qjjstime) {
uni.showToast({
title: "请选择开始时间和结束时间",
icon: "none",
});
return false;
}
// 使dayjs
@ -213,16 +290,40 @@ const validateTime = () => {
}
//
data.qjsc = Math.round((jsTime - ksTime) / (1000 * 60 * 60)) + "小时";
setValue({ qjsc: data.qjsc });
return true;
}
const submit = debounce(async () => {
const fd = await getValue();
if (!validateTime()) {
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) {
params.id = props.data.id;
} else {
@ -241,7 +342,8 @@ const submit = debounce(async () => {
setTimeout(() => {
if (res.resultCode === 1) {
showToast({ title: "提交成功", icon: "success" });
goHome();
//
emit('submit-success');
} else {
showToast({ title: res.message, icon: "error" });
}
@ -251,6 +353,78 @@ const submit = debounce(async () => {
</script>
<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 {
margin: 20px 0;
padding: 15px;

View File

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

View File

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