2026-01-19 18:03:45 +08:00
|
|
|
|
<script setup lang="ts">
|
2026-01-20 10:58:42 +08:00
|
|
|
|
import { debounce } from '@sa/utils'
|
2026-01-19 18:03:45 +08:00
|
|
|
|
import { NCard, NDatePicker, NForm, NFormItemGi, NGrid, NInput, NInputNumber } from 'naive-ui'
|
2026-01-20 10:58:42 +08:00
|
|
|
|
import { ref, useTemplateRef, watch } from 'vue'
|
|
|
|
|
|
|
|
|
|
|
|
const props = defineProps<{
|
|
|
|
|
|
modelValue: {
|
|
|
|
|
|
name: string
|
|
|
|
|
|
startTime: number | null
|
|
|
|
|
|
endTime: number | null
|
|
|
|
|
|
groupCount: number
|
|
|
|
|
|
teamCount: number
|
|
|
|
|
|
}
|
|
|
|
|
|
}>()
|
|
|
|
|
|
|
|
|
|
|
|
const emit = defineEmits(['update:modelValue'])
|
2026-01-19 18:03:45 +08:00
|
|
|
|
|
|
|
|
|
|
const formRef = useTemplateRef('formRef')
|
|
|
|
|
|
|
2026-01-20 10:58:42 +08:00
|
|
|
|
const formData = ref({ ...props.modelValue })
|
|
|
|
|
|
|
|
|
|
|
|
// 修复死循环:添加值对比逻辑
|
|
|
|
|
|
watch(() => props.modelValue, (val) => {
|
|
|
|
|
|
if (JSON.stringify(val) !== JSON.stringify(formData.value)) {
|
|
|
|
|
|
formData.value = { ...val }
|
|
|
|
|
|
}
|
|
|
|
|
|
}, { deep: true })
|
|
|
|
|
|
|
|
|
|
|
|
// 添加防抖:300ms 延迟,避免频繁触发父组件更新
|
|
|
|
|
|
const handleUpdate = debounce((val: typeof formData.value) => {
|
|
|
|
|
|
emit('update:modelValue', { ...val })
|
|
|
|
|
|
}, 300)
|
|
|
|
|
|
|
|
|
|
|
|
watch(formData, (val) => {
|
|
|
|
|
|
handleUpdate(val)
|
|
|
|
|
|
}, { deep: true })
|
2026-01-19 18:03:45 +08:00
|
|
|
|
|
|
|
|
|
|
defineExpose({
|
|
|
|
|
|
formRef,
|
|
|
|
|
|
formData,
|
|
|
|
|
|
})
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
|
<NCard :bordered="false" class="rounded-xl shadow-sm">
|
|
|
|
|
|
<div class="mb-4 flex items-center gap-2 border-l-4 border-blue-600 pl-3">
|
|
|
|
|
|
<span class="text-base font-bold">基础活动信息</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<NForm ref="formRef" label-placement="top" :show-feedback="false">
|
|
|
|
|
|
<NGrid :x-gap="24" :y-gap="24" cols="1 s:2 m:4 l:5" responsive="screen">
|
|
|
|
|
|
<NFormItemGi span="1" label="比赛名称">
|
|
|
|
|
|
<NInput v-model:value="formData.name" placeholder="请输入比赛名称" />
|
|
|
|
|
|
</NFormItemGi>
|
|
|
|
|
|
|
|
|
|
|
|
<NFormItemGi label="开始时间">
|
|
|
|
|
|
<NDatePicker
|
|
|
|
|
|
v-model:value="formData.startTime" type="datetime" clearable class="w-full"
|
|
|
|
|
|
placeholder="年 / 月 / 日 --:--"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</NFormItemGi>
|
|
|
|
|
|
|
|
|
|
|
|
<NFormItemGi label="结束时间">
|
|
|
|
|
|
<NDatePicker
|
|
|
|
|
|
v-model:value="formData.endTime" type="datetime" clearable class="w-full"
|
|
|
|
|
|
placeholder="年 / 月 / 日 --:--"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</NFormItemGi>
|
|
|
|
|
|
|
2026-01-20 10:58:42 +08:00
|
|
|
|
<NFormItemGi label="参赛队伍总数">
|
|
|
|
|
|
<NInputNumber
|
|
|
|
|
|
v-model:value="formData.groupCount"
|
|
|
|
|
|
class="w-full"
|
|
|
|
|
|
:min="1"
|
|
|
|
|
|
:max="999"
|
|
|
|
|
|
:precision="0"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<span class="text-xs text-gray-400">(对)</span>
|
2026-01-19 18:03:45 +08:00
|
|
|
|
</NFormItemGi>
|
|
|
|
|
|
|
|
|
|
|
|
<NFormItemGi label="单组队伍">
|
2026-01-20 10:58:42 +08:00
|
|
|
|
<NInputNumber
|
|
|
|
|
|
v-model:value="formData.teamCount"
|
|
|
|
|
|
class="w-full"
|
|
|
|
|
|
:min="1"
|
|
|
|
|
|
:max="formData.groupCount"
|
|
|
|
|
|
:precision="0"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<span class="text-xs text-gray-400">(对)</span>
|
2026-01-19 18:03:45 +08:00
|
|
|
|
</NFormItemGi>
|
|
|
|
|
|
</NGrid>
|
|
|
|
|
|
</NForm>
|
|
|
|
|
|
</NCard>
|
|
|
|
|
|
</template>
|