2025-10-24 21:29:01 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<view class="qj-push-page">
|
|
|
|
|
|
<!-- 顶部区域 - Logo -->
|
|
|
|
|
|
<view class="header-section">
|
|
|
|
|
|
<image class="logo" src="@/static/system/login/logo.png" mode="aspectFit"></image>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 中间白色卡片 -->
|
|
|
|
|
|
<view class="content-section">
|
|
|
|
|
|
<view class="info-card">
|
|
|
|
|
|
<!-- 审批印章 - 右上角,如果已审批通过 -->
|
|
|
|
|
|
<view v-if="qjData.spResult === 'B'" class="approval-stamp">
|
|
|
|
|
|
<image class="stamp-image" src="@/static/base/view/sptg.png" mode="aspectFit"></image>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 申请人头像 - 中央 -->
|
|
|
|
|
|
<view class="student-photo-center">
|
|
|
|
|
|
<BasicImage :src="qjData.xstx || '/static/base/default-avatar.png'" />
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 请假信息 -->
|
|
|
|
|
|
<view class="info-list">
|
2025-10-29 10:30:04 +08:00
|
|
|
|
<view class="info-item">
|
|
|
|
|
|
<text class="label">学生姓名:</text>
|
|
|
|
|
|
<text class="value">{{ qjData.xsxm }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="info-item">
|
|
|
|
|
|
<text class="label">所在班级:</text>
|
|
|
|
|
|
<text class="value">{{ qjData.bc }}</text>
|
|
|
|
|
|
</view>
|
2025-10-24 21:29:01 +08:00
|
|
|
|
<view class="info-item">
|
|
|
|
|
|
<text class="label">请假类型:</text>
|
|
|
|
|
|
<text class="value">{{ qjData.qjlx }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="info-item">
|
|
|
|
|
|
<text class="label">开始时间:</text>
|
|
|
|
|
|
<text class="value">{{ qjData.qjkstime }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="info-item">
|
|
|
|
|
|
<text class="label">结束时间:</text>
|
|
|
|
|
|
<text class="value">{{ qjData.qjjstime }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="info-item">
|
|
|
|
|
|
<text class="label">时长(天):</text>
|
|
|
|
|
|
<text class="value">{{ qjData.qjsc }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="info-item">
|
|
|
|
|
|
<text class="label">是否离校:</text>
|
|
|
|
|
|
<text class="value">{{ qjData.sflx === 1 ? '是' : '否' }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="info-item info-item-vertical">
|
|
|
|
|
|
<text class="label">请假事由:</text>
|
|
|
|
|
|
<text class="value">{{ qjData.qjsy }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 确认放行按钮 -->
|
|
|
|
|
|
<view class="action-button" @click="handleConfirm">
|
|
|
|
|
|
<text class="button-text">确认放行</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 底部区域 -->
|
|
|
|
|
|
<view class="footer-section"></view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
|
import { computed, nextTick } from 'vue';
|
|
|
|
|
|
import { onLoad } from "@dcloudio/uni-app";
|
|
|
|
|
|
import { useDataStore } from "@/store/modules/data";
|
|
|
|
|
|
import { useUserStore } from "@/store/modules/user";
|
|
|
|
|
|
import { xsQjFindByIdApi, xsQjConfirmReleaseApi } from "@/api/base/server";
|
|
|
|
|
|
import { xxtsFindByIdApi } from "@/api/base/xxtsApi";
|
|
|
|
|
|
import BasicImage from "@/components/BasicImage/Image.vue";
|
|
|
|
|
|
|
|
|
|
|
|
const { loginByOpenId, getJs } = useUserStore();
|
|
|
|
|
|
const dataStore = useDataStore();
|
|
|
|
|
|
const { setQjData } = dataStore;
|
|
|
|
|
|
|
|
|
|
|
|
// 请假ID - 从 store 中通过 computed 访问,保持响应式
|
|
|
|
|
|
const qjId = computed(() => {
|
|
|
|
|
|
return (dataStore.qjData as any)?.id || '';
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 请假基础数据 - 直接访问 store 的 state,保持响应式
|
|
|
|
|
|
const qjData = computed(() => (dataStore.qjData || {}) as any);
|
|
|
|
|
|
|
|
|
|
|
|
const goHome = () => {
|
|
|
|
|
|
uni.reLaunch({ url: '/pages/base/message/index' });
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 确认放行
|
|
|
|
|
|
const handleConfirm = async () => {
|
|
|
|
|
|
// 检查是否有请假ID
|
|
|
|
|
|
if (!qjId.value) {
|
|
|
|
|
|
uni.showToast({ title: '请假ID不存在', icon: 'none' });
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取当前教师信息
|
|
|
|
|
|
const js = getJs;
|
|
|
|
|
|
if (!js || !js.id) {
|
|
|
|
|
|
uni.showToast({ title: '获取教师信息失败', icon: 'none' });
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uni.showModal({
|
|
|
|
|
|
title: '确认放行',
|
|
|
|
|
|
content: '确认该学生已成功离校?',
|
|
|
|
|
|
success: async (res) => {
|
|
|
|
|
|
if (res.confirm) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
uni.showLoading({ title: '放行中...' });
|
|
|
|
|
|
|
|
|
|
|
|
// 调用放行接口
|
|
|
|
|
|
const result = await xsQjConfirmReleaseApi({
|
|
|
|
|
|
id: qjId.value,
|
|
|
|
|
|
fxjsId: js.id,
|
|
|
|
|
|
fxjsxm: js.jsxm
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
uni.hideLoading();
|
|
|
|
|
|
|
|
|
|
|
|
if (result.resultCode === 1) {
|
|
|
|
|
|
uni.showToast({ title: '放行成功', icon: 'success' });
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
goHome();
|
|
|
|
|
|
}, 1500);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: result.message || '放行失败',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('放行失败:', error);
|
|
|
|
|
|
uni.hideLoading();
|
|
|
|
|
|
uni.showToast({ title: '放行失败,请重试', icon: 'none' });
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
onLoad(async (options: any) => {
|
|
|
|
|
|
console.log('detail.vue onLoad 接收到的参数:', options);
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
uni.showLoading({ title: "加载中..." });
|
|
|
|
|
|
|
|
|
|
|
|
// 场景1: 从待办过来的(from=db),需要先获取待办信息
|
|
|
|
|
|
if (options && options.from === "db") {
|
|
|
|
|
|
console.log('从待办过来,参数:', options);
|
|
|
|
|
|
|
|
|
|
|
|
// 检查登录状态
|
|
|
|
|
|
if (options.openId) {
|
|
|
|
|
|
const isLoggedIn = await loginByOpenId(options.openId);
|
|
|
|
|
|
if (!isLoggedIn) {
|
|
|
|
|
|
console.log("用户未登录,跳过处理");
|
|
|
|
|
|
uni.hideLoading();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
await nextTick();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 优先从后端根据url中的id去查询Xxts(待办信息)
|
|
|
|
|
|
if (options.id) {
|
|
|
|
|
|
const xxtsRes = await xxtsFindByIdApi({ id: options.id });
|
|
|
|
|
|
if (xxtsRes && xxtsRes.result) {
|
|
|
|
|
|
const xxts = xxtsRes.result;
|
|
|
|
|
|
console.log('获取到待办信息:', xxts);
|
|
|
|
|
|
|
|
|
|
|
|
// 根据待办中的主表ID获取请假详情
|
|
|
|
|
|
const qjRes = await xsQjFindByIdApi({ id: xxts.xxzbId });
|
|
|
|
|
|
if (qjRes && qjRes.result) {
|
|
|
|
|
|
setQjData(qjRes.result);
|
|
|
|
|
|
await nextTick();
|
|
|
|
|
|
console.log('获取到请假详情:', qjRes.result);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
throw new Error('获取请假详情失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
throw new Error('获取待办信息失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
throw new Error('缺少待办ID参数');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 场景2: 直接传请假ID(内部跳转)
|
|
|
|
|
|
else if (options && options.id) {
|
|
|
|
|
|
console.log('直接传请假ID:', options.id);
|
|
|
|
|
|
const qjRes = await xsQjFindByIdApi({ id: options.id });
|
|
|
|
|
|
if (qjRes && qjRes.result) {
|
|
|
|
|
|
setQjData(qjRes.result);
|
|
|
|
|
|
await nextTick();
|
|
|
|
|
|
console.log('获取到请假详情:', qjRes.result);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
throw new Error('获取请假详情失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 场景3: 从 store 获取(兼容某些场景)
|
|
|
|
|
|
else if (dataStore.qjData && (dataStore.qjData as any).id) {
|
|
|
|
|
|
console.log('从 store 获取请假ID:', (dataStore.qjData as any).id);
|
|
|
|
|
|
// store 中已有数据,无需重新获取
|
|
|
|
|
|
} else {
|
|
|
|
|
|
throw new Error('缺少请假ID参数');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uni.hideLoading();
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
console.error('加载请假详情失败:', error);
|
|
|
|
|
|
uni.hideLoading();
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: error.message || "加载失败",
|
|
|
|
|
|
icon: "none"
|
|
|
|
|
|
});
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
uni.navigateBack();
|
|
|
|
|
|
}, 1500);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.qj-push-page {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
min-height: 100vh;
|
|
|
|
|
|
background: url("@/static/base/bg.jpg") no-repeat;
|
|
|
|
|
|
background-size: 100% 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 顶部区域 - Logo */
|
|
|
|
|
|
.header-section {
|
|
|
|
|
|
flex: 0 0 auto;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 80rpx 30rpx 40rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.logo {
|
|
|
|
|
|
width: 500rpx;
|
|
|
|
|
|
height: 120rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 中间白色卡片区域 */
|
|
|
|
|
|
.content-section {
|
|
|
|
|
|
flex: 1 0 auto;
|
|
|
|
|
|
padding: 0 30rpx 40rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.info-card {
|
|
|
|
|
|
background: #FFFFFF;
|
|
|
|
|
|
border-radius: 40rpx 40rpx 20rpx 20rpx;
|
|
|
|
|
|
padding: 40rpx 30rpx;
|
|
|
|
|
|
box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.15);
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
min-height: 700rpx;
|
|
|
|
|
|
|
|
|
|
|
|
/* 审批印章 - 右上角 */
|
|
|
|
|
|
.approval-stamp {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 30rpx;
|
|
|
|
|
|
right: 30rpx;
|
|
|
|
|
|
width: 160rpx;
|
|
|
|
|
|
height: 160rpx;
|
|
|
|
|
|
z-index: 10;
|
|
|
|
|
|
|
|
|
|
|
|
.stamp-image {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 学生头像 - 中央 */
|
|
|
|
|
|
.student-photo-center {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin-bottom: 40rpx;
|
|
|
|
|
|
padding-top: 20rpx;
|
|
|
|
|
|
|
|
|
|
|
|
// BasicImage 组件的容器样式
|
|
|
|
|
|
:deep(.wh-full) {
|
|
|
|
|
|
width: 280rpx !important;
|
|
|
|
|
|
height: 280rpx !important;
|
|
|
|
|
|
border-radius: 32rpx;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
background: #F5F5F5;
|
|
|
|
|
|
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.15);
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 信息列表 */
|
|
|
|
|
|
.info-list {
|
|
|
|
|
|
padding-top: 0;
|
|
|
|
|
|
|
|
|
|
|
|
.info-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
margin-bottom: 32rpx;
|
|
|
|
|
|
line-height: 1.6;
|
|
|
|
|
|
|
|
|
|
|
|
&.info-item-vertical {
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
|
|
|
|
|
|
.label {
|
|
|
|
|
|
margin-bottom: 12rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.label {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #999999;
|
|
|
|
|
|
width: 160rpx;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.value {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #333333;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
word-break: break-all;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 确认按钮 */
|
|
|
|
|
|
.action-button {
|
|
|
|
|
|
margin-top: 60rpx;
|
|
|
|
|
|
height: 88rpx;
|
|
|
|
|
|
background: linear-gradient(90deg, #FF9500 0%, #FF6B00 100%);
|
|
|
|
|
|
border-radius: 44rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
box-shadow: 0 8rpx 20rpx rgba(255, 107, 0, 0.3);
|
|
|
|
|
|
|
|
|
|
|
|
&:active {
|
|
|
|
|
|
opacity: 0.8;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.button-text {
|
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
color: #FFFFFF;
|
|
|
|
|
|
letter-spacing: 4rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 底部区域 */
|
|
|
|
|
|
.footer-section {
|
|
|
|
|
|
flex: 0 0 auto;
|
|
|
|
|
|
height: 80rpx;
|
|
|
|
|
|
background: transparent;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|