Compare commits
9 Commits
5e0207b224
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| ccd54f537a | |||
| cfcf1ad16e | |||
| beda8b5de7 | |||
| 994cf0c892 | |||
| c6788d210b | |||
| 73f9741a88 | |||
| 9f39a822f7 | |||
| 2fb5ffadc8 | |||
| 08571869b5 |
@@ -1,7 +0,0 @@
|
|||||||
# huike-front 项目指南
|
|
||||||
|
|
||||||
## vConsole 显示规则
|
|
||||||
|
|
||||||
vConsole 仅在当前用户有 `SYS_CAN_SUDO` tag 时显示。判断逻辑在 `src/App.vue:updateVConsoleVisibility()`。
|
|
||||||
|
|
||||||
Tags 通过 `get_all_tags_of_the_user` API 异步加载(`src/store/user.ts:getTags()`),在 `setCurrentUser()` 之后执行。vConsole 的 watch 需要 `{ deep: true }` 以及独立的 `store.current.tags` watch 来覆盖异步加载完成后的触发。
|
|
||||||
@@ -70,6 +70,7 @@ export default defineComponent({
|
|||||||
const badge_props: Partial<BadgeProps> = { showZero: false, max: 99 }
|
const badge_props: Partial<BadgeProps> = { showZero: false, max: 99 }
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
console.debug('[App.vue] deploy_ver=20260504.001');
|
||||||
let vconsole = document.getElementById("__vconsole");
|
let vconsole = document.getElementById("__vconsole");
|
||||||
if (vconsole) {
|
if (vconsole) {
|
||||||
vconsole.hidden = true;
|
vconsole.hidden = true;
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="hasMultipleDepts" class="current-dept">
|
||||||
|
<span>当前部门:{{ currentDeptName || '未选择' }}</span>
|
||||||
|
<van-button size="mini" plain type="primary" @click="showPicker = true">切换部门</van-button>
|
||||||
|
<van-action-sheet
|
||||||
|
v-model:show="showPicker"
|
||||||
|
:actions="deptActions"
|
||||||
|
@select="onSelect"
|
||||||
|
cancel-text="取消"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, ref, computed } from 'vue';
|
||||||
|
import { ActionSheet, Button } from 'vant';
|
||||||
|
import useOrg from '~/store/org';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'dept-switcher',
|
||||||
|
components: {
|
||||||
|
[ActionSheet.name!]: ActionSheet,
|
||||||
|
[Button.name!]: Button,
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
const { store, switchDepartment } = useOrg();
|
||||||
|
const showPicker = ref(false);
|
||||||
|
|
||||||
|
const hasMultipleDepts = computed(() => store.departments.length > 1);
|
||||||
|
|
||||||
|
const currentDeptName = computed(() => {
|
||||||
|
if (!store.currentDepartmentId) return '';
|
||||||
|
const dept = store.departments.find((d) => d.id === store.currentDepartmentId);
|
||||||
|
return dept?.dept_name || '';
|
||||||
|
});
|
||||||
|
|
||||||
|
const deptActions = computed(() =>
|
||||||
|
store.departments.map((d) => ({
|
||||||
|
name: d.dept_name,
|
||||||
|
id: d.id,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
const onSelect = async (action: { name: string; id: string }) => {
|
||||||
|
showPicker.value = false;
|
||||||
|
if (action.id !== store.currentDepartmentId) {
|
||||||
|
await switchDepartment(action.id);
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return { hasMultipleDepts, currentDeptName, showPicker, deptActions, onSelect };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.current-dept {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.12rem;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 0.12rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
<span>当前机构:{{ currentOrgName || '未选择机构' }}</span>
|
<span>当前机构:{{ currentOrgName || '未选择机构' }}</span>
|
||||||
<van-button size="mini" plain type="primary" @click="goOrgSelect">切换机构</van-button>
|
<van-button size="mini" plain type="primary" @click="goOrgSelect">切换机构</van-button>
|
||||||
</div>
|
</div>
|
||||||
|
<dept-switcher />
|
||||||
<div v-if="isStudent" class="current-teacher">
|
<div v-if="isStudent" class="current-teacher">
|
||||||
<span>当前老师:{{ currentTeacherName || '未选择老师' }}</span>
|
<span>当前老师:{{ currentTeacherName || '未选择老师' }}</span>
|
||||||
<van-button size="mini" plain type="primary" @click="goTeacherSelect">切换老师</van-button>
|
<van-button size="mini" plain type="primary" @click="goTeacherSelect">切换老师</van-button>
|
||||||
@@ -45,6 +46,7 @@ import { useRouter } from "vue-router";
|
|||||||
import {UpyunAccess} from "~/utils/upyun";
|
import {UpyunAccess} from "~/utils/upyun";
|
||||||
import {CurrentUserRole, HtyAuthToken, HtySudoToken} from "~/utils";
|
import {CurrentUserRole, HtyAuthToken, HtySudoToken} from "~/utils";
|
||||||
import useOrg from "~/store/org";
|
import useOrg from "~/store/org";
|
||||||
|
import DeptSwitcher from "~/components/dept-switcher.vue";
|
||||||
import useTeacher from "~/store/teacher";
|
import useTeacher from "~/store/teacher";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@@ -54,13 +56,14 @@ export default defineComponent({
|
|||||||
[Icon.name!]: Icon,
|
[Icon.name!]: Icon,
|
||||||
[Tag.name!]: Tag,
|
[Tag.name!]: Tag,
|
||||||
[ActionSheet.name!]: ActionSheet,
|
[ActionSheet.name!]: ActionSheet,
|
||||||
[Button.name!]: Button
|
[Button.name!]: Button,
|
||||||
|
DeptSwitcher,
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const switching = ref(false);
|
const switching = ref(false);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { store, chooseRole, update, logout } = useUser(router);
|
const { store, chooseRole, update, logout } = useUser(router);
|
||||||
const { store: orgStore, loadMyOrgs } = useOrg();
|
const { store: orgStore, loadMyOrgs, loadMyDepartments } = useOrg();
|
||||||
const { store: teacherStore, switchTeacher } = useTeacher();
|
const { store: teacherStore, switchTeacher } = useTeacher();
|
||||||
const user = computed(() => store.current)
|
const user = computed(() => store.current)
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
@@ -167,6 +170,9 @@ export default defineComponent({
|
|||||||
if (!orgStore.orgs.length) {
|
if (!orgStore.orgs.length) {
|
||||||
await loadMyOrgs();
|
await loadMyOrgs();
|
||||||
}
|
}
|
||||||
|
if (!orgStore.departments.length) {
|
||||||
|
await loadMyDepartments();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return { switching, hasMultiRoles, roles, user, currentRole, switchRole, editAvatar, avatarUrl, editName, state, logoutUser, currentOrgName, goOrgSelect, isStudent, currentTeacherName, goTeacherSelect }
|
return { switching, hasMultiRoles, roles, user, currentRole, switchRole, editAvatar, avatarUrl, editName, state, logoutUser, currentOrgName, goOrgSelect, isStudent, currentTeacherName, goTeacherSelect }
|
||||||
|
|||||||
+63
-18
@@ -209,14 +209,14 @@
|
|||||||
<van-calendar v-model:show="state.showCalendar" :min-date="repeatMinDate" :default-date="repeatDefaultDate" @confirm="onChangeDate" type="range" color="#1989fa" />
|
<van-calendar v-model:show="state.showCalendar" :min-date="repeatMinDate" :default-date="repeatDefaultDate" @confirm="onChangeDate" type="range" color="#1989fa" />
|
||||||
<van-cell title="操作记录" is-link v-if="state.readonly && store.current.id" @click="showAuditLogPopup" style="margin-bottom: 0.2rem;" />
|
<van-cell title="操作记录" is-link v-if="state.readonly && store.current.id" @click="showAuditLogPopup" style="margin-bottom: 0.2rem;" />
|
||||||
</div>
|
</div>
|
||||||
<div class="footer" v-if="is_creator || !store.current.id ">
|
<div class="footer" v-if="(is_creator || !store.current.id) && !isStudent">
|
||||||
<template v-if="state.readonly">
|
<template v-if="state.readonly">
|
||||||
<van-button v-if="is_creator && store.current.id && !store.current.is_repeat" size="small" type="primary" plain block @click="openAttendance">点名(消课)</van-button>
|
<van-button v-if="is_creator && store.current.id && !store.current.is_repeat" size="small" type="primary" plain block @click="openAttendance">点名(消课)</van-button>
|
||||||
<div class="footer-actions">
|
<div class="footer-actions">
|
||||||
<van-button size="mini" type="primary" @click="edit(true)" v-if="is_creator && (store.current.instance || store.current.has_root)">编辑重复排课</van-button>
|
<van-button size="mini" type="primary" @click="edit(true)" v-if="is_creator && (store.current.instance || store.current.has_root)">编辑重复排课</van-button>
|
||||||
<van-button size="mini" type="primary" @click="edit(false)">编辑本次排课</van-button>
|
<van-button size="mini" type="primary" @click="edit(false)" v-if="is_creator">编辑本次排课</van-button>
|
||||||
<van-button size="mini" type="danger" @click="remove(true)" v-if="is_creator && (store.current.instance || store.current.has_root)">取消重复排课</van-button>
|
<van-button size="mini" type="danger" @click="remove(true)" v-if="is_creator && (store.current.instance || store.current.has_root)">取消重复排课</van-button>
|
||||||
<van-button size="mini" type="danger" @click="remove(false)">取消本次排课</van-button>
|
<van-button size="mini" type="danger" @click="remove(false)" v-if="is_creator">取消本次排课</van-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
@@ -322,7 +322,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
setup({params}: any) {
|
setup({params}: any) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const {store, query_repeats, query, query_for_subsidiaries, query_repeats_for_subsidiaries, createOrUpdate, createInstance, removeCurrent, notify, find_clazz_attendance_by_clazz_id, batch_save_clazz_attendance, getAuditLog} = useClazz();
|
const {store, query_repeats, query, query_merged, query_merged_for_subsidiaries, query_for_subsidiaries, query_repeats_for_subsidiaries, createOrUpdate, createInstance, removeCurrent, notify, find_clazz_attendance_by_clazz_id, batch_save_clazz_attendance, getAuditLog} = useClazz();
|
||||||
const {set: setPool, setKey, getKey} = usePool();
|
const {set: setPool, setKey, getKey} = usePool();
|
||||||
const usingSupervisor = useSupervisor();
|
const usingSupervisor = useSupervisor();
|
||||||
const usingUser = useUser();
|
const usingUser = useUser();
|
||||||
@@ -461,6 +461,23 @@ export default defineComponent({
|
|||||||
// ═══ 老师过滤(矩阵视图用) ═══
|
// ═══ 老师过滤(矩阵视图用) ═══
|
||||||
const teacherList = computed(() => {
|
const teacherList = computed(() => {
|
||||||
const list: { id: string; name: string; color: string }[] = [];
|
const list: { id: string; name: string; color: string }[] = [];
|
||||||
|
const currentRole = usingUser.store.currentRole;
|
||||||
|
|
||||||
|
if (currentRole === HtyBaseRoles.STUDENT) {
|
||||||
|
const seen = new Set<string>();
|
||||||
|
normalizedEvents.value.forEach(ev => {
|
||||||
|
if (ev.teacherId && !seen.has(ev.teacherId)) {
|
||||||
|
seen.add(ev.teacherId);
|
||||||
|
list.push({
|
||||||
|
id: ev.teacherId,
|
||||||
|
name: ev.teacherName || ev.teacherId,
|
||||||
|
color: Colors[list.length % Colors.length],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
const myId = usingUser.store.current.hty_id;
|
const myId = usingUser.store.current.hty_id;
|
||||||
const myName = usingUser.store.current.real_name;
|
const myName = usingUser.store.current.real_name;
|
||||||
if (myId && myName) {
|
if (myId && myName) {
|
||||||
@@ -562,30 +579,62 @@ export default defineComponent({
|
|||||||
view(ev.id);
|
view(ev.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isStudent = computed(() => usingUser.store.currentRole === HtyBaseRoles.STUDENT);
|
||||||
|
|
||||||
|
const teacherColorMap = computed(() => {
|
||||||
|
const map: Record<string, string> = {};
|
||||||
|
teacherList.value.forEach(t => { map[t.id] = t.color; });
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
|
||||||
const draw = () => {
|
const draw = () => {
|
||||||
if (!calendar.value) { console.debug('[clazz draw] skip, calendar null'); return; }
|
if (!calendar.value) { console.debug('[clazz draw] skip, calendar null'); return; }
|
||||||
let api = calendar.value.getApi()
|
let api = calendar.value.getApi()
|
||||||
api.removeAllEvents();
|
api.removeAllEvents();
|
||||||
store.list.forEach(item => {
|
store.list.forEach(item => {
|
||||||
if (item.is_delete) return;
|
if (item.is_delete) return;
|
||||||
api.addEvent({
|
const ev: any = {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
title: item.clazz_name,
|
title: item.clazz_name,
|
||||||
start: item.start_from,
|
start: item.start_from,
|
||||||
end: item.end_by,
|
end: item.end_by,
|
||||||
})
|
};
|
||||||
|
if (isStudent.value) {
|
||||||
|
const teacherId = item.teachers?.val?.users?.vals?.[0]?.user_id;
|
||||||
|
if (teacherId && teacherColorMap.value[teacherId]) {
|
||||||
|
const color = teacherColorMap.value[teacherId];
|
||||||
|
ev.color = color;
|
||||||
|
const {r, g, b} = hexToRgb(color);
|
||||||
|
ev.borderColor = `rgba(${r}, ${g}, ${b}, 0.8)`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
api.addEvent(ev);
|
||||||
})
|
})
|
||||||
|
|
||||||
store.repeatList.forEach(item => {
|
store.repeatList.forEach(item => {
|
||||||
if (!item.instance.id) {
|
if (!item.instance.id) {
|
||||||
api.addEvent({
|
const rev: any = {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
title: item.instance.clazz_name,
|
title: item.instance.clazz_name,
|
||||||
start: item.instance.start_from,
|
start: item.instance.start_from,
|
||||||
end: item.instance.end_by,
|
end: item.instance.end_by,
|
||||||
color: "rgba(55, 136, 216, 0.6)",
|
};
|
||||||
borderColor: "rgba(55, 136, 216, 0.6)"
|
if (isStudent.value) {
|
||||||
})
|
const teacherId = item.teachers?.val?.users?.vals?.[0]?.user_id;
|
||||||
|
if (teacherId && teacherColorMap.value[teacherId]) {
|
||||||
|
const color = teacherColorMap.value[teacherId];
|
||||||
|
const {r, g, b} = hexToRgb(color);
|
||||||
|
rev.color = `rgba(${r}, ${g}, ${b}, 0.6)`;
|
||||||
|
rev.borderColor = `rgba(${r}, ${g}, ${b}, 0.6)`;
|
||||||
|
} else {
|
||||||
|
rev.color = "rgba(55, 136, 216, 0.6)";
|
||||||
|
rev.borderColor = "rgba(55, 136, 216, 0.6)";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rev.color = "rgba(55, 136, 216, 0.6)";
|
||||||
|
rev.borderColor = "rgba(55, 136, 216, 0.6)";
|
||||||
|
}
|
||||||
|
api.addEvent(rev);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -693,8 +742,8 @@ export default defineComponent({
|
|||||||
const lastQueryKey = ref('');
|
const lastQueryKey = ref('');
|
||||||
|
|
||||||
const searchForSubsidiaries = async (start_date: string, end_date: string) => {
|
const searchForSubsidiaries = async (start_date: string, end_date: string) => {
|
||||||
// 主管老师角色下才加载下属老师的排课
|
// 仅在教师或主管角色下加载下属老师的排课,学生角色不加载
|
||||||
if (usingUser.store.currentRole !== HtyBaseRoles.TEACHER && usingUser.store.current.roles.some(r => r.role_key === HtySuperRoles.SUPERVISOR)) {
|
if (usingUser.store.currentRole !== HtyBaseRoles.TEACHER && usingUser.store.currentRole !== HtyBaseRoles.STUDENT && usingUser.store.current.roles.some(r => r.role_key === HtySuperRoles.SUPERVISOR)) {
|
||||||
subsidiaries.value = usingSupervisor.store.subsidiaries;
|
subsidiaries.value = usingSupervisor.store.subsidiaries;
|
||||||
if (!subsidiaries.value.length) {
|
if (!subsidiaries.value.length) {
|
||||||
await usingSupervisor.getSubsidiaries();
|
await usingSupervisor.getSubsidiaries();
|
||||||
@@ -710,10 +759,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
if (subsidiaries.value.length) {
|
if (subsidiaries.value.length) {
|
||||||
const htyIds = subsidiaries.value.map(x => x.to_user_id);
|
const htyIds = subsidiaries.value.map(x => x.to_user_id);
|
||||||
return Promise.all([
|
return query_merged_for_subsidiaries(start_date, end_date, htyIds);
|
||||||
query_for_subsidiaries(start_date, end_date, htyIds),
|
|
||||||
query_repeats_for_subsidiaries(start_date, end_date, htyIds),
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -729,8 +775,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
query(start_date, end_date),
|
query_merged(start_date, end_date),
|
||||||
query_repeats(start_date, end_date),
|
|
||||||
searchForSubsidiaries(start_date, end_date),
|
searchForSubsidiaries(start_date, end_date),
|
||||||
]);
|
]);
|
||||||
lastQueryKey.value = key;
|
lastQueryKey.value = key;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<van-search shape="round" v-model.trim="state.keyword" />
|
<van-search shape="round" v-model.trim="state.keyword" />
|
||||||
</div>
|
</div>
|
||||||
<div class="list">
|
<div class="list">
|
||||||
<van-pull-refresh v-model="state.loading" @refresh="onRefresh">
|
<van-pull-refresh v-model="state.refreshing" @refresh="onRefresh">
|
||||||
<van-list v-model:loading="state.loading"
|
<van-list v-model:loading="state.loading"
|
||||||
:finished="state.finished" finished-text="没有更多数据了"
|
:finished="state.finished" finished-text="没有更多数据了"
|
||||||
@load="onPage">
|
@load="onPage">
|
||||||
@@ -102,7 +102,9 @@ export default defineComponent({
|
|||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
keyword: '',
|
keyword: '',
|
||||||
loading: false, finished: true,
|
refreshing: false,
|
||||||
|
loading: false,
|
||||||
|
finished: true,
|
||||||
start_date: '',
|
start_date: '',
|
||||||
page: 1,
|
page: 1,
|
||||||
page_size: 10,
|
page_size: 10,
|
||||||
@@ -123,14 +125,19 @@ export default defineComponent({
|
|||||||
if (start_date) {
|
if (start_date) {
|
||||||
params.start_date = start_date + " 00:00:00";
|
params.start_date = start_date + " 00:00:00";
|
||||||
}
|
}
|
||||||
await query(params);
|
try {
|
||||||
if (store.pages <= state.page) {
|
await query(params);
|
||||||
state.finished = true;
|
if (store.pages <= state.page) {
|
||||||
|
state.finished = true;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
state.loading = false;
|
||||||
|
state.refreshing = false;
|
||||||
}
|
}
|
||||||
state.loading = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const onRefresh = async () => {
|
const onRefresh = async () => {
|
||||||
|
state.refreshing = true;
|
||||||
await search({page: 1, page_size: state.page_size});
|
await search({page: 1, page_size: state.page_size});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+56
-1
@@ -220,6 +220,61 @@ export default function useClazz() {
|
|||||||
load_done()
|
load_done()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Merged query: fetches both non-repeatable and repeatable in one API call
|
||||||
|
async function query_merged(start_from: string, end_by: string) {
|
||||||
|
let {currentRole, current:{hty_id}} = usingUser.store;
|
||||||
|
load_start()
|
||||||
|
const {r, d, e, statusCode} = await request({
|
||||||
|
url: "/api/v1/clazz/find_all_within_date_range",
|
||||||
|
method: "GET", data: {start_from, end_by, hty_id}
|
||||||
|
})
|
||||||
|
load_done()
|
||||||
|
if (r) {
|
||||||
|
const nonRepeatable = normalizeClazzListPayload(d.non_repeatable, "merged_non_repeatable");
|
||||||
|
store.list = nonRepeatable.filter(x => {
|
||||||
|
if (currentRole === HtyBaseRoles.TEACHER || currentRole === HtySuperRoles.SUPERVISOR) {
|
||||||
|
return x.teachers?.val?.users?.vals?.some(u => u.user_id === hty_id)
|
||||||
|
}
|
||||||
|
if (currentRole === HtyBaseRoles.STUDENT) {
|
||||||
|
return x.students?.val?.users?.vals?.some(u => u.user_id === hty_id)
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
const repeatable = normalizeClazzListPayload(d.repeatable, "merged_repeatable");
|
||||||
|
store.repeatList = repeat_prepare(start_from, end_by, repeatable, store.list);
|
||||||
|
} else {
|
||||||
|
console.warn("[ClazzQuery] merged query failed", {
|
||||||
|
e, statusCode, start_from, end_by, hty_id,
|
||||||
|
});
|
||||||
|
showFailToast(e);
|
||||||
|
}
|
||||||
|
return Promise.resolve(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function query_merged_for_subsidiaries(start_from: string, end_by: string, hty_ids: string[]) {
|
||||||
|
load_start()
|
||||||
|
await Promise.all(hty_ids.map(async hty_id => {
|
||||||
|
const {r, d, e, statusCode} = await request({
|
||||||
|
url: "/api/v1/clazz/find_all_within_date_range",
|
||||||
|
method: "GET", data: {start_from, end_by, hty_id}
|
||||||
|
})
|
||||||
|
if (r) {
|
||||||
|
const nonRepeatable = normalizeClazzListPayload(d.non_repeatable, `merged_subsidiary_non_repeatable_${hty_id}`);
|
||||||
|
const list = nonRepeatable.filter(x => x.teachers?.val?.users?.vals?.some(u => u.user_id === hty_id));
|
||||||
|
const repeatable = normalizeClazzListPayload(d.repeatable, `merged_subsidiary_repeatable_${hty_id}`);
|
||||||
|
store.subsidiaryClazzByHtyId[hty_id] = {
|
||||||
|
list,
|
||||||
|
repeatList: repeat_prepare(start_from, end_by, repeatable, list)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn("[ClazzQuery] merged subsidiary failed", {
|
||||||
|
e, statusCode, hty_id, start_from, end_by,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
load_done()
|
||||||
|
}
|
||||||
|
|
||||||
async function prepareQS(course_sections?: MultiVals<CourseSection>) {
|
async function prepareQS(course_sections?: MultiVals<CourseSection>) {
|
||||||
for (let i = 0; i < (course_sections?.vals?.length || []); i++) {
|
for (let i = 0; i < (course_sections?.vals?.length || []); i++) {
|
||||||
let { resources, ref_resources, id, resource_note_group, ...rest } = course_sections?.vals[i];
|
let { resources, ref_resources, id, resource_note_group, ...rest } = course_sections?.vals[i];
|
||||||
@@ -506,7 +561,7 @@ export default function useClazz() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
store, query, query_repeats, createOrUpdate, removeCurrent, createInstance, notify, setDakasForClazz, query_for_subsidiaries, query_repeats_for_subsidiaries,
|
store, query, query_repeats, query_merged, query_merged_for_subsidiaries, createOrUpdate, removeCurrent, createInstance, notify, setDakasForClazz, query_for_subsidiaries, query_repeats_for_subsidiaries,
|
||||||
find_clazz_attendance_by_clazz_id, batch_save_clazz_attendance, getAuditLog, queryStudentLessons, queryTeacherDetailStats,
|
find_clazz_attendance_by_clazz_id, batch_save_clazz_attendance, getAuditLog, queryStudentLessons, queryTeacherDetailStats,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user