Skip to content

Commit

Permalink
feat: merge branch 'master' of github.com:cossim/coss-client
Browse files Browse the repository at this point in the history
  • Loading branch information
xie392 committed May 31, 2024
2 parents a813b5d + b732ecf commit 9528552
Show file tree
Hide file tree
Showing 7 changed files with 245 additions and 39 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/build-docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ on:
push:
branches:
- 'master'
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest
Expand Down
3 changes: 2 additions & 1 deletion src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import enUS from 'antd/locale/en_US'
import zhCN from 'antd/locale/zh_CN'
import dayjs from 'dayjs'
import { Locale } from 'antd/es/locale'
import Call from '@/components/call'

const App = memo(() => {
const commonStore = useCommonStore()
Expand Down Expand Up @@ -44,7 +45,7 @@ const App = memo(() => {
<AppComponent>
<Suspense fallback={<Loading />}>{useRoutes(routes)}</Suspense>
{/* 通话组件 */}
{/* <Call /> */}
<Call />
</AppComponent>
</ConfigProvider>
)
Expand Down
39 changes: 26 additions & 13 deletions src/components/call/index.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,33 @@
import { PhoneFilled, RollbackOutlined } from '@ant-design/icons'
import { Avatar, Flex } from 'antd'
import clsx from 'clsx'
import React, { memo, useEffect, useRef, useState } from 'react'
import React, { memo, useEffect, useMemo, useState } from 'react'
import useMobile from '@/hooks/useMobile'
import useDraggable from '@/hooks/useDraggable'
import useCallStore from '@/stores/call'

export interface CallProps {
mask?: boolean
}

const Call: React.FC<CallProps> = memo(() => {
const { isMobile } = useMobile()
const [open, setOpen] = useState(false)
const [runningBackground, setRunningBackground] = useState(false)
const callStore = useCallStore()

const el = useRef<HTMLDivElement>(null)
const { isDraggable } = useDraggable(el.current)
const open = useMemo(() => {
return callStore.isAudio || callStore.isVideo
}, [callStore.isAudio, callStore.isVideo])
const isVideo = useMemo(() => {
return false
}, [callStore.isVideo])
const [runningBackground, setRunningBackground] = useState(false)

const [avatar, setAvatar] = useState('')

useEffect(() => {
setOpen(true)
setAvatar(
'https://gw.alipayobjects.com/zos/antfincdn/LlvErxo8H9/photo-1503185912284-5271ff81b9a8.webp'
)
return () => {
setOpen(false)
setAvatar('')
}
}, [])
Expand All @@ -34,13 +36,12 @@ const Call: React.FC<CallProps> = memo(() => {
<>
<div
className={clsx(
'size-14 text-white bg-black bg-opacity-40 flex justify-center items-center rounded-sm fixed top-0 right-0 z-[9999]',
'size-14 text-white bg-black bg-opacity-40 flex justify-center items-center rounded-sm fixed top-1/3 right-0 z-[9999]',
open && runningBackground ? 'block' : 'hidden'
)}
onClick={() => setRunningBackground(false)}
>
<PhoneFilled className="text-2xl" />
{isDraggable ? '拖动' : '未拖动'}
</div>
<div
className={clsx(
Expand All @@ -49,7 +50,6 @@ const Call: React.FC<CallProps> = memo(() => {
)}
>
<Flex
ref={el}
className={clsx(
'relative p-4 rounded-sm top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 backdrop-blur overflow-hidden',
isMobile ? 'w-full h-full' : 'w-[400px] h-[550px]'
Expand Down Expand Up @@ -88,7 +88,7 @@ const Call: React.FC<CallProps> = memo(() => {
</Flex>
<Flex className="gap-20">
{/* 圆形按钮 */}
<Flex className="gap-2" vertical align="center">
<Flex className="gap-2" vertical align="center" onClick={() => callStore.hangup()}>
<Flex
className="size-16 text-2xl bg-red-500 rounded-full rotate-[-135deg]"
justify="center"
Expand All @@ -97,7 +97,20 @@ const Call: React.FC<CallProps> = memo(() => {
</Flex>
<span className="text-sm">挂断</span>
</Flex>
<Flex className="gap-2" vertical align="center">
<Flex
className="gap-2"
vertical
align="center"
onClick={() =>
callStore.join(
`${Date.now()}`,
isVideo ? 'video' : 'audio',
isVideo,
!isVideo,
false
)
}
>
<Flex className="size-16 text-2xl bg-green-500 rounded-full" justify="center">
<PhoneFilled />
</Flex>
Expand Down
20 changes: 18 additions & 2 deletions src/components/messages/message-header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,16 @@ import { Flex, Typography, Dropdown, Divider } from 'antd'
import { useMemo } from 'react'
import IconButton from '@/components/icon/icon-button'
import { $t } from '@/i18n'
import useCallStore from '@/stores/call'

const MessageHeader = () => {
const callStore = useCallStore()

const call = (video: boolean) => {
if (callStore.isAudio || callStore.isVideo) return
callStore.create(`${Date.now()}`, video ? 'video' : 'audio', video, !video, false)
}

return (
<Flex className="mobile:min-h-16 min-h-16 bg-background pl-5 pr-3" justify="center" vertical>
<Flex justify="space-between">
Expand All @@ -20,8 +28,16 @@ const MessageHeader = () => {
</Flex>
<Flex align="center" gap={10}>
<IconButton className="text-xl text-gray-500" component={SearchOutlined} />
<IconButton className="text-xl text-gray-500" component={PhoneOutlined} />
<IconButton className="text-xl text-gray-500" component={VideoCameraOutlined} />
<IconButton
className="text-xl text-gray-500"
component={PhoneOutlined}
onClick={() => call(true)}
/>
<IconButton
className="text-xl text-gray-500"
component={VideoCameraOutlined}
onClick={() => call(false)}
/>
<Dropdown
// menu={{ items }}
trigger={['click']}
Expand Down
7 changes: 2 additions & 5 deletions src/hooks/useDraggable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,10 @@ const useDraggable = (el: HTMLElement | null) => {
console.log('useDraggable', el)
if (!el) return
el.addEventListener('mousedown', handleMouseDown)
el.addEventListener('mouseup', handleMouseUp)
el.addEventListener('mousemove', (e) => {
console.log(e)
})
document.addEventListener('mouseup', handleMouseUp)
return () => {
el.removeEventListener('mousedown', handleMouseDown)
el.removeEventListener('mouseup', handleMouseUp)
document.removeEventListener('mouseup', handleMouseUp)
}
}, [el])

Expand Down
133 changes: 133 additions & 0 deletions src/stores/call.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { create } from 'zustand'
import { CallStore, CallStoreMethods, CallOptions } from '@/types/store'
import { createJSONStorage, devtools, persist } from 'zustand/middleware'

const states: CallOptions = {
callId: '',
callType: '',
callStatus: '',
isVideo: false,
isAudio: false,
isGroup: false
}

const actions = (set: any, get: any): CallStoreMethods => ({
update: async (options) => set(options),
create: function (
callId: string,
callType: string,
isVideo: boolean,
isAudio: boolean,
isGroup: boolean
): Promise<ResponseData<any>> {
console.log('create', callId, callType, isVideo, isAudio, isGroup)
const { update } = get()
update({
isAudio: !isVideo,
isVideo: isVideo
})
return Promise.resolve({
code: 200,
data: {
callId,
callType,
isVideo,
isAudio,
isGroup
},
msg: 'success'
})
},
join: function (
callId: string,
callType: string,
isVideo: boolean,
isAudio: boolean,
isGroup: boolean
): Promise<ResponseData<any>> {
console.log('join', callId, callType, isVideo, isAudio, isGroup)
const { update } = get()
update({
isAudio: !isVideo,
isVideo: isVideo
})
return Promise.resolve({
code: 0,
data: {
callId: '123',
callType: 'video',
isVideo: true,
isAudio: true,
isGroup: true
},
msg: 'success'
})
},
leave: function (): Promise<ResponseData<any>> {
console.log('leave')
const { update } = get()
update({
callId: '',
callType: '',
callStatus: '',
isVideo: false,
isAudio: false,
isGroup: false
})
return Promise.resolve({
code: 0,
data: {},
msg: 'success'
})
},
reject: function (): Promise<ResponseData<any>> {
console.log('reject')
const { update } = get()
update({
callId: '',
callType: '',
callStatus: '',
isVideo: false,
isAudio: false,
isGroup: false
})
return Promise.resolve({
code: 0,
data: {},
msg: 'success'
})
},
hangup: function (): Promise<ResponseData<any>> {
console.log('hangup')
const { update } = get()
update({
callId: '',
callType: '',
callStatus: '',
isVideo: false,
isAudio: false,
isGroup: false
})
return Promise.resolve({
code: 0,
data: {},
msg: 'success'
})
}
})

const commonStore = (set: any, get: any): CallStore => ({
...states,
...actions(set, get)
})

const useCallStore = create(
devtools(
persist(commonStore, {
name: 'COSS_CALL_STORE',
storage: createJSONStorage(() => localStorage)
})
)
)

export default useCallStore
80 changes: 62 additions & 18 deletions src/types/store.d.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,5 @@
import { LoginParams, LogoutParams } from './api'

export interface UserOptions {
/*** @description 用户 id*/
userId: string
/*** @description 用户所有信息*/
userInfo: any
/** @description token */
token: string
}

export interface UserStoreMethods {
/** @description 更新某个值 */
update: (options: Partial<UserOptions>) => Promise<void>
login: (params: LoginParams) => Promise<ResponseData<any>>
logout: (params: LogoutParams) => Promise<ResponseData<any>>
}

export interface CommonOptions {
/**
* @description 当前主题 'light' | 'dark'
Expand All @@ -39,7 +23,67 @@ export interface CommonStoreMethods {
update: (options: Partial<CommonOptions>) => Promise<void>
}

// 用户仓库
export type UserStore = UserOptions & UserStoreMethods
export interface UserOptions {
/*** @description 用户 id*/
userId: string
/*** @description 用户所有信息*/
userInfo: any
/** @description token */
token: string
}

export interface UserStoreMethods {
/** @description 更新某个值 */
update: (options: Partial<UserOptions>) => Promise<void>
login: (params: LoginParams) => Promise<ResponseData<any>>
logout: (params: LogoutParams) => Promise<ResponseData<any>>
}

export interface CallOptions {
/** @description 当前通话 id */
callId: string
/** @description 当前通话类型 */
callType: string
/** @description 当前通话状态 */
callStatus: string
/** @description 当前通话是否是视频通话 */
isVideo: boolean
/** @description 当前通话是否是音频通话 */
isAudio: boolean
/** @description 当前通话是否是群聊 */
isGroup: boolean
}

export interface CallStoreMethods {
/** @description 更新某个值 */
update: (options: Partial<CallOptions>) => Promise<void>
/** @description 创建通话 */
create: (
callId: string,
callType: string,
isVideo: boolean,
isAudio: boolean,
isGroup: boolean
) => Promise<ResponseData<any>>
/** @description 加入通话 */
join: (
callId: string,
callType: string,
isVideo: boolean,
isAudio: boolean,
isGroup: boolean
) => Promise<ResponseData<any>>
/** @description 离开通话 */
leave: () => Promise<ResponseData<any>>
/** @description 拒绝通话 */
reject: () => Promise<ResponseData<any>>
/** @description 挂断通话 */
hangup: () => Promise<ResponseData<any>>
}

// 通用仓库
export type CommonStore = CommonOptions & CommonStoreMethods
// 用户仓库
export type UserStore = UserOptions & UserStoreMethods
// 通话仓库
export type CallStore = CallOptions & CallStoreMethods

0 comments on commit 9528552

Please sign in to comment.