feat: 联系人

This commit is contained in:
dylanmay
2024-12-12 22:19:14 +08:00
parent e5b90372a6
commit 5c1bb25237
20 changed files with 421 additions and 65 deletions

View File

@ -4,7 +4,7 @@
style="height: 60px; min-height: 60px"
>
<label class="text-black text-size-xl font-medium mx-4">{{
chatStore.currentSession?.name
chatStore.currentSession?.nickname || chatStore.currentSession?.name
}}</label>
</view>
</template>

View File

@ -1,5 +1,5 @@
<template>
<view class="flex flex-col items-center h-full py-2 b-1 b-gray b-solid" style="width: 258px">
<view class="flex flex-col items-center h-full py-2 b-1 b-gray b-solid overflow-auto" style="width: 258px">
<view class="flex flex-col w-full">
<SessionItem
v-for="(item, index) in chatStore.sessionList"

View File

@ -53,8 +53,8 @@ const timefontColor = () => {
*/
const lastMessage = computed(() => {
if (props.conversation.msgList.length === 0) {
return props.conversation.lastMessageDescription
if (!props.conversation.msgList || props.conversation.msgList.length === 0) {
return props.conversation.lastMessageDescription || ''
}
const lastIndex = props.conversation.msgList.length - 1

View File

@ -0,0 +1,53 @@
<template>
<div class="tree-node" >
<div class="node-title custom-hover" @click.stop="onClick">
<ElAvatar class="m-2" shape="square" v-if="node.children.length > 0">{{ node.name.substring(0,1) }}</ElAvatar>
<span class="mx-1 p-1">{{ node.name }}</span>
</div>
<div v-if="node.children && node.children.length > 0" class="children">
<TreeNode
v-for="child in node.children"
:key="child.id"
:node="child"
@node-click="$emit('node-click', $event)"
/>
</div>
</div>
</template>
<script setup>
import TreeNode from './TreeNode.vue';
// 传递 `node` 数据作为属性
const props = defineProps({
node: {
type: Object,
required: true,
},
});
const emit = defineEmits(['node-click'])
const onClick = () => {
emit('node-click', props.node)
}
</script>
<style scoped>
.tree-node {
padding-left: 8px;
margin-left: 16px;
border-left: 1px solid #ccc;
}
.node-title {
margin: 4px 0;
font-weight: 500;
color: #333;
}
.children {
margin-top: 4px;
}
</style>

View File

@ -0,0 +1,28 @@
<template>
<div class="tree">
<TreeNode v-for="item in hierarchy" :key="item.id" :node="item" @node-click="$emit('tree-click', $event)"/>
</div>
</template>
<script setup>
import TreeNode from './TreeNode.vue';
// 传递 `hierarchy` 数据作为组件属性
defineProps({
hierarchy: {
type: Array,
required: true,
},
});
const emit = defineEmits(['tree-click'])
</script>
<style scoped>
.tree {
font-family: Arial, sans-serif;
font-size: 14px;
line-height: 1.5;
}
</style>

View File

@ -0,0 +1,63 @@
<template>
<view class="flex flex-col items-left h-full py-2 b-1 b-gray b-solid" style="width: 248px; min-width: 248px">
<!-- <view v-for="item in departListState.list" class="w-full justify-left custom-hover border-b-gray border-1" :key="item.id" style="height: 70px;">
<ElAvatar shape="square">{{ item.name.substring(0,1) }}</ElAvatar>
<view class="text-size-sm ml-1">{{ item.name }}</view>
</view> -->
<el-skeleton animated :loading="state.loading" :throttle="{ leading: 500, initVal: true, trailing: 500 }"
>
<template #template>
<div v-for="item in 12" :key="item" class="flex flex-1 mx-2 my-3">
<el-skeleton-item animated variant="rect" style="width: 50px; height: 50px; max-width: 50px;" />
<div class="mx-2 flex flex-1 flex-col mt-2">
<el-skeleton-item animated variant="rect" style="height: 10px;" />
<el-skeleton-item animated variant="rect" style="height: 10px;" class="mt-3" />
</div>
</div>
</template>
<template #default>
<div class="w-full h-full">
<TreeView :hierarchy="useFriendStore.departmentList" @tree-click="handleNodeClick" />
</div>
</template>
</el-skeleton>
<view
v-if="useFriendStore.departmentList.length === 0 && !state.loading"
class="flex justify-center items-center h-full">No data</view>
</view>
</template>
<script lang="ts" setup>
import { onMounted } from 'vue'
import TreeView from './components/TreeView.vue'
import { useFriendStoreWithOut } from '../../store/friendstore';
defineOptions({ name: 'Department' })
const useFriendStore = useFriendStoreWithOut()
const { fetchDepartment, setCurrentDepartmentId, fetchDeptUser } = useFriendStore
const state = reactive({
loading: true
})
onMounted(() => {
fetchDepartment()
})
watch(() => useFriendStore.departmentList, () => {
setTimeout(() => {
state.loading = false
}, 1000);
})
const handleNodeClick = (data: Tree) => {
setCurrentDepartmentId(data.id)
fetchDeptUser(data.id)
}
</script>

View File

@ -1,6 +1,6 @@
<template>
<view
class="flex justify-center w-full border-b-1 border-b-gray border-b-solid flex-1 border-b-1 border-b-gray border-b-solid py-2"
class="flex flex-col items-center w-full border-b-1 border-b-gray border-b-solid flex-1 border-b-1 border-b-gray border-b-solid py-2"
>
<view class="flex mt-20" v-if="friendStore.currentFriend != null">
<el-image
@ -8,22 +8,34 @@
class="rounded"
:src="friendStore.currentFriend.avatar"
/>
<view class="flex flex-col ml-2">
<label class="font-500 text-black font-size-5">{{ friendStore.currentFriend?.name }}</label>
<label>{{ friendStore.currentFriend?.description }}</label>
<view class="flex flex-col ml-4 mt-10">
<label class="font-500 text-black font-size-5">{{ friendStore.currentFriend?.name || '无名' }}</label>
<label class="mt-2 text-size-sm">{{ friendStore.currentFriend?.description || '--人生若只如初见' }}</label>
</view>
</view>
<view v-else class="mt-50 flex flex-col items-center">
<Icon icon="ep:coffee-cup" :size="64" />
<label>空空如也</label>
</view>
<el-button type="primary" class="mt-10" v-if="friendStore.currentFriend != null" @click="onSend"> 发送消息</el-button>
</view>
</template>
<script lang="ts" setup>
import { useChatStore } from '../../store/chatstore';
import { useFriendStore } from '../../store/friendstore'
import { CONVERSATION_TYPE } from '../../types/types';
defineOptions({ name: 'FriendDetail' })
const friendStore = useFriendStore()
const chatStore = useChatStore()
const onSend = () => {
const avatar = friendStore.currentFriend?.avatar || ''
const nickname = friendStore.currentFriend?.name || ''
chatStore.createConversation(friendStore.currentFriend?.id, CONVERSATION_TYPE.SINGLE, avatar, nickname)
}
</script>

View File

@ -1,7 +1,7 @@
<template>
<view class="flex py-2 border-b-gray-3 border-b-solid items-center px-2" :class="bgColor()">
<el-avatar shape="square" size="default" class="mr-2" :src="friend.avatar" />
<label>{{ friend.name }}</label>
<label :class="fontColor()">{{ friend.name }}</label>
</view>
</template>
@ -25,4 +25,8 @@ const friendStore = useFriendStore()
const bgColor = () => {
return props.friend.id === friendStore.currentFriend?.id ? 'bg-blue' : 'bg-white'
}
const fontColor = () => {
return props.friend.id === friendStore.currentFriend?.id ? 'text-white' : 'text-black'
}
</script>

View File

@ -1,6 +1,6 @@
<template>
<view
class="flex flex-col items-center h-full py-2 b-1 b-gray b-solid"
class="flex flex-col items-center h-full py-2 b-1 b-gray b-solid b-l-white"
style="width: 248px; min-width: 248px"
>
<view class="flex flex-col w-full">
@ -24,8 +24,9 @@ import Friend from '../../model/Friend'
defineOptions({ name: 'Friends' })
const friendStore = useFriendStore()
onMounted(() => {
onMounted(async () => {
// set default conversation
// await friendStore.fetchFriend()
})
const onFriendClick = (friend: Friend) => {

View File

@ -1,31 +1,35 @@
<template>
<view class="flex flex-col items-center bg-gray h-full py-2" style="width: 80px; min-width: 80px">
<view class="flex flex-col items-center bg-gray-2 h-full py-2" style="width: 80px; min-width: 80px">
<el-avatar shape="square" />
<icon
icon="ep:chat-line-round"
:size="24"
color="white"
class="px-4 py-4 mt-1 rounded-2"
:class="selectItem === MENU_LIST_ENUM.CONVERSATION ? 'bg-red' : ''"
@click="onConversatonClicked"
/>
<icon
icon="ep:avatar"
:size="24"
color="white"
class="px-4 py-4 rounded-2 mt-2"
:class="selectItem === MENU_LIST_ENUM.FRIENDS ? 'bg-red' : ''"
@click="onFriendsClicked"
/>
<div
class="flex flex-col items-center px-3 py-3 mt-4 rounded-2 hover:bg-white"
:class="chatStore.bussinessType === MENU_LIST_ENUM.CONVERSATION ? 'bg-gray-3' : ''" style="width: 60px;"
@click="onConversatonClicked">
<icon icon="ep:chat-line-round" :size="24" color="#409EFF" />
<span class="text-xs mt-1 text-gray-5"> </span>
<span></span>
</div>
<div
class="flex flex-col items-center rounded-2 mt-4 p-3 hover:bg-white"
:class="chatStore.bussinessType === MENU_LIST_ENUM.FRIENDS ? 'bg-gray-3' : ''" style="width: 60px;" @click="onFriendsClicked">
<icon icon="ep:avatar" :size="24" color="#409EFF" />
<span class="text-xs mt-1 text-gray-5">联系人</span>
</div>
</view>
</template>
<script lang="ts" setup>
import { useChatStore } from '../../store/chatstore';
import { MENU_LIST_ENUM } from '../../types/types'
defineOptions({ name: 'ToolSection' })
const selectItem = ref(1)
const chatStore = useChatStore()
const { setBussinessType } = useChatStore()
const emit = defineEmits(['menuSelectChange'])
watch(
@ -36,10 +40,10 @@ watch(
)
const onConversatonClicked = () => {
selectItem.value = MENU_LIST_ENUM.CONVERSATION
setBussinessType(MENU_LIST_ENUM.CONVERSATION)
}
const onFriendsClicked = () => {
selectItem.value = MENU_LIST_ENUM.FRIENDS
setBussinessType(MENU_LIST_ENUM.FRIENDS)
}
</script>