diff --git a/src/api/base/jcApi.ts b/src/api/base/jcApi.ts
new file mode 100644
index 0000000..6a9e339
--- /dev/null
+++ b/src/api/base/jcApi.ts
@@ -0,0 +1,276 @@
+import { get, post } from '@/utils/request'
+
+/**
+ * 获取就餐标准列表
+ */
+export const getJcBzListApi = async (params: any) => {
+ return await get('/api/jcBz/getJcBzList', params)
+}
+
+/**
+ * 获取就餐清单列表
+ */
+export const getJcQdListApi = async (params: any) => {
+ return await get('/api/jcQd/findPage', params)
+}
+
+/**
+ * 获取就餐点名分页
+ */
+export const getJcDmPageApi = async (params: any) => {
+ return await get('/api/jcDm/findPage', params)
+}
+
+/**
+ * 根据学生ID查询就餐清单状态
+ */
+export const getStudentJcStatusApi = async (xsId: string) => {
+ return await get('/api/jcQd/findPage', {
+ xsId,
+ pageNum: 1,
+ pageSize: 100
+ })
+}
+
+/**
+ * 提交就餐点名
+ */
+export const submitJcDmApi = async (data: any) => {
+ return await post('/api/jcDm/save', data)
+}
+
+/**
+ * 提交陪餐教师信息
+ */
+export const submitJcPtApi = async (data: any) => {
+ return await post('/api/jcPt/save', data)
+}
+
+/**
+ * 获取就餐点名记录
+ */
+export const getJcDmListApi = async (params: any) => {
+ return await get('/api/jcDm/findPage', params)
+}
+
+/**
+ * 获取陪餐教师记录
+ */
+export const getJcPtListApi = async (params: any) => {
+ return await get('/api/jcPt/findPage', params)
+}
+
+/**
+ * 【教师端专用】根据班级ID获取学生点名数据
+ * 返回两组学生数据:已缴费和未缴费/未报名
+ */
+export const getClassStudentDmDataApi = async (bjId: string, njId: string) => {
+ try {
+ const response = await get('/mobile/js/jc/getClassStudentDmData', { bjId, njId })
+ return response
+ } catch (error) {
+ console.error('获取班级学生点名数据失败:', error)
+ throw error
+ }
+}
+
+/**
+ * 【教师端专用】提交就餐点名数据
+ * 包含:点名教师ID、点名时间、学生列表、陪餐教师列表等
+ */
+export const submitJcDmDataApi = async (dmData: any) => {
+ try {
+ const response = await post('/mobile/js/jc/tjDmData', dmData)
+ return response
+ } catch (error) {
+ console.error('提交就餐点名数据失败:', error)
+ throw error
+ }
+}
+
+/**
+ * 【教师端专用】获取就餐点名详情
+ */
+export const getJcDmDetailApi = async (dmId: string) => {
+ try {
+ const response = await get('/mobile/js/jc/getDmDetail', { dmId })
+ return response
+ } catch (error) {
+ console.error('获取就餐点名详情失败:', error)
+ throw error
+ }
+}
+
+/**
+ * 【优化版本】根据班级ID获取学生就餐状态 - 使用批量查询避免循环
+ */
+export const getClassStudentJcStatusBatchApi = async (bjId: string, njId: string) => {
+ try {
+ // 1. 批量查询班级学生列表
+ const studentsRes = await get('/api/xs/findPage', {
+ bjId,
+ njId,
+ pageNum: 1,
+ pageSize: 1000
+ })
+
+ if (!studentsRes.result || !studentsRes.result.rows || studentsRes.result.rows.length === 0) {
+ return []
+ }
+
+ const students = studentsRes.result.rows
+ const studentIds = students.map((s: any) => s.id)
+
+ // 2. 批量查询所有学生的就餐清单状态
+ const jcQdRes = await get('/api/jcQd/findBatchByXsIds', {
+ xsIds: studentIds.join(','),
+ pageNum: 1,
+ pageSize: 1000
+ })
+
+ // 3. 将就餐清单转换为Map,便于快速查找
+ const jcQdMap = new Map()
+ if (jcQdRes.result && jcQdRes.result.rows) {
+ jcQdRes.result.rows.forEach((qd: any) => {
+ jcQdMap.set(qd.xsId, qd)
+ })
+ }
+
+ // 4. 构建学生状态列表
+ const studentStatusList = students.map((student: any) => {
+ const jcQdInfo = jcQdMap.get(student.id)
+ const hasJcQd = !!jcQdInfo
+ const jfZt = jcQdInfo?.jfZt || null
+
+ // 根据缴费状态和就餐清单情况设置默认状态
+ let defaultStatus = 'A' // 默认正常状态
+ if (!hasJcQd) {
+ defaultStatus = 'E' // 未报名
+ } else if (jfZt !== 'B') {
+ defaultStatus = 'D' // 未缴费
+ }
+
+ return {
+ ...student,
+ hasJcQd,
+ jcQdInfo,
+ jfZt,
+ jcZt: defaultStatus,
+ studentType: hasJcQd && jfZt === 'B' ? 'paid' : 'unpaid'
+ }
+ })
+
+ return studentStatusList
+ } catch (error) {
+ console.error('批量查询学生就餐状态失败:', error)
+ throw error
+ }
+}
+
+/**
+ * 【原版本】根据班级ID获取学生就餐状态 - 保留作为备用
+ * @deprecated 建议使用 getClassStudentDmDataApi 替代
+ */
+export const getClassStudentJcStatusApi = async (bjId: string, njId: string) => {
+ // 先获取班级学生列表
+ const studentsRes = await get('/api/xs/findPage', {
+ bjId,
+ njId,
+ pageNum: 1,
+ pageSize: 1000
+ })
+
+ if (!studentsRes.result || !studentsRes.result.rows) {
+ return []
+ }
+
+ const students = studentsRes.result.rows
+ const studentStatusList = []
+
+ // 为每个学生查询就餐清单状态
+ for (const student of students) {
+ try {
+ const jcQdRes = await get('/api/jcQd/findPage', {
+ xsId: student.id,
+ pageNum: 1,
+ pageSize: 10
+ })
+
+ let hasJcQd = false
+ let jcQdInfo = null
+ let jfZt = null // 缴费状态
+
+ if (jcQdRes.result && jcQdRes.result.rows && jcQdRes.result.rows.length > 0) {
+ jcQdInfo = jcQdRes.result.rows[0]
+ hasJcQd = true
+ jfZt = jcQdInfo.jfZt || null
+ }
+
+ // 根据缴费状态和就餐清单情况设置默认状态
+ let defaultStatus = 'A' // 默认正常状态
+ if (!hasJcQd) {
+ defaultStatus = 'E' // 未报名
+ } else if (jfZt !== 'B') {
+ defaultStatus = 'D' // 未缴费
+ }
+
+ studentStatusList.push({
+ ...student,
+ hasJcQd,
+ jcQdInfo,
+ jfZt,
+ jcZt: defaultStatus, // 默认就餐状态
+ // 添加学生类型标识,便于前端分类显示
+ studentType: hasJcQd && jfZt === 'B' ? 'paid' : 'unpaid'
+ })
+ } catch (error) {
+ console.error(`查询学生 ${student.xm} 就餐状态失败:`, error)
+ studentStatusList.push({
+ ...student,
+ hasJcQd: false,
+ jcQdInfo: null,
+ jfZt: null,
+ jcZt: 'E', // 查询失败时默认为未报名
+ studentType: 'unpaid'
+ })
+ }
+ }
+
+ return studentStatusList
+}
+
+/**
+ * 批量提交学生就餐点名记录
+ */
+export const submitBatchJcDmApi = async (dmList: any[]) => {
+ const promises = dmList.map(dm => submitJcDmApi(dm))
+ return await Promise.all(promises)
+}
+
+/**
+ * 批量提交学生就餐点名记录 - 优化版本
+ */
+export const submitBatchJcDmOptimizedApi = async (dmList: any[]) => {
+ return await post('/api/jcDm/saveBatch', dmList)
+}
+
+/**
+ * 根据班级ID获取学生就餐状态统计信息
+ */
+export const getClassStudentJcStatusStatsApi = async (bjId: string, njId: string) => {
+ return await get('/api/jcQd/getClassStats', { bjId, njId })
+}
+
+/**
+ * 根据点名批次ID获取点名记录
+ */
+export const getJcDmByBatchIdApi = async (dmPcId: string) => {
+ return await get('/api/jcDm/findByBatchId', { dmPcId })
+}
+
+/**
+ * 根据班级和日期获取点名记录
+ */
+export const getJcDmByClassAndDateApi = async (bjId: string, njId: string, dmDate: string) => {
+ return await get('/api/jcDm/findByClassAndDate', { bjId, njId, dmDate })
+}
diff --git a/src/pages.json b/src/pages.json
index 13e0a0c..dafddf7 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -565,6 +565,18 @@
"navigationBarTextStyle": "black",
"backgroundColor": "#f4f5f7"
}
+ },
+ {
+ "path": "pages/view/routine/jc/index",
+ "style": {
+ "navigationBarTitleText": "就餐点名"
+ }
+ },
+ {
+ "path": "pages/view/routine/jc/detail",
+ "style": {
+ "navigationBarTitleText": "就餐点名详情"
+ }
}
],
"globalStyle": {
diff --git a/src/pages/base/service/index.vue b/src/pages/base/service/index.vue
index 0b1f6aa..ed1c4d1 100644
--- a/src/pages/base/service/index.vue
+++ b/src/pages/base/service/index.vue
@@ -64,9 +64,9 @@
-
+
@@ -113,8 +113,8 @@ const isLoading = ref(true);
// 教师工作信息
const jsWork = ref({
- jf: 88,
- ks: 40
+ jf: 88,
+ ks: 40,
});
interface GridItem {
@@ -122,7 +122,7 @@ interface GridItem {
icon: string; // 图标文件名 (不含扩展名)
text: string;
show: boolean; // 是否显示
- permissionKey?: string; // 权限键
+ permissionKey: string; // 权限键
path?: string; // 页面路径
}
@@ -142,12 +142,15 @@ const handleLogout = () => {
if (res.confirm) {
try {
// 从userdata中获取用户ID
- const userDataStr = uni.getStorageSync('app-user');
+ const userDataStr = uni.getStorageSync("app-user");
let userData = null;
if (userDataStr) {
try {
- userData = typeof userDataStr === 'string' ? JSON.parse(userDataStr) : userDataStr;
+ userData =
+ typeof userDataStr === "string"
+ ? JSON.parse(userDataStr)
+ : userDataStr;
} catch (e) {
// 静默处理错误
}
@@ -260,6 +263,14 @@ const sections = reactive([
permissionKey: "routine-qdfb", // 签到发布权限编码
path: "/pages/view/routine/qd/index",
},
+ {
+ id: "r11",
+ icon: "draftfill",
+ text: "就餐点名",
+ show: true,
+ permissionKey: "routine-jcdm", // 就餐点名权限编码
+ path: "/pages/view/routine/jc/index",
+ },
],
},
{
@@ -381,7 +392,7 @@ onMounted(async () => {
isLoading.value = false;
// 强制清除权限缓存,确保数据一致性
- const { clearPermissionCachePublic } = await import('@/utils/permission');
+ const { clearPermissionCachePublic } = await import("@/utils/permission");
clearPermissionCachePublic();
});
@@ -395,20 +406,24 @@ async function initPositionInfo() {
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(", ");
+ }
}
// 检查区域权限
@@ -475,8 +490,12 @@ const hasPermissionDirect = (permissionKey: string) => {
}
@keyframes spin {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(360deg); }
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(360deg);
+ }
}
// 顶部 Header
diff --git a/src/pages/components/JsPicker/index.vue b/src/pages/components/JsPicker/index.vue
index 033c829..3c6732d 100644
--- a/src/pages/components/JsPicker/index.vue
+++ b/src/pages/components/JsPicker/index.vue
@@ -109,6 +109,7 @@ const rebuildJsList = () => {
jsList.value.push({
label: item.jsxm,
value: item.id,
+ headPic: item.headPic
});
}
});
diff --git a/src/pages/components/NjBjPicker/index.vue b/src/pages/components/NjBjPicker/index.vue
index 53bd8aa..ba6ed8e 100644
--- a/src/pages/components/NjBjPicker/index.vue
+++ b/src/pages/components/NjBjPicker/index.vue
@@ -13,9 +13,9 @@ import { findAllNjBjTreeApi } from "@/api/base/server";
// 接收外部传入属性并设置默认值
const props = withDefaults(defineProps<{
- defaultValue: any,
- customStyle: any,
- iconArrow: string
+ defaultValue?: any,
+ customStyle?: any,
+ iconArrow?: string
}>(), {
defaultValue: [],
customStyle: {},
diff --git a/src/pages/view/routine/jc/components/dm.vue b/src/pages/view/routine/jc/components/dm.vue
new file mode 100644
index 0000000..856f56f
--- /dev/null
+++ b/src/pages/view/routine/jc/components/dm.vue
@@ -0,0 +1,1017 @@
+
+
+
+
+ 选择班级
+
+
+
+
+ ℹ️
+ 请先选择班级
+
+
+
+
+
+ 陪餐教师
+
+
+
+
+
+
+
+ 教师陪餐状态
+ 刷新
+
+
+
+
+
+
+
+
+
+
+
+ {{ teacher.label }}
+
+
+
+
+ {{ hqJsZtWz(teacher.pcZt) }}
+ ▼
+
+
+
+
+
+
+
+
+
+
+
+
+ 学生状态列表
+ 刷新
+
+
+
+
+
+ {{ xsLb.length }}
+ 总人数
+
+
+ {{ hqZtSl('D') }}
+ 未缴费
+
+
+ {{ hqZtSl('E') }}
+ 未报名
+
+
+ {{ hqZtSl('A') }}
+ 正常
+
+
+ {{ hqZtSl('B') }}
+ 请假
+
+
+ {{ hqZtSl('C') }}
+ 缺勤
+
+
+
+
+
+
+
+ 已缴费学生 ({{ yjfXs.length }}人)
+
+
+
+
+
+
+
+
+ {{ student.xm }}
+
+
+
+
+ {{ hqZtWz(student.jcZt) }}
+ ▼
+
+
+
+
+
+
+
+
+
+
+ 未缴费/未报名学生 ({{ wjfXs.length }}人)
+
+
+
+
+
+
+
+
+ {{ student.xm }}
+
+
+
+
+ {{ hqZtWz(student.jcZt) }}
+
+
+
+
+
+
+
+
+
+ 暂无学生数据
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 加载中...
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/view/routine/jc/components/dmList.vue b/src/pages/view/routine/jc/components/dmList.vue
new file mode 100644
index 0000000..b1cd31f
--- /dev/null
+++ b/src/pages/view/routine/jc/components/dmList.vue
@@ -0,0 +1,491 @@
+
+
+
+
+
+
+ 班级:
+
+
+
+
+
+
+
+ 时间范围:
+
+ {{ getTimeRangeText() }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ data.njmc }} {{ data.bjmc }}
+
+
+
+
+ 学生
+ {{ data.xsCount }}人
+
+
+ 陪餐教师
+ {{ data.jsCount }}人
+
+
+
+
+
+
+
+
+
+
+
+ 📋
+ 暂无点名记录
+ 请选择班级和时间范围进行搜索
+
+
+
+
+ 🔍
+ 请选择班级和时间范围开始搜索
+
+
+
+
+
+
+
diff --git a/src/pages/view/routine/jc/detail.vue b/src/pages/view/routine/jc/detail.vue
new file mode 100644
index 0000000..85f808b
--- /dev/null
+++ b/src/pages/view/routine/jc/detail.vue
@@ -0,0 +1,508 @@
+
+
+
+
+ ⏳
+ 加载中...
+
+
+
+
+
+
+ 点名基本信息
+
+
+ 班级:
+ {{ dmDetail.bjmc }}
+
+
+ 年级:
+ {{ dmDetail.njmc }}
+
+
+ 点名时间:
+ {{ formatDateTime(dmDetail.dmTime) }}
+
+
+
+
+
+
+
+ 陪餐教师 ({{ dmDetail.jsList.length }}人)
+
+
+
+
+
+
+
+
+
+
+
+ {{ teacher.jsXm }}
+
+
+
+ {{ getTeacherStatusText(teacher.pcZt) }}
+
+
+
+
+
+
+
+
+
+
+
+
+ 学生状态列表 ({{ dmDetail.xsList.length }}人)
+
+
+
+
+
+ {{ dmDetail.xsList.length }}
+ 总人数
+
+
+ {{ getStatusCount('A') }}
+ 正常
+
+
+ {{ getStatusCount('B') }}
+ 请假
+
+
+ {{ getStatusCount('C') }}
+ 缺勤
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ student.xsXm }}
+
+
+
+ {{ getStatusText(student.jcZt) }}
+
+
+
+
+
+
+
+
+
+
+
+ 暂无学生数据
+
+
+
+
+
+ ❌
+ {{ error }}
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/view/routine/jc/index.vue b/src/pages/view/routine/jc/index.vue
new file mode 100644
index 0000000..434c47e
--- /dev/null
+++ b/src/pages/view/routine/jc/index.vue
@@ -0,0 +1,113 @@
+
+
+
+
+
+ 开始点名
+
+
+ 点名记录
+
+
+
+
+
+
+
+
+
+
+
+
+ 加载中...
+
+
+
+
+
+
+
+