123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- <template>
- <div class="search-list">
- <div class="user-search">
- <van-search
- v-model="username"
- show-action
- placeholder="search"
- @update:model-value="userChange"
- @clear="isSearching = false"
- >
- <template #action>
- <van-popover
- v-model:show="showPopover"
- :actions="actions"
- placement="bottom-end"
- @select="selectAction">
- <template #reference>
- <div style="padding-right: 6px">编辑</div>
- </template>
- </van-popover>
- </template>
- </van-search>
- </div>
- <div class="user-list-warp">
- <template v-if="isSearching">
- <template v-if="searchedUserList.length > 0">
- <div class="search-title">已添加的用户</div>
- <ul class="user-list">
- <li class="item" :key="item.id"
- v-for="item in searchedUserList" @click="selectUser(item)">
- <div class="common-pic">{{ item.friendName.charAt(0) }}</div>
- <div class="username">{{ item.friendName }}</div>
- </li>
- </ul>
- </template>
- <template v-if="searchedGlobalUserList.length > 0">
- <div class="search-title">全局搜索到的用户</div>
- <ul class="user-list">
- <li class="item" :key="item.id"
- v-for="item in searchedGlobalUserList" @click="addSearchedUser(item)">
- <div class="common-pic">{{ item.username.charAt(0) }}</div>
- <div class="username">{{ item.username }}</div>
- </li>
- </ul>
- </template>
- <div class="message" v-if="searchedUserList.length === 0 && searchedGlobalUserList.length === 0">没有数据</div>
- </template>
- <ul v-else class="user-list">
- <li class="item"
- :class="{active: currentUser.friendId===item.friendId && currentUser.friendName===item.friendName}"
- :key="item.id"
- v-for="item in store.state.userList" @click="selectUser(item)">
- <div class="common-pic">{{ item.friendName.charAt(0) }}</div>
- <div class="username">{{ item.friendName }}</div>
- <div class="message-num" v-if="item.noReadNum">{{ item.noReadNum }}</div>
- </li>
- </ul>
- </div>
- <van-popup v-model:show="show" class="common-pop">
- <van-icon name="close" class="close" @click="show=false"/>
- <div class="title">{{ currentAction.text }}</div>
- <div class="form">
- <van-cell-group inset>
- <van-field v-model="name" :label="currentAction.label"/>
- </van-cell-group>
- </div>
- <div class="footer" @click="submit">确定</div>
- </van-popup>
- </div>
- </template>
- <script lang="ts">
- import {defineComponent, reactive, toRefs, onMounted} from "vue";
- import {addFriend, addGroup, findUser, getFriends, noReadNum} from "../../../../api"
- import {useStore} from 'vuex'
- import {Obj, StrNumObj} from "../../../../interface"
- import {Toast} from "vant"
- interface ActionObj {
- type: number,
- key: string,
- text: string,
- label: string
- }
- interface State {
- username: string,
- showPopover: boolean,
- actions: ActionObj[],
- currentAction: StrNumObj,
- name: string,
- show: boolean,
- currentUser: StrNumObj,
- searchedUserList: Obj[],
- searchedGlobalUserList: Obj[],
- isSearching: boolean,
- timer: any,
- }
- export default defineComponent({
- setup() {
- const state = reactive<State>({
- username: '',
- showPopover: false,
- actions: [
- {type: 1, key: 'friendName', text: '添加好友', label: '用户名:'},
- {type: 2, key: 'groupName', text: '创建群', label: '群名字:'},
- ],
- currentAction: {},
- name: '',
- show: false,
- currentUser: {},
- searchedUserList: [],
- searchedGlobalUserList: [],
- isSearching: false,
- timer: 0,
- })
- const store = useStore()
- const userChange = () => {
- if (state.username) {
- state.isSearching = true
- state.searchedUserList = store.state.userList.filter((item: Obj) => item.friendName.includes(state.username))
- } else {
- state.isSearching = false
- state.searchedUserList = []
- }
- clearTimeout(state.timer)
- state.timer = setTimeout(() => {
- state.searchedGlobalUserList = []
- if (state.username.length >= 6 && store.state.userList.every((item: Obj) => item.friendName !== state.username)) {
- store.commit('setIsSearching', true)
- findUser({username: state.username}).then(({data}) => {
- state.searchedGlobalUserList = [data]
- }).finally(() => {
- store.commit('setIsSearching', false)
- })
- }
- }, 1000)
- }
- const addSearchedUser = async (item: StrNumObj) => {
- if (item.id === store.state.userInfo.id) {
- return Toast('不能添加自己')
- }
- await addFriend({id: item.id})
- state.username = ''
- state.isSearching = false
- let obj = {
- isGroup: 1,
- userId: store.state.userInfo.id,
- friendId: item.id,
- friendName: item.username
- }
- store.state.userList.unshift(obj)
- selectUser(obj)
- }
- const selectAction = (action: StrNumObj) => {
- state.currentAction = action
- state.show = true
- state.name = ''
- }
- const getUserList = async () => {
- if (store.state.userInfo.token) {
- const {data} = await getFriends()
- store.state.userList = data
- }
- }
- const getNoReadNum = async (item: StrNumObj) => {
- await noReadNum({
- fromId: item.userId,
- toId: item.friendId,
- messageType: item.isGroup
- })
- }
- const selectUser = (item: StrNumObj) => {
- state.currentUser = item
- state.username = ''
- state.isSearching = false
- item.noReadNum = 0
- getNoReadNum(item)
- store.commit('setChatUserInfo', item)
- store.commit('setIsShowRight', true)
- store.commit('setIsShowChat', true)
- store.commit('setIsShowUserInfo', false)
- store.commit('setIsShowGroupInfo', false)
- }
- const submit = async () => {
- if (!state.name.trim()) {
- return Toast(state.currentAction.type === 1 ? '请输入用户名' : '请输入群名字')
- }
- if (state.currentAction.type === 1) {
- if (state.name === store.state.userInfo.username) {
- return Toast('不能添加自己')
- }
- if (store.state.userList.some((item: Obj) => item.friendName === state.name)) {
- return Toast(state.name + '已存在')
- }
- Toast.loading('提交中...')
- let {data} = await findUser({username: state.name})
- await addFriend({id: data.id})
- let obj = {
- isGroup: 1,
- userId: store.state.userInfo.id,
- friendId: data.id,
- friendName: data.username
- }
- store.state.userList.unshift(obj)
- selectUser(obj)
- Toast.success('添加成功')
- } else {
- if (store.state.userList.some((item: Obj) => item.friendName === state.name)) {
- return Toast(state.name + '已存在')
- }
- Toast.loading('提交中...')
- await addGroup({groupName: state.name})
- getUserList()
- Toast.success('创建成功')
- }
- state.show = false
- }
- onMounted(() => {
- getUserList()
- })
- return {
- ...toRefs(state),
- store,
- userChange,
- addSearchedUser,
- selectAction,
- selectUser,
- submit
- }
- }
- })
- </script>
- <style lang="less" scoped>
- .search-list {
- flex: 1;
- display: flex;
- flex-direction: column;
- overflow-y: auto;
- }
- .user-list-warp {
- flex: 1;
- overflow-y: auto;
- }
- .search-title {
- padding: 6px 10px;
- color: #999;
- font-size: 13px;
- background: #f1f1f1;
- }
- .message {
- padding-top: 100px;
- color: #999;
- text-align: center;
- }
- .user-search {
- border-bottom: 1px solid #eee;
- }
- .user-list {
- .item {
- position: relative;
- display: flex;
- align-items: center;
- padding-left: 10px;
- &:hover {
- background: rgba(88,140,232,0.2)
- }
- &.active {
- background: #588ce8;
- .username {
- color: #fff;
- border-bottom-color: #588ce8;
- }
- }
- .username {
- flex: 1;
- padding: 18px 0;
- font-size: 16px;
- border-bottom: 1px solid #eee;
- margin-left: 10px;
- }
- .message-num {
- position: absolute;
- right: 10px;
- bottom: 10px;
- min-width: 20px;
- padding: 0 5px;
- color: #fff;
- background: var(--van-button-primary-background-color);
- border-radius: 10px;
- text-align: center;
- }
- }
- }
- </style>
|