411 lines
9.1 KiB
Vue
411 lines
9.1 KiB
Vue
<template>
|
||
<BasicLayout>
|
||
<!-- 课程信息卡片 -->
|
||
<view class="course-card mx-15 my-15 bg-white white-bg-color r-md p-15">
|
||
<view class="flex-row items-center mb-15">
|
||
<view class="course-icon flex-center mr-10">
|
||
<u-icon name="calendar" color="#4080ff" size="20"></u-icon>
|
||
</view>
|
||
<text class="font-16 font-bold">机器人创客</text>
|
||
<text class="font-14 cor-999 ml-auto">2024-12-25 (周三)</text>
|
||
</view>
|
||
|
||
<!-- 考勤统计 -->
|
||
<view class="attendance-stats flex-row">
|
||
<view class="stat-item flex-col items-center">
|
||
<text class="font-18 font-bold">18</text>
|
||
<text class="font-12 cor-666 mt-3">应到</text>
|
||
</view>
|
||
<view class="stat-item flex-col items-center">
|
||
<text class="font-18 font-bold cor-primary">18</text>
|
||
<text class="font-12 cor-666 mt-3">实到</text>
|
||
</view>
|
||
<view class="stat-item flex-col items-center">
|
||
<text class="font-18 font-bold cor-warning">0</text>
|
||
<text class="font-12 cor-666 mt-3">请假</text>
|
||
</view>
|
||
<view class="stat-item flex-col items-center">
|
||
<text class="font-18 font-bold cor-danger">0</text>
|
||
<text class="font-12 cor-666 mt-3">缺勤</text>
|
||
</view>
|
||
<view class="stat-circle flex-col flex-center ml-auto">
|
||
<text class="font-20 font-bold">18</text>
|
||
<text class="font-10 cor-666">总人数</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 学生列表 -->
|
||
<view class="student-list mb-30 white-bg-color">
|
||
<view class="student-grid">
|
||
<view
|
||
v-for="(student, index) in studentList"
|
||
:key="index"
|
||
class="student-item bg-white r-md p-12"
|
||
>
|
||
<view class="flex-row items-center">
|
||
<view class="avatar-container mr-8">
|
||
<image
|
||
class="student-avatar"
|
||
:src="student.avatar || '/static/images/default-avatar.png'"
|
||
mode="aspectFill"
|
||
></image>
|
||
</view>
|
||
<view class="flex-1 overflow-hidden">
|
||
<view class="flex-row items-center mb-3">
|
||
<text class="font-14 font-bold mr-5 text-ellipsis">{{
|
||
student.name
|
||
}}
|
||
</text>
|
||
<view
|
||
class="status-tag"
|
||
:class="getStatusClass(student.status)"
|
||
@click="openStatusPicker(student)"
|
||
>
|
||
{{ student.status }}
|
||
<u-icon name="arrow-down" size="10"></u-icon>
|
||
</view>
|
||
</view>
|
||
<text class="font-12 cor-666">{{ student.className }}</text>
|
||
<view class="contact-parent mt-8 flex-center">
|
||
<text class="font-12 cor-primary">联系家长</text>
|
||
<u-icon
|
||
name="phone"
|
||
color="#4080ff"
|
||
size="14"
|
||
class="ml-2"
|
||
></u-icon>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 状态选择弹窗 -->
|
||
<u-picker
|
||
:show="statusPickerVisible"
|
||
:columns="[statusOptions]"
|
||
@confirm="confirmStatus"
|
||
@cancel="statusPickerVisible = false"
|
||
></u-picker>
|
||
|
||
<template #bottom>
|
||
<view class="submit-btn-wrap py-10 px-20 bg-white">
|
||
<button class="submit-btn" @click="submit">提交</button>
|
||
</view>
|
||
</template>
|
||
</BasicLayout>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import {onMounted, ref} from "vue";
|
||
import BasicLayout from "@/components/BasicLayout/Layout.vue";
|
||
import { useDicStore } from "@/store/modules/dic";
|
||
const { findByPid } = useDicStore();
|
||
|
||
// 模拟学生数据
|
||
const studentList = ref([
|
||
{
|
||
id: 1,
|
||
name: "伍添昊",
|
||
status: "正常",
|
||
className: "三年八班",
|
||
avatar: "/static/images/avatar1.png",
|
||
},
|
||
{
|
||
id: 2,
|
||
name: "时振宇",
|
||
status: "正常",
|
||
className: "三年八班",
|
||
avatar: "/static/images/avatar2.png",
|
||
},
|
||
{
|
||
id: 3,
|
||
name: "程子璇",
|
||
status: "正常",
|
||
className: "三年八班",
|
||
avatar: "/static/images/avatar3.png",
|
||
},
|
||
{
|
||
id: 4,
|
||
name: "柘延兴",
|
||
status: "正常",
|
||
className: "三年八班",
|
||
avatar: "/static/images/avatar4.png",
|
||
},
|
||
{
|
||
id: 5,
|
||
name: "张茜溪",
|
||
status: "正常",
|
||
className: "三年八班",
|
||
avatar: "/static/images/avatar5.png",
|
||
},
|
||
{
|
||
id: 6,
|
||
name: "孟嘉乐",
|
||
status: "正常",
|
||
className: "三年八班",
|
||
avatar: "/static/images/avatar6.png",
|
||
},
|
||
{
|
||
id: 7,
|
||
name: "韩汝鑫",
|
||
status: "正常",
|
||
className: "三年八班",
|
||
avatar: "/static/images/avatar7.png",
|
||
},
|
||
{
|
||
id: 8,
|
||
name: "曹佳毅",
|
||
status: "正常",
|
||
className: "三年八班",
|
||
avatar: "/static/images/avatar8.png",
|
||
},
|
||
{
|
||
id: 9,
|
||
name: "郎甜",
|
||
status: "正常",
|
||
className: "三年八班",
|
||
avatar: "/static/images/avatar9.png",
|
||
},
|
||
{
|
||
id: 10,
|
||
name: "萧文懿",
|
||
status: "正常",
|
||
className: "三年八班",
|
||
avatar: "/static/images/avatar10.png",
|
||
},
|
||
]);
|
||
|
||
// 状态选择相关
|
||
const statusPickerVisible = ref(false);
|
||
const statusOptions = ref<Array<{ text: string, value: string }>>([]);
|
||
const currentStudent = ref<any>(null);
|
||
|
||
// 获取状态对应的样式类
|
||
const getStatusClass = (status: string) => {
|
||
switch (status) {
|
||
case "正常":
|
||
return "status-normal";
|
||
case "请假":
|
||
return "status-leave";
|
||
case "缺勤":
|
||
return "status-absent";
|
||
default:
|
||
return "status-normal";
|
||
}
|
||
};
|
||
|
||
// 获取学生状态选项
|
||
const fetchStatusOptions = async () => {
|
||
try {
|
||
// 假设字典表中出勤状态的pid为810984651,根据实际情况修改
|
||
const res = await findByPid({pid: 810984651});
|
||
if (res && res.result) {
|
||
statusOptions.value = res.result.map((item: any) => {
|
||
return {
|
||
text: item.dictionaryValue,
|
||
value: item.dictionaryCode
|
||
};
|
||
});
|
||
}
|
||
} catch (error) {
|
||
console.error("获取状态选项失败", error);
|
||
// 使用默认状态
|
||
statusOptions.value = [
|
||
{text: "正常", value: "1"},
|
||
{text: "请假", value: "2"},
|
||
{text: "缺勤", value: "3"}
|
||
];
|
||
}
|
||
};
|
||
|
||
// 打开状态选择器
|
||
const openStatusPicker = (student: any) => {
|
||
currentStudent.value = student;
|
||
statusPickerVisible.value = true;
|
||
};
|
||
|
||
// 确认选择状态
|
||
const confirmStatus = (e: any) => {
|
||
if (currentStudent.value && e.value && e.value[0]) {
|
||
const selectedStatus = statusOptions.value.find(
|
||
(option: any) => option.value === e.value[0]
|
||
);
|
||
|
||
if (selectedStatus) {
|
||
// 更新当前学生状态
|
||
currentStudent.value.status = selectedStatus.text;
|
||
}
|
||
}
|
||
statusPickerVisible.value = false;
|
||
};
|
||
|
||
// 导航相关方法
|
||
const navigateBack = () => {
|
||
uni.navigateBack();
|
||
};
|
||
|
||
const toRollCallRecord = () => {
|
||
uni.navigateTo({
|
||
url: "/pages/base/groupTeaching/rollCallRecord",
|
||
});
|
||
};
|
||
|
||
// 联系家长
|
||
const contactParent = (student: any) => {
|
||
console.log("联系家长", student.name);
|
||
};
|
||
|
||
// 提交数据
|
||
const submit = () => {
|
||
uni.showToast({
|
||
title: "提交成功",
|
||
icon: "success",
|
||
});
|
||
};
|
||
|
||
// 页面加载时获取状态选项
|
||
onMounted(() => {
|
||
fetchStatusOptions();
|
||
});
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.container {
|
||
min-height: 100vh;
|
||
background-color: #f5f5f5;
|
||
}
|
||
|
||
.header {
|
||
height: 44px;
|
||
background-color: #fff;
|
||
}
|
||
|
||
.course-card {
|
||
border-radius: 8px;
|
||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
|
||
}
|
||
|
||
.course-icon {
|
||
width: 30px;
|
||
height: 30px;
|
||
border-radius: 4px;
|
||
background-color: rgba(64, 128, 255, 0.1);
|
||
}
|
||
|
||
.attendance-stats {
|
||
padding: 10px 0;
|
||
}
|
||
|
||
.stat-item {
|
||
flex: 1;
|
||
}
|
||
|
||
.stat-circle {
|
||
width: 60px;
|
||
height: 60px;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.student-list {
|
||
padding: 0 15px;
|
||
}
|
||
|
||
.student-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.student-item {
|
||
position: relative;
|
||
}
|
||
|
||
.avatar-container {
|
||
width: 46px;
|
||
height: 46px;
|
||
border-radius: 50%;
|
||
padding: 3px;
|
||
background-color: #fff;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
|
||
}
|
||
|
||
.student-avatar {
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 50%;
|
||
background-color: #f5f5f5;
|
||
}
|
||
|
||
.status-tag {
|
||
font-size: 10px;
|
||
padding: 1px 5px;
|
||
border-radius: 4px;
|
||
display: flex;
|
||
align-items: center;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.status-normal {
|
||
color: #4080ff;
|
||
}
|
||
|
||
.status-leave {
|
||
color: #ff9900;
|
||
}
|
||
|
||
.status-absent {
|
||
color: #ff4d4f;
|
||
}
|
||
|
||
.text-ellipsis {
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
max-width: 60px;
|
||
}
|
||
|
||
.contact-parent {
|
||
padding: 3px 8px;
|
||
border-radius: 4px;
|
||
border: 1px solid #4080ff;
|
||
display: inline-flex;
|
||
}
|
||
|
||
.submit-btn {
|
||
background-color: #4080ff;
|
||
color: #fff;
|
||
height: 44px;
|
||
border-radius: 22px;
|
||
font-size: 16px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.cor-primary {
|
||
color: #4080ff;
|
||
}
|
||
|
||
.cor-warning {
|
||
color: #ff9900;
|
||
}
|
||
|
||
.cor-danger {
|
||
color: #ff4d4f;
|
||
}
|
||
|
||
.cor-666 {
|
||
color: #666;
|
||
}
|
||
|
||
.cor-999 {
|
||
color: #999;
|
||
}
|
||
</style>
|