|
@@ -0,0 +1,323 @@
|
|
|
+import Taro, { Component } from '@tarojs/taro'
|
|
|
+import { View, ScrollView } from '@tarojs/components'
|
|
|
+import ListMore from '@/c/pageDataList/listMore'
|
|
|
+import { strTrim, arrToObj } from '@utils'
|
|
|
+import './chat.scss'
|
|
|
+
|
|
|
+class Index extends Component {
|
|
|
+
|
|
|
+ constructor (props) {
|
|
|
+ super(props)
|
|
|
+ const {id: curId} = this.$router.params
|
|
|
+ this.state = {
|
|
|
+ page_size: 10,
|
|
|
+ page: 1,
|
|
|
+ isListEnd: false,
|
|
|
+ isListLoading: false,
|
|
|
+ isListEmpty: false,
|
|
|
+ dataList: [],
|
|
|
+ curId,
|
|
|
+ curObj: {},
|
|
|
+ commentVal: '',
|
|
|
+ msgSocketList: [],
|
|
|
+ uObj: {},
|
|
|
+ chatUserObj: {},
|
|
|
+ viewId: '',
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ config = {
|
|
|
+ navigationBarTitleText: '在线聊天',
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ componentWillMount () {
|
|
|
+ const that = this
|
|
|
+ let uObj = Taro.getStorageSync('APP_userInfo')
|
|
|
+ const { to_user_id } = this.$router.params
|
|
|
+ this.setState({
|
|
|
+ uObj
|
|
|
+ }, () => {
|
|
|
+ let uArr = [uObj.user_id, to_user_id]
|
|
|
+ Taro.api.base.apiuserinfolist({
|
|
|
+ user_ids: uArr.join(',')
|
|
|
+ }).then(res => {
|
|
|
+ let chatUserObj = {}
|
|
|
+ const list = res.list || []
|
|
|
+ list.forEach(item => {
|
|
|
+ chatUserObj[item.id] = item
|
|
|
+ })
|
|
|
+ that.setState({
|
|
|
+ chatUserObj
|
|
|
+ })
|
|
|
+ })
|
|
|
+ Taro.$AHU(this)
|
|
|
+ this.getDataList()
|
|
|
+ this.initSocket()
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ getDataList () {
|
|
|
+ const { to_user_id } = this.$router.params
|
|
|
+ let { page_size, page, dataList, isListEmpty } = this.state
|
|
|
+ Taro.api.room.apiuserchatlist({
|
|
|
+ page,
|
|
|
+ page_size,
|
|
|
+ to_user_id,
|
|
|
+ }).then(res => {
|
|
|
+ let curData = res.list || []
|
|
|
+ curData = curData.reverse()
|
|
|
+ let isListEnd = false
|
|
|
+ if (curData.length > 0) {
|
|
|
+ if (page === 1) {
|
|
|
+ dataList = curData
|
|
|
+ } else {
|
|
|
+ dataList = [].concat(curData, dataList)
|
|
|
+ }
|
|
|
+ if (curData.length === page_size && res.total !== curData.length) {
|
|
|
+ isListEnd = false
|
|
|
+ } else {
|
|
|
+ isListEnd = true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (curData.length === 0 && page === 1) {
|
|
|
+ isListEmpty = true
|
|
|
+ dataList = []
|
|
|
+ } else {
|
|
|
+ isListEmpty = false
|
|
|
+ }
|
|
|
+ const that = this
|
|
|
+ this.setState({
|
|
|
+ dataList,
|
|
|
+ isListEnd,
|
|
|
+ isListEmpty,
|
|
|
+ isListLoading: false
|
|
|
+ }, () => {
|
|
|
+ if (page > 1) {
|
|
|
+ setTimeout(() => {
|
|
|
+ that.setState({
|
|
|
+ viewId: `history11`
|
|
|
+ })
|
|
|
+ }, 100)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+ onScrollToUpper (e) {
|
|
|
+ let { isListEnd, isListLoading, page } = this.state
|
|
|
+ if (!isListEnd && !isListLoading) {
|
|
|
+ page++
|
|
|
+ this.setState({
|
|
|
+ page,
|
|
|
+ isListLoading: true
|
|
|
+ }, () => {
|
|
|
+ this.getDataList()
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ initSocket () {
|
|
|
+ const that = this
|
|
|
+ Taro.connectSocket({
|
|
|
+ url: 'ws://192.168.101.147:8089/acc',
|
|
|
+ success: function () {
|
|
|
+ console.log('connect success')
|
|
|
+ }
|
|
|
+ }).then(task => {
|
|
|
+ task.onOpen(function () {
|
|
|
+ // console.log('onOpen')
|
|
|
+ const { to_user_id } = this.$router.params
|
|
|
+ let token = Taro.getStorageSync('APP_token')
|
|
|
+ task.send({ data: '{"seq":"' + that.sendId() + '","cmd":"login","data":{"userId":"' + to_user_id + '","appId":101,"serviceToken":"' + token + '"}}' })
|
|
|
+ setInterval(() => {
|
|
|
+ task.send({data: '{"seq":"' + that.sendId() + '","cmd":"heartbeat","data":{}}'});
|
|
|
+ }, 30000)
|
|
|
+ })
|
|
|
+ task.onMessage(function (msg) {
|
|
|
+ // console.log('onMessage: ', msg)
|
|
|
+ let { msgSocketList } = that.state
|
|
|
+ const data = JSON.parse(msg.data)
|
|
|
+ // console.log(data)
|
|
|
+ if (data.cmd === 'msg' || data.cmd === 'login') {
|
|
|
+ const res = data.response || {}
|
|
|
+ if (res.code === 200) {
|
|
|
+ if (data.cmd === 'login') {
|
|
|
+ msgSocketList.push({msg: '登录成功~'})
|
|
|
+ } else {
|
|
|
+ msgSocketList.push(res.data)
|
|
|
+ }
|
|
|
+ that.setState({
|
|
|
+ msgSocketList
|
|
|
+ }, () => {
|
|
|
+ setTimeout(() => {
|
|
|
+ that.setState({
|
|
|
+ viewId: `item${msgSocketList.length - 1}`
|
|
|
+ })
|
|
|
+ }, 100)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // task.close()
|
|
|
+ })
|
|
|
+ task.onError(function () {
|
|
|
+ console.log('onError')
|
|
|
+ })
|
|
|
+ task.onClose(function (e) {
|
|
|
+ console.log('onClose: ', e)
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+ sendId () {
|
|
|
+ let timeStamp = +new Date()
|
|
|
+ let randId = parseInt(Math.random() * 1000000)
|
|
|
+ return `${timeStamp}-${randId}`
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ componentDidShow () { }
|
|
|
+
|
|
|
+ componentDidHide () { }
|
|
|
+
|
|
|
+
|
|
|
+ renderList () {
|
|
|
+ const { chatUserObj, uObj, viewId } = this.state
|
|
|
+ const { dataList, isListEnd, isListLoading, isListEmpty } = this.state
|
|
|
+ const itemList = dataList.map((item, index) => {
|
|
|
+ return (
|
|
|
+ <View className="sl-item" key={index} id={`history${index}`}>
|
|
|
+ <View className={item.user_id === uObj.user_id ? 'sl-wrap' : 'sl-wrap t2'}>
|
|
|
+ <View className="sl-img">
|
|
|
+ <Image className="img" src={chatUserObj[item.user_id].avatar}></Image>
|
|
|
+ </View>
|
|
|
+ <View className="sl-right">
|
|
|
+ <View className="sign"></View>
|
|
|
+ <View className="sl-text">{item.content}</View>
|
|
|
+ <View className="sl-time">{item.create_at}</View>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ )
|
|
|
+ })
|
|
|
+ return (
|
|
|
+ <ScrollView
|
|
|
+ className='l-scroll-view'
|
|
|
+ scrollY
|
|
|
+ scrollWithAnimation
|
|
|
+ upperThreshold="10"
|
|
|
+ scrollIntoView={viewId}
|
|
|
+ onScrollToUpper={this.onScrollToUpper.bind(this)}
|
|
|
+ >
|
|
|
+ <ListMore isListEnd={isListEnd} isListLoading={isListLoading} isListEmpty={isListEmpty} text="暂无历史消息" />
|
|
|
+ <View className="scoped-list">
|
|
|
+ {itemList}
|
|
|
+ </View>
|
|
|
+ {/* {
|
|
|
+ dataList.length > 0
|
|
|
+ &&
|
|
|
+ <AtDivider content="以上为历史消息" fontColor='#ccc' lineColor='#ccc' />
|
|
|
+ } */}
|
|
|
+ {this.renderMsgList()}
|
|
|
+ <View id="msgId"></View>
|
|
|
+ </ScrollView>
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ renderMsgList () {
|
|
|
+ const { msgSocketList } = this.state
|
|
|
+ const { chatUserObj, uObj } = this.state
|
|
|
+ const curItems = msgSocketList.map((item, index) => {
|
|
|
+ return (
|
|
|
+ <View className="sl-item" key={index} id={`item${index}`}>
|
|
|
+ {
|
|
|
+ item.from
|
|
|
+ ?
|
|
|
+ <View className={item.from === uObj.user_id ? 'sl-wrap' : 'sl-wrap t2'}>
|
|
|
+ <View className="sl-img">
|
|
|
+ <Image className="img" src={chatUserObj[item.from].avatar}></Image>
|
|
|
+ </View>
|
|
|
+ <View className="sl-right">
|
|
|
+ <View className="sign"></View>
|
|
|
+ <View className="sl-text">{item.msg}</View>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ :
|
|
|
+ <View className="scoped-msg-tips">{item.msg}</View>
|
|
|
+ }
|
|
|
+ </View>
|
|
|
+ )
|
|
|
+ })
|
|
|
+ return (
|
|
|
+ <View className="scoped-list">
|
|
|
+ {curItems}
|
|
|
+ </View>
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ sendHandle () {
|
|
|
+ const that = this
|
|
|
+ const { uObj } = this.state
|
|
|
+ const { commentVal } = this.state
|
|
|
+ let { msgSocketList } = this.state
|
|
|
+ const { to_user_id } = this.$router.params
|
|
|
+ let apiStr = 'apiusersendmessage'
|
|
|
+ if (commentVal) {
|
|
|
+ Taro.api.room[apiStr]({
|
|
|
+ message: commentVal,
|
|
|
+ type: 'text',
|
|
|
+ to_user: to_user_id,
|
|
|
+ }).then(res => {
|
|
|
+ msgSocketList.push({
|
|
|
+ from: uObj.user_id,
|
|
|
+ msg: commentVal
|
|
|
+ })
|
|
|
+ this.setState({
|
|
|
+ msgSocketList,
|
|
|
+ commentVal: '',
|
|
|
+ }, () => {
|
|
|
+ setTimeout(() => {
|
|
|
+ that.setState({
|
|
|
+ viewId: `item${msgSocketList.length - 1}`
|
|
|
+ })
|
|
|
+ }, 100)
|
|
|
+ })
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ Taro.$msg('请输入')
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ changeInput (e) {
|
|
|
+ const val = strTrim(e.target.value)
|
|
|
+ this.setState({
|
|
|
+ commentVal: val
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ renderFooter () {
|
|
|
+ const { commentVal } = this.state
|
|
|
+ return (
|
|
|
+ <View className="l-floor-footer">
|
|
|
+ <View className="scoped-footer">
|
|
|
+ <View className="sf-input">
|
|
|
+ <Input className="input" placeholder={`请输入`} value={commentVal} onInput={this.changeInput.bind(this)} />
|
|
|
+ <View className="btn" onClick={this.sendHandle.bind(this)}>发送</View>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ render () {
|
|
|
+ return (
|
|
|
+ <View className="l-box has-footer">
|
|
|
+ {this.renderList()}
|
|
|
+ {this.renderFooter()}
|
|
|
+ </View>
|
|
|
+ )
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export default Index
|