123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- <template>
- <div ref="headerRef" class="header">
- <h3>我的房间({{ roomStore.list.length }})</h3>
- <a-input
- v-model:value="keyword"
- placeholder="搜索房间"
- class="room-search"
- allow-clear
- >
- <template #prefix><search-outlined class="room-search-icon" /></template>
- </a-input>
- </div>
- <DataList
- :data-source="roomList.filter(room => room !== addMarked)"
- :keyword="keyword"
- name="作品"
- >
- <template #undata>
- <a-button type="primary" shape="round" size="middle" @click="editRoom()">
- 创建房间
- </a-button>
- </template>
- <a-list
- :grid="{ gutter: 20, xl: 5, lg: 4, md: 3, sm: 2, xs: 1, column: 5 }"
- :data-source="roomList"
- >
- <template #renderItem="{ item }">
- <a-list-item>
- <RoomSign
- v-if="item !== addMarked"
- :room="item"
- @web-sync="webSyncRoom(item)"
- @delete="deleteRoom(item)"
- @share="miniSyncRoom(item)"
- @mini-sync="miniSyncRoom(item, 'leader')"
- @edit="editRoom(item)"
- />
- <a-card v-else class="add-room" hoverable @click="editRoom()">
- <a-button shape="circle" class="button" type="primary">
- <plus-outlined class="add-room-icon" />
- </a-button>
- <p>创建作品</p>
- </a-card>
- </a-list-item>
- </template>
- </a-list>
- </DataList>
- <teleport v-if="!headerVisible" to="#app">
- <div class="content-layout goto-layer">
- <div
- class="goto-top"
- @click="contentRef?.scroll({ left: 0, top: 0, behavior: 'smooth' })"
- >
- <vertical-align-top-outlined />
- </div>
- </div>
- </teleport>
- </template>
- <script setup lang="ts">
- import { useRoomStore } from '@/store'
- import { ref, computed, createVNode } from 'vue'
- import { message, Modal } from 'ant-design-vue'
- import { copyText } from '@/shared'
- import { renderModal } from '@/helper'
- import { app } from '@/main'
- import { useVisible } from '@/hook'
- import { contentRef } from '@/App.vue'
- import EditRoom from './edit-room'
- import RoomSign from './sign.vue'
- import Share from './modal/share.vue'
- import MiniSync from './modal/mini-sync.vue'
- import DataList from '@/components/data-list/index.vue'
- import type { Room } from '@/store'
- defineOptions({ name: 'RoomList' })
- const addMarked = Symbol('add-room')
- const roomStore = useRoomStore()
- roomStore.fetchList()
- const keyword = ref('')
- const roomList = computed(() => [addMarked, ...roomStore.filter(keyword.value)])
- const deleteRoom = (room: Room) => {
- Modal.confirm({
- content: '删除后无法恢复,是否确认?',
- title: '删除作品',
- width: '400px',
- okText: '删除',
- icon: null,
- cancelText: '取消',
- onOk: () => roomStore.delete(room)
- })
- }
- const shareRoom = async (room: Room) => {
- await roomStore.setRoomMiniCode(room)
- Modal.confirm({
- content: createVNode(Share, { room }),
- title: '分享',
- icon: null,
- width: '500px',
- okText: '复制链接',
- appContext: app._context,
- cancelText: '取消',
- onOk: async (room: Room) => {
- await copyText(roomStore.getShareUrl(room))
- message.success('链接复制成功')
- }
- })
- }
- const miniSyncRoom = async (room: Room, key?: 'leader') => {
- let miniCode: string
- if (key === 'leader') {
- await roomStore.setLeaderRoomMiniCode(room)
- miniCode = room.leaderMiniCode!
- } else {
- await roomStore.setRoomMiniCode(room)
- miniCode = room.miniCode!
- }
- Modal.info({
- content: createVNode(MiniSync, { miniCode }),
- title: '小程序带看',
- width: '500px',
- icon: null,
- okText: '确定',
- cancelText: null
- })
- }
- const webSyncRoom = (room: Room) => window.open(roomStore.getShareUrl(room))
- const editRoom = async (room?: Room) => {
- if (room) {
- await roomStore.setRoomScenes(room)
- }
- renderModal(EditRoom, {
- room,
- onSave(actionRoom) {
- if (room) {
- roomStore.update(actionRoom)
- } else {
- roomStore.insert(actionRoom)
- }
- }
- })
- }
- const headerRef = ref<HTMLElement>()
- const headerVisible = useVisible({
- target: headerRef,
- parent: contentRef,
- bound: -140
- })
- </script>
- <style scoped lang="scss">
- .header {
- padding: 0 30px;
- height: 80px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- background-color: #fff;
- margin: 30px 0;
- .room-search {
- width: 290px;
- height: 40px;
- border-radius: 20px;
- }
- .room-search-icon {
- color: #cfd0d3;
- }
- }
- .add-room {
- height: 321px;
- cursor: pointer;
- display: flex;
- align-items: center;
- justify-content: center;
- .button {
- width: 60px;
- height: 60px;
- background: linear-gradient(144deg, #00aefb 0%, #0076f6 100%);
- }
- .add-room-icon {
- font-size: 24px;
- }
- p {
- font-size: 14px;
- color: #333;
- margin-top: 10px;
- }
- }
- .goto-layer {
- position: fixed;
- left: 50%;
- transform: translateX(-50%);
- pointer-events: none;
- }
- .goto-top {
- pointer-events: all;
- right: 20px;
- bottom: 20px;
- background-color: #fff;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 8px;
- width: 60px;
- height: 60px;
- font-size: 24px;
- color: #747575;
- position: absolute;
- opacity: 0.5;
- transition: opacity 0.3s ease;
- cursor: pointer;
- &:hover {
- opacity: 1;
- }
- }
- </style>
- <style>
- .room-search,
- .room-search input {
- background: #f7f8fa;
- }
- </style>
|