调整课程巡查
This commit is contained in:
parent
f32e8f5a5f
commit
f8c27fd710
@ -104,11 +104,6 @@ export const jsdXkXsListApi = async (params: any) => {
|
||||
return await get("/mobile/js/xkxs/list", params);
|
||||
};
|
||||
|
||||
// 获取班级学生考试成绩
|
||||
export const jsdBjKscjApi = async (params: any) => {
|
||||
return await get("/mobile/js/kscj/bj", params);
|
||||
};
|
||||
|
||||
// 获取班级学生考试成绩(按科目)
|
||||
export const jsdBjKscjKmApi = async (params: any) => {
|
||||
return await get("/mobile/js/kscj/bjKm", params);
|
||||
|
||||
29
src/api/base/xkscApi.ts
Normal file
29
src/api/base/xkscApi.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { get, post } from "@/utils/request";
|
||||
|
||||
/**
|
||||
* 分页查询巡查记录
|
||||
*/
|
||||
export const xkscFindPageApi = async (params: any) => {
|
||||
return await get("/api/xksc/findPage", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 新增/修改巡查记录
|
||||
*/
|
||||
export const xkscSaveApi = async (params: any) => {
|
||||
return await post("/api/xksc/save", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 根据id查询巡查记录
|
||||
*/
|
||||
export const xkscFindByIdApi = async (params: any) => {
|
||||
return await get("/api/xksc/findById", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除巡查记录
|
||||
*/
|
||||
export const xkscLogicDeleteApi = async (params: any) => {
|
||||
return await post("/api/xksc/logicDelete", params);
|
||||
};
|
||||
@ -1,6 +1,11 @@
|
||||
import { get, post } from "@/utils/request";
|
||||
import { get } from "@/utils/request";
|
||||
|
||||
//字典接口
|
||||
//配置参数接口
|
||||
export const dmBeforeMinuteApi = async () => {
|
||||
return await get("/api/comConfig/getDmBeforeMinute");
|
||||
};
|
||||
};
|
||||
|
||||
//配置参数接口
|
||||
export const xcBeforeMinuteApi = async () => {
|
||||
return await get("/api/comConfig/getXcBeforeMinute");
|
||||
};
|
||||
|
||||
@ -228,14 +228,14 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/view/routine/kefuxuncha/KeFuXunCha",
|
||||
"path": "pages/view/routine/kefuxuncha/xcXkList",
|
||||
"style": {
|
||||
"navigationBarTitleText": "课服巡查",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/view/routine/kefuxuncha/KeFuXunChaDetail",
|
||||
"path": "pages/view/routine/kefuxuncha/xcXkkcDetail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "课服巡查详情",
|
||||
"enablePullDownRefresh": false
|
||||
|
||||
@ -94,7 +94,6 @@ import { useCommonStore } from "@/store/modules/common";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { imagUrl } from "@/utils";
|
||||
import { hideLoading, showLoading } from "@/utils/uniapp";
|
||||
import { set } from "lodash";
|
||||
import { reactive, ref } from "vue";
|
||||
const { logout, getUser, getJs, setJs } = useUserStore();
|
||||
const { getZwListByLx } = useCommonStore();
|
||||
@ -108,11 +107,10 @@ const qtZwLabel = ref<any>("");
|
||||
|
||||
// 教师工作信息
|
||||
const jsWork = ref<any>({
|
||||
jf: 88,
|
||||
ks: 40
|
||||
jf: 88,
|
||||
ks: 40,
|
||||
});
|
||||
|
||||
|
||||
interface GridItem {
|
||||
id: number | string;
|
||||
icon: string; // 图标文件名 (不含扩展名)
|
||||
@ -214,7 +212,7 @@ const sections = reactive<Section[]>([
|
||||
icon: "pass-pending-fill",
|
||||
text: "课服巡查",
|
||||
show: true,
|
||||
path: "/pages/view/routine/kefuxuncha/KeFuXunCha",
|
||||
path: "/pages/view/routine/kefuxuncha/xcXkList",
|
||||
},
|
||||
{
|
||||
id: "r7",
|
||||
@ -340,9 +338,9 @@ const handleGridItemClick = async (item: GridItem) => {
|
||||
const res = await jsdfindJsByPhoneApi({
|
||||
phone: getJs.lxdh,
|
||||
});
|
||||
if (res.result.headPic && res.result.headPic.length) {
|
||||
res.result.headPic = imagUrl(res.result.headPic);
|
||||
}
|
||||
if (res.result.headPic && res.result.headPic.length) {
|
||||
res.result.headPic = imagUrl(res.result.headPic);
|
||||
}
|
||||
setJs(res.result);
|
||||
hideLoading();
|
||||
}
|
||||
@ -365,22 +363,25 @@ onMounted(async () => {
|
||||
if (getJs.qtzw && typeof getJs.qtzw == "string") {
|
||||
qtZw = getJs.qtzw.split(",");
|
||||
}
|
||||
if (dzZw && dzZw.length){
|
||||
const res = await getZwListByLx({ zwlx: '党政职务' });
|
||||
dzZwLabel.value = dzZw.map((zwId: string) => {
|
||||
const zw = res.result.find((zw: any) => zwId == zw.id);
|
||||
return zw ? zw.zwmc : '';
|
||||
}).join(', ');
|
||||
};
|
||||
if (qtZw && qtZw.length){
|
||||
const res = await getZwListByLx({ zwlx: '其他职务' });
|
||||
qtZwLabel.value = qtZw.map((zwId: string) => {
|
||||
const zw = res.result.find((zw: any) => zwId == zw.id);
|
||||
return zw ? zw.zwmc : '';
|
||||
}).join(', ');
|
||||
};
|
||||
})
|
||||
|
||||
if (dzZw && dzZw.length) {
|
||||
const res = await getZwListByLx({ zwlx: "党政职务" });
|
||||
dzZwLabel.value = dzZw
|
||||
.map((zwId: string) => {
|
||||
const zw = res.result.find((zw: any) => zwId == zw.id);
|
||||
return zw ? zw.zwmc : "";
|
||||
})
|
||||
.join(", ");
|
||||
}
|
||||
if (qtZw && qtZw.length) {
|
||||
const res = await getZwListByLx({ zwlx: "其他职务" });
|
||||
qtZwLabel.value = qtZw
|
||||
.map((zwId: string) => {
|
||||
const zw = res.result.find((zw: any) => zwId == zw.id);
|
||||
return zw ? zw.zwmc : "";
|
||||
})
|
||||
.join(", ");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@ -1,433 +0,0 @@
|
||||
<template>
|
||||
<view class="page-container">
|
||||
<!-- 1. 顶部 Banner -->
|
||||
<!-- <view class="header-banner mx-15 mt-15 r-md" style="box-sizing: border-box">
|
||||
<view class="banner-text">
|
||||
<text class="banner-title">上课巡查</text>
|
||||
<text class="banner-subtitle">泸州市实验小学城西学校</text>
|
||||
</view>
|
||||
<view class="banner-image-placeholder"></view>
|
||||
</view> -->
|
||||
|
||||
<!-- 2. 我的应用 -->
|
||||
<!-- <view class="section my-apps mt-15 px-15">
|
||||
<view class="section-title-bar">
|
||||
<view class="decorator"></view>
|
||||
<text class="title-text">我的应用</text>
|
||||
</view>
|
||||
<uni-card :is-shadow="false" is-full margin="0">
|
||||
<view class="app-grid">
|
||||
<view class="app-item" @click="goToRecord">
|
||||
<view class="app-icon-wrapper record-icon">
|
||||
</view>
|
||||
<text class="app-text">巡查记录</text>
|
||||
</view>
|
||||
<view class="app-item" @click="goToSummary">
|
||||
<view class="app-icon-wrapper summary-icon">
|
||||
</view>
|
||||
<text class="app-text">巡查汇总</text>
|
||||
</view>
|
||||
</view>
|
||||
</uni-card>
|
||||
</view> -->
|
||||
|
||||
<!-- 3. 巡检情况 -->
|
||||
<view class="section inspection-status flex-1 flex-col mt-15">
|
||||
<view class="px-15">
|
||||
<view class="section-title-bar">
|
||||
<view class="decorator"></view>
|
||||
<text class="title-text">巡检情况</text>
|
||||
</view>
|
||||
<uni-segmented-control
|
||||
:current="currentTab"
|
||||
:values="tabs"
|
||||
style-type="text"
|
||||
active-color="#447ade"
|
||||
@clickItem="onTabClick"
|
||||
/>
|
||||
</view>
|
||||
<view class="inspection-list po-re">
|
||||
<view class="po-ab inset-0">
|
||||
<BasicListLayout :key="listKey" @register="register">
|
||||
<template v-slot="{ data: item }">
|
||||
<uni-card :key="item.id" :is-shadow="true" margin="10px 0">
|
||||
<view class="inspection-item">
|
||||
<view class="item-top-row">
|
||||
<view class="item-image-placeholder"></view>
|
||||
<view class="item-content">
|
||||
<text class="item-title">{{ item.title }}</text>
|
||||
<text class="item-detail">开课老师: {{ item.teacher }}</text>
|
||||
<text class="item-detail">上课地点: {{ item.location }}</text>
|
||||
</view>
|
||||
<view class="item-action" @click="goToDetail(item)">
|
||||
<text class="action-text">检查</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-stats">
|
||||
<view class="stat-item">
|
||||
<text class="stat-value">{{ item.expected }}</text>
|
||||
<text class="stat-label">应到</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value">{{ item.actual }}</text>
|
||||
<text class="stat-label">实到</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value leave">{{ item.leave }}</text>
|
||||
<text class="stat-label">请假</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value absent">{{ item.absent }}</text>
|
||||
<text class="stat-label">缺勤</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-card>
|
||||
</template>
|
||||
</BasicListLayout>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {ref} from "vue";
|
||||
import {useLayout} from "@/components/BasicListLayout/hooks/useLayout";
|
||||
|
||||
interface InspectionItem {
|
||||
id: number;
|
||||
title: string;
|
||||
teacher: string;
|
||||
location: string;
|
||||
expected: number;
|
||||
actual: number;
|
||||
leave: number;
|
||||
absent: number;
|
||||
imageUrl?: string; // 图片 URL,暂时留空
|
||||
}
|
||||
|
||||
const currentTab = ref(0); // 0: 待巡查, 1: 已巡查
|
||||
const tabs = ["待巡查", "已巡查"];
|
||||
const listKey = ref(0);
|
||||
|
||||
// 模拟待巡查列表数据
|
||||
const pendingMockItems: InspectionItem[] = [
|
||||
{
|
||||
id: 1,
|
||||
title: "机器人创客",
|
||||
teacher: "叶老师",
|
||||
location: "教学楼3楼",
|
||||
expected: 18,
|
||||
actual: 18,
|
||||
leave: 0,
|
||||
absent: 0,
|
||||
imageUrl: "placeholder1.png",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "篮球",
|
||||
teacher: "叶老师",
|
||||
location: "教学楼3楼",
|
||||
expected: 18,
|
||||
actual: 18,
|
||||
leave: 0,
|
||||
absent: 0,
|
||||
imageUrl: "placeholder2.png",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "足球",
|
||||
teacher: "叶老师",
|
||||
location: "教学楼3楼",
|
||||
expected: 18,
|
||||
actual: 18,
|
||||
leave: 0,
|
||||
absent: 0,
|
||||
imageUrl: "placeholder3.png",
|
||||
},
|
||||
];
|
||||
|
||||
const testList = async (param: any): Promise<Requests<any>> => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve({message: "测试", resultCode: 1, rows: pendingMockItems});
|
||||
}, 1000);
|
||||
});
|
||||
};
|
||||
|
||||
const [register, {reload, setParam}] = useLayout({
|
||||
api: testList,
|
||||
componentProps: {
|
||||
fixed: false,
|
||||
},
|
||||
});
|
||||
|
||||
const onTabClick = (e: { currentIndex: number }) => {
|
||||
if (currentTab.value !== e.currentIndex) {
|
||||
currentTab.value = e.currentIndex;
|
||||
console.log(`切换到: ${tabs[currentTab.value]}`);
|
||||
// 调用 reload 并传递新的参数,同时指定从第一页开始加载
|
||||
reload({pageNo: 1, param: {status: currentTab.value}} as any);
|
||||
// 使用 as any 暂时绕过可能的 reload 参数类型检查问题,
|
||||
// 或者根据 useLayout 的实际类型定义调整参数结构
|
||||
}
|
||||
};
|
||||
|
||||
const goToDetail = (item: InspectionItem) => {
|
||||
console.log("检查:", item.title);
|
||||
uni.navigateTo({
|
||||
url: `/pages/view/routine/kefuxuncha/KeFuXunChaDetail?id=${item.id}`,
|
||||
});
|
||||
};
|
||||
|
||||
const goToRecord = () => {
|
||||
console.log("跳转到巡查记录");
|
||||
uni.showToast({title: "功能暂未开放", icon: "none"});
|
||||
};
|
||||
|
||||
const goToSummary = () => {
|
||||
console.log("跳转到巡查汇总");
|
||||
uni.showToast({title: "功能暂未开放", icon: "none"});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.page-container {
|
||||
background-color: #f4f5f7;
|
||||
min-height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* 1. 顶部 Banner */
|
||||
.header-banner {
|
||||
background-color: #447ade; // 主题蓝
|
||||
color: #ffffff;
|
||||
padding: 20px 15px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 120px; // 根据设计稿调整
|
||||
box-sizing: border-box;
|
||||
|
||||
.banner-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.banner-title {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.banner-subtitle {
|
||||
font-size: 14px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.banner-image-placeholder {
|
||||
width: 100px; // 图片区域宽度
|
||||
height: 70px; // 图片区域高度
|
||||
background-color: rgba(255, 255, 255, 0.2); // 临时占位符颜色
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 通用 Section 样式 */
|
||||
.section {
|
||||
}
|
||||
|
||||
.section-title-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.decorator {
|
||||
width: 4px;
|
||||
height: 16px;
|
||||
background-color: #447ade;
|
||||
margin-right: 8px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.title-text {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
/* 2. 我的应用 */
|
||||
.my-apps {
|
||||
.app-grid {
|
||||
display: flex;
|
||||
justify-content: space-around; /* 均匀分布 */
|
||||
}
|
||||
|
||||
.app-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.app-icon-wrapper {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
margin-bottom: 8px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
// 实际使用 image 替换背景色
|
||||
&.record-icon {
|
||||
background-color: #447ade; // 模拟巡查记录图标背景
|
||||
}
|
||||
|
||||
&.summary-icon {
|
||||
background-color: #ff9800; // 模拟巡查汇总图标背景
|
||||
}
|
||||
}
|
||||
|
||||
.app-text {
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
/* uni-card 默认样式调整 */
|
||||
::v-deep .uni-card {
|
||||
border-radius: 8px !important;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06) !important; // 确保阴影生效
|
||||
}
|
||||
|
||||
// BasicListLayout 内部可能也需要调整 uni-card 的样式
|
||||
::v-deep .inspection-list .uni-card {
|
||||
margin: 0 0 10px 0 !important; // 列表内部 card 的 margin
|
||||
}
|
||||
|
||||
::v-deep .uni-card .uni-card__content {
|
||||
padding: 0 !important; // 去除 uni-card 内部 padding
|
||||
}
|
||||
|
||||
::v-deep .my-apps .uni-card .uni-card__content {
|
||||
padding: 15px 0 !important; // 我的应用卡片内边距
|
||||
}
|
||||
|
||||
// BasicListLayout 中的 uni-card content padding
|
||||
::v-deep .inspection-list .uni-card .uni-card__content {
|
||||
padding: 15px !important; // 巡查列表卡片内边距
|
||||
}
|
||||
|
||||
/* 3. 巡检情况 */
|
||||
.inspection-status {
|
||||
::v-deep .uni-segmented-control__text {
|
||||
font-size: 15px !important;
|
||||
}
|
||||
|
||||
::v-deep .segmented-control {
|
||||
margin-bottom: 10px; // tab 和列表间距
|
||||
background-color: #ffffff; // 背景设为白色
|
||||
border-radius: 8px; // 轻微圆角
|
||||
}
|
||||
}
|
||||
|
||||
.inspection-list {
|
||||
flex: 1;
|
||||
// 列表样式
|
||||
}
|
||||
|
||||
.inspection-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.item-top-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.item-image-placeholder {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background-color: #eee; // 图片占位符颜色
|
||||
border-radius: 8px;
|
||||
margin-right: 15px;
|
||||
flex-shrink: 0; // 防止被压缩
|
||||
}
|
||||
|
||||
.item-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.item-detail {
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.item-stats {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
width: 100%;
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
|
||||
&.leave {
|
||||
color: #ff9800; // 请假颜色
|
||||
}
|
||||
|
||||
&.absent {
|
||||
color: #f44336; // 缺勤颜色
|
||||
}
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.item-action {
|
||||
margin-left: auto;
|
||||
padding-left: 10px;
|
||||
align-self: flex-start;
|
||||
padding-top: 5px;
|
||||
.action-text {
|
||||
font-size: 14px;
|
||||
color: #f44336; // 检查按钮颜色
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
color: #999;
|
||||
padding: 30px 0;
|
||||
}
|
||||
</style>
|
||||
@ -1,404 +0,0 @@
|
||||
<template>
|
||||
<view class="detail-page-container">
|
||||
<scroll-view scroll-y class="main-content">
|
||||
<!-- 1. 顶部课程信息 (复用列表样式) -->
|
||||
<uni-card v-if="detailData" :is-shadow="true" margin="15px">
|
||||
<view class="inspection-item">
|
||||
<view class="item-top-row">
|
||||
<view class="item-image-placeholder"></view> <!-- 图片占位 -->
|
||||
<view class="item-content">
|
||||
<text class="item-title">{{ detailData.title }}</text>
|
||||
<text class="item-detail">开课老师: {{ detailData.teacher }}</text>
|
||||
<text class="item-detail">上课地点: {{ detailData.location }}</text>
|
||||
</view>
|
||||
<!-- 详情页不再需要检查按钮 -->
|
||||
<!-- <view class="item-action">
|
||||
<text class="action-text">检查</text>
|
||||
</view> -->
|
||||
</view>
|
||||
<view class="item-stats">
|
||||
<view class="stat-item">
|
||||
<text class="stat-value">{{ detailData.expected }}</text>
|
||||
<text class="stat-label">应到</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value">{{ detailData.actual }}</text>
|
||||
<text class="stat-label">实到</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value leave">{{ detailData.leave }}</text>
|
||||
<text class="stat-label">请假</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value absent">{{ detailData.absent }}</text>
|
||||
<text class="stat-label">缺勤</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-card>
|
||||
|
||||
<!-- 2. 教学计划 -->
|
||||
<view class="section teaching-plan" v-if="detailData?.teachingPlan">
|
||||
<view class="section-title-bar">
|
||||
<view class="decorator"></view>
|
||||
<text class="title-text">教学计划</text>
|
||||
</view>
|
||||
<uni-card :is-shadow="true" margin="0 15px">
|
||||
<view class="plan-content">
|
||||
<text v-for="(plan, index) in detailData.teachingPlan" :key="index" class="plan-text">{{ plan }}</text>
|
||||
</view>
|
||||
</uni-card>
|
||||
</view>
|
||||
|
||||
<!-- 3. 巡查项目 -->
|
||||
<view class="section inspection-check-items">
|
||||
<view class="section-title-bar">
|
||||
<view class="decorator"></view>
|
||||
<text class="title-text">巡查项目</text>
|
||||
</view>
|
||||
<uni-card :is-shadow="true" margin="0 15px">
|
||||
<checkbox-group class="check-list">
|
||||
<label v-for="item in checkItems" :key="item.id" class="check-item">
|
||||
<view class="item-info">
|
||||
<text class="item-text">{{ item.id }}、{{ item.text }}</text>
|
||||
<text class="item-deduction">扣{{ item.deduction }}分</text>
|
||||
</view>
|
||||
<checkbox :value="String(item.id)" :checked="item.checked" @click="item.checked = !item.checked" color="#447ade" style="transform:scale(0.8)"/>
|
||||
</label>
|
||||
</checkbox-group>
|
||||
</uni-card>
|
||||
</view>
|
||||
|
||||
<!-- 4. 拍照上传 -->
|
||||
<view class="section photo-upload">
|
||||
<view class="section-title-bar">
|
||||
<view class="decorator"></view>
|
||||
<text class="title-text">拍照上传</text>
|
||||
</view>
|
||||
<uni-card :is-shadow="true" margin="0 15px">
|
||||
<view class="upload-area">
|
||||
<!-- 这里放置 uni-file-picker 或其他上传组件 -->
|
||||
<uni-file-picker
|
||||
v-model="uploadedFiles"
|
||||
fileMediatype="image"
|
||||
mode="grid"
|
||||
:limit="3"
|
||||
@success="handleUploadSuccess"
|
||||
/>
|
||||
</view>
|
||||
</uni-card>
|
||||
</view>
|
||||
|
||||
</scroll-view>
|
||||
|
||||
<!-- 底部提交按钮 -->
|
||||
<view class="footer-submit">
|
||||
<button class="submit-button" @click="handleSubmit">提交</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import { ref } from 'vue';
|
||||
|
||||
interface InspectionDetail {
|
||||
id: number;
|
||||
title: string;
|
||||
teacher: string;
|
||||
location: string;
|
||||
expected: number;
|
||||
actual: number;
|
||||
leave: number;
|
||||
absent: number;
|
||||
imageUrl?: string; // 图片 URL,暂时留空
|
||||
teachingPlan: string[];
|
||||
}
|
||||
|
||||
interface InspectionCheckItem {
|
||||
id: number;
|
||||
text: string;
|
||||
deduction: number; // 扣分
|
||||
checked: boolean;
|
||||
}
|
||||
|
||||
const inspectionId = ref<string | null>(null);
|
||||
const detailData = ref<InspectionDetail | null>(null); // 存储详情数据
|
||||
const checkItems = ref<InspectionCheckItem[]>([ // 巡查项目数据
|
||||
{ id: 1, text: '未按时上课', deduction: 1, checked: false },
|
||||
{ id: 2, text: '上课迟到', deduction: 2, checked: false },
|
||||
{ id: 3, text: '上课内容与教学计划不一致', deduction: 1, checked: false },
|
||||
]);
|
||||
const uploadedFiles = ref([]); // 存储上传的文件
|
||||
|
||||
// 模拟获取详情数据
|
||||
const fetchDetailData = (id: string) => {
|
||||
console.log('模拟请求详情数据,ID:', id);
|
||||
// 这里应该是 API 请求,现在使用模拟数据
|
||||
detailData.value = {
|
||||
id: parseInt(id),
|
||||
title: '机器人创客',
|
||||
teacher: '叶老师',
|
||||
location: '教学楼3楼',
|
||||
expected: 18,
|
||||
actual: 18,
|
||||
leave: 0,
|
||||
absent: 0,
|
||||
teachingPlan: [
|
||||
'第一阶段:了解机器人的组成,知道每个零件的名称及用途,认识机器人的结构。',
|
||||
'第二阶段:在老师的引导下,分组搭建机器人,注意引导幼儿理解机器人的数据线连接和遥控器方向的关系。',
|
||||
'第三阶段:学会操控机器人的移动方向,并练习把魔方根据要求推到指定位置。',
|
||||
'第四阶段:组织幼儿参加创客机器人比赛。',
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
onLoad((options) => {
|
||||
if (options?.id) {
|
||||
inspectionId.value = options.id;
|
||||
console.log('接收到的巡查 ID:', inspectionId.value);
|
||||
// 确保 inspectionId.value 不是 null 再调用
|
||||
if (inspectionId.value) {
|
||||
fetchDetailData(inspectionId.value);
|
||||
}
|
||||
} else {
|
||||
console.error('未接收到巡查 ID');
|
||||
// 可以添加错误处理,例如返回上一页或显示提示
|
||||
uni.showToast({ title: '加载失败,缺少参数', icon: 'error' });
|
||||
// 考虑是否需要返回上一页
|
||||
// setTimeout(() => uni.navigateBack(), 1500);
|
||||
}
|
||||
});
|
||||
|
||||
// 处理文件上传(需要根据使用的上传组件调整)
|
||||
const handleUploadSuccess = (res: any) => {
|
||||
console.log('上传成功:', res);
|
||||
// uploadedFiles 会通过 v-model 自动更新
|
||||
};
|
||||
|
||||
const handleSubmit = () => {
|
||||
console.log('提交巡查记录');
|
||||
const selectedCheckItems = checkItems.value.filter(item => item.checked);
|
||||
console.log('选中的巡查项目:', selectedCheckItems);
|
||||
console.log('上传的文件:', uploadedFiles.value);
|
||||
// 在这里执行提交逻辑,例如调用 API
|
||||
uni.showLoading({ title: '提交中...' });
|
||||
setTimeout(() => { // 模拟提交
|
||||
uni.hideLoading();
|
||||
uni.showToast({ title: '提交成功', icon: 'success' });
|
||||
// 提交成功后可能需要返回列表页
|
||||
// uni.navigateBack();
|
||||
}, 1000);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.detail-page-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background-color: #f4f5f7;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 80px; /* 为底部按钮留出空间 */
|
||||
}
|
||||
|
||||
/* 复用列表页样式并微调 */
|
||||
.inspection-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.item-top-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.item-image-placeholder {
|
||||
width: 60px; /* 详情页图片稍小 */
|
||||
height: 60px;
|
||||
background-color: #eee;
|
||||
border-radius: 8px;
|
||||
margin-right: 15px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.item-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.item-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.item-detail {
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.item-stats {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
width: 100%;
|
||||
padding: 5px 0;
|
||||
}
|
||||
.stat-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.stat-value {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
&.leave {
|
||||
color: #ff9800;
|
||||
}
|
||||
&.absent {
|
||||
color: #f44336;
|
||||
}
|
||||
}
|
||||
.stat-label {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
/* Section 标题栏 */
|
||||
.section {
|
||||
margin-top: 15px;
|
||||
}
|
||||
.section-title-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
padding: 0 15px; /* 标题栏左右加内边距 */
|
||||
|
||||
.decorator {
|
||||
width: 4px;
|
||||
height: 16px;
|
||||
background-color: #447ade;
|
||||
margin-right: 8px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.title-text {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
/* uni-card 样式调整 */
|
||||
::v-deep .uni-card {
|
||||
border-radius: 8px !important;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06) !important;
|
||||
}
|
||||
|
||||
::v-deep .uni-card .uni-card__content {
|
||||
padding: 15px !important; // 卡片默认内边距
|
||||
}
|
||||
|
||||
/* 教学计划 */
|
||||
.teaching-plan {
|
||||
.plan-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.plan-text {
|
||||
font-size: 14px;
|
||||
color: #555;
|
||||
line-height: 1.8;
|
||||
margin-bottom: 8px;
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 巡查项目 */
|
||||
.inspection-check-items {
|
||||
.check-list {
|
||||
// display: flex; // 如果需要更复杂的布局
|
||||
// flex-direction: column;
|
||||
}
|
||||
.check-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 0; // 增加垂直间距
|
||||
border-bottom: 1px solid #eee;
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
.item-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.item-text {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.item-deduction {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
/* 拍照上传 */
|
||||
.photo-upload {
|
||||
.upload-area {
|
||||
// 添加上传区域的样式
|
||||
// padding: 10px;
|
||||
}
|
||||
::v-deep .uni-file-picker__container {
|
||||
justify-content: flex-start; // 让图片靠左
|
||||
}
|
||||
::v-deep .file-picker__box {
|
||||
margin: 0 10px 10px 0; // 调整图片间距
|
||||
}
|
||||
// .upload-placeholder {
|
||||
// width: 80px;
|
||||
// height: 80px;
|
||||
// background-color: #f8f8f8;
|
||||
// border: 1px dashed #ddd;
|
||||
// border-radius: 8px;
|
||||
// display: flex;
|
||||
// justify-content: center;
|
||||
// align-items: center;
|
||||
// }
|
||||
}
|
||||
|
||||
/* 底部提交按钮 */
|
||||
.footer-submit {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #ffffff;
|
||||
padding: 10px 15px;
|
||||
padding-bottom: calc(10px + constant(safe-area-inset-bottom)); /* 适配 iPhone X 等底部安全区域 */
|
||||
padding-bottom: calc(10px + env(safe-area-inset-bottom));
|
||||
box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.05);
|
||||
z-index: 10;
|
||||
|
||||
.submit-button {
|
||||
background-color: #447ade;
|
||||
color: #ffffff;
|
||||
border-radius: 20px;
|
||||
font-size: 16px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
&:active {
|
||||
background-color: #3963bb;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
447
src/pages/view/routine/kefuxuncha/xcXkList.vue
Normal file
447
src/pages/view/routine/kefuxuncha/xcXkList.vue
Normal file
@ -0,0 +1,447 @@
|
||||
<template>
|
||||
<view class="interest-course">
|
||||
<!-- 选课信息头部 - 固定部分 -->
|
||||
<view class="selection-header">
|
||||
<view class="header-content">
|
||||
<view class="title-section" @click="clickShowXkSelector">
|
||||
<view class="title">
|
||||
<text v-if="xkData && xkData.xkmc">{{ xkData.xkmc }}</text>
|
||||
<text v-else>巡查选课</text>
|
||||
</view>
|
||||
<view class="switch-btn" v-if="xkList.length > 1">切换</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 可滚动的内容区域 -->
|
||||
<view class="scrollable-content">
|
||||
<!-- 课程网格列表 -->
|
||||
<view class="course-list" v-if="xkkcList && xkkcList.length > 0">
|
||||
<view
|
||||
v-for="(xkkc, index) in xkkcList"
|
||||
:key="xkkc.id || index"
|
||||
class="course-item"
|
||||
>
|
||||
<view class="course-name">{{ xkkc.kcmc }}</view>
|
||||
<view class="course-info-item">
|
||||
<view class="info-label">上课周期类型:</view>
|
||||
<view class="info-data">{{ xkkc.skzqlx }}</view>
|
||||
</view>
|
||||
<view class="course-info-item">
|
||||
<view class="info-label">上课周期:</view>
|
||||
<view class="info-data">{{ xkkc.skzqmc }}</view>
|
||||
</view>
|
||||
<view class="course-info-item">
|
||||
<view class="info-label">上课开始时间:</view>
|
||||
<view class="info-data">{{ xkkc.skkstime }}</view>
|
||||
</view>
|
||||
<view class="course-info-item">
|
||||
<view class="info-label">上课结束时间:</view>
|
||||
<view class="info-data">{{ xkkc.skjstime }}</view>
|
||||
</view>
|
||||
<view class="course-info-item">
|
||||
<view class="info-label">开课地点:</view>
|
||||
<view class="info-data">{{ xkkc.kcdd }}</view>
|
||||
</view>
|
||||
<view class="course-info-item">
|
||||
<view class="info-label">上课人数:</view>
|
||||
<view class="info-data"
|
||||
>{{ xkkc.hasNum || 0 }} | {{ xkkc.maxNum || 0 }}</view
|
||||
>
|
||||
</view>
|
||||
<view class="course-btn-group">
|
||||
<view class="xc-btn" @click.stop="goXc(xkkc)">巡查</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 暂无数据提示 -->
|
||||
<view v-else class="empty-course-list">
|
||||
<view class="empty-icon">
|
||||
<u-icon name="list" size="50" color="#C8C9CC"></u-icon>
|
||||
</view>
|
||||
<view class="empty-text">暂无课程数据</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view>
|
||||
<!-- 选课选择弹窗 -->
|
||||
<u-popup
|
||||
:show="showXkFlag"
|
||||
@close="showXkFlag = false"
|
||||
mode="bottom"
|
||||
round="10"
|
||||
>
|
||||
<view class="xk-selector">
|
||||
<view class="selector-header">
|
||||
<text class="selector-title">选择俱乐部</text>
|
||||
<u-icon name="close" size="20" @click="showXkFlag = false"></u-icon>
|
||||
</view>
|
||||
<view class="xk-list">
|
||||
<view
|
||||
v-for="(xk, index) in xkList"
|
||||
:key="index"
|
||||
class="xk-item"
|
||||
:class="{
|
||||
'xk-item-active': xkData.id === xk.id,
|
||||
}"
|
||||
@click="switchXk(xk)"
|
||||
>
|
||||
<view class="xk-info">
|
||||
<text class="xk-name">{{ xk.xkmc }}</text>
|
||||
<text class="xk-type">{{ xk.xkmc }}</text>
|
||||
</view>
|
||||
<u-icon
|
||||
v-if="xkData.id === xk.id"
|
||||
name="checkmark"
|
||||
color="#409EFF"
|
||||
size="20"
|
||||
></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { jsdXkListApi } from "@/api/base/server";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { onBeforeUnmount, onMounted, ref } from "vue";
|
||||
|
||||
const { getJs } = useUserStore();
|
||||
const { getData, setData } = useDataStore();
|
||||
|
||||
const wdNameList = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"];
|
||||
|
||||
// 控制选择器显示状态
|
||||
const showXkFlag = ref(false);
|
||||
|
||||
const xkList = ref<any>([]);
|
||||
const xkData = ref();
|
||||
|
||||
// 课程列表数据
|
||||
const xkkcList = ref<any[]>([]);
|
||||
|
||||
const xcBeforeMinute = ref<number>(0);
|
||||
|
||||
onMounted(async () => {
|
||||
uni.showLoading({
|
||||
title: "加载中...",
|
||||
});
|
||||
await loadCourseList();
|
||||
uni.hideLoading();
|
||||
});
|
||||
|
||||
// 加载课程列表
|
||||
const loadCourseList = async () => {
|
||||
const res = await jsdXkListApi({
|
||||
jsId: getJs.id,
|
||||
});
|
||||
if (res.resultCode == 1) {
|
||||
if (res.result && res.result.length) {
|
||||
xkList.value = res.result;
|
||||
switchXk(res.result[0]);
|
||||
} else {
|
||||
xkList.value = [];
|
||||
xkData.value = {};
|
||||
xkkcList.value = [];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 显示选课选择器
|
||||
function clickShowXkSelector() {
|
||||
if (xkList.value.length > 1) {
|
||||
showXkFlag.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 切换选课
|
||||
function switchXk(xk: any) {
|
||||
xkData.value = xk;
|
||||
xkkcList.value = xk.xkkcs;
|
||||
showXkFlag.value = false;
|
||||
for (let i = 0; i < xk.xkkcs.length; i++) {
|
||||
let xkkc = xk.xkkcs[i];
|
||||
// 判断周期
|
||||
switch (xkkc.skzqlx) {
|
||||
case "每天":
|
||||
xkkc.skzqmc = "每天";
|
||||
break;
|
||||
case "每周":
|
||||
const daysOfWeek = xkkc.skzq.split(",").map(Number);
|
||||
xkkc.skzqmc = daysOfWeek
|
||||
.map((day: number) => wdNameList[day - 1])
|
||||
.join(",");
|
||||
break;
|
||||
case "每月":
|
||||
const daysOfMonth = xkkc.skzq.split(",").map(Number);
|
||||
xkkc.skzqmc = daysOfMonth.map((day: number) => day + "号").join(",");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 显示切换成功提示
|
||||
uni.showToast({
|
||||
title: `已切换到${xk.xkmc}`,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
|
||||
// 跳转到巡查
|
||||
const goXc = (xkkc: any) => {
|
||||
setData(xkkc);
|
||||
uni.navigateTo({
|
||||
url: `/pages/view/routine/kefuxuncha/xcXkkcDetail`,
|
||||
});
|
||||
};
|
||||
|
||||
// 页面卸载前清除定时器
|
||||
onBeforeUnmount(() => {});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.interest-course {
|
||||
min-height: 100%;
|
||||
background-color: #f5f7fa;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.selection-header {
|
||||
background: linear-gradient(135deg, #4a90e2, #2879ff);
|
||||
padding: 20px 15px;
|
||||
color: #fff;
|
||||
border-radius: 0 0 15px 15px;
|
||||
box-shadow: 0 4px 12px rgba(40, 121, 255, 0.2);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
|
||||
.title-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.title {
|
||||
flex: 1 0 1px;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 14px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.switch-btn {
|
||||
padding: 5px 15px;
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
color: #fff;
|
||||
border-radius: 15px;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 可滚动内容区域样式
|
||||
.scrollable-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.inspection-tabs {
|
||||
padding: 15px 15px 0 15px;
|
||||
background-color: #fff;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.course-list {
|
||||
padding: 15px 15px 0 15px;
|
||||
|
||||
.course-item {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
margin-bottom: 15px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid transparent;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&.selected {
|
||||
border: 1px solid #3fbf72;
|
||||
background-color: rgba(63, 191, 114, 0.05);
|
||||
box-shadow: 0 2px 8px rgba(63, 191, 114, 0.15);
|
||||
}
|
||||
|
||||
.course-name {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.course-btn-group {
|
||||
display: flex;
|
||||
|
||||
.xc-btn {
|
||||
flex: 1 0 1px;
|
||||
display: inline-block;
|
||||
color: #2879ff;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.course-info-item {
|
||||
display: flex;
|
||||
margin-bottom: 12px;
|
||||
font-size: 12px;
|
||||
|
||||
.info-label {
|
||||
color: #949aa4;
|
||||
flex: 0 0 100px;
|
||||
}
|
||||
|
||||
.info-data {
|
||||
flex: 1 0 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 学生选择器弹窗样式 */
|
||||
.xk-selector {
|
||||
background-color: #ffffff;
|
||||
border-top-left-radius: 12px;
|
||||
border-top-right-radius: 12px;
|
||||
padding-bottom: 20px;
|
||||
|
||||
.selector-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
|
||||
.selector-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
|
||||
.xk-list {
|
||||
padding: 0 15px;
|
||||
|
||||
.xk-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 15px 0;
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&-active {
|
||||
background-color: rgba(64, 158, 255, 0.05);
|
||||
}
|
||||
|
||||
.xk-info {
|
||||
flex: 1;
|
||||
margin-left: 12px;
|
||||
|
||||
.xk-name {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.xk-type {
|
||||
font-size: 13px;
|
||||
color: #303133;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.xk-class {
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 全局图片样式 */
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.h-full {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
// 暂无数据样式
|
||||
.empty-course-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 60px 20px;
|
||||
text-align: center;
|
||||
|
||||
.empty-icon {
|
||||
margin-bottom: 20px;
|
||||
background-color: #f5f6f7;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.empty-desc {
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
max-width: 80%;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
/* 选课已结束样式 */
|
||||
.enrollment-ended {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 8px;
|
||||
padding: 12px 15px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
gap: 8px;
|
||||
}
|
||||
</style>
|
||||
857
src/pages/view/routine/kefuxuncha/xcXkkcDetail.vue
Normal file
857
src/pages/view/routine/kefuxuncha/xcXkkcDetail.vue
Normal file
@ -0,0 +1,857 @@
|
||||
<template>
|
||||
<BasicLayout>
|
||||
<!-- 巡查状态切换 -->
|
||||
<view class="inspection-tabs">
|
||||
<uni-segmented-control
|
||||
:current="currentTab"
|
||||
:values="tabs"
|
||||
style-type="text"
|
||||
active-color="#2879ff"
|
||||
@clickItem="onTabClick"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 待巡查内容 -->
|
||||
<view v-if="currentTab === 0" class="pending-inspection">
|
||||
<!-- 课程信息卡片 -->
|
||||
<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">{{ xkkc.kcmc }}</text>
|
||||
<text class="font-14 cor-999 ml-10"
|
||||
>{{ todayInfo.date }} ({{ todayInfo.weekName }})</text
|
||||
>
|
||||
</view>
|
||||
|
||||
<!-- 上课时间信息 -->
|
||||
<view class="course-time-info">
|
||||
<view class="time-item">
|
||||
<text class="time-label">上课周期类型:</text>
|
||||
<text class="time-value">{{ xkkc.skzqlx }}</text>
|
||||
</view>
|
||||
<view class="time-item">
|
||||
<text class="time-label">上课周期:</text>
|
||||
<text class="time-value">{{ xkkc.skzqmc }}</text>
|
||||
</view>
|
||||
<view class="time-item">
|
||||
<text class="time-label">上课时间:</text>
|
||||
<text class="time-value"
|
||||
>{{ xkkc.skkstime }} - {{ xkkc.skjstime }}</text
|
||||
>
|
||||
</view>
|
||||
<view class="time-item">
|
||||
<text class="time-label">上课地点:</text>
|
||||
<text class="time-value">{{ xkkc.kcdd }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 巡查时间状态 -->
|
||||
<view class="inspection-status" v-if="!canInspect">
|
||||
<u-icon name="clock" color="#ff9900" size="16"></u-icon>
|
||||
<text class="status-text">{{ inspectionStatusText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="canInspect">
|
||||
<!-- 巡查项目 -->
|
||||
<view class="section mx-15 mb-15">
|
||||
<view class="section-title-bar">
|
||||
<view class="decorator"></view>
|
||||
<text class="title-text">巡查项目</text>
|
||||
</view>
|
||||
<view class="check-card bg-white r-md p-15">
|
||||
<checkbox-group class="check-list">
|
||||
<label
|
||||
v-for="item in checkItems"
|
||||
:key="item.id"
|
||||
class="check-item"
|
||||
>
|
||||
<view class="item-info">
|
||||
<text class="item-text">{{ item.id }}、{{ item.text }}</text>
|
||||
<text class="item-deduction">扣{{ item.deduction }}分</text>
|
||||
</view>
|
||||
<checkbox
|
||||
:value="String(item.id)"
|
||||
:checked="item.checked"
|
||||
@click="item.checked = !item.checked"
|
||||
color="#4080ff"
|
||||
style="transform: scale(0.8)"
|
||||
/>
|
||||
</label>
|
||||
</checkbox-group>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 拍照上传 -->
|
||||
<view class="section mx-15 mb-15">
|
||||
<view class="section-title-bar">
|
||||
<view class="decorator"></view>
|
||||
<text class="title-text">拍照上传</text>
|
||||
</view>
|
||||
<view class="upload-card bg-white r-md p-15">
|
||||
<view class="upload-area">
|
||||
<uni-file-picker
|
||||
v-model="uploadedImages"
|
||||
fileMediatype="image"
|
||||
mode="grid"
|
||||
:limit="5"
|
||||
@success="handleImageUploadSuccess"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 拍视频上传 -->
|
||||
<view class="section mx-15 mb-30">
|
||||
<view class="section-title-bar">
|
||||
<view class="decorator"></view>
|
||||
<text class="title-text">拍视频上传</text>
|
||||
</view>
|
||||
<view class="upload-card bg-white r-md p-15">
|
||||
<view class="upload-area">
|
||||
<uni-file-picker
|
||||
v-model="uploadedVideos"
|
||||
fileMediatype="video"
|
||||
mode="grid"
|
||||
:limit="3"
|
||||
@success="handleVideoUploadSuccess"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 已巡查内容 -->
|
||||
<view v-else class="completed-inspection">
|
||||
<!-- 巡查记录列表 -->
|
||||
<view class="inspection-list">
|
||||
<view
|
||||
v-for="(record, index) in inspectionRecords"
|
||||
:key="record.id || index"
|
||||
class="inspection-record bg-white r-md p-15 mb-15 mx-15"
|
||||
>
|
||||
<view class="record-header">
|
||||
<view class="record-time">
|
||||
<u-icon name="clock" color="#666" size="14"></u-icon>
|
||||
<text class="time-text">{{ formatTime(record.xctime) }}</text>
|
||||
</view>
|
||||
<view class="record-status">
|
||||
<text class="status-text">已巡查</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="record-content">
|
||||
<view class="content-item">
|
||||
<text class="item-label">巡查教师:</text>
|
||||
<text class="item-value">{{ record.jsxm }}</text>
|
||||
</view>
|
||||
<view
|
||||
class="content-item"
|
||||
v-if="record.xcItems && record.xcItems.length > 0"
|
||||
>
|
||||
<text class="item-label">巡查项目:</text>
|
||||
<text class="item-value">{{ record.xcItems.join(", ") }}</text>
|
||||
</view>
|
||||
<view
|
||||
class="content-item"
|
||||
v-if="record.images && record.images.length > 0"
|
||||
>
|
||||
<text class="item-label">巡查图片:</text>
|
||||
<text class="item-value">{{ record.images.length }}张</text>
|
||||
</view>
|
||||
<view
|
||||
class="content-item"
|
||||
v-if="record.videos && record.videos.length > 0"
|
||||
>
|
||||
<text class="item-label">巡查视频:</text>
|
||||
<text class="item-value">{{ record.videos.length }}个</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 暂无记录提示 -->
|
||||
<view v-if="inspectionRecords.length === 0" class="empty-records">
|
||||
<view class="empty-icon">
|
||||
<u-icon name="list" size="50" color="#C8C9CC"></u-icon>
|
||||
</view>
|
||||
<view class="empty-text">暂无巡查记录</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 状态选择弹窗 -->
|
||||
<u-picker
|
||||
:defaultIndex="defSel"
|
||||
:show="statusPickerVisible"
|
||||
:columns="[statusOptions]"
|
||||
@confirm="confirmStatus"
|
||||
@cancel="statusPickerVisible = false"
|
||||
></u-picker>
|
||||
|
||||
<template #bottom>
|
||||
<view
|
||||
v-if="currentTab === 0 && canInspect"
|
||||
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 { jsdXkXsListApi } from "@/api/base/server";
|
||||
import { xkscFindPageApi, xkscSaveApi } from "@/api/base/xkscApi";
|
||||
import { xcBeforeMinuteApi } from "@/api/system/config/index";
|
||||
import BasicLayout from "@/components/BasicLayout/Layout.vue";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
import { useDicStore } from "@/store/modules/dic";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
const { findByPid } = useDicStore();
|
||||
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const { getJs } = useUserStore();
|
||||
const { getData } = useDataStore();
|
||||
|
||||
const js = computed(() => getJs);
|
||||
const xkkc = computed(() => getData);
|
||||
|
||||
const now = dayjs();
|
||||
let wDay = now.day();
|
||||
if (wDay === 0) {
|
||||
wDay = 7;
|
||||
}
|
||||
const wdNameList = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"];
|
||||
const todayInfo = ref({
|
||||
date: now.format("YYYY-MM-DD"),
|
||||
weekName: wdNameList[wDay - 1],
|
||||
});
|
||||
|
||||
// 人数信息
|
||||
const numInfo = ref({
|
||||
yd: 18,
|
||||
sd: 18,
|
||||
qj: 0,
|
||||
qq: 0,
|
||||
zg: 18,
|
||||
});
|
||||
|
||||
// 学生列表
|
||||
const xsList = ref<any>([]);
|
||||
|
||||
// 状态选择相关
|
||||
const statusPickerVisible = ref(false);
|
||||
const statusOptions = ref<Array<{ text: string; value: string }>>([]);
|
||||
const curXs = ref<any>(null);
|
||||
const defSel = ref<any>([]);
|
||||
|
||||
// 巡查项目
|
||||
const checkItems = ref<any[]>([
|
||||
{ id: 1, text: "未按时上课", deduction: 1, checked: false },
|
||||
{ id: 2, text: "上课迟到", deduction: 2, checked: false },
|
||||
{ id: 3, text: "上课内容与教学计划不一致", deduction: 1, checked: false },
|
||||
{ id: 4, text: "课堂纪律差", deduction: 2, checked: false },
|
||||
{ id: 5, text: "教学设备使用不当", deduction: 1, checked: false },
|
||||
]);
|
||||
|
||||
// 上传文件
|
||||
const uploadedImages = ref([]);
|
||||
const uploadedVideos = ref([]);
|
||||
|
||||
// 巡查状态相关
|
||||
const currentTab = ref(0); // 0: 待巡查, 1: 已巡查
|
||||
const tabs = ref(["待巡查", "已巡查"]);
|
||||
const inspectionStatusText = ref("");
|
||||
const canInspect = ref(true); // 是否可以巡查
|
||||
const xcBeforeMinute = ref<number>(0);
|
||||
|
||||
// 巡查记录
|
||||
const inspectionRecords = ref<any[]>([]);
|
||||
|
||||
// 获取状态对应的样式类
|
||||
const getStatusClass = (status: string) => {
|
||||
switch (status) {
|
||||
case "正常":
|
||||
return "status-normal";
|
||||
case "请假":
|
||||
return "status-leave";
|
||||
case "缺勤":
|
||||
return "status-absent";
|
||||
default:
|
||||
return "status-normal";
|
||||
}
|
||||
};
|
||||
|
||||
// 获取学生状态选项
|
||||
const loadStatusOptions = async () => {
|
||||
try {
|
||||
// 假设字典表中考勤状态的pid为763939514,根据实际情况修改
|
||||
const res = await findByPid({ pid: 763939514 });
|
||||
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: "正常" },
|
||||
{ text: "请假", value: "请假" },
|
||||
{ text: "缺勤", value: "缺勤" },
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
const loadXsList = async () => {
|
||||
const res = await jsdXkXsListApi({
|
||||
xkkcId: xkkc.value.id,
|
||||
});
|
||||
if (res && res.resultCode === 1) {
|
||||
xsList.value = res.result || [];
|
||||
rebuildNumInfo();
|
||||
}
|
||||
};
|
||||
|
||||
const rebuildNumInfo = () => {
|
||||
let sd = 0;
|
||||
let qj = 0;
|
||||
let qq = 0;
|
||||
// 循环统计状态对应的人数
|
||||
for (let i = 0; i < xsList.value.length; i++) {
|
||||
const xs = xsList.value[i];
|
||||
switch (xs.xszt) {
|
||||
case "正常":
|
||||
sd++;
|
||||
break;
|
||||
case "请假":
|
||||
qj++;
|
||||
break;
|
||||
case "缺勤":
|
||||
qq++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
numInfo.value = {
|
||||
zg: xsList.value.length,
|
||||
yd: xsList.value.length - qj,
|
||||
sd: sd,
|
||||
qj: qj,
|
||||
qq: qq,
|
||||
};
|
||||
};
|
||||
|
||||
// 打开状态选择器
|
||||
const openStatusPicker = (xs: any) => {
|
||||
curXs.value = xs;
|
||||
for (let i = 0; i < statusOptions.value.length; i++) {
|
||||
if (statusOptions.value[i].text === xs.xszt) {
|
||||
defSel.value = [i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
statusPickerVisible.value = true;
|
||||
};
|
||||
|
||||
// 确认选择状态
|
||||
const confirmStatus = (e: any) => {
|
||||
if (curXs.value && e.value && e.value[0]) {
|
||||
const selectedStatus = statusOptions.value.find(
|
||||
(option: any) => option.value === e.value[0].value
|
||||
);
|
||||
|
||||
if (selectedStatus) {
|
||||
// 更新当前学生状态
|
||||
curXs.value.xszt = selectedStatus.text;
|
||||
}
|
||||
rebuildNumInfo();
|
||||
}
|
||||
statusPickerVisible.value = false;
|
||||
};
|
||||
|
||||
// 处理图片上传
|
||||
const handleImageUploadSuccess = (res: any) => {
|
||||
console.log("图片上传成功:", res);
|
||||
};
|
||||
|
||||
// 处理视频上传
|
||||
const handleVideoUploadSuccess = (res: any) => {
|
||||
console.log("视频上传成功:", res);
|
||||
};
|
||||
|
||||
// 切换tab
|
||||
const onTabClick = (e: any) => {
|
||||
currentTab.value = e.currentIndex;
|
||||
if (currentTab.value === 1) {
|
||||
loadInspectionRecords();
|
||||
}
|
||||
};
|
||||
|
||||
// 加载巡查记录
|
||||
const loadInspectionRecords = async () => {
|
||||
try {
|
||||
const res = await xkscFindPageApi({
|
||||
xkkcId: xkkc.value.id,
|
||||
jsId: js.value.id,
|
||||
pageSize: 20,
|
||||
pageNum: 1,
|
||||
});
|
||||
if (res && res.resultCode === 1) {
|
||||
inspectionRecords.value = res.result?.rows || [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载巡查记录失败:", error);
|
||||
inspectionRecords.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 格式化时间
|
||||
const formatTime = (timestamp: string) => {
|
||||
return dayjs(timestamp).format("YYYY-MM-DD HH:mm");
|
||||
};
|
||||
|
||||
// 检查巡查时间
|
||||
const checkInspectionTime = () => {
|
||||
const currentTime = now;
|
||||
let wDay = currentTime.day();
|
||||
if (wDay === 0) {
|
||||
wDay = 7;
|
||||
}
|
||||
let mDay = currentTime.date();
|
||||
const strDate = currentTime.format("YYYY-MM-DD") + " ";
|
||||
let xcFlag = false;
|
||||
let msg = "";
|
||||
|
||||
// 判断周期
|
||||
switch (xkkc.value.skzqlx) {
|
||||
case "每天":
|
||||
xcFlag = true;
|
||||
break;
|
||||
case "每周":
|
||||
const daysOfWeek = xkkc.value.skzq.split(",").map(Number);
|
||||
xcFlag = daysOfWeek.includes(wDay);
|
||||
break;
|
||||
case "每月":
|
||||
const daysOfMonth = xkkc.value.skzq.split(",").map(Number);
|
||||
xcFlag = daysOfMonth.includes(mDay);
|
||||
break;
|
||||
}
|
||||
|
||||
// 判断日期是否合格
|
||||
if (xcFlag) {
|
||||
// xkkc.skkstime开始时间向前xcBeforeMinute分钟
|
||||
const startTime = dayjs(strDate + xkkc.value.skkstime).subtract(
|
||||
xcBeforeMinute.value,
|
||||
"minute"
|
||||
);
|
||||
const endTime = dayjs(strDate + xkkc.value.skjstime);
|
||||
xcFlag = currentTime.isBefore(endTime) && currentTime.isAfter(startTime);
|
||||
|
||||
if (!xcFlag) {
|
||||
msg = "没到巡查时间";
|
||||
}
|
||||
} else {
|
||||
msg = "没到巡查日期";
|
||||
}
|
||||
|
||||
canInspect.value = xcFlag;
|
||||
inspectionStatusText.value = msg || "可以巡查";
|
||||
};
|
||||
|
||||
// 获取巡查时间提前分钟数
|
||||
const loadXcBeforeMinute = async () => {
|
||||
try {
|
||||
const res = await xcBeforeMinuteApi();
|
||||
if (res.resultCode == 1) {
|
||||
xcBeforeMinute.value = parseInt(res.result);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取巡查时间配置失败:", error);
|
||||
xcBeforeMinute.value = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// 提交数据
|
||||
const submit = async () => {
|
||||
if (!canInspect.value) {
|
||||
uni.showToast({
|
||||
title: inspectionStatusText.value,
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await xkscSaveApi({
|
||||
jsId: js.value.id,
|
||||
xkkcId: xkkc.value.id,
|
||||
xctime: now.format("YYYY-MM-DD HH:mm:ss"),
|
||||
xkxcList: xsList.value,
|
||||
xcItems: checkItems.value
|
||||
.filter((item) => item.checked)
|
||||
.map((item) => item.text),
|
||||
images: uploadedImages.value,
|
||||
videos: uploadedVideos.value,
|
||||
});
|
||||
|
||||
if (res && res.resultCode === 1) {
|
||||
uni.showToast({
|
||||
title: "提交成功",
|
||||
icon: "success",
|
||||
});
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: "提交失败",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("提交巡查失败:", error);
|
||||
uni.showToast({
|
||||
title: "提交失败",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 页面加载时获取状态选项
|
||||
onMounted(async () => {
|
||||
// await loadXcBeforeMinute();
|
||||
await loadXsList();
|
||||
await loadStatusOptions();
|
||||
checkInspectionTime();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 44px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.inspection-tabs {
|
||||
padding: 15px 15px 0 15px;
|
||||
background-color: #fff;
|
||||
margin-bottom: 10px;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.pending-inspection,
|
||||
.completed-inspection {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
|
||||
.course-time-info {
|
||||
margin-top: 15px;
|
||||
padding: 10px 15px;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #eee;
|
||||
|
||||
.time-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 5px;
|
||||
|
||||
.time-label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.time-value {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.inspection-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 15px;
|
||||
padding: 10px 15px;
|
||||
background-color: #fffbe6;
|
||||
border: 1px solid #ffe58f;
|
||||
border-radius: 4px;
|
||||
color: #faad14;
|
||||
font-size: 14px;
|
||||
|
||||
.status-text {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.section {
|
||||
.section-title-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.decorator {
|
||||
width: 4px;
|
||||
height: 16px;
|
||||
background-color: #4080ff;
|
||||
margin-right: 8px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.title-text {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.check-card {
|
||||
background-color: white;
|
||||
// .check-list {
|
||||
// // 巡查项目列表样式
|
||||
// }
|
||||
|
||||
.check-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.item-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.item-text {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.item-deduction {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.upload-card {
|
||||
background-color: white;
|
||||
// .upload-area {
|
||||
// // 上传区域样式
|
||||
// }
|
||||
}
|
||||
|
||||
.inspection-list {
|
||||
.inspection-record {
|
||||
.record-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
|
||||
.record-time {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
|
||||
.time-text {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.record-status {
|
||||
padding: 3px 8px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #4080ff;
|
||||
display: inline-flex;
|
||||
font-size: 12px;
|
||||
color: #4080ff;
|
||||
}
|
||||
}
|
||||
|
||||
.record-content {
|
||||
.content-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 5px;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
|
||||
.item-label {
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty-records {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 50px 0;
|
||||
|
||||
.empty-icon {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 16px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.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>
|
||||
Loading…
x
Reference in New Issue
Block a user