diff --git a/src/app/config.ts b/src/app/config.ts index d9ba8f30..cdb47731 100644 --- a/src/app/config.ts +++ b/src/app/config.ts @@ -43,6 +43,12 @@ export const ContentTypes = { formData: "multipart/form-data", json: "application/json" }; +export const MessageTypes = { + text: "text/plain", + markdown: "text/markdown", + file: "vocechat/file", + archive: "vocechat/archive", +}; export const firebaseConfig = { apiKey: "AIzaSyCc3VuCJZgzQLIH2wrYdQzsUOc1DuZiIOA", authDomain: "vocechatdev.firebaseapp.com", diff --git a/src/app/slices/message.ts b/src/app/slices/message.ts index bc74fffb..c6ceade1 100644 --- a/src/app/slices/message.ts +++ b/src/app/slices/message.ts @@ -1,13 +1,13 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; -import BASE_URL, { ContentTypes } from "../config"; -import { isImage } from "../../common/utils"; +// import { ContentTypes } from "../config"; +import { normalizeFileMessage } from "../../common/utils"; import { ContentType } from "../../types/message"; export interface MessagePayload { mid: number; from_uid?: number; read?: boolean; created_at?: number; - sending: boolean; + sending?: boolean; content_type: ContentType; content: string; expires_in?: number | null; @@ -49,34 +49,18 @@ const messageSlice = createSlice({ }, addMessage(state, action: PayloadAction) { const data = action.payload; - const { mid, sending, content_type, content, properties } = data; + const { mid, sending } = data; // console.log("tfile", sending, content, content_type); // 如果是正发送,并且已存在,则不覆盖 if (sending && state[mid]) return; - const isFile = content_type == ContentTypes.file; - // image - const props = properties; - const isPic = isImage(props?.content_type, props?.size); - if (isFile) { - if (!sending) { - data.file_path = content; - data.content = `${BASE_URL}/resource/file?file_path=${encodeURIComponent( - content - )}`; - data.download = `${BASE_URL}/resource/file?file_path=${encodeURIComponent( - content - )}&download=true`; - data.thumbnail = isPic - ? `${BASE_URL}/resource/file?file_path=${encodeURIComponent( - content - )}&thumbnail=true` - : ""; - } else if (isPic) { - data.thumbnail = content; - } + // 文件类消息的处理 + const normalized = normalizeFileMessage(data); + if (normalized) { + state[mid] = { ...state[mid], ...data, ...normalized }; + } else { + state[mid] = { ...state[mid], ...data }; } - state[mid] = { ...state[mid], ...data }; }, removeMessage(state, action: PayloadAction) { const mids = Array.isArray(action.payload) ? action.payload : [action.payload]; diff --git a/src/common/component/Message/PreviewMessage.tsx b/src/common/component/Message/PreviewMessage.tsx index 08496b9f..0425d1eb 100644 --- a/src/common/component/Message/PreviewMessage.tsx +++ b/src/common/component/Message/PreviewMessage.tsx @@ -14,8 +14,8 @@ const PreviewMessage: FC = ({ mid = 0 }) => { return { msg: store.message[mid], usersData: store.users.byId }; }); if (!msg) return null; - const { from_uid, created_at, content_type, content, thumbnail = "", properties } = msg; - const { name, avatar } = usersData[from_uid || 0] || {}; + const { from_uid = 0, created_at, content_type, content, thumbnail = "", properties } = msg; + const { name, avatar } = usersData[from_uid] ?? {}; return (
diff --git a/src/common/component/PinnedMessage.tsx b/src/common/component/PinnedMessage.tsx new file mode 100644 index 00000000..6cfd93a9 --- /dev/null +++ b/src/common/component/PinnedMessage.tsx @@ -0,0 +1,49 @@ +import dayjs from "dayjs"; +import renderContent from "./Message/renderContent"; +import Avatar from "./Avatar"; +import StyledWrapper from "./Message/styled"; +import { useAppSelector } from "../../app/store"; +import { FC } from "react"; +import { PinnedMessage } from "../../types/channel"; +import { normalizeFileMessage } from "../utils"; +import { MessagePayload } from "../../app/slices/message"; + +interface Props { + data: PinnedMessage +} + +const PinnedMessageView: FC = ({ data }) => { + const { usersData } = useAppSelector((store) => { + return { usersData: store.users.byId }; + }); + const { created_by = 0 } = data; + const normalized = normalizeFileMessage(data as MessagePayload) || {}; + console.log("nnnn", normalized); + + const { created_at, content_type, content, properties, thumbnail = "" } = { ...data, ...normalized }; + const { name, avatar } = usersData[created_by] ?? {}; + return ( + +
+ +
+
+
+ {name} + {dayjs(created_at).format("YYYY-MM-DD h:mm:ss A")} +
+
+ {renderContent({ + content_type, + content, + thumbnail, + from_uid: created_by, + properties + })} +
+
+
+ ); +}; + +export default PinnedMessageView; diff --git a/src/common/utils.tsx b/src/common/utils.tsx index eb02e8f1..6b587f91 100644 --- a/src/common/utils.tsx +++ b/src/common/utils.tsx @@ -7,6 +7,8 @@ import IconDoc from "../assets/icons/file.doc.svg"; import IconCode from "../assets/icons/file.code.svg"; import IconImage from "../assets/icons/file.image.svg"; import { Archive, ArchiveMessage } from "../types/resource"; +import { MessagePayload } from "../app/slices/message"; +import { PinnedMessage } from "../types/channel"; export const getLocalAuthData = () => { return { @@ -181,6 +183,33 @@ export const getFileIcon = (type: string, name = "") => { } return icon; }; +export const normalizeFileMessage = (data: MessagePayload) => { + const { properties, content, sending = false, content_type } = data; + const isFile = content_type == ContentTypes.file; + const isPic = isImage(properties?.content_type, properties?.size); + let res: null | { file_path?: string, content?: string, download?: string, thumbnail: string } = null; + if (isFile) { + if (!sending) { + res = { + file_path: content, + content: `${BASE_URL}/resource/file?file_path=${encodeURIComponent( + content + )}`, + download: `${BASE_URL}/resource/file?file_path=${encodeURIComponent( + content + )}&download=true`, + thumbnail: isPic + ? `${BASE_URL}/resource/file?file_path=${encodeURIComponent( + content + )}&thumbnail=true` + : "" + }; + } else if (isPic) { + res = { thumbnail: content }; + } + } + return res; +}; export const normalizeArchiveData = ( data: Archive | null, filePath: string | null, diff --git a/src/routes/chat/ChannelChat/PinList.tsx b/src/routes/chat/ChannelChat/PinList.tsx index a8d56ebe..2f3396c0 100644 --- a/src/routes/chat/ChannelChat/PinList.tsx +++ b/src/routes/chat/ChannelChat/PinList.tsx @@ -1,10 +1,10 @@ import { FC, FormEvent } from "react"; import styled from "styled-components"; import usePinMessage from "../../../common/hook/usePinMessage"; -import PreviewMessage from "../../../common/component/Message/PreviewMessage"; import IconSurprise from "../../../assets/icons/emoji.surprise.svg"; import IconClose from "../../../assets/icons/close.svg"; import { useTranslation } from "react-i18next"; +import PinnedMessage from "../../../common/component/PinnedMessage"; const Styled = styled.div` padding: 16px; background: #f9fafb; @@ -98,7 +98,6 @@ const PinList: FC = ({ id }: Props) => { return (

{t("pinned_msg")}({pins.length})

- {noPins ? (
@@ -106,13 +105,13 @@ const PinList: FC = ({ id }: Props) => {
) : (
    - {pins.map(({ mid }) => { + {pins.map((data) => { return ( -
  • - +
  • +
    {canPin && ( - )} diff --git a/src/types/channel.ts b/src/types/channel.ts index 4b64eca7..58e6d09e 100644 --- a/src/types/channel.ts +++ b/src/types/channel.ts @@ -1,8 +1,8 @@ //call `group` in backend import { ContentType } from "./message"; -export interface ChannelMember {} +export interface ChannelMember { } -export interface Message {} +export interface Message { } export interface PinnedMessage { mid: number; @@ -11,7 +11,9 @@ export interface PinnedMessage { created_by: number; created_at: number; properties: { - local_id?: string; + local_id?: number; + content_type?: string; + size?: number }; }