useCalendar.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import { ref, computed, watch } from 'vue';
  2. import { getPlanStudyRecord } from '@/api/modules/study';
  3. // @ts-ignore
  4. import CalendarUtil from '@/uni_modules/uni-calendar/components/uni-calendar/util.js';
  5. export interface PracticeStatistics {
  6. list: PracticeData[],
  7. rate: number,
  8. studyDays: number,
  9. total: number,
  10. }
  11. export interface PracticeData {
  12. date: string;
  13. info: number;
  14. questionNum: number;
  15. }
  16. export function useCalendar() {
  17. const calendarUtil = new CalendarUtil();
  18. const globalStudentId = ref(0);
  19. const selected = ref<PracticeData[]>([]);
  20. const statistics = ref<PracticeStatistics>({
  21. list: [],
  22. rate: 0,
  23. studyDays: 0,
  24. total: 0
  25. });
  26. const currentWeekNumber = ref(1); // 用于外部数据计算
  27. const calendarWeekNumber = ref(1); // 专门用于日历组件显示
  28. const currentDate = ref(new Date());
  29. const displayMode = ref<'year' | 'month'>('year');
  30. const loading = ref(false);
  31. // 计算当前周范围
  32. const currentWeekRange = computed(() => {
  33. return calendarUtil.getCurrentWeekRange(currentDate.value, currentWeekNumber.value);
  34. });
  35. // 计算当前月份范围
  36. const currentMonthRange = computed(() => {
  37. return calendarUtil.getCurrentMonthRange(currentDate.value);
  38. });
  39. // 计算是否可以切换到上一周/月/年
  40. const canGoPrev = computed(() => {
  41. const today = new Date();
  42. const current = currentDate.value;
  43. if (displayMode.value === 'year') {
  44. return current.getFullYear() > EARLIEST_YEAR.value;
  45. } else {
  46. // 月份模式:支持跨年,只要不是最早年份1月就可以往前切换
  47. return !(current.getFullYear() === EARLIEST_YEAR.value && current.getMonth() === 0);
  48. }
  49. });
  50. // 计算是否可以切换到下一周/月/年(不能超过当前日期)
  51. const canGoNext = computed(() => {
  52. const today = new Date();
  53. const current = currentDate.value;
  54. if (displayMode.value === 'year') {
  55. return current.getFullYear() < today.getFullYear();
  56. } else {
  57. // 月份模式,不能超过当前月份
  58. return current.getFullYear() < today.getFullYear() ||
  59. (current.getFullYear() === today.getFullYear() && current.getMonth() < today.getMonth());
  60. }
  61. });
  62. // 3. 确保返回的数据格式符合 PracticeData[] 接口
  63. // 4. 统计数据会从返回的练习数据中自动计算,无需额外处理
  64. // ========================================================
  65. const fetchPracticeData = async (year: number, month: number): Promise<PracticeStatistics> => {
  66. console.log('请求数据', year, month, globalStudentId.value)
  67. let practiceData: PracticeStatistics = {
  68. list: [],
  69. rate: 0,
  70. studyDays: 0,
  71. total: 0
  72. };
  73. const { data } = await getPlanStudyRecord({
  74. year,
  75. month
  76. });
  77. practiceData.list = data.list.map(item => ({
  78. date: item.date,
  79. info: item.rate ? Number(item.rate) : 0,
  80. questionNum: item.study ? Number(item.study) : 0
  81. })).sort((a, b) => a.date.localeCompare(b.date));
  82. practiceData.rate = data.rate ? Number(data.rate) : 0;
  83. practiceData.studyDays = data.studyDays ? Number(data.studyDays) : 0;
  84. practiceData.total = data.total ? Number(data.total) : 0;
  85. console.log('response', practiceData)
  86. return practiceData;
  87. };
  88. // 更新日历数据 - 统一的数据更新方法
  89. const updateCalendarData = async (year: number, month: number) => {
  90. if (month !== 0) {
  91. displayMode.value = 'month';
  92. currentDate.value = new Date(year, month - 1, 1);
  93. } else {
  94. displayMode.value = 'year';
  95. currentDate.value = new Date(year, month, 1);
  96. }
  97. console.log(year, month)
  98. console.log('currentDate', currentDate.value)
  99. loading.value = true;
  100. try {
  101. // 请求数据
  102. const practiceData = await fetchPracticeData(year, month);
  103. // 更新状态
  104. selected.value = practiceData.list
  105. statistics.value = practiceData;
  106. } finally {
  107. loading.value = false;
  108. }
  109. };
  110. // 切换到上一个月
  111. const goToPrevMonth = async () => {
  112. if (!canGoPrev.value) return;
  113. const currentMonth = currentDate.value.getMonth();
  114. const targetMonth = currentMonth === 0 ? 12 : currentMonth; // 如果当前是1月,目标月份是12月
  115. const targetYear = currentMonth === 0 ? currentDate.value.getFullYear() - 1 : currentDate.value.getFullYear();
  116. const prevDate = new Date(targetYear, targetMonth - 1, 1);
  117. currentDate.value = prevDate;
  118. await updateCalendarData(targetYear, targetMonth);
  119. };
  120. // 切换到下一个月
  121. const goToNextMonth = async () => {
  122. if (!canGoNext.value) return;
  123. const currentMonth = currentDate.value.getMonth();
  124. const targetMonth = currentMonth === 11 ? 1 : currentMonth + 2; // 如果当前是12月,目标月份是1月
  125. const targetYear = currentMonth === 11 ? currentDate.value.getFullYear() + 1 : currentDate.value.getFullYear();
  126. const nextDate = new Date(targetYear, targetMonth - 1, 1);
  127. currentDate.value = nextDate;
  128. await updateCalendarData(targetYear, targetMonth);
  129. };
  130. // 根据年份跳转
  131. const goToYear = async (year: number) => {
  132. await updateCalendarData(year, 0);
  133. };
  134. // 根据年份和月份跳转
  135. const goToYearMonth = async (year: number, month: number) => {
  136. await updateCalendarData(year, month);
  137. };
  138. // 生成可以选择的年份列表,默认去年+今年
  139. const yearList = computed(() => {
  140. const today = new Date();
  141. const currentYear = today.getFullYear();
  142. return [
  143. {
  144. label: currentYear - 1,
  145. value: currentYear - 1
  146. },
  147. {
  148. label: currentYear,
  149. value: currentYear
  150. }
  151. ];
  152. })
  153. // 配置变量:最早可访问的年份
  154. const EARLIEST_YEAR = computed(() => {
  155. return yearList.value[0].value;
  156. });
  157. // 获取当前年份
  158. const currentYear = computed(() => currentDate.value.getFullYear());
  159. // 获取当前月份
  160. const currentMonth = computed(() => currentDate.value.getMonth() + 1);
  161. // 初始化下拉菜单数据
  162. const initializeFormData = () => {
  163. const today = new Date();
  164. const currentYearToday = today.getFullYear();
  165. return {
  166. year: currentYearToday.toString(),
  167. month: '', // 默认不选择月份
  168. };
  169. };
  170. // 初始化数据 - 默认按年份模式初始化
  171. const init = async (studentId: number) => {
  172. const today = new Date();
  173. globalStudentId.value = studentId;
  174. await updateCalendarData(today.getFullYear(), 0);
  175. };
  176. return {
  177. // 数据
  178. calendarUtil,
  179. selected,
  180. statistics,
  181. currentWeekNumber,
  182. calendarWeekNumber,
  183. currentDate,
  184. displayMode,
  185. currentWeekRange,
  186. currentMonthRange,
  187. // 状态
  188. canGoPrev,
  189. canGoNext,
  190. loading,
  191. // 计算属性
  192. currentYear,
  193. currentMonth,
  194. // 配置
  195. EARLIEST_YEAR,
  196. yearList,
  197. // 方法
  198. updateCalendarData,
  199. goToPrevMonth,
  200. goToNextMonth,
  201. goToYear,
  202. goToYearMonth,
  203. initializeFormData,
  204. init
  205. };
  206. }