接龙调整

This commit is contained in:
hebo 2025-09-26 18:10:23 +08:00
parent b578cf8c60
commit de573ba4b5
5 changed files with 858 additions and 384 deletions

View File

@ -248,7 +248,12 @@ export const jlSaveApi = async (params: any) => {
}; };
// 根据接龙ID查询接龙执行情况学生列表 // 根据接龙ID查询接龙执行情况学生列表
export const jlzxFindByJlParamsApi = async (params: { jlId: string }) => { export const jlzxFindByJlParamsApi = async (params: {
jlId: string;
njId?: string;
njmcId?: string;
bjId?: string;
}) => {
return await get("/api/jlzx/findByJlParams", params); return await get("/api/jlzx/findByJlParams", params);
}; };

View File

@ -149,8 +149,8 @@ export function getGwFlowByIdApi(id: string) {
/** /**
* *
*/ */
export function findUserTodosApi(approveStatus: string, jsId: string, pageNum: number = 1, pageSize: number = 20) { export function findUserTodosApi(dbZt: string, jsId: string, page: number = 1, rows: number = 20) {
return get('/api/gw/findUserTodos', { approveStatus, jsId, pageNum, pageSize }); return get('/api/gw/findUserTodos', { dbZt, jsId, page, rows });
} }
// ===== 新增:统一的流程接口 ===== // ===== 新增:统一的流程接口 =====

View File

@ -25,7 +25,7 @@
</view> </view>
</view> </view>
</u-popup> </u-popup>
<YwTransfer ref="transferRef" @submit="handleTransfer" /> <YwTransfer ref="transferRef" @submit="handleTransfer" v-if="Transferflag" />
<XtDkJs ref="xtDkJsRef" @submit="handleXtDkJs" /> <XtDkJs ref="xtDkJsRef" @submit="handleXtDkJs" />
</view> </view>
</template> </template>
@ -86,6 +86,7 @@ const dlgFlag = ref(false);
const dlgType = ref(""); const dlgType = ref("");
const dlgTips = ref(""); const dlgTips = ref("");
const spRemark = ref(""); const spRemark = ref("");
const Transferflag = ref(false);
const goToMessage = () => { const goToMessage = () => {
setTimeout(() => { setTimeout(() => {
@ -108,7 +109,11 @@ const closeDlg = () => {
}; };
const showTransfer = () => { const showTransfer = () => {
Transferflag.value = true;
nextTick(() => {
transferRef.value.showDlg(); transferRef.value.showDlg();
});
}; };
const showXtDlg = () => { const showXtDlg = () => {
@ -160,6 +165,7 @@ const handleTransfer = async (data: any) => {
uni.showLoading({ title: "正在转办..." }); uni.showLoading({ title: "正在转办..." });
await props.transferApi(params); await props.transferApi(params);
transferRef.value.closeDlg(); transferRef.value.closeDlg();
Transferflag.value = false;
uni.hideLoading(); uni.hideLoading();
emit('transfer'); emit('transfer');
if (props.autoToMessage) { if (props.autoToMessage) {

View File

@ -1,7 +1,76 @@
<!-- src/pages/view/notice/detail.vue --> <!-- src/pages/view/notice/detail.vue -->
<template> <template>
<BasicLayout> <BasicLayout>
<view class="notice-detail-page"> <view class="jl-detail-page">
<!-- 顶部Tab -->
<view class="tab-container">
<view
class="tab-item"
:class="{ active: activeTab === 'progress' }"
@click="switchTab('progress')"
>
完成情况
</view>
<view
class="tab-item"
:class="{ active: activeTab === 'detail' }"
@click="switchTab('detail')"
>
接龙详情
</view>
</view>
<!-- 完成情况内容 -->
<view v-if="activeTab === 'progress'" class="progress-content">
<!-- 班级选择器 -->
<view class="section">
<text class="section-title">选择班级可多选</text>
<view class="class-selector" @click="showClassTree">
<text :class="{ placeholder: !selectedClassText }">{{ selectedClassText || "请选择班级" }}</text>
<uni-icons type="right" size="16" color="#999"></uni-icons>
</view>
<!-- 班级选择提示 -->
<view v-if="selectedClasses.length === 0" class="class-tip">
<text class="tip-icon"></text>
<text class="tip-text">请先选择班级查看接龙完成情况</text>
</view>
</view>
<!-- 按班级统计信息 -->
<view v-if="selectedClasses.length > 0" class="section">
<view class="section-title">
接龙完成情况
<text class="refresh-btn" @click="loadAllClassData">刷新</text>
</view>
<!-- 每个班级的统计数据 -->
<view v-for="classData in classStatsList" :key="classData.bjId" class="class-stats-card">
<view class="class-header">
<text class="class-name">{{ classData.displayName }}</text>
<text class="class-completion">{{ classData.completionRate }}%</text>
</view>
<view class="class-stats-grid">
<view class="stat-item">
<text class="stat-number">{{ classData.total }}</text>
<text class="stat-label">总人数</text>
</view>
<view class="stat-item clickable" @click="showStudentDrawer('completed', classData)">
<text class="stat-number completed">{{ classData.completed }}</text>
<text class="stat-label">已接龙</text>
</view>
<view class="stat-item clickable" @click="showStudentDrawer('pending', classData)">
<text class="stat-number pending">{{ classData.pending }}</text>
<text class="stat-label">未接龙</text>
</view>
</view>
</view>
</view>
</view>
<!-- 接龙详情内容 -->
<view v-if="activeTab === 'detail'" class="detail-content">
<view v-if="isLoading" class="loading-indicator">加载中...</view> <view v-if="isLoading" class="loading-indicator">加载中...</view>
<view v-else-if="noticeDetail" class="detail-container"> <view v-else-if="noticeDetail" class="detail-container">
<!-- 1. 主要内容卡片 --> <!-- 1. 主要内容卡片 -->
@ -45,46 +114,104 @@
</view> </view>
</view> </view>
</view> </view>
<!-- 3. 学生完成状态卡片 -->
<view class="info-card feedback-card">
<text class="feedback-title">接龙完成情况 ({{ receivedCount }}/{{ totalStudents }})</text>
<view class="name-tags">
<view
v-for="stu in studentList"
:key="stu.id || stu.xsId"
class="name-tag"
:class="{ received: stu.jlwc_status === 'A' }"
>
<text>{{ stu.xsxm || stu.name }}</text>
<view v-if="stu.jlwc_status === 'A'" class="checkmark-icon">
<uni-icons type="checkmarkempty" size="12" color="#ffffff"></uni-icons>
</view>
</view>
</view>
</view>
</view> </view>
<view v-else class="empty-state">通知详情未找到</view> <view v-else class="empty-state">通知详情未找到</view>
</view> </view>
<template #bottom>
<view class="bottom-actions"> <!-- 班级选择树 -->
<button class="action-btn publish-btn">接龙</button> <BasicTree
ref="treeRef"
:range="treeData"
idKey="key"
rangeKey="title"
title="选择班级(可多选)"
:multiple="true"
:selectParent="false"
@confirm="onTreeConfirm"
@cancel="onTreeCancel"
/>
</view> </view>
</template>
<!-- 学生抽屉 -->
<view v-if="showDrawer" class="drawer-mask" @click="closeDrawer">
<view class="drawer-content" @click.stop>
<view class="drawer-header">
<text class="drawer-title">{{ drawerTitle }}</text>
<view class="drawer-close" @click="closeDrawer">
<uni-icons type="close" size="20" color="#666"></uni-icons>
</view>
</view>
<view class="drawer-body">
<view v-if="drawerStudents.length === 0" class="empty-state">
<text>暂无学生数据</text>
</view>
<view v-else class="student-list">
<view
v-for="student in drawerStudents"
:key="student.id || student.xsId"
class="student-item"
>
<view class="student-avatar">
<image
:src="imagUrl(student.xstx) || '/static/images/default-avatar.png'"
mode="aspectFill"
class="avatar-img"
></image>
</view>
<view class="student-info">
<text class="student-name">{{ student.xsxm || student.name }}</text>
<view class="student-status">
<view
class="status-tag"
:class="drawerType === 'completed' ? 'completed' : 'pending'"
>
{{ drawerType === 'completed' ? '已完成' : '未完成' }}
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</BasicLayout> </BasicLayout>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed, watch } from "vue"; import { ref, computed, watch, onMounted } from "vue";
import { onLoad } from "@dcloudio/uni-app"; import { onLoad } from "@dcloudio/uni-app";
import { getByJlIdApi, jlzxFindByJlParamsApi } from "@/api/base/server"; import { getByJlIdApi, jlzxFindByJlParamsApi, findAllNjBjTree } from "@/api/base/server";
import { imagUrl } from "@/utils"; import { imagUrl } from "@/utils";
import { BASE_IMAGE_URL } from "@/config"; import { BASE_IMAGE_URL } from "@/config";
import BasicTree from '@/components/BasicTree/Tree.vue';
// Tab
const activeTab = ref('progress');
//
const noticeId = ref<string>(""); const noticeId = ref<string>("");
const noticeDetail = ref<any>(null); const noticeDetail = ref<any>(null);
const isLoading = ref(false); const isLoading = ref(false);
const studentList = ref<any[]>([]); const descExpanded = ref(true);
const descExpanded = ref(false);
//
const treeData = ref<any[]>([]);
const treeRef = ref();
const selectedClasses = ref<any[]>([]);
const selectedClassText = ref('');
//
const classStatsList = ref<any[]>([]);
//
const showDrawer = ref(false);
const drawerType = ref('');
const drawerTitle = ref('');
const drawerStudents = ref<any[]>([]);
const currentClassData = ref<any>(null);
const descPreview = computed(() => { const descPreview = computed(() => {
if (!noticeDetail.value?.jlms) return ''; if (!noticeDetail.value?.jlms) return '';
const div = document.createElement('div'); const div = document.createElement('div');
@ -99,32 +226,214 @@ const getFileName = (filePath: string) => {
return parts[parts.length - 1] || filePath; return parts[parts.length - 1] || filePath;
}; };
// Computed properties for feedback status // Tab
const receivedCount = computed(() => { const switchTab = (tab: string) => {
return studentList.value.filter((s) => s.jlwc_status === 'A').length; activeTab.value = tab;
}); if (tab === 'progress') {
const totalStudents = computed(() => studentList.value.length); loadClassTree();
}
};
//
const loadClassTree = async () => {
try {
const res = await findAllNjBjTree();
console.log('【班级树API响应】', res);
if (res.resultCode === 1 && res.result) {
// BasicTree
const convertTreeData = (items: any[]): any[] => {
return items.map((item: any) => ({
key: item.key,
title: item.title,
njmcId: item.njmcId,
children: item.children ? convertTreeData(item.children) : [],
}));
};
treeData.value = convertTreeData(res.result);
console.log('【转换后的树数据】', treeData.value);
} else {
console.log('【API响应格式不正确】', res);
treeData.value = [];
}
} catch (error) {
console.error('加载班级树失败:', error);
treeData.value = [];
}
};
//
const showClassTree = () => {
if (treeRef.value) {
treeRef.value._show();
}
};
//
const onTreeConfirm = (selectedNodes: any[]) => {
if (selectedNodes && selectedNodes.length > 0) {
selectedClasses.value = selectedNodes;
//
if (selectedNodes.length === 1) {
selectedClassText.value = selectedNodes[0].title;
} else {
selectedClassText.value = `已选择${selectedNodes.length}个班级`;
}
loadAllClassData();
} else {
selectedClasses.value = [];
selectedClassText.value = '';
classStatsList.value = [];
}
};
//
const onTreeCancel = () => {
//
};
//
const loadAllClassData = async () => {
if (selectedClasses.value.length === 0 || !noticeId.value) return;
try {
isLoading.value = true;
const classStatsPromises = selectedClasses.value.map(async (classNode) => {
try {
const stuRes = await jlzxFindByJlParamsApi({
jlId: noticeId.value,
bjId: classNode.key
} as any);
const students = stuRes?.rows || stuRes?.result || [];
//
students.forEach((stu: any) => {
if (stu.jlwcStatus && !stu.jlwc_status) {
stu.jlwc_status = stu.jlwcStatus;
}
if (stu.jlwc_status === '1') {
stu.jlwc_status = 'A';
}
});
const completed = students.filter((s: any) => s.jlwc_status === 'A').length;
const total = students.length;
const pending = total - completed;
const completionRate = total > 0 ? Math.round((completed / total) * 100) : 0;
//
let njmc = '';
let bjmc = '';
if (students.length > 0) {
njmc = students[0].njmc || '';
bjmc = students[0].bjmc || '';
}
return {
bjId: classNode.key,
className: classNode.title,
njmc,
bjmc,
displayName: njmc && bjmc ? `${njmc}${bjmc}` : classNode.title,
total,
completed,
pending,
completionRate
};
} catch (error) {
console.error(`加载班级 ${classNode.title} 数据失败:`, error);
return {
bjId: classNode.key,
className: classNode.title,
total: 0,
completed: 0,
pending: 0,
completionRate: 0
};
}
});
const results = await Promise.all(classStatsPromises);
classStatsList.value = results;
} catch (error) {
console.error('加载班级数据失败:', error);
uni.showToast({ title: "加载班级数据失败", icon: "none" });
} finally {
isLoading.value = false;
}
};
//
const showStudentDrawer = async (type: string, classData: any) => {
if (!classData || !noticeId.value) return;
try {
drawerType.value = type;
currentClassData.value = classData;
//
const stuRes = await jlzxFindByJlParamsApi({
jlId: noticeId.value,
bjId: classData.bjId
} as any);
const students = stuRes?.rows || stuRes?.result || [];
//
students.forEach((stu: any) => {
if (stu.jlwcStatus && !stu.jlwc_status) {
stu.jlwc_status = stu.jlwcStatus;
}
if (stu.jlwc_status === '1') {
stu.jlwc_status = 'A';
}
});
//
if (type === 'completed') {
drawerStudents.value = students.filter((s: any) => s.jlwc_status === 'A');
drawerTitle.value = `${classData.displayName} - 已接龙学生 (${drawerStudents.value.length}人)`;
} else if (type === 'pending') {
drawerStudents.value = students.filter((s: any) => s.jlwc_status !== 'A');
drawerTitle.value = `${classData.displayName} - 未接龙学生 (${drawerStudents.value.length}人)`;
}
showDrawer.value = true;
} catch (error) {
console.error('加载学生数据失败:', error);
uni.showToast({ title: "加载学生数据失败", icon: "none" });
}
};
//
const closeDrawer = () => {
showDrawer.value = false;
drawerStudents.value = [];
currentClassData.value = null;
};
onLoad(async (options) => { onLoad(async (options) => {
if (options && options.id) { if (options && options.id) {
noticeId.value = options.id; noticeId.value = options.id;
isLoading.value = true; isLoading.value = true;
// 1.
// 1.
try { try {
const detailRes = await getByJlIdApi({ jlId: noticeId.value }); const detailRes = await getByJlIdApi({ jlId: noticeId.value });
noticeDetail.value = Array.isArray(detailRes) ? detailRes[0] : {}; noticeDetail.value = Array.isArray(detailRes) ? detailRes[0] : {};
} catch (e) { } catch (e) {
uni.showToast({ title: "加载接龙详情失败", icon: "none" }); uni.showToast({ title: "加载接龙详情失败", icon: "none" });
} }
// 2.
try { // 2.
const stuRes = await jlzxFindByJlParamsApi({ jlId: noticeId.value }); await loadClassTree();
studentList.value = stuRes?.rows || stuRes?.result || [];
} catch (e) {
uni.showToast({ title: "加载学生状态失败", icon: "none" });
}
isLoading.value = false; isLoading.value = false;
uni.setNavigationBarTitle({ title: "接龙情况" }); uni.setNavigationBarTitle({ title: "接龙详情" });
} else { } else {
uni.showToast({ title: "加载失败缺少通知ID", icon: "none" }); uni.showToast({ title: "加载失败缺少通知ID", icon: "none" });
} }
@ -185,82 +494,260 @@ const previewAttachment = (filePath: string) => {
}); });
}; };
watch(noticeDetail, (val) => {
//
}, { immediate: true, deep: true });
//
watch(studentList, (list) => {
list.forEach(stu => {
//
if (stu.jlwcStatus && !stu.jlwc_status) {
stu.jlwc_status = stu.jlwcStatus;
}
// '1''A'
if (stu.jlwc_status === '1') {
stu.jlwc_status = 'A';
}
});
}, { immediate: true, deep: true });
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.notice-detail-page { .jl-detail-page {
background-color: #f4f5f7; background-color: #f5f5f5;
padding-bottom: 70px; min-height: 100vh;
display: flex;
flex-direction: column;
}
// Tab
.tab-container {
display: flex;
background-color: #fff;
border-bottom: 1px solid #e5e5e5;
position: sticky;
top: 0;
z-index: 100;
}
.tab-item {
flex: 1;
text-align: center;
padding: 20rpx 0;
font-size: 28rpx;
color: #666;
position: relative;
&.active {
color: #007aff;
font-weight: bold;
&::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 60rpx;
height: 4rpx;
background-color: #007aff;
border-radius: 2rpx;
}
}
}
//
.detail-content,
.progress-content {
flex: 1;
padding: 15px; padding: 15px;
box-sizing: border-box; box-sizing: border-box;
} }
.bottom-actions { // Section
.section {
background-color: #fff;
border-radius: 8px;
padding: 15px;
margin-bottom: 12px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
}
.section-title {
font-size: 16px;
font-weight: bold;
color: #333;
margin-bottom: 15px;
display: flex; display: flex;
justify-content: space-around; justify-content: space-between;
align-items: center; align-items: center;
padding: 12px 15px; }
background-color: #ffffff;
border-top: 1px solid #e5e5e5;
.action-btn { .section-subtitle {
width: 90%; font-size: 14px;
min-width: 90px; color: #666;
margin: 0 5px; margin-bottom: 10px;
font-size: 15px; display: block;
height: 40px; }
line-height: 40px;
border-radius: 20px;
padding: 0 20px;
&::after { .refresh-btn {
border: none; font-size: 12px;
}
&.draft-btn {
background-color: #f4f4f5;
color: #909399;
border: 1px solid #e9e9eb;
}
&.preview-btn {
background-color: #ecf5ff;
color: #409eff; color: #409eff;
border: 1px solid #d9ecff; padding: 4px 8px;
border: 1px solid #409eff;
border-radius: 4px;
}
//
.class-selector {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px;
background-color: #f8f9fa;
border-radius: 6px;
border: 1px solid #e9ecef;
margin-bottom: 10px;
.placeholder {
color: #999;
} }
&.publish-btn { }
background-color: #409eff;
color: #ffffff; .class-tip {
border: none; display: flex;
align-items: center;
padding: 10px;
background-color: #f0f9ff;
border-radius: 6px;
border-left: 4px solid #409eff;
.tip-icon {
margin-right: 8px;
font-size: 16px;
} }
&.draft-btn:active {
background-color: #e0e0e0; .tip-text {
font-size: 14px;
color: #409eff;
} }
&.preview-btn:active { }
background-color: #d9ecff;
//
.class-stats-card {
background-color: #f8f9fa;
border-radius: 8px;
padding: 15px;
margin-bottom: 12px;
border: 1px solid #e9ecef;
}
.class-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid #e9ecef;
}
.class-name {
font-size: 16px;
font-weight: bold;
color: #333;
}
.class-completion {
font-size: 18px;
font-weight: bold;
color: #409eff;
}
.class-stats-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
.stat-item.clickable {
cursor: pointer;
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
background-color: #e9ecef;
} }
&.publish-btn:active { }
background-color: #3a8ee6;
//
.stats-container {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
margin-bottom: 15px;
}
.stat-item {
text-align: center;
padding: 15px 8px;
background-color: #f8f9fa;
border-radius: 8px;
border: 1px solid #e9ecef;
&.clickable {
cursor: pointer;
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
background-color: #e9ecef;
} }
} }
} }
.stat-number {
display: block;
font-size: 18px;
font-weight: bold;
margin-bottom: 4px;
&.completed {
color: #67c23a;
}
&.pending {
color: #f56c6c;
}
}
.stat-label {
display: block;
font-size: 12px;
color: #666;
}
.status-tag {
display: inline-flex;
align-items: center;
padding: 4px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
&.completed {
background-color: #e1f3d8;
color: #67c23a;
border: 1px solid #b3e19d;
}
&.pending {
background-color: #fef0f0;
color: #f56c6c;
border: 1px solid #fbc4c4;
}
}
.status-icon {
margin-left: 4px;
}
.bg-white {
background-color: #fff;
}
.r-md {
border-radius: 8px;
}
.p-12 {
padding: 12px;
}
.loading-indicator, .loading-indicator,
.empty-state { .empty-state {
text-align: center; text-align: center;
@ -538,4 +1025,115 @@ watch(studentList, (list) => {
} }
} }
} }
/* 抽屉样式 */
.drawer-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1000;
display: flex;
align-items: flex-end;
}
.drawer-content {
width: 100%;
max-height: 70vh;
background-color: #fff;
border-radius: 20px 20px 0 0;
overflow: hidden;
}
.drawer-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px;
border-bottom: 1px solid #f0f0f0;
background-color: #fff;
}
.drawer-title {
font-size: 18px;
font-weight: bold;
color: #333;
}
.drawer-close {
padding: 5px;
cursor: pointer;
}
.drawer-body {
max-height: calc(70vh - 80px);
overflow-y: auto;
padding: 0 20px 20px;
}
.student-list {
padding-top: 10px;
}
.student-item {
display: flex;
align-items: center;
padding: 15px 0;
border-bottom: 1px solid #f5f5f5;
}
.student-item:last-child {
border-bottom: none;
}
.student-avatar {
width: 50px;
height: 50px;
border-radius: 50%;
overflow: hidden;
margin-right: 15px;
background-color: #f5f5f5;
}
.avatar-img {
width: 100%;
height: 100%;
}
.student-info {
flex: 1;
}
.student-name {
font-size: 16px;
color: #333;
font-weight: 500;
display: block;
margin-bottom: 5px;
}
.student-status {
display: flex;
align-items: center;
}
.status-tag {
font-size: 12px;
padding: 4px 8px;
border-radius: 12px;
display: inline-block;
}
.status-tag.completed {
background-color: #e6f7ff;
color: #52c41a;
}
.status-tag.pending {
background-color: #fff2f0;
color: #ff4d4f;
}
</style> </style>

View File

@ -1,7 +1,7 @@
<template> <template>
<view class="gw-list-page"> <view class="gw-list-page">
<!-- 搜索和筛选组件 --> <!-- 顶部搜索区域 -->
<view class="query-component"> <view class="top-section">
<view class="search-card"> <view class="search-card">
<!-- 搜索框和查询按钮 --> <!-- 搜索框和查询按钮 -->
<view class="search-item"> <view class="search-item">
@ -37,24 +37,32 @@
</view> </view>
</view> </view>
<!-- 中间数据区域 -->
<view class="middle-section">
<z-paging
ref="pagingRef"
v-model="dataList"
@query="queryData"
:auto="true"
:refresher-enabled="true"
:loading-more-enabled="true"
:loading-more-threshold="50"
:default-page-size="10"
:show-loading-more-no-more-view="true"
:show-empty-view-reload="false"
:fixed="false"
class="paging-container"
>
<!-- 列表内容 --> <!-- 列表内容 -->
<view class="list-content">
<!-- 加载状态 -->
<view v-if="loading" class="loading-container">
<view class="loading-text">加载中...</view>
</view>
<!-- 数据列表 -->
<view v-else>
<view <view
v-for="(data, index) in filteredGwList" v-for="(data, index) in dataList"
:key="data.id || index" :key="data.id || index"
class="gw-card" class="gw-card"
> >
<view class="card-header"> <view class="card-header">
<text class="gw-title">{{ data.title }}</text> <text class="gw-title">{{ data.title }}</text>
<text class="gw-status" :class="getStatusClass(data.gwStatus)"> <text class="gw-status" :class="getStatusClass(data.spJd)">
{{ getStatusText(data.gwStatus) }} {{ getStatusText(data.spJd) }}
</text> </text>
</view> </view>
@ -103,12 +111,7 @@
</view> </view>
</view> </view>
</view> </view>
</z-paging>
<!-- 空状态 -->
<view v-if="!loading && filteredGwList.length === 0" class="empty-container">
<view class="empty-text">暂无数据</view>
</view>
</view>
</view> </view>
</view> </view>
</template> </template>
@ -118,7 +121,7 @@ import { ref, computed, watch, onMounted, onUnmounted } from "vue";
import { onShow } from "@dcloudio/uni-app"; import { onShow } from "@dcloudio/uni-app";
import { navigateTo } from "@/utils/uniapp"; import { navigateTo } from "@/utils/uniapp";
import BasicSearch from "@/components/BasicSearch/Search.vue"; import BasicSearch from "@/components/BasicSearch/Search.vue";
import { gwFindPageApi, findUserTodosApi } from "@/api/routine/gw"; import { findUserTodosApi } from "@/api/routine/gw";
import { gwSqApi, gwSpApi, gwTransferApi, gwStopApi, gwCxtjApi, gwXtApi } from "@/api/routine/gw"; import { gwSqApi, gwSpApi, gwTransferApi, gwStopApi, gwCxtjApi, gwXtApi } from "@/api/routine/gw";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { imagUrl } from "@/utils"; import { imagUrl } from "@/utils";
@ -143,7 +146,7 @@ interface GwListItem {
id: string; id: string;
title: string; title: string;
docType: string; docType: string;
gwStatus: string; spJd: string; // A-Z-
fileUrl?: string; fileUrl?: string;
fileName?: string; fileName?: string;
fileFormat?: string; fileFormat?: string;
@ -169,174 +172,108 @@ const userStore = useUserStore();
// //
const dataList = ref<GwListItem[]>([]); const dataList = ref<GwListItem[]>([]);
const loading = ref(false); const pagingRef = ref<any>(null);
// ID // ID
const getCurrentTeacherId = () => { const getCurrentTeacherId = () => {
const jsData = userStore.getJs; const jsData = userStore.getJs;
console.log('用户store数据:', userStore);
console.log('教师数据:', jsData);
return jsData?.id || null; return jsData?.id || null;
}; };
// // z-paging
const filteredGwList = computed(() => { const queryData = async (pageNo: number, pageSize: number) => {
let list = dataList.value; console.log('queryData 被调用:', { pageNo, pageSize, activeTab: activeTab.value });
// /API try {
// "" const currentTeacherId = getCurrentTeacherId();
if (activeTab.value === "all") { console.log('当前教师ID:', currentTeacherId);
//
if (!currentTeacherId) {
console.log('教师ID为空停止查询');
uni.showToast({
title: '无法获取用户信息',
icon: 'error'
});
pagingRef.value?.complete([]);
return;
} }
// let response: any;
if (activeTab.value === "all") {
// dbZt
console.log('调用全部API:', { jsId: currentTeacherId, pageNo, pageSize });
response = await findUserTodosApi('', currentTeacherId, pageNo, pageSize);
console.log('全部API响应:', response);
} else if (activeTab.value === "pending") {
// dbZt = 'A'
console.log('调用待办API:', { dbZt: 'A', jsId: currentTeacherId, pageNo, pageSize });
response = await findUserTodosApi('A', currentTeacherId, pageNo, pageSize);
console.log('待办API响应:', response);
} else if (activeTab.value === "approved") {
// dbZt = 'B'
console.log('调用已办API:', { dbZt: 'B', jsId: currentTeacherId, pageNo, pageSize });
response = await findUserTodosApi('B', currentTeacherId, pageNo, pageSize);
console.log('已办API响应:', response);
}
// API
const result = (response as any).data || response;
let newData: GwListItem[] = [];
if (result.rows && Array.isArray(result.rows)) {
newData = result.rows;
} else if (result.resultCode === 1) {
newData = result.result || [];
} else {
uni.showToast({
title: result.message || '加载失败',
icon: 'error'
});
newData = [];
}
//
if (searchKeyword.value) { if (searchKeyword.value) {
const keyword = searchKeyword.value.toLowerCase(); const keyword = searchKeyword.value.toLowerCase();
list = list.filter((item: GwListItem) => newData = newData.filter((item: GwListItem) =>
item.title.toLowerCase().includes(keyword) || item.title.toLowerCase().includes(keyword) ||
(item.gwNo && item.gwNo.toLowerCase().includes(keyword)) || (item.gwNo && item.gwNo.toLowerCase().includes(keyword)) ||
(item.docType && item.docType.toLowerCase().includes(keyword)) (item.docType && item.docType.toLowerCase().includes(keyword))
); );
} }
return list; pagingRef.value?.complete(newData);
});
} catch (error) {
console.error('查询数据失败:', error);
uni.showToast({
title: '查询失败',
icon: 'error'
});
pagingRef.value?.complete([]);
}
};
// //
const switchTab = (tabKey: string) => { const switchTab = (tabKey: string) => {
activeTab.value = tabKey; activeTab.value = tabKey;
//
// ID pagingRef.value?.reload();
const currentTeacherId = getCurrentTeacherId();
if (tabKey === "all") {
// findPage API
loadAllData();
} else if (tabKey === "pending") {
// findUserTodos API approveStatus = 'pending'
if (currentTeacherId) {
loadUserTodos('pending', currentTeacherId);
} else {
uni.showToast({
title: '无法获取用户信息',
icon: 'error'
});
}
} else if (tabKey === "approved") {
// findUserTodos API approveStatus = 'approved'
if (currentTeacherId) {
loadUserTodos('approved', currentTeacherId);
} else {
uni.showToast({
title: '无法获取用户信息',
icon: 'error'
});
}
}
};
// findPage
const loadAllData = async () => {
try {
loading.value = true;
uni.showLoading({ title: '加载中...' });
const response = await gwFindPageApi({
title: searchKeyword.value,
docType: searchKeyword.value,
gwStatus: ""
});
// -
const result = (response as any).data || response;
// {total, page, records, rows}
if (result.rows && Array.isArray(result.rows)) {
dataList.value = result.rows;
} else if (result.resultCode === 1) {
//
dataList.value = result.result || [];
} else {
uni.showToast({
title: result.message || '加载失败',
icon: 'error'
});
dataList.value = [];
}
} catch (error) {
console.error('加载全部数据失败:', error);
uni.showToast({
title: '加载失败',
icon: 'error'
});
dataList.value = [];
} finally {
loading.value = false;
uni.hideLoading();
}
};
// / findUserTodos
const loadUserTodos = async (approveStatus: string, jsId: string) => {
try {
loading.value = true;
uni.showLoading({ title: '加载中...' });
// findUserTodos 使
const response = await findUserTodosApi(approveStatus, jsId, 1, 50); // 使
// -
const result = (response as any).data || response;
// {total, page, records, rows}
if (result.rows && Array.isArray(result.rows)) {
dataList.value = result.rows;
} else if (result.resultCode === 1) {
//
dataList.value = result.result || [];
} else {
uni.showToast({
title: result.message || '加载失败',
icon: 'error'
});
dataList.value = [];
}
} catch (error) {
console.error('加载用户待办/已办数据失败:', error);
uni.showToast({
title: '加载失败',
icon: 'error'
});
dataList.value = [];
} finally {
loading.value = false;
uni.hideLoading();
}
}; };
// //
const handleSearch = (keyword: string) => { const handleSearch = (keyword: string) => {
searchKeyword.value = keyword; searchKeyword.value = keyword;
//
// pagingRef.value?.reload();
if (activeTab.value === "all") {
// 使 findPage API
loadAllData();
} else {
// / findUserTodos
const currentTeacherId = getCurrentTeacherId();
if (currentTeacherId) {
loadUserTodos(activeTab.value, currentTeacherId);
} else {
uni.showToast({
title: '无法获取用户信息',
icon: 'error'
});
}
}
}; };
// //
const goToDetail = (item: GwListItem) => { const goToDetail = (item: GwListItem) => {
navigateTo(`/pages/view/routine/gwlz/gwFlow?id=${item.id}`); navigateTo(`/pages/view/routine/gwlz/gwFlow?id=${item.id}&openId=${userStore.getUser.openId}&from=db`);
}; };
// //
@ -355,34 +292,30 @@ const createNewGw = () => {
}; };
// //
const getStatusClass = (status: string) => { const getStatusClass = (spJd: string) => {
const statusMap: Record<string, string> = { const statusMap: Record<string, string> = {
'A': "status-draft", // A 'A': "status-pending", // A-
'B': "status-submitted", // B 'Z': "status-completed", // Z-
'C': "status-pending", // C
'D': "status-completed", // D
}; };
return statusMap[status] || "status-default"; return statusMap[spJd] || "status-default";
}; };
// //
const getStatusText = (status: string) => { const getStatusText = (spJd: string) => {
const statusMap: Record<string, string> = { const statusMap: Record<string, string> = {
'A': "暂存", // A 'A': "审批中", // A-
'B': "提交", // B 'Z': "审批结束", // Z-
'C': "审批中", // C
'D': "已完结", // D
}; };
return statusMap[status] || "未知"; return statusMap[spJd] || "未知";
}; };
// - // -
const getButtonText = (item: GwListItem) => { const getButtonText = (item: GwListItem) => {
const currentTeacherId = getCurrentTeacherId(); const currentTeacherId = getCurrentTeacherId();
const { gwStatus, spZbqd, spResult } = item; const { spJd, spZbqd, spResult } = item;
// "" // ""
if (currentTeacherId && spZbqd && gwStatus === 'B' && activeTab.value === 'pending') { if (currentTeacherId && spZbqd && spJd === 'A' && activeTab.value === 'pending') {
const approverIds = spZbqd.split(',').map(id => id.trim()); const approverIds = spZbqd.split(',').map(id => id.trim());
if (approverIds.includes(currentTeacherId)) { if (approverIds.includes(currentTeacherId)) {
return '审批'; return '审批';
@ -408,7 +341,7 @@ const getButtonText = (item: GwListItem) => {
const getButtonClass = (item: GwListItem) => { const getButtonClass = (item: GwListItem) => {
const buttonText = getButtonText(item); const buttonText = getButtonText(item);
const currentTeacherId = getCurrentTeacherId(); const currentTeacherId = getCurrentTeacherId();
const { gwStatus, spZbqd, spResult } = item; const { spJd, spZbqd, spResult } = item;
// //
if (buttonText === '审批') { if (buttonText === '审批') {
@ -590,58 +523,21 @@ const getFileIcon = (fileType: string) => {
} }
}; };
//
watch(dataList, (val) => {
//
});
// //
onShow(() => { onShow(() => {
if (activeTab.value === "all") { pagingRef.value?.reload();
loadAllData();
} else {
// / findUserTodos
const currentTeacherId = getCurrentTeacherId();
if (currentTeacherId) {
loadUserTodos(activeTab.value, currentTeacherId);
} else {
uni.showToast({
title: '无法获取用户信息',
icon: 'error'
});
}
}
}); });
// //
onMounted(() => { onMounted(() => {
// "" findUserTodos console.log('页面加载完成z-paging ref:', pagingRef.value);
const currentTeacherId = getCurrentTeacherId(); console.log('当前用户store:', userStore);
if (currentTeacherId) { console.log('当前教师ID:', getCurrentTeacherId());
loadUserTodos('pending', currentTeacherId);
} else {
uni.showToast({
title: '无法获取用户信息',
icon: 'error'
});
}
// gwFlow // gwFlow
uni.$on('refreshGwList', () => { uni.$on('refreshGwList', () => {
if (activeTab.value === "all") { console.log('收到刷新事件');
loadAllData(); pagingRef.value?.reload();
} else {
// / findUserTodos
const currentTeacherId = getCurrentTeacherId();
if (currentTeacherId) {
loadUserTodos(activeTab.value, currentTeacherId);
} else {
uni.showToast({
title: '无法获取用户信息',
icon: 'error'
});
}
}
}); });
}); });
@ -659,16 +555,31 @@ onUnmounted(() => {
background-color: #f5f7fa; background-color: #f5f7fa;
} }
.list-component { //
flex: 1; .top-section {
overflow: hidden; position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
background-color: #fff;
border-bottom: 1px solid #eee;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
padding: 12px;
} }
.query-component { //
padding: 15px; .middle-section {
background-color: white; flex: 1;
border-bottom: 1px solid #eee; margin-top: 140px; //
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04); height: calc(100vh - 140px);
background-color: #f5f7fa;
}
.paging-container {
height: 100%;
padding: 12px;
box-sizing: border-box;
} }
.search-card { .search-card {
@ -780,14 +691,6 @@ onUnmounted(() => {
flex-shrink: 0; flex-shrink: 0;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
&.status-draft {
background: linear-gradient(135deg, #ffa726 0%, #ff9800 100%);
color: white;
}
&.status-submitted {
background: linear-gradient(135deg, #2196f3 0%, #1976d2 100%);
color: white;
}
&.status-pending { &.status-pending {
background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%); background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%);
color: white; color: white;
@ -984,47 +887,9 @@ onUnmounted(() => {
} }
} }
// // z-paging
.list-content { .paging-container {
flex: 1;
padding: 15px; padding: 15px;
overflow-y: auto;
}
//
.loading-container {
display: flex;
justify-content: center;
align-items: center;
padding: 40px 20px;
background-color: white;
border-radius: 8px;
margin-bottom: 15px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.loading-text {
font-size: 14px;
color: #666;
text-align: center;
}
//
.empty-container {
display: flex;
justify-content: center;
align-items: center;
padding: 60px 20px;
background-color: white;
border-radius: 8px;
margin-bottom: 15px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.empty-text {
font-size: 14px;
color: #999;
text-align: center;
} }
// //