216 lines
5.1 KiB
Vue
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>
|