zhxy-jsd/src/pages/view/notice/selectStudents.vue
2025-04-22 10:22:33 +08:00

216 lines
5.1 KiB
Vue

<template>
<BasicLayout>
<!-- Default slot content -->
<view class="student-selector-content">
<view class="header">
<text class="class-name">{{ className }}</text>
<text class="select-count"
>已选 {{ selectedStudentIds.length }} </text
>
</view>
<scroll-view scroll-y class="student-list-scroll">
<view v-if="isLoading" class="loading-indicator">加载中...</view>
<checkbox-group
@change="handleCheckboxChange"
v-else-if="studentList.length > 0"
>
<label
v-for="student in studentList"
:key="student.id"
class="student-item"
>
<view class="avatar-name-wrapper">
<image
:src="student.avatar || '/static/default-avatar.png'"
class="avatar"
></image>
<text class="student-name">{{ student.name }}</text>
</view>
<checkbox
:value="student.id"
:checked="selectedStudentIds.includes(student.id)"
class="checkbox"
/>
</label>
</checkbox-group>
<view v-else class="empty-state">该班级暂无学生数据</view>
</scroll-view>
</view>
<!-- Bottom slot content -->
<template #bottom>
<view class="bottom-actions">
<button class="action-btn confirm-btn" @click="confirmSelection">
确定
</button>
</view>
</template>
</BasicLayout>
</template>
<script lang="ts" setup>
import { ref, reactive } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import { navigateBack } from "@/utils/uniapp";
interface Student {
id: string;
name: string;
avatar?: string;
}
const classId = ref<string>("");
const className = ref<string>("未知班级");
const studentList = ref<Student[]>([
{ id: "s111", name: "施延兴", avatar: "/static/mock/avatar-m1.png" },
{ id: "s112", name: "安苒溪", avatar: "/static/mock/avatar-f1.png" },
{ id: "s113", name: "罗浩晨", avatar: "/static/mock/avatar-m2.png" },
{ id: "s114", name: "康萌", avatar: "/static/mock/avatar-f2.png" },
{ id: "s115", name: "范文昊", avatar: "/static/mock/avatar-m3.png" },
{ id: "s116", name: "丁贺祥", avatar: "/static/mock/avatar-m4.png" },
{ id: "s117", name: "韦运昊", avatar: "/static/mock/avatar-m5.png" },
{ id: "s118", name: "萧润丽", avatar: "/static/mock/avatar-f3.png" },
{ id: "s119", name: "谢林", avatar: "/static/mock/avatar-m6.png" },
{ id: "s120", name: "鲍泽远", avatar: "/static/mock/avatar-m7.png" },
{ id: "s121", name: "杨俊", avatar: "/static/mock/avatar-m8.png" },
]);
const isLoading = ref(false);
const selectedStudentIds = reactive<string[]>([]);
onLoad((options) => {});
const handleCheckboxChange = (e: any) => {
const currentSelectedIds = e.detail.value as string[];
selectedStudentIds.splice(
0,
selectedStudentIds.length,
...currentSelectedIds
);
};
const confirmSelection = () => {
navigateBack();
};
</script>
<style scoped lang="scss">
/* Remove original page container styles */
/*
.select-students-page {
display: flex;
flex-direction: column;
height: 100vh;
background-color: #f4f5f7;
}
*/
// Styles for the content within the default slot
.student-selector-content {
display: flex;
flex-direction: column;
height: 100%; // Assume BasicLayout provides a container with height
}
.header {
padding: 10px 15px;
background-color: #fff;
border-bottom: 1px solid #eee;
display: flex;
justify-content: space-between;
align-items: center;
flex-shrink: 0;
.class-name {
font-size: 16px;
font-weight: bold;
color: #333;
}
.select-count {
font-size: 14px;
color: #999;
}
}
.student-list-scroll {
flex: 1; // Allow scroll view to take remaining height
// Remove explicit height calculation
// height: calc(100vh - 51px - 65px);
background-color: #fff;
box-sizing: border-box;
overflow-y: auto;
}
.student-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 15px;
border-bottom: 1px solid #f0f0f0;
&:last-child {
border-bottom: none;
}
.avatar-name-wrapper {
display: flex;
align-items: center;
flex-grow: 1;
margin-right: 15px;
}
.avatar {
width: 35px;
height: 35px;
border-radius: 50%;
margin-right: 10px;
background-color: #eee;
}
.student-name {
font-size: 15px;
color: #333;
}
.checkbox {
flex-shrink: 0;
}
}
.loading-indicator,
.empty-state {
text-align: center;
color: #999;
padding: 30px 15px;
font-size: 14px;
}
// Styles for the content within the #bottom slot
.bottom-actions {
padding: 10px 15px;
background-color: #ffffff;
border-top: 1px solid #e0e0e0;
// flex-shrink: 0; // No longer needed as it's in a fixed slot
.action-btn {
width: 100%;
height: 44px;
line-height: 44px;
font-size: 16px;
border-radius: 22px;
&.confirm-btn {
background-color: #409eff;
color: #ffffff;
border: none;
&:active {
background-color: #3a8ee6;
}
}
&::after {
border: none;
}
}
}
</style>