240 lines
6.7 KiB
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>
|