Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
F
fns_front_2
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
chenqikuai
fns_front_2
Commits
0f5069c2
Commit
0f5069c2
authored
Aug 27, 2021
by
chenqikuai
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update
parent
b1a9feea
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
209 additions
and
154 deletions
+209
-154
colors.config.js
colors.config.js
+1
-1
Chat.vue
src/views/Chat/Chat.vue
+11
-10
ChatContent.vue
src/views/Chat/ChatContent.vue
+74
-60
ChatContentMessage.vue
src/views/Chat/ChatContentMessage.vue
+68
-55
ChatContentMessageText.vue
src/views/Chat/ChatContentMessageText.vue
+54
-28
tailwind.config.js
tailwind.config.js
+1
-0
No files found.
colors.config.js
View file @
0f5069c2
...
...
@@ -2,7 +2,7 @@
const
colors
=
{
primary
:
'#1888FA'
,
secondary
:
'#
E8F3F
F'
,
secondary
:
'#
3E4FA
F'
,
'secondary-focus'
:
'#D6E3F0'
,
dark
:
'#24374E'
,
negative
:
'#db394c'
,
...
...
src/views/Chat/Chat.vue
View file @
0f5069c2
<
template
>
<div
class=
"flex flex-col flex-nowrap
h-full
text-base bg-gray-50 h-screen"
>
<div
class=
"flex flex-col flex-nowrap text-base bg-gray-50 h-screen"
>
<!-- 没连上时界面上只有一个返回按钮 -->
<!-- 👇是返回按钮 -->
<!--
<div
...
...
@@ -134,15 +134,16 @@ export default defineComponent({
// 收到的非本笔订单的消息不处理
// if (msg.orderid !== orderid) return;
msg
&&
messageStore
.
displayNewMessage
({
content
:
msg
.
content
,
from
:
msg
.
from
,
uuid
:
msg
.
uuid
,
state
:
null
,
type
:
(
msg
.
type
||
0
)
as
ChatMessageTypes
,
datetime
:
msg
.
datetime
,
logid
:
msg
.
logid
,
});
msg
&&
messageStore
.
displayNewMessage
({
content
:
msg
.
content
,
from
:
msg
.
from
,
uuid
:
msg
.
uuid
,
state
:
null
,
type
:
(
msg
.
type
||
0
)
as
ChatMessageTypes
,
datetime
:
msg
.
datetime
,
logid
:
msg
.
logid
,
});
};
// 连接后,指定每次断开连接要做的事
...
...
src/views/Chat/ChatContent.vue
View file @
0f5069c2
<
template
>
<!-- style="flex-basis: 0px" 是为了兼容 iOS 和 macOS 下的 Safari 浏览器,如果没有这个样式,整个聊天列表无法显示 -->
<q-scroll-area
ref=
"scrollArea"
class=
"flex-grow"
style=
"flex-basis: 0px"
:visible=
"false"
>
<q-pull-to-refresh
<!-- style="flex-basis: 0px" 是为了兼容 iOS 和 macOS 下的 Safari 浏览器,如果没有这个样式,整个聊天列表无法显示 -->
<q-scroll-area
ref=
"scrollArea"
class=
"flex-grow"
style=
"flex-basis: 0px"
:visible=
"false"
>
<!--
<q-pull-to-refresh
v-if=
"messages.length"
@
refresh=
"loadMore"
:disable=
"noMoreMessages || messages.length === 0"
icon=
"history"
class=
"h-full w-full absolute"
>
<div
class=
"text-center py-2.5 text-xs font-medium text-subtle"
>
>
-->
<!--
<div
class=
"text-center py-2.5 text-xs font-medium text-subtle"
>
<div
v-if=
"noMoreMessages && messages.length >= 10"
>
没有更多消息
</div>
<div
v-else-if=
"!noMoreMessages && messages.length >= 10"
>
{{
isMobile
?
'下滑加载更多'
:
'按住鼠标向下拖拽以加载更多'
}}
</div>
</div>
<ChatContentMessageVue
v-for=
"message in messages"
:key=
"message.uuid"
:id=
"message.uuid"
:content=
"message.content"
:fromMyself=
"myid == message.from"
:time=
"formatDate(message.datetime, 'MM月DD日 HH:mm')"
:uuid=
"message.uuid"
:type=
"message.type"
:state=
"message.state"
:hideDatetime=
"message.hideDatetime"
:uploadProgress=
"message.uploadProgress"
/>
</q-pull-to-refresh
>
</q-scroll-area>
</div>
-->
<ChatContentMessageVue
v-for=
"message in messages"
:key=
"message.uuid"
:id=
"message.uuid"
:content=
"message.content"
:fromMyself=
"myid == message.from"
:time=
"formatDate(message.datetime, 'MM月DD日 HH:mm')"
:uuid=
"message.uuid"
:type=
"message.type"
:state=
"message.state"
:hideDatetime=
"message.hideDatetime"
:uploadProgress=
"message.uploadProgress"
/>
<!--
</q-pull-to-refresh>
--
>
</q-scroll-area>
</
template
>
<
script
lang=
"ts"
>
import
{
defineComponent
,
nextTick
,
watch
}
from
'vue'
import
{
from
}
from
'@/store/appCallerStore'
import
{
DisplayMessage
,
messageStore
}
from
'@/store/messagesStore'
import
useScrollTo
from
'@/composables/useScrollTo'
import
ChatContentMessageVue
from
'./ChatContentMessage.vue'
import
{
date
,
Platform
}
from
'quasar'
import
{
defineComponent
,
nextTick
,
watch
}
from
"vue"
;
import
{
from
}
from
"@/store/appCallerStore"
;
import
{
DisplayMessage
,
messageStore
}
from
"@/store/messagesStore"
;
import
useScrollTo
from
"@/composables/useScrollTo"
;
import
ChatContentMessageVue
from
"./ChatContentMessage.vue"
;
import
{
date
,
Platform
}
from
"quasar"
;
export
default
defineComponent
({
components
:
{
ChatContentMessageVue
},
setup
()
{
const
messages
=
messageStore
.
messages
const
noMoreMessages
=
messageStore
.
noMoreHistoryMessages
const
myid
=
from
const
formatDate
=
date
.
formatDate
const
isMobile
=
Platform
.
is
.
mobile
components
:
{
ChatContentMessageVue
},
setup
()
{
const
messages
=
messageStore
.
messages
;
const
noMoreMessages
=
messageStore
.
noMoreHistoryMessages
;
const
myid
=
from
;
const
formatDate
=
date
.
formatDate
;
const
isMobile
=
Platform
.
is
.
mobile
;
// 监听「下拉加载更多」操作,记录当前的第一条消息 id
let
firstMessageSnapshot
:
DisplayMessage
const
loadMore
=
(
done
?:
()
=>
void
)
=>
{
firstMessageSnapshot
=
messages
[
0
]
retrieveMessages
().
then
(()
=>
done
&&
done
())
}
// 监听「下拉加载更多」操作,记录当前的第一条消息 id
let
firstMessageSnapshot
:
DisplayMessage
;
const
loadMore
=
(
done
?:
()
=>
void
)
=>
{
firstMessageSnapshot
=
messages
[
0
];
retrieveMessages
().
then
(()
=>
done
&&
done
());
};
const
retrieveMessages
=
():
Promise
<
void
>
=>
{
return
new
Promise
((
resolve
)
=>
{
messageStore
.
retrieveMessages
().
then
(()
=>
resolve
())
})
}
retrieveMessages
()
const
retrieveMessages
=
():
Promise
<
void
>
=>
{
return
new
Promise
((
resolve
)
=>
{
messageStore
.
retrieveMessages
().
then
(()
=>
resolve
());
});
};
// retrieveMessages();
// 收到新消息时滚动至底部
const
{
scrollToBottom
,
scrollArea
,
scrollToElement
}
=
useScrollTo
()
watch
(
messages
,
()
=>
{
nextTick
(()
=>
{
if
(
messageStore
.
appendingNewMessage
.
value
)
{
scrollToBottom
()
}
else
{
scrollToElement
(
document
.
getElementById
(
firstMessageSnapshot
.
uuid
))
}
})
})
// 收到新消息时滚动至底部
const
{
scrollToBottom
,
scrollArea
,
scrollToElement
}
=
useScrollTo
();
watch
(
messages
,
()
=>
{
nextTick
(()
=>
{
if
(
messageStore
.
appendingNewMessage
.
value
)
{
scrollToBottom
();
}
else
{
scrollToElement
(
document
.
getElementById
(
firstMessageSnapshot
.
uuid
));
}
});
});
return
{
scrollToBottom
,
scrollArea
,
messages
,
noMoreMessages
,
isMobile
,
myid
,
formatDate
,
loadMore
}
},
})
return
{
scrollToBottom
,
scrollArea
,
messages
,
noMoreMessages
,
isMobile
,
myid
,
formatDate
,
loadMore
,
};
},
});
</
script
>
src/views/Chat/ChatContentMessage.vue
View file @
0f5069c2
...
...
@@ -17,74 +17,87 @@
min-w-chat-msg-avatar
w-chat-msg-avatar
h-chat-msg-avatar
rounded-lg
!rounded-md
"
>
<img
:src=
"default_avatar_url"
/>
</q-avatar>
<!-- 消息气泡 -->
<div
:class=
"[
{ 'flex-row-reverse': fromMyself }]"
class="flex items-center max-w-chat-msg-bubble"
>
<!-- 文本消息 -->
<ChatContentMessageTextVue
v-if=
"type === 1"
:from-myself=
"fromMyself"
:content=
"content"
/>
<div
:class=
"[
{ 'flex-row-reverse': fromMyself }]">
<div
class=
"text-right"
style=
"
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #adadad;
"
>
15990184793
</div>
<div
:class=
"[
{ 'flex-row-reverse': fromMyself }]"
class="flex items-center max-w-chat-msg-bubble"
>
<!-- 文本消息 -->
<ChatContentMessageTextVue
v-if=
"type === 1"
:from-myself=
"fromMyself"
:content=
"content"
/>
<!-- 图片消息 -->
<ChatContentMessageImageVue
v-else-if=
"type === 3"
:from-myself=
"fromMyself"
:state=
"state"
:content=
"content"
:uploadProgress=
"uploadProgress"
/>
<!-- 图片消息 -->
<ChatContentMessageImageVue
v-else-if=
"type === 3"
:from-myself=
"fromMyself"
:state=
"state"
:content=
"content"
:uploadProgress=
"uploadProgress"
/>
<ChatContentMessageVideoVue
v-else-if=
"type === 4"
:from-myself=
"fromMyself"
:state=
"state"
:content=
"content"
:uploadProgress=
"uploadProgress"
/>
<ChatContentMessageVideoVue
v-else-if=
"type === 4"
:from-myself=
"fromMyself"
:state=
"state"
:content=
"content"
:uploadProgress=
"uploadProgress"
/>
<!-- 卡片消息 -->
<ChatContentMessageCardVue
v-else-if=
"type === 6"
:from-myself=
"fromMyself"
:content=
"content"
/>
<!-- 卡片消息 -->
<ChatContentMessageCardVue
v-else-if=
"type === 6"
:from-myself=
"fromMyself"
:content=
"content"
/>
<!-- 消息状态 -->
<div
class=
"w-10 self-stretch flex flex-row justify-center items-center"
>
<!-- 发送失败 -->
<!-- 消息状态 -->
<div
v-if=
"state === 'failure'"
@
click=
"resend"
class=
"w-full h-full flex flex-row justify-center items-center"
class=
"w-10 self-stretch flex flex-row justify-center items-center"
>
<q-icon
name=
"error"
size=
"22px"
color=
"negative"
/>
<!-- 发送失败 -->
<div
v-if=
"state === 'failure'"
@
click=
"resend"
class=
"w-full h-full flex flex-row justify-center items-center"
>
<q-icon
name=
"error"
size=
"22px"
color=
"negative"
/>
</div>
<!-- 正在发送 -->
<q-spinner-ios
v-else-if=
"state === 'pending' && !isMedia"
color=
"grey"
size=
"1.25rem"
:thickness=
"5"
/>
<q-icon
v-else-if=
"state === 'pending' && isMedia"
@
click=
"abort"
name=
"cancel"
size=
"22px"
color=
"negative"
/>
</div>
<!-- 正在发送 -->
<q-spinner-ios
v-else-if=
"state === 'pending' && !isMedia"
color=
"grey"
size=
"1.25rem"
:thickness=
"5"
/>
<q-icon
v-else-if=
"state === 'pending' && isMedia"
@
click=
"abort"
name=
"cancel"
size=
"22px"
color=
"negative"
/>
</div>
</div>
</div>
...
...
src/views/Chat/ChatContentMessageText.vue
View file @
0f5069c2
<
template
>
<div
:class=
"[
fromMyself ? 'bg-secondary' : 'bg-white',
fromMyself ? 'rounded-chat-msg-bubble-myself' : 'rounded-chat-msg-bubble-opposite',
]"
class=
"py-3 px-4 max-w-chat-msg-text break-all"
<div
:class=
"[
fromMyself ? 'bg-secondary text-white' : 'bg-white',
fromMyself ? 'message-box-self' : 'message-box-other',
]"
class=
"py-3 px-4 max-w-chat-msg-text break-all message-box rounded-md"
>
<a
v-if=
"isUrlMessage"
:href=
"prependHttp(textMessage)"
class=
"text-primary enable-touch"
target=
"_blank"
rel=
"noopener noreferrer"
>
<a
v-if=
"isUrlMessage"
:href=
"prependHttp(textMessage)"
class=
"text-primary enable-touch"
target=
"_blank"
rel=
"noopener noreferrer"
>
{{
textMessage
}}
</a>
<div
v-else
class=
"enable-touch"
>
{{
textMessage
}}
</div>
</div>
{{
textMessage
}}
</a>
<div
v-else
class=
"enable-touch"
>
{{
textMessage
}}
</div>
</div>
</
template
>
<
script
lang=
"ts"
>
import
{
computed
,
defineComponent
}
from
'vue'
import
isUrl
from
'@/utils/is-url'
import
prependHttp
from
'prepend-http'
import
{
computed
,
defineComponent
}
from
"vue"
;
import
isUrl
from
"@/utils/is-url"
;
import
prependHttp
from
"prepend-http"
;
export
default
defineComponent
({
props
:
{
fromMyself
:
Boolean
,
content
:
Object
},
props
:
{
fromMyself
:
Boolean
,
content
:
Object
},
setup
(
props
)
{
const
textMessage
=
computed
(()
=>
props
.
content
?.
content
)
const
isUrlMessage
=
computed
(()
=>
isUrl
(
textMessage
.
value
))
setup
(
props
)
{
const
textMessage
=
computed
(()
=>
props
.
content
?.
content
);
const
isUrlMessage
=
computed
(()
=>
isUrl
(
textMessage
.
value
));
return
{
isUrlMessage
,
prependHttp
,
textMessage
}
},
})
return
{
isUrlMessage
,
prependHttp
,
textMessage
};
},
})
;
</
script
>
<
style
scoped
></
style
>
<
style
scoped
>
.message-box
{
position
:
relative
;
}
.message-box-self
::after
{
content
:
""
;
position
:
absolute
;
right
:
0
;
top
:
0px
;
transform
:
translate
(
100%
,
15px
);
border-top
:
6px
solid
transparent
;
border-right
:
6px
solid
transparent
;
border-bottom
:
6px
solid
transparent
;
border-left
:
6px
solid
#3e4faf
;
}
.message-box-other
::after
{
content
:
""
;
position
:
absolute
;
left
:
0
;
top
:
0px
;
transform
:
translate
(
-100%
,
15px
);
border-top
:
6px
solid
transparent
;
border-right
:
6px
solid
white
;
border-bottom
:
6px
solid
transparent
;
border-left
:
6px
solid
transparent
;
}
</
style
>
tailwind.config.js
View file @
0f5069c2
...
...
@@ -78,6 +78,7 @@ module.exports = {
extend
:
{},
padding
:
[
'responsive'
,
'important'
],
backgroundColor
:
[
'responsive'
,
'important'
],
borderRadius
:
[
'responsive'
,
'important'
],
},
plugins
:
[
plugin
(
function
({
addVariant
})
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment