hookehuyr

docs: 为多个组件添加JSDoc注释和中文注释

为TaskCascaderFilter、AddTargetDialog、CheckInList等组件添加详细的JSDoc注释
将LiveStreamCard组件的英文注释转换为中文
完善postCountModel组件的类型检查和空值处理
为CheckinDetailPage的关键方法添加详细说明
......@@ -67,7 +67,10 @@ const emit = defineEmits(['update:show', 'confirm'])
// 本地表单字段状态
const localFields = ref([])
// 监听弹窗显示状态、字段配置和初始值的变化
/**
* 监听弹窗显示状态、字段配置和初始值的变化
* @description 弹窗显示时,根据传入的 fields 配置初始化 localFields,并填充 initialValues 中的值
*/
watch([() => props.show, () => props.fields, () => props.initialValues], ([showVal, fieldsVal, initialValuesVal]) => {
if (showVal) {
// 初始化字段,添加 value 属性
......
......@@ -192,6 +192,11 @@ const actions = [
// 没有加删除功能, 那个接口也是不存在的
]
/**
* 开启长按计时器
* @description 设置500ms定时器,触发后激活长按状态并显示操作菜单
* @param {Object} item - 长按的目标对象
*/
const startLongPress = (item) => {
isLongPress.value = false
longPressTimer.value = setTimeout(() => {
......@@ -205,6 +210,10 @@ const startLongPress = (item) => {
}, 500)
}
/**
* 清除长按计时器
* @description 取消未触发的长按定时器
*/
const clearLongPress = () => {
if (longPressTimer.value) {
clearTimeout(longPressTimer.value)
......@@ -212,7 +221,7 @@ const clearLongPress = () => {
}
}
// Touch events
// 触摸事件处理
const onTouchStart = (item) => {
startLongPress(item)
}
......
<!--
* @Date: 2025-12-11 17:26:25
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-12-18 20:57:49
* @LastEditTime: 2026-01-22 17:00:53
* @FilePath: /mlaj/src/components/count/postCountModel.vue
* @Description: 发布作业统计模型(包括感恩次数和感恩对象)
-->
<template>
<div v-if="postData.gratitude_count" class="post-count-model">
<div v-if="postData && postData.gratitude_count" class="post-count-model">
<div class="flex justify-between items-center mb-2">
<div class="text-gray-500">感恩次数: </div>
<div class="font-bold text-gray-600">{{ postData.gratitude_count }} </div>
</div>
<div class="flex justify-between items-center">
<div class="text-gray-500">感恩对象: </div>
<div class="font-bold text-gray-600">{{ postData.gratitude_form_list?.map(item => item.name).join('、') }}</div>
<div class="font-bold text-gray-600">
{{ Array.isArray(postData.gratitude_form_list) ? postData.gratitude_form_list.map(item => item.name).join('、') : '' }}
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { defineProps } from 'vue'
const props = defineProps({
postData: {
type: Object,
default: () => ({})
}
/**
* 帖子数据对象
* @property {number} gratitude_count - 感恩次数
* @property {Array} gratitude_form_list - 感恩对象列表 [{name: string}]
*/
postData: {
type: Object,
default: () => ({})
}
})
</script>
......
......@@ -175,6 +175,11 @@ const onChange = async ({ value, selectedOptions, tabIndex }) => {
}
}
/**
* @description 完成选择
* @param {Object} params
* @param {Array} params.selectedOptions - 选中的选项数组
*/
const onFinish = ({ selectedOptions }) => {
show.value = false
......
......@@ -95,9 +95,25 @@ import dayjs from 'dayjs'
* @property {boolean} [plain] - 是否普通模式,默认 `false`。
*/
const props = defineProps({
/**
* 打卡项列表
* @type {CheckInItem[]}
*/
items: { type: Array, default: () => [] },
/**
* 是否紧凑模式
* @default false
*/
dense: { type: Boolean, default: false },
/**
* 是否启用滚动区域
* @default false
*/
scroll: { type: Boolean, default: false },
/**
* 是否普通模式
* @default false
*/
plain: { type: Boolean, default: false },
})
......
......@@ -2,7 +2,7 @@
* @Author: hookehuyr hookehuyr@gmail.com
* @Date: 2025-11-07 11:00:00
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-12-18 23:11:35
* @LastEditTime: 2026-01-22 17:14:40
* @FilePath: /mlaj/src/components/ui/CourseGroupCascader.vue
* @Description: 教师页面筛选组件(年级/班级/课程),内部管理v-model与options并对外emit change事件
-->
......@@ -26,14 +26,17 @@ const emit = defineEmits(['change'])
// 接收外部传入的默认值
const props = defineProps({
/** 默认选中的课程ID */
defaultCourseId: {
type: [Number, String],
default: null
},
/** 默认选中的年级ID */
defaultMajorGroupId: {
type: [Number, String],
default: null
},
/** 默认选中的班级ID */
defaultMinorGroupId: {
type: [Number, String],
default: null
......@@ -50,7 +53,12 @@ const course_option = ref([])
const major_group_option = ref([])
const minor_group_option = ref([])
// 获取筛选选项列表
/**
* @description 获取筛选选项列表
* 根据传入的 group_id (年级) 和 team_id (班级 - 这里参数名可能需确认 API 定义,但按原代码逻辑)
* @param {number|null} group_id 课程ID? 原代码参数名有些混淆,根据 usage 应该是课程ID
* @param {number|null} team_id 年级ID
*/
const getFilterList = async (group_id = null, team_id = null) => {
const { code, data } = await getTeacherGradeClassListAPI({ group_id, team_id });
if (code === 1) {
......
......@@ -7,7 +7,7 @@
-->
<template>
<div class="relative">
<!-- Live indicator -->
<!-- 直播状态指示器 -->
<div class="absolute top-2 left-2 bg-red-500/90 text-white text-xs px-2 py-1 rounded flex items-center z-10">
<div class="w-2 h-2 bg-white rounded-full mr-1 animate-pulse"></div>
直播中
......@@ -20,10 +20,10 @@
class="w-full h-28 object-cover"
/>
<!-- Gradient overlay -->
<!-- 渐变遮罩 -->
<div class="absolute inset-0 bg-gradient-to-b from-transparent to-black/60"></div>
<!-- Stream info -->
<!-- 直播信息 -->
<div class="absolute bottom-2 left-2 right-2">
<h3 class="text-white text-sm font-medium">{{ stream.title }}{{ stream.subtitle }}</h3>
<div class="flex items-center mt-2">
......@@ -44,7 +44,14 @@
<script setup>
defineProps({
/** 直播流数据对象 */
/**
* 直播流数据对象
* @property {string} id - 直播ID
* @property {string} title - 标题
* @property {string} subtitle - 副标题
* @property {string} imageUrl - 封面图片URL
* @property {number} [viewers] - 观看人数
*/
stream: {
type: Object,
required: true
......
......@@ -289,6 +289,7 @@ const personType = ref('') // 动态表单字段中的person_type
/**
* 更新动态表单字段
* @description 根据选中的作业选项更新动态表单字段配置
* @param {Object} option - 选中的作业选项
*/
const updateDynamicFormFields = (option) => {
......@@ -322,7 +323,12 @@ const updateDynamicFormFields = (option) => {
}
}
// 确认作业选择
/**
* 确认作业选择
* @description 处理作业选择器的确认事件,更新相关状态
* @param {Object} param0 - 选择器返回对象
* @param {Array} param0.selectedOptions - 选中的选项数组
*/
const onConfirmTask = async ({ selectedOptions }) => {
const option = selectedOptions[0]
selectedTaskText.value = option.text
......@@ -386,6 +392,10 @@ const toggleTarget = (item) => {
}
}
/**
* 打开新增计数对象弹窗
* @description 重置编辑状态并显示弹窗
*/
const openAddTargetDialog = () => {
editingTarget.value = null; // 重置编辑对象
isConfirmMode.value = false;
......@@ -393,8 +403,9 @@ const openAddTargetDialog = () => {
}
/**
* 确认添加/编辑对象
* @param {Array} formFields - 表单字段数组
* 确认添加/编辑计数对象
* @description 处理弹窗确认事件,更新本地列表和选中状态
* @param {Array} formFields - 表单字段数组,包含字段ID和值
*/
const confirmAddTarget = async (formFields) => {
// 将表单字段数组转换为对象
......@@ -445,7 +456,9 @@ const confirmAddTarget = async (formFields) => {
}
/**
* 处理对象编辑
* 处理计数对象编辑
* @description 打开弹窗并填充当前对象数据进行编辑
* @param {Object} item - 待编辑的计数对象
*/
const handleTargetEdit = (item) => {
editingTarget.value = item
......@@ -454,7 +467,9 @@ const handleTargetEdit = (item) => {
}
/**
* 处理对象删除
* 处理计数对象删除
* @description 从本地列表和选中列表中移除对象(暂未调用后端接口)
* @param {Object} item - 待删除的计数对象
*/
const handleTargetDelete = async (item) => {
// 屏蔽删除功能, 那个接口也是不存在的
......@@ -478,6 +493,8 @@ const handleTargetDelete = async (item) => {
/**
* 是否禁用提交按钮
* @description 根据打卡类型(计数/普通)和必填项(文本/文件/选中对象)判断是否可提交
* @returns {boolean}
*/
const isSubmitDisabled = computed(() => {
// 1. 校验作业选择
......@@ -504,6 +521,8 @@ const isSubmitDisabled = computed(() => {
/**
* 提交打卡
* @description 校验表单数据(作业选择、计数对象、必填项等),构建提交数据,调用 useCheckin 的 onSubmit 方法
* @returns {Promise<void>}
*/
const handleSubmit = async () => {
// 计数打卡校验
......