Merge branch 'master' of http://119.29.194.155:8894/zwq/zhxy-jsd
This commit is contained in:
commit
3fe5dc5b14
29
src/api/base/kyXcApi.ts
Normal file
29
src/api/base/kyXcApi.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { get, post } from "@/utils/request";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存课业辅导巡查
|
||||||
|
*/
|
||||||
|
export const kyXcSaveApi = async (params: any) => {
|
||||||
|
return await post("/api/kyXc/save", params);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取课业辅导巡查分页数据
|
||||||
|
*/
|
||||||
|
export const getKyXcPageApi = async (params: any) => {
|
||||||
|
return await get("/api/kyXc/findPage", params);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID获取课业辅导巡查详情
|
||||||
|
*/
|
||||||
|
export const getKyXcByIdApi = async (id: string) => {
|
||||||
|
return await get(`/api/kyXc/${id}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除课业辅导巡查
|
||||||
|
*/
|
||||||
|
export const deleteKyXcApi = async (id: string) => {
|
||||||
|
return await post(`/api/kyXc/delete/${id}`);
|
||||||
|
};
|
||||||
57
src/api/base/xkPbApi.ts
Normal file
57
src/api/base/xkPbApi.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { get, post } from "@/utils/request";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取选课排班分页数据
|
||||||
|
*/
|
||||||
|
export const getXkPbPageApi = async (params: any) => {
|
||||||
|
return await get("/api/xkPb/findPage", params);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID获取选课排班详情
|
||||||
|
*/
|
||||||
|
export const getXkPbByIdApi = async (id: string) => {
|
||||||
|
return await get(`/api/xkPb/${id}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建选课排班
|
||||||
|
*/
|
||||||
|
export const createXkPbApi = async (params: any) => {
|
||||||
|
return await post("/api/xkPb", params);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新选课排班
|
||||||
|
*/
|
||||||
|
export const updateXkPbApi = async (params: any) => {
|
||||||
|
return await post("/api/xkPb/update", params);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除选课排班
|
||||||
|
*/
|
||||||
|
export const deleteXkPbApi = async (id: string) => {
|
||||||
|
return await post(`/api/xkPb/delete/${id}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据选课ID获取排班列表
|
||||||
|
*/
|
||||||
|
export const getXkPbListByXkIdApi = async (params: any) => {
|
||||||
|
return await get("/api/xkPb/findByXkId", params);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 课程巡查接口
|
||||||
|
*/
|
||||||
|
export const getXcCourseListApi = async (params: any) => {
|
||||||
|
return await get("/api/xkPb/getXcCourseList", params);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 课业辅导巡查接口
|
||||||
|
*/
|
||||||
|
export const getKyXcCourseListApi = async (params: any) => {
|
||||||
|
return await get("/api/xkPb/getKyXcCourseList", params);
|
||||||
|
};
|
||||||
@ -147,3 +147,9 @@ const setDefaultValue = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -250,6 +250,27 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/view/routine/kefuxuncha/xcXkList",
|
"path": "pages/view/routine/kefuxuncha/xcXkList",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "课服清单",
|
||||||
|
"enablePullDownRefresh": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/view/routine/kefuxuncha/kyXkList",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "课业辅导巡查",
|
||||||
|
"enablePullDownRefresh": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/view/routine/kefuxuncha/kyXkkcDetail",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "课业辅导巡查执行",
|
||||||
|
"enablePullDownRefresh": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/view/routine/kefuxuncha/xcPbList",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "课服巡查",
|
"navigationBarTitleText": "课服巡查",
|
||||||
"enablePullDownRefresh": false
|
"enablePullDownRefresh": false
|
||||||
|
|||||||
@ -245,7 +245,7 @@ const sections = reactive<Section[]>([
|
|||||||
text: "课服巡查",
|
text: "课服巡查",
|
||||||
show: true,
|
show: true,
|
||||||
permissionKey: "routine-kfxc", // 课服巡查权限编码
|
permissionKey: "routine-kfxc", // 课服巡查权限编码
|
||||||
path: "/pages/view/routine/kefuxuncha/xcXkList",
|
path: "/pages/view/routine/kefuxuncha/xcPbList",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "r5",
|
id: "r5",
|
||||||
|
|||||||
@ -90,10 +90,10 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- 更多图标 -->
|
<!-- 箭头图标 -->
|
||||||
<view class="more-icon-container" @click.stop="showMoreOptions(student)">
|
<view class="arrow-icon-container" @click.stop="viewStudentDetail(student)">
|
||||||
<image
|
<image
|
||||||
class="more-icon"
|
class="arrow-icon"
|
||||||
src="/static/base/view/more.png"
|
src="/static/base/view/more.png"
|
||||||
mode="aspectFit"
|
mode="aspectFit"
|
||||||
></image>
|
></image>
|
||||||
@ -146,6 +146,9 @@ interface StudentInfo {
|
|||||||
bjmc: string
|
bjmc: string
|
||||||
jzIds?: string
|
jzIds?: string
|
||||||
jzxm?: string
|
jzxm?: string
|
||||||
|
xb?: string // 性别
|
||||||
|
sfzh?: string // 身份证号
|
||||||
|
cstime?: string // 出生日期
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ApiResponse {
|
interface ApiResponse {
|
||||||
@ -258,60 +261,7 @@ const getListTitle = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示更多选项
|
|
||||||
const showMoreOptions = (student: StudentInfo) => {
|
|
||||||
console.log('显示更多选项:', student)
|
|
||||||
|
|
||||||
// 显示操作菜单
|
|
||||||
uni.showActionSheet({
|
|
||||||
itemList: ['查看详情', '编辑信息', '联系家长', '删除学生'],
|
|
||||||
success: (res) => {
|
|
||||||
const tapIndex = res.tapIndex
|
|
||||||
switch (tapIndex) {
|
|
||||||
case 0:
|
|
||||||
// 查看详情
|
|
||||||
viewStudentDetail(student)
|
|
||||||
break
|
|
||||||
case 1:
|
|
||||||
// 编辑信息
|
|
||||||
uni.showToast({
|
|
||||||
title: '编辑功能开发中',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
break
|
|
||||||
case 2:
|
|
||||||
// 联系家长
|
|
||||||
if (student.jzxm) {
|
|
||||||
uni.showToast({
|
|
||||||
title: '联系家长功能开发中',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
uni.showToast({
|
|
||||||
title: '该学生暂无家长信息',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 3:
|
|
||||||
// 删除学生
|
|
||||||
uni.showModal({
|
|
||||||
title: '确认删除',
|
|
||||||
content: `确定要删除学生 ${student.xsxm} 吗?`,
|
|
||||||
success: (modalRes) => {
|
|
||||||
if (modalRes.confirm) {
|
|
||||||
uni.showToast({
|
|
||||||
title: '删除功能开发中',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取关注状态样式类
|
// 获取关注状态样式类
|
||||||
const getFollowStatusClass = (jzxm?: string) => {
|
const getFollowStatusClass = (jzxm?: string) => {
|
||||||
@ -336,7 +286,10 @@ const viewStudentDetail = (student: StudentInfo) => {
|
|||||||
bjId: student.bjId,
|
bjId: student.bjId,
|
||||||
bjmc: student.bjmc,
|
bjmc: student.bjmc,
|
||||||
jzIds: student.jzIds,
|
jzIds: student.jzIds,
|
||||||
jzxm: student.jzxm
|
jzxm: student.jzxm,
|
||||||
|
xb: student.xb, // 性别
|
||||||
|
sfzh: student.sfzh, // 身份证号
|
||||||
|
cstime: student.cstime // 出生日期
|
||||||
})
|
})
|
||||||
|
|
||||||
// 跳转到学生详情页面
|
// 跳转到学生详情页面
|
||||||
@ -542,7 +495,7 @@ onLoad(() => {
|
|||||||
padding: 24rpx;
|
padding: 24rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.more-icon-container {
|
.arrow-icon-container {
|
||||||
width: 40rpx;
|
width: 40rpx;
|
||||||
height: 40rpx;
|
height: 40rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -563,14 +516,14 @@ onLoad(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.more-icon {
|
.arrow-icon {
|
||||||
width: 35rpx;
|
width: 35rpx;
|
||||||
height: 35rpx;
|
height: 35rpx;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
transition: opacity 0.2s ease;
|
transition: opacity 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.more-icon-container:hover .more-icon {
|
.arrow-icon-container:hover .arrow-icon {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
707
src/pages/view/routine/kefuxuncha/kyXkList.vue
Normal file
707
src/pages/view/routine/kefuxuncha/kyXkList.vue
Normal file
@ -0,0 +1,707 @@
|
|||||||
|
<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.gradeName || '暂无' }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="course-info-item" v-if="xkkc.bjmc">
|
||||||
|
<view class="info-label">班级:</view>
|
||||||
|
<view class="info-data">{{ xkkc.bjmc || '暂无' }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="separator-line"></view>
|
||||||
|
<view class="course-btn-group">
|
||||||
|
<view class="xc-btn" @click.stop="goXc(xkkc)">巡查</view>
|
||||||
|
<view class="record-btn" @click.stop="goRecord(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 { getKyXcCourseListApi } from "@/api/base/xkPbApi";
|
||||||
|
import { useDataStore } from "@/store/modules/data";
|
||||||
|
import { useUserStore } from "@/store/modules/user";
|
||||||
|
import { onBeforeUnmount, onMounted, ref } from "vue";
|
||||||
|
|
||||||
|
const { getJs } = useUserStore();
|
||||||
|
const dataStore = useDataStore();
|
||||||
|
|
||||||
|
// 控制选择器显示状态
|
||||||
|
const showXkFlag = ref(false);
|
||||||
|
|
||||||
|
const xkList = ref<any>([]);
|
||||||
|
const xkData = ref();
|
||||||
|
|
||||||
|
// 课程列表数据
|
||||||
|
const xkkcList = ref<any[]>([]);
|
||||||
|
|
||||||
|
const xcBeforeMinute = ref<number>(0);
|
||||||
|
|
||||||
|
// 星期名称列表
|
||||||
|
const wdNameList = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"];
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
uni.showLoading({
|
||||||
|
title: "加载中...",
|
||||||
|
});
|
||||||
|
|
||||||
|
// 优先从global获取排班数据,如果没有则从data获取
|
||||||
|
let pbData = dataStore.getGlobal;
|
||||||
|
|
||||||
|
if (!pbData || !pbData.xcbt || !pbData.xcbt.includes('课业辅导巡计划')) {
|
||||||
|
pbData = dataStore.getData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查数据是否有效
|
||||||
|
if (!pbData || !pbData.xcbt || pbData.xcbt.includes('课业辅导巡计划') === false) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '数据异常,请重新选择排班',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
uni.navigateBack();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否是课程数据(包含kcmc字段)
|
||||||
|
if (pbData.kcmc) {
|
||||||
|
// 这是课程数据,需要重建排班数据
|
||||||
|
// 从课程数据中提取排班相关字段
|
||||||
|
const reconstructedPbData = {
|
||||||
|
id: pbData.pbId, // 使用pbId作为排班ID
|
||||||
|
status: 'A',
|
||||||
|
njIds: pbData.njIds || '',
|
||||||
|
bjIds: pbData.bjIds || '',
|
||||||
|
xcbt: pbData.xcbt,
|
||||||
|
xclx: pbData.xclx,
|
||||||
|
xqId: pbData.xqId,
|
||||||
|
xqmc: pbData.xqmc,
|
||||||
|
xcstime: pbData.xcstime,
|
||||||
|
xcjstime: pbData.xcjstime,
|
||||||
|
pk: pbData.pk
|
||||||
|
};
|
||||||
|
dataStore.setGlobal(reconstructedPbData);
|
||||||
|
pbData = reconstructedPbData;
|
||||||
|
} else {
|
||||||
|
// 这是排班数据,直接保存
|
||||||
|
dataStore.setGlobal(pbData);
|
||||||
|
}
|
||||||
|
|
||||||
|
await loadXcCourseList(pbData);
|
||||||
|
|
||||||
|
uni.hideLoading();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 加载巡查课程列表
|
||||||
|
const loadXcCourseList = async (pbData: any) => {
|
||||||
|
try {
|
||||||
|
// 检查pbData是否有效
|
||||||
|
if (!pbData || !pbData.id) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '排班数据无效,请重新选择',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await getKyXcCourseListApi({
|
||||||
|
jsId: getJs.id,
|
||||||
|
pbId: pbData.id
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res && res.resultCode == 1) {
|
||||||
|
const list = res.result || [];
|
||||||
|
xkkcList.value = list.map((item: any) => ({
|
||||||
|
id: item.id, // 课程记录ID
|
||||||
|
pbId: item.pbId || pbData.id, // 排班ID
|
||||||
|
kcmc: item.kmmc || '课业辅导',
|
||||||
|
gradeName: item.bc && item.njmc ? `${item.bc}(${item.njmc})` : (item.njmc || '暂无'),
|
||||||
|
bjmc: item.bjmc || '暂无',
|
||||||
|
// 添加年级和班级ID字段
|
||||||
|
njId: item.njId || '',
|
||||||
|
njmcId: item.njmcId || '',
|
||||||
|
bjId: item.bjId || ''
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
xkkcList.value = [];
|
||||||
|
uni.showToast({
|
||||||
|
title: (res as any).resultMessage || '获取课业辅导巡查失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载巡查课程失败:', error);
|
||||||
|
xkkcList.value = [];
|
||||||
|
uni.showToast({
|
||||||
|
title: '加载巡查课程失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 显示选课选择器
|
||||||
|
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) => {
|
||||||
|
// 直接从global获取排班数据
|
||||||
|
const pbData = dataStore.getGlobal;
|
||||||
|
|
||||||
|
// 检查排班数据是否有效
|
||||||
|
if (!pbData || !pbData.xcbt || !pbData.xcbt.includes('课业辅导巡计划')) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '数据异常,请重新选择排班',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 合并排班数据和课程数据
|
||||||
|
const combinedData = {
|
||||||
|
...xkkc,
|
||||||
|
id: xkkc.id, // 课程记录ID
|
||||||
|
pbId: pbData.id, // 排班ID - 确保使用正确的排班ID
|
||||||
|
xclx: pbData.xclx,
|
||||||
|
xcbt: pbData.xcbt,
|
||||||
|
xqmc: pbData.xqmc,
|
||||||
|
// 确保传递年级和班级ID
|
||||||
|
njId: xkkc.njId || '',
|
||||||
|
njmcId: xkkc.njmcId || '',
|
||||||
|
bjId: xkkc.bjId || ''
|
||||||
|
};
|
||||||
|
|
||||||
|
// 使用不同的存储键来避免覆盖排班数据
|
||||||
|
dataStore.setData(combinedData); // 存储课程数据
|
||||||
|
|
||||||
|
// 确保保存到global的是原始排班数据,而不是课程数据
|
||||||
|
// 从combinedData中提取排班相关字段
|
||||||
|
const originalPbData = {
|
||||||
|
id: pbData.id, // 排班ID
|
||||||
|
status: pbData.status,
|
||||||
|
njIds: pbData.njIds,
|
||||||
|
bjIds: pbData.bjIds,
|
||||||
|
xcbt: pbData.xcbt,
|
||||||
|
xclx: pbData.xclx,
|
||||||
|
xqId: pbData.xqId,
|
||||||
|
xqmc: pbData.xqmc,
|
||||||
|
xcstime: pbData.xcstime,
|
||||||
|
xcjstime: pbData.xcjstime,
|
||||||
|
pk: pbData.pk
|
||||||
|
};
|
||||||
|
dataStore.setGlobal(originalPbData); // 保存原始排班数据到global
|
||||||
|
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/view/routine/kefuxuncha/kyXkkcDetail`,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 跳转到巡查记录
|
||||||
|
const goRecord = (xkkc: any) => {
|
||||||
|
// 直接从global获取排班数据
|
||||||
|
const pbData = dataStore.getGlobal;
|
||||||
|
|
||||||
|
// 检查排班数据是否有效
|
||||||
|
if (!pbData || !pbData.xcbt || !pbData.xcbt.includes('课业辅导巡计划')) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '数据异常,请重新选择排班',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 合并排班数据和课程数据
|
||||||
|
const combinedData = {
|
||||||
|
...xkkc,
|
||||||
|
id: xkkc.id, // 课程记录ID
|
||||||
|
pbId: pbData.id, // 排班ID - 确保使用正确的排班ID
|
||||||
|
xclx: pbData.xclx,
|
||||||
|
xcbt: pbData.xcbt,
|
||||||
|
xqmc: pbData.xqmc,
|
||||||
|
// 确保传递年级和班级ID
|
||||||
|
njId: xkkc.njId || '',
|
||||||
|
njmcId: xkkc.njmcId || '',
|
||||||
|
bjId: xkkc.bjId || ''
|
||||||
|
};
|
||||||
|
dataStore.setData(combinedData);
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/view/routine/kefuxuncha/xcRecord`,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 页面卸载前清除定时器
|
||||||
|
onBeforeUnmount(() => {});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.interest-course {
|
||||||
|
min-height: 100%;
|
||||||
|
background: linear-gradient(180deg, #f8fafc 0%, #f1f5f9 100%);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selection-header {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
padding: 25px 20px;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 0 0 20px 20px;
|
||||||
|
box-shadow: 0 8px 32px rgba(102, 126, 234, 0.3);
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 10;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: linear-gradient(45deg, rgba(255, 255, 255, 0.1) 0%, transparent 50%, rgba(255, 255, 255, 0.05) 100%);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
.title-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch-btn {
|
||||||
|
padding: 8px 16px;
|
||||||
|
background-color: rgba(255, 255, 255, 0.2);
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.3);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 可滚动内容区域样式
|
||||||
|
.scrollable-content {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
-webkit-overflow-scrolling: touch; // 增强iOS滚动体验
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-list {
|
||||||
|
padding: 15px 15px 0 15px;
|
||||||
|
|
||||||
|
.course-item {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid #f0f0f0;
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||||
|
animation: fadeInUp 0.6s ease-out;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.12);
|
||||||
|
border-color: #e8e8e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
border: 2px solid #3fbf72;
|
||||||
|
background-color: rgba(63, 191, 114, 0.02);
|
||||||
|
box-shadow: 0 4px 20px rgba(63, 191, 114, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-name {
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a1a1a;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
line-height: 1.4;
|
||||||
|
animation: fadeInLeft 0.5s ease-out 0.1s both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-btn-group {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 10px; // Added gap for spacing between buttons
|
||||||
|
|
||||||
|
.xc-btn {
|
||||||
|
display: inline-block;
|
||||||
|
color: #ff6b35;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 8px 18px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: linear-gradient(135deg, rgba(255, 107, 53, 0.1), rgba(255, 107, 53, 0.05));
|
||||||
|
border: 1px solid #ff6b35;
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
box-shadow: 0 2px 8px rgba(255, 107, 53, 0.15);
|
||||||
|
animation: fadeInUp 0.5s ease-out 0.3s both;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: linear-gradient(135deg, rgba(255, 107, 53, 0.15), rgba(255, 107, 53, 0.1));
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 15px rgba(255, 107, 53, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: linear-gradient(135deg, rgba(255, 107, 53, 0.2), rgba(255, 107, 53, 0.15));
|
||||||
|
transform: translateY(0);
|
||||||
|
box-shadow: 0 2px 8px rgba(255, 107, 53, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-btn {
|
||||||
|
display: inline-block;
|
||||||
|
color: #409EFF;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 8px 18px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: linear-gradient(135deg, rgba(64, 158, 255, 0.1), rgba(64, 158, 255, 0.05));
|
||||||
|
border: 1px solid #409EFF;
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.15);
|
||||||
|
animation: fadeInUp 0.5s ease-out 0.3s both;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: linear-gradient(135deg, rgba(64, 158, 255, 0.15), rgba(64, 158, 255, 0.1));
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 15px rgba(64, 158, 255, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: linear-gradient(135deg, rgba(64, 158, 255, 0.2), rgba(64, 158, 255, 0.15));
|
||||||
|
transform: translateY(0);
|
||||||
|
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-info-item {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
font-size: 13px;
|
||||||
|
align-items: center;
|
||||||
|
animation: fadeInUp 0.5s ease-out 0.15s both;
|
||||||
|
|
||||||
|
.info-label {
|
||||||
|
color: #666;
|
||||||
|
flex: 0 0 100px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-data {
|
||||||
|
flex: 1 0 1px;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator-line {
|
||||||
|
height: 1px;
|
||||||
|
background: linear-gradient(90deg, transparent, #e8e8e8, transparent);
|
||||||
|
margin: 18px 0;
|
||||||
|
opacity: 0.8;
|
||||||
|
animation: fadeIn 0.5s ease-out 0.25s both;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加动画关键帧
|
||||||
|
@keyframes fadeInUp {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(20px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInLeft {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-20px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInRight {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(20px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 全局图片样式 */
|
||||||
|
.w-full {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h-full {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暂无数据样式
|
||||||
|
.empty-course-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 80px 20px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.empty-icon {
|
||||||
|
margin-bottom: 25px;
|
||||||
|
background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
|
||||||
|
width: 90px;
|
||||||
|
height: 90px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
|
||||||
|
border: 2px solid rgba(255, 255, 255, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-text {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #475569;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-desc {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #64748b;
|
||||||
|
max-width: 80%;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 选课选择弹窗样式 */
|
||||||
|
.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;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-active {
|
||||||
|
background-color: rgba(64, 158, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(64, 158, 255, 0.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
815
src/pages/view/routine/kefuxuncha/kyXkkcDetail.vue
Normal file
815
src/pages/view/routine/kefuxuncha/kyXkkcDetail.vue
Normal file
@ -0,0 +1,815 @@
|
|||||||
|
<template>
|
||||||
|
<BasicLayout>
|
||||||
|
<!-- 待巡查内容 -->
|
||||||
|
<view 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">
|
||||||
|
<view class="time-label">年级:</view>
|
||||||
|
<view class="time-value">{{ xkkc.gradeName || '暂无' }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="time-item" v-if="xkkc.bjmc">
|
||||||
|
<view class="time-label">班级:</view>
|
||||||
|
<view class="time-value">{{ xkkc.bjmc || '暂无' }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="time-item">
|
||||||
|
<view class="time-label">巡查类型:</view>
|
||||||
|
<view class="time-value">{{ xkkc.xclx === 'B' ? '课业辅导巡查' : '课程巡查' }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="time-item">
|
||||||
|
<view class="time-label">排班标题:</view>
|
||||||
|
<view class="time-value">{{ xkkc.xcbt || '暂无' }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="time-item">
|
||||||
|
<view class="time-label">学期:</view>
|
||||||
|
<view class="time-value">{{ xkkc.xqmc || '暂无' }}</view>
|
||||||
|
</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">
|
||||||
|
<template v-if="checkItems && checkItems.length > 0">
|
||||||
|
<view class="check-list">
|
||||||
|
<view
|
||||||
|
v-for="(item, index) in checkItems"
|
||||||
|
:key="item.id"
|
||||||
|
class="check-item"
|
||||||
|
>
|
||||||
|
<view class="item-info flex-1">
|
||||||
|
<!-- 项目名称单独一行 -->
|
||||||
|
<text class="item-text"
|
||||||
|
>{{ index + 1 }}、{{ item.xcMc }}</text
|
||||||
|
>
|
||||||
|
<!-- 分值和结果同一行 -->
|
||||||
|
<view class="item-score-result">
|
||||||
|
<text class="item-deduction mr-20">
|
||||||
|
分值:{{ item.xmFz }}分
|
||||||
|
</text>
|
||||||
|
<view class="item-result">
|
||||||
|
<radio-group
|
||||||
|
:name="'result_' + item.id"
|
||||||
|
class="item-radio-group"
|
||||||
|
@change="onCheckItemChange($event, item)"
|
||||||
|
>
|
||||||
|
<label class="item-radio-label mr-10">
|
||||||
|
<radio
|
||||||
|
:value="'A'"
|
||||||
|
:checked="item.checked === true"
|
||||||
|
color="#4080ff"
|
||||||
|
class="item-radio"
|
||||||
|
/>
|
||||||
|
<text class="ml-2">有</text>
|
||||||
|
</label>
|
||||||
|
<label class="item-radio-label">
|
||||||
|
<radio
|
||||||
|
:value="'B'"
|
||||||
|
:checked="item.checked === false"
|
||||||
|
color="#4080ff"
|
||||||
|
class="item-radio"
|
||||||
|
/>
|
||||||
|
<text class="ml-2">无</text>
|
||||||
|
</label>
|
||||||
|
</radio-group>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<view
|
||||||
|
class="no-check-items"
|
||||||
|
style="text-align: center; color: #999; padding: 20px 0"
|
||||||
|
>
|
||||||
|
暂无巡查项目
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</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-section">
|
||||||
|
<view class="upload-list">
|
||||||
|
<view
|
||||||
|
v-for="(image, index) in imageList"
|
||||||
|
:key="index"
|
||||||
|
class="upload-item"
|
||||||
|
>
|
||||||
|
<image
|
||||||
|
:src="image.url ? imagUrl(image.url) : image.tempPath"
|
||||||
|
mode="aspectFill"
|
||||||
|
class="upload-image"
|
||||||
|
@click="previewImage(index)"
|
||||||
|
/>
|
||||||
|
<view class="upload-delete" @click="deleteImage(index)">
|
||||||
|
<text class="delete-icon">×</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
v-if="imageList.length < 5"
|
||||||
|
class="upload-add"
|
||||||
|
@click="chooseImage"
|
||||||
|
>
|
||||||
|
<text class="add-icon">+</text>
|
||||||
|
<text class="add-text">添加图片</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</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-section">
|
||||||
|
<view class="upload-list">
|
||||||
|
<view
|
||||||
|
v-for="(video, index) in videoList"
|
||||||
|
:key="index"
|
||||||
|
class="upload-item"
|
||||||
|
>
|
||||||
|
<video
|
||||||
|
:src="video.url ? video.url : video.tempPath"
|
||||||
|
class="upload-video"
|
||||||
|
:controls="false"
|
||||||
|
:show-center-play-btn="false"
|
||||||
|
:show-play-btn="false"
|
||||||
|
:show-fullscreen-btn="false"
|
||||||
|
:show-progress="false"
|
||||||
|
:show-mute-btn="false"
|
||||||
|
:enable-progress-gesture="false"
|
||||||
|
:enable-play-gesture="false"
|
||||||
|
:loop="false"
|
||||||
|
:muted="true"
|
||||||
|
:poster="''"
|
||||||
|
></video>
|
||||||
|
<view class="video-play-icon">
|
||||||
|
<u-icon name="play-right-fill" color="#fff" size="20"></u-icon>
|
||||||
|
</view>
|
||||||
|
<view class="upload-delete" @click="deleteVideo(index)">
|
||||||
|
<text class="delete-icon">×</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
v-if="videoList.length < 3"
|
||||||
|
class="upload-add"
|
||||||
|
@click="chooseVideo"
|
||||||
|
>
|
||||||
|
<text class="add-icon">+</text>
|
||||||
|
<text class="add-text">添加视频</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<template #bottom>
|
||||||
|
<view
|
||||||
|
v-if="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 { xcXmFindByXcLxApi } from "@/api/base/xcXmApi";
|
||||||
|
import { kyXcSaveApi } from "@/api/base/kyXcApi";
|
||||||
|
import { attachmentUpload } from "@/api/system/upload";
|
||||||
|
import BasicLayout from "@/components/BasicLayout/Layout.vue";
|
||||||
|
import { useDataStore } from "@/store/modules/data";
|
||||||
|
import { useUserStore } from "@/store/modules/user";
|
||||||
|
import { computed, onMounted, ref } from "vue";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import { imagUrl } from "@/utils";
|
||||||
|
import { showLoading, hideLoading, showToast } from "@/utils/uniapp";
|
||||||
|
|
||||||
|
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 checkItems = ref<any[]>([]);
|
||||||
|
|
||||||
|
// 图片列表 - 修改为包含临时路径和服务器路径的对象
|
||||||
|
interface ImageItem {
|
||||||
|
tempPath?: string; // 临时路径(用于预览)
|
||||||
|
url?: string; // 服务器路径(上传成功后)
|
||||||
|
name?: string; // 文件名
|
||||||
|
}
|
||||||
|
|
||||||
|
// 视频列表 - 修改为包含临时路径和服务器路径的对象
|
||||||
|
interface VideoItem {
|
||||||
|
tempPath?: string; // 临时路径(用于预览)
|
||||||
|
url?: string; // 服务器路径(上传成功后)
|
||||||
|
name?: string; // 文件名
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageList = ref<ImageItem[]>([]);
|
||||||
|
const videoList = ref<VideoItem[]>([]);
|
||||||
|
|
||||||
|
// 巡查状态相关
|
||||||
|
const inspectionStatusText = ref("");
|
||||||
|
const canInspect = ref(true); // 是否可以巡查
|
||||||
|
|
||||||
|
// 加载巡查项目
|
||||||
|
const loadCheckItems = async () => {
|
||||||
|
try {
|
||||||
|
const res = await xcXmFindByXcLxApi("课业辅导巡查");
|
||||||
|
|
||||||
|
if (res && res.resultCode === 1 && res.result && res.result.length > 0) {
|
||||||
|
checkItems.value = res.result.map((item: any) => {
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
|
xcMc: item.xcMc,
|
||||||
|
xmFz: item.xmFz,
|
||||||
|
xcLx: item.xcLx,
|
||||||
|
checked: false,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
checkItems.value = [];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("加载巡查项目失败:", error);
|
||||||
|
checkItems.value = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onCheckItemChange = (e: any, item: any) => {
|
||||||
|
item.checked = e.detail.value === "A";
|
||||||
|
};
|
||||||
|
|
||||||
|
// 选择图片
|
||||||
|
const chooseImage = () => {
|
||||||
|
uni.chooseImage({
|
||||||
|
count: 5 - imageList.value.length,
|
||||||
|
sizeType: ['compressed'],
|
||||||
|
sourceType: ['album', 'camera'],
|
||||||
|
success: async (res) => {
|
||||||
|
// 添加临时图片到列表
|
||||||
|
const tempFilePaths = res.tempFilePaths as string[];
|
||||||
|
const newImages = tempFilePaths.map((path: string) => ({
|
||||||
|
tempPath: path,
|
||||||
|
name: path.split('/').pop() || 'image.jpg'
|
||||||
|
}));
|
||||||
|
imageList.value = [...imageList.value, ...newImages];
|
||||||
|
// 自动上传图片
|
||||||
|
await uploadImages(newImages);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 选择视频
|
||||||
|
const chooseVideo = () => {
|
||||||
|
uni.chooseVideo({
|
||||||
|
sourceType: ['album', 'camera'],
|
||||||
|
maxDuration: 60,
|
||||||
|
camera: 'back',
|
||||||
|
success: async (res) => {
|
||||||
|
// 添加临时视频到列表
|
||||||
|
const tempFilePath = res.tempFilePath;
|
||||||
|
const newVideo = {
|
||||||
|
tempPath: tempFilePath,
|
||||||
|
name: tempFilePath.split('/').pop() || 'video.mp4'
|
||||||
|
};
|
||||||
|
videoList.value = [...videoList.value, newVideo];
|
||||||
|
// 自动上传视频
|
||||||
|
await uploadVideos([newVideo]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 上传图片到服务器
|
||||||
|
const uploadImages = async (images: ImageItem[]) => {
|
||||||
|
try {
|
||||||
|
showLoading('上传图片中...');
|
||||||
|
|
||||||
|
for (let i = 0; i < images.length; i++) {
|
||||||
|
const image = images[i];
|
||||||
|
if (image.tempPath) {
|
||||||
|
try {
|
||||||
|
// 调用上传接口
|
||||||
|
const uploadResult: any = await attachmentUpload(image.tempPath as any);
|
||||||
|
|
||||||
|
if (uploadResult && uploadResult.resultCode === 1 && uploadResult.result && uploadResult.result.length > 0) {
|
||||||
|
// 保存服务器返回的文件路径
|
||||||
|
const serverPath = uploadResult.result[0].filePath;
|
||||||
|
|
||||||
|
// 更新图片对象,保存服务器路径
|
||||||
|
const index = imageList.value.findIndex(img => img.tempPath === image.tempPath);
|
||||||
|
if (index !== -1) {
|
||||||
|
imageList.value[index].url = serverPath;
|
||||||
|
// 可以删除临时路径以节省内存
|
||||||
|
delete imageList.value[index].tempPath;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error('上传响应格式异常');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('图片上传失败:', error);
|
||||||
|
showToast({ title: `${image.name || '图片'}上传失败`, icon: 'none' });
|
||||||
|
|
||||||
|
// 从列表中移除上传失败的图片
|
||||||
|
const index = imageList.value.findIndex(img => img.tempPath === image.tempPath);
|
||||||
|
if (index !== -1) {
|
||||||
|
imageList.value.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hideLoading();
|
||||||
|
showToast({ title: '图片上传完成', icon: 'success' });
|
||||||
|
} catch (error) {
|
||||||
|
hideLoading();
|
||||||
|
console.error('批量上传图片失败:', error);
|
||||||
|
showToast({ title: '图片上传失败,请重试', icon: 'none' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 上传视频到服务器
|
||||||
|
const uploadVideos = async (videos: VideoItem[]) => {
|
||||||
|
try {
|
||||||
|
showLoading('上传视频中...');
|
||||||
|
|
||||||
|
for (let i = 0; i < videos.length; i++) {
|
||||||
|
const video = videos[i];
|
||||||
|
if (video.tempPath) {
|
||||||
|
try {
|
||||||
|
// 调用上传接口
|
||||||
|
const uploadResult: any = await attachmentUpload(video.tempPath as any);
|
||||||
|
|
||||||
|
if (uploadResult && uploadResult.resultCode === 1 && uploadResult.result && uploadResult.result.length > 0) {
|
||||||
|
// 保存服务器返回的文件路径
|
||||||
|
const serverPath = uploadResult.result[0].filePath;
|
||||||
|
|
||||||
|
// 更新视频对象,保存服务器路径
|
||||||
|
const index = videoList.value.findIndex(v => v.tempPath === video.tempPath);
|
||||||
|
if (index !== -1) {
|
||||||
|
videoList.value[index].url = serverPath;
|
||||||
|
// 可以删除临时路径以节省内存
|
||||||
|
delete videoList.value[index].tempPath;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error('上传响应格式异常');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('视频上传失败:', error);
|
||||||
|
showToast({ title: `${video.name || '视频'}上传失败`, icon: 'none' });
|
||||||
|
|
||||||
|
// 从列表中移除上传失败的视频
|
||||||
|
const index = videoList.value.findIndex(v => v.tempPath === video.tempPath);
|
||||||
|
if (index !== -1) {
|
||||||
|
videoList.value.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hideLoading();
|
||||||
|
showToast({ title: '视频上传完成', icon: 'success' });
|
||||||
|
} catch (error) {
|
||||||
|
hideLoading();
|
||||||
|
console.error('批量上传视频失败:', error);
|
||||||
|
showToast({ title: '视频上传失败,请重试', icon: 'none' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 预览图片
|
||||||
|
const previewImage = (index: number) => {
|
||||||
|
const urls = imageList.value.map(img =>
|
||||||
|
img.url ? imagUrl(img.url) : img.tempPath
|
||||||
|
).filter((url): url is string => !!url);
|
||||||
|
|
||||||
|
uni.previewImage({
|
||||||
|
urls: urls,
|
||||||
|
current: index
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除图片
|
||||||
|
const deleteImage = (index: number) => {
|
||||||
|
imageList.value.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除视频
|
||||||
|
const deleteVideo = (index: number) => {
|
||||||
|
videoList.value.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 检查巡查时间 - 课业辅导巡查不需要时间验证
|
||||||
|
const checkInspectionTime = () => {
|
||||||
|
// 课业辅导巡查直接允许巡查,不需要时间验证
|
||||||
|
canInspect.value = true;
|
||||||
|
inspectionStatusText.value = "可以巡查";
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提交数据
|
||||||
|
const submit = async () => {
|
||||||
|
if (!canInspect.value) {
|
||||||
|
uni.showToast({
|
||||||
|
title: inspectionStatusText.value,
|
||||||
|
icon: "none",
|
||||||
|
duration: 2000,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证巡查项目是否已选择
|
||||||
|
const hasCheckedItems = checkItems.value.some(item => item.checked !== undefined);
|
||||||
|
if (!hasCheckedItems) {
|
||||||
|
uni.showToast({
|
||||||
|
title: "请至少选择一个巡查项目",
|
||||||
|
icon: "none",
|
||||||
|
duration: 2000,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 构建巡查项目列表
|
||||||
|
const xkXcXmList = checkItems.value.map((item: any) => {
|
||||||
|
const newItem = {
|
||||||
|
...item,
|
||||||
|
xcXmId: item.id,
|
||||||
|
xcJg: item.checked ? "A" : "B",
|
||||||
|
xkXcId: "", // 这个会在后端设置
|
||||||
|
};
|
||||||
|
newItem.id = "";
|
||||||
|
return newItem;
|
||||||
|
});
|
||||||
|
|
||||||
|
const submitData = {
|
||||||
|
jsId: js.value.id,
|
||||||
|
jsxm: js.value.xm || js.value.jsxm, // 添加教师姓名
|
||||||
|
njId: xkkc.value.njId || '', // 确保年级ID不为空
|
||||||
|
njmcId: xkkc.value.njmcId || '', // 确保年级名称ID不为空
|
||||||
|
bjId: xkkc.value.bjId || '', // 确保班级ID不为空
|
||||||
|
xctime: now.format("YYYY-MM-DD HH:mm:ss"),
|
||||||
|
zp: getImageUrls(),
|
||||||
|
sp: getVideoUrls(),
|
||||||
|
kyXcXmList: xkXcXmList, // 添加巡查项目列表
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await kyXcSaveApi(submitData);
|
||||||
|
|
||||||
|
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",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取图片URL列表 - 转换为逗号分隔的字符串
|
||||||
|
const getImageUrls = () => {
|
||||||
|
const urls = imageList.value
|
||||||
|
.filter(img => img.url) // 只返回有url的图片
|
||||||
|
.map(img => img.url)
|
||||||
|
.filter((url): url is string => !!url); // 过滤掉undefined和null
|
||||||
|
|
||||||
|
// 返回逗号分隔的字符串,如果没有图片则返回空字符串
|
||||||
|
return urls.length > 0 ? urls.join(',') : '';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取视频URL列表 - 转换为逗号分隔的字符串
|
||||||
|
const getVideoUrls = () => {
|
||||||
|
const urls = videoList.value
|
||||||
|
.filter(video => video.url) // 只返回有url的视频
|
||||||
|
.map(video => video.url)
|
||||||
|
.filter((url): url is string => !!url); // 过滤掉undefined和null
|
||||||
|
|
||||||
|
// 返回逗号分隔的字符串,如果没有视频则返回空字符串
|
||||||
|
return urls.length > 0 ? urls.join(',') : '';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 页面加载时获取状态选项
|
||||||
|
onMounted(async () => {
|
||||||
|
await loadCheckItems(); // 加载巡查项目
|
||||||
|
checkInspectionTime();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-white {
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pending-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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 0;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
|
||||||
|
.item-score-result {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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-section {
|
||||||
|
.upload-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-item {
|
||||||
|
position: relative;
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid #e9ecef;
|
||||||
|
|
||||||
|
.upload-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-video {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-play-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.6);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-delete {
|
||||||
|
position: absolute;
|
||||||
|
top: 4px;
|
||||||
|
right: 4px;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.6);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.delete-icon {
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-add {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
border: 2px dashed #e9ecef;
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.add-icon {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #6c757d;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-text {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #6c757d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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>
|
||||||
|
|
||||||
|
|
||||||
524
src/pages/view/routine/kefuxuncha/xcPbList.vue
Normal file
524
src/pages/view/routine/kefuxuncha/xcPbList.vue
Normal file
@ -0,0 +1,524 @@
|
|||||||
|
<template>
|
||||||
|
<view class="interest-course">
|
||||||
|
<!-- 选课排班信息头部 - 固定部分 -->
|
||||||
|
<view class="selection-header">
|
||||||
|
<view class="header-content">
|
||||||
|
<view class="title-section">
|
||||||
|
<view class="title">
|
||||||
|
<text v-if="pbList && pbList.length > 0">
|
||||||
|
{{ getCurrentSemesterName() }} - 选课排班
|
||||||
|
</text>
|
||||||
|
<text v-else>暂无排班数据</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 可滚动的内容区域 -->
|
||||||
|
<view class="scrollable-content">
|
||||||
|
<!-- 排班列表 -->
|
||||||
|
<view class="course-list" v-if="pbList && pbList.length > 0">
|
||||||
|
<view v-for="(pb, index) in pbList" :key="pb.id || index" class="course-item">
|
||||||
|
<view class="status-badge" :class="getStatusClass(pb)">
|
||||||
|
{{ getStatusText(pb) }}
|
||||||
|
</view>
|
||||||
|
<view class="course-name">{{ pb.xcbt }}</view>
|
||||||
|
<view class="course-info-item">
|
||||||
|
<view class="info-label">巡查类型:</view>
|
||||||
|
<view class="info-data">{{ getXclxText(pb.xclx) }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="course-info-item">
|
||||||
|
<view class="info-label">当前学期:</view>
|
||||||
|
<view class="info-data">{{ pb.xqmc || '暂无' }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="course-info-item" v-if="pb.remark">
|
||||||
|
<view class="info-label">备注:</view>
|
||||||
|
<view class="info-data">{{ pb.remark }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="separator-line"></view>
|
||||||
|
<view class="course-btn-group">
|
||||||
|
<view class="detail-btn" @click.stop="goXc(pb)">巡查</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 class="load-more" v-if="hasMore && pbList.length > 0">
|
||||||
|
<u-loading-icon v-if="loading" mode="spinner" size="20"></u-loading-icon>
|
||||||
|
<text v-else @click="loadMore">加载更多</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {
|
||||||
|
ref,
|
||||||
|
onBeforeUnmount,
|
||||||
|
onMounted,
|
||||||
|
reactive,
|
||||||
|
} from "vue";
|
||||||
|
import { useUserStore } from "@/store/modules/user";
|
||||||
|
import { useDataStore } from "@/store/modules/data";
|
||||||
|
import { getXkPbPageApi } from "@/api/base/xkPbApi";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
const { getJs } = useUserStore();
|
||||||
|
const { getData, setData } = useDataStore();
|
||||||
|
|
||||||
|
// 排班列表数据
|
||||||
|
const pbList = ref<any[]>([]);
|
||||||
|
const loading = ref(false);
|
||||||
|
const hasMore = ref(true);
|
||||||
|
|
||||||
|
// 分页参数
|
||||||
|
const pagination = reactive({
|
||||||
|
page: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadPbList();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 加载排班列表
|
||||||
|
const loadPbList = async (isRefresh = false) => {
|
||||||
|
if (loading.value) return;
|
||||||
|
|
||||||
|
loading.value = true;
|
||||||
|
|
||||||
|
if (isRefresh) {
|
||||||
|
pagination.page = 1;
|
||||||
|
pbList.value = [];
|
||||||
|
hasMore.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
page: pagination.page,
|
||||||
|
rows: pagination.pageSize,
|
||||||
|
// 可以根据需要添加筛选条件
|
||||||
|
// xcbt: '', // 排班标题
|
||||||
|
// xclx: '', // 排班类型
|
||||||
|
// xkId: '', // 选课ID
|
||||||
|
// xqId: '', // 学期ID
|
||||||
|
};
|
||||||
|
|
||||||
|
const res: any = await getXkPbPageApi(params);
|
||||||
|
|
||||||
|
// 根据实际API响应结构判断成功条件
|
||||||
|
if (res && (res.resultCode == 1 || res.rows || res.result)) {
|
||||||
|
// 根据实际API响应结构调整数据获取逻辑
|
||||||
|
const list = res.rows || res.result?.rows || res.result?.list || [];
|
||||||
|
|
||||||
|
if (isRefresh) {
|
||||||
|
pbList.value = list;
|
||||||
|
} else {
|
||||||
|
pbList.value.push(...list);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用records字段作为总记录数,如果没有则使用total
|
||||||
|
pagination.total = res.records || res.total || res.result?.total || 0;
|
||||||
|
|
||||||
|
// 判断是否还有更多数据
|
||||||
|
hasMore.value = pbList.value.length < pagination.total;
|
||||||
|
|
||||||
|
if (list.length < pagination.pageSize) {
|
||||||
|
hasMore.value = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: res.resultMessage || res.message || '获取排班列表失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载排班列表失败:', error);
|
||||||
|
uni.showToast({
|
||||||
|
title: '加载排班列表失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 加载更多
|
||||||
|
const loadMore = () => {
|
||||||
|
if (hasMore.value && !loading.value) {
|
||||||
|
pagination.page++;
|
||||||
|
loadPbList();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 下拉刷新
|
||||||
|
const onRefresh = () => {
|
||||||
|
loadPbList(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取当前学期名称
|
||||||
|
const getCurrentSemesterName = () => {
|
||||||
|
if (pbList.value && pbList.value.length > 0) {
|
||||||
|
// 从第一个排班获取学期名称
|
||||||
|
return pbList.value[0].xqmc || '当前学期';
|
||||||
|
}
|
||||||
|
return '当前学期';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 格式化日期时间
|
||||||
|
const formatDateTime = (dateTime: string) => {
|
||||||
|
if (!dateTime) {
|
||||||
|
return '暂无';
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return dayjs(dateTime).format('YYYY-MM-DD HH:mm:ss');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('时间格式化错误:', error);
|
||||||
|
return dateTime;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取状态文本
|
||||||
|
const getStatusText = (pb: any) => {
|
||||||
|
if (!pb.status || pb.status === 'A') {
|
||||||
|
return '正常';
|
||||||
|
}
|
||||||
|
return '已停用';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取状态样式类
|
||||||
|
const getStatusClass = (pb: any) => {
|
||||||
|
if (!pb.status || pb.status === 'A') {
|
||||||
|
return 'normal';
|
||||||
|
}
|
||||||
|
return 'disabled';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取巡查类型文本
|
||||||
|
const getXclxText = (xclx: string) => {
|
||||||
|
if (xclx === 'A') {
|
||||||
|
return '课程巡查';
|
||||||
|
} else if (xclx === 'B') {
|
||||||
|
return '课业辅导巡查';
|
||||||
|
}
|
||||||
|
return '暂无';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 跳转到巡查
|
||||||
|
const goXc = (pb: any) => {
|
||||||
|
// 添加调试信息
|
||||||
|
console.log('排班数据pb:', pb);
|
||||||
|
console.log('pb.id:', pb?.id);
|
||||||
|
console.log('pb的所有属性:', Object.keys(pb || {}));
|
||||||
|
|
||||||
|
setData(pb);
|
||||||
|
if (pb.xclx === 'A') {
|
||||||
|
// 课程巡查,跳转到课程巡查列表
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/view/routine/kefuxuncha/xcXkList`,
|
||||||
|
});
|
||||||
|
} else if (pb.xclx === 'B') {
|
||||||
|
// 课业辅导巡查,跳转到课业辅导巡查列表
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/view/routine/kefuxuncha/kyXkList`,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: '未知的巡查类型',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 页面卸载前清除定时器
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
// 清理工作
|
||||||
|
});
|
||||||
|
|
||||||
|
// 暴露方法给父组件
|
||||||
|
defineExpose({
|
||||||
|
loadPbList,
|
||||||
|
onRefresh,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.interest-course {
|
||||||
|
min-height: 100%;
|
||||||
|
background: linear-gradient(180deg, #f8fafc 0%, #f1f5f9 100%);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selection-header {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
padding: 25px 20px;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 0 0 20px 20px;
|
||||||
|
box-shadow: 0 8px 32px rgba(102, 126, 234, 0.3);
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 10;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: linear-gradient(45deg, rgba(255, 255, 255, 0.1) 0%, transparent 50%, rgba(255, 255, 255, 0.05) 100%);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
.title-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-align: center;
|
||||||
|
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 可滚动内容区域样式
|
||||||
|
.scrollable-content {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
-webkit-overflow-scrolling: touch; // 增强iOS滚动体验
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-list {
|
||||||
|
padding: 15px 15px 0 15px;
|
||||||
|
|
||||||
|
.course-item {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid #f0f0f0;
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||||
|
animation: fadeInUp 0.6s ease-out;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.12);
|
||||||
|
border-color: #e8e8e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-badge {
|
||||||
|
position: absolute;
|
||||||
|
top: 15px;
|
||||||
|
right: 15px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
animation: fadeInRight 0.5s ease-out 0.2s both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-badge.normal {
|
||||||
|
color: #67c23a;
|
||||||
|
border-color: #e1f3d8;
|
||||||
|
background-color: #f0f9ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-badge.disabled {
|
||||||
|
color: #f56c6c;
|
||||||
|
border-color: #fde2e2;
|
||||||
|
background-color: #fef0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-name {
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a1a1a;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
padding-right: 90px;
|
||||||
|
line-height: 1.4;
|
||||||
|
animation: fadeInLeft 0.5s ease-out 0.1s both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-btn-group {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
.detail-btn {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 8px 18px;
|
||||||
|
border-radius: 8px;
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||||
|
animation: fadeInUp 0.5s ease-out 0.3s both;
|
||||||
|
color: #2879ff;
|
||||||
|
background: linear-gradient(135deg, rgba(40, 121, 255, 0.1), rgba(40, 121, 255, 0.05));
|
||||||
|
border: 1px solid #2879ff;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: linear-gradient(135deg, rgba(40, 121, 255, 0.15), rgba(40, 121, 255, 0.1));
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 15px rgba(40, 121, 255, 0.25);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-info-item {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
font-size: 13px;
|
||||||
|
align-items: center;
|
||||||
|
animation: fadeInUp 0.5s ease-out 0.15s both;
|
||||||
|
|
||||||
|
.info-label {
|
||||||
|
color: #666;
|
||||||
|
flex: 0 0 100px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-data {
|
||||||
|
flex: 1 0 1px;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator-line {
|
||||||
|
height: 1px;
|
||||||
|
background: linear-gradient(90deg, transparent, #e8e8e8, transparent);
|
||||||
|
margin: 18px 0;
|
||||||
|
opacity: 0.8;
|
||||||
|
animation: fadeIn 0.5s ease-out 0.25s both;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载更多样式
|
||||||
|
.load-more {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20px;
|
||||||
|
color: #666;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
text {
|
||||||
|
color: #2879ff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加动画关键帧
|
||||||
|
@keyframes fadeInUp {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(20px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInLeft {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-20px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInRight {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(20px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暂无数据样式
|
||||||
|
.empty-course-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 80px 20px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.empty-icon {
|
||||||
|
margin-bottom: 25px;
|
||||||
|
background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
|
||||||
|
width: 90px;
|
||||||
|
height: 90px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
|
||||||
|
border: 2px solid rgba(255, 255, 255, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-text {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #475569;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -35,6 +35,10 @@
|
|||||||
<view class="info-label">开课地点:</view>
|
<view class="info-label">开课地点:</view>
|
||||||
<view class="info-data">{{ xkkc.kcdd }}</view>
|
<view class="info-data">{{ xkkc.kcdd }}</view>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="course-info-item">
|
||||||
|
<view class="info-label">授课教师:</view>
|
||||||
|
<view class="info-data">{{ xkkc.jsName || '暂无' }}</view>
|
||||||
|
</view>
|
||||||
<view class="course-info-item">
|
<view class="course-info-item">
|
||||||
<view class="info-label">开课年级:</view>
|
<view class="info-label">开课年级:</view>
|
||||||
<view class="info-data">{{ xkkc.njname || '暂无' }}</view>
|
<view class="info-data">{{ xkkc.njname || '暂无' }}</view>
|
||||||
@ -105,13 +109,14 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { jsdXkListApi } from "@/api/base/server";
|
import { jsdXkListApi } from "@/api/base/server";
|
||||||
|
import { getXcCourseListApi } from "@/api/base/xkPbApi";
|
||||||
import { useDataStore } from "@/store/modules/data";
|
import { useDataStore } from "@/store/modules/data";
|
||||||
import { useUserStore } from "@/store/modules/user";
|
import { useUserStore } from "@/store/modules/user";
|
||||||
import { onBeforeUnmount, onMounted, ref } from "vue";
|
import { onBeforeUnmount, onMounted, ref } from "vue";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
const { getJs } = useUserStore();
|
const { getJs } = useUserStore();
|
||||||
const { getData, setData } = useDataStore();
|
const dataStore = useDataStore();
|
||||||
|
|
||||||
const wdNameList = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"];
|
const wdNameList = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"];
|
||||||
|
|
||||||
@ -130,7 +135,39 @@ onMounted(async () => {
|
|||||||
uni.showLoading({
|
uni.showLoading({
|
||||||
title: "加载中...",
|
title: "加载中...",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 检查是否从排班页面跳转过来
|
||||||
|
const pbData = dataStore.getData;
|
||||||
|
|
||||||
|
if (pbData && pbData.id) {
|
||||||
|
// 检查是否是课程数据(包含kcmc字段)
|
||||||
|
if (pbData.kcmc) {
|
||||||
|
// 这是课程数据,需要重建排班数据
|
||||||
|
const reconstructedPbData = {
|
||||||
|
id: pbData.pbId, // 使用pbId作为排班ID
|
||||||
|
status: 'A',
|
||||||
|
njIds: pbData.njIds || '',
|
||||||
|
bjIds: pbData.bjIds || '',
|
||||||
|
xcbt: pbData.xcbt,
|
||||||
|
xclx: pbData.xclx,
|
||||||
|
xqId: pbData.xqId,
|
||||||
|
xqmc: pbData.xqmc,
|
||||||
|
xcstime: pbData.xcstime,
|
||||||
|
xcjstime: pbData.xcjstime,
|
||||||
|
pk: pbData.pk
|
||||||
|
};
|
||||||
|
dataStore.setGlobal(reconstructedPbData);
|
||||||
|
await loadXcCourseList(reconstructedPbData);
|
||||||
|
} else {
|
||||||
|
// 这是排班数据,直接使用
|
||||||
|
dataStore.setGlobal(pbData);
|
||||||
|
await loadXcCourseList(pbData);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 正常加载课程列表
|
||||||
await loadCourseList();
|
await loadCourseList();
|
||||||
|
}
|
||||||
|
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -151,6 +188,89 @@ const loadCourseList = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 加载巡查课程列表
|
||||||
|
const loadXcCourseList = async (pbData: any) => {
|
||||||
|
try {
|
||||||
|
const res = await getXcCourseListApi({
|
||||||
|
jsId: getJs.id,
|
||||||
|
pbId: pbData.id,
|
||||||
|
xclx: pbData.xclx
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res && res.resultCode == 1) {
|
||||||
|
const list = res.result || [];
|
||||||
|
|
||||||
|
if (pbData.xclx === 'A') {
|
||||||
|
// 类型A:直接使用返回的课程数据
|
||||||
|
xkkcList.value = list.map((item: any) => ({
|
||||||
|
id: item.id,
|
||||||
|
kcmc: item.kcmc,
|
||||||
|
skzqmc: item.skzqmc || '每周',
|
||||||
|
skkstime: item.skkstime,
|
||||||
|
skjstime: item.skjstime,
|
||||||
|
kcdd: item.kcdd || '暂无',
|
||||||
|
njname: item.njname || '暂无',
|
||||||
|
hasNum: item.hasNum || 0,
|
||||||
|
maxNum: item.maxNum || 0,
|
||||||
|
skzqlx: item.skzqlx,
|
||||||
|
skzq: item.skzq,
|
||||||
|
jsName: item.jsName
|
||||||
|
}));
|
||||||
|
} else if (pbData.xclx === 'B') {
|
||||||
|
// 类型B:直接使用返回的课程数据
|
||||||
|
xkkcList.value = list.map((item: any) => ({
|
||||||
|
id: item.id,
|
||||||
|
kcmc: item.kcmc,
|
||||||
|
skzqmc: item.skzqmc || '每周',
|
||||||
|
skkstime: item.skkstime,
|
||||||
|
skjstime: item.skjstime,
|
||||||
|
kcdd: item.kcdd || '暂无',
|
||||||
|
njname: item.njname || '暂无',
|
||||||
|
hasNum: item.hasNum || 0,
|
||||||
|
maxNum: item.maxNum || 0,
|
||||||
|
skzqlx: item.skzqlx,
|
||||||
|
skzq: item.skzq,
|
||||||
|
jsName: item.jsName
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理课程周期显示
|
||||||
|
for (let i = 0; i < xkkcList.value.length; i++) {
|
||||||
|
let xkkc = xkkcList.value[i];
|
||||||
|
// 判断周期
|
||||||
|
switch (xkkc.skzqlx) {
|
||||||
|
case '每天':
|
||||||
|
xkkc.skzqmc = "每天";
|
||||||
|
break;
|
||||||
|
case '每周':
|
||||||
|
const daysOfWeek = xkkc.skzq.split(',').map(Number);
|
||||||
|
// 从wdNameList读取daysOfWeek对应的周几
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
xkkcList.value = [];
|
||||||
|
uni.showToast({
|
||||||
|
title: (res as any).resultMessage || '获取巡查课程失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载巡查课程失败:', error);
|
||||||
|
xkkcList.value = [];
|
||||||
|
uni.showToast({
|
||||||
|
title: '加载巡查课程失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 显示选课选择器
|
// 显示选课选择器
|
||||||
function clickShowXkSelector() {
|
function clickShowXkSelector() {
|
||||||
if (xkList.value.length > 1) {
|
if (xkList.value.length > 1) {
|
||||||
@ -191,7 +311,29 @@ function switchXk(xk: any) {
|
|||||||
|
|
||||||
// 跳转到巡查
|
// 跳转到巡查
|
||||||
const goXc = (xkkc: any) => {
|
const goXc = (xkkc: any) => {
|
||||||
setData(xkkc);
|
// 直接从global获取排班数据
|
||||||
|
const pbData = dataStore.getGlobal;
|
||||||
|
|
||||||
|
// 检查排班数据是否有效
|
||||||
|
if (!pbData || !pbData.xcbt || !pbData.xcbt.includes('排班计划')) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '数据异常,请重新选择排班',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 合并排班数据和课程数据
|
||||||
|
const combinedData = {
|
||||||
|
...xkkc,
|
||||||
|
id: xkkc.id, // 课程记录ID
|
||||||
|
pbId: pbData.id, // 排班ID - 确保使用正确的排班ID
|
||||||
|
xclx: pbData.xclx,
|
||||||
|
xcbt: pbData.xcbt,
|
||||||
|
xqmc: pbData.xqmc
|
||||||
|
};
|
||||||
|
|
||||||
|
dataStore.setData(combinedData);
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pages/view/routine/kefuxuncha/xcXkkcDetail`,
|
url: `/pages/view/routine/kefuxuncha/xcXkkcDetail`,
|
||||||
});
|
});
|
||||||
@ -199,7 +341,29 @@ const goXc = (xkkc: any) => {
|
|||||||
|
|
||||||
// 跳转到巡查记录
|
// 跳转到巡查记录
|
||||||
const goRecord = (xkkc: any) => {
|
const goRecord = (xkkc: any) => {
|
||||||
setData(xkkc);
|
// 直接从global获取排班数据
|
||||||
|
const pbData = dataStore.getGlobal;
|
||||||
|
|
||||||
|
// 检查排班数据是否有效
|
||||||
|
if (!pbData || !pbData.xcbt || !pbData.xcbt.includes('排班计划')) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '数据异常,请重新选择排班',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 合并排班数据和课程数据
|
||||||
|
const combinedData = {
|
||||||
|
...xkkc,
|
||||||
|
id: xkkc.id, // 课程记录ID
|
||||||
|
pbId: pbData.id, // 排班ID - 确保使用正确的排班ID
|
||||||
|
xclx: pbData.xclx,
|
||||||
|
xcbt: pbData.xcbt,
|
||||||
|
xqmc: pbData.xqmc
|
||||||
|
};
|
||||||
|
|
||||||
|
dataStore.setData(combinedData);
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pages/view/routine/kefuxuncha/xcRecord`,
|
url: `/pages/view/routine/kefuxuncha/xcRecord`,
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user