CheckinTargetList.vue 5.53 KB
<!--
 * @Date: 2025-12-16 11:44:27
 * @LastEditors: hookehuyr hookehuyr@gmail.com
 * @LastEditTime: 2025-12-16 14:17:38
 * @FilePath: /mlaj/src/components/count/CheckinTargetList.vue
 * @Description: 打卡动态对象列表组件
-->
<template>
    <div class="mb-4">
        <div class="flex justify-between items-center mb-2 mx-2">
            <div class="flex items-center gap-2">
                <div class="text-sm font-bold text-gray-700">{{ dynamicFieldText }}对象</div>
                <div class="text-xs text-gray-400 font-normal scale-90 origin-left">(长按可编辑/删除)</div>
            </div>
            <van-button size="small" type="primary" plain icon="plus" @click="onAdd" class="!h-7">添加</van-button>
        </div>

        <div class="bg-gray-50 rounded-lg p-2">
            <div class="flex flex-wrap gap-2">
                <template v-if="targetList.length > 0">
                    <div v-for="(item, index) in targetList" :key="index"
                        class="px-4 py-1.5 rounded-full text-sm transition-colors duration-200 border cursor-pointer select-none relative"
                        :style="[
                            selectedTargets.some(t => t.id === item.id) ? {
                                backgroundColor: '#4caf50',
                                color: '#ffffff',
                                borderColor: '#4caf50'
                            } : {
                                backgroundColor: '#ffffff',
                                color: '#4b5563',
                                borderColor: '#e5e7eb'
                            },
                            {
                                '-webkit-touch-callout': 'none',
                                '-webkit-user-select': 'none',
                                'user-select': 'none'
                            }
                        ]"
                        @contextmenu.prevent
                        @click="onClick(item)"
                        @touchstart="onTouchStart(item)"
                        @touchend="onTouchEnd"
                        @touchmove="onTouchMove"
                        @mousedown="onMouseDown(item)"
                        @mouseup="onMouseUp"
                        @mouseleave="onMouseUp"
                    >
                        {{ item.name }}
                    </div>
                </template>
                <div v-else class="w-full text-center py-4 text-gray-400 text-sm">
                    暂无{{ dynamicFieldText }}对象,请点击上方添加按钮
                </div>
            </div>
        </div>

        <!-- 操作菜单 -->
        <van-action-sheet
            v-model:show="showActionSheet"
            :actions="actions"
            cancel-text="取消"
            close-on-click-action
            @select="onSelectAction"
        />
    </div>
</template>

<script setup>
import { ref } from 'vue'
import { showConfirmDialog } from 'vant'

/**
 * 计数对象列表组件
 * @description 展示可供选择的计数对象列表,支持选择和添加
 */

const props = defineProps({
    /**
     * 动态字段文本 (e.g. "感恩", "念佛")
     */
    dynamicFieldText: {
        type: String,
        default: '计数'
    },
    /**
     * 所有可用的对象列表
     */
    targetList: {
        type: Array,
        default: () => []
    },
    /**
     * 当前选中的对象列表
     */
    selectedTargets: {
        type: Array,
        default: () => []
    }
})

const emit = defineEmits(['add', 'toggle', 'edit', 'delete'])

/**
 * 点击添加按钮
 */
const onAdd = () => {
    emit('add')
}

// 长按相关逻辑
const longPressTimer = ref(null)
const isLongPress = ref(false)
const showActionSheet = ref(false)
const currentItem = ref(null)

const actions = [
    { name: '编辑', color: '#1989fa', action: 'edit' },
    { name: '删除', color: '#ee0a24', action: 'delete' }
]

const startLongPress = (item) => {
    isLongPress.value = false
    longPressTimer.value = setTimeout(() => {
        isLongPress.value = true
        currentItem.value = item
        showActionSheet.value = true
        // 震动反馈 (如果设备支持)
        if (navigator.vibrate) {
            navigator.vibrate(50)
        }
    }, 500)
}

const clearLongPress = () => {
    if (longPressTimer.value) {
        clearTimeout(longPressTimer.value)
        longPressTimer.value = null
    }
}

// Touch events
const onTouchStart = (item) => {
    startLongPress(item)
}

const onTouchEnd = () => {
    clearLongPress()
}

const onTouchMove = () => {
    clearLongPress()
}

// Mouse events (for PC debugging)
const onMouseDown = (item) => {
    startLongPress(item)
}

const onMouseUp = () => {
    clearLongPress()
}

/**
 * 点击项
 * @param {Object} item
 */
const onClick = (item) => {
    // 如果是长按触发的结束,不执行点击
    if (isLongPress.value) {
        // 重置状态
        setTimeout(() => {
            isLongPress.value = false
        }, 0)
        return
    }
    emit('toggle', item)
}

/**
 * 选中操作
 */
const onSelectAction = (action) => {
    if (action.action === 'edit') {
        emit('edit', currentItem.value)
    } else if (action.action === 'delete') {
        confirmDelete()
    }
}

// 删除相关
const confirmDelete = () => {
    if (!currentItem.value) return

    showConfirmDialog({
        title: '确认删除',
        message: `确定要删除"${currentItem.value.name}"吗?`,
    })
        .then(() => {
            emit('delete', currentItem.value)
        })
        .catch(() => {
            // on cancel
        })
}
</script>