feat: 老师端
This commit is contained in:
parent
d1765d936c
commit
da364bc97d
4
.env
4
.env
@ -1,5 +1,5 @@
|
|||||||
#VITE_HOST = http://192.168.0.114:9053
|
#VITE_HOST = http://192.168.0.114:9053
|
||||||
#VITE_HOST = http://43.136.52.196:9053
|
VITE_HOST = http://43.136.52.196:9053
|
||||||
VITE_HOST= https://ai.xuexiaole.com
|
#VITE_HOST= https://ai.xuexiaole.com
|
||||||
VITE_OSS_HOST = https://xxl-1313840333.cos.ap-guangzhou.myqcloud.com
|
VITE_OSS_HOST = https://xxl-1313840333.cos.ap-guangzhou.myqcloud.com
|
||||||
VITE_WS_URL = wss://test.qiaoying.vip/wss/websocket
|
VITE_WS_URL = wss://test.qiaoying.vip/wss/websocket
|
||||||
@ -55,6 +55,8 @@ export const getPaperReleaseRecordList = (params: {
|
|||||||
schoolId: string;
|
schoolId: string;
|
||||||
current: number;
|
current: number;
|
||||||
size: number;
|
size: number;
|
||||||
|
classId?: string;
|
||||||
|
subjectId?: string;
|
||||||
}) => {
|
}) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/school/paperReleaseRecord/list',
|
url: '/school/paperReleaseRecord/list',
|
||||||
@ -62,3 +64,81 @@ export const getPaperReleaseRecordList = (params: {
|
|||||||
params,
|
params,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 班级列表(按教师)- 接口 org/class/listByTeacher,可选年级筛选
|
||||||
|
export const getClassListByTeacher = (params?: { gradeId?: string; gradeName?: string }) => {
|
||||||
|
return request({
|
||||||
|
url: '/org/class/listByTeacher',
|
||||||
|
method: 'GET',
|
||||||
|
params: params || {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 根据班级ID获取学科列表
|
||||||
|
export const getSubjectListByClassId = (classId: string) => {
|
||||||
|
return request({
|
||||||
|
url: '/org/class/listSubjectInfoByClassId',
|
||||||
|
method: 'GET',
|
||||||
|
params: { classId },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// ---------- 班级作业完成情况报表 school/report/classHomework/list ----------
|
||||||
|
export interface ClassHomeworkSubjectStat {
|
||||||
|
subjectId: number;
|
||||||
|
subjectName: string;
|
||||||
|
homeworkCount: number;
|
||||||
|
completedCount: number;
|
||||||
|
uncompletedCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClassHomeworkStudentItem {
|
||||||
|
userId: number;
|
||||||
|
userName: string;
|
||||||
|
totalCount: number;
|
||||||
|
completedCount: number;
|
||||||
|
uncompletedCount: number;
|
||||||
|
subjectStats: ClassHomeworkSubjectStat[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClassHomeworkReportData {
|
||||||
|
classId: number;
|
||||||
|
className: string;
|
||||||
|
subjects: { subjectId: number; subjectName: string }[];
|
||||||
|
studentList: ClassHomeworkStudentItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 班级作业报表:GET 请求,参数以 form 表单风格放在 query(subjectIds 为多个同名参数) */
|
||||||
|
export const getClassHomeworkReport = (params: {
|
||||||
|
classId: string | number;
|
||||||
|
/** 学科ID列表,可多选,不传或空则查全部学科 */
|
||||||
|
subjectIds?: number[];
|
||||||
|
startTime?: string;
|
||||||
|
endTime?: string;
|
||||||
|
}) => {
|
||||||
|
// form 表单编码:空格用 +,特殊字符用 encodeURIComponent 后把 %20 替换为 +
|
||||||
|
const formEncode = (v: string) => encodeURIComponent(v).replace(/%20/g, '+');
|
||||||
|
|
||||||
|
const query: string[] = [];
|
||||||
|
query.push('classId=' + formEncode(String(params.classId)));
|
||||||
|
if (params.subjectIds && params.subjectIds.length > 0) {
|
||||||
|
params.subjectIds.forEach((id) => {
|
||||||
|
query.push('subjectIds=' + formEncode(String(id)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (params.startTime != null && params.startTime !== '' && String(params.startTime).trim() !== '') {
|
||||||
|
// 后端 Date 类型需要带时分秒,picker 只返回 yyyy-MM-dd,补 00:00:00
|
||||||
|
const st = String(params.startTime).trim();
|
||||||
|
query.push('startTime=' + formEncode(st.includes(' ') ? st : st + ' 00:00:00'));
|
||||||
|
}
|
||||||
|
if (params.endTime != null && params.endTime !== '' && String(params.endTime).trim() !== '') {
|
||||||
|
// 结束时间补 23:59:59,保证包含当天
|
||||||
|
const et = String(params.endTime).trim();
|
||||||
|
query.push('endTime=' + formEncode(et.includes(' ') ? et : et + ' 23:59:59'));
|
||||||
|
}
|
||||||
|
const queryString = query.join('&');
|
||||||
|
return request({
|
||||||
|
url: '/school/report/classHomework/list?' + queryString,
|
||||||
|
method: 'GET',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="select-wrap">
|
<view class="select-wrap">
|
||||||
<view class="select-btn" @click="showPicker = true">
|
<view class="select-btn" @click="openPopup">
|
||||||
<text class="select-text">{{ currentLabel }}</text>
|
<text class="select-text">{{ currentLabel }}</text>
|
||||||
<image class="select-arrow" :src="`${OSS_URL}/icon/icon_arrow_down.svg`" mode="aspectFit" />
|
<image class="select-arrow" :src="`${OSS_URL}/icon/icon_arrow_down.svg`" mode="aspectFit" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<uni-popup ref="popupRef" type="bottom" @change="onPopupChange">
|
<uni-popup ref="popupRef" type="bottom" @change="onPopupChange">
|
||||||
<view class="picker-content">
|
<view
|
||||||
|
class="picker-content"
|
||||||
|
:style="{ paddingRight: capsulePaddingRightRpx + 'rpx' }"
|
||||||
|
>
|
||||||
<view class="picker-header">
|
<view class="picker-header">
|
||||||
<text class="cancel" @click="handleCancel">取消</text>
|
<text class="cancel" @click="handleCancel">取消</text>
|
||||||
<text class="title">请选择</text>
|
<text class="title">请选择</text>
|
||||||
@ -33,10 +36,39 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, watch } from 'vue';
|
import { ref, computed, watch, onMounted } from 'vue';
|
||||||
|
|
||||||
const OSS_URL = 'https://xxl-1313840333.cos.ap-guangzhou.myqcloud.com';
|
const OSS_URL = 'https://xxl-1313840333.cos.ap-guangzhou.myqcloud.com';
|
||||||
|
|
||||||
|
// 右上角胶囊预留(避免弹层被遮挡)
|
||||||
|
const capsulePaddingRightRpx = ref(0);
|
||||||
|
|
||||||
|
const getCapsulePadding = () => {
|
||||||
|
try {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
const menuButton = uni.getMenuButtonBoundingClientRect();
|
||||||
|
const systemInfo = uni.getSystemInfoSync();
|
||||||
|
if (menuButton && systemInfo?.windowWidth) {
|
||||||
|
const pxToRpx = 750 / systemInfo.windowWidth;
|
||||||
|
// 右侧:从胶囊左缘到屏幕右缘 + 间距,避免「确定」等被胶囊遮住
|
||||||
|
const rightPx = systemInfo.windowWidth - menuButton.left;
|
||||||
|
capsulePaddingRightRpx.value = Math.ceil(rightPx * pxToRpx) + 24;
|
||||||
|
} else {
|
||||||
|
capsulePaddingRightRpx.value = 140;
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
|
capsulePaddingRightRpx.value = 0;
|
||||||
|
// #endif
|
||||||
|
} catch {
|
||||||
|
capsulePaddingRightRpx.value = 140;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getCapsulePadding();
|
||||||
|
});
|
||||||
|
|
||||||
interface SelectOption {
|
interface SelectOption {
|
||||||
label: string;
|
label: string;
|
||||||
value: string | number;
|
value: string | number;
|
||||||
@ -76,6 +108,10 @@ watch(
|
|||||||
{ immediate: true },
|
{ immediate: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const openPopup = () => {
|
||||||
|
showPicker.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
watch(showPicker, (val) => {
|
watch(showPicker, (val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
popupRef.value?.open();
|
popupRef.value?.open();
|
||||||
|
|||||||
@ -115,6 +115,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "homework/filter",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"navigationBarTitleText": "筛选条件",
|
||||||
|
"disableScroll": true,
|
||||||
|
"pageOrientation": "landscape",
|
||||||
|
"allowsBounceVertical": "NO",
|
||||||
|
"mp-weixin": {
|
||||||
|
"pageOrientation": "landscape"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "homework/index",
|
"path": "homework/index",
|
||||||
"style": {
|
"style": {
|
||||||
|
|||||||
@ -210,6 +210,13 @@
|
|||||||
<rich-text :nodes="filterTitle(typeof data.aiAnswer === 'string' ? data.aiAnswer : String(data.aiAnswer))" />
|
<rich-text :nodes="filterTitle(typeof data.aiAnswer === 'string' ? data.aiAnswer : String(data.aiAnswer))" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<!-- AI点评 -->
|
||||||
|
<view v-if="data?.aiAnalyze != null " class="answer-box">
|
||||||
|
<view class="answer-box-title">AI点评</view>
|
||||||
|
<view class="answer-box-main analyze">
|
||||||
|
<rich-text :nodes="filterTitle(typeof data.aiAnalyze === 'string' ? data.aiAnalyze : String(data.aiAnalyze))" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</template>
|
</template>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,9 @@
|
|||||||
<view class="book-box">
|
<view class="book-box">
|
||||||
<view class="book">
|
<view class="book">
|
||||||
<template v-if="paperList.length && paperList[activeIdx]">
|
<template v-if="paperList.length && paperList[activeIdx]">
|
||||||
|
<!-- key 随题目变化,切换题目时强制重新挂载,重新加载题目内容(含公式 SVG 等),避免网络差时图片加载失败不重试 -->
|
||||||
<Question
|
<Question
|
||||||
|
:key="`question-${activeIdx}-${paperList[activeIdx]?.id ?? ''}`"
|
||||||
:data="paperList[activeIdx]"
|
:data="paperList[activeIdx]"
|
||||||
:idx="activeIdx + 1"
|
:idx="activeIdx + 1"
|
||||||
:total="paperList.length"
|
:total="paperList.length"
|
||||||
|
|||||||
475
src/pages/teacher/homework/filter.vue
Normal file
475
src/pages/teacher/homework/filter.vue
Normal file
@ -0,0 +1,475 @@
|
|||||||
|
<template>
|
||||||
|
<view class="filter-page" :style="safeAreaStyle">
|
||||||
|
<!-- 顶部标题 -->
|
||||||
|
<view class="header" :style="topRightPaddingStyle">
|
||||||
|
<qy-BackBar leftText="筛选条件" />
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 筛选区域 -->
|
||||||
|
<scroll-view class="filter-body" scroll-y>
|
||||||
|
<!-- 班级选择 -->
|
||||||
|
<view class="filter-section">
|
||||||
|
<view class="section-title">
|
||||||
|
<text class="section-title-text">选择班级</text>
|
||||||
|
<text class="section-required">*必选</text>
|
||||||
|
</view>
|
||||||
|
<view class="option-grid">
|
||||||
|
<view
|
||||||
|
v-for="cls in classList"
|
||||||
|
:key="cls.id"
|
||||||
|
class="option-item"
|
||||||
|
:class="{ active: selectedClassId === cls.id }"
|
||||||
|
@click="selectedClassId = cls.id"
|
||||||
|
>
|
||||||
|
<text class="option-text">{{ cls.name }}</text>
|
||||||
|
<view v-if="selectedClassId === cls.id" class="option-check">✓</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-if="classList.length === 0" class="empty-hint">
|
||||||
|
<text>{{ classLoading ? '加载中...' : '暂无班级数据' }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 学科选择 -->
|
||||||
|
<view class="filter-section">
|
||||||
|
<view class="section-title">
|
||||||
|
<text class="section-title-text">选择学科</text>
|
||||||
|
<text class="section-hint">可多选,不选默认全部</text>
|
||||||
|
</view>
|
||||||
|
<view v-if="!selectedClassId" class="empty-hint">
|
||||||
|
<text>请先选择班级</text>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="subjectLoading" class="empty-hint">
|
||||||
|
<text>加载学科中...</text>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="subjectList.length === 0" class="empty-hint">
|
||||||
|
<text>该班级暂无学科数据</text>
|
||||||
|
</view>
|
||||||
|
<view v-else class="option-grid">
|
||||||
|
<view
|
||||||
|
v-for="sub in subjectList"
|
||||||
|
:key="sub.value"
|
||||||
|
class="option-item"
|
||||||
|
:class="{ active: selectedSubjectIds.includes(sub.value) }"
|
||||||
|
@click="toggleSubject(sub.value)"
|
||||||
|
>
|
||||||
|
<text class="option-text">{{ sub.label }}</text>
|
||||||
|
<view v-if="selectedSubjectIds.includes(sub.value)" class="option-check">✓</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 时间范围 -->
|
||||||
|
<view class="filter-section">
|
||||||
|
<view class="section-title">
|
||||||
|
<text class="section-title-text">时间范围</text>
|
||||||
|
<text class="section-hint">可选</text>
|
||||||
|
</view>
|
||||||
|
<view class="date-row">
|
||||||
|
<picker mode="date" :value="startTime" @change="onStartChange">
|
||||||
|
<view class="date-picker-box" :class="{ filled: !!startTime }">
|
||||||
|
<text class="date-picker-text">{{ startTime || '开始日期' }}</text>
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
<text class="date-sep">至</text>
|
||||||
|
<picker mode="date" :value="endTime" @change="onEndChange">
|
||||||
|
<view class="date-picker-box" :class="{ filled: !!endTime }">
|
||||||
|
<text class="date-picker-text">{{ endTime || '结束日期' }}</text>
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
<view v-if="startTime || endTime" class="date-clear" @click="clearDate">
|
||||||
|
<text>清除</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<!-- 底部按钮 -->
|
||||||
|
<view class="bottom-bar">
|
||||||
|
<view class="btn-reset" @click="handleReset">
|
||||||
|
<text>重置</text>
|
||||||
|
</view>
|
||||||
|
<view class="btn-confirm" :class="{ disabled: !selectedClassId }" @click="handleConfirm">
|
||||||
|
<text>查询</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, watch, onMounted } from 'vue';
|
||||||
|
import { onShow } from '@dcloudio/uni-app';
|
||||||
|
import { getClassListByTeacher, getSubjectListByClassId } from '@/api/teacher';
|
||||||
|
import { teacher } from '@/store/teacher';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
const teacherStore = teacher();
|
||||||
|
const { schoolId } = storeToRefs(teacherStore);
|
||||||
|
|
||||||
|
// 胶囊预留 + 安全区域
|
||||||
|
const topPaddingRightRpx = ref(0);
|
||||||
|
const safeAreaLeftRpx = ref(0);
|
||||||
|
const topRightPaddingStyle = computed(() =>
|
||||||
|
topPaddingRightRpx.value > 0 ? { paddingRight: topPaddingRightRpx.value + 'rpx' } : {},
|
||||||
|
);
|
||||||
|
const safeAreaStyle = computed(() => {
|
||||||
|
const style: Record<string, string> = {};
|
||||||
|
if (safeAreaLeftRpx.value > 0) {
|
||||||
|
style.paddingLeft = safeAreaLeftRpx.value + 'rpx';
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
});
|
||||||
|
function getCapsulePadding() {
|
||||||
|
try {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
const menuButton = uni.getMenuButtonBoundingClientRect();
|
||||||
|
const systemInfo = uni.getSystemInfoSync();
|
||||||
|
if (menuButton && systemInfo?.windowWidth) {
|
||||||
|
const pxToRpx = 750 / systemInfo.windowWidth;
|
||||||
|
const rightPx = systemInfo.windowWidth - menuButton.left;
|
||||||
|
topPaddingRightRpx.value = Math.ceil(rightPx * pxToRpx) + 24;
|
||||||
|
} else {
|
||||||
|
topPaddingRightRpx.value = 140;
|
||||||
|
}
|
||||||
|
// 计算左侧安全区域
|
||||||
|
if (systemInfo?.safeArea && systemInfo.safeArea.left > 0) {
|
||||||
|
const pxToRpx = 750 / (systemInfo.windowWidth || systemInfo.screenWidth);
|
||||||
|
safeAreaLeftRpx.value = Math.ceil(systemInfo.safeArea.left * pxToRpx) + 4;
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
|
topPaddingRightRpx.value = 0;
|
||||||
|
// #endif
|
||||||
|
} catch {
|
||||||
|
topPaddingRightRpx.value = 140;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 班级列表
|
||||||
|
const classList = ref<{ id: string; name: string }[]>([]);
|
||||||
|
const classLoading = ref(false);
|
||||||
|
const selectedClassId = ref('');
|
||||||
|
|
||||||
|
// 学科列表(根据选择的班级动态获取)
|
||||||
|
const subjectList = ref<{ value: number; label: string }[]>([]);
|
||||||
|
const subjectLoading = ref(false);
|
||||||
|
const selectedSubjectIds = ref<number[]>([]);
|
||||||
|
|
||||||
|
// 监听班级选择变化,获取对应学科
|
||||||
|
watch(() => selectedClassId.value, async (newClassId) => {
|
||||||
|
// 清空之前的学科选择
|
||||||
|
selectedSubjectIds.value = [];
|
||||||
|
subjectList.value = [];
|
||||||
|
if (!newClassId) return;
|
||||||
|
subjectLoading.value = true;
|
||||||
|
try {
|
||||||
|
const res = await getSubjectListByClassId(newClassId);
|
||||||
|
const data = res?.data ?? res;
|
||||||
|
// 适配接口返回格式
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
subjectList.value = data.map((item: any) => ({
|
||||||
|
value: item.subjectId ?? item.id ?? item.value,
|
||||||
|
label: item.subjectName ?? item.name ?? item.label ?? '',
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
subjectList.value = [];
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('获取学科列表失败', e);
|
||||||
|
subjectList.value = [];
|
||||||
|
} finally {
|
||||||
|
subjectLoading.value = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 时间 —— 默认当天
|
||||||
|
function getTodayStr() {
|
||||||
|
const d = new Date();
|
||||||
|
const y = d.getFullYear();
|
||||||
|
const m = String(d.getMonth() + 1).padStart(2, '0');
|
||||||
|
const day = String(d.getDate()).padStart(2, '0');
|
||||||
|
return `${y}-${m}-${day}`;
|
||||||
|
}
|
||||||
|
const today = getTodayStr();
|
||||||
|
const startTime = ref(today);
|
||||||
|
const endTime = ref(today);
|
||||||
|
|
||||||
|
function toggleSubject(value: number) {
|
||||||
|
const idx = selectedSubjectIds.value.indexOf(value);
|
||||||
|
if (idx >= 0) {
|
||||||
|
selectedSubjectIds.value = selectedSubjectIds.value.filter((v) => v !== value);
|
||||||
|
} else {
|
||||||
|
selectedSubjectIds.value = [...selectedSubjectIds.value, value];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onStartChange(e: any) {
|
||||||
|
startTime.value = e.detail?.value || '';
|
||||||
|
}
|
||||||
|
function onEndChange(e: any) {
|
||||||
|
endTime.value = e.detail?.value || '';
|
||||||
|
}
|
||||||
|
function clearDate() {
|
||||||
|
startTime.value = '';
|
||||||
|
endTime.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleReset() {
|
||||||
|
selectedClassId.value = '';
|
||||||
|
selectedSubjectIds.value = [];
|
||||||
|
startTime.value = '';
|
||||||
|
endTime.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleConfirm() {
|
||||||
|
if (!selectedClassId.value) {
|
||||||
|
uni.showToast({ title: '请先选择班级', icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 找到班级名称
|
||||||
|
const cls = classList.value.find((c) => c.id === selectedClassId.value);
|
||||||
|
const className = cls?.name || '';
|
||||||
|
// 拼接参数跳转到作业记录页
|
||||||
|
const params: string[] = [];
|
||||||
|
params.push('classId=' + encodeURIComponent(selectedClassId.value));
|
||||||
|
params.push('className=' + encodeURIComponent(className));
|
||||||
|
if (selectedSubjectIds.value.length > 0) {
|
||||||
|
params.push('subjectIds=' + encodeURIComponent(selectedSubjectIds.value.join(',')));
|
||||||
|
}
|
||||||
|
if (startTime.value) {
|
||||||
|
params.push('startTime=' + encodeURIComponent(startTime.value));
|
||||||
|
}
|
||||||
|
if (endTime.value) {
|
||||||
|
params.push('endTime=' + encodeURIComponent(endTime.value));
|
||||||
|
}
|
||||||
|
const url = '/pages/teacher/homework/index?' + params.join('&');
|
||||||
|
uni.navigateTo({ url });
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchClassList = async () => {
|
||||||
|
if (!schoolId.value) return;
|
||||||
|
classLoading.value = true;
|
||||||
|
try {
|
||||||
|
const res = await getClassListByTeacher();
|
||||||
|
const data = res?.data ?? res;
|
||||||
|
classList.value = Array.isArray(data) ? data : data?.list ?? data?.rows ?? [];
|
||||||
|
} catch (e) {
|
||||||
|
console.error('获取班级列表失败', e);
|
||||||
|
classList.value = [];
|
||||||
|
} finally {
|
||||||
|
classLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getCapsulePadding();
|
||||||
|
if (schoolId.value) fetchClassList();
|
||||||
|
});
|
||||||
|
|
||||||
|
onShow(async () => {
|
||||||
|
if (!schoolId.value) {
|
||||||
|
try {
|
||||||
|
await teacherStore.getLoginUser();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('刷新老师信息失败', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (schoolId.value && classList.value.length === 0) {
|
||||||
|
fetchClassList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.filter-page {
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background-image: url('https://xxl-1313840333.cos.ap-guangzhou.myqcloud.com/urm/main_bg.svg');
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
padding-left: 16rpx;
|
||||||
|
padding-right: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding: 4rpx 12rpx 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选区域
|
||||||
|
.filter-body {
|
||||||
|
flex: 1;
|
||||||
|
height: 0;
|
||||||
|
padding: 4rpx 12rpx 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-section {
|
||||||
|
background: linear-gradient(180deg, #fff 0%, #f8f6ff 100%);
|
||||||
|
border-radius: 8rpx;
|
||||||
|
padding: 6rpx 10rpx;
|
||||||
|
margin-bottom: 6rpx;
|
||||||
|
box-shadow: 0 1rpx 6rpx rgba(143, 157, 247, 0.1);
|
||||||
|
border: 1rpx solid rgba(196, 181, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 5rpx;
|
||||||
|
gap: 4rpx;
|
||||||
|
}
|
||||||
|
.section-title-text {
|
||||||
|
font-family: $font-special;
|
||||||
|
font-size: 15rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $font-color;
|
||||||
|
}
|
||||||
|
.section-required {
|
||||||
|
font-size: 11rpx;
|
||||||
|
color: #e05040;
|
||||||
|
}
|
||||||
|
.section-hint {
|
||||||
|
font-size: 11rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选项网格
|
||||||
|
.option-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 5rpx;
|
||||||
|
}
|
||||||
|
.option-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 3rpx;
|
||||||
|
padding: 4rpx 8rpx;
|
||||||
|
background: rgba(196, 181, 255, 0.1);
|
||||||
|
border: 1rpx solid rgba(196, 181, 255, 0.25);
|
||||||
|
border-radius: 6rpx;
|
||||||
|
transition: all 0.2s;
|
||||||
|
|
||||||
|
.option-text {
|
||||||
|
font-family: $font-special;
|
||||||
|
font-size: 13rpx;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
.option-check {
|
||||||
|
width: 16rpx;
|
||||||
|
height: 16rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: linear-gradient(135deg, #8f9df7 0%, #92fc90 100%);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 10rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: linear-gradient(135deg, rgba(143, 157, 247, 0.15) 0%, rgba(202, 181, 255, 0.15) 100%);
|
||||||
|
border-color: #8f9df7;
|
||||||
|
|
||||||
|
.option-text {
|
||||||
|
color: #8f9df7;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-hint {
|
||||||
|
padding: 8rpx 0;
|
||||||
|
text {
|
||||||
|
font-size: 12rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 日期行
|
||||||
|
.date-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6rpx;
|
||||||
|
}
|
||||||
|
.date-picker-box {
|
||||||
|
padding: 4rpx 10rpx;
|
||||||
|
background: rgba(196, 181, 255, 0.1);
|
||||||
|
border: 1rpx solid rgba(196, 181, 255, 0.25);
|
||||||
|
border-radius: 6rpx;
|
||||||
|
min-width: 90rpx;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.date-picker-text {
|
||||||
|
font-size: 12rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.filled {
|
||||||
|
border-color: #8f9df7;
|
||||||
|
.date-picker-text {
|
||||||
|
color: #8f9df7;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.date-sep {
|
||||||
|
font-size: 12rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.date-clear {
|
||||||
|
padding: 2rpx 6rpx;
|
||||||
|
text {
|
||||||
|
font-size: 12rpx;
|
||||||
|
color: #e05040;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 底部按钮
|
||||||
|
.bottom-bar {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
gap: 10rpx;
|
||||||
|
padding: 0 12rpx;
|
||||||
|
padding-bottom: calc(6rpx + env(safe-area-inset-bottom));
|
||||||
|
}
|
||||||
|
.btn-reset {
|
||||||
|
flex: 1;
|
||||||
|
padding: 7rpx 0;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
background: rgba(255, 255, 255, 0.9);
|
||||||
|
border: 1rpx solid rgba(196, 181, 255, 0.3);
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-family: $font-special;
|
||||||
|
font-size: 13rpx;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.btn-confirm {
|
||||||
|
flex: 2;
|
||||||
|
padding: 7rpx 0;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
background: linear-gradient(269deg, #adadff 2%, #cab5ff 52%, #8f9df7 100%);
|
||||||
|
box-shadow: 0 2rpx 8rpx rgba(143, 157, 247, 0.3);
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-family: $font-special;
|
||||||
|
font-size: 13rpx;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active:not(.disabled) {
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
File diff suppressed because it is too large
Load Diff
@ -38,7 +38,7 @@
|
|||||||
<!-- 右侧功能入口 -->
|
<!-- 右侧功能入口 -->
|
||||||
<view class="right-section">
|
<view class="right-section">
|
||||||
<view class="content">
|
<view class="content">
|
||||||
<view class="entry-card" @click="handleNavigate('/pages/teacher/homework/index')">
|
<view class="entry-card" @click="handleNavigate('/pages/teacher/homework/filter')">
|
||||||
<view class="card-icon homework-icon">
|
<view class="card-icon homework-icon">
|
||||||
<image :src="`${OSS_URL}/icon/homeWork_hisJob.svg`" mode="aspectFit" />
|
<image :src="`${OSS_URL}/icon/homeWork_hisJob.svg`" mode="aspectFit" />
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
export * from './tool';
|
export * from './tool';
|
||||||
export * from './map';
|
export * from './map';
|
||||||
export * from './getStatic';
|
export * from './getStatic';
|
||||||
|
export * from './subject';
|
||||||
36
src/utils/subject.ts
Normal file
36
src/utils/subject.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* 学科选项:与 admin playground store/basic-data/subject 保持一致(教材选择弹框学科数据来源)
|
||||||
|
*/
|
||||||
|
export interface SubjectOption {
|
||||||
|
value: number;
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const subjects: SubjectOption[] = [
|
||||||
|
{ value: 2, label: '语文' },
|
||||||
|
{ value: 3, label: '数学' },
|
||||||
|
{ value: 4, label: '英语' },
|
||||||
|
{ value: 5, label: '科学' },
|
||||||
|
{ value: 6, label: '物理' },
|
||||||
|
{ value: 7, label: '化学' },
|
||||||
|
{ value: 8, label: '历史' },
|
||||||
|
{ value: 9, label: '道德与法治' },
|
||||||
|
{ value: 10, label: '地理' },
|
||||||
|
{ value: 11, label: '生物' },
|
||||||
|
{ value: 12, label: '政治' },
|
||||||
|
{ value: 13, label: '信息' },
|
||||||
|
{ value: 14, label: '通用' },
|
||||||
|
{ value: 15, label: '日语' },
|
||||||
|
];
|
||||||
|
|
||||||
|
/** 学科下拉选项(用于筛选等),与 admin 教材选择弹框学科数据一致 */
|
||||||
|
export function getSubjectOptions(): SubjectOption[] {
|
||||||
|
return subjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 学科 value 转 label */
|
||||||
|
export function getSubjectLabel(value: number | string): string {
|
||||||
|
const v = Number(value);
|
||||||
|
const item = subjects.find((s) => s.value === v);
|
||||||
|
return item?.label ?? '';
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user