CheckInDialog.vue
4.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<template>
<van-popup
:show="show"
@update:show="$emit('update:show', $event)"
round
position="bottom"
:style="{ minHeight: '30%', maxHeight: '80%', width: '100%' }"
>
<div class="p-4">
<div class="flex justify-between items-center mb-3">
<h3 class="font-medium">
<span :class="{ 'text-green-500' : active_tab === 'today' }" @click="active_tab = 'today'">今日打卡</span>
<span v-if="has_history" :class="{ 'text-green-500' : active_tab === 'history' }" @click="active_tab = 'history'">历史打卡</span>
</h3>
<van-icon name="cross" @click="handleClose" />
</div>
<CheckInList :items="active_list" @submit-success="handleListSuccess" />
</div>
</van-popup>
</template>
<script setup>
import { ref, computed, onMounted, provide } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import CheckInList from '@/components/ui/CheckInList.vue'
import { getTaskListAPI } from "@/api/checkin";
// 签到列表
const checkInTypes = ref([]);
const route = useRoute()
const router = useRouter()
const props = defineProps({
/** 弹窗显隐 */
show: { type: Boolean, required: true, default: false },
/** 今日打卡任务(外部传入,可选) */
items_today: { type: Array, default: () => [] },
/** 历史打卡任务(外部传入,可选) */
items_history: { type: Array, default: () => [] }
})
const emit = defineEmits(['update:show', 'check-in-success', 'check-in-data'])
/**
* @var {import('vue').Ref<'today'|'history'>} active_tab
* @description 当前选中的任务标签页:今日或历史。
*/
const active_tab = ref('today')
/**
* @function has_history
* @description 是否存在历史任务(用于显示“历史打卡”标签)。
* @returns {boolean}
*/
const has_history = computed(() => {
const list = Array.isArray(props.items_history) ? props.items_history : []
return list.length > 0
})
/**
* @function active_list
* @description 当前展示的任务列表:优先使用外部传入,未传时回退为组件内部获取的列表。
* @returns {Array}
*/
const active_list = computed(() => {
const today = Array.isArray(props.items_today) ? props.items_today : []
const history = Array.isArray(props.items_history) ? props.items_history : []
if (active_tab.value === 'today') {
return today.length ? today : checkInTypes.value
}
return history
})
/**
* @function refresh_checkin_list
* @description 重新获取打卡任务列表,用于提交成功后更新置灰状态;同时向父组件透出最新数据。
* @returns {Promise<void>}
*/
const refresh_checkin_list = async () => {
const task = await getTaskListAPI()
if (task?.code) {
// 重建本地签到任务列表(当未传入 props.items_today 时用于展示)
checkInTypes.value = (task.data || []).map(item => ({
id: item.id,
name: item.title,
task_type: item.task_type,
is_gray: item.is_gray
}))
// 向父组件透出最新数据,便于父组件自行刷新其持有的数据源
emit('check-in-data', task.data)
}
}
/**
* @function handleListSuccess
* @description 子组件提交成功后,刷新任务列表并通知外部,然后关闭弹窗。
* @returns {Promise<void>}
*/
const handleListSuccess = async () => {
await refresh_checkin_list()
emit('check-in-success')
setTimeout(() => emit('update:show', false), 1500)
}
const handleClose = () => {
emit('update:show', false)
}
onMounted(async () => {
// 当未从外部传入“今日任务”时,回退为组件内部获取的通用任务列表
if (!Array.isArray(props.items_today) || props.items_today.length === 0) {
await refresh_checkin_list()
}
})
// 向子组件提供父级弹框的联动控制方法
provide('parent_popup_control', {
/**
* @function hideParent
* @description 隐藏父级弹框。
* @returns {void}
*/
hideParent: () => emit('update:show', false),
/**
* @function reopenParent
* @description 重新打开父级弹框。
* @returns {void}
*/
reopenParent: () => emit('update:show', true)
})
</script>