调整学生请假的详情里面的审批流程显示

This commit is contained in:
ywyonui 2025-09-20 14:33:52 +08:00
parent 350e39cee1
commit 6f927ac65e
4 changed files with 582 additions and 19 deletions

View File

@ -8,3 +8,14 @@ import { get } from "@/utils/request";
export const getByYwIdAndYwTypeApi = (ywId: string, ywType: string) => {
return get("/api/lcglSp/getByYwIdAndYwType", { ywId, ywType });
};
/**
*
* @param params
*/
export function getLcglApi(params: {
ywId?: string;
ywType?: string;
}) {
return get('/api/lcglSp/getLcgl', params);
}

View File

@ -0,0 +1,550 @@
<template>
<view class="lcgl-info">
<!-- 申请人 -->
<view class="info-section sqr">
<view class="section-title">申请人</view>
<view class="sp-list">
<view class="sp-item">
<view class="sp-info">
<text class="name">{{ sqr.userName }}</text>
<text class="dept">{{ sqr.deptName }}</text>
<text class="status" :class="getSqrStatusClass(sqr.approveStatus)">
{{ getSqrStatusText(sqr.approveStatus) }}
</text>
</view>
<!-- 显示审批意见和审批时间 -->
<view class="sp-detail" v-if="sqr.approveRemark || sqr.approveTime">
<view class="approval-info" v-if="sqr.approveRemark">
<text class="info-label">申请意见</text>
<text class="info-value">{{ sqr.approveRemark }}</text>
</view>
<view class="approval-info" v-if="sqr.approveTime">
<text class="info-label">申请时间</text>
<text class="info-value">{{ formatTime(sqr.approveTime) }}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 审批人 -->
<view class="info-section spr" v-if="sprList.length > 0">
<view class="section-title">审批人</view>
<view class="sp-list">
<view v-for="spr in sprList" :key="spr.id" class="sp-item">
<view class="sp-info">
<text class="name">{{ spr.userName }}</text>
<text class="dept">{{ spr.deptName }}</text>
<text class="status" :class="getSprStatusClass(spr.approveStatus)">
{{ getSprStatusText(spr.approveStatus) }}
</text>
</view>
<!-- 显示审批意见和审批时间 -->
<view class="sp-detail" v-if="spr.approveStatus !== 'pending'">
<view class="approval-info" v-if="spr.approveRemark">
<text class="info-label">审批意见</text>
<text class="info-value">{{ spr.approveRemark }}</text>
</view>
<view class="approval-info" v-if="spr.approveTime">
<text class="info-label">审批时间</text>
<text class="info-value">{{ formatTime(spr.approveTime) }}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 抄送人 -->
<view class="info-section csr" v-if="csrList.length > 0">
<view class="section-title">抄送人</view>
<view class="sp-list">
<view v-for="csr in displayedcsrList" :key="csr.id" class="sp-item">
<view class="sp-info">
<text class="name">{{ csr.userName }}</text>
<text class="dept">{{ csr.deptName }}</text>
<text class="status" :class="getSprStatusClass(csr.approveStatus)">
{{ getSprStatusText(csr.approveStatus) }}
</text>
</view>
</view>
</view>
<!-- 更多按钮 -->
<view v-if="csrList.length > 2" class="more-button" @click="toggleCsrExpanded">
<text class="more-text">
{{ csrExpanded ? '收起' : `更多(${csrList.length - 2})` }}
</text>
<text class="more-icon" :class="{ expanded: csrExpanded }"></text>
</view>
</view>
<!-- 操作记录 -->
<view class="info-section log" v-if="logList.length > 0">
<view class="section-title">操作记录</view>
<view class="sp-list">
<view v-for="log in displayedLogList" :key="log.id" class="sp-item">
<view class="log-header">
<text class="operator">{{ log.operatorName }}</text>
<text class="time">{{ formatTime(log.operationTime) }}</text>
</view>
<view class="log-content">
<text class="content">{{ log.operationContent }}</text>
</view>
<view class="log-detail" v-if="log.beforeChange || log.afterChange">
<u-button text="详情" size="mini" @click="showLogDetail(log)" />
</view>
</view>
</view>
<!-- 更多按钮 -->
<view v-if="logList.length > 2" class="more-button" @click="toggleLogExpanded">
<text class="more-text">
{{ logExpanded ? '收起' : `更多(${logList.length - 2})` }}
</text>
<text class="more-icon" :class="{ expanded: logExpanded }"></text>
</view>
</view>
<!-- 操作记录详情弹窗 -->
<u-popup :show="showLogDetailModal" @close="showLogDetailModal = false" mode="center">
<view class="detail-modal">
<view class="detail-header">
<text class="detail-title">操作详情</text>
<u-button text="关闭" @click="showLogDetailModal = false" />
</view>
<view class="detail-content">
<view class="detail-item" v-if="currentLog.beforeChange">
<text class="detail-label">变更前</text>
<text class="detail-value">{{ currentLog.beforeChange }}</text>
</view>
<view class="detail-item" v-if="currentLog.afterChange">
<text class="detail-label">变更后</text>
<text class="detail-value">{{ currentLog.afterChange }}</text>
</view>
<view class="detail-item" v-if="currentLog.remark">
<text class="detail-label">备注</text>
<text class="detail-value">{{ currentLog.remark }}</text>
</view>
</view>
</view>
</u-popup>
</view>
</template>
<script setup lang="ts">
import dayjs from "dayjs";
import { getLcglApi } from "@/api/base/lcglSpApi";
//
const props = withDefaults(defineProps<{
ywId: string,
ywType: string
}>(), {
ywId: '',
ywType: ''
});
const sqr = ref<any>({});
const sprList = ref<any>([]);
const csrList = ref<any>([]);
const logList = ref<any>([]);
//
const csrExpanded = ref(false);
//
const logExpanded = ref(false);
//
const displayedcsrList = computed(() => {
if (csrExpanded.value || csrList.value.length <= 2) {
return csrList.value;
}
return csrList.value.slice(0, 2);
});
//
const displayedLogList = computed(() => {
if (logExpanded.value || logList.value.length <= 2) {
return logList.value;
}
return logList.value.slice(0, 2);
});
const showLogDetailModal = ref(false);
const currentLog = ref<any>({});
//
const showLogDetail = (log: any) => {
currentLog.value = log;
showLogDetailModal.value = true;
};
//
const toggleCsrExpanded = () => {
csrExpanded.value = !csrExpanded.value;
};
//
const toggleLogExpanded = () => {
logExpanded.value = !logExpanded.value;
};
//
const getStatusClass = (status: any) => {
const statusMap: Record<string, string> = {
draft: "status-draft",
pending: "status-pending",
approved: "status-approved",
rejected: "status-rejected",
};
return statusMap[status] || "status-default";
};
//
const getStatusText = (status: any) => {
const statusMap: Record<string, string> = {
draft: "草稿",
pending: "待审批",
approved: "已通过",
rejected: "已驳回",
};
return statusMap[status] || "未知";
};
//
const getSqrStatusText = (status: any) => {
const statusMap: Record<string, string> = {
apply: "已申请",
};
return statusMap[status] || "未知";
};
//
const getSqrStatusClass = (status: any) => {
const statusMap: Record<string, string> = {
unread: "status-unread",
read: "status-read",
};
return statusMap[status] || "status-default";
};
//
const getSprStatusClass = (status: any) => {
const statusMap: Record<string, string> = {
pending: "status-pending",
approved: "status-approved",
rejected: "status-rejected",
skipped: "status-skipped",
};
return statusMap[status] || "status-default";
};
//
const getSprStatusText = (status: any) => {
const statusMap: Record<string, string> = {
pending: "待审批",
approved: "已同意",
rejected: "已驳回",
skipped: "已跳过",
};
return statusMap[status] || "未知";
};
//
const getCCStatusClass = (status: any) => {
const statusMap: Record<string, string> = {
unread: "status-unread",
read: "status-read",
};
return statusMap[status] || "status-default";
};
//
const getCCStatusText = (status: any) => {
const statusMap: Record<string, string> = {
unread: "未读",
read: "已读",
};
return statusMap[status] || "未知";
};
//
const loadLcgl = async () => {
if (!props.ywId || !props.ywType) return;
try {
const params = {
ywId: props.ywId,
ywType: props.ywType,
}
// API
const res = await getLcglApi(params);
sqr.value = {};
sprList.value = [];
csrList.value = [];
logList.value = [];
if (res.resultCode === 1 && res.result) {
sqr.value = res.result.sqrSp || {};
sprList.value = res.result.sprSpList || [];
csrList.value = res.result.csrSpList || [];
logList.value = res.result.logList || [];
}
} catch (error) {
}
};
//
const formatTime = (time: string | Date) => {
if (!time) return '';
return dayjs(time).format('YYYY-MM-DD HH:mm');
};
// ywId
watch(() => props.ywId, (newVal) => {
if (newVal) {
loadLcgl();
}
});
//
if (props.ywId) {
loadLcgl();
}
</script>
<style lang="scss" scoped>
.lcgl-info {
padding: 0 30rpx;
.info-section {
margin-bottom: 30rpx;
padding: 30rpx;
background: #fff;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
&.sqr {
/* 申请人区域特殊样式可以在这里添加 */
background-color: white;
}
&.spr {
/* 审批人区域特殊样式可以在这里添加 */
background-color: white;
}
&.csr {
/* 抄送人区域特殊样式可以在这里添加 */
background-color: white;
}
&.log {
margin-bottom: 80rpx; //
}
}
.section-title {
font-size: 32rpx;
font-weight: bold;
margin-bottom: 30rpx;
color: #333;
border-bottom: 4rpx solid #007aff;
padding-bottom: 10rpx;
}
.sp-list {
/* 列表容器样式 */
background-color: white;
}
.sp-item {
display: flex;
flex-direction: column;
padding: 20rpx;
border: 2rpx solid #eee;
border-radius: 8rpx;
margin-bottom: 20rpx;
.sp-info {
display: flex;
align-items: center;
.name {
font-weight: 500;
margin-right: 16rpx;
}
.dept {
color: #666;
font-size: 24rpx;
margin-right: 16rpx;
}
.status {
padding: 4rpx 12rpx;
border-radius: 8rpx;
font-size: 24rpx;
margin-left: auto;
&.status-pending {
background: #fff7e6;
color: #fa8c16;
}
&.status-approved {
background: #f6ffed;
color: #52c41a;
}
&.status-rejected {
background: #fff2f0;
color: #ff4d4f;
}
&.status-skipped {
background: #f0f0f0;
color: #666;
}
&.status-unread {
background: #fff7e6;
color: #fa8c16;
}
&.status-read {
background: #f6ffed;
color: #52c41a;
}
&.status-default {
background: #f0f0f0;
color: #666;
}
}
}
}
.sp-detail {
margin-top: 20rpx;
padding: 20rpx;
background: #f8f9fa;
border-radius: 8rpx;
border-left: 6rpx solid #007aff;
.approval-info {
display: flex;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
.info-label {
width: 160rpx;
color: #666;
font-size: 24rpx;
flex-shrink: 0;
}
.info-value {
flex: 1;
color: #333;
font-size: 24rpx;
word-break: break-all;
}
}
}
.log-header {
display: flex;
justify-content: space-between;
margin-bottom: 16rpx;
.operator {
font-weight: 500;
color: #007aff;
}
.time {
font-size: 24rpx;
color: #666;
}
}
.log-content {
margin-bottom: 16rpx;
.content {
color: #333;
}
}
.log-detail {
margin-top: 10rpx;
}
.more-button {
display: flex;
align-items: center;
justify-content: center;
padding: 16rpx 32rpx;
margin-top: 20rpx;
margin-bottom: 40rpx;
background: #f8f9fa;
border: 2rpx solid #e9ecef;
border-radius: 12rpx;
cursor: pointer;
transition: all 0.3s ease;
&:active {
background: #e9ecef;
transform: translateY(1px);
}
.more-text {
font-size: 28rpx;
color: #007aff;
margin-right: 12rpx;
}
.more-icon {
font-size: 24rpx;
color: #007aff;
transition: transform 0.3s ease;
&.expanded {
transform: rotate(180deg);
}
}
}
.detail-modal {
width: 80vw;
max-width: 800rpx;
padding: 40rpx;
.detail-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 40rpx;
.detail-title {
font-size: 32rpx;
font-weight: bold;
}
}
.detail-content {
.detail-item {
margin-bottom: 30rpx;
.detail-label {
font-weight: 500;
color: #666;
margin-right: 20rpx;
}
.detail-value {
color: #333;
word-break: break-all;
}
}
}
}
}
</style>

View File

@ -22,7 +22,7 @@
text="取消"
class="ml-15 mr-7"
:plain="true"
@click="navigateBack"
@click="goHome"
/>
<u-button
text="提交"
@ -37,7 +37,6 @@
</template>
<script setup lang="ts">
import { navigateBack } from "@/utils/uniapp";
import { useForm } from "@/components/BasicForm/hooks/useForm";
import { jzAddXsQjApi } from "@/api/base/xsQjApi";
import { useDicStore } from "@/store/modules/dic";
@ -52,15 +51,15 @@ const commonStore = useCommonStore();
//
const props = withDefaults(defineProps<{
data: any
data?: any
}>(), {
data: () => ({
id: "",
qjlx: "事假",
qjkssj: "2025-07-07 09:00:00",
qjjssj: "2025-07-08 10:00:00",
qjsc: "25小时",
qjsy: "我有事情",
qjsc: "",
qjsy: "",
sflx: 1
})
});
@ -155,6 +154,12 @@ const [register, { getValue, setValue }] = useForm({
setValue(props.data)
const goHome = () => {
uni.reLaunch({
url: "/pages/base/home/index",
});
};
//
onMounted(async () => {
await getDefaultApprover();
@ -227,20 +232,17 @@ const submit = async () => {
params.jzId = getUser.jzId; // ID
params.jzxm = getUser.jzxm || getUser.xm; //
}
params.flag = 2;
// 便
console.log('当前学生信息:', getCurXs);
console.log('提交参数:', params);
uni.showLoading({ title: "提交中..." });
await jzAddXsQjApi(params).then(() => {
showToast({ title: "提交成功", icon: "success" });
uni.reLaunch({
url: "/pages/base/home/index"
});
});
const res = await jzAddXsQjApi(params);
uni.hideLoading();
setTimeout(() => {
if (res.resultCode === 1) {
showToast({ title: "提交成功", icon: "success" });
goHome();
} else {
showToast({ title: res.message, icon: "error" });
}
}, 500);
};
</script>

View File

@ -36,7 +36,7 @@
</view>
<!-- 审批流程 -->
<LcglSpList :yw-id="qjId" yw-type="XS_QJ" />
<LcglSp :yw-id="qjId" yw-type="XS_QJ" />
</view>
<template #bottom>
<view class="white-bg-color py-5">
@ -57,7 +57,7 @@
import { navigateBack } from "@/utils/uniapp";
import { useDataStore } from "@/store/modules/data";
import { getXsQjDetailApi } from "@/api/base/xsQjApi";
import LcglSpList from "@/components/LcglSpList/index.vue";
import LcglSp from "@/components/LcglSp/index.vue";
const { getData } = useDataStore();