Merge branch 'dev' of codeup.aliyun.com:61c14a7efa282c88e103c23f/oak-general-business into dev

This commit is contained in:
wenjiarui 2023-10-09 14:45:42 +08:00
commit 986aa17d48
83 changed files with 1431 additions and 637 deletions

View File

@ -4,5 +4,6 @@ declare const _default: (props: import("oak-frontend-base").ReactComponentProps<
onSelect: (id: string) => void;
key: string;
entityFilter: {};
name: undefined;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -122,6 +122,7 @@ export default OakComponent({
onSelect: (id) => { },
key: '',
entityFilter: {},
name: undefined,
},
methods: {
getAvatarUrl() {

View File

@ -7,6 +7,7 @@ export default function render(props: WebComponentProps<EntityDict, 'session', f
userType: string;
selectedId: string;
onSelect: (id: string) => void;
name: string;
}, {
getName: () => string;
getAvatarUrl: () => string;

View File

@ -5,7 +5,7 @@ import classNames from 'classnames';
import Style from './web.module.less';
export default function render(props) {
const { methods, data } = props;
const { selectedId, onSelect, userType, id, unreadLength, sessiontMessages = [], } = data;
const { selectedId, onSelect, userType, id, unreadLength, sessiontMessages = [], name, } = data;
const { t, getName, getAvatarUrl } = methods;
const sessiontMessage = sessiontMessages && sessiontMessages[0];
const createAt = sessiontMessage?.$$createAt$$;
@ -17,7 +17,7 @@ export default function render(props) {
[Style.cell_selected]: id === selectedId,
}), onClick: () => {
onSelect(id);
}, children: [_jsx(Badge, { dot: id === selectedId ? false : true, count: unreadLength || 0, children: _jsx(Image, { className: Style.avatar, src: getAvatarUrl(), preview: false }) }), _jsxs("div", { className: Style.inner, children: [_jsxs("div", { className: Style.top, children: [_jsx("div", { className: Style.title, children: getName() }), _jsx("div", { className: Style.date, children: sessiontMessage &&
}, children: [_jsx(Badge, { dot: id === selectedId ? false : true, count: unreadLength || 0, children: _jsx(Image, { className: Style.avatar, src: getAvatarUrl(), preview: false }) }), _jsxs("div", { className: Style.inner, children: [_jsxs("div", { className: Style.top, children: [_jsx("div", { className: Style.title, children: name || getName() }), _jsx("div", { className: Style.date, children: sessiontMessage &&
(today === createAt2
? dayjs(createAt).format('HH:mm')
: dayjs(createAt).format('YYYY-MM-DD')) })] }), _jsx("div", { className: Style.message, children: type &&

View File

@ -1,7 +1,6 @@
type HeaderProps = {
showBack: boolean;
/// <reference types="react" />
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, false, {
sessionId: string;
userId: string;
};
declare function Header(props: HeaderProps): import("react/jsx-runtime").JSX.Element;
export default Header;
isEntity: boolean;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -1,23 +1,104 @@
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useEffect } from 'react';
import { Button, Image } from 'antd';
import { LeftOutlined } from '@ant-design/icons';
import useFeatures from '../../..//hooks/useFeatures';
import classNames from 'classnames';
import Style from './index.module.less';
import { useWidth } from 'oak-frontend-base/es/platforms/web';
function Header(props) {
const features = useFeatures();
const width = useWidth();
const { showBack = true, sessionId, userId } = props;
const [name, setName] = useState('');
const [url, setUrl] = useState('');
useEffect(() => {
if (sessionId) {
const [session] = features.cache?.get('session', {
export default OakComponent({
// entity: 'session',
// projection: {
// id: 1,
// userId: 1,
// entity: 1,
// entityId: 1,
// lmts: 1,
// user: {
// id: 1,
// name: 1,
// nickname: 1,
// mobile$user: {
// $entity: 'mobile',
// data: {
// id: 1,
// mobile: 1,
// userId: 1,
// },
// },
// extraFile$entity: {
// $entity: 'extraFile',
// data: {
// id: 1,
// tag1: 1,
// origin: 1,
// bucket: 1,
// objectId: 1,
// filename: 1,
// extra1: 1,
// extension: 1,
// type: 1,
// entity: 1,
// },
// filter: {
// tag1: {
// $in: ['avatar'],
// },
// },
// },
// },
// },
isList: false,
// formData({ data, features }) {
// const session = Object.assign(
// {},
// data
// ) as any;
// console.log(session)
// Object.assign(session, {
// userUrl: features.extraFile.getUrl(
// session?.user?.extraFile$entity &&
// session?.user?.extraFile$entity[0]
// ),
// });
// // if (session?.sessionMessage$session) {
// // Object.assign(session, {
// // wechatMessages: session?.sessionMessage$session,
// // // unreadLength: session?.sessionMessage$session?.filter(
// // // (ele: any) => ele.isRead === false
// // // )?.length,
// // });
// // }
// return session;
// },
// filters: [
// {
// filter() {
// const { sessionId } = this.props;
// if (sessionId) {
// return {
// id: sessionId,
// };
// }
// },
// },
// ],
lifetimes: {
ready() {
const { sessionId } = this.props;
if (sessionId) {
this.getSession(sessionId);
}
},
},
listeners: {
sessionId(prev, next) {
if (prev.sessionId !== next.sessionId) {
this.getSession(next.sessionId);
}
},
},
properties: {
sessionId: '',
isEntity: false,
},
methods: {
getSession(sessionId) {
const [session] = this.features.cache.get('session', {
data: {
id: 1,
uerId: 1,
user: {
id: 1,
name: 1,
@ -43,7 +124,6 @@ function Header(props) {
extension: 1,
type: 1,
entity: 1,
entityId: 1,
},
filter: {
tag1: {
@ -54,49 +134,41 @@ function Header(props) {
},
},
filter: {
id: sessionId,
},
id: sessionId
}
});
if (session) {
const url2 = getAvatarUrl(session);
setUrl(url2);
const name2 = getName(session);
setName(name2);
this.setState({ session });
},
getAvatarUrl() {
const { userUrl, entity } = this.state;
const { isEntity } = this.props;
const defaultUrl = 'http://qiniu.gecomebox.com/static/defaultAvatar.png';
if (isEntity) {
return userUrl || defaultUrl;
}
}
}, [sessionId, userId]);
const getAvatarUrl = (session) => {
const { entity, user } = session || {};
const defaultUrl = 'http://qiniu.gecomebox.com/static/defaultAvatar.png';
if (user) {
const userAvatar = features.extraFile.getUrl(session?.user?.extraFile$entity &&
session?.user?.extraFile$entity[0]);
return userAvatar || defaultUrl;
}
return defaultUrl;
};
const getName = (session) => {
const { user } = session || {};
if (user) {
const userName = user?.name || '';
const userNickname = user?.name || user?.nickname || '';
const userMobile = (user?.mobile$user &&
user?.mobile$user[0]?.mobile) ||
'';
if (userName) {
return userName;
else {
return defaultUrl;
}
if (userMobile) {
return '用户' + userMobile;
},
getName() {
const { session, entity } = this.state;
const { isEntity } = this.props;
if (isEntity) {
const userName = session?.user?.name;
const userNickname = session?.user?.name || session?.user?.nickname;
const userMobile = session?.user?.mobile$user &&
session?.user?.mobile$user[0]?.mobile;
if (userName) {
return userName;
}
if (userMobile) {
return '用户' + userMobile;
}
return userNickname;
}
return userNickname;
}
return '未知';
};
return (_jsxs("div", { className: classNames(Style.header, {
[Style.header_mobile]: width === 'xs'
}), children: [showBack && (_jsx(Button, { type: "text", onClick: () => {
features.navigator.navigateBack();
}, children: _jsx(LeftOutlined, { className: Style.backIcon }) })), _jsxs("div", { className: Style.middle, children: [_jsx(Image, { src: url, className: Style.icon, preview: false }), _jsx("div", { className: Style.name, children: name })] })] }));
}
export default Header;
else {
return '未知';
}
},
},
});

View File

@ -0,0 +1,11 @@
import { WebComponentProps } from 'oak-frontend-base';
import { EntityDict } from '../../../oak-app-domain';
export default function render(props: WebComponentProps<EntityDict, 'session', false, {
avatarUrl: string;
nickname: string;
name: string;
showBack: boolean;
sessionId: string;
}, {
getName: () => string;
}>): import("react/jsx-runtime").JSX.Element;

View File

@ -0,0 +1,21 @@
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
// import { UserOutlined } from '@ant-design/icons';
import Style from './web.module.less';
import { Button } from 'antd';
import { LeftOutlined } from '@ant-design/icons';
import useFeatures from '../../../hooks/useFeatures';
import classNames from 'classnames';
import { useWidth } from 'oak-frontend-base/es/platforms/web';
export default function render(props) {
const { methods, data } = props;
const { nickname, avatarUrl, name, showBack } = data;
const { getName } = methods;
const defaultUrl = 'http://qiniu.gecomebox.com/static/defaultAvatar.png';
const features = useFeatures();
const width = useWidth();
return (_jsxs("div", { className: classNames(Style.header, {
[Style.header_mobile]: width === 'xs'
}), children: [showBack && (_jsx(Button, { type: "text", onClick: () => {
features.navigator.navigateBack();
}, children: _jsx(LeftOutlined, { className: Style.backIcon }) })), _jsx("div", { className: Style.middle, children: _jsx("div", { className: Style.name, children: getName() }) })] }));
}

View File

@ -26,6 +26,7 @@
.name {
font-size: 16px;
margin-left: 10px;
}
}
}

View File

@ -3,4 +3,5 @@ import { EntityDict } from '../../../oak-app-domain';
export default function render(props: WebComponentProps<EntityDict, 'session', false, {
avatarUrl: string;
nickname: string;
name: string;
}, {}>): import("react/jsx-runtime").JSX.Element;

View File

@ -4,7 +4,7 @@ import { Avatar } from 'antd';
import Style from './web.module.less';
export default function render(props) {
const { methods, data } = props;
const { nickname, avatarUrl } = data;
const { nickname, avatarUrl, name } = data;
const defaultUrl = 'http://qiniu.gecomebox.com/static/defaultAvatar.png';
return (_jsxs("div", { className: Style.header, children: [_jsx(Avatar, { shape: "square", className: Style.avatar, src: avatarUrl || defaultUrl }), _jsx("div", { className: Style.nickname, children: nickname })] }));
return (_jsxs("div", { className: Style.header, children: [_jsx(Avatar, { shape: "square", className: Style.avatar, src: avatarUrl || defaultUrl }), _jsx("div", { className: Style.nickname, children: nickname || name })] }));
}

View File

@ -2,7 +2,7 @@
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "session", true, {
entity: string;
entityFilter: any;
entityDisplay: (entity: string, entityId: string) => "";
entityDisplay: (data: any) => "";
entityProjection: any;
sessionId: string;
dialog: boolean;

View File

@ -1,71 +1,85 @@
export default OakComponent({
entity: 'session',
projection: {
id: 1,
entity: 1,
entityId: 1,
userId: 1,
user: {
projection() {
const { entityProjection } = this.props;
const proj = {
id: 1,
name: 1,
nickname: 1,
mobile$user: {
$entity: 'mobile',
data: {
id: 1,
mobile: 1,
userId: 1,
},
},
extraFile$entity: {
$entity: 'extraFile',
data: {
id: 1,
tag1: 1,
origin: 1,
bucket: 1,
objectId: 1,
filename: 1,
extra1: 1,
extension: 1,
type: 1,
entity: 1,
entityId: 1,
},
filter: {
tag1: {
$in: ['avatar'],
},
},
},
},
sessionMessage$session: {
$entity: 'sessionMessage',
data: {
entity: 1,
entityId: 1,
userId: 1,
user: {
id: 1,
text: 1,
type: 1,
userId: 1,
wechatUserId: 1,
createTime: 1,
$$createAt$$: 1,
aaoe: 1,
},
sorter: [
{
$attr: {
$$createAt$$: 1,
name: 1,
nickname: 1,
mobile$user: {
$entity: 'mobile',
data: {
id: 1,
mobile: 1,
userId: 1,
},
$direction: 'desc',
},
],
indexFrom: 0,
count: 1,
},
$$createAt$$: 1,
extraFile$entity: {
$entity: 'extraFile',
data: {
id: 1,
tag1: 1,
origin: 1,
bucket: 1,
objectId: 1,
filename: 1,
extra1: 1,
extension: 1,
type: 1,
entity: 1,
entityId: 1,
},
filter: {
tag1: {
$in: ['avatar'],
},
},
},
},
sessionMessage$session: {
$entity: 'sessionMessage',
data: {
id: 1,
text: 1,
type: 1,
userId: 1,
wechatUserId: 1,
createTime: 1,
$$createAt$$: 1,
aaoe: 1,
},
sorter: [
{
$attr: {
$$createAt$$: 1,
},
$direction: 'desc',
},
],
indexFrom: 0,
count: 1,
},
$$createAt$$: 1,
};
if (entityProjection) {
Object.assign(proj, { ...entityProjection });
}
return proj;
},
isList: true,
formData: function ({ data: sessions, features, props }) {
const { entityDisplay, entityProjection } = this.props;
if (entityProjection && entityDisplay && sessions && sessions.length > 0) {
const sessions1 = entityDisplay(sessions);
return {
sessions: sessions1,
};
}
// const unReadLength = wechatSessions?.filter(
// (ele) => ele.isRead
// )
@ -100,8 +114,8 @@ export default OakComponent({
},
properties: {
entity: '',
entityFilter: {},
entityDisplay: (entity, entityId) => '',
entityFilter: undefined,
entityDisplay: (data) => '',
entityProjection: {},
sessionId: '',
dialog: false,
@ -165,7 +179,7 @@ export default OakComponent({
{
sorter: {
$attr: {
$$updateAt$$: 1,
lmts: 1,
},
$direction: 'desc',
},

View File

@ -5,8 +5,8 @@
}
.bothContainer {
margin: 0 auto;
margin-top: 5vh;
margin: 5vh auto;
// margin-top: 5vh;
width: 90%;
min-width: 600px;
height: 80vh;

View File

@ -1,7 +1,7 @@
import { WebComponentProps } from 'oak-frontend-base';
import { EntityDict } from '../../../oak-app-domain';
export default function Render(props: WebComponentProps<EntityDict, 'session', false, {
sessions: EntityDict['session']['Schema'][];
sessions: any;
selectedSessionId: string;
className: string;
dialog: boolean;

View File

@ -13,14 +13,14 @@ export default function Render(props) {
return (_jsx("div", { className: Style.container, children: _jsxs("div", { className: classNames(Style.bothContainer, className, {
[Style.dialogContainer]: dialog,
}), children: [_jsxs("div", { className: Style.conversationContainer, children: [_jsx(Header, {}), _jsx("div", { className: Style.inner, children: sessions?.map((session, index) => {
return (_jsx(SessionCell, { entityFilter: entityFilter, selectedId: selectedSessionId, onSelect: (id) => {
return (_jsx(SessionCell, { entityFilter: entityFilter, name: session?.name, selectedId: selectedSessionId, onSelect: (id) => {
setSelectedSessionId(id);
}, oakId: session.id, oakPath: oakFullpath
? `${oakFullpath}.${session.id}`
: '' }, session.id));
}) })] }), selectedSessionId && (_jsx(MessageList, { sessionId: selectedSessionId,
// isCombine={true}
isEntity: !!entityFilter, oakAutoUnmount: true, oakPath: oakFullpath
isEntity: entityFilter ? true : false, isUser: entityFilter ? false : true, oakAutoUnmount: true, oakPath: oakFullpath
? `$$sessionMessage/list`
: undefined }))] }) }));
}

View File

@ -2,5 +2,6 @@
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "sessionMessage", false, {
key: string;
isEntity: boolean;
isUser: boolean;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -16,6 +16,38 @@ export default OakComponent({
id: 1,
entity: 1,
entityId: 1,
userId: 1,
user: {
id: 1,
name: 1,
mobile$user: {
$entity: 'mobile',
data: {
id: 1,
mobile: 1,
},
},
extraFile$entity: {
$entity: 'extraFile',
data: {
id: 1,
tag1: 1,
origin: 1,
bucket: 1,
objectId: 1,
filename: 1,
extra1: 1,
extension: 1,
type: 1,
entity: 1,
},
filter: {
tag1: {
$in: ['avatar'],
},
},
},
},
},
aaoe: 1,
extraFile$entity: {
@ -43,7 +75,7 @@ export default OakComponent({
formData({ data: sessionMessage, features }) {
const type = sessionMessage?.type;
// const data = wechatMessage?.data;
// const session = sessionMessage?.session;
const session = sessionMessage?.session;
const newSessionMessage = {
type,
aaoe: sessionMessage?.aaoe,
@ -52,15 +84,12 @@ export default OakComponent({
id: sessionMessage?.id,
$$createAt$$: sessionMessage?.$$createAt$$,
sessionId: sessionMessage?.sessionId,
// employerId: conversation?.employerId,
// employerMobile:
// conversation?.employer?.mobile$user &&
// conversation?.employer?.mobile$user[0]?.mobile,
userId: session?.userId,
userMobile: session?.user?.mobile$user &&
session?.user?.mobile$user[0]?.mobile,
// companyName: conversation?.company?.name,
// employerAvatar: this.features.extraFile.getUrl(
// conversation?.employer?.extraFile$entity &&
// conversation?.employer?.extraFile$entity[0]
// ),
userAvatar: this.features.extraFile.getUrl(session?.user?.extraFile$entity &&
session?.user?.extraFile$entity[0]),
};
// if (type === 'image') {
// const extraFile$entity =
@ -74,25 +103,35 @@ export default OakComponent({
properties: {
key: '',
isEntity: false,
isUser: false,
},
methods: {
getAvatarUrl(type) {
getAvatarUrl(aaoe) {
const defaultUrl = 'http://qiniu.gecomebox.com/static/defaultAvatar.png';
const { companyLogoUrl, employerAvatar, parkLogoUrl } = this.state;
switch (type) {
case 'company': {
return companyLogoUrl || defaultUrl;
}
case 'employer': {
return employerAvatar || defaultUrl;
}
case 'platformProvider': {
return process.env.PUBLIC_URL + '/logo192.png';
}
case 'park': {
return parkLogoUrl || defaultUrl;
}
const { companyLogoUrl, userAvatar, parkLogoUrl } = this.state;
if (aaoe) {
return defaultUrl;
}
else {
return userAvatar || defaultUrl;
}
// switch (type) {
// case 'company': {
// return companyLogoUrl || defaultUrl;
// }
// case 'user': {
// return userAvatar || defaultUrl;
// }
// case 'platformProvider': {
// return process.env.PUBLIC_URL + '/logo192.png';
// }
// case 'park': {
// return parkLogoUrl || defaultUrl;
// }
// default: {
// return defaultUrl
// }
// }
},
},
});

View File

@ -2,6 +2,7 @@ import { WebComponentProps } from 'oak-frontend-base';
import { EntityDict } from '../../../oak-app-domain';
export default function render(props: WebComponentProps<EntityDict, 'sessionMessage', false, {
isEntity: boolean;
isUser: boolean;
$$createAt$$: number;
text: string;
type: string;
@ -10,5 +11,5 @@ export default function render(props: WebComponentProps<EntityDict, 'sessionMess
sessionId: string;
id: string;
}, {
getAvatarUrl: (type: string) => string;
getAvatarUrl: (aaoe: boolean) => string;
}>): import("react/jsx-runtime").JSX.Element;

View File

@ -5,13 +5,13 @@ import classNames from 'classnames';
import Style from './web.module.less';
export default function render(props) {
const { data, methods } = props;
const { $$createAt$$, text, type, picUrl, isEntity, aaoe, sessionId, } = data;
const { $$createAt$$, text, type, picUrl, isEntity, isUser, aaoe, sessionId, } = data;
const { t, getAvatarUrl } = methods;
return (_jsx(ICell, { time: $$createAt$$, children: _jsxs("div", { className: classNames(Style.myMessage, {
[Style.notMyMessage]: isEntity !== aaoe,
}), children: [_jsx(Image, { preview: false, className: Style.avatar, src: getAvatarUrl(type) }), _jsxs("div", { className: classNames({
[Style.notMyMessage]: (isEntity && !aaoe) || (isUser && aaoe),
}), children: [_jsx(Image, { preview: false, className: Style.avatar, src: getAvatarUrl(aaoe) }), _jsxs("div", { className: classNames({
[Style.messageType_text]: type === 'text',
[Style.messageType_text_no]: isEntity !== aaoe,
[Style.messageType_text_no]: (isEntity && !aaoe) || (isUser && aaoe),
}), children: [type === 'text' && _jsx(IText, { value: text }), type === 'image' && _jsx(IImage, { url: picUrl })] })] }) }));
}
function ICell(props) {
@ -23,7 +23,12 @@ function ICell(props) {
}
function IText(props) {
const { value } = props;
return _jsx("div", { children: value });
return _jsx("div", { style: { whiteSpace: 'pre-wrap' }, children: value });
// return <div>
// <Typography.Paragraph>
// {value}
// </Typography.Paragraph>
// </div>;
}
function IImage(props) {
const { url } = props;

View File

@ -49,7 +49,7 @@
}
.avatar {
margin: 10px;
margin: 0 10px;
height: 30px !important;
width: 30px !important;
padding: 0 !important;
@ -93,7 +93,8 @@
display: flex;
flex-direction: row-reverse;
justify-content: flex-start;
align-items: baseline;
align-items: flex-start;
margin-bottom: 10px;
}
.notMyMessage {

View File

@ -3,6 +3,7 @@ import { EntityDict } from '../../../oak-app-domain';
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<EntityDict, "sessionMessage", true, {
sessionId: string;
isEntity: boolean;
isUser: boolean;
dialog: boolean;
entity: string;
entityId: string;

View File

@ -43,7 +43,7 @@ export default OakComponent({
lifetimes: {
async ready() {
const { sessionId } = this.props;
this.subData([
await this.subData([
{
entity: 'sessionMessage',
filter: {
@ -51,7 +51,7 @@ export default OakComponent({
},
id: `${DATA_SUBSCRIBER_KEYS.sessionMessageList}-${sessionId}`,
}
]);
], async () => { await this.pageScroll('comment'); });
// const userId = this.features.token.getUserId(true);
// const applicationId = this.features.application.getApplicationId();
// if (!sessionId) {
@ -118,6 +118,7 @@ export default OakComponent({
properties: {
sessionId: '',
isEntity: false,
isUser: false,
dialog: false,
entity: '',
entityId: '',
@ -266,7 +267,7 @@ export default OakComponent({
fileType: type,
size,
extension,
entity: 'wechatMessage',
entity: 'sessionMessage',
bucket: '',
id: generateNewId(),
};

View File

@ -12,7 +12,7 @@
display: flex;
overflow: scroll;
flex-direction: column;
// margin-top: 50px;
margin-top: 50px;
overflow-x: hidden;
height: 100%;
}
@ -37,6 +37,8 @@
position: absolute;
z-index: 100;
// resize: both;
// cursor: nwse-resize;
.toolbar {
display: flex;
flex-direction: row;
@ -56,14 +58,17 @@
padding: 0 10px;
.textarea {
border: none;
outline: none;
resize: none;
}
.textarea:focus {
border: none;
box-shadow: none;
resize: none;
}
.btn {

View File

@ -12,6 +12,7 @@ export default function Render(props: WebComponentProps<EntityDict, 'sessionMess
buttonHidden: boolean;
sessionId: string;
isEntity: boolean;
isUser: boolean;
employerId: string;
}, {
setButtonHidden: (isHidden: boolean) => void;

View File

@ -1,14 +1,19 @@
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useEffect } from 'react';
import { useState, useEffect, useRef } from 'react';
import { Button, Input, Upload } from 'antd';
import { PictureOutlined } from '@ant-design/icons';
import MessageCell from '../../../components/sessionMessage/cell';
import Header from '../../../components/session/forMessage';
import Style from './web.module.less';
export default function Render(props) {
const { data, methods } = props;
const { sessionId, isEntity, sessionMessageList, oakFullpath, text, employerId, buttonHidden, } = data;
const { sessionId, isEntity, isUser, sessionMessageList, oakFullpath, text, employerId, buttonHidden, } = data;
const { setButtonHidden, customUpload, setContent, pageScroll, createMessage, } = methods;
const [bottomHeight, setBottomHeight] = useState(0);
const textareaRef = useRef(null);
// const [text1, setText1] = useState("");
// const newBottomHeight =
// window.document.getElementById('bottom')?.offsetHeight!;
useEffect(() => {
if (buttonHidden) {
const newBottomHeight = window.document.getElementById('bottom')?.offsetHeight;
@ -18,7 +23,42 @@ export default function Render(props) {
setBottomHeight(0);
}
}, [buttonHidden]);
return (_jsxs("div", { className: Style.container, children: [_jsx("div", { className: Style.inner, style: {
const handleKeyDown = (event) => {
// if (event.key === "Enter" && event.shiftKey) {
// event.preventDefault(); // 阻止默认的换行行为
// 执行你的换行逻辑
// setContent(text + "\n");
// if (textareaRef && textareaRef.current && textareaRef.current!.resizableTextArea) {
// const textArea = textareaRef.current.resizableTextArea.textAreaRef; // 获取 Input.TextArea 的原生 textarea 元素
// console.log(textArea)
// if (textArea) {
// console.log(textArea)
// const selectionStart = textArea?.selectionStart;
// const value = textArea?.value;
// const newValue =
// value?.substring(0, selectionStart) +
// "\n" +
// value?.substring(selectionStart);
// textArea.value = newValue;
// textArea.selectionStart = textArea.selectionEnd = selectionStart + 1;
// // 触发 onChange 事件,更新 Input.TextArea 的值
// textArea.dispatchEvent(new Event("input"));
// }
// }
// }
if (event.key === "Enter" && !event.shiftKey) {
event.preventDefault();
createMessage();
pageScroll('comment');
}
};
return (_jsxs("div", { className: Style.container, children: [_jsx(Header
// showBack={false}
, {
// showBack={false}
sessionId: sessionId, isEntity: isEntity,
// userId={employerId}
oakPath: 'session:header1', oakAutoUnmount: true }), _jsx("div", { className: Style.inner, style: {
marginBottom: bottomHeight ? `${bottomHeight}px` : '168px',
}, id: "comment", onClick: () => setButtonHidden(true), children: sessionMessageList
?.sort((a, b) => a.$$createAt$$ -
@ -26,18 +66,22 @@ export default function Render(props) {
.map((sessionMessage, index) => {
return (_jsx(MessageCell, { oakId: sessionMessage.id, oakPath: oakFullpath
? `${oakFullpath}.${sessionMessage.id}`
: '', isEntity: isEntity }, sessionMessage.id));
: '', isEntity: isEntity, isUser: isUser }, sessionMessage.id));
}) }), _jsxs("div", { className: Style.bottom, id: "bottom", children: [_jsx("div", { className: Style.toolbar, children: _jsx(Upload, { accept: 'image/*', multiple: false, showUploadList: false, customRequest: () => { }, onChange: ({ file }) => {
customUpload(file);
}, children: _jsx(PictureOutlined, { className: Style.icon }) }) }), _jsxs("div", { className: Style.textareaBox, children: [_jsx(Input.TextArea, { className: Style.textarea, rows: 5, onChange: (e) => {
}, children: _jsx(PictureOutlined, { className: Style.icon }) }) }), _jsxs("div", { className: Style.textareaBox, children: [_jsx(Input.TextArea, { ref: textareaRef, className: Style.textarea,
// autoSize={{ minRows: 2, maxRows: 15 }}
maxLength: 500, placeholder: "Enter \u53D1\u9001\uFF0CShift + Enter\u6362\u884C", rows: 5, onChange: (e) => {
setContent(e.target.value);
}, onFocus: () => {
setButtonHidden(true);
}, onPressEnter: (e) => {
e.preventDefault();
createMessage();
pageScroll('comment');
}, value: text }), _jsx("div", { className: Style.btn, children: _jsx(Button, { type: "primary", disabled: text ? false : true, onClick: () => {
},
// onPressEnter={(e) => {
// e.preventDefault();
// createMessage();
// pageScroll('comment');
// }}
onKeyDown: handleKeyDown, value: text }), _jsx("div", { className: Style.btn, children: _jsx(Button, { type: "primary", disabled: text ? false : true, onClick: () => {
createMessage();
pageScroll('comment');
}, children: "\u53D1\u9001" }) })] })] })] }));

View File

@ -6,5 +6,6 @@ export interface Schema extends EntityShape {
entityId: String<64>;
user?: User;
lmts?: Datetime;
openId?: String<64>;
}
export type Relation = 'partner';

View File

@ -8,6 +8,7 @@ const entityDesc = {
entityId: '关联对象id',
user: '发送者',
lmts: '最后一条消息的发送时间',
openId: 'openId'
},
r: {
partner: '所有者',

View File

@ -17,6 +17,7 @@ export type OpSchema = EntityShape & {
entityId: String<64>;
userId?: ForeignKey<"user"> | null;
lmts?: Datetime | null;
openId?: String<64> | null;
};
export type OpAttr = keyof OpSchema;
export type Schema = EntityShape & {
@ -24,6 +25,7 @@ export type Schema = EntityShape & {
entityId: String<64>;
userId?: ForeignKey<"user"> | null;
lmts?: Datetime | null;
openId?: String<64> | null;
user?: User.Schema | null;
application?: Application.Schema;
readRemark$session?: Array<ReadRemark.Schema>;
@ -49,6 +51,7 @@ type AttrFilter = {
userId: Q_StringValue;
user: User.Filter;
lmts: Q_DateValue;
openId: Q_StringValue;
application: Application.Filter;
readRemark$session: ReadRemark.Filter & SubQueryPredicateMetadata;
sessionMessage$session: SessionMessage.Filter & SubQueryPredicateMetadata;
@ -69,6 +72,7 @@ export type Projection = {
userId?: number;
user?: User.Projection;
lmts?: number;
openId?: number;
application?: Application.Projection;
readRemark$session?: ReadRemark.Selection & {
$entity: "readRemark";
@ -128,6 +132,8 @@ export type SortAttr = {
user: User.SortAttr;
} | {
lmts: number;
} | {
openId: number;
} | {
application: Application.SortAttr;
} | {

View File

@ -22,6 +22,12 @@ export const desc = {
},
lmts: {
type: "datetime"
},
openId: {
type: "varchar",
params: {
length: 64
}
}
},
actionType: "crud",

View File

@ -1 +1 @@
{ "name": "会话", "attr": { "entity": "关联对象", "entityId": "关联对象id", "user": "发送者", "lmts": "最后一条消息的发送时间" }, "r": { "partner": "所有者" } }
{ "name": "会话", "attr": { "entity": "关联对象", "entityId": "关联对象id", "user": "发送者", "lmts": "最后一条消息的发送时间", "openId": "openId" }, "r": { "partner": "所有者" } }

View File

@ -4,5 +4,6 @@ declare const _default: (props: import("oak-frontend-base").ReactComponentProps<
onSelect: (id: string) => void;
key: string;
entityFilter: {};
name: undefined;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -124,6 +124,7 @@ exports.default = OakComponent({
onSelect: (id) => { },
key: '',
entityFilter: {},
name: undefined,
},
methods: {
getAvatarUrl() {

View File

@ -7,6 +7,7 @@ export default function render(props: WebComponentProps<EntityDict, 'session', f
userType: string;
selectedId: string;
onSelect: (id: string) => void;
name: string;
}, {
getName: () => string;
getAvatarUrl: () => string;

View File

@ -8,7 +8,7 @@ const classnames_1 = tslib_1.__importDefault(require("classnames"));
const web_module_less_1 = tslib_1.__importDefault(require("./web.module.less"));
function render(props) {
const { methods, data } = props;
const { selectedId, onSelect, userType, id, unreadLength, sessiontMessages = [], } = data;
const { selectedId, onSelect, userType, id, unreadLength, sessiontMessages = [], name, } = data;
const { t, getName, getAvatarUrl } = methods;
const sessiontMessage = sessiontMessages && sessiontMessages[0];
const createAt = sessiontMessage?.$$createAt$$;
@ -20,7 +20,7 @@ function render(props) {
[web_module_less_1.default.cell_selected]: id === selectedId,
}), onClick: () => {
onSelect(id);
}, children: [(0, jsx_runtime_1.jsx)(antd_1.Badge, { dot: id === selectedId ? false : true, count: unreadLength || 0, children: (0, jsx_runtime_1.jsx)(antd_1.Image, { className: web_module_less_1.default.avatar, src: getAvatarUrl(), preview: false }) }), (0, jsx_runtime_1.jsxs)("div", { className: web_module_less_1.default.inner, children: [(0, jsx_runtime_1.jsxs)("div", { className: web_module_less_1.default.top, children: [(0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.title, children: getName() }), (0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.date, children: sessiontMessage &&
}, children: [(0, jsx_runtime_1.jsx)(antd_1.Badge, { dot: id === selectedId ? false : true, count: unreadLength || 0, children: (0, jsx_runtime_1.jsx)(antd_1.Image, { className: web_module_less_1.default.avatar, src: getAvatarUrl(), preview: false }) }), (0, jsx_runtime_1.jsxs)("div", { className: web_module_less_1.default.inner, children: [(0, jsx_runtime_1.jsxs)("div", { className: web_module_less_1.default.top, children: [(0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.title, children: name || getName() }), (0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.date, children: sessiontMessage &&
(today === createAt2
? (0, dayjs_1.default)(createAt).format('HH:mm')
: (0, dayjs_1.default)(createAt).format('YYYY-MM-DD')) })] }), (0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.message, children: type &&

View File

@ -1,7 +1,6 @@
type HeaderProps = {
showBack: boolean;
/// <reference types="react" />
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, false, {
sessionId: string;
userId: string;
};
declare function Header(props: HeaderProps): import("react/jsx-runtime").JSX.Element;
export default Header;
isEntity: boolean;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -1,26 +1,106 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const antd_1 = require("antd");
const icons_1 = require("@ant-design/icons");
const useFeatures_1 = tslib_1.__importDefault(require("../../..//hooks/useFeatures"));
const classnames_1 = tslib_1.__importDefault(require("classnames"));
const index_module_less_1 = tslib_1.__importDefault(require("./index.module.less"));
const web_1 = require("oak-frontend-base/es/platforms/web");
function Header(props) {
const features = (0, useFeatures_1.default)();
const width = (0, web_1.useWidth)();
const { showBack = true, sessionId, userId } = props;
const [name, setName] = (0, react_1.useState)('');
const [url, setUrl] = (0, react_1.useState)('');
(0, react_1.useEffect)(() => {
if (sessionId) {
const [session] = features.cache?.get('session', {
exports.default = OakComponent({
// entity: 'session',
// projection: {
// id: 1,
// userId: 1,
// entity: 1,
// entityId: 1,
// lmts: 1,
// user: {
// id: 1,
// name: 1,
// nickname: 1,
// mobile$user: {
// $entity: 'mobile',
// data: {
// id: 1,
// mobile: 1,
// userId: 1,
// },
// },
// extraFile$entity: {
// $entity: 'extraFile',
// data: {
// id: 1,
// tag1: 1,
// origin: 1,
// bucket: 1,
// objectId: 1,
// filename: 1,
// extra1: 1,
// extension: 1,
// type: 1,
// entity: 1,
// },
// filter: {
// tag1: {
// $in: ['avatar'],
// },
// },
// },
// },
// },
isList: false,
// formData({ data, features }) {
// const session = Object.assign(
// {},
// data
// ) as any;
// console.log(session)
// Object.assign(session, {
// userUrl: features.extraFile.getUrl(
// session?.user?.extraFile$entity &&
// session?.user?.extraFile$entity[0]
// ),
// });
// // if (session?.sessionMessage$session) {
// // Object.assign(session, {
// // wechatMessages: session?.sessionMessage$session,
// // // unreadLength: session?.sessionMessage$session?.filter(
// // // (ele: any) => ele.isRead === false
// // // )?.length,
// // });
// // }
// return session;
// },
// filters: [
// {
// filter() {
// const { sessionId } = this.props;
// if (sessionId) {
// return {
// id: sessionId,
// };
// }
// },
// },
// ],
lifetimes: {
ready() {
const { sessionId } = this.props;
if (sessionId) {
this.getSession(sessionId);
}
},
},
listeners: {
sessionId(prev, next) {
if (prev.sessionId !== next.sessionId) {
this.getSession(next.sessionId);
}
},
},
properties: {
sessionId: '',
isEntity: false,
},
methods: {
getSession(sessionId) {
const [session] = this.features.cache.get('session', {
data: {
id: 1,
uerId: 1,
user: {
id: 1,
name: 1,
@ -46,7 +126,6 @@ function Header(props) {
extension: 1,
type: 1,
entity: 1,
entityId: 1,
},
filter: {
tag1: {
@ -57,49 +136,41 @@ function Header(props) {
},
},
filter: {
id: sessionId,
},
id: sessionId
}
});
if (session) {
const url2 = getAvatarUrl(session);
setUrl(url2);
const name2 = getName(session);
setName(name2);
this.setState({ session });
},
getAvatarUrl() {
const { userUrl, entity } = this.state;
const { isEntity } = this.props;
const defaultUrl = 'http://qiniu.gecomebox.com/static/defaultAvatar.png';
if (isEntity) {
return userUrl || defaultUrl;
}
}
}, [sessionId, userId]);
const getAvatarUrl = (session) => {
const { entity, user } = session || {};
const defaultUrl = 'http://qiniu.gecomebox.com/static/defaultAvatar.png';
if (user) {
const userAvatar = features.extraFile.getUrl(session?.user?.extraFile$entity &&
session?.user?.extraFile$entity[0]);
return userAvatar || defaultUrl;
}
return defaultUrl;
};
const getName = (session) => {
const { user } = session || {};
if (user) {
const userName = user?.name || '';
const userNickname = user?.name || user?.nickname || '';
const userMobile = (user?.mobile$user &&
user?.mobile$user[0]?.mobile) ||
'';
if (userName) {
return userName;
else {
return defaultUrl;
}
if (userMobile) {
return '用户' + userMobile;
},
getName() {
const { session, entity } = this.state;
const { isEntity } = this.props;
if (isEntity) {
const userName = session?.user?.name;
const userNickname = session?.user?.name || session?.user?.nickname;
const userMobile = session?.user?.mobile$user &&
session?.user?.mobile$user[0]?.mobile;
if (userName) {
return userName;
}
if (userMobile) {
return '用户' + userMobile;
}
return userNickname;
}
return userNickname;
}
return '未知';
};
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(index_module_less_1.default.header, {
[index_module_less_1.default.header_mobile]: width === 'xs'
}), children: [showBack && ((0, jsx_runtime_1.jsx)(antd_1.Button, { type: "text", onClick: () => {
features.navigator.navigateBack();
}, children: (0, jsx_runtime_1.jsx)(icons_1.LeftOutlined, { className: index_module_less_1.default.backIcon }) })), (0, jsx_runtime_1.jsxs)("div", { className: index_module_less_1.default.middle, children: [(0, jsx_runtime_1.jsx)(antd_1.Image, { src: url, className: index_module_less_1.default.icon, preview: false }), (0, jsx_runtime_1.jsx)("div", { className: index_module_less_1.default.name, children: name })] })] }));
}
exports.default = Header;
else {
return '未知';
}
},
},
});

View File

@ -0,0 +1,11 @@
import { WebComponentProps } from 'oak-frontend-base';
import { EntityDict } from '../../../oak-app-domain';
export default function render(props: WebComponentProps<EntityDict, 'session', false, {
avatarUrl: string;
nickname: string;
name: string;
showBack: boolean;
sessionId: string;
}, {
getName: () => string;
}>): import("react/jsx-runtime").JSX.Element;

View File

@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const jsx_runtime_1 = require("react/jsx-runtime");
// import { UserOutlined } from '@ant-design/icons';
const web_module_less_1 = tslib_1.__importDefault(require("./web.module.less"));
const antd_1 = require("antd");
const icons_1 = require("@ant-design/icons");
const useFeatures_1 = tslib_1.__importDefault(require("../../../hooks/useFeatures"));
const classnames_1 = tslib_1.__importDefault(require("classnames"));
const web_1 = require("oak-frontend-base/es/platforms/web");
function render(props) {
const { methods, data } = props;
const { nickname, avatarUrl, name, showBack } = data;
const { getName } = methods;
const defaultUrl = 'http://qiniu.gecomebox.com/static/defaultAvatar.png';
const features = (0, useFeatures_1.default)();
const width = (0, web_1.useWidth)();
return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(web_module_less_1.default.header, {
[web_module_less_1.default.header_mobile]: width === 'xs'
}), children: [showBack && ((0, jsx_runtime_1.jsx)(antd_1.Button, { type: "text", onClick: () => {
features.navigator.navigateBack();
}, children: (0, jsx_runtime_1.jsx)(icons_1.LeftOutlined, { className: web_module_less_1.default.backIcon }) })), (0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.middle, children: (0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.name, children: getName() }) })] }));
}
exports.default = render;

View File

@ -0,0 +1,45 @@
.header {
display: flex;
background: #eee;
flex-direction: row;
align-items: center;
position: fixed;
width: 100%;
z-index: 20;
height: 50px;
position: absolute;
.middle {
display: flex;
flex-direction: row;
flex: 1;
align-items: center;
.icon {
height: 30px;
width: 30px;
align-items: center;
display: flex;
justify-content: center;
margin: 10px;
}
.name {
font-size: 16px;
margin-left: 10px;
}
}
}
.header_mobile {
background: var(--oak-color-primary);
.backIcon {
color: #fff;
}
.name {
font-size: 16px;
color: #fff;
}
}

View File

@ -3,4 +3,5 @@ import { EntityDict } from '../../../oak-app-domain';
export default function render(props: WebComponentProps<EntityDict, 'session', false, {
avatarUrl: string;
nickname: string;
name: string;
}, {}>): import("react/jsx-runtime").JSX.Element;

View File

@ -7,8 +7,8 @@ const antd_1 = require("antd");
const web_module_less_1 = tslib_1.__importDefault(require("./web.module.less"));
function render(props) {
const { methods, data } = props;
const { nickname, avatarUrl } = data;
const { nickname, avatarUrl, name } = data;
const defaultUrl = 'http://qiniu.gecomebox.com/static/defaultAvatar.png';
return ((0, jsx_runtime_1.jsxs)("div", { className: web_module_less_1.default.header, children: [(0, jsx_runtime_1.jsx)(antd_1.Avatar, { shape: "square", className: web_module_less_1.default.avatar, src: avatarUrl || defaultUrl }), (0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.nickname, children: nickname })] }));
return ((0, jsx_runtime_1.jsxs)("div", { className: web_module_less_1.default.header, children: [(0, jsx_runtime_1.jsx)(antd_1.Avatar, { shape: "square", className: web_module_less_1.default.avatar, src: avatarUrl || defaultUrl }), (0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.nickname, children: nickname || name })] }));
}
exports.default = render;

View File

@ -2,7 +2,7 @@
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "session", true, {
entity: string;
entityFilter: any;
entityDisplay: (entity: string, entityId: string) => "";
entityDisplay: (data: any) => "";
entityProjection: any;
sessionId: string;
dialog: boolean;

View File

@ -2,72 +2,86 @@
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = OakComponent({
entity: 'session',
projection: {
id: 1,
entity: 1,
entityId: 1,
userId: 1,
user: {
projection() {
const { entityProjection } = this.props;
const proj = {
id: 1,
name: 1,
nickname: 1,
mobile$user: {
$entity: 'mobile',
data: {
id: 1,
mobile: 1,
userId: 1,
},
},
extraFile$entity: {
$entity: 'extraFile',
data: {
id: 1,
tag1: 1,
origin: 1,
bucket: 1,
objectId: 1,
filename: 1,
extra1: 1,
extension: 1,
type: 1,
entity: 1,
entityId: 1,
},
filter: {
tag1: {
$in: ['avatar'],
},
},
},
},
sessionMessage$session: {
$entity: 'sessionMessage',
data: {
entity: 1,
entityId: 1,
userId: 1,
user: {
id: 1,
text: 1,
type: 1,
userId: 1,
wechatUserId: 1,
createTime: 1,
$$createAt$$: 1,
aaoe: 1,
},
sorter: [
{
$attr: {
$$createAt$$: 1,
name: 1,
nickname: 1,
mobile$user: {
$entity: 'mobile',
data: {
id: 1,
mobile: 1,
userId: 1,
},
$direction: 'desc',
},
],
indexFrom: 0,
count: 1,
},
$$createAt$$: 1,
extraFile$entity: {
$entity: 'extraFile',
data: {
id: 1,
tag1: 1,
origin: 1,
bucket: 1,
objectId: 1,
filename: 1,
extra1: 1,
extension: 1,
type: 1,
entity: 1,
entityId: 1,
},
filter: {
tag1: {
$in: ['avatar'],
},
},
},
},
sessionMessage$session: {
$entity: 'sessionMessage',
data: {
id: 1,
text: 1,
type: 1,
userId: 1,
wechatUserId: 1,
createTime: 1,
$$createAt$$: 1,
aaoe: 1,
},
sorter: [
{
$attr: {
$$createAt$$: 1,
},
$direction: 'desc',
},
],
indexFrom: 0,
count: 1,
},
$$createAt$$: 1,
};
if (entityProjection) {
Object.assign(proj, { ...entityProjection });
}
return proj;
},
isList: true,
formData: function ({ data: sessions, features, props }) {
const { entityDisplay, entityProjection } = this.props;
if (entityProjection && entityDisplay && sessions && sessions.length > 0) {
const sessions1 = entityDisplay(sessions);
return {
sessions: sessions1,
};
}
// const unReadLength = wechatSessions?.filter(
// (ele) => ele.isRead
// )
@ -102,8 +116,8 @@ exports.default = OakComponent({
},
properties: {
entity: '',
entityFilter: {},
entityDisplay: (entity, entityId) => '',
entityFilter: undefined,
entityDisplay: (data) => '',
entityProjection: {},
sessionId: '',
dialog: false,
@ -167,7 +181,7 @@ exports.default = OakComponent({
{
sorter: {
$attr: {
$$updateAt$$: 1,
lmts: 1,
},
$direction: 'desc',
},

View File

@ -5,8 +5,8 @@
}
.bothContainer {
margin: 0 auto;
margin-top: 5vh;
margin: 5vh auto;
// margin-top: 5vh;
width: 90%;
min-width: 600px;
height: 80vh;

View File

@ -1,7 +1,7 @@
import { WebComponentProps } from 'oak-frontend-base';
import { EntityDict } from '../../../oak-app-domain';
export default function Render(props: WebComponentProps<EntityDict, 'session', false, {
sessions: EntityDict['session']['Schema'][];
sessions: any;
selectedSessionId: string;
className: string;
dialog: boolean;

View File

@ -16,14 +16,14 @@ function Render(props) {
return ((0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.container, children: (0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(web_module_less_1.default.bothContainer, className, {
[web_module_less_1.default.dialogContainer]: dialog,
}), children: [(0, jsx_runtime_1.jsxs)("div", { className: web_module_less_1.default.conversationContainer, children: [(0, jsx_runtime_1.jsx)(header_1.default, {}), (0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.inner, children: sessions?.map((session, index) => {
return ((0, jsx_runtime_1.jsx)(cell_1.default, { entityFilter: entityFilter, selectedId: selectedSessionId, onSelect: (id) => {
return ((0, jsx_runtime_1.jsx)(cell_1.default, { entityFilter: entityFilter, name: session?.name, selectedId: selectedSessionId, onSelect: (id) => {
setSelectedSessionId(id);
}, oakId: session.id, oakPath: oakFullpath
? `${oakFullpath}.${session.id}`
: '' }, session.id));
}) })] }), selectedSessionId && ((0, jsx_runtime_1.jsx)(list_1.default, { sessionId: selectedSessionId,
// isCombine={true}
isEntity: !!entityFilter, oakAutoUnmount: true, oakPath: oakFullpath
isEntity: entityFilter ? true : false, isUser: entityFilter ? false : true, oakAutoUnmount: true, oakPath: oakFullpath
? `$$sessionMessage/list`
: undefined }))] }) }));
}

View File

@ -2,5 +2,6 @@
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "sessionMessage", false, {
key: string;
isEntity: boolean;
isUser: boolean;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -18,6 +18,38 @@ exports.default = OakComponent({
id: 1,
entity: 1,
entityId: 1,
userId: 1,
user: {
id: 1,
name: 1,
mobile$user: {
$entity: 'mobile',
data: {
id: 1,
mobile: 1,
},
},
extraFile$entity: {
$entity: 'extraFile',
data: {
id: 1,
tag1: 1,
origin: 1,
bucket: 1,
objectId: 1,
filename: 1,
extra1: 1,
extension: 1,
type: 1,
entity: 1,
},
filter: {
tag1: {
$in: ['avatar'],
},
},
},
},
},
aaoe: 1,
extraFile$entity: {
@ -45,7 +77,7 @@ exports.default = OakComponent({
formData({ data: sessionMessage, features }) {
const type = sessionMessage?.type;
// const data = wechatMessage?.data;
// const session = sessionMessage?.session;
const session = sessionMessage?.session;
const newSessionMessage = {
type,
aaoe: sessionMessage?.aaoe,
@ -54,15 +86,12 @@ exports.default = OakComponent({
id: sessionMessage?.id,
$$createAt$$: sessionMessage?.$$createAt$$,
sessionId: sessionMessage?.sessionId,
// employerId: conversation?.employerId,
// employerMobile:
// conversation?.employer?.mobile$user &&
// conversation?.employer?.mobile$user[0]?.mobile,
userId: session?.userId,
userMobile: session?.user?.mobile$user &&
session?.user?.mobile$user[0]?.mobile,
// companyName: conversation?.company?.name,
// employerAvatar: this.features.extraFile.getUrl(
// conversation?.employer?.extraFile$entity &&
// conversation?.employer?.extraFile$entity[0]
// ),
userAvatar: this.features.extraFile.getUrl(session?.user?.extraFile$entity &&
session?.user?.extraFile$entity[0]),
};
// if (type === 'image') {
// const extraFile$entity =
@ -76,25 +105,35 @@ exports.default = OakComponent({
properties: {
key: '',
isEntity: false,
isUser: false,
},
methods: {
getAvatarUrl(type) {
getAvatarUrl(aaoe) {
const defaultUrl = 'http://qiniu.gecomebox.com/static/defaultAvatar.png';
const { companyLogoUrl, employerAvatar, parkLogoUrl } = this.state;
switch (type) {
case 'company': {
return companyLogoUrl || defaultUrl;
}
case 'employer': {
return employerAvatar || defaultUrl;
}
case 'platformProvider': {
return process.env.PUBLIC_URL + '/logo192.png';
}
case 'park': {
return parkLogoUrl || defaultUrl;
}
const { companyLogoUrl, userAvatar, parkLogoUrl } = this.state;
if (aaoe) {
return defaultUrl;
}
else {
return userAvatar || defaultUrl;
}
// switch (type) {
// case 'company': {
// return companyLogoUrl || defaultUrl;
// }
// case 'user': {
// return userAvatar || defaultUrl;
// }
// case 'platformProvider': {
// return process.env.PUBLIC_URL + '/logo192.png';
// }
// case 'park': {
// return parkLogoUrl || defaultUrl;
// }
// default: {
// return defaultUrl
// }
// }
},
},
});

View File

@ -2,6 +2,7 @@ import { WebComponentProps } from 'oak-frontend-base';
import { EntityDict } from '../../../oak-app-domain';
export default function render(props: WebComponentProps<EntityDict, 'sessionMessage', false, {
isEntity: boolean;
isUser: boolean;
$$createAt$$: number;
text: string;
type: string;
@ -10,5 +11,5 @@ export default function render(props: WebComponentProps<EntityDict, 'sessionMess
sessionId: string;
id: string;
}, {
getAvatarUrl: (type: string) => string;
getAvatarUrl: (aaoe: boolean) => string;
}>): import("react/jsx-runtime").JSX.Element;

View File

@ -8,13 +8,13 @@ const classnames_1 = tslib_1.__importDefault(require("classnames"));
const web_module_less_1 = tslib_1.__importDefault(require("./web.module.less"));
function render(props) {
const { data, methods } = props;
const { $$createAt$$, text, type, picUrl, isEntity, aaoe, sessionId, } = data;
const { $$createAt$$, text, type, picUrl, isEntity, isUser, aaoe, sessionId, } = data;
const { t, getAvatarUrl } = methods;
return ((0, jsx_runtime_1.jsx)(ICell, { time: $$createAt$$, children: (0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(web_module_less_1.default.myMessage, {
[web_module_less_1.default.notMyMessage]: isEntity !== aaoe,
}), children: [(0, jsx_runtime_1.jsx)(antd_1.Image, { preview: false, className: web_module_less_1.default.avatar, src: getAvatarUrl(type) }), (0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)({
[web_module_less_1.default.notMyMessage]: (isEntity && !aaoe) || (isUser && aaoe),
}), children: [(0, jsx_runtime_1.jsx)(antd_1.Image, { preview: false, className: web_module_less_1.default.avatar, src: getAvatarUrl(aaoe) }), (0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)({
[web_module_less_1.default.messageType_text]: type === 'text',
[web_module_less_1.default.messageType_text_no]: isEntity !== aaoe,
[web_module_less_1.default.messageType_text_no]: (isEntity && !aaoe) || (isUser && aaoe),
}), children: [type === 'text' && (0, jsx_runtime_1.jsx)(IText, { value: text }), type === 'image' && (0, jsx_runtime_1.jsx)(IImage, { url: picUrl })] })] }) }));
}
exports.default = render;
@ -27,7 +27,12 @@ function ICell(props) {
}
function IText(props) {
const { value } = props;
return (0, jsx_runtime_1.jsx)("div", { children: value });
return (0, jsx_runtime_1.jsx)("div", { style: { whiteSpace: 'pre-wrap' }, children: value });
// return <div>
// <Typography.Paragraph>
// {value}
// </Typography.Paragraph>
// </div>;
}
function IImage(props) {
const { url } = props;

View File

@ -49,7 +49,7 @@
}
.avatar {
margin: 10px;
margin: 0 10px;
height: 30px !important;
width: 30px !important;
padding: 0 !important;
@ -93,7 +93,8 @@
display: flex;
flex-direction: row-reverse;
justify-content: flex-start;
align-items: baseline;
align-items: flex-start;
margin-bottom: 10px;
}
.notMyMessage {

View File

@ -3,6 +3,7 @@ import { EntityDict } from '../../../oak-app-domain';
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<EntityDict, "sessionMessage", true, {
sessionId: string;
isEntity: boolean;
isUser: boolean;
dialog: boolean;
entity: string;
entityId: string;

View File

@ -45,7 +45,7 @@ exports.default = OakComponent({
lifetimes: {
async ready() {
const { sessionId } = this.props;
this.subData([
await this.subData([
{
entity: 'sessionMessage',
filter: {
@ -53,7 +53,7 @@ exports.default = OakComponent({
},
id: `${constants_1.DATA_SUBSCRIBER_KEYS.sessionMessageList}-${sessionId}`,
}
]);
], async () => { await this.pageScroll('comment'); });
// const userId = this.features.token.getUserId(true);
// const applicationId = this.features.application.getApplicationId();
// if (!sessionId) {
@ -120,6 +120,7 @@ exports.default = OakComponent({
properties: {
sessionId: '',
isEntity: false,
isUser: false,
dialog: false,
entity: '',
entityId: '',
@ -268,7 +269,7 @@ exports.default = OakComponent({
fileType: type,
size,
extension,
entity: 'wechatMessage',
entity: 'sessionMessage',
bucket: '',
id: (0, uuid_1.generateNewId)(),
};

View File

@ -12,7 +12,7 @@
display: flex;
overflow: scroll;
flex-direction: column;
// margin-top: 50px;
margin-top: 50px;
overflow-x: hidden;
height: 100%;
}
@ -37,6 +37,8 @@
position: absolute;
z-index: 100;
// resize: both;
// cursor: nwse-resize;
.toolbar {
display: flex;
flex-direction: row;
@ -56,14 +58,17 @@
padding: 0 10px;
.textarea {
border: none;
outline: none;
resize: none;
}
.textarea:focus {
border: none;
box-shadow: none;
resize: none;
}
.btn {

View File

@ -12,6 +12,7 @@ export default function Render(props: WebComponentProps<EntityDict, 'sessionMess
buttonHidden: boolean;
sessionId: string;
isEntity: boolean;
isUser: boolean;
employerId: string;
}, {
setButtonHidden: (isHidden: boolean) => void;

View File

@ -6,12 +6,17 @@ const react_1 = require("react");
const antd_1 = require("antd");
const icons_1 = require("@ant-design/icons");
const cell_1 = tslib_1.__importDefault(require("../../../components/sessionMessage/cell"));
const forMessage_1 = tslib_1.__importDefault(require("../../../components/session/forMessage"));
const web_module_less_1 = tslib_1.__importDefault(require("./web.module.less"));
function Render(props) {
const { data, methods } = props;
const { sessionId, isEntity, sessionMessageList, oakFullpath, text, employerId, buttonHidden, } = data;
const { sessionId, isEntity, isUser, sessionMessageList, oakFullpath, text, employerId, buttonHidden, } = data;
const { setButtonHidden, customUpload, setContent, pageScroll, createMessage, } = methods;
const [bottomHeight, setBottomHeight] = (0, react_1.useState)(0);
const textareaRef = (0, react_1.useRef)(null);
// const [text1, setText1] = useState("");
// const newBottomHeight =
// window.document.getElementById('bottom')?.offsetHeight!;
(0, react_1.useEffect)(() => {
if (buttonHidden) {
const newBottomHeight = window.document.getElementById('bottom')?.offsetHeight;
@ -21,7 +26,42 @@ function Render(props) {
setBottomHeight(0);
}
}, [buttonHidden]);
return ((0, jsx_runtime_1.jsxs)("div", { className: web_module_less_1.default.container, children: [(0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.inner, style: {
const handleKeyDown = (event) => {
// if (event.key === "Enter" && event.shiftKey) {
// event.preventDefault(); // 阻止默认的换行行为
// 执行你的换行逻辑
// setContent(text + "\n");
// if (textareaRef && textareaRef.current && textareaRef.current!.resizableTextArea) {
// const textArea = textareaRef.current.resizableTextArea.textAreaRef; // 获取 Input.TextArea 的原生 textarea 元素
// console.log(textArea)
// if (textArea) {
// console.log(textArea)
// const selectionStart = textArea?.selectionStart;
// const value = textArea?.value;
// const newValue =
// value?.substring(0, selectionStart) +
// "\n" +
// value?.substring(selectionStart);
// textArea.value = newValue;
// textArea.selectionStart = textArea.selectionEnd = selectionStart + 1;
// // 触发 onChange 事件,更新 Input.TextArea 的值
// textArea.dispatchEvent(new Event("input"));
// }
// }
// }
if (event.key === "Enter" && !event.shiftKey) {
event.preventDefault();
createMessage();
pageScroll('comment');
}
};
return ((0, jsx_runtime_1.jsxs)("div", { className: web_module_less_1.default.container, children: [(0, jsx_runtime_1.jsx)(forMessage_1.default
// showBack={false}
, {
// showBack={false}
sessionId: sessionId, isEntity: isEntity,
// userId={employerId}
oakPath: 'session:header1', oakAutoUnmount: true }), (0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.inner, style: {
marginBottom: bottomHeight ? `${bottomHeight}px` : '168px',
}, id: "comment", onClick: () => setButtonHidden(true), children: sessionMessageList
?.sort((a, b) => a.$$createAt$$ -
@ -29,18 +69,22 @@ function Render(props) {
.map((sessionMessage, index) => {
return ((0, jsx_runtime_1.jsx)(cell_1.default, { oakId: sessionMessage.id, oakPath: oakFullpath
? `${oakFullpath}.${sessionMessage.id}`
: '', isEntity: isEntity }, sessionMessage.id));
: '', isEntity: isEntity, isUser: isUser }, sessionMessage.id));
}) }), (0, jsx_runtime_1.jsxs)("div", { className: web_module_less_1.default.bottom, id: "bottom", children: [(0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.toolbar, children: (0, jsx_runtime_1.jsx)(antd_1.Upload, { accept: 'image/*', multiple: false, showUploadList: false, customRequest: () => { }, onChange: ({ file }) => {
customUpload(file);
}, children: (0, jsx_runtime_1.jsx)(icons_1.PictureOutlined, { className: web_module_less_1.default.icon }) }) }), (0, jsx_runtime_1.jsxs)("div", { className: web_module_less_1.default.textareaBox, children: [(0, jsx_runtime_1.jsx)(antd_1.Input.TextArea, { className: web_module_less_1.default.textarea, rows: 5, onChange: (e) => {
}, children: (0, jsx_runtime_1.jsx)(icons_1.PictureOutlined, { className: web_module_less_1.default.icon }) }) }), (0, jsx_runtime_1.jsxs)("div", { className: web_module_less_1.default.textareaBox, children: [(0, jsx_runtime_1.jsx)(antd_1.Input.TextArea, { ref: textareaRef, className: web_module_less_1.default.textarea,
// autoSize={{ minRows: 2, maxRows: 15 }}
maxLength: 500, placeholder: "Enter \u53D1\u9001\uFF0CShift + Enter\u6362\u884C", rows: 5, onChange: (e) => {
setContent(e.target.value);
}, onFocus: () => {
setButtonHidden(true);
}, onPressEnter: (e) => {
e.preventDefault();
createMessage();
pageScroll('comment');
}, value: text }), (0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.btn, children: (0, jsx_runtime_1.jsx)(antd_1.Button, { type: "primary", disabled: text ? false : true, onClick: () => {
},
// onPressEnter={(e) => {
// e.preventDefault();
// createMessage();
// pageScroll('comment');
// }}
onKeyDown: handleKeyDown, value: text }), (0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.btn, children: (0, jsx_runtime_1.jsx)(antd_1.Button, { type: "primary", disabled: text ? false : true, onClick: () => {
createMessage();
pageScroll('comment');
}, children: "\u53D1\u9001" }) })] })] })] }));

View File

@ -6,5 +6,6 @@ export interface Schema extends EntityShape {
entityId: String<64>;
user?: User;
lmts?: Datetime;
openId?: String<64>;
}
export type Relation = 'partner';

View File

@ -10,6 +10,7 @@ const entityDesc = {
entityId: '关联对象id',
user: '发送者',
lmts: '最后一条消息的发送时间',
openId: 'openId'
},
r: {
partner: '所有者',

View File

@ -17,6 +17,7 @@ export type OpSchema = EntityShape & {
entityId: String<64>;
userId?: ForeignKey<"user"> | null;
lmts?: Datetime | null;
openId?: String<64> | null;
};
export type OpAttr = keyof OpSchema;
export type Schema = EntityShape & {
@ -24,6 +25,7 @@ export type Schema = EntityShape & {
entityId: String<64>;
userId?: ForeignKey<"user"> | null;
lmts?: Datetime | null;
openId?: String<64> | null;
user?: User.Schema | null;
application?: Application.Schema;
readRemark$session?: Array<ReadRemark.Schema>;
@ -49,6 +51,7 @@ type AttrFilter = {
userId: Q_StringValue;
user: User.Filter;
lmts: Q_DateValue;
openId: Q_StringValue;
application: Application.Filter;
readRemark$session: ReadRemark.Filter & SubQueryPredicateMetadata;
sessionMessage$session: SessionMessage.Filter & SubQueryPredicateMetadata;
@ -69,6 +72,7 @@ export type Projection = {
userId?: number;
user?: User.Projection;
lmts?: number;
openId?: number;
application?: Application.Projection;
readRemark$session?: ReadRemark.Selection & {
$entity: "readRemark";
@ -128,6 +132,8 @@ export type SortAttr = {
user: User.SortAttr;
} | {
lmts: number;
} | {
openId: number;
} | {
application: Application.SortAttr;
} | {

View File

@ -25,6 +25,12 @@ exports.desc = {
},
lmts: {
type: "datetime"
},
openId: {
type: "varchar",
params: {
length: 64
}
}
},
actionType: "crud",

View File

@ -1 +1 @@
{ "name": "会话", "attr": { "entity": "关联对象", "entityId": "关联对象id", "user": "发送者", "lmts": "最后一条消息的发送时间" }, "r": { "partner": "所有者" } }
{ "name": "会话", "attr": { "entity": "关联对象", "entityId": "关联对象id", "user": "发送者", "lmts": "最后一条消息的发送时间", "openId": "openId" }, "r": { "partner": "所有者" } }

View File

@ -134,6 +134,7 @@ export default OakComponent({
onSelect: (id: string) => { },
key: '' as string,
entityFilter: {},
name: undefined,
},
methods: {
getAvatarUrl() {
@ -164,6 +165,7 @@ export default OakComponent({
return '用户' + userMobile;
}
return userNickname;
} else {
return '未知';

View File

@ -19,6 +19,7 @@ export default function render(
userType: string;
selectedId: string;
onSelect: (id: string) => void;
name: string;
},
{
getName: () => string;
@ -34,6 +35,7 @@ export default function render(
id,
unreadLength,
sessiontMessages = [],
name,
} = data;
const { t, getName, getAvatarUrl } = methods;
const sessiontMessage = sessiontMessages && sessiontMessages[0];
@ -67,7 +69,7 @@ export default function render(
</Badge>
<div className={Style.inner}>
<div className={Style.top}>
<div className={Style.title}>{getName()}</div>
<div className={Style.title}>{name || getName()}</div>
<div className={Style.date}>
{sessiontMessage &&
(today === createAt2

View File

@ -0,0 +1,183 @@
import { OpSchema as ExtraFile } from '../../../oak-app-domain/ExtraFile/Schema';
export default OakComponent({
// entity: 'session',
// projection: {
// id: 1,
// userId: 1,
// entity: 1,
// entityId: 1,
// lmts: 1,
// user: {
// id: 1,
// name: 1,
// nickname: 1,
// mobile$user: {
// $entity: 'mobile',
// data: {
// id: 1,
// mobile: 1,
// userId: 1,
// },
// },
// extraFile$entity: {
// $entity: 'extraFile',
// data: {
// id: 1,
// tag1: 1,
// origin: 1,
// bucket: 1,
// objectId: 1,
// filename: 1,
// extra1: 1,
// extension: 1,
// type: 1,
// entity: 1,
// },
// filter: {
// tag1: {
// $in: ['avatar'],
// },
// },
// },
// },
// },
isList: false,
// formData({ data, features }) {
// const session = Object.assign(
// {},
// data
// ) as any;
// console.log(session)
// Object.assign(session, {
// userUrl: features.extraFile.getUrl(
// session?.user?.extraFile$entity &&
// session?.user?.extraFile$entity[0]
// ),
// });
// // if (session?.sessionMessage$session) {
// // Object.assign(session, {
// // wechatMessages: session?.sessionMessage$session,
// // // unreadLength: session?.sessionMessage$session?.filter(
// // // (ele: any) => ele.isRead === false
// // // )?.length,
// // });
// // }
// return session;
// },
// filters: [
// {
// filter() {
// const { sessionId } = this.props;
// if (sessionId) {
// return {
// id: sessionId,
// };
// }
// },
// },
// ],
lifetimes: {
ready() {
const { sessionId } = this.props;
if (sessionId) {
this.getSession(sessionId)
}
},
},
listeners: {
sessionId(prev, next) {
if (prev.sessionId !== next.sessionId) {
this.getSession(next.sessionId);
}
},
},
properties: {
sessionId: '' as string,
isEntity: false,
},
methods: {
getSession(sessionId: string) {
const [session] = this.features.cache.get(
'session',
{
data: {
id: 1,
user: {
id: 1,
name: 1,
nickname: 1,
mobile$user: {
$entity: 'mobile',
data: {
id: 1,
mobile: 1,
userId: 1,
},
},
extraFile$entity: {
$entity: 'extraFile',
data: {
id: 1,
tag1: 1,
origin: 1,
bucket: 1,
objectId: 1,
filename: 1,
extra1: 1,
extension: 1,
type: 1,
entity: 1,
},
filter: {
tag1: {
$in: ['avatar'],
},
},
},
},
},
filter: {
id: sessionId
}
}
);
this.setState({ session })
},
getAvatarUrl() {
const { userUrl, entity } = this.state;
const { isEntity } = this.props;
const defaultUrl =
'http://qiniu.gecomebox.com/static/defaultAvatar.png';
if (isEntity) {
return userUrl || defaultUrl;
} else {
return defaultUrl;
}
},
getName() {
const { session, entity } = this.state;
const { isEntity } = this.props;
if (isEntity) {
const userName = session?.user?.name;
const userNickname = session?.user?.name || session?.user?.nickname;
const userMobile =
session?.user?.mobile$user &&
session?.user?.mobile$user[0]?.mobile;
if (userName) {
return userName;
}
if (userMobile) {
return '用户' + userMobile;
}
return userNickname;
} else {
return '未知';
}
},
},
});

View File

@ -1,147 +0,0 @@
import React, { useState, useEffect } from 'react';
import { Button, Image } from 'antd';
import { LeftOutlined } from '@ant-design/icons';
import useFeatures from '../../..//hooks/useFeatures';
import classNames from 'classnames';
import { EntityDict } from '../../../oak-app-domain';
import Style from './index.module.less';
import { useWidth } from 'oak-frontend-base/es/platforms/web';
type HeaderProps = {
showBack: boolean;
sessionId: string;
userId: string; //雇主
};
function Header(props: HeaderProps) {
const features = useFeatures();
const width = useWidth();
const { showBack = true, sessionId, userId } = props;
const [name, setName] = useState('');
const [url, setUrl] = useState('');
useEffect(() => {
if (sessionId) {
const [session] = features.cache?.get(
'session',
{
data: {
id: 1,
uerId: 1, //顾客
user: {
id: 1,
name: 1,
nickname: 1,
mobile$user: {
$entity: 'mobile',
data: {
id: 1,
mobile: 1,
userId: 1,
},
},
extraFile$entity: {
$entity: 'extraFile',
data: {
id: 1,
tag1: 1,
origin: 1,
bucket: 1,
objectId: 1,
filename: 1,
extra1: 1,
extension: 1,
type: 1,
entity: 1,
entityId: 1,
},
filter: {
tag1: {
$in: ['avatar'],
},
},
},
},
},
filter: {
id: sessionId!,
},
}
);
if (session) {
const url2 = getAvatarUrl(session);
setUrl(url2);
const name2 = getName(session);
setName(name2);
}
}
}, [sessionId, userId]);
const getAvatarUrl = (
session: Partial<EntityDict['session']['Schema']>
) => {
const { entity, user } = session || {};
const defaultUrl = 'http://qiniu.gecomebox.com/static/defaultAvatar.png';
if (user) {
const userAvatar = features.extraFile.getUrl(
session?.user?.extraFile$entity &&
session?.user?.extraFile$entity[0]
);
return userAvatar || defaultUrl;
}
return defaultUrl;
};
const getName = (
session: Partial<EntityDict['session']['Schema']>
): string => {
const { user } =
session || {};
if (user) {
const userName = user?.name || '';
const userNickname = user?.name || user?.nickname || '';
const userMobile =
(user?.mobile$user &&
user?.mobile$user[0]?.mobile) ||
'';
if (userName) {
return userName;
}
if (userMobile) {
return '用户' + userMobile;
}
return userNickname;
}
return '未知';
};
return (
<div className={classNames(Style.header, {
[Style.header_mobile]: width === 'xs'
})}>
{showBack && (
<Button
type="text"
onClick={() => {
features.navigator.navigateBack();
}}
>
<LeftOutlined className={Style.backIcon} />
</Button>
)}
<div className={Style.middle}>
<Image src={url} className={Style.icon} preview={false} />
<div className={Style.name}>{name}</div>
</div>
</div>
);
}
export default Header;

View File

@ -0,0 +1,45 @@
.header {
display: flex;
background: #eee;
flex-direction: row;
align-items: center;
position: fixed;
width: 100%;
z-index: 20;
height: 50px;
position: absolute;
.middle {
display: flex;
flex-direction: row;
flex: 1;
align-items: center;
.icon {
height: 30px;
width: 30px;
align-items: center;
display: flex;
justify-content: center;
margin: 10px;
}
.name {
font-size: 16px;
margin-left: 10px;
}
}
}
.header_mobile {
background: var(--oak-color-primary);
.backIcon {
color: #fff;
}
.name {
font-size: 16px;
color: #fff;
}
}

View File

@ -0,0 +1,54 @@
import React from "react";
import { Avatar } from 'antd';
// import { UserOutlined } from '@ant-design/icons';
import Style from './web.module.less';
import { WebComponentProps } from 'oak-frontend-base';
import { EntityDict } from '../../../oak-app-domain';
import { Button, Image } from 'antd';
import { LeftOutlined } from '@ant-design/icons';
import useFeatures from '../../../hooks/useFeatures';
import classNames from 'classnames';
import { useWidth } from 'oak-frontend-base/es/platforms/web';
export default function render(props: WebComponentProps<
EntityDict,
'session',
false,
{
avatarUrl: string,
nickname: string,
name: string,
showBack: boolean;
sessionId: string;
},
{
getName: () => string;
}
>) {
const { methods, data } = props;
const { nickname, avatarUrl, name, showBack } = data;
const { getName } = methods;
const defaultUrl = 'http://qiniu.gecomebox.com/static/defaultAvatar.png'
const features = useFeatures();
const width = useWidth();
return (
<div className={classNames(Style.header, {
[Style.header_mobile]: width === 'xs'
})}>
{showBack && (
<Button
type="text"
onClick={() => {
features.navigator.navigateBack();
}}
>
<LeftOutlined className={Style.backIcon} />
</Button>
)}
<div className={Style.middle}>
{/* <Image src={url} className={Style.icon} preview={false} /> */}
<div className={Style.name}>{getName()}</div>
</div>
</div>
);
}

View File

@ -11,7 +11,6 @@ export default OakComponent({
(ele: ExtraFile) => ele.tag1 === 'avatar'
);
const avatarUrl = features.extraFile.getUrl(extraFile);
return {
mobile,
avatarUrl,

View File

@ -13,13 +13,14 @@ export default function render(props: WebComponentProps<
{
avatarUrl: string,
nickname: string,
name: string,
},
{
}
>) {
const { methods, data } = props;
const { nickname, avatarUrl } = data;
const { nickname, avatarUrl, name } = data;
const defaultUrl = 'http://qiniu.gecomebox.com/static/defaultAvatar.png'
return (
@ -43,7 +44,7 @@ export default function render(props: WebComponentProps<
src={avatarUrl || defaultUrl}
/>
<div className={Style.nickname}>{nickname}</div>
<div className={Style.nickname}>{nickname || name}</div>
</div>
);
}

View File

@ -2,72 +2,88 @@ import assert from "assert";
export default OakComponent({
entity: 'session',
projection: {
id: 1,
entity: 1,
entityId: 1,
userId: 1,
user: {
projection() {
const { entityProjection } = this.props;
const proj = {
id: 1,
name: 1,
nickname: 1,
mobile$user: {
$entity: 'mobile',
data: {
id: 1,
mobile: 1,
userId: 1,
},
},
extraFile$entity: {
$entity: 'extraFile',
data: {
id: 1,
tag1: 1,
origin: 1,
bucket: 1,
objectId: 1,
filename: 1,
extra1: 1,
extension: 1,
type: 1,
entity: 1,
entityId: 1,
},
filter: {
tag1: {
$in: ['avatar'],
},
},
},
},
sessionMessage$session: {
$entity: 'sessionMessage',
data: {
entity: 1,
entityId: 1,
userId: 1,
user: {
id: 1,
text: 1,
type: 1,
userId: 1,
wechatUserId: 1,
createTime: 1,
$$createAt$$: 1,
aaoe: 1,
},
sorter: [
{
$attr: {
$$createAt$$: 1,
name: 1,
nickname: 1,
mobile$user: {
$entity: 'mobile',
data: {
id: 1,
mobile: 1,
userId: 1,
},
$direction: 'desc',
},
],
indexFrom: 0,
count: 1,
},
$$createAt$$: 1,
extraFile$entity: {
$entity: 'extraFile',
data: {
id: 1,
tag1: 1,
origin: 1,
bucket: 1,
objectId: 1,
filename: 1,
extra1: 1,
extension: 1,
type: 1,
entity: 1,
entityId: 1,
},
filter: {
tag1: {
$in: ['avatar'],
},
},
},
},
sessionMessage$session: {
$entity: 'sessionMessage',
data: {
id: 1,
text: 1,
type: 1,
userId: 1,
wechatUserId: 1,
createTime: 1,
$$createAt$$: 1,
aaoe: 1,
},
sorter: [
{
$attr: {
$$createAt$$: 1,
},
$direction: 'desc',
},
],
indexFrom: 0,
count: 1,
},
$$createAt$$: 1,
};
if (entityProjection) {
Object.assign(proj, { ...entityProjection })
}
return proj;
},
isList: true,
formData: function ({ data: sessions, features, props }) {
const { entityDisplay, entityProjection } = this.props;
if (entityProjection && entityDisplay && sessions && sessions.length > 0) {
const sessions1 = entityDisplay(sessions)
return {
sessions: sessions1,
}
}
// const unReadLength = wechatSessions?.filter(
// (ele) => ele.isRead
// )
@ -102,8 +118,8 @@ export default OakComponent({
},
properties: {
entity: '' as string, // entity端指示相应的entity
entityFilter: {} as any, // entity端指示相应的entity查询条件
entityDisplay: (entity: string, entityId: string) => '', // user端指示如何显示entity对象名称
entityFilter: undefined as any, // entity端指示相应的entity查询条件
entityDisplay: (data: any) => '', // user端指示如何显示entity对象名称
entityProjection: {} as any, // user端指示需要取哪些entity的属性来显示entityDisplay
sessionId: '' as string, // 指示需要打开的默认session
dialog: false as boolean,
@ -168,7 +184,7 @@ export default OakComponent({
{
sorter: {
$attr: {
$$updateAt$$: 1,
lmts: 1,
},
$direction: 'desc',
},

View File

@ -5,8 +5,8 @@
}
.bothContainer {
margin: 0 auto;
margin-top: 5vh;
margin: 5vh auto;
// margin-top: 5vh;
width: 90%;
min-width: 600px;
height: 80vh;

View File

@ -15,7 +15,7 @@ export default function Render(
'session',
false,
{
sessions: EntityDict['session']['Schema'][];
sessions: any;
selectedSessionId: string;
// unReadConversation: number;
className: string;
@ -52,10 +52,11 @@ export default function Render(
// clear={clearUnRead}
/> */}
<div className={Style.inner}>
{sessions?.map((session, index: number) => {
{sessions?.map((session: any, index: number) => {
return (
<SessionCell
entityFilter={entityFilter}
name={session?.name}
selectedId={selectedSessionId}
onSelect={(id: string) => {
setSelectedSessionId(id);
@ -76,7 +77,8 @@ export default function Render(
<MessageList
sessionId={selectedSessionId}
// isCombine={true}
isEntity={!!entityFilter}
isEntity={entityFilter ? true : false}
isUser={entityFilter ? false : true}
oakAutoUnmount={true}
oakPath={
oakFullpath

View File

@ -17,6 +17,38 @@ export default OakComponent({
id: 1,
entity: 1,
entityId: 1,
userId: 1,
user: {
id: 1,
name: 1,
mobile$user: {
$entity: 'mobile',
data: {
id: 1,
mobile: 1,
},
},
extraFile$entity: {
$entity: 'extraFile',
data: {
id: 1,
tag1: 1,
origin: 1,
bucket: 1,
objectId: 1,
filename: 1,
extra1: 1,
extension: 1,
type: 1,
entity: 1,
},
filter: {
tag1: {
$in: ['avatar'],
},
},
},
},
},
aaoe: 1,
extraFile$entity: {
@ -44,7 +76,7 @@ export default OakComponent({
formData({ data: sessionMessage, features }) {
const type = sessionMessage?.type;
// const data = wechatMessage?.data;
// const session = sessionMessage?.session;
const session = sessionMessage?.session;
const newSessionMessage = {
type,
aaoe: sessionMessage?.aaoe,
@ -53,15 +85,15 @@ export default OakComponent({
id: sessionMessage?.id,
$$createAt$$: sessionMessage?.$$createAt$$,
sessionId: sessionMessage?.sessionId,
// employerId: conversation?.employerId,
// employerMobile:
// conversation?.employer?.mobile$user &&
// conversation?.employer?.mobile$user[0]?.mobile,
userId: session?.userId,
userMobile:
session?.user?.mobile$user &&
session?.user?.mobile$user[0]?.mobile,
// companyName: conversation?.company?.name,
// employerAvatar: this.features.extraFile.getUrl(
// conversation?.employer?.extraFile$entity &&
// conversation?.employer?.extraFile$entity[0]
// ),
userAvatar: this.features.extraFile.getUrl(
session?.user?.extraFile$entity &&
session?.user?.extraFile$entity[0]
),
};
// if (type === 'image') {
@ -78,26 +110,36 @@ export default OakComponent({
properties: {
key: '' as string,
isEntity: false,
isUser: false,
},
methods: {
getAvatarUrl(type: string) {
getAvatarUrl(aaoe: boolean) {
const defaultUrl =
'http://qiniu.gecomebox.com/static/defaultAvatar.png';
const { companyLogoUrl, employerAvatar, parkLogoUrl } = this.state;
switch (type) {
case 'company': {
return companyLogoUrl || defaultUrl;
}
case 'employer': {
return employerAvatar || defaultUrl;
}
case 'platformProvider': {
return process.env.PUBLIC_URL + '/logo192.png';
}
case 'park': {
return parkLogoUrl || defaultUrl;
}
const { companyLogoUrl, userAvatar, parkLogoUrl } = this.state;
if (aaoe) {
return defaultUrl
}
else {
return userAvatar || defaultUrl;
}
// switch (type) {
// case 'company': {
// return companyLogoUrl || defaultUrl;
// }
// case 'user': {
// return userAvatar || defaultUrl;
// }
// case 'platformProvider': {
// return process.env.PUBLIC_URL + '/logo192.png';
// }
// case 'park': {
// return parkLogoUrl || defaultUrl;
// }
// default: {
// return defaultUrl
// }
// }
},
},
});

View File

@ -49,7 +49,7 @@
}
.avatar {
margin: 10px;
margin: 0 10px;
height: 30px !important;
width: 30px !important;
padding: 0 !important;
@ -93,7 +93,8 @@
display: flex;
flex-direction: row-reverse;
justify-content: flex-start;
align-items: baseline;
align-items: flex-start;
margin-bottom: 10px;
}
.notMyMessage {

View File

@ -1,5 +1,5 @@
import React from 'react';
import { Image } from 'antd';
import { Image, Typography } from 'antd';
import dayjs from 'dayjs';
import classNames from 'classnames';
import { WebComponentProps } from 'oak-frontend-base';
@ -13,6 +13,7 @@ export default function render(
false,
{
isEntity: boolean;
isUser: boolean;
$$createAt$$: number;
text: string;
type: string;
@ -22,7 +23,7 @@ export default function render(
id: string;
},
{
getAvatarUrl: (type: string) => string;
getAvatarUrl: (aaoe: boolean) => string;
}
>
) {
@ -33,6 +34,7 @@ export default function render(
type,
picUrl,
isEntity,
isUser,
aaoe,
sessionId,
} = data;
@ -41,18 +43,18 @@ export default function render(
<ICell time={$$createAt$$}>
<div
className={classNames(Style.myMessage, {
[Style.notMyMessage]: isEntity !== aaoe,
[Style.notMyMessage]: (isEntity && !aaoe) || (isUser && aaoe),
})}
>
<Image
preview={false}
className={Style.avatar}
src={getAvatarUrl(type)}
src={getAvatarUrl(aaoe)}
/>
<div
className={classNames({
[Style.messageType_text]: type === 'text',
[Style.messageType_text_no]: isEntity !== aaoe,
[Style.messageType_text_no]: (isEntity && !aaoe) || (isUser && aaoe),
})}
>
@ -91,7 +93,12 @@ type ITextProps = {
function IText(props: ITextProps) {
const { value } = props;
return <div>{value}</div>;
return <div style={{ whiteSpace: 'pre-wrap' }}>{value}</div>;
// return <div>
// <Typography.Paragraph>
// {value}
// </Typography.Paragraph>
// </div>;
}
type IImageProps = {

View File

@ -44,7 +44,7 @@ export default OakComponent({
lifetimes: {
async ready() {
const { sessionId } = this.props;
this.subData([
await this.subData([
{
entity: 'sessionMessage',
filter: {
@ -52,7 +52,9 @@ export default OakComponent({
},
id: `${DATA_SUBSCRIBER_KEYS.sessionMessageList}-${sessionId}`,
}
])
],
async () => { await this.pageScroll('comment') }
)
// const userId = this.features.token.getUserId(true);
// const applicationId = this.features.application.getApplicationId();
// if (!sessionId) {
@ -121,6 +123,7 @@ export default OakComponent({
properties: {
sessionId: '' as string,
isEntity: false as boolean,
isUser: false as boolean,
dialog: false as boolean,
entity: '',
entityId: '',
@ -281,7 +284,7 @@ export default OakComponent({
fileType: type,
size,
extension,
entity: 'wechatMessage',
entity: 'sessionMessage',
bucket: '',
id: generateNewId(),
} as EntityDict['extraFile']['CreateSingle']['data'];

View File

@ -12,7 +12,7 @@
display: flex;
overflow: scroll;
flex-direction: column;
// margin-top: 50px;
margin-top: 50px;
overflow-x: hidden;
height: 100%;
}
@ -37,6 +37,8 @@
position: absolute;
z-index: 100;
// resize: both;
// cursor: nwse-resize;
.toolbar {
display: flex;
flex-direction: row;
@ -56,14 +58,17 @@
padding: 0 10px;
.textarea {
border: none;
outline: none;
resize: none;
}
.textarea:focus {
border: none;
box-shadow: none;
resize: none;
}
.btn {

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useRef } from 'react';
import { Button, Image, Input, Upload, Modal } from 'antd';
import { PictureOutlined, ShoppingCartOutlined } from '@ant-design/icons';
import MessageCell from '../../../components/sessionMessage/cell';
@ -25,6 +25,7 @@ export default function Render(
buttonHidden: boolean;
sessionId: string;
isEntity: boolean;
isUser: boolean;
employerId: string;
},
{
@ -40,6 +41,7 @@ export default function Render(
const {
sessionId,
isEntity,
isUser,
sessionMessageList,
oakFullpath,
text,
@ -54,6 +56,10 @@ export default function Render(
createMessage,
} = methods;
const [bottomHeight, setBottomHeight] = useState(0);
const textareaRef = useRef(null);
// const [text1, setText1] = useState("");
// const newBottomHeight =
// window.document.getElementById('bottom')?.offsetHeight!;
useEffect(() => {
if (buttonHidden) {
const newBottomHeight =
@ -63,14 +69,50 @@ export default function Render(
setBottomHeight(0);
}
}, [buttonHidden]);
const handleKeyDown = (event: any) => {
// if (event.key === "Enter" && event.shiftKey) {
// event.preventDefault(); // 阻止默认的换行行为
// 执行你的换行逻辑
// setContent(text + "\n");
// if (textareaRef && textareaRef.current && textareaRef.current!.resizableTextArea) {
// const textArea = textareaRef.current.resizableTextArea.textAreaRef; // 获取 Input.TextArea 的原生 textarea 元素
// console.log(textArea)
// if (textArea) {
// console.log(textArea)
// const selectionStart = textArea?.selectionStart;
// const value = textArea?.value;
// const newValue =
// value?.substring(0, selectionStart) +
// "\n" +
// value?.substring(selectionStart);
// textArea.value = newValue;
// textArea.selectionStart = textArea.selectionEnd = selectionStart + 1;
// // 触发 onChange 事件,更新 Input.TextArea 的值
// textArea.dispatchEvent(new Event("input"));
// }
// }
// }
if (event.key === "Enter" && !event.shiftKey) {
event.preventDefault();
createMessage();
pageScroll('comment');
}
};
return (
<div className={Style.container}>
{/* <Header
showBack={false}
<Header
// showBack={false}
sessionId={sessionId}
userId={employerId}
/> */}
isEntity={isEntity}
// userId={employerId}
oakPath={
'session:header1'
}
oakAutoUnmount={true}
/>
<div
className={Style.inner}
style={{
@ -96,6 +138,7 @@ export default function Render(
: ''
}
isEntity={isEntity}
isUser={isUser}
/>
);
})}
@ -117,7 +160,11 @@ export default function Render(
</div>
<div className={Style.textareaBox}>
<Input.TextArea
ref={textareaRef}
className={Style.textarea}
// autoSize={{ minRows: 2, maxRows: 15 }}
maxLength={500}
placeholder="Enter 发送Shift + Enter换行"
rows={5}
onChange={(e) => {
setContent(e.target.value);
@ -125,11 +172,12 @@ export default function Render(
onFocus={() => {
setButtonHidden(true);
}}
onPressEnter={(e) => {
e.preventDefault();
createMessage();
pageScroll('comment');
}}
// onPressEnter={(e) => {
// e.preventDefault();
// createMessage();
// pageScroll('comment');
// }}
onKeyDown={handleKeyDown}
value={text}
/>
<div className={Style.btn}>

View File

@ -7,6 +7,7 @@ export interface Schema extends EntityShape {
entityId: String<64>;
user?: User; //发送者
lmts?: Datetime;//最后一条消息的发送时间
openId?: String<64>;
};
@ -21,6 +22,7 @@ const entityDesc: EntityDesc<Schema, '', Relation, {
entityId: '关联对象id',
user: '发送者',
lmts: '最后一条消息的发送时间',
openId: 'openId'
},
r: {
partner: '所有者',

View File

@ -18,6 +18,7 @@ export type OpSchema = EntityShape & {
entityId: String<64>;
userId?: ForeignKey<"user"> | null;
lmts?: Datetime | null;
openId?: String<64> | null;
};
export type OpAttr = keyof OpSchema;
export type Schema = EntityShape & {
@ -25,6 +26,7 @@ export type Schema = EntityShape & {
entityId: String<64>;
userId?: ForeignKey<"user"> | null;
lmts?: Datetime | null;
openId?: String<64> | null;
user?: User.Schema | null;
application?: Application.Schema;
readRemark$session?: Array<ReadRemark.Schema>;
@ -50,6 +52,7 @@ type AttrFilter = {
userId: Q_StringValue;
user: User.Filter;
lmts: Q_DateValue;
openId: Q_StringValue;
application: Application.Filter;
readRemark$session: ReadRemark.Filter & SubQueryPredicateMetadata;
sessionMessage$session: SessionMessage.Filter & SubQueryPredicateMetadata;
@ -70,6 +73,7 @@ export type Projection = {
userId?: number;
user?: User.Projection;
lmts?: number;
openId?: number;
application?: Application.Projection;
readRemark$session?: ReadRemark.Selection & {
$entity: "readRemark";
@ -129,6 +133,8 @@ export type SortAttr = {
user: User.SortAttr;
} | {
lmts: number;
} | {
openId: number;
} | {
application: Application.SortAttr;
} | {

View File

@ -24,6 +24,12 @@ export const desc: StorageDesc<OpSchema> = {
},
lmts: {
type: "datetime"
},
openId: {
type: "varchar",
params: {
length: 64
}
}
},
actionType: "crud",

View File

@ -1 +1 @@
{"name":"会话","attr":{"entity":"关联对象","entityId":"关联对象id","user":"发送者","lmts":"最后一条消息的发送时间"},"r":{"partner":"所有者"}}
{"name":"会话","attr":{"entity":"关联对象","entityId":"关联对象id","user":"发送者","lmts":"最后一条消息的发送时间","openId":"openId"},"r":{"partner":"所有者"}}