资源调整

This commit is contained in:
hebo 2025-10-29 10:30:04 +08:00
parent 9a5d8cf606
commit 33643f78ae
20 changed files with 1020 additions and 154 deletions

View File

@ -194,24 +194,24 @@ export const xsJzListByXsIdApi = async (params: any) => {
return await get("/api/jz/getListByXsId", params);
};
// 教学资源树形
export const typesFindTreeApi = async () => {
return await get("/api/types/qryTreeReturn");
// 资源目录树形
export const zymlFindTreeApi = async () => {
return await get("/api/zyml/qryTreeReturn");
};
// 根据资源类型获取教学资源树形
export const typesFindTreeByZylxApi = async (params: any) => {
return await get("/api/types/qryTreeByZylx", params);
// 根据资源类型获取资源目录树形
export const zymlFindTreeByZylxApi = async (params: any) => {
return await get("/api/zyml/qryTreeByZylx", params);
};
// 获取资源分页
export const resourcesFindPageApi = async (params: any) => {
return await get("/api/resources/findPage", params);
// 获取资源明细分页
export const zymxFindPageApi = async (params: any) => {
return await get("/api/zymx/findPage", params);
};
// 根据资源类型获取资源分页
export const resourcesFindPageByZylxApi = async (params: any) => {
return await get("/api/resources/findPageByZylx", params);
// 根据资源类型获取资源明细分页
export const zymxFindPageByZylxApi = async (params: any) => {
return await get("/api/zymx/findPageByZylx", params);
};
// 教师积分查询
@ -224,12 +224,12 @@ export const inspectItemFindAllApi = async (params: any) => {
return await get("/api/inspectItem/findAlls", params);
};
export const resourcesSaveApi = async (params: any) => {
return await post("/api/resources/save", params);
export const zymxSaveApi = async (params: any) => {
return await post("/api/zymx/save", params);
};
export const resourcesAddNumByTypeApi = async (params: any) => {
return await post("/api/resources/addNumByType", params);
export const zymxAddNumByTypeApi = async (params: any) => {
return await post("/api/zymx/addNumByType", params);
};
// 获取校平均工作量
@ -346,3 +346,10 @@ export const clearUserOpenIdApi = async (params: { userId: string }) => {
export const jsdXkkcPhotoSaveApi = async (params: any) => {
return await post("/mobile/js/xk/photo/save", params);
};
/**
*
*/
export const dicFindByPidApi = async (params: { pid: string }) => {
return await get("/api/dic/findByPid", params);
};

View File

@ -30,9 +30,7 @@
</picker-view-column>
</picker-view>
</view>
<view class="button" style="width: 90%; margin: 5px auto" @click="ok"
>确定</view
>
<view class="confirm-button" @click="ok">确定</view>
</view>
</uni-popup>
</template>
@ -165,4 +163,22 @@ picker-view-column {
display: block !important;
text-align: center;
}
.confirm-button {
width: 90%;
margin: 10px auto;
padding: 12px 0;
background-color: #007bff;
color: #fff;
text-align: center;
border-radius: 8px;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: background-color 0.3s;
&:active {
background-color: #0056b3;
}
}
</style>

View File

@ -16,7 +16,7 @@
</picker-view-column>
</picker-view>
</view>
<view class="button" style="width: 90%;margin: 5px auto;" @click="confirm">确定</view>
<view class="confirm-button" @click="confirm">确定</view>
</view>
</uni-popup>
</template>
@ -487,10 +487,27 @@ export default {
.center {
padding-bottom: var(--window-bottom);
}
.picker-view {
height: 400rpx;
}
.confirm-button {
width: 90%;
margin: 10px auto;
padding: 12px 0;
background-color: #007bff;
color: #fff;
text-align: center;
border-radius: 8px;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: background-color 0.3s;
&:active {
background-color: #0056b3;
}
}
</style>

View File

@ -872,21 +872,28 @@
}
},
{
"path": "pages/view/routine/kefuxuncha/zbList",
"path": "pages/view/routine/zbxc/xcPbList",
"style": {
"navigationBarTitleText": "值周巡查",
"enablePullDownRefresh": false
}
},
{
"path": "pages/view/routine/kefuxuncha/zbDetail",
"path": "pages/view/routine/zbxc/zbList",
"style": {
"navigationBarTitleText": "值周巡查列表",
"enablePullDownRefresh": false
}
},
{
"path": "pages/view/routine/zbxc/zbDetail",
"style": {
"navigationBarTitleText": "值周巡查详情",
"enablePullDownRefresh": false
}
},
{
"path": "pages/view/routine/kefuxuncha/zbRecord",
"path": "pages/view/routine/zbxc/zbRecord",
"style": {
"navigationBarTitleText": "值周巡查记录",
"enablePullDownRefresh": false

View File

@ -455,7 +455,14 @@ const sections = reactive<Section[]>([
permissionKey: "routine-yrcg", //
path: "/pages/view/quantitativeAssessment/index/index",
},
{
id: "r19",
icon: "zbxc",
text: "值周巡查",
show: true,
permissionKey: "routine-zbxc", //
path: "/pages/view/routine/zbxc/xcPbList",
},
],
},
{

View File

@ -20,6 +20,14 @@
<!-- 请假信息 -->
<view class="info-list">
<view class="info-item">
<text class="label">学生姓名:</text>
<text class="value">{{ qjData.xsxm }}</text>
</view>
<view class="info-item">
<text class="label">所在班级:</text>
<text class="value">{{ qjData.bc }}</text>
</view>
<view class="info-item">
<text class="label">请假类型:</text>
<text class="value">{{ qjData.qjlx }}</text>

View File

@ -1,26 +1,26 @@
<template>
<view class="wh-full">
<BasicLoading
:isShow="isShow"
bgColor="#fff"
isShowTitle
textColor="#000"
title="启动中..."
:type="1"
:isShow="isShow"
bgColor="#fff"
isShowTitle
textColor="#000"
title="启动中..."
:type="1"
/>
</view>
</template>
<script lang="ts" setup>
import { onLoad } from "@dcloudio/uni-app";
import { useDataStore } from "@/store/modules/data";
import { useUserStore } from "@/store/modules/user";
import { checkOpenId, findJsByPhoneApi } from "@/api/system/login";
import { PermissionCacheManager } from "@/utils/permission";
import {onLoad} from "@dcloudio/uni-app";
import {useDataStore} from "@/store/modules/data";
import {useUserStore} from "@/store/modules/user";
import {checkOpenId, findJsByPhoneApi} from "@/api/system/login";
import {PermissionCacheManager} from "@/utils/permission";
const { setGlobal, getGlobal } = useDataStore();
const { afterLoginAction } = useUserStore();
const { setFile, getFile } = useDataStore();
const {setGlobal, getGlobal} = useDataStore();
const {afterLoginAction} = useUserStore();
const {setFile, getFile} = useDataStore();
const isShow = ref(true);
/**
@ -28,25 +28,25 @@ const isShow = ref(true);
*/
async function forceRefreshPermission(changeTime?: string): Promise<void> {
try {
//
const userStore = useUserStore();
const currentUser = userStore.getUser;
if (currentUser && currentUser.id) {
//
const { authenticationApi } = await import('@/api/system/login');
const result = await authenticationApi({ userId: currentUser.id });
const {authenticationApi} = await import('@/api/system/login');
const result = await authenticationApi({userId: currentUser.id});
if (result && result.result) {
// setAuth
userStore.auth = result.result;
//
const { refreshPermissionCache } = await import('@/utils/permission');
const {refreshPermissionCache} = await import('@/utils/permission');
refreshPermissionCache(result.result, changeTime);
}
}
} catch (error) {
@ -106,33 +106,32 @@ onLoad(async (data: any) => {
rqgqtime: data.rqgqtime,
timestampqd: data.timestampqd
});
console.log('已保存参数到 global:', { openId: data.openId, type: data.type });
console.log('已保存参数到 global:', {openId: data.openId, type: data.type});
try {
const res = await checkOpenId({
openId: data.openId,
appCode: "JS",
});
if (data && data.qdId) {
goByqd(data);
}else if (res.resultCode == 1 && res.result) {
if (res.resultCode == 1 && res.result) {
//
afterLoginAction(res.result);
// changeTime
if (data.changeTime) {
const { refreshPermissionCache } = await import('@/utils/permission');
const {refreshPermissionCache} = await import('@/utils/permission');
const userStore = useUserStore();
const currentPermissions = userStore.getAuth;
if (currentPermissions && currentPermissions.length > 0) {
refreshPermissionCache(currentPermissions, data.changeTime);
}
}
//
console.log('launchPage onLoad - 准备调用goByJs');
goByJs(res.result.js);
if (data && data.qdId) {
goByqd(data);
} else {
goByJs(res.result.js);
}
} else {
uni.reLaunch({
url: "/pages/system/login/login",

View File

@ -1,7 +1,46 @@
<template>
<BasicLayout :fixed="false">
<view class="p-15">
<BasicForm @register="register">
<!-- 请假类型 -->
<BasicForm @register="register" />
<!-- 间隔空白 -->
<view class="section-gap"></view>
<!-- 时间选择区域 -->
<view class="time-section">
<view class="time-item" @click="startTimePicker?.open()">
<text class="time-label">
<text class="required-star">*</text>
开始时间
</text>
<view class="time-value">
<text :class="{ placeholder: !formData.qjkstime }">{{ formData.qjkstime || "请选择开始时间" }}</text>
<uni-icons type="right" size="16" color="#999"></uni-icons>
</view>
</view>
<view class="time-item" @click="endTimePicker?.open()">
<text class="time-label">
<text class="required-star">*</text>
结束时间
</text>
<view class="time-value">
<text :class="{ placeholder: !formData.qjjstime }">{{ formData.qjjstime || "请选择结束时间" }}</text>
<uni-icons type="right" size="16" color="#999"></uni-icons>
</view>
</view>
<view class="time-item time-item-readonly">
<text class="time-label">请假时长</text>
<view class="time-value">
<text :class="{ placeholder: !formData.qjsc }">{{ formData.qjsc || "请输入选择开始时间和结束时间" }}</text>
</view>
</view>
</view>
<!-- 请假事由等其他字段 -->
<BasicForm @register="register2">
<template #dkmx>
<view class="mt-15" v-show="formData.dkfs === 0">
<JsQjDkEdit :data="formData" ref="dkRef" />
@ -24,12 +63,29 @@
</view>
</view>
</template>
<!-- 自定义时间选择器 -->
<DatetimePicker
ref="startTimePicker"
:value="formData.qjkstime || new Date().getTime()"
mode="datetime"
title="选择开始时间"
@confirm="handleStartTimeConfirm"
/>
<DatetimePicker
ref="endTimePicker"
:value="formData.qjjstime || new Date().getTime()"
mode="datetime"
title="选择结束时间"
@confirm="handleEndTimeConfirm"
/>
</BasicLayout>
</template>
<script setup lang="ts">
import JsQjDkEdit from "./jsQjDkEdit.vue"
import BasicSpCsMgr from "@/components/BasicSpCsMgr/index.vue"
import DatetimePicker from "@/components/BasicPicker/TimePicker/DatetimePicker.vue"
import { useForm } from "@/components/BasicForm/hooks/useForm";
import { jsQjSqApi, jsQjCxtjApi } from "@/api/base/jsQjApi";
import { showToast } from "@/utils/uniapp";
@ -41,6 +97,10 @@ import { QjPageUtils } from "@/utils/qjPageUtils";
const { getJs, getUser } = useUserStore();
const { findByPid } = useDicStore();
//
const startTimePicker = ref<any>(null);
const endTimePicker = ref<any>(null);
//
const props = withDefaults(defineProps<{
data?: any
@ -69,6 +129,7 @@ const dkRef = ref<any>(null);
const fileName = ref<string>('');
const fileFormat = ref<string>('');
//
const [register, { setValue, getValue }] = useForm({
schema: [
{
@ -83,35 +144,12 @@ const [register, { setValue, getValue }] = useForm({
savaKey: "dictionaryCode",
},
},
{
field: "qjkstime",
label: "开始时间",
component: "BasicDateTimes",
required: true,
componentProps: {
type: 'datetime',
change: (e: string) => changeKsTime(e)
},
},
{
field: "qjjstime",
label: "结束时间",
component: "BasicDateTimes",
required: true,
componentProps: {
type: 'datetime',
change: (e: string) => changeJsTime(e)
},
},
{
field: "qjsc",
label: "请假时长",
component: "BasicInput",
componentProps: {
disabled: true,
placeholder: "请输入选择开始时间和结束时间"
},
},
],
});
//
const [register2, { setValue: setValue2, getValue: getValue2 }] = useForm({
schema: [
{
field: "qjsy",
label: "请假事由",
@ -179,25 +217,62 @@ const [register, { setValue, getValue }] = useForm({
],
});
const changeKsTime = (selectedTime?: string) => {
if (!selectedTime) {
return;
}
formData.value.qjkstime = selectedTime;
validateTime();
//
const formatDate = (dateString: string | null): string | null => {
if (!dateString) return null;
const date = new Date(dateString);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
};
const changeJsTime = (selectedTime?: string) => {
if (!selectedTime) {
return;
}
formData.value.qjjstime = selectedTime;
validateTime();
//
const handleStartTimeConfirm = (e: any) => {
formData.value.qjkstime = formatDate(e.value);
calculateDuration();
};
const handleEndTimeConfirm = (e: any) => {
formData.value.qjjstime = formatDate(e.value);
calculateDuration();
};
//
const calculateDuration = () => {
const data = formData.value;
//
if (!data.qjkstime || !data.qjjstime) {
data.qjsc = "";
return;
}
// 使dayjs
const ksTime = dayjs(data.qjkstime).valueOf();
const jsTime = dayjs(data.qjjstime).valueOf();
if (ksTime > jsTime) {
uni.showToast({
title: "请假开始时间不能大于请假结束时间!",
icon: "none",
});
data.qjsc = "";
return;
}
//
data.qjsc = Math.round((jsTime - ksTime) / (1000 * 60 * 60)) + "小时";
updateDk();
};
//
const validateTime = () => {
const data = formData.value;
if (!data.qjkstime || !data.qjjstime) {
uni.showToast({
title: "请选择开始时间和结束时间",
icon: "none",
});
return false;
}
// 使dayjs
@ -212,8 +287,6 @@ const validateTime = () => {
}
//
data.qjsc = Math.round((jsTime - ksTime) / (1000 * 60 * 60)) + "小时";
setValue({ qjsc: data.qjsc });
updateDk();
return true;
}
@ -235,10 +308,17 @@ const initDk = () => {
const submit = async () => {
const fd = await getValue();
const fd2 = await getValue2();
if (!validateTime()) {
return;
}
const params = { ...fd };
const params = {
...fd,
...fd2,
qjkstime: formData.value.qjkstime,
qjjstime: formData.value.qjjstime,
qjsc: formData.value.qjsc,
};
// /
params.sprList = formData.value.sprList || [];
params.csrList = formData.value.csrList || [];
@ -337,7 +417,10 @@ onMounted(() => {
jsId: formData.value.jsId || getJs.id,
sprList: formData.value.sprList || [],
csrList: formData.value.csrList || [],
dkfs: formData.value.dkfs || 0
dkfs: formData.value.dkfs || 0,
qjkstime: props.data.qjkstime || "",
qjjstime: props.data.qjjstime || "",
qjsc: props.data.qjsc || ""
};
formData.value = {
...props.data,
@ -347,9 +430,11 @@ onMounted(() => {
if (props.data && props.data.id) {
//
setValue(formData.value);
setValue2(formData.value);
initDk();
} else {
setValue(formData.value);
setValue2(formData.value);
}
console.log("onMounted:", formData.value);
});
@ -361,4 +446,75 @@ onMounted(() => {
/* 保持BasicForm区块背景统一 */
:deep(.white-bg-color) { background-color: #fff; }
.section-gap {
height: 12px;
}
.required-star {
color: #f56c6c;
margin-right: 4px;
font-size: 15px;
}
.time-section {
background-color: #ffffff;
border-radius: 8px;
margin-bottom: 12px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
.time-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 15px;
border-bottom: 1px solid #f0f0f0;
cursor: pointer;
transition: background-color 0.2s;
&:last-child {
border-bottom: none;
}
&:active {
background-color: #fafafa;
}
&.time-item-readonly {
cursor: default;
&:active {
background-color: transparent;
}
}
.time-label {
font-size: 15px;
color: #303133;
display: flex;
align-items: center;
}
.time-value {
display: flex;
align-items: center;
font-size: 15px;
color: #909399;
flex: 1;
justify-content: flex-end;
text {
margin-right: 5px;
color: #606266;
&.placeholder {
color: #c0c4cc;
}
}
.uni-icons {
color: #c0c4cc !important;
}
}
}
}
</style>

View File

@ -140,8 +140,8 @@
</template>
<script lang="ts" setup>
import { resourcesSaveApi } from "@/api/base/server";
import { typesFindTreeApi } from "@/api/base/server";
import { zymxSaveApi } from "@/api/base/server";
import { zymlFindTreeApi } from "@/api/base/server";
import { attachmentUpload } from "@/api/system/upload";
import { imagUrl } from "@/utils";
import { useDicStore } from "@/store/modules/dic";
@ -438,7 +438,7 @@ const handleSubmitForm = async () => {
const result = await resourcesSaveApi(params);
const result = await zymxSaveApi(params);
if (result.resultCode === 1) {
uni.showToast({ title: '操作成功', icon: 'success' });
@ -477,7 +477,7 @@ const resetFormData = () => {
//
const loadTreeData = async () => {
try {
const res = await typesFindTreeApi();
const res = await zymlFindTreeApi();
// BasicTree
if (res && Array.isArray(res)) {
treeData.value = res.map(item => ({

View File

@ -56,22 +56,15 @@
</template>
<script lang="ts" setup>
import { typesFindTreeApi } from "@/api/base/server";
import { zymlFindTreeApi, dicFindByPidApi } from "@/api/base/server";
import { useDataStore } from "@/store/modules/data";
const { setData } = useDataStore();
const typeTree = ref<any>([]);
const categoryList = ref([
{ key: '', label: '不限' },
{ key: '1', label: '课件' },
{ key: '2', label: '教案' },
{ key: '3', label: '学案' },
{ key: '4', label: '作业' },
{ key: '5', label: '试卷' },
{ key: '6', label: '教材' },
{ key: '7', label: '示范课' },
{ key: '8', label: '音视频合集' }
//
const categoryList = ref<any[]>([
{ key: '', label: '不限' }
]);
const curType = ref<any>();
@ -81,13 +74,28 @@ const curCategory = ref<any>(categoryList.value[0]);
const selectType = (type: any) => {
curType.value = type;
curNj.value = curType.value.children[0];
curCe.value = curNj.value.children[0];
if (curType.value.children && curType.value.children.length > 0) {
curNj.value = curType.value.children[0];
if (curNj.value.children && curNj.value.children.length > 0) {
curCe.value = curNj.value.children[0];
} else {
curCe.value = null;
}
} else {
curNj.value = null;
curCe.value = null;
}
}
const selectNj = (type: any) => {
curNj.value = type;
curCe.value = curNj.value.children[0];
if (curNj.value.children && curNj.value.children.length > 0) {
curCe.value = curNj.value.children[0];
} else {
curCe.value = null;
}
}
const selectCe = (type: any) => {
curCe.value = type;
}
@ -96,9 +104,36 @@ const selectCategory = (type: any) => {
curCategory.value = type;
}
// 23
const getLeafNode = () => {
// 33
if (curCe.value) {
return curCe.value;
}
// 22
if (curNj.value) {
return curNj.value;
}
// 11
if (curType.value) {
return curType.value;
}
return null;
}
const goTo = function () {
const leafNode = getLeafNode();
if (!leafNode) {
uni.showToast({
title: '请先选择资源类型',
icon: 'none'
});
return;
}
const params = {
resourType: curCe.value.key, // resourType
resourType: leafNode.key, // key
category: curCategory.value.key,
};
@ -106,6 +141,8 @@ const goTo = function () {
科目: curType.value?.title,
年级: curNj.value?.title,
上下册: curCe.value?.title,
叶子节点: leafNode.title,
叶子节点层级: curCe.value ? '3级' : (curNj.value ? '2级' : '1级'),
资源类型: curCategory.value?.label,
传递参数: params
});
@ -116,9 +153,41 @@ const goTo = function () {
});
}
//
const loadCategoryList = async () => {
try {
const pid = '1391443399'; // ID
const res = await dicFindByPidApi({ pid });
console.log('资源类别字典数据:', res);
if (res && res.result && Array.isArray(res.result) && res.result.length > 0) {
// ""
const dictOptions = res.result.map((item: any) => ({
key: item.dictionaryCode || item.dictionaryValue || item.id, // 使 dictionaryCode key
label: item.dictionaryName || item.dictionaryValue || item.name
}));
categoryList.value = [
{ key: '', label: '不限' },
...dictOptions
];
console.log('资源类别选项(使用 dictionaryCode:', categoryList.value);
} else {
console.warn('字典数据为空或格式不正确,使用默认资源类别选项');
}
} catch (error) {
console.error('加载资源类别字典失败:', error);
// ""
}
};
//
onMounted(async () => {
const res = await typesFindTreeApi();
//
await loadCategoryList();
const res = await zymlFindTreeApi();
typeTree.value = res.result || [];
console.log('教学资源页面加载完成', res);

View File

@ -103,7 +103,7 @@
<script lang="ts" setup>
import { imagUrl } from "@/utils";
import { useLayout } from "@/components/BasicListLayout/hooks/useLayout";
import { resourcesFindPageApi, resourcesAddNumByTypeApi } from "@/api/base/server";
import { zymxFindPageApi, zymxAddNumByTypeApi } from "@/api/base/server";
import { useDataStore } from "@/store/modules/data";
import {
isVideo,
@ -131,7 +131,7 @@ const searchKeyword = ref<string>('');
// --- Layout Hook (Removed 'immediate' from componentProps) ---
const [register, { reload, setParam }] = useLayout({
api: resourcesFindPageApi,
api: zymxFindPageApi,
componentProps: {
defaultPageSize: 5, // 5
loadingMoreEnabled: true, //
@ -203,7 +203,7 @@ const handlePreviewImage = (item) => {
// --- ---
const recordViewAction = (item) => {
resourcesAddNumByTypeApi({
zymxAddNumByTypeApi({
id: item.id,
type: 'view'
});
@ -227,7 +227,7 @@ const downloadResouce = (item: any) => {
// 使
downloadFile(finalUrl, fileName)
.then(() => {
resourcesAddNumByTypeApi({
zymxAddNumByTypeApi({
id: item.id,
type: 'down'
});

View File

@ -118,12 +118,13 @@ const loadPbList = async (isRefresh = false) => {
}
try {
//
// (A)(B)(C)zbxc/xcPbList.vue
const params = {
page: pagination.page,
rows: pagination.pageSize,
//
// xcbt: '', //
// xclx: '', //
// xkId: '', // ID
// xqId: '', // ID
};
@ -135,10 +136,16 @@ const loadPbList = async (isRefresh = false) => {
// API
const list = res.rows || res.result?.rows || res.result?.list || [];
// (A)(B)(C)
const filteredList = list.filter((item: any) => item.xclx === 'A' || item.xclx === 'B');
console.log('原始数据数量:', list.length, '过滤后数据数量:', filteredList.length);
console.log('过滤掉的值周巡查(C)数量:', list.length - filteredList.length);
if (isRefresh) {
pbList.value = list;
pbList.value = filteredList;
} else {
pbList.value.push(...list);
pbList.value.push(...filteredList);
}
// 使records使total
@ -235,6 +242,8 @@ const getXclxText = (xclx: string) => {
return '课程巡查';
} else if (xclx === 'B') {
return '课业辅导巡查';
} else if (xclx === 'C') {
return '值周巡查';
}
return '暂无';
};
@ -254,6 +263,7 @@ const goXc = (pb: any) => {
delete pbData.id; // id
setData(pbData);
if (pb.xclx === 'A') {
//
uni.navigateTo({
@ -265,9 +275,9 @@ const goXc = (pb: any) => {
url: `/pages/view/routine/kefuxuncha/kyXkList`,
});
} else if (pb.xclx === 'C') {
//
// zbxc
uni.navigateTo({
url: `/pages/view/routine/kefuxuncha/zbList`,
url: `/pages/view/routine/zbxc/zbList`,
});
} else {
uni.showToast({

View File

@ -141,8 +141,8 @@
</template>
<script lang="ts" setup>
import { resourcesSaveApi } from "@/api/base/server";
import { typesFindTreeByZylxApi } from "@/api/base/server";
import { zymxSaveApi } from "@/api/base/server";
import { zymlFindTreeByZylxApi } from "@/api/base/server";
import { attachmentUpload } from "@/api/system/upload";
import { imagUrl } from "@/utils";
import { useDicStore } from "@/store/modules/dic";
@ -439,7 +439,7 @@ const handleSubmitForm = async () => {
const result = await resourcesSaveApi(params);
const result = await zymxSaveApi(params);
if (result.resultCode === 1) {
uni.showToast({ title: '操作成功', icon: 'success' });
@ -528,7 +528,7 @@ const loadTreeData = async () => {
console.log('add-resource 加载资源目录zylx:', zylx.value);
const res = await typesFindTreeByZylxApi({ zylx: zylx.value });
const res = await zymlFindTreeByZylxApi({ zylx: zylx.value });
// BasicTree
if (res && Array.isArray(res)) {
treeData.value = res.map((item: any) => ({

View File

@ -37,7 +37,7 @@
</template>
<script lang="ts" setup>
import { typesFindTreeByZylxApi } from "@/api/base/server";
import { zymlFindTreeByZylxApi } from "@/api/base/server";
import { useDataStore } from "@/store/modules/data";
const { setData } = useDataStore();
@ -136,7 +136,7 @@ const initData = async () => {
console.log('当前URL:', window.location.href);
//
const res = await typesFindTreeByZylxApi({ zylx: zylx.value });
const res = await zymlFindTreeByZylxApi({ zylx: zylx.value });
typeTree.value = res.result || [];
console.log(`${topLevelTitle.value}资源页面加载完成`, res);

View File

@ -103,7 +103,7 @@
<script lang="ts" setup>
import { imagUrl } from "@/utils";
import { useLayout } from "@/components/BasicListLayout/hooks/useLayout";
import { resourcesFindPageApi, resourcesAddNumByTypeApi } from "@/api/base/server";
import { zymxFindPageApi, zymxAddNumByTypeApi } from "@/api/base/server";
import { useDataStore } from "@/store/modules/data";
import {
isVideo,
@ -131,7 +131,7 @@ const searchKeyword = ref<string>('');
// --- Layout Hook (Removed 'immediate' from componentProps) ---
const [register, { reload, setParam }] = useLayout({
api: resourcesFindPageApi,
api: zymxFindPageApi,
componentProps: {
defaultPageSize: 5, // 5
loadingMoreEnabled: true, //
@ -203,7 +203,7 @@ const handlePreviewImage = (item) => {
// --- ---
const recordViewAction = (item) => {
resourcesAddNumByTypeApi({
zymxAddNumByTypeApi({
id: item.id,
type: 'view'
});
@ -227,7 +227,7 @@ const downloadResouce = (item: any) => {
// 使
downloadFile(finalUrl, fileName)
.then(() => {
resourcesAddNumByTypeApi({
zymxAddNumByTypeApi({
id: item.id,
type: 'down'
});

View File

@ -0,0 +1,570 @@
<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>
<!-- 可滚动的内容区域 -->
<scroll-view
class="scrollable-content"
scroll-y
@scrolltolower="onScrollToLower"
:refresher-enabled="true"
:refresher-triggered="refreshing"
@refresherrefresh="onRefresh"
refresher-background="#f8fafc"
>
<!-- 排班列表 -->
<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 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>加载更多</text>
</view>
<!-- 没有更多数据提示 -->
<view class="no-more" v-if="!hasMore && pbList.length > 0">
<text>没有更多数据了</text>
</view>
</scroll-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 { getPbPageApi } from "@/api/base/pbApi";
import dayjs from "dayjs";
const { getJs } = useUserStore();
const { getData, setData } = useDataStore();
//
const pbList = ref<any[]>([]);
const loading = ref(false);
const hasMore = ref(true);
const refreshing = ref(false);
//
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,
xclx: 'C', // C-
//
// xcbt: '', //
// xkId: '', // ID
// xqId: '', // ID
};
const res: any = await getPbPageApi(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;
refreshing.value = false;
}
};
//
const loadMore = () => {
if (hasMore.value && !loading.value) {
pagination.page++;
loadPbList();
}
};
//
const onScrollToLower = () => {
if (hasMore.value && !loading.value) {
pagination.page++;
loadPbList();
}
};
//
const onRefresh = () => {
refreshing.value = true;
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 '课业辅导巡查';
} else if (xclx === 'C') {
return '值周巡查';
}
return '暂无';
};
//
const goXc = (pb: any) => {
//
console.log('排班数据pb:', pb);
console.log('pb.id:', pb?.id);
console.log('pb的所有属性:', Object.keys(pb || {}));
// 使pbId
const pbData = {
...pb,
pbId: pb.id, // idpbId
};
delete pbData.id; // id
setData(pbData);
// (C)
if (pb.xclx === 'C') {
// zbxc
uni.navigateTo({
url: `/pages/view/routine/zbxc/zbList`,
});
} else {
//
console.warn('意外的巡查类型:', pb.xclx);
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;
}
}
//
.no-more {
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
color: #999;
font-size: 12px;
text {
color: #999;
}
}
//
@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>

View File

@ -137,8 +137,8 @@
<ImageVideoUpload
v-model:image-list="imageList"
v-model:video-list="videoList"
:max-image-count="5"
:max-video-count="3"
:max-image-count="10"
:max-video-count="5"
:compress-config="compressConfig"
:upload-api="attachmentUpload"
@image-upload-success="onImageUploadSuccess"
@ -259,10 +259,10 @@ const currentInputLabel = ref('');
const currentInputValue = ref('');
const currentItem = ref<any>(null);
//
//
const formatTime = (timestamp: string) => {
if (!timestamp) return '';
return dayjs(timestamp).format('MM-DD HH:mm');
return dayjs(timestamp).format('MM-DD');
};
//

View File

@ -135,11 +135,11 @@ const getDutyDisplayName = (zb: any) => {
return displayName || '值周教师';
};
//
//
const formatDutyTime = (zb: any) => {
if (zb.zbkstime && zb.zbjstime) {
const startTime = dayjs(zb.zbkstime).format('MM-DD HH:mm');
const endTime = dayjs(zb.zbjstime).format('MM-DD HH:mm');
const startTime = dayjs(zb.zbkstime).format('MM-DD');
const endTime = dayjs(zb.zbjstime).format('MM-DD');
return `${startTime} ~ ${endTime}`;
}
return '暂无';
@ -384,7 +384,7 @@ const goXc = async (zb: any) => {
dataStore.setData(combinedData);
uni.navigateTo({
url: `/pages/view/routine/kefuxuncha/zbDetail`,
url: `/pages/view/routine/zbxc/zbDetail`,
});
};
@ -413,7 +413,7 @@ const goRecord = (zb: any) => {
dataStore.setData(combinedData);
uni.navigateTo({
url: `/pages/view/routine/kefuxuncha/zbRecord`,
url: `/pages/view/routine/zbxc/zbRecord`,
});
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB