douyin/src/pages/message/Message.vue
2024-04-02 17:24:18 +08:00

1085 lines
30 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div id="Message" ref="app" :class="createChatDialog ? 'disable-scroll' : ''">
<div class="no-search" v-show="!searching">
<header>
<Icon @click="createChatDialog = true" icon="formkit:add" />
<Icon icon="tabler:camera-selfie" />
<Icon @click="searching = true" icon="tabler:search" />
</header>
<Scroll ref="mainScroll">
<div class="friends pl1r">
<div
class="friend pr1r pl1r"
@click="$nav('/message/chat')"
:key="index"
v-for="(item, index) in friends.all"
>
<div class="avatar" :class="index % 2 === 0 ? 'on-line' : ''">
<img :src="$imgPreview(item.avatar)" alt="" />
</div>
<span>{{ item.name }}</span>
</div>
<div class="friend pr10p">
<img src="../../assets/img/icon/message/setting.png" alt="" />
<span class="ml1r">状态设置</span>
</div>
</div>
<div class="line mt2r"></div>
<div class="messages">
<!-- 粉丝-->
<div class="message" @click="$nav('/message/fans')">
<div class="avatar">
<img src="../../assets/img/icon/msg-icon1.png" alt="" class="head-image" />
</div>
<div class="content">
<div class="left">
<div class="name">
<span>新朋友</span>
</div>
<div class="detail">xxx 关注了你</div>
</div>
<div class="right">
<dy-back class="arrow" mode="gray" img="back" direction="right" />
</div>
</div>
</div>
<!-- 互动消息-->
<div class="message" @click="$nav('/message/all')">
<div class="avatar">
<img src="../../assets/img/icon/msg-icon2.png" alt="" class="head-image" />
</div>
<div class="content">
<div class="left">
<div class="name">
<span>互动消息</span>
</div>
<div class="detail">xxx 赞了你的评论</div>
</div>
<div class="right">
<dy-back class="arrow" mode="gray" img="back" direction="right" />
</div>
</div>
</div>
<!-- 消息-->
<div class="message" @click="$nav('/message/chat')">
<div class="avatar on-line">
<img src="../../assets/img/icon/avatar/2.png" alt="" class="head-image" />
</div>
<div class="content">
<div class="left">
<div class="name">
<span>{{ userinfo.nickname }}</span>
</div>
<div class="detail">
哈哈哈哈哈哈
<div class="point"></div>
10-10
</div>
</div>
<div class="right">
<!-- <div class="not-read"></div>-->
<!-- <img class="camera" src="../../assets/img/icon/close-white.png" alt="">-->
<!-- <img class="arrow" src="../../assets/img/icon/close-white.png" alt="">-->
<div class="badge">12</div>
</div>
</div>
</div>
<!-- 抖音小助手-->
<div class="message" @click="$nav('/message/douyin-helper')">
<div class="avatar">
<img src="../../assets/img/icon/msg-icon5.webp" alt="" class="head-image" />
</div>
<div class="content">
<div class="left">
<div class="name">
<span>抖音小助手</span>
<span class="tag">官方</span>
</div>
<div class="detail">
#今天谁请客呢
<div class="point"></div>
星期四
</div>
</div>
<div class="right">
<div class="not-read"></div>
</div>
</div>
</div>
<!-- 系统通知-->
<div class="message" @click="$nav('/message/system-notice')">
<div class="avatar">
<img src="../../assets/img/icon/msg-icon4.png" alt="" class="head-image" />
</div>
<div class="content">
<div class="left">
<div class="name">
<span>系统通知</span>
<span class="tag">官方</span>
</div>
<div class="detail">
协议修订通知
<div class="point"></div>
08-31
</div>
</div>
<div class="right">
<div class="not-read"></div>
</div>
</div>
</div>
<!-- 求更新-->
<div class="message" @click="$nav('/me/request-update')">
<div class="avatar">
<img src="../../assets/img/icon/msg-icon7.webp" alt="" class="head-image" />
</div>
<div class="content">
<div class="left">
<div class="name">
<span>求更新</span>
<span class="tag">官方</span>
</div>
<div class="detail">
你收到过1次求更新
<div class="point"></div>
10-09
</div>
</div>
<div class="right">
<div class="not-read"></div>
</div>
</div>
</div>
<!-- 任务通知-->
<div class="message" @click="$nav('/message/task-notice')">
<div class="avatar">
<img src="../../assets/img/icon/msg-icon6.webp" alt="" class="head-image" />
</div>
<div class="content">
<div class="left">
<div class="name">
<span>任务通知</span>
<span class="tag">官方</span>
</div>
<div class="detail">
发作品得流量
<div class="point"></div>
05-26
</div>
</div>
<div class="right">
<div class="not-read"></div>
</div>
</div>
</div>
<!-- 直播通知-->
<div class="message" @click="$nav('/message/live-notice')">
<div class="avatar">
<img src="../../assets/img/icon/msg-icon8.webp" alt="" class="head-image" />
</div>
<div class="content">
<div class="left">
<div class="name">
<span>直播通知</span>
<span class="tag">官方</span>
</div>
<div class="detail">
举报结果通知
<div class="point"></div>
05-26
</div>
</div>
<div class="right">
<div class="not-read"></div>
</div>
</div>
</div>
<!-- 钱包通知-->
<div class="message" @click="$nav('/message/money-notice')">
<div class="avatar">
<img src="../../assets/img/icon/msg-icon9.webp" alt="" class="head-image" />
</div>
<div class="content">
<div class="left">
<div class="name">
<span>钱包通知</span>
<span class="tag">官方</span>
</div>
<div class="detail">
卡券发放提醒
<div class="point"></div>
05-26
</div>
</div>
<div class="right">
<div class="not-read"></div>
</div>
</div>
</div>
<NoMore />
<!-- 模板-->
<!-- <div class="message">-->
<!-- <div class="avatar on-line">-->
<!-- <img src="../../assets/img/icon/avatar/2.png" alt="" class="head-image">-->
<!-- </div>-->
<!-- <div class="content">-->
<!-- <div class="left">-->
<!-- <div class="name">-->
<!-- <span>粉丝</span>-->
<!-- <span class="tag">官方</span>-->
<!-- </div>-->
<!-- <div class="detail">-->
<!-- <img class="sent" src="../../assets/img/icon/close-white.png" alt="">-->
<!-- 已送达 sb凌晨 01:15-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="right">-->
<!-- &lt;!&ndash; <div class="not-read"></div>&ndash;&gt;-->
<!-- &lt;!&ndash; <img class="camera" src="../../assets/img/icon/close-white.png" alt="">&ndash;&gt;-->
<!-- &lt;!&ndash; <img class="arrow" src="../../assets/img/icon/close-white.png" alt="">&ndash;&gt;-->
<!-- <div class="badge">12</div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
</div>
</Scroll>
<from-bottom-dialog page-id="Message" v-model="createChatDialog">
<div class="create-chat-wrapper" v-show="!showJoinedChat">
<Search
:isShowRightText="isShowRightText"
@click="isShowRightText = true"
@notice="isShowRightText = false"
@clear="isShowRightText = false"
class="ml2r mr2r"
placeholder="搜索用户"
v-model="createChatSearchKey"
></Search>
<template v-if="createChatSearchKey">
<div class="search-result" v-if="searchFriends.length">
<div
class="search-result-item"
:key="i"
v-for="(item, i) in searchFriends"
@click="handleClick(item)"
>
<img class="left" src="../../assets/img/icon/head-image.jpeg" alt="" />
<div class="right">
<div class="info">
<span class="name">{{ item.name }}</span>
<span class="account">{{ item.account ? '抖音号:' + item.account : '' }}</span>
</div>
<img v-if="item.select" src="../../assets/img/icon/message/checked.png" alt="" />
<img
v-if="!item.select"
src="../../assets/img/icon/message/no-check2.png"
alt=""
/>
</div>
</div>
</div>
<div class="no-result" v-else>
<div class="notice-h1">搜索结果为空</div>
<div class="notice-h2">没有搜索到相关的联系人</div>
</div>
</template>
<template v-else>
<div class="joined-chat" @click="showJoinedChat = true">
<img class="left" src="../../assets/img/icon/people-gray.png" alt="" />
<div class="right">
<span>已加入的群聊</span>
<dy-back direction="right" mode="light"></dy-back>
</div>
</div>
<div class="friend-list">
<div class="index">Z</div>
<div
class="friend-item"
:key="i"
v-for="(item, i) in friends.all"
@click="item.select = !item.select"
>
<img class="left" :src="$imgPreview(item.avatar)" alt="" />
<div class="right">
<span>{{ item.name }}</span>
<Check mode="red" style="height: 20rem; width: 20rem" v-model="item.select" />
</div>
</div>
</div>
</template>
<div class="btn-wrapper">
<div class="btn" :class="selectFriends ? 'primary' : ''">发起聊天</div>
</div>
</div>
<div class="joined-chat-wrapper" v-show="showJoinedChat">
<div class="nav">
<dy-back @click="showJoinedChat = false" mode="light" scale="1.2"></dy-back>
<span>已加入的群聊</span>
<span>&nbsp;</span>
</div>
<div class="chat-list">
<div class="chat-item" :key="i" v-for="(item, i) in 15">
<img class="left" src="../../assets/img/icon/head-image.jpeg" alt="" />
<div class="right">
<div class="title">
<div class="name">
{{ text.length > 20 ? text.substr(0, 20) + '...' : text }}
</div>
<div class="num">(3)</div>
</div>
<dy-back direction="right" mode="light"></dy-back>
</div>
</div>
</div>
<NoMore></NoMore>
</div>
</from-bottom-dialog>
<transition name="fade">
<div class="recommend-dialog" v-if="isShowRecommend">
<div class="dialog-content">
<div class="dialog-header">
<img
style="opacity: 0"
src="../../assets/img/icon/components/gray-close-full2.png"
alt=""
/>
<div class="title">
<span>朋友推荐</span>
<img src="../../assets/img/icon/about-gray.png" alt="" />
</div>
<img
@click="isShowRecommend = false"
src="../../assets/img/icon/components/gray-close-full2.png"
alt=""
/>
</div>
<div class="dialog-body">
<Scroll ref="scroll" @pulldown="loadRecommendData">
<Peoples v-model:list="recommend" :loading="loading" mode="recommend" />
<Loading :is-full-screen="false" v-if="loading" />
<NoMore v-else />
</Scroll>
</div>
</div>
<BaseMask />
</div>
</transition>
<BaseFooter v-bind:init-tab="4" />
</div>
<div class="searching" v-show="searching">
<Search
v-model="searchKey"
right-text="取消"
right-text-color="white"
@notice="searching = false"
:isShowRightText="true"
/>
<div class="more-chat">
<template v-if="searchKey">
<div class="sub-title" v-if="searchFriendsAll.length">
<span>联系人</span>
<div
class="right"
v-if="searchFriendsAll.length > 3"
@click="$nav('/message/more-search', { key: searchKey })"
>
<span>更多联系人</span>
<dy-back mode="gray" img="back" scale=".6" direction="right" />
</div>
</div>
<People
v-for="item in searchFriendsAll.slice(0, 3)"
:key="item.id"
mode="search"
:searchKey="searchKey"
:people="item"
/>
<div class="goto-search-page" @click="$nav('/home/search', { key: searchKey })">
<img class="icon" src="../../assets/img/icon/search-light.png" alt="" />
<div class="right">
<div class="left">
<span
>搜索 <span style="color: yellow">{{ searchKey }}</span></span
>
<span class="second-text-color f12">视频、用户、音乐、话题、地点等</span>
</div>
<dy-back mode="gray" img="back" direction="right" scale=".7" />
</div>
</div>
</template>
<template v-else>
<div class="sub-title">更多聊天</div>
<People v-for="item in moreChat" :key="item.id" :people="item" />
</template>
</div>
</div>
</div>
</template>
<script>
import Search from '../../components/Search'
import FromBottomDialog from '../../components/dialog/FromBottomDialog'
import Check from '../../components/Check'
import { mapState } from 'pinia'
import Peoples from '../people/components/Peoples'
import Scroll from '../../components/Scroll'
import People from '../people/components/People'
import BasePage from '../BasePage'
import { useBaseStore } from '@/store/pinia'
export default {
extends: BasePage,
name: 'Message',
components: {
Scroll,
Search,
FromBottomDialog,
Check,
Peoples,
People
},
data() {
return {
isShowRecommend: false,
searching: false,
searchKey: '',
createChatSearchKey: '',
showJoinedChat: false,
loading: false,
createChatDialog: false,
isShowRightText: false,
text: 'AAAAAAAAA、BBBBBBBBBBBBB、CCCCCCCC',
searchFriends: [],
recommend: [],
moreChat: []
}
},
computed: {
...mapState(useBaseStore, ['friends', 'userinfo']),
selectFriends() {
return this.friends.all.filter((v) => v.select).length
},
searchFriendsAll() {
return this.friends.all.filter((v) => {
return v.name.search(this.searchKey) !== -1 || v.account.search(this.searchKey) !== -1
})
}
},
watch: {
createChatSearchKey(newVal) {
if (newVal) {
//TODO 搜索时仅仅判断是否包含了对应字符串,抖音做了拼音判断的
this.searchFriends = this.friends.all.filter((v) => {
if (v.name.includes(newVal)) return true
return v.account.includes(newVal)
})
} else {
this.searchFriends = []
}
}
},
created() {
console.log('create')
this.recommend = this.$clone(this.friends.all)
this.recommend.map((v) => {
v.type = -2
})
this.moreChat = this.$clone(this.friends.all.slice(0, 3))
},
mounted() {
setTimeout(() => {
// this.isShowRecommend = true
}, 1000)
},
methods: {
handleClick(item) {
item.select = !item.select
this.createChatSearchKey = ''
},
async loadRecommendData() {
if (this.loading) return
this.loading = true
await this.$sleep(500)
this.loading = false
let temp = this.$clone(this.friends.all)
temp.map((v) => {
v.type = -2
})
this.recommend = this.recommend.concat(temp)
}
}
}
</script>
<style scoped lang="less">
@import '../../assets/less/index';
#Message {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
font-size: 14rem;
background: var(--color-message);
color: white;
.no-search {
height: calc(var(--vh, 1vh) * 100);
> header {
padding: 0 20rem;
display: flex;
justify-content: space-between;
align-items: center;
height: var(--common-header-height);
box-sizing: border-box;
position: relative;
font-size: 24rem;
}
.create-chat-wrapper {
min-height: 70vh;
padding-bottom: 60rem;
.joined-chat {
border-bottom: 1px solid var(--line-color);
height: 50rem;
padding: 0 20rem;
display: flex;
align-items: center;
.left {
width: 22rem;
height: 22rem;
margin-left: 10rem;
margin-right: 20rem;
}
.right {
font-size: 14rem;
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
img {
height: 15rem;
}
}
}
.friend-list {
padding: 0 20rem;
.index {
height: 60rem;
line-height: 60rem;
font-size: 14rem;
}
.friend-item {
margin-bottom: 20rem;
display: flex;
align-items: center;
//background: #fff;
&:nth-child(1) {
margin-top: 10rem;
}
.left {
width: 48rem;
height: 48rem;
border-radius: 50%;
margin-right: 10rem;
}
.right {
font-size: 14rem;
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
img {
height: 20rem;
}
}
}
}
.btn-wrapper {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: var(--main-bg);
//background: red;
display: flex;
align-items: center;
justify-content: center;
.btn {
margin-bottom: 20rem;
width: calc(100% - 40rem);
height: 40rem;
display: flex;
align-items: center;
font-size: 14rem;
justify-content: center;
background: #3f445c;
border-radius: 2rem;
&.primary {
background: var(--primary-btn-color);
}
}
}
.search-result {
padding: 0 20rem;
.search-result-item {
margin-bottom: 20rem;
display: flex;
align-items: center;
&:nth-child(1) {
margin-top: 10rem;
}
.left {
width: 48rem;
height: 48rem;
border-radius: 50%;
margin-right: 10rem;
}
.right {
font-size: 14rem;
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
.info {
display: flex;
flex-direction: column;
.name {
font-size: 14rem;
}
.account {
font-size: 13rem;
color: var(--second-text-color);
}
}
img {
height: 20rem;
}
}
}
}
.no-result {
height: 50vh;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
.notice-h1 {
font-size: 16rem;
}
.notice-h2 {
margin-top: 10rem;
font-size: 14rem;
color: var(--second-text-color);
}
}
}
.joined-chat-wrapper {
min-height: 70vh;
.nav {
font-size: 17rem;
padding: 20rem;
display: flex;
justify-content: space-between;
img {
height: 20rem;
}
}
.chat-list {
padding: 0 20rem;
.chat-item {
margin-bottom: 20rem;
display: flex;
align-items: center;
position: relative;
overflow: hidden;
&:nth-last-child(1) {
margin-bottom: 0;
}
&:nth-child(1) {
margin-top: 10rem;
}
.left {
width: 48rem;
height: 48rem;
border-radius: 50%;
margin-right: 10rem;
}
.right {
font-size: 14rem;
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
.title {
box-sizing: border-box;
display: flex;
align-items: center;
.name {
}
.num {
margin-left: 5rem;
color: var(--second-text-color);
}
}
img {
height: 15rem;
}
}
}
}
}
:deep(#BaseHeader .header) {
border-bottom: none;
.left {
opacity: 0;
}
}
.scroll {
height: calc(100% - var(--common-header-height) - var(--footer-height));
padding-top: 10rem;
}
.friends {
overflow-x: scroll;
display: flex;
font-size: 14rem;
.friend {
&:nth-last-child(1) {
img {
margin: 0 10rem;
padding: 17rem;
background: var(--second-btn-color-tran);
width: 30rem;
height: 30rem;
border-radius: 50%;
margin-bottom: 6rem;
}
}
.avatar {
position: relative;
margin-bottom: 6rem;
img {
@width: 64rem;
width: @width;
height: @width;
border-radius: 50%;
}
&.on-line::before {
content: ' ';
border: 4rem solid black;
width: 18rem;
height: 18rem;
background: rgb(115, 254, 73);
border-radius: 50%;
position: absolute;
bottom: 0;
right: 0;
}
}
span {
width: 64rem;
font-size: 12rem;
color: lightgray;
display: block;
text-align: center;
word-break: break-all;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
}
}
.messages {
.message {
display: flex;
align-items: center;
&.top {
background: #353a4f;
}
&:active {
background: rgb(57, 57, 57);
}
.avatar {
position: relative;
.head-image {
margin-left: 20rem;
margin-right: 15rem;
@width: 55rem;
width: @width;
height: @width;
border-radius: 50%;
}
&.on-line::before {
content: ' ';
border: 3rem solid black;
width: 12rem;
height: 12rem;
background: rgb(115, 254, 73);
border-radius: 50%;
position: absolute;
bottom: 0;
right: 15rem;
}
}
.content {
flex: 1;
display: flex;
justify-content: space-between;
@padding: 14rem;
padding: @padding 0 @padding 0;
.left {
.name {
font-size: 14rem;
color: white;
display: flex;
align-items: flex-start;
.tag {
margin-left: 5rem;
font-size: 10rem;
background: var(--second-btn-color-tran);
color: var(--second-text-color);
padding: 2rem 5rem;
border-radius: 2rem;
}
}
.detail {
color: var(--second-text-color);
font-size: 12rem;
margin-top: 4rem;
display: flex;
align-items: center;
.point {
display: inline-block;
margin-left: 8rem;
margin-right: 8rem;
border-radius: 50%;
width: 1.5px;
height: 1.5px;
background: var(--second-text-color);
}
.sent {
width: 10rem;
height: 10rem;
}
}
}
.right {
margin-right: 20rem;
display: flex;
align-items: center;
.arrow {
width: 15rem;
height: 15rem;
}
.camera {
width: 20rem;
height: 20rem;
}
.not-read {
margin-right: 5rem;
}
}
}
}
.not-more {
color: var(--second-text-color);
text-align: center;
padding: 20rem;
}
}
.recommend-dialog {
position: fixed;
z-index: 11;
top: 0;
left: 0;
width: 100vw;
height: calc(var(--vh, 1vh) * 100);
display: flex;
align-items: center;
justify-content: center;
.dialog-content {
position: relative;
z-index: 4;
background: white;
width: 85vw;
height: 80vh;
border-radius: 12rem;
overflow: hidden;
.dialog-header {
color: black;
border-bottom: 1px solid whitesmoke;
padding: var(--page-padding);
display: flex;
align-items: center;
justify-content: space-between;
.title {
display: flex;
align-items: center;
& > img {
margin-left: 3rem;
width: 15rem;
}
}
& > img {
width: 20rem;
}
}
.dialog-body {
padding: var(--page-padding);
padding-top: 0;
height: calc(80vh - 50rem);
overflow: auto;
.scroll {
height: calc(80vh - 50rem);
}
.l-button {
color: white;
}
.name {
color: black !important;
}
:deep(.People .content .left .name) {
color: black !important;
}
}
}
}
}
.searching {
padding: var(--page-padding);
.sub-title {
margin-top: var(--page-padding);
color: var(--second-text-color);
font-size: 12rem;
display: flex;
align-items: center;
justify-content: space-between;
.right {
display: flex;
align-items: center;
}
}
.goto-search-page {
display: flex;
align-items: center;
justify-content: space-between;
padding-top: var(--page-padding);
margin-top: var(--page-padding);
border-top: 1px solid var(--line-color);
.icon {
border-radius: 50%;
padding: 13rem;
background: var(--second-btn-color-tran);
width: 22rem;
height: 22rem;
margin-right: 10rem;
}
.right {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
.left {
display: flex;
flex-direction: column;
justify-content: space-between;
.second-text-color {
margin-top: 5rem;
}
}
}
}
}
}
</style>