mcwl-pc/app/components/planet-item.vue

240 lines
6.7 KiB
Vue

<script setup lang="ts">
import { EllipsisVertical, User } from 'lucide-vue-next'
import { defineEmits, defineProps } from 'vue'
import { useRouter } from 'vue-router'
import EditPlanet from './EditPlanet.vue'
const props = defineProps<{
item: PlanetItem
type: 'myCreate' | 'myJoin' | 'all'
}>()
const emit = defineEmits<{
(e: 'click', id: number): void
(e: 'refresh'): void
}>()
const router = useRouter()
const message = useMessage()
const isDelete = ref(false)
interface PlanetItem {
id: number
imageUrl: string
publishNum: number
communityName: string
avatar: string
nickName: string
createDay: number
description: string
price: number | null
userType: number
}
const showEditPlanet = ref(false)
const menuItems = computed(() => {
const items = [
{
label: '分享星球',
action: () => {
const url = window.location.href
navigator.clipboard.writeText(url)
message.success('链接已复制到剪贴板')
},
},
{
label: '退出星球',
action: async () => {
isDelete.value = true
},
},
]
if (props.type === 'myCreate') {
items.splice(1, 0, {
label: '星球设置',
action: () => {
showEditPlanet.value = true
},
})
}
if (props.item.userType !== 0) {
items.splice(1, 0, {
label: '成员管理',
action: () => window.open(`/planetMember?communityId=${props.item.id}&tenantId=${props.item.userId}`, '_blank'),
})
}
return items
})
async function onDelete() {
try {
const res = await request.post('/community/quit', { communityId: props.item.id, tenantId: props.item.userId })
if (res.code === 200) {
message.success('退出成功!')
emit('refresh')
isDelete.value = false
}
}
catch (error: any) {
if (error.code !== 12202) {
message.error('退出失败,请重新退出!')
}
}
}
const showDropdown = ref(false)
let timeoutId: number | null = null
function showMenu() {
if (timeoutId)
clearTimeout(timeoutId)
showDropdown.value = true
}
function hideMenu() {
timeoutId = setTimeout(() => {
showDropdown.value = false
}, 100)
}
function handleMenuClick(e: Event) {
e.stopPropagation() // 防止触发 goDetail
}
function handleSuccess() {
emit('refresh')
}
function goDetail(item: any) {
if (item.isJoin === 1) {
router.push(`/public-planet-detail?communityId=${item.id}&tenantId=${item.tenantId}`)
}
else {
router.push(`/planet-detail?communityId=${item.id}&tenantId=${item.tenantId}`)
}
}
</script>
<template>
<div>
<div class="bg-white rounded-lg shadow-sm flex p-4 cursor-pointer hover:shadow-[0_4px_14px_0_rgba(0,0,0,0.1)]" @click="goDetail(item)">
<div class="w-[161px] h-[161px] relative rounded-lg">
<img class="w-full h-full object-cover rounded-lg" :src="item.imageUrl" alt="">
<span class="absolute bottom-2 left-2 text-white text-xs">{{ item.publishNum || 0 }}人已经加入</span>
</div>
<div class="flex flex-col gap-2 px-4 flex-1 justify-between">
<div class="flex flex-col gap-2">
<div class="flex items-center justify-between">
<div class="text-base font-bold flex-1 truncate">
{{ item.communityName }}
</div>
<div v-if="props.type === 'myCreate'" class="relative" @click="handleMenuClick">
<div
class="cursor-pointer p-1 hover:bg-gray-100 rounded-full"
@mouseenter="showMenu"
@mouseleave="hideMenu"
>
<User class="w-4 h-4" />
</div>
<!-- 下拉菜单 -->
<div
v-if="showDropdown"
class="absolute right-0 top-full mt-1 bg-white border border-[#e5e6eb] rounded-lg py-2 min-w-[120px] z-999 shadow-[0_4px_14px_0_rgba(0,0,0,0.1)]"
@mouseenter="showMenu"
@mouseleave="hideMenu"
>
<div
v-for="item in menuItems"
:key="item.label"
class="px-4 py-2 text-sm hover:bg-gray-100 cursor-pointer"
@click="item.action"
>
{{ item.label }}
</div>
</div>
</div>
<div v-if="props.type === 'myJoin'" class="relative" @click="handleMenuClick">
<div
class="cursor-pointer p-1 hover:bg-gray-100 rounded-full"
@mouseenter="showMenu"
@mouseleave="hideMenu"
>
<EllipsisVertical class="w-6 h-4 rotate-90" />
</div>
<!-- 下拉菜单 -->
<div
v-if="showDropdown"
class="absolute right-0 top-full mt-1 bg-white border border-[#e5e6eb] rounded-lg py-2 min-w-[120px] z-10 shadow-[0_4px_14px_0_rgba(0,0,0,0.1)]"
@mouseenter="showMenu"
@mouseleave="hideMenu"
>
<div
v-for="item in menuItems"
:key="item.label"
class="px-4 py-2 text-sm hover:bg-gray-100 cursor-pointer"
@click="item.action"
>
{{ item.label }}
</div>
</div>
</div>
</div>
<div class="flex items-center gap-2 text-xs text-[#878d95]">
<img class="w-[20px] h-[20px] rounded-full" :src="item.avatar" alt="">
<div>
{{ item.nickName }}
</div>
<div>创建{{ item.createDay || 0 }}天</div>
</div>
<div class="text-sm text-[#4a5563] line-clamp-3">
{{ item.description }}
</div>
</div>
<div class="text-[#fc4141]">
<div v-if="item.price">
<span class="text-base font-bold mr-1">
{{ item.price }}
</span>
<span class="text-xs">
</span>
</div>
<div v-else>
</div>
</div>
</div>
</div>
<n-modal
v-model:show="isDelete"
:mask-closable="false"
preset="dialog"
title="提示!"
content="退出后将无法查看/操作该星球的内容,是否确认退出该星球"
negative-text=""
positive-text="退"
@negative-click="isDelete = false"
@positive-click="onDelete"
/>
<EditPlanet
v-model:show="showEditPlanet"
:community-id="props.item.id"
:tenant-id="props.item.userId"
@success="handleSuccess"
/>
</div>
</template>
<style scoped>
.line-clamp-3 {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
</style>