...
This commit is contained in:
BIN
pages/.DS_Store
vendored
BIN
pages/.DS_Store
vendored
Binary file not shown.
163
pages/im/components/conversationList.vue
Normal file
163
pages/im/components/conversationList.vue
Normal file
@@ -0,0 +1,163 @@
|
||||
<template>
|
||||
<view>
|
||||
<view v-for="(item, index) in conversations" :key="index" :class="['message', { 'is-top': item.isTop }]"
|
||||
:data-item="item" @longpress="onLongPress" @click="toDetail(item)">
|
||||
<message-cell :item="item" />
|
||||
</view>
|
||||
|
||||
<view class="shade" @click="hidePop" v-show="showPop">
|
||||
<view class="pop" :style="popStyle" :class="{'show':showPop}">
|
||||
<view v-for="(item, index) in popButton" :key="index" @click="pickerMenu" :data-index="index">
|
||||
{{item}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
|
||||
import im from '@/utils/im/index.js'
|
||||
import messageCell from './messageCell'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
conversations: {
|
||||
type: Array,
|
||||
default: function() {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
messageCell
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
/* 窗口尺寸 */
|
||||
winSize: {},
|
||||
/* 显示操作弹窗 */
|
||||
showPop: false,
|
||||
/* 弹窗按钮列表 */
|
||||
popButton: ['置顶聊天', '删除该聊天'],
|
||||
/* 弹窗定位样式 */
|
||||
popStyle: "",
|
||||
pickedItem: {},
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 隐藏功能菜单
|
||||
hidePop() {
|
||||
this.showPop = false
|
||||
this.pickedItem = {}
|
||||
setTimeout(() => {
|
||||
this.showShade = false
|
||||
}, 250)
|
||||
},
|
||||
// 点击会话功能菜单
|
||||
pickerMenu(e) {
|
||||
const index = Number(e.currentTarget.dataset.index)
|
||||
|
||||
if (index == 0) {
|
||||
RongIMLib.setConversationToTop(this.pickedItem.conversationType, this.pickedItem.targetId, !this
|
||||
.pickedItem.isTop)
|
||||
} else {
|
||||
RongIMLib.removeConversation(this.pickedItem.conversationType, this.pickedItem.targetId)
|
||||
RongIMLib.deleteMessages(this.pickedItem.conversationType, this.pickedItem.targetId)
|
||||
}
|
||||
this.$emit('refresh')
|
||||
im.setNotifyBadge()
|
||||
this.hidePop()
|
||||
},
|
||||
// 长按会话,展示功能菜单
|
||||
onLongPress(e) {
|
||||
let [touches, style, item] = [e.touches[0], "", e.currentTarget.dataset.item]
|
||||
|
||||
if (touches.clientY > (this.winSize.height / 2)) {
|
||||
style = `bottom:${this.winSize.height-touches.clientY}px;`
|
||||
} else {
|
||||
style = `top:${touches.clientY}px;`
|
||||
}
|
||||
if (touches.clientX > (this.winSize.witdh / 2)) {
|
||||
style += `right:${this.winSize.witdh-touches.clientX}px`
|
||||
} else {
|
||||
style += `left:${touches.clientX}px`
|
||||
}
|
||||
|
||||
this.popButton[0] = item.isTop ? '取消置顶' : '置顶聊天'
|
||||
this.popStyle = style
|
||||
this.pickedItem = item
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.showPop = true;
|
||||
}, 10)
|
||||
})
|
||||
},
|
||||
toDetail(item) {
|
||||
if (item.conversationType == 1) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/im/private/chat?targetId=' + item.targetId
|
||||
})
|
||||
} else if (item.conversationType == 3) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/im/group/chat?targetId=' + item.targetId
|
||||
})
|
||||
}
|
||||
|
||||
this.hidePop()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.message {
|
||||
background: white;
|
||||
|
||||
&.is-top {
|
||||
background: $window-color;
|
||||
}
|
||||
}
|
||||
|
||||
/* 遮罩 */
|
||||
.shade {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.pop {
|
||||
position: fixed;
|
||||
z-index: 101;
|
||||
width: 200rpx;
|
||||
box-sizing: border-box;
|
||||
font-size: 28rpx;
|
||||
text-align: left;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
|
||||
line-height: 80rpx;
|
||||
transition: transform 0.15s ease-in-out 0s;
|
||||
user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
transform: scale(0, 0);
|
||||
|
||||
&.show {
|
||||
transform: scale(1, 1);
|
||||
}
|
||||
|
||||
&>view {
|
||||
padding: 0 20rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
|
||||
&:active {
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
112
pages/im/components/friendApplyCell.vue
Normal file
112
pages/im/components/friendApplyCell.vue
Normal file
@@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<view class="apply--cell u-border-bottom">
|
||||
<view class="avatar">
|
||||
<u-avatar :src="user.portraitUrl" shape="square" size="46" />
|
||||
</view>
|
||||
<view class="info">
|
||||
<view class="name">
|
||||
{{ user.name }}
|
||||
</view>
|
||||
<view class="message">
|
||||
{{ message.message }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="action">
|
||||
<u-button type="success" size="mini" @click="resolve">通过</u-button>
|
||||
<u-button type="warning" size="mini" @click="reject">拒绝</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
|
||||
import {
|
||||
resolveFriend,
|
||||
rejectFriend
|
||||
} from '@/apis/interfaces/im.js'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
message: {
|
||||
type: Object,
|
||||
default: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
user() {
|
||||
return JSON.parse(this.message.extra)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
resolve() {
|
||||
resolveFriend(this.message.sourceUserId).then(res => {
|
||||
this.clearMessages()
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '通过好友申请'
|
||||
})
|
||||
}).catch(err => {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: err.message
|
||||
})
|
||||
})
|
||||
},
|
||||
reject() {
|
||||
uni.showModal({
|
||||
title: '拒绝申请',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
rejectFriend(this.message.sourceUserId).then(res => {
|
||||
this.clearMessages()
|
||||
}).catch(err => {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: err.message
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
// 不管是通过还是拒绝,都要把相关的信息清理
|
||||
clearMessages() {
|
||||
RongIMLib.deleteMessages(RongIMLib.ConversationType.SYSTEM, this.message.sourceUserId)
|
||||
this.$emit('success')
|
||||
uni.$emit('onContactNotification')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.apply--cell {
|
||||
display: flex;
|
||||
padding: $padding;
|
||||
align-items: center;
|
||||
|
||||
.info {
|
||||
flex: 1;
|
||||
margin-left: $padding;
|
||||
|
||||
.name {
|
||||
font-size: $title-size + 2;
|
||||
}
|
||||
|
||||
.message {
|
||||
color: $text-gray-m;
|
||||
font-size: $title-size-m;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.action {
|
||||
justify-content: space-between;
|
||||
|
||||
.u-button+.u-button {
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
125
pages/im/components/friendApplyList.vue
Normal file
125
pages/im/components/friendApplyList.vue
Normal file
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<view class="friend-apply">
|
||||
<block v-for="(item, index) in lists" v-if="lists.length > 0" :key="index">
|
||||
<view class="lists">
|
||||
<view class="" style="width: 100rpx;height: 100rpx;">
|
||||
<u-avatar :src="JSON.parse(item.latestMessage.extra).portraitUrl" shape="square" size="44" />
|
||||
</view>
|
||||
<view class="right">
|
||||
<view class="title">
|
||||
<view class="name">{{ item.name }}</view>
|
||||
<view class="des">{{ item.latestMessage.message }}</view>
|
||||
</view>
|
||||
<view class="agress-btn">
|
||||
<span v-if="isAgree" @click="action('agree', item)">通过</span>
|
||||
<span v-if="isAgree" @click="action('reject', item)">拒绝</span>
|
||||
<span v-if="isApply && !item.is_friend" @click="action('apply', item)">查看</span>
|
||||
<span class="isFri" v-if="isApply && item.is_friend" @click="action('isFriend', item)">已是好友</span>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'friend-apply-reject-agree',
|
||||
props: {
|
||||
lists: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
isAgree: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isReject: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isApply: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
console.log(this.lists);
|
||||
},
|
||||
methods: {
|
||||
action(type, item) {
|
||||
if (type === 'isFriend') {
|
||||
// ,后期可以跳转到信息介绍页面,先留在这里
|
||||
return uni.showToast({ title: '已是好友,无需重复添加', icon: 'none', duration:2000});
|
||||
}
|
||||
this.$emit('action', { type, item });
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.lists {
|
||||
padding: 0 $padding;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
box-sizing: border-box;
|
||||
font-size: $title-size;
|
||||
color: $text-gray;
|
||||
|
||||
.cover {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.right {
|
||||
width: 570rpx;
|
||||
margin-left: $margin - 10;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: $padding 0;
|
||||
border-bottom: solid 1rpx #f9f9f9;
|
||||
.title {
|
||||
width: 370rpx;
|
||||
.name {
|
||||
width: 100%;
|
||||
color: $text-color;
|
||||
font-size: $title-size + 2;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.des {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-size: $title-size-m;
|
||||
margin-top: $margin - 10;
|
||||
color: $text-gray-m;
|
||||
}
|
||||
}
|
||||
.agress-btn {
|
||||
display: flex;
|
||||
color: #fff;
|
||||
span {
|
||||
display: inline-block;
|
||||
padding: 6rpx 14rpx;
|
||||
background-color: $text-price;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
span:nth-child(1) {
|
||||
background-color: $main-color;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
.isFri {
|
||||
background-color: #f9f9f9 !important;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
85
pages/im/components/messageCell.vue
Normal file
85
pages/im/components/messageCell.vue
Normal file
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<view class="message--cell">
|
||||
<view class="avatar">
|
||||
<u-badge max="99" shape="horn" absolute :offset="[-5, -8]" :value="item.unreadMessageCount" />
|
||||
<u-avatar :src="contact(item.targetId).portraitUrl" shape="square" size="44" />
|
||||
</view>
|
||||
<view class="content">
|
||||
<view class="header">
|
||||
<view class="name">{{ contact(item.targetId).name }}</view>
|
||||
<view class="time">{{ item.sentTime|timeCustomCN }}</view>
|
||||
</view>
|
||||
<message-preview class="preview" :msg="item.latestMessage" :conversationType="item.conversationType"
|
||||
:user="item.latestMessage.userInfo" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import messagePreview from './messagePreview'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
default: function() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
contact() {
|
||||
return function(targetId) {
|
||||
return this.$store.getters.contactInfo(targetId)
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
messagePreview
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.message--cell {
|
||||
display: flex;
|
||||
padding: 20rpx 0 0 20rpx;
|
||||
|
||||
.avatar {
|
||||
position: relative;
|
||||
|
||||
.u-badge {
|
||||
z-index: 998;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-left: 30rpx;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
|
||||
border-bottom-width: 0.5px !important;
|
||||
border-color: $u-border-color !important;
|
||||
border-bottom-style: solid;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.name {
|
||||
font-size: $title-size + 2;
|
||||
color: #454545;
|
||||
color: #454545;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: $title-size-sm;
|
||||
color: $text-gray-m;
|
||||
position: absolute;
|
||||
right: 30rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
65
pages/im/components/messagePreview.nvue
Normal file
65
pages/im/components/messagePreview.nvue
Normal file
@@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="preview" v-if="msg.objectName=='RC:TxtMsg'">
|
||||
<text v-if="conversationType == 3">{{ user.name }}: </text>{{ msg.content || '' }}
|
||||
</view>
|
||||
<view class="preview" v-if="msg.objectName=='RC:HQVCMsg'">
|
||||
<text v-if="conversationType == 3">{{ user.name }}: </text>[语音]
|
||||
</view>
|
||||
<view class="preview" v-if="msg.objectName=='RC:ImgMsg'">
|
||||
<text v-if="conversationType == 3">{{ user.name }}: </text>[图片]
|
||||
</view>
|
||||
<view class="preview" v-if="msg.objectName=='RC:GIFMsg'">
|
||||
<text v-if="conversationType == 3">{{ user.name }}: </text>[表情]
|
||||
</view>
|
||||
<view class="preview" v-if="msg.objectName=='RC:FileMsg'">
|
||||
<text v-if="conversationType == 3">{{ user.name }}: </text>[文件]
|
||||
</view>
|
||||
<view class="preview" v-if="msg.objectName=='RC:LBSMsg'">
|
||||
<text v-if="conversationType == 3">{{ user.name }}: </text>[位置]
|
||||
</view>
|
||||
<view class="preview" v-if="msg.objectName=='RC:AudioMsg'">
|
||||
<text v-if="conversationType == 3">{{ user.name }}: </text>[语音通话]
|
||||
</view>
|
||||
<view class="preview" v-if="msg.objectName=='RC:VideoMsg'">
|
||||
<text v-if="conversationType == 3">{{ user.name }}: </text>[视频通话]
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
msg: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
conversationType: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
user: {
|
||||
type: Object,
|
||||
default: function() {
|
||||
return {
|
||||
name: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.preview {
|
||||
word-break: break-all;
|
||||
color: $text-gray-m;
|
||||
padding-top: $padding - 20;
|
||||
padding-bottom: $padding;
|
||||
font-size: $title-size-m;
|
||||
height: 32rpx;
|
||||
line-height: 32rpx;
|
||||
width: 520rpx;
|
||||
@extend .nowrap;
|
||||
}
|
||||
</style>
|
||||
83
pages/im/components/sentMessageBar.nvue
Normal file
83
pages/im/components/sentMessageBar.nvue
Normal file
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<view class="">
|
||||
<!-- footer -->
|
||||
<view class="footer">
|
||||
<view class="msg-type" @click="changeMessageType">
|
||||
<image class="icon" src="@/static/icon/key-icon.png" v-if="chatType === 0" mode="widthFix">
|
||||
</image>
|
||||
<image class="icon" src="@/static/icon/msg-icon.png" v-if="chatType === 1" mode="widthFix">
|
||||
</image>
|
||||
</view>
|
||||
<sent-voice v-if="chatType === 0" :conversationType="conversationType" :targetId="targetId"
|
||||
@success="onSuccess" />
|
||||
<sent-text v-if="chatType === 1" :conversationType="conversationType" :targetId="targetId"
|
||||
@success="onSuccess" />
|
||||
<view class="msg-type msg-popups" @click="showPopups = !showPopups">
|
||||
<image class="icon" src="@/static/icon/popups-icon.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 弹出层 -->
|
||||
<sent-popups :show="showPopups" :conversationType="conversationType" :targetId="targetId"
|
||||
@success="() => {showPopups = false, onSuccess()}"></sent-popups>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import sentText from '../components/sentText'
|
||||
import sentVoice from '../components/sentVoice'
|
||||
import sentPopups from '../components/sentPopups'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
conversationType: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
targetId: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
components: {
|
||||
sentText,
|
||||
sentVoice,
|
||||
sentPopups
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
chatType: 1, // 0 语音,1 文本
|
||||
showPopups: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 切换聊天类型,语音/文本
|
||||
changeMessageType() {
|
||||
this.chatType = this.chatType === 1 ? 0 : 1
|
||||
},
|
||||
onSuccess() {
|
||||
this.$emit('onSuccess')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.footer {
|
||||
background: white;
|
||||
padding: 20rpx 30rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-direction: row;
|
||||
|
||||
.msg-type {
|
||||
width: 70rpx;
|
||||
height: 70rpx;
|
||||
|
||||
.icon {
|
||||
margin: 5rpx;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
173
pages/im/components/sentPopups.nvue
Normal file
173
pages/im/components/sentPopups.nvue
Normal file
@@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<view class="sent--popups u-border-top" v-if="show">
|
||||
<view class="item" @click="onPopupsItem('picture')">
|
||||
<image class="icon" src="@/static/icon/popups-icon-00.png" mode="widthFix"></image>
|
||||
<text class="text">相册</text>
|
||||
</view>
|
||||
<view class="item" @click="onPopupsItem('camera')">
|
||||
<image class="icon" src="@/static/icon/popups-icon-01.png" mode="widthFix"></image>
|
||||
<text class="text">拍摄</text>
|
||||
</view>
|
||||
<view class="item" @click="onPopupsItem('video')">
|
||||
<image class="icon" src="@/static/icon/popups-icon-02.png" mode="widthFix"></image>
|
||||
<text class="text">视频通话</text>
|
||||
</view>
|
||||
<view class="item" @click="onPopupsItem('location')">
|
||||
<image class="icon" src="@/static/icon/popups-icon-03.png" mode="widthFix"></image>
|
||||
<text class="text">位置</text>
|
||||
</view>
|
||||
<view class="item" @click="onPopupsItem('redpacket')">
|
||||
<image class="icon" src="@/static/icon/popups-icon-04.png" mode="widthFix"></image>
|
||||
<text class="text">红包</text>
|
||||
</view>
|
||||
<view class="item" @click="onPopupsItem('file')">
|
||||
<image class="icon" src="@/static/icon/popups-icon-05.png" mode="widthFix"></image>
|
||||
<text class="text">文件</text>
|
||||
</view>
|
||||
|
||||
<u-action-sheet :actions="callActions" cancelText="取消" @close="callShow = false" @select="singleCall"
|
||||
:show="callShow">
|
||||
</u-action-sheet>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import im from '@/utils/im/index.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
callActions: [{
|
||||
type: 0,
|
||||
name: '语音通话'
|
||||
},
|
||||
{
|
||||
type: 1,
|
||||
name: '视频通话'
|
||||
}
|
||||
],
|
||||
callShow: false
|
||||
}
|
||||
},
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
conversationType: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
targetId: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
user() {
|
||||
return this.$store.getters.sender
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
singleCall(e) {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '功能正在开发中'
|
||||
})
|
||||
// CallLib.startSingleCall(this.targetId, e.type, '');
|
||||
// uni.redirectTo({
|
||||
// url: '/pages/im/private/call?targetId=' + this.targetId + '&mediaType=' + e.type
|
||||
// })
|
||||
},
|
||||
onPopupsItem(type) {
|
||||
switch (type) {
|
||||
case 'picture':
|
||||
uni.chooseImage({
|
||||
count: 9,
|
||||
sourceType: ['album'],
|
||||
success: res => {
|
||||
im.sentImage(this.conversationType, this.targetId, res.tempFilePaths[0],
|
||||
this.user, (
|
||||
res) => {
|
||||
this.success()
|
||||
})
|
||||
}
|
||||
})
|
||||
break;
|
||||
case 'camera':
|
||||
uni.chooseImage({
|
||||
sourceType: ['camera'],
|
||||
success: res => {
|
||||
im.sentImage(this.conversationType, this.targetId, res.tempFilePaths[0],
|
||||
this.user, (
|
||||
res) => {
|
||||
this.success()
|
||||
})
|
||||
}
|
||||
})
|
||||
break;
|
||||
case 'video':
|
||||
this.callShow = true
|
||||
break;
|
||||
case 'location':
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '功能正在开发中'
|
||||
})
|
||||
// uni.chooseLocation({
|
||||
// success: res => {
|
||||
// console.log(res);
|
||||
// this.success()
|
||||
// }
|
||||
// })
|
||||
break;
|
||||
case 'redpacket':
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '功能正在开发中'
|
||||
})
|
||||
break;
|
||||
case 'file':
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '功能正在开发中'
|
||||
})
|
||||
break;
|
||||
}
|
||||
},
|
||||
// 处理返回
|
||||
success() {
|
||||
this.$emit('success')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.sent--popups {
|
||||
background: white;
|
||||
padding: 30rpx 15rpx;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
|
||||
.item {
|
||||
width: 150rpx;
|
||||
margin: 15rpx;
|
||||
}
|
||||
|
||||
.text {
|
||||
text-align: center;
|
||||
font-size: 26rpx;
|
||||
color: #555;
|
||||
padding-top: 15rpx;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 110rpx;
|
||||
height: 110rpx;
|
||||
margin: 0 20rpx;
|
||||
border-radius: 20rpx;
|
||||
background: #F3F6FB;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
84
pages/im/components/sentText.nvue
Normal file
84
pages/im/components/sentText.nvue
Normal file
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<view class="sent--text">
|
||||
<input class="input" type="text" @focus="focus" @blur="blur" v-model="inputTxt" confirm-type="send"
|
||||
@confirm="sent" cursor-spacing="10" />
|
||||
<!-- <button class="button" size="mini" :disabled="disabled" @click="sent">发送</button> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import im from '@/utils/im/index.js'
|
||||
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
conversationType: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
targetId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
inputTxt: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
disabled() {
|
||||
return this.inputTxt.length === 0
|
||||
},
|
||||
user() {
|
||||
return this.$store.getters.sender
|
||||
}
|
||||
},
|
||||
created() {
|
||||
RongIMLib.getTextMessageDraft(this.conversationType, this.targetId, ({
|
||||
draft
|
||||
}) => {
|
||||
draft ? this.inputTxt = draft : ''
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
RongIMLib.saveTextMessageDraft(this.conversationType, this.targetId, this.inputTxt, (res) => {
|
||||
console.log('销毁组件之前,保存草稿信息,但是没有执行', res);
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
// 发送文本消息
|
||||
sent() {
|
||||
if (!this.disabled) {
|
||||
RongIMLib.clearTextMessageDraft(this.conversationType, this.targetId)
|
||||
im.sentText(this.conversationType, this.targetId, this.inputTxt, this.user, () => {
|
||||
this.$emit('success')
|
||||
this.inputTxt = ''
|
||||
})
|
||||
}
|
||||
},
|
||||
focus() {
|
||||
this.$emit('focus')
|
||||
},
|
||||
blur() {
|
||||
this.$emit('blur')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.sent--text {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
.input {
|
||||
background: #F3F6FB;
|
||||
height: 70rpx;
|
||||
width: 500rpx;
|
||||
border-radius: 10rpx;
|
||||
margin-right: 15rpx;
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
144
pages/im/components/sentVoice.nvue
Normal file
144
pages/im/components/sentVoice.nvue
Normal file
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<view class="send--voice">
|
||||
<view class="voice" hover-class="chat-hover" @touchstart="startRecord" @touchend="stopRecord">
|
||||
<text class="button">按住说话</text>
|
||||
</view>
|
||||
<!-- 录音中提示 -->
|
||||
<view class="modal" v-if="showRecordTip">
|
||||
<image class="icon" src="@/static/icon/record-icon.png" mode="widthFix"></image>
|
||||
<text class="text">录音中 {{recordTime}} s</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import im from '@/utils/im/index.js'
|
||||
import permision from '@/utils/permission.js'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
conversationType: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
targetId: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showRecordTip: false,
|
||||
recordTime: 60,
|
||||
interval: 0,
|
||||
maxRecordTime: 60,
|
||||
recorderManager: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
user() {
|
||||
return this.$store.getters.sender
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.recorderManager = uni.getRecorderManager()
|
||||
},
|
||||
methods: {
|
||||
// 检查安卓录制权限
|
||||
async getAndroidPermission() {
|
||||
return await permision.requestAndroidPermission('android.permission.RECORD_AUDIO')
|
||||
},
|
||||
// 录制语音消息
|
||||
startRecord() {
|
||||
this.getAndroidPermission().then(code => {
|
||||
switch (code) {
|
||||
case 1:
|
||||
this.showRecordTip = true
|
||||
this.recorderManager.start()
|
||||
this.interval = setInterval(() => {
|
||||
this.recordTime -= 1
|
||||
if (this.recordTime === 0) {
|
||||
this.stopRecord()
|
||||
}
|
||||
}, 1000)
|
||||
break;
|
||||
case 0:
|
||||
uni.showToast({
|
||||
title: '暂无麦克风权限,请前往应用设置开启麦克风',
|
||||
icon: 'none'
|
||||
})
|
||||
break;
|
||||
case -1:
|
||||
uni.showToast({
|
||||
title: '应用权限错误',
|
||||
icon: 'none'
|
||||
})
|
||||
break;
|
||||
}
|
||||
})
|
||||
},
|
||||
// 结束录音
|
||||
stopRecord(e) {
|
||||
if (!this.showRecordTip) return
|
||||
this.recorderManager.stop()
|
||||
clearInterval(this.interval)
|
||||
// 监听录音结束
|
||||
this.recorderManager.onStop(res => {
|
||||
im.sentVoice(this.conversationType, this.targetId, res.tempFilePath, (this.maxRecordTime -
|
||||
this
|
||||
.recordTime), this.user, () => {
|
||||
setTimeout(() => {
|
||||
this.$emit('success')
|
||||
}, 500)
|
||||
})
|
||||
this.recordTime = this.maxRecordTime
|
||||
this.showRecordTip = false
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.send--voice {
|
||||
.voice {
|
||||
background: $window-color;
|
||||
height: 70rpx;
|
||||
line-height: 70rpx;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 500rpx;
|
||||
border-radius: 10rpx;
|
||||
margin-right: 15rpx;
|
||||
|
||||
.button {
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.modal {
|
||||
background: rgba(0, 0, 0, .6);
|
||||
position: fixed;
|
||||
height: 200rpx;
|
||||
width: 300rpx;
|
||||
border-radius: 10rpx;
|
||||
z-index: 99;
|
||||
top: 550rpx;
|
||||
left: 225rpx;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.icon {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: 28rpx;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
73
pages/im/components/showImage.nvue
Normal file
73
pages/im/components/showImage.nvue
Normal file
@@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<view class="">
|
||||
<text class="name" v-if="!guest && name">{{ name }}</text>
|
||||
<view class="msg--image" :class="guest ? 'right': 'left'">
|
||||
<image class="img" :src="msg.thumbnail" @click="previewImage" mode="widthFix"></image>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'showImage',
|
||||
props: {
|
||||
msg: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
local: '',
|
||||
remote: '',
|
||||
objectName: '',
|
||||
thumbnail: '',
|
||||
isFull: false
|
||||
}
|
||||
}
|
||||
},
|
||||
guest: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
previewImage() {
|
||||
uni.previewImage({
|
||||
urls: [
|
||||
this.msg.remote
|
||||
],
|
||||
current: 1
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.name {
|
||||
font-size: 24rpx;
|
||||
line-height: 34rpx;
|
||||
color: $text-gray-m;
|
||||
}
|
||||
|
||||
.msg--image {
|
||||
padding: 20rpx;
|
||||
|
||||
&.left {
|
||||
border-radius: 0 20rpx 20rpx 20rpx;
|
||||
background: white;
|
||||
}
|
||||
|
||||
&.right {
|
||||
border-radius: 20rpx 0 20rpx 20rpx;
|
||||
background: #34CE98;
|
||||
}
|
||||
|
||||
.img {
|
||||
width: 150rpx;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
54
pages/im/components/showText.nvue
Normal file
54
pages/im/components/showText.nvue
Normal file
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<view class="msg--text">
|
||||
<text class="name" v-if="!guest && name">{{ name }}</text>
|
||||
<text class="im--text" :class="guest ? 'right': 'left'">{{ msg.content }}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'showText',
|
||||
props: {
|
||||
msg: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
guest: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.msg--text {
|
||||
.name {
|
||||
font-size: 24rpx;
|
||||
line-height: 34rpx;
|
||||
color: $text-gray-m;
|
||||
}
|
||||
|
||||
.im--text {
|
||||
max-width: 500rpx;
|
||||
padding: 20rpx;
|
||||
line-height: 44rpx;
|
||||
font-size: 32rpx;
|
||||
|
||||
&.left {
|
||||
border-radius: 0 20rpx 20rpx 20rpx;
|
||||
background: white;
|
||||
}
|
||||
|
||||
&.right {
|
||||
border-radius: 20rpx 0 20rpx 20rpx;
|
||||
background: $main-color;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,9 +1,10 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="im--audio" :class="guest ? 'right': 'left'" @click="onPlayMsg">
|
||||
<image v-if="!guest" class="audio-mp3" src="@/static/icon/audio_green.png" mode="widthFix"></image>
|
||||
<text class="audio-text">"{{msg.duration}}"</text>
|
||||
<image v-if="guest" class="audio-mp3" src="@/static/icon/audio_white.png" mode="widthFix"></image>
|
||||
<view class="">
|
||||
<text class="name" v-if="!guest && name">{{ name }}</text>
|
||||
<view class="msg--voice" :class="guest ? 'right': 'left'" @click="onPlayMsg">
|
||||
<image v-if="!guest" class="icon" src="@/static/icon/audio_green.png" mode="widthFix"></image>
|
||||
<text class="duration">{{msg.duration}}"</text>
|
||||
<image v-if="guest" class="icon" src="@/static/icon/audio_white.png" mode="widthFix"></image>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -23,6 +24,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
guest: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
@@ -57,43 +62,45 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.im--audio {
|
||||
<style scoped lang="scss">
|
||||
.name {
|
||||
font-size: 24rpx;
|
||||
line-height: 34rpx;
|
||||
color: $text-gray-m;
|
||||
}
|
||||
|
||||
.msg--voice {
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 79rpx;
|
||||
width: 170rpx;
|
||||
padding: 0 20rpx;
|
||||
box-sizing:border-box;
|
||||
/* box-sizing: border-box; */
|
||||
}
|
||||
box-sizing: border-box;
|
||||
|
||||
,
|
||||
.im--audio.left {
|
||||
border-radius: 0 20rpx 20rpx 20rpx;
|
||||
background: white;
|
||||
}
|
||||
.icon {
|
||||
width: 38rpx;
|
||||
height: 38rpx;
|
||||
}
|
||||
|
||||
.im--audio.right {
|
||||
border-radius: 20rpx 0 20rpx 20rpx;
|
||||
background: #34CE98;
|
||||
}
|
||||
&.left {
|
||||
border-radius: 0 20rpx 20rpx 20rpx;
|
||||
background: white;
|
||||
|
||||
.audio-mp3 {
|
||||
width: 38rpx;
|
||||
height: 38rpx;
|
||||
}
|
||||
.duration {
|
||||
color: #333;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.audio-text {
|
||||
font-size: 30rpx;
|
||||
}
|
||||
&.right {
|
||||
border-radius: 20rpx 0 20rpx 20rpx;
|
||||
background: $main-color;
|
||||
|
||||
.im--audio.left .audio-text {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.im--audio.right .audio-text {
|
||||
color: white;
|
||||
.duration {
|
||||
color: white;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,47 +1,32 @@
|
||||
<template>
|
||||
<view>
|
||||
<u-index-list :index-list="indexs" inactiveColor="#666" activeColor="#34CE98">
|
||||
<view>
|
||||
<view class="friend-flex u-border-bottom" @click="toPending">
|
||||
<u-avatar class="cover" size="40" shape="square" :src="require('@/static/im/im_01.png')"></u-avatar>
|
||||
<view class="name">
|
||||
新的朋友 ({{ pendingCount }})
|
||||
</view>
|
||||
</view>
|
||||
<view class="friend-flex" @click="showToast">
|
||||
<u-avatar class="cover" size="40" shape="square" :src="require('@/static/im/im_00.png')"></u-avatar>
|
||||
<view class="name">我的群聊</view>
|
||||
</view>
|
||||
<view class="friend-flex u-border-bottom" @click="toPending">
|
||||
<u-avatar class="cover" size="40" shape="square" :src="require('@/static/im/im_01.png')"></u-avatar>
|
||||
<u-badge max="99" absolute :offset="[23, 20]" :value="pendingCount" />
|
||||
<view class="info">新的朋友</view>
|
||||
</view>
|
||||
<view class="friend-flex" @click="toGroup">
|
||||
<u-avatar class="cover" size="40" shape="square" :src="require('@/static/im/im_00.png')"></u-avatar>
|
||||
<view class="info">我的群聊</view>
|
||||
</view>
|
||||
<block v-if="friends.length > 0">
|
||||
<template v-for="(item, friend) in friends">
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<u-index-anchor :text="indexs[friend]" bgColor="#F3F6FB" height="20" size="12" color="#666">
|
||||
<u-index-item v-for="(item, fkey) in friends" :key="fkey">
|
||||
<u-index-anchor :text="indexs[fkey]" bgColor="#F3F6FB" height="20" size="12" color="#666">
|
||||
</u-index-anchor>
|
||||
<!-- #endif -->
|
||||
<u-index-item>
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<u-index-anchor :text="indexs[friend]" bgColor="#F3F6FB" height="20" size="12" color="#666">
|
||||
</u-index-anchor>
|
||||
<!-- #endif -->
|
||||
<view v-for="(friendItem, index) in item" :key="friendItem.userId"
|
||||
class="friend-flex u-border-bottom"
|
||||
@click="$Router.push({ name: 'imFriendsInfo', params: { targetId: friendItem.userId } })">
|
||||
<block v-if="friendItem.portraitUrl != ''">
|
||||
<u-avatar class="cover" size="40" shape="square" :src="friendItem.portraitUrl || ''"
|
||||
:default-url="require('@/static/user/cover.png')"></u-avatar>
|
||||
</block>
|
||||
<block v-else>
|
||||
<u-avatar class="cover" size="40" shape="square"
|
||||
:src="require('@/static/user/cover.png')"></u-avatar>
|
||||
</block>
|
||||
<view class="name">{{ friendItem.name }}</view>
|
||||
|
||||
<view v-for="(friendItem, index) in item" :key="index" class="friend-flex u-border-bottom"
|
||||
@click="toFriend(friendItem.targetId)">
|
||||
<u-avatar size="40" shape="square" :src="contact(friendItem.targetId).portraitUrl" />
|
||||
<view class="info">
|
||||
<view class="name">{{ contact(friendItem.targetId).name }}</view>
|
||||
<view class="address">{{ friendItem.address }}</view>
|
||||
</view>
|
||||
</u-index-item>
|
||||
</template>
|
||||
</view>
|
||||
</u-index-item>
|
||||
</block>
|
||||
<block v-else>
|
||||
<u-empty class="pages-null" mode="data" icon="http://cdn.uviewui.com/uview/empty/data.png" text="暂无好友">
|
||||
<u-empty class="pages-null" mode="data" text="暂无好友">
|
||||
</u-empty>
|
||||
</block>
|
||||
</u-index-list>
|
||||
@@ -50,9 +35,9 @@
|
||||
|
||||
<script>
|
||||
import {
|
||||
getFriends,
|
||||
getPendingCount
|
||||
getFriendsLetter
|
||||
} from '@/apis/interfaces/im';
|
||||
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@@ -62,22 +47,53 @@
|
||||
pendingCount: 0
|
||||
};
|
||||
},
|
||||
onShow() {
|
||||
getFriends().then(res => {
|
||||
this.indexs = res.indexList
|
||||
this.friends = res.itemArr
|
||||
})
|
||||
getPendingCount().then(res => {
|
||||
console.log(res);
|
||||
this.pendingCount = res
|
||||
computed: {
|
||||
contact() {
|
||||
return function(targetId) {
|
||||
return this.$store.getters.contactInfo(targetId)
|
||||
}
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.getFriendList()
|
||||
this.checkNewFriendPending()
|
||||
uni.$on('onContactNotification', () => {
|
||||
this.checkNewFriendPending()
|
||||
this.getFriendList()
|
||||
})
|
||||
},
|
||||
onUnload() {
|
||||
uni.$off('onContactNotification')
|
||||
},
|
||||
methods: {
|
||||
showToast() {
|
||||
uni.showToast({
|
||||
title: '群聊功能暂未开放,敬请期待',
|
||||
icon: 'none'
|
||||
});
|
||||
getFriendList() {
|
||||
getFriendsLetter().then(res => {
|
||||
this.indexs = res.indexList
|
||||
this.friends = res.itemArr
|
||||
})
|
||||
},
|
||||
checkNewFriendPending() {
|
||||
// 获取是否有新的好友申请
|
||||
RongIMLib.getConversationList([RongIMLib.ConversationType.SYSTEM], 1000, 0, (res) => {
|
||||
if (res.code === 0) {
|
||||
this.pendingCount = res.conversations.filter((item) => {
|
||||
return item.objectName == RongIMLib.ObjectName.ContactNotification
|
||||
}).length
|
||||
}
|
||||
})
|
||||
},
|
||||
toGroup() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/im/group/index',
|
||||
fail(err) {
|
||||
console.log(err);
|
||||
}
|
||||
})
|
||||
},
|
||||
toFriend(targetId) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/im/friends/info?targetId=' + targetId
|
||||
})
|
||||
},
|
||||
// 新朋友
|
||||
toPending() {
|
||||
@@ -108,14 +124,21 @@
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
// .cover
|
||||
.name {
|
||||
.info {
|
||||
flex: 1;
|
||||
padding-left: $padding;
|
||||
font-size: $title-size + 2;
|
||||
font-size: $title-size + 2;
|
||||
color: #454545 !important;
|
||||
@extend .nowrap;
|
||||
margin-left: $padding;
|
||||
|
||||
.name {
|
||||
font-size: $title-size + 2;
|
||||
font-size: $title-size + 2;
|
||||
color: #454545 !important;
|
||||
@extend .nowrap;
|
||||
}
|
||||
|
||||
.address {
|
||||
color: $text-gray-m;
|
||||
font-size: $title-size-m - 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
<view class="content">
|
||||
<!-- 用户信息 -->
|
||||
<view class="info-flex">
|
||||
<u-avatar :src="userInfo.portraitUrl || require('@/static/user/cover.png')" shape="square" size="50" bg-color="#fff"></u-avatar>
|
||||
<u-avatar :src="userInfo.portraitUrl || require('@/static/user/cover.png')" shape="square" size="50"
|
||||
bg-color="#fff"></u-avatar>
|
||||
<view class="info-text">
|
||||
<view class="nickname">{{userInfo.name}}</view>
|
||||
<view class="address" @longpress="copyAddress">地址:{{userInfo.address}}</view>
|
||||
<view class="nickname">{{ userInfo.name }}</view>
|
||||
<view class="address" @longpress="copyAddress">地址:{{ userInfo.address }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 用户资料 -->
|
||||
@@ -105,10 +106,11 @@
|
||||
}
|
||||
},
|
||||
onLoad(e) {
|
||||
console.log(e);
|
||||
this.targetId = e.targetId
|
||||
getFriendInfo(e.targetId).then(res => {
|
||||
this.userInfo = res
|
||||
// 获取到用户信息之后,去检查一下要不要更新
|
||||
this.$store.dispatch('updateContact', res)
|
||||
uni.setNavigationBarTitle({
|
||||
title: res.name
|
||||
})
|
||||
@@ -125,7 +127,7 @@
|
||||
if (code == 0) {
|
||||
this.isTop = conversation.isTop
|
||||
}
|
||||
});
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
copyAddress() {
|
||||
@@ -141,7 +143,7 @@
|
||||
},
|
||||
toPrivate() {
|
||||
uni.redirectTo({
|
||||
url: '/pages/im/private/chat?conversationType=1&targetId=' + this.targetId
|
||||
url: '/pages/im/private/chat?targetId=' + this.targetId
|
||||
});
|
||||
},
|
||||
setRemark() {
|
||||
@@ -156,7 +158,8 @@
|
||||
content: '确认删除后不可恢复',
|
||||
success: e => {
|
||||
if (e.confirm) {
|
||||
deleteFriend(this.targetId).then(res => {
|
||||
deleteFriend(this.targetId).then(res => {
|
||||
uni.$emit('onContactNotification')
|
||||
// 删除聊天记录
|
||||
RongIMLib.deleteMessages(1, this.targetId);
|
||||
RongIMLib.removeConversation(1, this.targetId);
|
||||
@@ -313,14 +316,16 @@
|
||||
background: white;
|
||||
margin: $margin;
|
||||
border-radius: $radius;
|
||||
.u-border-bottom{
|
||||
|
||||
.u-border-bottom {
|
||||
border-bottom: solid 1rpx #f9f9f9 !important;
|
||||
}
|
||||
|
||||
.item {
|
||||
line-height: 100rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding:10rpx $padding;
|
||||
padding: 10rpx $padding;
|
||||
justify-content: space-between;
|
||||
font-size: $title-size-lg;
|
||||
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
<!--
|
||||
* @Description:新朋友即新增好友申请列表 可以搜索跳转
|
||||
* @Author: Aimee·Zhang
|
||||
* @Date: 2022-01-24 10:49:15
|
||||
* @LastEditors: Aimee·Zhang
|
||||
* @LastEditTime: 2022-01-25 10:18:26
|
||||
-->
|
||||
|
||||
<template>
|
||||
<view class="pending">
|
||||
<u-sticky>
|
||||
@@ -14,67 +6,42 @@
|
||||
:disabled="true" :show-action="false" />
|
||||
</view>
|
||||
</u-sticky>
|
||||
<block v-if="pedings.length > 0">
|
||||
<applyFriend :lists="pedings" :isAgree="true" :isReject="false" @action="action" />
|
||||
</block>
|
||||
<view class="no-lists" v-else>
|
||||
<u-image class="cover" radius="4" width="400rpx" height="400rpx"
|
||||
:src="require('@/static/imgs/no-friend.png')" :lazy-load="true" />
|
||||
<span>暂无申请记录~</span>
|
||||
<view v-for="(item, index) in pendings" :key="index">
|
||||
<apply-cell :message="item.latestMessage" @success="getPendingList" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getPedings,
|
||||
resolveFriend,
|
||||
rejectFriend
|
||||
} from '@/apis/interfaces/im.js'
|
||||
import * as RongIMLib from "@/uni_modules/RongCloud-IMWrapper/js_sdk/index"
|
||||
import applyFriend from '@/components/friend-apply-reject-agree'
|
||||
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
|
||||
import applyCell from '../components/friendApplyCell'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
applyFriend
|
||||
applyCell
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pedings: []
|
||||
pendings: []
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.getPeddingList()
|
||||
this.getPendingList()
|
||||
uni.$on('onContactNotification', this.getPendingList)
|
||||
},
|
||||
onUnload() {
|
||||
uni.$off('onContactNotification')
|
||||
},
|
||||
methods: {
|
||||
// 操作同意或拒绝
|
||||
action(e) {
|
||||
let url = e.type === 'agree' ? resolveFriend : rejectFriend
|
||||
uni.showModal({
|
||||
title: e.type === 'agree' ? '通过' : '拒绝',
|
||||
content: e.type === 'agree' ? '通过后即可与该用户畅所欲言' : '拒绝后将不会收到该用户发来信息',
|
||||
success: res => {
|
||||
if (res.confirm) {
|
||||
url(e.item.userId).then(res => {
|
||||
this.getPeddingList()
|
||||
})
|
||||
}
|
||||
getPendingList() {
|
||||
// 获取系统中的好友关系会话列表
|
||||
RongIMLib.getConversationList([RongIMLib.ConversationType.SYSTEM], 1000, 0, (res) => {
|
||||
if (res.code === 0) {
|
||||
this.pendings = res.conversations.filter((item) => {
|
||||
return item.objectName == RongIMLib.ObjectName.ContactNotification
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
getPeddingList() {
|
||||
// 获取系统中的好友关系会话列表
|
||||
// RongIMLib.getConversationList([RongIMLib.ConversationType.SYSTEM], 50, 0, (res) => {
|
||||
// if (res.code === 0) {
|
||||
// this.pedings = res.conversations.filter((item) => {
|
||||
// return item.objectName == RongIMLib.ObjectName.ContactNotification
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
getPedings().then(res => {
|
||||
console.log(res)
|
||||
this.pedings = res
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
searchFriend,
|
||||
pedingFriend
|
||||
} from '@/apis/interfaces/im.js';
|
||||
import applyFriend from '@/components/friend-apply-reject-agree';
|
||||
import applyFriend from '../components/friendApplyList.vue';
|
||||
export default {
|
||||
components: {
|
||||
applyFriend
|
||||
|
||||
54
pages/im/group/announceCreate.vue
Normal file
54
pages/im/group/announceCreate.vue
Normal file
@@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<view class="create">
|
||||
<u--textarea v-model="content" count height="200" maxlength="200" placeholder="请输入公告内容"></u--textarea>
|
||||
|
||||
<u-button type="primary" text="发布" @click="onCreate"></u-button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
createGroupAnnouncement
|
||||
} from '@/apis/interfaces/im.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
targetId: '',
|
||||
content: ''
|
||||
}
|
||||
},
|
||||
onLoad(e) {
|
||||
this.targetId = e.targetId
|
||||
},
|
||||
methods: {
|
||||
onCreate() {
|
||||
createGroupAnnouncement(this.targetId, this.content).then(res => {
|
||||
uni.showToast({
|
||||
title: '发布成功',
|
||||
success: () => {
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1000)
|
||||
}
|
||||
})
|
||||
}).catch(err => {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: err.message
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.create {
|
||||
padding: $padding;
|
||||
|
||||
.u-button {
|
||||
margin-top: $padding;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
105
pages/im/group/announcement.vue
Normal file
105
pages/im/group/announcement.vue
Normal file
@@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<view class="announce">
|
||||
<u-skeleton rows="2" :loading="loading" avatar :rows="5">
|
||||
<view v-for="(item,index) in announcements" :key="index">
|
||||
<view class="header">
|
||||
<u-avatar :src="item.user.portraitUrl"></u-avatar>
|
||||
<view class="user">
|
||||
<view class="name">{{ item.user.name }}</view>
|
||||
<view class="time">{{ item.created_at }}</view>
|
||||
</view>
|
||||
<view class="delete" v-if="isAdmin" @click="onDelete(item.announcement_id)">删除</view>
|
||||
</view>
|
||||
<view class="content">{{ item.content }}</view>
|
||||
</view>
|
||||
</u-skeleton>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getGroupInfo,
|
||||
getGroupAnnouncements,
|
||||
deleteGroupAnnouncement
|
||||
} from '@/apis/interfaces/im.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
targetId: '',
|
||||
announcements: [],
|
||||
loading: true,
|
||||
isAdmin: false
|
||||
}
|
||||
},
|
||||
onLoad(e) {
|
||||
this.targetId = e.targetId
|
||||
getGroupInfo(this.targetId).then(res => {
|
||||
this.isAdmin = res.group.is_admin
|
||||
})
|
||||
this.initData()
|
||||
},
|
||||
onNavigationBarButtonTap() {
|
||||
if (this.isAdmin) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/im/group/announceCreate?targetId=' + this.targetId
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '没有权限'
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initData() {
|
||||
getGroupAnnouncements(this.targetId).then(res => {
|
||||
this.announcements = res
|
||||
console.log(res);
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
onDelete(aId) {
|
||||
deleteGroupAnnouncement(this.targetId, aId).then(res => {
|
||||
this.initData()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.announce {
|
||||
padding: $padding;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.user {
|
||||
margin-left: $padding;
|
||||
flex: 1;
|
||||
|
||||
.name {
|
||||
line-height: 44rpx;
|
||||
}
|
||||
|
||||
.time {
|
||||
margin-top: 15rpx;
|
||||
font-size: 24rpx;
|
||||
color: $text-gray-m;
|
||||
}
|
||||
}
|
||||
|
||||
.delete {
|
||||
color: $text-price;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: $padding;
|
||||
font-size: 34rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
186
pages/im/group/chat.nvue
Normal file
186
pages/im/group/chat.nvue
Normal file
@@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<view class="group--chat">
|
||||
<list class="body" :show-scrollbar="false">
|
||||
<cell class="cell" v-for="(item, index) in messages" :key="index">
|
||||
<view class="cell-item" :class="item.messageDirection == 1 ? 'right' : 'left'">
|
||||
<u-avatar class="avatar" @click="toUser(item)" size="36" shape="square" :src="item.content.userInfo.portraitUrl" />
|
||||
<view class="msg">
|
||||
<show-voice v-if="item.objectName === 'RC:HQVCMsg'" :guest="item.messageDirection == 1"
|
||||
:msg="item.content" :name="item.content.userInfo.name" />
|
||||
<show-image v-if="item.objectName === 'RC:ImgMsg'" :guest="item.messageDirection == 1"
|
||||
:msg="item.content" :name="item.content.userInfo.name" />
|
||||
<show-text v-if="item.objectName === 'RC:TxtMsg'" :guest="item.messageDirection == 1"
|
||||
:msg="item.content" :name="item.content.userInfo.name" />
|
||||
</view>
|
||||
</view>
|
||||
</cell>
|
||||
<cell class="cell-footer" ref="chatBottom"></cell>
|
||||
</list>
|
||||
<sent-message-bar :conversationType="conversationType" :targetId="targetId" @onSuccess="getMessageList()" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
timeCustomCN
|
||||
} from '@/utils/filters.js'
|
||||
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
|
||||
import im from '@/utils/im/index.js'
|
||||
import showVoice from '../components/showVoice'
|
||||
import showImage from '../components/showImage'
|
||||
import showText from '../components/showText'
|
||||
import sentMessageBar from '../components/sentMessageBar'
|
||||
|
||||
const ChatList = uni.requireNativePlugin('dom')
|
||||
|
||||
export default {
|
||||
components: {
|
||||
showVoice,
|
||||
showImage,
|
||||
showText,
|
||||
sentMessageBar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
targetId: '',
|
||||
conversationType: 3,
|
||||
messages: [],
|
||||
groupInfo: {
|
||||
name: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
onLoad(e) {
|
||||
this.targetId = e.targetId
|
||||
this.groupInfo = this.$store.getters.contactInfo(this.targetId)
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.groupInfo.name
|
||||
})
|
||||
this.getMessageList()
|
||||
uni.$on('onReceiveMessage', (msg) => {
|
||||
if (msg.targetId == this.targetId) {
|
||||
this.getMessageList()
|
||||
}
|
||||
})
|
||||
},
|
||||
onBackPress() {
|
||||
uni.$off('onReceiveMessage')
|
||||
},
|
||||
onNavigationBarButtonTap() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/im/group/info?targetId=' + this.targetId
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
toUser(item) {
|
||||
console.log(item);
|
||||
uni.navigateTo({
|
||||
url: '/pages/im/friends/info?targetId=' + item.senderUserId
|
||||
})
|
||||
},
|
||||
// 获取消息列表
|
||||
getMessageList() {
|
||||
im.getMessageList(
|
||||
this.conversationType,
|
||||
this.targetId,
|
||||
new Date().getTime(),
|
||||
20,
|
||||
true,
|
||||
(messages) => {
|
||||
this.messages = messages.reverse()
|
||||
this.scrollBottom()
|
||||
})
|
||||
},
|
||||
// 滚动到底部
|
||||
scrollBottom(type) {
|
||||
// 清理当前会话,未读消息数量
|
||||
RongIMLib.clearMessagesUnreadStatus(this.conversationType, this.targetId, new Date().getTime() + 1100)
|
||||
// 发送消息已读状态给对方
|
||||
RongIMLib.sendReadReceiptMessage(this.conversationType, this.targetId, new Date().getTime())
|
||||
// 更新badge提醒数量
|
||||
im.setNotifyBadge()
|
||||
|
||||
setTimeout(() => {
|
||||
let el = this.$refs.chatBottom
|
||||
ChatList.scrollToElement(el, {
|
||||
offset: 0,
|
||||
animated: false
|
||||
})
|
||||
}, 50)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.group--chat {
|
||||
background: $window-color;
|
||||
flex: 1;
|
||||
|
||||
.body {
|
||||
flex: 1;
|
||||
|
||||
.cell {
|
||||
padding: 10rpx 30rpx;
|
||||
|
||||
.cell-item {
|
||||
width: 690rpx;
|
||||
justify-content: flex-start;
|
||||
|
||||
|
||||
&.left {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
&.right {
|
||||
flex-direction: row-reverse;
|
||||
|
||||
.state {
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 78rpx;
|
||||
height: 78rpx;
|
||||
background-color: white;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.msg {
|
||||
margin: 0 20rpx;
|
||||
|
||||
.user {
|
||||
font-size: 18rpx;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cell-footer {
|
||||
height: 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
background: white;
|
||||
padding: 20rpx 30rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-direction: row;
|
||||
|
||||
.msg-type {
|
||||
width: 70rpx;
|
||||
height: 70rpx;
|
||||
|
||||
.icon {
|
||||
margin: 5rpx;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
48
pages/im/group/create.vue
Normal file
48
pages/im/group/create.vue
Normal file
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<view>
|
||||
<u--input placeholder="请输入内容" border="surround" v-model="group_name"></u--input>
|
||||
|
||||
<u-button type="primary" text="确定" @click="onCreate"></u-button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
createGroup
|
||||
} from '@/apis/interfaces/im.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
group_name: '',
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
onCreate() {
|
||||
console.log('阿斯利康');
|
||||
createGroup({
|
||||
name: this.group_name
|
||||
}).then(res => {
|
||||
console.log(res);
|
||||
uni.showToast({
|
||||
title: '创建成功'
|
||||
})
|
||||
uni.navigateBack()
|
||||
}).catch(err => {
|
||||
console.log(err);
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: err
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@@ -1,11 +1,79 @@
|
||||
<template>
|
||||
<view class="">
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<template>
|
||||
<view>
|
||||
<view v-for="(item, index) in groups" :key="index" class="friend-flex u-border-bottom"
|
||||
@click="toGroup(item.targetId)">
|
||||
<u-avatar size="40" shape="square" :src="contact(item.targetId).portraitUrl" />
|
||||
<view class="info">
|
||||
<view class="name">{{ item.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getMyGroups
|
||||
} from '@/apis/interfaces/im.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
groups: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
contact() {
|
||||
return function(targetId) {
|
||||
return this.$store.getters.contactInfo(targetId)
|
||||
}
|
||||
}
|
||||
},
|
||||
onNavigationBarButtonTap() {
|
||||
uni.navigateTo({
|
||||
url: 'pages/im/group/create'
|
||||
})
|
||||
},
|
||||
onLoad() {
|
||||
getMyGroups().then((res) => {
|
||||
this.groups = res
|
||||
res.map(item => {
|
||||
this.$store.dispatch('updateContact', item)
|
||||
})
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
toGroup(targetId) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/im/group/chat?targetId=' + targetId
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 好友列表
|
||||
.friend-flex {
|
||||
position: relative;
|
||||
padding: 20rpx $padding;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
.info {
|
||||
flex: 1;
|
||||
margin-left: $padding;
|
||||
|
||||
.name {
|
||||
font-size: $title-size + 2;
|
||||
font-size: $title-size + 2;
|
||||
color: #454545 !important;
|
||||
}
|
||||
|
||||
.address {
|
||||
color: $text-gray-m;
|
||||
font-size: $title-size-m - 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
213
pages/im/group/info.vue
Normal file
213
pages/im/group/info.vue
Normal file
@@ -0,0 +1,213 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="members u-border-bottom">
|
||||
<view class="users">
|
||||
<view class="user" v-for="(item, index) in members" :key="index" @click="toUser(item)">
|
||||
<u-avatar size="44" shape="square" :src="item.portraitUrl"></u-avatar>
|
||||
<view class="name">{{ item.name }}</view>
|
||||
</view>
|
||||
<view class="user">
|
||||
<u-avatar @click="inviteUser" size="44" shape="square" icon="plus" bg-color="#eeeeee"
|
||||
color="#999999"></u-avatar>
|
||||
<view class="name">邀请用户</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view @click="loadMore" class="loadmore">查看更多群成员</view>
|
||||
</view>
|
||||
|
||||
<u-cell-group class="cells">
|
||||
<u-cell isLink title="群公告" :label="announcement" @click="toAnnouncement"></u-cell>
|
||||
<u-cell title="聊天置顶">
|
||||
<u-switch slot="value" size="20" v-model="isTop" activeColor="#34CE98" @change="setTop"></u-switch>
|
||||
</u-cell>
|
||||
<u-cell title="免打扰">
|
||||
<u-switch slot="value" size="20" v-model="status" activeColor="#34CE98" @change="setStatus"></u-switch>
|
||||
</u-cell>
|
||||
</u-cell-group>
|
||||
|
||||
<u-cell-group class="cells" v-if="group.is_owner">
|
||||
<u-cell isLink title="修改群聊名称" :value="group.name" @click="onGroupName"></u-cell>
|
||||
<u-cell isLink title="修改群头像">
|
||||
<u-avatar slot="value" size="24" shape="square" :src="group.cover"></u-avatar>
|
||||
</u-cell>
|
||||
</u-cell-group>
|
||||
|
||||
<view class="cells actions u-border-top">
|
||||
<view class="action u-border-bottom" @click="onClean">清空聊天记录</view>
|
||||
<view class="action u-border-bottom" v-if="group.is_owner" @click="onDismiss">解散群聊</view>
|
||||
<view class="action u-border-bottom" v-else @click="onQuite">删除并退出</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getGroupInfo
|
||||
} from '@/apis/interfaces/im.js'
|
||||
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
targetId: '',
|
||||
group: {},
|
||||
conversationType: 3,
|
||||
announcement: '',
|
||||
members: [],
|
||||
status: false,
|
||||
isTop: false,
|
||||
}
|
||||
},
|
||||
onLoad(e) {
|
||||
this.targetId = e.targetId
|
||||
getGroupInfo(this.targetId).then(res => {
|
||||
this.group = res.group
|
||||
console.log(this.group);
|
||||
this.announcement = res.announcement
|
||||
this.members = res.members
|
||||
})
|
||||
RongIMLib.getConversationNotificationStatus(this.conversationType, this.targetId, ({
|
||||
status
|
||||
}) => {
|
||||
this.status = !Boolean(status)
|
||||
})
|
||||
RongIMLib.getConversation(this.conversationType, this.targetId, ({
|
||||
code,
|
||||
conversation
|
||||
}) => {
|
||||
if (code == 0) {
|
||||
this.isTop = conversation.isTop
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
setStatus() {
|
||||
RongIMLib.setConversationNotificationStatus(this.conversationType, this.targetId, this.status,
|
||||
({
|
||||
status
|
||||
}) => {
|
||||
this.status = !Boolean(status)
|
||||
})
|
||||
},
|
||||
setTop() {
|
||||
RongIMLib.setConversationToTop(this.conversationType, this.targetId, this.isTop, (res) => {
|
||||
RongIMLib.getConversation(this.conversationType, this.targetId, ({
|
||||
conversation
|
||||
}) => {
|
||||
this.isTop = conversation.isTop
|
||||
})
|
||||
})
|
||||
},
|
||||
toUser(item) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/im/friends/info?targetId=' + item.targetId
|
||||
})
|
||||
},
|
||||
inviteUser() {
|
||||
|
||||
},
|
||||
loadMore() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/im/group/users?targetId=' + this.targetId
|
||||
})
|
||||
},
|
||||
toAnnouncement() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/im/group/announcement?targetId=' + this.targetId
|
||||
})
|
||||
},
|
||||
onGroupName() {
|
||||
|
||||
},
|
||||
onClean() {
|
||||
uni.showModal({
|
||||
title: '清空聊天记录',
|
||||
content: '清空聊天记录,只会清空本地的记录,其他成员不会变化',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
RongIMLib.deleteMessages(3, this.targetId, () => {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '清空成功'
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
onDismiss() {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '开发中'
|
||||
})
|
||||
},
|
||||
onQuite() {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '开发中'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
background: $window-color;
|
||||
}
|
||||
|
||||
.cells {
|
||||
margin-top: $padding;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.members {
|
||||
background-color: white;
|
||||
padding-bottom: 40rpx;
|
||||
|
||||
.users {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
display: flex;
|
||||
padding: 20rpx 0;
|
||||
|
||||
.user {
|
||||
width: 126rpx;
|
||||
margin-left: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.name {
|
||||
width: 126rpx;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.loadmore {
|
||||
font-size: 28rpx;
|
||||
color: $text-gray-m;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin-top: $padding;
|
||||
text-align: center;
|
||||
|
||||
.action {
|
||||
padding: $padding;
|
||||
color: $text-price;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
74
pages/im/group/users.vue
Normal file
74
pages/im/group/users.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<view class="members">
|
||||
<view class="users">
|
||||
<view class="user" v-for="(item, index) in members" :key="index" @click="toUser(item)">
|
||||
<u-avatar size="44" shape="square" :src="item.portraitUrl"></u-avatar>
|
||||
<view class="name">{{ item.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getGroupInfo,
|
||||
getGroupUsers
|
||||
} from '@/apis/interfaces/im.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
targetId: '',
|
||||
members: []
|
||||
}
|
||||
},
|
||||
onLoad(e) {
|
||||
this.targetId = e.targetId
|
||||
getGroupInfo(this.targetId).then(res => {
|
||||
|
||||
})
|
||||
getGroupUsers(this.targetId).then(res => {
|
||||
this.members = res
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
toUser(item) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/im/friends/info?targetId=' + item.targetId
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.members {
|
||||
background-color: white;
|
||||
padding-bottom: 40rpx;
|
||||
|
||||
.users {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
display: flex;
|
||||
padding: 20rpx 0;
|
||||
|
||||
.user {
|
||||
width: 126rpx;
|
||||
margin-left: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.name {
|
||||
width: 126rpx;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -5,56 +5,23 @@
|
||||
<view class="custom-header">
|
||||
<view class="header-flex">
|
||||
<view class="tabs">
|
||||
<view class="item show">私聊</view>
|
||||
<view class="item" @click="onNav('', {})">群聊</view>
|
||||
<view class="item active">聊聊</view>
|
||||
</view>
|
||||
<view class="btns">
|
||||
<view class="item" @click="onNav('imFriends', {})">
|
||||
<uni-icons color="#555" custom-prefix="iconfont" type="icon-tuandui" size="22"></uni-icons>
|
||||
</view>
|
||||
<view class="item" @click="scanQrCode">
|
||||
<uni-icons color="#555" type="scan" size="22"></uni-icons>
|
||||
<uni-icons color="#555" type="scan" size="22" />
|
||||
</view>
|
||||
<view class="item" @click="toFriendList">
|
||||
<u-badge absolute max="99" :offset="[-5, -5]" :value="hasNewFriends" />
|
||||
<uni-icons color="#555" custom-prefix="iconfont" type="icon-tuandui" size="22" />
|
||||
</view>
|
||||
<!-- <view class="item" @click="onNav('', {})">
|
||||
<uni-icons color="#555" custom-prefix="iconfont" type="icon-gengduo2" size="22"></uni-icons>
|
||||
</view> -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<u-alert type="warning" v-if="connection != 0" description="网络似乎断开了,请检查网络" :show-icon="true" />
|
||||
<!-- content -->
|
||||
<view v-if="$store.state.token != ''">
|
||||
<block v-if="conversations.length < 1">
|
||||
<view class="vertical null-list">
|
||||
<u-empty mode="message" textColor="#999" text="暂无好友消息" />
|
||||
</view>
|
||||
</block>
|
||||
<block v-else>
|
||||
<u-alert type="warning" v-if="connection != 0" description="网络似乎断开了" :show-icon="true" />
|
||||
<view v-for="(item, index) in conversations" :key="index" :class="['message', { 'is-top': item.isTop }]"
|
||||
@tap="toDetail(item)" @longpress="onLongPress" :data-item="item">
|
||||
<view class="avatar">
|
||||
<u-badge numberType="ellipsis" max="99" shape="horn" absolute :offset="[-5, -5]"
|
||||
:value="item.unreadMessageCount" />
|
||||
<u-avatar :src="friend(item.targetId).portraitUrl || require('@/static/user/cover.png')"
|
||||
shape="square" size="46" />
|
||||
</view>
|
||||
<view class="content">
|
||||
<view class="header">
|
||||
<view class="name">{{ friend(item.targetId).name || '未知用户' }}</view>
|
||||
<view class="time">{{ item.sentTime|timeCustomCN }}</view>
|
||||
</view>
|
||||
<view class="preview">{{ item.latestMessage.content || '' }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- TODO 长按的弹出框,怎么点击隐藏,没搞明白 -->
|
||||
<view class="shade" @tap="hidePop">
|
||||
<view class="pop" :style="popStyle" :class="{'show':showPop}">
|
||||
<view v-for="(item, index) in popButton" :key="index" @tap="pickerMenu" :data-index="index">
|
||||
{{item}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view v-if="$store.state.token !== ''">
|
||||
<conversation-list @refresh="getConversationList()" :conversations="conversations" />
|
||||
</view>
|
||||
<!-- 未登录 -->
|
||||
<view v-else class="vertical null-list">
|
||||
@@ -68,113 +35,51 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as RongIMLib from "@/uni_modules/RongCloud-IMWrapper/js_sdk/index"
|
||||
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
|
||||
import im from '@/utils/im/index.js'
|
||||
import userAuth from '@/public/userAuth'
|
||||
import {
|
||||
getImToken
|
||||
} from '@/apis/interfaces/im.js'
|
||||
import conversationList from './components/conversationList'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
isShown: true, // 当前页面显示状态
|
||||
conversations: [], // 会话列表
|
||||
connection: 0,
|
||||
/* 窗口尺寸 */
|
||||
winSize: {},
|
||||
/* 显示操作弹窗 */
|
||||
showPop: false,
|
||||
/* 弹窗按钮列表 */
|
||||
popButton: ['置顶聊天', '删除该聊天'],
|
||||
/* 弹窗定位样式 */
|
||||
popStyle: "",
|
||||
pickedItem: {}
|
||||
hasNewFriends: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
friend() {
|
||||
return function(targetId) {
|
||||
return this.$store.getters.userInfo(targetId)
|
||||
}
|
||||
}
|
||||
components: {
|
||||
conversationList
|
||||
},
|
||||
onLoad() {
|
||||
uni.$on('onReceiveMessage', (msg) => {
|
||||
this.getConversationList()
|
||||
})
|
||||
// 好友申请数量
|
||||
this.checkNewFriendPending()
|
||||
uni.$on('onConnectionStatusChange', (status) => {
|
||||
this.connection = status
|
||||
})
|
||||
uni.$on('onContactNotification', this.checkNewFriendPending)
|
||||
},
|
||||
onShow() {
|
||||
if (this.$store.state.token !== '') {
|
||||
this.getConversationList()
|
||||
}
|
||||
this.isShown = true
|
||||
// 监听新消息
|
||||
uni.$on('onReceiveMessage', (msg) => {
|
||||
this.getConversationList()
|
||||
})
|
||||
},
|
||||
onHide() {
|
||||
this.isShown = false
|
||||
uni.$off('onReceiveMessage')
|
||||
},
|
||||
onNavigationBarButtonTap(e) {
|
||||
if (e.index == 0) {
|
||||
uni.showToast({
|
||||
title: '开发中暂未开放,敬请期待',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
if (e.index == 1) {
|
||||
if (this.toLogin()) {
|
||||
this.$Router.push({
|
||||
name: 'imFriends'
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 隐藏功能菜单
|
||||
hidePop() {
|
||||
this.showPop = false
|
||||
this.pickedItem = {}
|
||||
setTimeout(() => {
|
||||
this.showShade = false
|
||||
}, 250)
|
||||
},
|
||||
// 点击会话功能菜单
|
||||
pickerMenu(e) {
|
||||
const index = Number(e.currentTarget.dataset.index)
|
||||
|
||||
if (index == 0) {
|
||||
RongIMLib.setConversationToTop(this.pickedItem.conversationType, this.pickedItem.targetId, !this
|
||||
.pickedItem.isTop)
|
||||
} else {
|
||||
RongIMLib.removeConversation(this.pickedItem.conversationType, this.pickedItem.targetId)
|
||||
}
|
||||
im.setNotifyBadge()
|
||||
this.getConversationList()
|
||||
this.hidePop()
|
||||
},
|
||||
// 长按会话,展示功能菜单
|
||||
onLongPress(e) {
|
||||
let [touches, style, item] = [e.touches[0], "", e.currentTarget.dataset.item]
|
||||
|
||||
if (touches.clientY > (this.winSize.height / 2)) {
|
||||
style = `bottom:${this.winSize.height-touches.clientY}px;`
|
||||
} else {
|
||||
style = `top:${touches.clientY}px;`
|
||||
}
|
||||
if (touches.clientX > (this.winSize.witdh / 2)) {
|
||||
style += `right:${this.winSize.witdh-touches.clientX}px`
|
||||
} else {
|
||||
style += `left:${touches.clientX}px`
|
||||
}
|
||||
|
||||
this.popButton[0] = item.isTop ? '取消置顶' : '置顶聊天'
|
||||
this.popStyle = style
|
||||
this.pickedItem = item
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.showPop = true;
|
||||
}, 10)
|
||||
methods: {
|
||||
checkNewFriendPending() {
|
||||
// 获取是否有新的好友申请
|
||||
RongIMLib.getConversationList([RongIMLib.ConversationType.SYSTEM], 1000, 0, (res) => {
|
||||
if (res.code === 0) {
|
||||
this.hasNewFriends = res.conversations.filter((item) => {
|
||||
return item.objectName == RongIMLib.ObjectName.ContactNotification
|
||||
}).length
|
||||
}
|
||||
})
|
||||
},
|
||||
// 检查登录
|
||||
@@ -186,41 +91,16 @@
|
||||
}
|
||||
return true
|
||||
},
|
||||
// 获取私聊的会话列表
|
||||
getConversationList() {
|
||||
const count = 1000
|
||||
const timestamp = 0
|
||||
RongIMLib.getConversationList([RongIMLib.ConversationType.PRIVATE], count, timestamp, (res) => {
|
||||
RongIMLib.getConversationList([1, 3], count, timestamp, (res) => {
|
||||
if (res.code === 0) {
|
||||
this.conversations = res.conversations
|
||||
}
|
||||
})
|
||||
},
|
||||
// 进入聊天的详情页面,清理未读消息数量
|
||||
toDetail(item) {
|
||||
this.hidePop()
|
||||
uni.navigateTo({
|
||||
url: '/pages/im/private/chat?targetId=' + item.targetId + '&conversationType=' + item
|
||||
.conversationType
|
||||
})
|
||||
|
||||
// url: '/pages/im/private/index?targetId=' + item.targetId + '&conversationType=' + item.conversationType
|
||||
},
|
||||
// 点击按钮
|
||||
onNav(name, params) {
|
||||
if (this.toLogin) {
|
||||
if (name === '') {
|
||||
uni.showToast({
|
||||
title: '开发中,敬请期待',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
this.$Router.push({
|
||||
name,
|
||||
params
|
||||
})
|
||||
}
|
||||
},
|
||||
// 调起扫码
|
||||
scanQrCode() {
|
||||
uni.scanCode({
|
||||
@@ -233,59 +113,17 @@
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
toFriendList() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/im/friends/index'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// header
|
||||
.custom-header {
|
||||
@extend .ios-top;
|
||||
background: $window-color;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 9999;
|
||||
|
||||
.header-flex {
|
||||
padding: 20rpx $padding;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
|
||||
.tabs {
|
||||
.item {
|
||||
margin-left: $margin;
|
||||
display: inline-block;
|
||||
font-size: $title-size-lg;
|
||||
color: $text-gray;
|
||||
padding: 0 ($padding - 10);
|
||||
border-radius: 30rpx;
|
||||
|
||||
&:first-child {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&.show {
|
||||
background: rgba($color: $main-color, $alpha: .1);
|
||||
color: $main-color;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btns {
|
||||
.item {
|
||||
display: inline-block;
|
||||
margin-left: $margin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// contents
|
||||
.contents {
|
||||
background-color: $window-color;
|
||||
@@ -293,6 +131,50 @@
|
||||
padding-top: 90rpx + 20rpx;
|
||||
box-sizing: border-box;
|
||||
|
||||
.custom-header {
|
||||
@extend .ios-top;
|
||||
background: $window-color;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 9999;
|
||||
|
||||
.header-flex {
|
||||
padding: 20rpx $padding;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
|
||||
.tabs {
|
||||
|
||||
.item {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
font-size: $title-size-lg;
|
||||
color: $text-gray;
|
||||
padding: 0 ($padding - 10);
|
||||
border-radius: 30rpx;
|
||||
|
||||
&.active {
|
||||
background: rgba($color: $main-color, $alpha: .1);
|
||||
color: $main-color;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btns {
|
||||
.item {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin-left: $margin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.null-list {
|
||||
height: 100vh;
|
||||
text-align: center;
|
||||
@@ -308,116 +190,6 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
.message {
|
||||
background: white;
|
||||
padding: 30rpx 0 0 30rpx;
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
||||
|
||||
&.is-top {
|
||||
background: $window-color;
|
||||
border-bottom: #e8e8e8;
|
||||
// background-color: rgba($color: $main-color, $alpha: 0.02);
|
||||
}
|
||||
|
||||
.avatar {
|
||||
position: relative;
|
||||
|
||||
.u-badge {
|
||||
z-index: 998;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-left: 30rpx;
|
||||
width: calc(100% - 46px);
|
||||
box-sizing: border-box;
|
||||
border-bottom: solid 1rpx #f3f3f3;
|
||||
position: relative;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.name {
|
||||
font-size: $title-size + 2;
|
||||
color: #454545;
|
||||
color: #454545;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: $title-size-sm;
|
||||
color: $text-gray-m;
|
||||
position: absolute;
|
||||
right: 30rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.preview {
|
||||
word-break: break-all;
|
||||
color: $text-gray-m;
|
||||
padding-top: $padding - 20;
|
||||
padding-bottom: $padding;
|
||||
font-size: $title-size-m;
|
||||
height: 40rpx;
|
||||
line-height: 40rpx;
|
||||
width: 500rpx;
|
||||
@extend .nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// .message:not(:last-child) {
|
||||
// &::after {
|
||||
// position: absolute;
|
||||
// left: calc(44px + #{$padding} + 30rpx);
|
||||
// right: 0;
|
||||
// bottom: 0;
|
||||
// content: " ";
|
||||
// height: 1rpx;
|
||||
// background: $border-color;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/* 遮罩 */
|
||||
.shade {
|
||||
|
||||
.pop {
|
||||
position: fixed;
|
||||
z-index: 101;
|
||||
width: 200rpx;
|
||||
box-sizing: border-box;
|
||||
font-size: 28rpx;
|
||||
text-align: left;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
|
||||
line-height: 80rpx;
|
||||
transition: transform 0.15s ease-in-out 0s;
|
||||
user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
transform: scale(0, 0);
|
||||
|
||||
&.show {
|
||||
transform: scale(1, 1);
|
||||
}
|
||||
|
||||
&>view {
|
||||
padding: 0 20rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
user-select: none;
|
||||
-webkit-touch-callout: none;
|
||||
|
||||
&:active {
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.u-border-bottom {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view class="call-page">
|
||||
<view class="call">
|
||||
<view class="video">
|
||||
<RongCloud-Call-RCUniCallView ref="bigVideoView" :style="{width:windowWidth+'px',height:windowHeight+'px'}"
|
||||
class="bigVideoView">
|
||||
@@ -9,9 +9,11 @@
|
||||
</view>
|
||||
|
||||
<view class="status" v-if="!connected || mediaType == 0">
|
||||
<view class="call-user">
|
||||
<u-avatar v-if="userInfo.portraitUrl" :src="userInfo.portraitUrl" shape="square" size="96" bgColor="#fff" />
|
||||
<u-avatar size="80" v-if="!userInfo.portraitUrl" shape="square" :text="userInfo.name ? userInfo.name.substring(0,1) : '未'" font-size="44" randomBgColor />
|
||||
<view class="remote">
|
||||
<u-avatar v-if="userInfo.portraitUrl" :src="userInfo.portraitUrl" shape="square" size="96"
|
||||
bgColor="#fff" />
|
||||
<u-avatar size="80" v-if="!userInfo.portraitUrl" shape="square"
|
||||
:text="userInfo.name ? userInfo.name.substring(0,1) : '未'" font-size="44" randomBgColor />
|
||||
<view><text class="nickname">{{userInfo.name}}</text></view>
|
||||
<view v-if="remoteRinging"><text class="mediaType">等待对方接听</text></view>
|
||||
<view v-if="connected"><text class="mediaType">已接通</text></view>
|
||||
@@ -163,85 +165,88 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.call-page {
|
||||
<style scoped lang="scss">
|
||||
.call {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.bigVideoView {
|
||||
background: #000;
|
||||
}
|
||||
.video {
|
||||
.bigVideoView {
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.smallVideoView {
|
||||
background: blue;
|
||||
position: absolute;
|
||||
right: 100rpx;
|
||||
top: 100rpx;
|
||||
width: 180rpx;
|
||||
height: 320rpx;
|
||||
}
|
||||
.smallVideoView {
|
||||
background: blue;
|
||||
position: absolute;
|
||||
right: 100rpx;
|
||||
top: 100rpx;
|
||||
width: 180rpx;
|
||||
height: 320rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.buttons {
|
||||
position: fixed;
|
||||
bottom: 100rpx;
|
||||
width: 750rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
}
|
||||
.status {
|
||||
flex: 1;
|
||||
background: #666;
|
||||
width: 750rpx;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
|
||||
.btn {
|
||||
align-items: center;
|
||||
}
|
||||
.remote {
|
||||
flex: 1;
|
||||
width: 750rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
top: 300rpx;
|
||||
|
||||
.icon {
|
||||
background: #34CE98;
|
||||
width: 132rpx;
|
||||
height: 132rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.mediaType {
|
||||
font-size: 32rpx;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.btn .text {
|
||||
margin-top: 16rpx;
|
||||
color: #FFFFFF;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
.nickname {
|
||||
margin: 30rpx;
|
||||
font-size: 44rpx;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon.hangup {
|
||||
background: #dd524d;
|
||||
}
|
||||
.buttons {
|
||||
position: fixed;
|
||||
bottom: 100rpx;
|
||||
width: 750rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.status {
|
||||
flex: 1;
|
||||
background: #666;
|
||||
width: 750rpx;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.call-user {
|
||||
flex: 1;
|
||||
width: 750rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
top: 300rpx;
|
||||
}
|
||||
.btn {
|
||||
align-items: center;
|
||||
|
||||
.mediaType {
|
||||
font-size: 32rpx;
|
||||
color: #aaa;
|
||||
}
|
||||
&.hangup {
|
||||
background: $text-price;
|
||||
}
|
||||
|
||||
.nickname {
|
||||
margin: 30rpx;
|
||||
font-size: 44rpx;
|
||||
color: #ffffff;
|
||||
.icon {
|
||||
background: $main-color;
|
||||
width: 132rpx;
|
||||
height: 132rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.text {
|
||||
margin-top: 16rpx;
|
||||
color: #FFFFFF;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
<template>
|
||||
<view class="chat">
|
||||
<!-- chat -->
|
||||
<list class="chat-scroll" :show-scrollbar="false">
|
||||
<list class="body" :show-scrollbar="false">
|
||||
<cell class="cell" v-for="(item, index) in messages" :key="index">
|
||||
<view class="cell-time">
|
||||
<text class="cell-time-text">{{ customCN(item.sentTime) }}</text>
|
||||
<view class="time">
|
||||
<text class="text">{{ customCN(item.sentTime) }}</text>
|
||||
</view>
|
||||
<view class="cell-item" :class="item.messageDirection == 1 ? 'right' : 'left'">
|
||||
<image class="active" :src="userInfo.portraitUrl" mode="aspectFill"
|
||||
@click="showFriend(targetId, item.messageDirection)"></image>
|
||||
<view class="cell-item" :class="item.messageDirection == 1 ? 'right' : 'left'">
|
||||
<u-avatar class="avatar" size="36" shape="square" @click="showUser(targetId, item.messageDirection)" :src="userInfo.portraitUrl" />
|
||||
<view class="msg">
|
||||
<show-voice v-if="item.objectName === 'RC:HQVCMsg'" :guest="item.messageDirection == 1"
|
||||
:msg="item.content"></show-voice>
|
||||
:msg="item.content" />
|
||||
<show-image v-if="item.objectName === 'RC:ImgMsg'" :guest="item.messageDirection == 1"
|
||||
:msg="item.content.content"></show-image>
|
||||
:msg="item.content" />
|
||||
<show-text v-if="item.objectName === 'RC:TxtMsg'" :guest="item.messageDirection == 1"
|
||||
:msg="item.content.content"></show-text>
|
||||
:msg="item.content" />
|
||||
<view class="state" v-if="item.messageDirection == 1">
|
||||
<text class="state-text">{{ item.sentStatus == 50 ? '已读': '未读'}}</text>
|
||||
</view>
|
||||
@@ -24,30 +23,7 @@
|
||||
</cell>
|
||||
<cell class="cell-footer" ref="chatBottom"></cell>
|
||||
</list>
|
||||
<!-- footer -->
|
||||
<view class="chat-footer">
|
||||
<view class="msg-type" @click="msgType">
|
||||
<image class="msg-type-icon" src="@/static/icon/key-icon.png" v-if="importTabs === 0" mode="widthFix">
|
||||
</image>
|
||||
<image class="msg-type-icon" src="@/static/icon/msg-icon.png" v-if="importTabs === 1" mode="widthFix">
|
||||
</image>
|
||||
</view>
|
||||
<block v-if="importTabs === 0">
|
||||
<view class="chat-mp3" hover-class="chat-hover" @touchstart="startAudio" @touchend="chendAudio">
|
||||
<text class="chat-mp3-text">按住说话</text>
|
||||
</view>
|
||||
</block>
|
||||
<block v-if="importTabs === 1">
|
||||
<input class="chat-input" type="text" v-model="inputTxt" confirm-type="发送" @confirm="send"
|
||||
cursor-spacing="10" />
|
||||
</block>
|
||||
<text class="chat-push" size="mini" @click="send">发送</text>
|
||||
</view>
|
||||
<!-- 录音中提示 -->
|
||||
<view class="audio-transcribe" v-if="showAudioTranscribe">
|
||||
<image class="audio-transcribe-src" src="@/static/icon/record-icon.png" mode="widthFix"></image>
|
||||
<text class="audio-transcribe-text">录音中 {{transcribeTime}} s</text>
|
||||
</view>
|
||||
<sent-message-bar :conversationType="conversationType" :targetId="targetId" @onSuccess="getMessageList()" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -55,171 +31,94 @@
|
||||
import {
|
||||
timeCustomCN
|
||||
} from '@/utils/filters.js'
|
||||
import * as RongIMLib from "@/uni_modules/RongCloud-IMWrapper/js_sdk/index"
|
||||
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
|
||||
import im from '@/utils/im/index.js'
|
||||
import permision from "@/js_sdk/wa-permission/permission.js"
|
||||
import showVoice from './components/showVoice'
|
||||
import showImage from './components/showImage'
|
||||
import showText from './components/showText'
|
||||
import showVoice from '../components/showVoice'
|
||||
import showImage from '../components/showImage'
|
||||
import showText from '../components/showText'
|
||||
import sentMessageBar from '../components/sentMessageBar'
|
||||
|
||||
var transcribe
|
||||
const recorderManager = uni.getRecorderManager()
|
||||
const ChatList = uni.requireNativePlugin('dom')
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
targetId: '',
|
||||
inputTxt: '',
|
||||
messages: [],
|
||||
conversationType: 1,
|
||||
userInfo: {
|
||||
name: '',
|
||||
userId: '',
|
||||
portraitUrl: ''
|
||||
},
|
||||
importTabs: 1,
|
||||
showAudioTranscribe: false,
|
||||
transcribeTime: 60,
|
||||
audioContextPaused: true
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
sentMessageBar,
|
||||
showVoice,
|
||||
showImage,
|
||||
showText
|
||||
},
|
||||
onLoad(e) {
|
||||
this.targetId = e.targetId
|
||||
this.conversationType = e.conversationType // 会话类型
|
||||
this.userInfo = this.$store.getters.userInfo(this.targetId)
|
||||
this.userInfo = this.$store.getters.contactInfo(this.targetId)
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.$store.getters.userInfo(this.targetId).name
|
||||
title: this.userInfo.name
|
||||
})
|
||||
|
||||
RongIMLib.clearMessagesUnreadStatus(this.conversationType, this.targetId, new Date().getTime())
|
||||
im.setNotifyBadge()
|
||||
RongIMLib.sendReadReceiptMessage(this.conversationType, this.targetId, new Date().getTime())
|
||||
|
||||
// 获取消息列表
|
||||
this.getMessageList()
|
||||
|
||||
// 监听消息回执
|
||||
RongIMLib.addReadReceiptReceivedListener(({
|
||||
data
|
||||
}) => {
|
||||
// 监听消息已读状态
|
||||
uni.$on('onReadReceiptReceived', (data) => {
|
||||
if (data.targetId == this.targetId) {
|
||||
this.getMessageList()
|
||||
}
|
||||
})
|
||||
|
||||
// 监听收到新消息,判断是否是当前会话,更新会话内容
|
||||
uni.$on('onReceiveMessage', (msg) => {
|
||||
if (msg.targetId == this.targetId) {
|
||||
RongIMLib.clearMessagesUnreadStatus(msg.conversationType, msg.targetId, msg.sentTime)
|
||||
RongIMLib.sendReadReceiptMessage(msg.conversationType, msg.targetId, msg.sentTime)
|
||||
this.getMessageList()
|
||||
im.setNotifyBadge()
|
||||
}
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
onBackPress() {
|
||||
uni.$off('onReceiveMessage')
|
||||
},
|
||||
onUnload() {
|
||||
RongIMLib.clearReadReceiptReceivedListener()
|
||||
},
|
||||
computed: {
|
||||
disabled() {
|
||||
return this.inputTxt.length == 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
customCN(val) {
|
||||
return timeCustomCN(val)
|
||||
},
|
||||
// 检查安卓录制权限
|
||||
async getAndroidPermission() {
|
||||
return await permision.requestAndroidPermission('android.permission.RECORD_AUDIO')
|
||||
},
|
||||
// 切换聊天信息
|
||||
msgType() {
|
||||
this.importTabs = this.importTabs === 1 ? 0 : 1
|
||||
},
|
||||
// 录制语音消息
|
||||
startAudio(e) {
|
||||
this.getAndroidPermission().then(code => {
|
||||
switch (code) {
|
||||
case 1:
|
||||
this.showAudioTranscribe = true
|
||||
recorderManager.start()
|
||||
transcribe = setInterval(() => {
|
||||
this.transcribeTime -= 1
|
||||
if (this.transcribeTime === 0) {
|
||||
this.chendAudio()
|
||||
}
|
||||
}, 1000)
|
||||
break;
|
||||
case 0:
|
||||
uni.showToast({
|
||||
title: '暂无麦克风权限,请前往应用设置开启麦克风',
|
||||
icon: 'none'
|
||||
})
|
||||
break;
|
||||
case -1:
|
||||
uni.showToast({
|
||||
title: '应用权限错误',
|
||||
icon: 'none'
|
||||
})
|
||||
break;
|
||||
}
|
||||
})
|
||||
},
|
||||
// 结束录音
|
||||
chendAudio(e) {
|
||||
if (!this.showAudioTranscribe) return
|
||||
recorderManager.stop()
|
||||
clearInterval(transcribe)
|
||||
// 监听录音结束
|
||||
recorderManager.onStop(res => {
|
||||
im.sentVoice(this.conversationType, this.targetId, res.tempFilePath, (60 - this
|
||||
.transcribeTime), () => {
|
||||
setTimeout(() => {
|
||||
this.getMessageList()
|
||||
}, 500)
|
||||
})
|
||||
this.transcribeTime = 60
|
||||
this.showAudioTranscribe = false
|
||||
})
|
||||
},
|
||||
// 获取消息列表
|
||||
getMessageList() {
|
||||
im.getMessageList(this.conversationType, this.targetId, (messages) => {
|
||||
this.messages = messages.reverse()
|
||||
this.scrollBottom()
|
||||
})
|
||||
im.getMessageList(
|
||||
this.conversationType,
|
||||
this.targetId,
|
||||
new Date().getTime(),
|
||||
10,
|
||||
true,
|
||||
(messages) => {
|
||||
this.messages = messages.reverse()
|
||||
this.scrollBottom()
|
||||
})
|
||||
},
|
||||
// 发送文本消息
|
||||
send() {
|
||||
if (this.inputTxt === '') return
|
||||
im.sentText(this.conversationType, this.targetId, this.inputTxt, () => {
|
||||
setTimeout(() => {
|
||||
this.getMessageList()
|
||||
}, 500)
|
||||
this.inputTxt = ''
|
||||
})
|
||||
},
|
||||
// 展示好友信息
|
||||
showFriend(targetId, type) {
|
||||
// 展示好友信息, type 1 是自己, 2 是对方
|
||||
showUser(targetId, type) {
|
||||
uni.navigateTo({
|
||||
url: type === 1 ? '/pages/im/friends/mine?targetId=' + targetId :
|
||||
'/pages/im/friends/info?targetId=' + targetId
|
||||
})
|
||||
},
|
||||
// 滚动到底部
|
||||
scrollBottom() {
|
||||
scrollBottom(type) {
|
||||
// 清理当前会话,未读消息数量
|
||||
RongIMLib.clearMessagesUnreadStatus(this.conversationType, this.targetId, new Date().getTime() + 1100)
|
||||
// 发送消息已读状态给对方
|
||||
RongIMLib.sendReadReceiptMessage(this.conversationType, this.targetId, new Date().getTime())
|
||||
// 更新badge提醒数量
|
||||
im.setNotifyBadge()
|
||||
setTimeout(() => {
|
||||
let el = this.$refs.chatBottom
|
||||
ChatList.scrollToElement(el, {
|
||||
offset: 0,
|
||||
animated: false
|
||||
})
|
||||
}, 50)
|
||||
@@ -228,155 +127,69 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.audio-transcribe {
|
||||
background: rgba(0, 0, 0, .6);
|
||||
position: fixed;
|
||||
height: 200rpx;
|
||||
width: 300rpx;
|
||||
border-radius: 10rpx;
|
||||
z-index: 99;
|
||||
top: 550rpx;
|
||||
left: 225rpx;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.audio-transcribe-src {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
}
|
||||
|
||||
.audio-transcribe-text {
|
||||
font-size: 28rpx;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
<style scoped lang="scss">
|
||||
/* 窗口 */
|
||||
.chat {
|
||||
background: #F3F6FB;
|
||||
background: $window-color;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.chat-scroll {
|
||||
flex: 1;
|
||||
}
|
||||
.body {
|
||||
flex: 1;
|
||||
|
||||
.cell {
|
||||
padding: 10rpx 30rpx;
|
||||
}
|
||||
.cell {
|
||||
padding: 10rpx 30rpx;
|
||||
|
||||
.cell-time {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
.time {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-bottom: 20rpx;
|
||||
|
||||
.cell-time-text {
|
||||
background: #fff;
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
line-height: 40rpx;
|
||||
padding: 0 20rpx;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
.text {
|
||||
background: #fff;
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
line-height: 40rpx;
|
||||
padding: 0 20rpx;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.cell-item {
|
||||
width: 690rpx;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.cell-item {
|
||||
width: 690rpx;
|
||||
justify-content: flex-start;
|
||||
|
||||
.cell-footer {
|
||||
height: 20rpx;
|
||||
}
|
||||
|
||||
.active {
|
||||
width: 78rpx;
|
||||
height: 78rpx;
|
||||
background-color: white;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
&.left {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.msg {
|
||||
margin: 0 20rpx;
|
||||
}
|
||||
&.right {
|
||||
flex-direction: row-reverse;
|
||||
|
||||
.state {
|
||||
padding-top: 10rpx;
|
||||
}
|
||||
.state {
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.state-text {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
.msg {
|
||||
margin: 0 20rpx;
|
||||
|
||||
.cell-item.left {
|
||||
flex-direction: row;
|
||||
}
|
||||
.state {
|
||||
padding-top: 10rpx;
|
||||
|
||||
.cell-item.right {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
.state-text {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cell-item.right .state {
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* footer */
|
||||
.chat-footer {
|
||||
background: white;
|
||||
padding: 20rpx 30rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.msg-type {
|
||||
width: 70rpx;
|
||||
height: 70rpx;
|
||||
}
|
||||
|
||||
.msg-type>.msg-type-icon {
|
||||
margin: 5rpx;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
}
|
||||
|
||||
.chat-mp3 {
|
||||
background: #F3F6FB;
|
||||
height: 70rpx;
|
||||
line-height: 70rpx;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 460rpx;
|
||||
border-radius: 10rpx;
|
||||
margin-right: 15rpx;
|
||||
}
|
||||
|
||||
.chat-mp3-text {
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.chat-input {
|
||||
background: #F3F6FB;
|
||||
height: 70rpx;
|
||||
width: 460rpx;
|
||||
border-radius: 10rpx;
|
||||
margin-right: 15rpx;
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
.chat-push {
|
||||
background: #34CE98;
|
||||
color: white;
|
||||
width: 120rpx;
|
||||
line-height: 70rpx;
|
||||
text-align: center;
|
||||
border-radius: 10rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
.cell-footer {
|
||||
height: 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<template>
|
||||
<view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@@ -1,15 +0,0 @@
|
||||
<template>
|
||||
<view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@@ -1,49 +0,0 @@
|
||||
<template>
|
||||
<view class="im--img" :class="guest ? 'right': 'left'">
|
||||
<image class="src" :src="msg" @click="openImg" mode="widthFix"></image>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'showImage',
|
||||
props: {
|
||||
msg: {
|
||||
type: String,
|
||||
default: 'https://images.pexels.com/photos/9024609/pexels-photo-9024609.jpeg'
|
||||
},
|
||||
guest: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openImg() {
|
||||
uni.previewImage({
|
||||
urls: [this.msg],
|
||||
current: 1
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.im--img {
|
||||
padding: 19rpx;
|
||||
}
|
||||
|
||||
.im--img.left {
|
||||
border-radius: 0 20rpx 20rpx 20rpx;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.im--img.right {
|
||||
border-radius: 20rpx 0 20rpx 20rpx;
|
||||
background: #34CE98;
|
||||
}
|
||||
|
||||
.src {
|
||||
width: 240rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -1,46 +0,0 @@
|
||||
<template>
|
||||
<view class="im--box">
|
||||
<text class="im--text" :class="guest ? 'right': 'left'">{{msg}}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'showText',
|
||||
data() {
|
||||
return {
|
||||
|
||||
};
|
||||
},
|
||||
props: {
|
||||
msg: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
guest: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.im--text {
|
||||
max-width: 400rpx;
|
||||
padding: 20rpx;
|
||||
font-size: 28rpx;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
|
||||
.im--text.left {
|
||||
border-radius: 0 20rpx 20rpx 20rpx;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.im--text.right {
|
||||
border-radius: 20rpx 0 20rpx 20rpx;
|
||||
background: #34CE98;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
@@ -1,499 +0,0 @@
|
||||
<template>
|
||||
<view class="chat-content">
|
||||
<scroll-view class="chat-scrool" :scroll-y="true" :scroll-into-view="scrollIntoID"
|
||||
:scroll-with-animation="false">
|
||||
<!-- 聊天窗口 -->
|
||||
<view class="chat-item" v-for="(item,index) in messages" :key="index">
|
||||
<view class="chat-item-article" :class="item.messageDirection == 1 ? 'right' : 'left'">
|
||||
<view class="chat-msg">
|
||||
<!-- 文字消息 -->
|
||||
<view class="chat-msg-text">{{ item.content.content }}</view>
|
||||
<!-- 语音消息 -->
|
||||
<view class="chat-msg-audio" @click="onPlayMsg()">
|
||||
<image v-if="item.messageDirection == 0" src="@/static/icon/audio_green.png"
|
||||
mode="widthFix"></image>
|
||||
10"
|
||||
<image v-if="item.messageDirection == 1" src="@/static/icon/audio_white.png"
|
||||
mode="widthFix"></image>
|
||||
</view>
|
||||
<!-- 预留一些图片,语音表情包等位置 -->
|
||||
</view>
|
||||
<view class="chat-status" :class="{'hide': item.sentStatus == 50}"
|
||||
v-if="item.messageDirection == 1">{{targetId}}{{ item.sentStatus == 50 ? '已读': '未读'}}</view>
|
||||
<view class="chat-avatar" @click="showFriend(targetId, item.messageDirection)">
|
||||
<u-avatar v-if="item.messageDirection == 2" shape="square" bg-color="#ffffff"
|
||||
:src="userInfo.portraitUrl"></u-avatar>
|
||||
<u-avatar v-else shape="square" bg-color="#ffffff" :src="$store.getters.sender.portraitUrl" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="chat-item-time" :id="'chatId_'+index">
|
||||
<text>{{ item.sentTime|timeCustomCN }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="chat-footer">
|
||||
<view class="msg-type" @click="msgType">
|
||||
<image src="@/static/icon/key-icon.png" v-if="importTabs === 0" mode="widthFix"></image>
|
||||
<image src="@/static/icon/msg-icon.png" v-if="importTabs === 1" mode="widthFix"></image>
|
||||
</view>
|
||||
<block v-if="importTabs === 0">
|
||||
<button type="default" class="chat-mp3" hover-class="chat-hover" @touchstart="startAudio"
|
||||
@touchend="chendAudio">按住 说话</button>
|
||||
</block>
|
||||
<block v-if="importTabs === 1">
|
||||
<input class="chat-input" type="text" v-model="inputTxt" confirm-type="发送" @confirm="send"
|
||||
cursor-spacing="10" />
|
||||
</block>
|
||||
<button class="chat-push" :disabled="disabled" size="mini" @click="send">发送</button>
|
||||
</view>
|
||||
|
||||
<!-- 录音中提示 -->
|
||||
<view class="audio-transcribe" v-if="showAudioTranscribe">
|
||||
<image src="@/static/icon/record-icon.png" mode="widthFix"></image>
|
||||
<view class="text">录音中 {{transcribeTime}} s</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as RongIMLib from "@/uni_modules/RongCloud-IMWrapper/js_sdk/index"
|
||||
import im from '@/utils/im/index.js'
|
||||
import permision from "@/js_sdk/wa-permission/permission.js"
|
||||
|
||||
var transcribe
|
||||
var recorderManager = uni.getRecorderManager()
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
targetId: '',
|
||||
scrollIntoID: 'chatID_0',
|
||||
inputTxt: '',
|
||||
messages: [],
|
||||
conversationType: 1,
|
||||
totalCount: 0,
|
||||
userInfo: {
|
||||
name: '',
|
||||
userId: '',
|
||||
portraitUrl: ''
|
||||
},
|
||||
importTabs: 0,
|
||||
showAudioTranscribe: false,
|
||||
transcribeTime: 60,
|
||||
audioSrc: '',
|
||||
audioContextPaused: true
|
||||
}
|
||||
},
|
||||
onLoad(e) {
|
||||
this.targetId = e.targetId
|
||||
this.conversationType = e.conversationType // 会话类型
|
||||
// 消息总数量
|
||||
RongIMLib.getMessageCount(this.conversationType, this.targetId, ({
|
||||
code,
|
||||
count
|
||||
}) => {
|
||||
if (code == 0) {
|
||||
this.totalCount = count
|
||||
}
|
||||
})
|
||||
this.userInfo = this.$store.getters.userInfo(this.targetId)
|
||||
uni.setNavigationBarTitle({
|
||||
title: this.$store.getters.userInfo(this.targetId).name
|
||||
})
|
||||
|
||||
RongIMLib.clearMessagesUnreadStatus(this.conversationType, this.targetId, new Date().getTime())
|
||||
im.setNotifyBadge()
|
||||
RongIMLib.sendReadReceiptMessage(this.conversationType, this.targetId, new Date().getTime())
|
||||
|
||||
this.getMessageList()
|
||||
|
||||
// 监听消息回执
|
||||
RongIMLib.addReadReceiptReceivedListener(({
|
||||
data
|
||||
}) => {
|
||||
if (data.targetId == this.targetId) {
|
||||
this.getMessageList()
|
||||
}
|
||||
})
|
||||
|
||||
// 监听录音结束
|
||||
recorderManager.onStop(res => {
|
||||
if (res.tempFilePath) this.audioSrc = res.tempFilePath
|
||||
console.log('------------------获取到了录音的临时路径---------------')
|
||||
console.log(res.tempFilePath)
|
||||
})
|
||||
// 简童收到新消息,判断是否是当前会话,更新会话内容
|
||||
uni.$on('onReceiveMessage', (msg) => {
|
||||
if (msg.targetId == this.targetId) {
|
||||
RongIMLib.clearMessagesUnreadStatus(msg.conversationType, msg.targetId, msg.sentTime)
|
||||
RongIMLib.sendReadReceiptMessage(msg.conversationType, msg.targetId, msg.sentTime)
|
||||
this.getMessageList()
|
||||
im.setNotifyBadge()
|
||||
}
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
uni.$off('onReceiveMessage')
|
||||
},
|
||||
onUnload() {
|
||||
RongIMLib.clearReadReceiptReceivedListener()
|
||||
},
|
||||
computed: {
|
||||
disabled() {
|
||||
return this.inputTxt.length == 0
|
||||
}
|
||||
},
|
||||
onNavigationBarButtonTap(e) {
|
||||
if (e.index == 0) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/im/private/setting?targetId=' + this.targetId +
|
||||
'&conversationType=' + this.conversationType,
|
||||
events: {
|
||||
messageClear: () => {
|
||||
this.getMessageList()
|
||||
console.log('聊天消息被清空');
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 播放语音消息
|
||||
onPlayMsg() {
|
||||
let innerAudioContext = uni.createInnerAudioContext()
|
||||
innerAudioContext.src = this.audioSrc
|
||||
if (this.audioContextPaused) {
|
||||
innerAudioContext.play()
|
||||
this.audioContextPaused = false
|
||||
return
|
||||
}
|
||||
innerAudioContext.stop()
|
||||
innerAudioContext.onStop(resStop => {
|
||||
this.audioContextPaused = true
|
||||
})
|
||||
},
|
||||
// 检查安卓录制权限
|
||||
async getAndroidPermission() {
|
||||
return await permision.requestAndroidPermission('android.permission.RECORD_AUDIO')
|
||||
},
|
||||
// 切换聊天信息
|
||||
msgType() {
|
||||
this.importTabs = this.importTabs === 1 ? 0 : 1
|
||||
},
|
||||
// 录制语音消息
|
||||
startAudio(e) {
|
||||
this.getAndroidPermission().then(code => {
|
||||
switch (code) {
|
||||
case 1:
|
||||
this.showAudioTranscribe = true
|
||||
recorderManager.start()
|
||||
transcribe = setInterval(() => {
|
||||
this.transcribeTime -= 1
|
||||
if (this.transcribeTime === 0) {
|
||||
this.chendAudio()
|
||||
}
|
||||
}, 1000)
|
||||
break;
|
||||
case 0:
|
||||
uni.showToast({
|
||||
title: '暂无麦克风权限,请前往应用设置开启麦克风',
|
||||
icon: 'none'
|
||||
})
|
||||
break;
|
||||
case -1:
|
||||
uni.showToast({
|
||||
title: '应用权限错误',
|
||||
icon: 'none'
|
||||
})
|
||||
break;
|
||||
}
|
||||
})
|
||||
},
|
||||
// 结束录音
|
||||
chendAudio(e) {
|
||||
if (!this.showAudioTranscribe) return
|
||||
recorderManager.stop()
|
||||
clearInterval(transcribe)
|
||||
this.transcribeTime = 60
|
||||
this.showAudioTranscribe = false
|
||||
},
|
||||
getMessageList() {
|
||||
// 获取消息列表
|
||||
const objectNames = [
|
||||
'RC:TxtMsg',
|
||||
'RC:VcMsg',
|
||||
'RC:HQVCMsg',
|
||||
'RC:ImgMsg',
|
||||
'RC:GIFMsg',
|
||||
'RC:ImgTextMsg',
|
||||
'RC:FileMsg',
|
||||
'RC:LBSMsg',
|
||||
'RC:SightMsg',
|
||||
'RC:ReferenceMsg',
|
||||
'RC:CombineMsg'
|
||||
]
|
||||
const timeStamp = new Date().getTime()
|
||||
const count = 20 // 获取的消息数量
|
||||
const isForward = true // 是否向前获取
|
||||
RongIMLib.getHistoryMessagesByTimestamp(this.conversationType, this.targetId, objectNames, timeStamp,
|
||||
count,
|
||||
isForward,
|
||||
({
|
||||
code,
|
||||
messages
|
||||
}) => {
|
||||
if (code === 0) {
|
||||
this.messages = messages.reverse()
|
||||
this.scrollBottom()
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
send() {
|
||||
im.sendMsg(this.conversationType, this.targetId, this.inputTxt, () => {
|
||||
this.getMessageList()
|
||||
this.inputTxt = ''
|
||||
})
|
||||
},
|
||||
showFriend(targetId, type) {
|
||||
this.$Router.push({
|
||||
name: type === 1 ? 'imFriendsMine' : 'imFriendsInfo',
|
||||
params: {
|
||||
targetId
|
||||
}
|
||||
})
|
||||
},
|
||||
scrollBottom() {
|
||||
this.$nextTick(function() {
|
||||
setTimeout(() => {
|
||||
let len = this.messages.length
|
||||
if (len) {
|
||||
if (this.scrollIntoID == "chatId_" + (len - 1)) {
|
||||
this.scrollIntoID = "chatId_" + (len - 2)
|
||||
this.scrollBottom()
|
||||
} else if (this.scrollIntoID == "chatId_" + (len - 2)) {
|
||||
this.scrollIntoID = "chatId_" + (len - 1)
|
||||
} else {
|
||||
this.scrollIntoID = "chatId_" + (len - 1)
|
||||
}
|
||||
} else {
|
||||
this.scrollIntoID = "chatId_0";
|
||||
}
|
||||
}, 50)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.chat-content {
|
||||
height: 100vh;
|
||||
background: $window-color;
|
||||
|
||||
.audio-transcribe {
|
||||
background: rgba($color: #000000, $alpha: .6);
|
||||
position: fixed;
|
||||
height: 200rpx;
|
||||
width: 300rpx;
|
||||
border-radius: $radius;
|
||||
color: white;
|
||||
z-index: 99;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-top: -200rpx;
|
||||
margin-left: -150rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
image {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: $title-size-m;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-scrool {
|
||||
height: calc(100vh - 140rpx);
|
||||
box-sizing: border-box;
|
||||
padding-bottom: $padding;
|
||||
|
||||
.chat-item {
|
||||
.chat-item-time {
|
||||
text-align: center;
|
||||
padding: $padding/2 $padding;
|
||||
|
||||
text {
|
||||
background: rgba($color: #000000, $alpha: .2);
|
||||
color: white;
|
||||
font-size: $title-size-sm - 4;
|
||||
line-height: 40rpx;
|
||||
padding: 0 15rpx;
|
||||
display: inline-block;
|
||||
border-radius: $radius-lg;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-item-article {
|
||||
position: relative;
|
||||
padding: 10rpx ($padding + 110) 0;
|
||||
overflow: hidden;
|
||||
min-height: 40px;
|
||||
|
||||
.chat-msg {
|
||||
overflow: hidden;
|
||||
|
||||
.chat-msg-text {
|
||||
display: inline-block;
|
||||
padding: ($padding - 10) $padding;
|
||||
color: $text-color;
|
||||
box-sizing: border-box;
|
||||
font-size: $title-size-lg;
|
||||
}
|
||||
|
||||
.chat-msg-audio {
|
||||
@extend .chat-msg-text;
|
||||
width: 50%;
|
||||
|
||||
image {
|
||||
width: 38rpx;
|
||||
height: 38rpx;
|
||||
margin: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-status {
|
||||
color: $text-gray;
|
||||
font-size: $title-size-sm;
|
||||
text-align: right;
|
||||
|
||||
&.hide {
|
||||
color: $text-gray-m;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-avatar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
background: white;
|
||||
border-radius: $radius-m;
|
||||
}
|
||||
|
||||
&.left {
|
||||
.chat-avatar {
|
||||
left: $margin;
|
||||
}
|
||||
|
||||
.chat-msg {
|
||||
.chat-msg-text {
|
||||
background-color: white;
|
||||
border-radius: 0 $radius*2 $radius*2 $radius*2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.right {
|
||||
.chat-avatar {
|
||||
right: $margin;
|
||||
}
|
||||
|
||||
.chat-msg {
|
||||
text-align: right;
|
||||
|
||||
.chat-msg-text {
|
||||
border-radius: $radius*2 0 $radius*2 $radius*2;
|
||||
background: $main-color;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 140rpx;
|
||||
padding: 20rpx ($padding + 150rpx) 40rpx ($padding + 94rpx);
|
||||
background: white;
|
||||
box-sizing: border-box;
|
||||
z-index: 99;
|
||||
|
||||
.msg-type {
|
||||
position: absolute;
|
||||
top: 20rpx;
|
||||
left: $padding;
|
||||
line-height: 80rpx;
|
||||
|
||||
image {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
vertical-align: middle;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-input {
|
||||
background: $window-color;
|
||||
height: 80rpx;
|
||||
border-radius: $radius-lg;
|
||||
font-size: $title-size-m;
|
||||
padding: 0 $padding;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.chat-mp3 {
|
||||
background: $window-color;
|
||||
line-height: 80rpx;
|
||||
text-align: center;
|
||||
border-radius: $radius-lg;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
font-size: $title-size-m;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-hover {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.chat-push[size='mini'] {
|
||||
position: absolute;
|
||||
right: $margin;
|
||||
top: 20rpx;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 120rpx;
|
||||
background: $main-color;
|
||||
color: white;
|
||||
border-radius: $radius-lg;
|
||||
font-size: $title-size-m;
|
||||
font-weight: bold;
|
||||
|
||||
&[disabled] {
|
||||
background: rgba($color: $main-color, $alpha: .5);
|
||||
}
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -4,7 +4,15 @@
|
||||
<view class="status-main">
|
||||
<view class="helloe">欢迎使用ZH-HEALTH健康</view>
|
||||
<view class="btns">
|
||||
<view class="btns-item" @click="onBtn('signIndex')"><image src="@/static/icon/sign-icon.gif" mode="widthFix"></image></view>
|
||||
<!-- 打卡图标gif -->
|
||||
<!-- <view class="btns-item" @click="$Router.push({name: 'signIndex'})"><image src="@/static/icon/sign-icon.gif" mode="widthFix"></image></view> -->
|
||||
<view class="btns-clock" @click="$Router.push({name: 'signIndex'})">
|
||||
<image src="@/static/icon/clock_icon.png" mode="widthFix"></image>
|
||||
<view class="btns-clock-text">
|
||||
打卡
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="btns-item show" @click="onBtn('noticeIndex')"><uni-icons custom-prefix="iconfont" type="icon-pinglun" size="25"></uni-icons></view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -101,12 +109,29 @@
|
||||
align-items: center;
|
||||
.helloe {
|
||||
line-height: 100rpx;
|
||||
font-size: $title-size + 10;
|
||||
font-size: $title-size + 4;
|
||||
font-weight: bold;
|
||||
}
|
||||
.btns {
|
||||
margin-left: $margin;
|
||||
display: flex;
|
||||
.btns-clock {
|
||||
color: #885100;
|
||||
height: 50rpx;
|
||||
font-size: $title-size-sm - 2;
|
||||
border-radius: 40rpx;
|
||||
display: flex;
|
||||
background-image: linear-gradient(to right, #fce938, #ffce36);
|
||||
image {
|
||||
width: 48rpx;
|
||||
display: inline-block;
|
||||
}
|
||||
.btns-clock-text {
|
||||
line-height: 50rpx;
|
||||
font-weight: 600;
|
||||
padding: 0 20rpx 0 8rpx;
|
||||
}
|
||||
}
|
||||
.btns-item {
|
||||
position: relative;
|
||||
text-align: right;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<view class="number">
|
||||
<text>{{ dateData.total }}</text>天
|
||||
</view>
|
||||
本月签到
|
||||
本月打卡
|
||||
</view>
|
||||
</view>
|
||||
<view class="label">
|
||||
@@ -18,7 +18,7 @@
|
||||
<view class="number">
|
||||
<text>{{ dateData.continue }}</text>天
|
||||
</view>
|
||||
累计签到
|
||||
累计打卡
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -50,25 +50,28 @@
|
||||
六
|
||||
</view>
|
||||
</view>
|
||||
<view class="day" v-for="(item, index) in dateArr">
|
||||
<view class="day-label" v-for="(items, index) in item">
|
||||
<view class="label-block" :class="{active : items.isSign}" v-if="!items.isHidden">{{ items.isSign ? '签' : items.date }}</view>
|
||||
<view class="day" v-for="(item, index) in dateArr" :key="index">
|
||||
<view class="day-label" v-for="(items, index) in item" :key="index">
|
||||
<view class="label-block" :class="{active : items.isSign}" v-if="!items.isHidden">
|
||||
<uni-icons v-if="items.isSign" class="search-icon" custom-prefix="iconfont" type="icon-dui" color="#ffffff" size="18"></uni-icons>
|
||||
<block v-else>{{ items.date }}</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="signBtn">
|
||||
<view class="btn" @click="signClick" :class="{active : dateData.isSign}">
|
||||
{{ dateData.isSign ? '当日已签' : '立即签到'}}
|
||||
{{ dateData.isSign ? '今日已打卡' : '今日打卡'}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="tipsText">
|
||||
ZH大健康用户签到
|
||||
ZH大健康用户打卡
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { date, sign } from '@/apis/interfaces/sign'
|
||||
export default {
|
||||
@@ -112,9 +115,9 @@
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
page {
|
||||
background: $window-color;
|
||||
@@ -174,7 +177,9 @@
|
||||
}
|
||||
}
|
||||
.signDate {
|
||||
padding: $padding;
|
||||
padding: $padding;
|
||||
border-radius: $radius-m;
|
||||
background-color: white;
|
||||
.date {
|
||||
text-align: center;
|
||||
font-size: $title-size + 6;
|
||||
@@ -209,6 +214,12 @@
|
||||
height: 56rpx;
|
||||
line-height: 56rpx;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
.label-icon {
|
||||
position: absolute;
|
||||
left: 10rpx;
|
||||
top: 0;
|
||||
}
|
||||
&.active {
|
||||
background-color: $main-color;
|
||||
color: white;
|
||||
@@ -232,7 +243,8 @@
|
||||
color: $text-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tipsText {
|
||||
text-align: center;
|
||||
@@ -241,4 +253,4 @@
|
||||
color: $text-gray-m;
|
||||
}
|
||||
}
|
||||
color: $text-gray-m;
|
||||
</style>
|
||||
|
||||
@@ -155,12 +155,10 @@
|
||||
if (this.$store.state.token === '') return;
|
||||
info()
|
||||
.then(res => {
|
||||
console.log(res);
|
||||
uni.setNavigationBarTitle({
|
||||
title: res.nickname
|
||||
});
|
||||
this.userInfo = res;
|
||||
console.log(res);
|
||||
})
|
||||
.catch(err => {
|
||||
uni.showToast({
|
||||
|
||||
@@ -1,64 +1,68 @@
|
||||
<template>
|
||||
<view class="content vertical">
|
||||
<!-- logo -->
|
||||
<image class="logo" src="@/static/wallet/logo.png" mode="widthFix"></image>
|
||||
<!-- 副标题 -->
|
||||
<view class="sub-title">激活您的ZH健康钱包获取钱包地址,地址可以理解为您的个人银行卡卡号</view>
|
||||
<!-- 按钮 -->
|
||||
<view class="wallet-btn" @click="$Router.replace({name: 'WalletCreate'})">激活钱包</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
page {
|
||||
background-color: white;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content{
|
||||
position: relative;
|
||||
height: 100vh;
|
||||
padding: 0 15vw;
|
||||
text-align: center;
|
||||
.logo{
|
||||
width: 138rpx;
|
||||
vertical-align: top;
|
||||
margin-bottom: 20vh;
|
||||
}
|
||||
.sub-title{
|
||||
font-size: $title-size-m;
|
||||
color: $text-gray;
|
||||
}
|
||||
.wallet-btn{
|
||||
width: 100%;
|
||||
background-color: $main-color;
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
margin-top: $margin * 2;
|
||||
border-radius: $radius-lg;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: $title-size;
|
||||
&.hollow{
|
||||
background-color: white;
|
||||
color: $main-color;
|
||||
border:solid 2rpx $main-color;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
}
|
||||
<template>
|
||||
<view class="content vertical">
|
||||
<!-- logo -->
|
||||
<image class="logo" src="@/static/wallet/logo.png" mode="widthFix"></image>
|
||||
<!-- 副标题 -->
|
||||
<view class="sub-title">激活您的ZH健康钱包获取钱包地址,地址可以理解为您的个人银行卡卡号</view>
|
||||
<!-- 按钮 -->
|
||||
<view class="wallet-btn" @click="$Router.replace({name: 'WalletCreate'})">激活钱包</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
page {
|
||||
background-color: white;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content {
|
||||
position: relative;
|
||||
height: 100vh;
|
||||
padding: 0 15vw;
|
||||
text-align: center;
|
||||
|
||||
.logo {
|
||||
width: 138rpx;
|
||||
vertical-align: top;
|
||||
margin-bottom: 20vh;
|
||||
}
|
||||
|
||||
.sub-title {
|
||||
font-size: $title-size-m;
|
||||
color: $text-gray;
|
||||
}
|
||||
|
||||
.wallet-btn {
|
||||
width: 100%;
|
||||
background-color: $main-color;
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
margin-top: $margin * 2;
|
||||
border-radius: $radius-lg;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: $title-size;
|
||||
|
||||
&.hollow {
|
||||
background-color: white;
|
||||
color: $main-color;
|
||||
border: solid 2rpx $main-color;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,187 +1,193 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 设置钱包密码 -->
|
||||
<view class="password">
|
||||
<view class="prompt">请设置6位数字密码,建议不要使用连续的数字</view>
|
||||
<view class="group">
|
||||
<view class="inputs" @click="onShowKet('password')">
|
||||
<block v-if="password.length > 0">
|
||||
<text v-for="item in password.length" :key="item">•</text>
|
||||
</block>
|
||||
<block v-if="keyShow && valKye === 'password'">
|
||||
<text class="flicker-animation">|</text>
|
||||
</block>
|
||||
<block v-else>
|
||||
<text v-if="password.length === 0" class="placeholder">请设置密码</text>
|
||||
</block>
|
||||
</view>
|
||||
<view class="inputs" :class="{'hide': verify === ''}" @click="onShowKet('verify')">
|
||||
<block v-if="verify.length > 0">
|
||||
<text v-for="item in verify.length" :key="item">•</text>
|
||||
</block>
|
||||
<block v-if="keyShow && valKye === 'verify'">
|
||||
<text class="flicker-animation">|</text>
|
||||
</block>
|
||||
<block v-else>
|
||||
<text v-if="verify.length === 0" class="placeholder">请确认密码</text>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- key键盘 -->
|
||||
<u-keyboard
|
||||
mode="number"
|
||||
random
|
||||
dotDisabled
|
||||
:overlay="false"
|
||||
:show="keyShow"
|
||||
:showCancel="false"
|
||||
@change="keyValChange"
|
||||
@backspace="keyValBackspace"
|
||||
@confirm="keyShow = false"
|
||||
></u-keyboard>
|
||||
<!-- 按钮 -->
|
||||
<view class="buttons">
|
||||
<button type="default" form-type="submit" @click="createWallet">确认激活</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { security } from '@/apis/interfaces/wallet';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
password: '',
|
||||
verify : '',
|
||||
valKye : '',
|
||||
keyShow : false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
// 唤起key
|
||||
onShowKet(key){
|
||||
this.valKye = key
|
||||
this.keyShow = true
|
||||
},
|
||||
// 键盘输入
|
||||
keyValChange(e){
|
||||
if(this[this.valKye].length >= 6) return
|
||||
this[this.valKye] += e
|
||||
},
|
||||
// 键盘删除
|
||||
keyValBackspace(e){
|
||||
if(this[this.valKye].length) this[this.valKye] = this[this.valKye].substr(0, this[this.valKye].length - 1)
|
||||
},
|
||||
// 激活钱包
|
||||
createWallet() {
|
||||
if (this.password === '' || this.verify === '') {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '请设置密码'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (this.password !== this.verify) {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '两次输入密码不一致'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
security({
|
||||
code: Number(this.password)
|
||||
}).then(res => {
|
||||
this.$Router.replace({
|
||||
name: 'WalletProperty'
|
||||
})
|
||||
}).catch(err => {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: err.message
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.flicker-animation{
|
||||
animation: flicker .8s infinite;
|
||||
}
|
||||
@keyframes flicker{
|
||||
0%{opacity: 0;}
|
||||
100{opacity: 1;}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 副标题
|
||||
.sub-title {
|
||||
color: $text-gray;
|
||||
text-align: center;
|
||||
margin: $margin * 2 $margin;
|
||||
font-size: $title-size-m;
|
||||
}
|
||||
|
||||
// 设置密码
|
||||
.password {
|
||||
padding: 0 $padding * 2;
|
||||
.prompt {
|
||||
margin-top: $margin * 2;
|
||||
font-size: $title-size-m;
|
||||
color: $main-color;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.group {
|
||||
padding-top: $padding;
|
||||
.inputs {
|
||||
padding: 10rpx $padding + 10;
|
||||
margin-top: $margin;
|
||||
border-radius: $radius-m;
|
||||
background-color: $window-color;
|
||||
height: 70rpx;
|
||||
line-height: 70rpx;
|
||||
font-size: $title-size-lg;
|
||||
text-align: center;
|
||||
text{
|
||||
padding: 0 10rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.placeholder{
|
||||
color: $text-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按钮
|
||||
.buttons {
|
||||
padding: $padding * 2;
|
||||
.text {
|
||||
text-align: center;
|
||||
line-height: 90rpx;
|
||||
height: 90rpx;
|
||||
margin-bottom: $margin * 2;
|
||||
font-size: $title-size-lg;
|
||||
color: $main-color;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
button {
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
background-color: $main-color;
|
||||
border-radius: $radius-m;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: $title-size;
|
||||
&::after{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
<template>
|
||||
<view>
|
||||
<!-- 设置钱包密码 -->
|
||||
<view class="password">
|
||||
<view class="prompt">请设置6位数字密码,建议不要使用连续的数字</view>
|
||||
<view class="group">
|
||||
<view class="inputs" @click="onShowKet('password')">
|
||||
<block v-if="password.length > 0">
|
||||
<text v-for="item in password.length" :key="item">•</text>
|
||||
</block>
|
||||
<block v-if="keyShow && valKye === 'password'">
|
||||
<text class="flicker-animation">|</text>
|
||||
</block>
|
||||
<block v-else>
|
||||
<text v-if="password.length === 0" class="placeholder">请设置密码</text>
|
||||
</block>
|
||||
</view>
|
||||
<view class="inputs" :class="{'hide': verify === ''}" @click="onShowKet('verify')">
|
||||
<block v-if="verify.length > 0">
|
||||
<text v-for="item in verify.length" :key="item">•</text>
|
||||
</block>
|
||||
<block v-if="keyShow && valKye === 'verify'">
|
||||
<text class="flicker-animation">|</text>
|
||||
</block>
|
||||
<block v-else>
|
||||
<text v-if="verify.length === 0" class="placeholder">请确认密码</text>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- key键盘 -->
|
||||
<u-keyboard mode="number" random dotDisabled :overlay="false" :show="keyShow" :showCancel="false"
|
||||
@change="keyValChange" @backspace="keyValBackspace" @confirm="keyShow = false"></u-keyboard>
|
||||
<!-- 按钮 -->
|
||||
<view class="buttons">
|
||||
<button type="default" form-type="submit" @click="createWallet">确认激活</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
security
|
||||
} from '@/apis/interfaces/wallet';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
password: '',
|
||||
verify: '',
|
||||
valKye: '',
|
||||
keyShow: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
// 唤起key
|
||||
onShowKet(key) {
|
||||
this.valKye = key
|
||||
this.keyShow = true
|
||||
},
|
||||
// 键盘输入
|
||||
keyValChange(e) {
|
||||
if (this[this.valKye].length >= 6) return
|
||||
this[this.valKye] += e
|
||||
},
|
||||
// 键盘删除
|
||||
keyValBackspace(e) {
|
||||
if (this[this.valKye].length) this[this.valKye] = this[this.valKye].substr(0, this[this.valKye].length -
|
||||
1)
|
||||
},
|
||||
// 激活钱包
|
||||
createWallet() {
|
||||
if (this.password === '' || this.verify === '') {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '请设置密码'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (this.password !== this.verify) {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '两次输入密码不一致'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
security({
|
||||
code: Number(this.password)
|
||||
}).then(res => {
|
||||
this.$Router.replace({
|
||||
name: 'WalletProperty'
|
||||
})
|
||||
}).catch(err => {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: err.message
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.flicker-animation {
|
||||
animation: flicker .8s infinite;
|
||||
}
|
||||
|
||||
@keyframes flicker {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100 {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 副标题
|
||||
.sub-title {
|
||||
color: $text-gray;
|
||||
text-align: center;
|
||||
margin: $margin * 2 $margin;
|
||||
font-size: $title-size-m;
|
||||
}
|
||||
|
||||
// 设置密码
|
||||
.password {
|
||||
padding: 0 $padding * 2;
|
||||
|
||||
.prompt {
|
||||
margin-top: $margin * 2;
|
||||
font-size: $title-size-m;
|
||||
color: $main-color;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.group {
|
||||
padding-top: $padding;
|
||||
|
||||
.inputs {
|
||||
padding: 10rpx $padding + 10;
|
||||
margin-top: $margin;
|
||||
border-radius: $radius-m;
|
||||
background-color: $window-color;
|
||||
height: 70rpx;
|
||||
line-height: 70rpx;
|
||||
font-size: $title-size-lg;
|
||||
text-align: center;
|
||||
|
||||
text {
|
||||
padding: 0 10rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: $text-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按钮
|
||||
.buttons {
|
||||
padding: $padding * 2;
|
||||
|
||||
.text {
|
||||
text-align: center;
|
||||
line-height: 90rpx;
|
||||
height: 90rpx;
|
||||
margin-bottom: $margin * 2;
|
||||
font-size: $title-size-lg;
|
||||
color: $main-color;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
button {
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
background-color: $main-color;
|
||||
border-radius: $radius-m;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: $title-size;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,112 +1,122 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 提示信息 -->
|
||||
<view class="prompt">请按照顺序记录并确保正确备份助记词</view>
|
||||
<!-- 助记词 -->
|
||||
<ul class="mnemonic">
|
||||
<li v-for="(item, index) in mnemonic" :key="index">{{item}}</li>
|
||||
</ul>
|
||||
<!-- 按钮 -->
|
||||
<view class="buttons">
|
||||
<view class="text">注:助记词是用户账户的唯一标识,不能分享给他人,掌握该助记词即可控制该账户与钱包</view>
|
||||
<!-- <button type="default" @click="goto">验证助记词</button> -->
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { seed } from "@/apis/interfaces/wallet"
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
mnemonic: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
seed({
|
||||
code: this.$Route.query.password
|
||||
}).then(res => {
|
||||
this.mnemonic = res.seed.split(' ')
|
||||
}).catch(err => {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: err.message
|
||||
})
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
goto(){
|
||||
this.$Router.replace({
|
||||
name: 'WalletValidation',
|
||||
params: {
|
||||
seed: this.mnemonic,
|
||||
sign: this.sign
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 提示信息
|
||||
.prompt{
|
||||
color: $text-gray;
|
||||
text-align: center;
|
||||
line-height: 90rpx;
|
||||
font-size: $title-size-m;
|
||||
}
|
||||
// 跳过
|
||||
.skip{
|
||||
padding: $padding * 2;
|
||||
text-align: center;
|
||||
color: $text-gray;
|
||||
navigator{
|
||||
color: $main-color;
|
||||
margin-left: $margin/2;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
// 助记词
|
||||
.mnemonic{
|
||||
margin: $margin $margin * 2;
|
||||
border-radius: $radius-m;
|
||||
box-shadow: 0 0 4rpx 4rpx rgba($color: $text-color, $alpha: .02);
|
||||
background-color: white;
|
||||
padding: $padding;
|
||||
list-style: none;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
li{
|
||||
text-align: center;
|
||||
height: 58rpx;
|
||||
padding: 0 $padding/2;
|
||||
line-height: 58rpx;
|
||||
margin: $margin / 2;
|
||||
color: $text-color;
|
||||
background: rgba($color: $border-color, $alpha: .4);
|
||||
}
|
||||
}
|
||||
// 按钮
|
||||
.buttons{
|
||||
padding: $padding $padding * 2;
|
||||
.text{
|
||||
text-align: center;
|
||||
margin-bottom: $margin * 2;
|
||||
font-size: $title-size-m;
|
||||
color: $text-price;
|
||||
}
|
||||
button{
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
background-color: $main-color;
|
||||
border-radius: $radius-lg;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: $title-size;
|
||||
&::after{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
<template>
|
||||
<view>
|
||||
<!-- 提示信息 -->
|
||||
<view class="prompt">请按照顺序记录并确保正确备份助记词</view>
|
||||
<!-- 助记词 -->
|
||||
<ul class="mnemonic">
|
||||
<li v-for="(item, index) in mnemonic" :key="index">{{item}}</li>
|
||||
</ul>
|
||||
<!-- 按钮 -->
|
||||
<view class="buttons">
|
||||
<view class="text">注:助记词是用户账户的唯一标识,不能分享给他人,掌握该助记词即可控制该账户与钱包</view>
|
||||
<!-- <button type="default" @click="goto">验证助记词</button> -->
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
seed
|
||||
} from "@/apis/interfaces/wallet"
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
mnemonic: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
seed({
|
||||
code: this.$Route.query.password
|
||||
}).then(res => {
|
||||
this.mnemonic = res.seed.split(' ')
|
||||
}).catch(err => {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: err.message
|
||||
})
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
goto() {
|
||||
this.$Router.replace({
|
||||
name: 'WalletValidation',
|
||||
params: {
|
||||
seed: this.mnemonic,
|
||||
sign: this.sign
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 提示信息
|
||||
.prompt {
|
||||
color: $text-gray;
|
||||
text-align: center;
|
||||
line-height: 90rpx;
|
||||
font-size: $title-size-m;
|
||||
}
|
||||
|
||||
// 跳过
|
||||
.skip {
|
||||
padding: $padding * 2;
|
||||
text-align: center;
|
||||
color: $text-gray;
|
||||
|
||||
navigator {
|
||||
color: $main-color;
|
||||
margin-left: $margin/2;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
// 助记词
|
||||
.mnemonic {
|
||||
margin: $margin $margin * 2;
|
||||
border-radius: $radius-m;
|
||||
box-shadow: 0 0 4rpx 4rpx rgba($color: $text-color, $alpha: .02);
|
||||
background-color: white;
|
||||
padding: $padding;
|
||||
list-style: none;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
li {
|
||||
text-align: center;
|
||||
height: 58rpx;
|
||||
padding: 0 $padding/2;
|
||||
line-height: 58rpx;
|
||||
margin: $margin / 2;
|
||||
color: $text-color;
|
||||
background: rgba($color: $border-color, $alpha: .4);
|
||||
}
|
||||
}
|
||||
|
||||
// 按钮
|
||||
.buttons {
|
||||
padding: $padding $padding * 2;
|
||||
|
||||
.text {
|
||||
text-align: center;
|
||||
margin-bottom: $margin * 2;
|
||||
font-size: $title-size-m;
|
||||
color: $text-price;
|
||||
}
|
||||
|
||||
button {
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
background-color: $main-color;
|
||||
border-radius: $radius-lg;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: $title-size;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,119 +1,130 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 私钥 -->
|
||||
<view class="keys">
|
||||
<view class="title">您的ZH托管钱包</view>
|
||||
<view class="key">{{key || '-'}}</view>
|
||||
<view class="copykey" @click="copykey">复制我的私钥</view>
|
||||
</view>
|
||||
<!-- 疑问 -->
|
||||
<view class="doubt" v-if="rules.length > 0">
|
||||
<view class="doubt-item" v-for="(item, index) in rules" :key="index">
|
||||
<view class="title">{{item.title || '-'}}</view>
|
||||
<view class="content">{{item.description || '-'}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 免责说明 -->
|
||||
<!-- <view class="liability">
|
||||
<navigator url="/pages/wallet/cmsWithDraw">免责条款</navigator>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { privatekey, keyrules } from '@/apis/interfaces/wallet'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
key: "",
|
||||
rules: [
|
||||
{
|
||||
title: "什么是托管钱包?",
|
||||
description: "托管钱包顾名思义就是用户把私钥和数字资产委托给其他机构管理,也就是就是通过中心化的方式安全管理并保存资产,本质上是与区块链所追求的去中心化相背离的。"
|
||||
},
|
||||
{
|
||||
title: "什么是钱包私钥?",
|
||||
description: "作为管理和使用加密货币最关键的东西,私钥对所有数字货币用户而言具有所有权,拥有私钥才能支配相应的加密资产。"
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
privatekey(this.$Route.query.password).then(res => {
|
||||
this.key = res.private_key
|
||||
}).catch(err => {
|
||||
uni.showToast({
|
||||
title: err.message,
|
||||
icon : 'none'
|
||||
})
|
||||
})
|
||||
},
|
||||
methods:{
|
||||
copykey(){
|
||||
uni.setClipboardData({
|
||||
data: this.key
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.keys{
|
||||
margin: $margin * 2;
|
||||
background: white;
|
||||
padding: $padding * 2;
|
||||
box-shadow: 0 0 4rpx 4rpx rgba($color: #000000, $alpha: .02);
|
||||
border-radius: $radius;
|
||||
.title{
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: $title-size + 4;
|
||||
color: $text-color;
|
||||
}
|
||||
.key{
|
||||
padding: $padding * 2 0;
|
||||
text-align: center;
|
||||
color: $main-color;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.copykey{
|
||||
background-color: $main-color;
|
||||
color: white;
|
||||
height: 95rpx;
|
||||
line-height: 95rpx;
|
||||
text-align: center;
|
||||
font-size: $title-size;
|
||||
border-radius: $radius-m;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.doubt{
|
||||
margin: $margin $margin * 2;
|
||||
.doubt-item{
|
||||
padding: $padding 0;
|
||||
.title{
|
||||
font-weight: bold;
|
||||
color: $text-color;
|
||||
line-height: 50rpx;
|
||||
font-size: $title-size + 2;
|
||||
}
|
||||
.content{
|
||||
color: $text-gray;
|
||||
font-size: $title-size-m;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.liability{
|
||||
text-align: center;
|
||||
color: $text-gray;
|
||||
@extend .ios-bottom;
|
||||
navigator{
|
||||
font-size: $title-size-sm;
|
||||
display: inline-block;
|
||||
line-height: 90rpx;
|
||||
padding: 0 ($padding * 2);
|
||||
}
|
||||
}
|
||||
<template>
|
||||
<view>
|
||||
<!-- 私钥 -->
|
||||
<view class="keys">
|
||||
<view class="title">您的ZH托管钱包</view>
|
||||
<view class="key">{{key || '-'}}</view>
|
||||
<view class="copykey" @click="copykey">复制我的私钥</view>
|
||||
</view>
|
||||
<!-- 疑问 -->
|
||||
<view class="doubt" v-if="rules.length > 0">
|
||||
<view class="doubt-item" v-for="(item, index) in rules" :key="index">
|
||||
<view class="title">{{item.title || '-'}}</view>
|
||||
<view class="content">{{item.description || '-'}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 免责说明 -->
|
||||
<!-- <view class="liability">
|
||||
<navigator url="/pages/wallet/cmsWithDraw">免责条款</navigator>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
privatekey,
|
||||
keyrules
|
||||
} from '@/apis/interfaces/wallet'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
key: "",
|
||||
rules: [{
|
||||
title: "什么是托管钱包?",
|
||||
description: "托管钱包顾名思义就是用户把私钥和数字资产委托给其他机构管理,也就是就是通过中心化的方式安全管理并保存资产,本质上是与区块链所追求的去中心化相背离的。"
|
||||
},
|
||||
{
|
||||
title: "什么是钱包私钥?",
|
||||
description: "作为管理和使用加密货币最关键的东西,私钥对所有数字货币用户而言具有所有权,拥有私钥才能支配相应的加密资产。"
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
privatekey(this.$Route.query.password).then(res => {
|
||||
this.key = res.private_key
|
||||
}).catch(err => {
|
||||
uni.showToast({
|
||||
title: err.message,
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
copykey() {
|
||||
uni.setClipboardData({
|
||||
data: this.key
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.keys {
|
||||
margin: $margin * 2;
|
||||
background: white;
|
||||
padding: $padding * 2;
|
||||
box-shadow: 0 0 4rpx 4rpx rgba($color: #000000, $alpha: .02);
|
||||
border-radius: $radius;
|
||||
|
||||
.title {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: $title-size + 4;
|
||||
color: $text-color;
|
||||
}
|
||||
|
||||
.key {
|
||||
padding: $padding * 2 0;
|
||||
text-align: center;
|
||||
color: $main-color;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.copykey {
|
||||
background-color: $main-color;
|
||||
color: white;
|
||||
height: 95rpx;
|
||||
line-height: 95rpx;
|
||||
text-align: center;
|
||||
font-size: $title-size;
|
||||
border-radius: $radius-m;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.doubt {
|
||||
margin: $margin $margin * 2;
|
||||
|
||||
.doubt-item {
|
||||
padding: $padding 0;
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
color: $text-color;
|
||||
line-height: 50rpx;
|
||||
font-size: $title-size + 2;
|
||||
}
|
||||
|
||||
.content {
|
||||
color: $text-gray;
|
||||
font-size: $title-size-m;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.liability {
|
||||
text-align: center;
|
||||
color: $text-gray;
|
||||
@extend .ios-bottom;
|
||||
|
||||
navigator {
|
||||
font-size: $title-size-sm;
|
||||
display: inline-block;
|
||||
line-height: 90rpx;
|
||||
padding: 0 ($padding * 2);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,359 +1,386 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="propery">
|
||||
<view class="propery-content">
|
||||
<view class="currency">钱包余额</view>
|
||||
<view class="balance">{{ balance.balance || '0' }}</view>
|
||||
<view class="frozen">{{ balance.frozen || '0' }} 冻结中</view>
|
||||
<view class="balance-flex">
|
||||
<view class="balance-flex-item" @click="showAddress">区块链地址</view>
|
||||
<view class="balance-flex-item" @click="showPrivatekey('privatekey')">我的私钥</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 账户记录 -->
|
||||
<view class="record">
|
||||
<view class="record-tabs">
|
||||
<view class="tabs-item" :class="logsType === 0 ? 'show': ''" @click="onLogsType(0)">全部</view>
|
||||
<view class="tabs-item" :class="logsType === 2 ? 'show': ''" @click="onLogsType(2)">收入</view>
|
||||
<view class="tabs-item" :class="logsType === 1 ? 'show': ''" @click="onLogsType(1)">支出</view>
|
||||
</view>
|
||||
<record :list="logs" />
|
||||
<!-- ios安全距离 -->
|
||||
<view class="ios-bottom"></view>
|
||||
</view>
|
||||
<!-- 钱包密码 -->
|
||||
<u-popup :show="passwordShow" @close="resetPassword" mode="center" round="10" borderRadius="10">
|
||||
<view class="validationPassword">
|
||||
<view class="from">
|
||||
<view class="title">验证钱包密码</view>
|
||||
<view class="inputs">
|
||||
<text v-for="item in password.length" :key="item">•</text>
|
||||
<text class="flicker-animation">|</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
<!-- key -->
|
||||
<u-keyboard
|
||||
mode="number"
|
||||
random
|
||||
dotDisabled
|
||||
:overlay="false"
|
||||
:show="passwordShow"
|
||||
confirmText="验证"
|
||||
@change="keyValChange"
|
||||
@backspace="keyValBackspace"
|
||||
@confirm="payPassword('confirm', passwordPages)"
|
||||
@cancel="passwordShow = false"
|
||||
></u-keyboard>
|
||||
</view>
|
||||
<view>
|
||||
<view class="propery">
|
||||
<view class="propery-content">
|
||||
<view class="currency">钱包余额</view>
|
||||
<view class="balance">{{ balance.balance || '0' }}</view>
|
||||
<view class="frozen">{{ balance.frozen || '0' }} 冻结中</view>
|
||||
<view class="balance-flex">
|
||||
<view class="balance-flex-item" @click="showAddress">区块链地址</view>
|
||||
<view class="balance-flex-item" @click="showPrivatekey('privatekey')">我的私钥</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 账户记录 -->
|
||||
<view class="record">
|
||||
<view class="record-tabs">
|
||||
<view class="tabs-item" :class="logsType === 0 ? 'show': ''" @click="onLogsType(0)">全部</view>
|
||||
<view class="tabs-item" :class="logsType === 2 ? 'show': ''" @click="onLogsType(2)">收入</view>
|
||||
<view class="tabs-item" :class="logsType === 1 ? 'show': ''" @click="onLogsType(1)">支出</view>
|
||||
</view>
|
||||
<record :list="logs" />
|
||||
<!-- ios安全距离 -->
|
||||
<view class="ios-bottom"></view>
|
||||
</view>
|
||||
<!-- 钱包密码 -->
|
||||
<u-popup :show="passwordShow" @close="resetPassword" mode="center" round="10" borderRadius="10">
|
||||
<view class="validationPassword">
|
||||
<view class="from">
|
||||
<view class="title">验证钱包密码</view>
|
||||
<view class="inputs">
|
||||
<text v-for="item in password.length" :key="item">•</text>
|
||||
<text class="flicker-animation">|</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
<!-- key -->
|
||||
<u-keyboard mode="number" random dotDisabled :overlay="false" :show="passwordShow" confirmText="验证"
|
||||
@change="keyValChange" @backspace="keyValBackspace" @confirm="payPassword('confirm', passwordPages)"
|
||||
@cancel="passwordShow = false"></u-keyboard>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import record from '@/components/property/record'
|
||||
import { sum, logs, securityCheck } from '@/apis/interfaces/wallet'
|
||||
export default {
|
||||
components: {
|
||||
record
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
balance : {},
|
||||
logs : [],
|
||||
logsType : 0,
|
||||
password : '',
|
||||
passwordShow : false,
|
||||
passwordPages: ''
|
||||
};
|
||||
},
|
||||
onShow() {
|
||||
Promise.all([
|
||||
sum(),
|
||||
logs()
|
||||
]).then(res => {
|
||||
this.balance = res[0]
|
||||
this.logs = res[1]
|
||||
}).catch(err => {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: err.message
|
||||
})
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
// 键盘输入
|
||||
keyValChange(e){
|
||||
if(this.password.length >= 6) return
|
||||
this.password += e
|
||||
},
|
||||
// 键盘删除
|
||||
keyValBackspace(e){
|
||||
if(this.password.length) this.password = this.password.substr(0, this.password.length - 1)
|
||||
},
|
||||
// 弹出私钥
|
||||
showPrivatekey(pages){
|
||||
this.passwordShow = true
|
||||
this.passwordPages = pages
|
||||
},
|
||||
// 重置密码
|
||||
resetPassword(){
|
||||
this.passwordShow = false
|
||||
this.password = ''
|
||||
},
|
||||
// 验证私钥
|
||||
payPassword(type){
|
||||
if(type === 'confirm'){
|
||||
if(this.password === '') {
|
||||
uni.showToast({
|
||||
title: '请输入安全密码',
|
||||
icon : 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
securityCheck(this.password).then(res => {
|
||||
switch (this.passwordPages){
|
||||
case 'privatekey':
|
||||
this.$Router.push({name:'WalletPrivatekey', params: {password: this.password}})
|
||||
break;
|
||||
case 'ResetPassword':
|
||||
this.$Router.push({name:'ResetPassword', params: {password: this.password}})
|
||||
break;
|
||||
case 'WalletMnemonic':
|
||||
this.$Router.push({name:'WalletMnemonic', params: {password: this.password}})
|
||||
break;
|
||||
}
|
||||
this.resetPassword()
|
||||
}).catch(err => {
|
||||
uni.showToast({
|
||||
title: err.message,
|
||||
icon: 'none',
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
this.$refs.showPassword.close()
|
||||
},
|
||||
// 交易记录
|
||||
onLogsType(index) {
|
||||
if (this.logsType === index) return
|
||||
this.logsType = index
|
||||
this.logs = []
|
||||
logs({
|
||||
flag: this.logsType
|
||||
}).then(res => {
|
||||
this.logs = res
|
||||
})
|
||||
},
|
||||
// 区块地址
|
||||
showAddress() {
|
||||
uni.showModal({
|
||||
title: '我的区块链地址',
|
||||
content: this.balance.address,
|
||||
cancelText: '复制',
|
||||
cancelColor: '#009B69',
|
||||
success: (res) => {
|
||||
if (res.cancel) {
|
||||
uni.setClipboardData({
|
||||
data: this.balance.address
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
onNavigationBarButtonTap(e) {
|
||||
if (e.index === 0) {
|
||||
uni.showActionSheet({
|
||||
itemList: ['导出助记词', '修改密码'],
|
||||
success: (res) => {
|
||||
switch (res.tapIndex) {
|
||||
case 0:
|
||||
this.showPrivatekey('WalletMnemonic')
|
||||
break;
|
||||
case 1:
|
||||
this.showPrivatekey('ResetPassword')
|
||||
break;
|
||||
}
|
||||
uni.hideLoading()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.flicker-animation{
|
||||
animation: flicker .8s infinite;
|
||||
}
|
||||
@keyframes flicker{
|
||||
0%{opacity: 0;}
|
||||
100{opacity: 1;}
|
||||
}
|
||||
<script>
|
||||
import record from '@/components/property/record'
|
||||
import {
|
||||
sum,
|
||||
logs,
|
||||
securityCheck
|
||||
} from '@/apis/interfaces/wallet'
|
||||
export default {
|
||||
components: {
|
||||
record
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
balance: {},
|
||||
logs: [],
|
||||
logsType: 0,
|
||||
password: '',
|
||||
passwordShow: false,
|
||||
passwordPages: ''
|
||||
};
|
||||
},
|
||||
onShow() {
|
||||
Promise.all([
|
||||
sum(),
|
||||
logs()
|
||||
]).then(res => {
|
||||
this.balance = res[0]
|
||||
this.logs = res[1]
|
||||
}).catch(err => {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: err.message
|
||||
})
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
// 键盘输入
|
||||
keyValChange(e) {
|
||||
if (this.password.length >= 6) return
|
||||
this.password += e
|
||||
},
|
||||
// 键盘删除
|
||||
keyValBackspace(e) {
|
||||
if (this.password.length) this.password = this.password.substr(0, this.password.length - 1)
|
||||
},
|
||||
// 弹出私钥
|
||||
showPrivatekey(pages) {
|
||||
this.passwordShow = true
|
||||
this.passwordPages = pages
|
||||
},
|
||||
// 重置密码
|
||||
resetPassword() {
|
||||
this.passwordShow = false
|
||||
this.password = ''
|
||||
},
|
||||
// 验证私钥
|
||||
payPassword(type) {
|
||||
if (type === 'confirm') {
|
||||
if (this.password === '') {
|
||||
uni.showToast({
|
||||
title: '请输入安全密码',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
securityCheck(this.password).then(res => {
|
||||
switch (this.passwordPages) {
|
||||
case 'privatekey':
|
||||
this.$Router.push({
|
||||
name: 'WalletPrivatekey',
|
||||
params: {
|
||||
password: this.password
|
||||
}
|
||||
})
|
||||
break;
|
||||
case 'ResetPassword':
|
||||
this.$Router.push({
|
||||
name: 'ResetPassword',
|
||||
params: {
|
||||
password: this.password
|
||||
}
|
||||
})
|
||||
break;
|
||||
case 'WalletMnemonic':
|
||||
this.$Router.push({
|
||||
name: 'WalletMnemonic',
|
||||
params: {
|
||||
password: this.password
|
||||
}
|
||||
})
|
||||
break;
|
||||
}
|
||||
this.resetPassword()
|
||||
}).catch(err => {
|
||||
uni.showToast({
|
||||
title: err.message,
|
||||
icon: 'none',
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
this.$refs.showPassword.close()
|
||||
},
|
||||
// 交易记录
|
||||
onLogsType(index) {
|
||||
if (this.logsType === index) return
|
||||
this.logsType = index
|
||||
this.logs = []
|
||||
logs({
|
||||
flag: this.logsType
|
||||
}).then(res => {
|
||||
this.logs = res
|
||||
})
|
||||
},
|
||||
// 区块地址
|
||||
showAddress() {
|
||||
uni.showModal({
|
||||
title: '我的区块链地址',
|
||||
content: this.balance.address,
|
||||
cancelText: '复制',
|
||||
cancelColor: '#009B69',
|
||||
success: (res) => {
|
||||
if (res.cancel) {
|
||||
uni.setClipboardData({
|
||||
data: this.balance.address
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
onNavigationBarButtonTap(e) {
|
||||
if (e.index === 0) {
|
||||
uni.showActionSheet({
|
||||
itemList: ['导出助记词', '修改密码'],
|
||||
success: (res) => {
|
||||
switch (res.tapIndex) {
|
||||
case 0:
|
||||
this.showPrivatekey('WalletMnemonic')
|
||||
break;
|
||||
case 1:
|
||||
this.showPrivatekey('ResetPassword')
|
||||
break;
|
||||
}
|
||||
uni.hideLoading()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.flicker-animation {
|
||||
animation: flicker .8s infinite;
|
||||
}
|
||||
|
||||
@keyframes flicker {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100 {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 验证密码弹出层
|
||||
.validationPassword{
|
||||
width: 80vw;
|
||||
.from{
|
||||
padding: $padding*2;
|
||||
text-align: center;
|
||||
.title{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: bold;
|
||||
font-size: $title-size;
|
||||
padding-bottom: $padding;
|
||||
}
|
||||
// input{
|
||||
// background: $window-color;
|
||||
// height: 90rpx;
|
||||
// left: 90rpx;
|
||||
// font-size: $title-size-lg;
|
||||
// border-radius: 45rpx;
|
||||
// }
|
||||
.inputs {
|
||||
background-color: $window-color;
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
border-radius: 45rpx;
|
||||
font-size: $title-size-lg;
|
||||
text-align: center;
|
||||
text{
|
||||
padding: 0 10rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.placeholder{
|
||||
color: $text-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
.buttons{
|
||||
text-align: center;
|
||||
padding: 0 $padding*2;
|
||||
.button{
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
margin-bottom: $margin;
|
||||
&.cancel{
|
||||
color: $text-gray;
|
||||
}
|
||||
&.confirm{
|
||||
color: white;
|
||||
background: $main-color;
|
||||
border-radius: 45rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
//
|
||||
}
|
||||
// 账户
|
||||
.propery {
|
||||
position: relative;
|
||||
padding-top: var(--status-bar-height);
|
||||
background-image: linear-gradient(to right, $main-color, #22aa98);
|
||||
<style lang="scss" scoped>
|
||||
// 验证密码弹出层
|
||||
.validationPassword {
|
||||
width: 80vw;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
content: " ";
|
||||
// background-image: url(@/static/background/wallet-back.png);
|
||||
background-size: 100%;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.from {
|
||||
padding: $padding*2;
|
||||
text-align: center;
|
||||
|
||||
.propery-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding: $padding * 5 $padding * 2;
|
||||
text-align: center;
|
||||
.title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: bold;
|
||||
font-size: $title-size;
|
||||
padding-bottom: $padding;
|
||||
}
|
||||
|
||||
.currency {
|
||||
font-size: $title-size-m;
|
||||
color: rgba($color: white, $alpha: .8);
|
||||
}
|
||||
// input{
|
||||
// background: $window-color;
|
||||
// height: 90rpx;
|
||||
// left: 90rpx;
|
||||
// font-size: $title-size-lg;
|
||||
// border-radius: 45rpx;
|
||||
// }
|
||||
.inputs {
|
||||
background-color: $window-color;
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
border-radius: 45rpx;
|
||||
font-size: $title-size-lg;
|
||||
text-align: center;
|
||||
|
||||
.balance {
|
||||
font-size: $title-size * 2;
|
||||
padding: ($padding / 2) 0;
|
||||
color: white;
|
||||
}
|
||||
text {
|
||||
padding: 0 10rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.frozen {
|
||||
background: rgba($color: #000000, $alpha: .1);
|
||||
color: rgba($color: white, $alpha: .7);
|
||||
display: inline-block;
|
||||
padding: 0 $padding;
|
||||
font-size: $title-size-m;
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
border-radius: $radius-m;
|
||||
border: solid 1rpx rgba($color: white, $alpha: .4)
|
||||
}
|
||||
.placeholder {
|
||||
color: $text-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.balance-flex {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: $margin * 3;
|
||||
.buttons {
|
||||
text-align: center;
|
||||
padding: 0 $padding*2;
|
||||
|
||||
.balance-flex-item {
|
||||
background-color: white;
|
||||
width: 200rpx;
|
||||
height: 75rpx;
|
||||
line-height: 75rpx;
|
||||
color: $main-color;
|
||||
margin: 0 $margin;
|
||||
border-radius: $radius-m;
|
||||
font-size: $title-size-lg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.button {
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
margin-bottom: $margin;
|
||||
|
||||
// 记录
|
||||
.record {
|
||||
background-color: white;
|
||||
border-radius: $radius $radius 0 0;
|
||||
padding: $padding ($padding * 2);
|
||||
margin-top: -$margin;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
&.cancel {
|
||||
color: $text-gray;
|
||||
}
|
||||
|
||||
.record-tabs {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
font-weight: bold;
|
||||
font-size: $title-size;
|
||||
color: $text-gray;
|
||||
line-height: 70rpx;
|
||||
margin-bottom: $margin;
|
||||
&.confirm {
|
||||
color: white;
|
||||
background: $main-color;
|
||||
border-radius: 45rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tabs-item {
|
||||
position: relative;
|
||||
padding: 0 $padding;
|
||||
//
|
||||
//
|
||||
}
|
||||
|
||||
&.show {
|
||||
color: $main-color;
|
||||
// 账户
|
||||
.propery {
|
||||
position: relative;
|
||||
padding-top: var(--status-bar-height);
|
||||
background-image: linear-gradient(to right, $main-color, #22aa98);
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: $padding;
|
||||
right: $padding;
|
||||
height: 4rpx;
|
||||
content: " ";
|
||||
background-color: $main-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&::before {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
content: " ";
|
||||
// background-image: url(@/static/background/wallet-back.png);
|
||||
background-size: 100%;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.propery-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding: $padding * 5 $padding * 2;
|
||||
text-align: center;
|
||||
|
||||
.currency {
|
||||
font-size: $title-size-m;
|
||||
color: rgba($color: white, $alpha: .8);
|
||||
}
|
||||
|
||||
.balance {
|
||||
font-size: $title-size * 2;
|
||||
padding: ($padding / 2) 0;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.frozen {
|
||||
background: rgba($color: #000000, $alpha: .1);
|
||||
color: rgba($color: white, $alpha: .7);
|
||||
display: inline-block;
|
||||
padding: 0 $padding;
|
||||
font-size: $title-size-m;
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
border-radius: $radius-m;
|
||||
border: solid 1rpx rgba($color: white, $alpha: .4)
|
||||
}
|
||||
|
||||
.balance-flex {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: $margin * 3;
|
||||
|
||||
.balance-flex-item {
|
||||
background-color: white;
|
||||
width: 200rpx;
|
||||
height: 75rpx;
|
||||
line-height: 75rpx;
|
||||
color: $main-color;
|
||||
margin: 0 $margin;
|
||||
border-radius: $radius-m;
|
||||
font-size: $title-size-lg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 记录
|
||||
.record {
|
||||
background-color: white;
|
||||
border-radius: $radius $radius 0 0;
|
||||
padding: $padding ($padding * 2);
|
||||
margin-top: -$margin;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
|
||||
.record-tabs {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
font-weight: bold;
|
||||
font-size: $title-size;
|
||||
color: $text-gray;
|
||||
line-height: 70rpx;
|
||||
margin-bottom: $margin;
|
||||
|
||||
.tabs-item {
|
||||
position: relative;
|
||||
padding: 0 $padding;
|
||||
|
||||
&.show {
|
||||
color: $main-color;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: $padding;
|
||||
right: $padding;
|
||||
height: 4rpx;
|
||||
content: " ";
|
||||
background-color: $main-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,198 +1,203 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 设置钱包密码 -->
|
||||
<view class="password">
|
||||
<view class="prompt">请设置6位数字密码,建议不要使用连续的数字</view>
|
||||
<view class="group">
|
||||
<view class="inputs" @click="onShowKet('password')">
|
||||
<block v-if="password.length > 0">
|
||||
<text v-for="item in password.length" :key="item">•</text>
|
||||
</block>
|
||||
<block v-if="keyShow && valKye === 'password'">
|
||||
<text class="flicker-animation">|</text>
|
||||
</block>
|
||||
<block v-else>
|
||||
<text v-if="password.length === 0" class="placeholder">请设置密码</text>
|
||||
</block>
|
||||
</view>
|
||||
<view class="inputs" :class="{'hide': verify === ''}" @click="onShowKet('verify')">
|
||||
<block v-if="verify.length > 0">
|
||||
<text v-for="item in verify.length" :key="item">•</text>
|
||||
</block>
|
||||
<block v-if="keyShow && valKye === 'verify'">
|
||||
<text class="flicker-animation">|</text>
|
||||
</block>
|
||||
<block v-else>
|
||||
<text v-if="verify.length === 0" class="placeholder">请确认密码</text>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- key键盘 -->
|
||||
<u-keyboard
|
||||
mode="number"
|
||||
random
|
||||
dotDisabled
|
||||
:overlay="false"
|
||||
:show="keyShow"
|
||||
:showCancel="false"
|
||||
@change="keyValChange"
|
||||
@backspace="keyValBackspace"
|
||||
@confirm="keyShow = false"
|
||||
></u-keyboard>
|
||||
<!-- 按钮 -->
|
||||
<view class="buttons">
|
||||
<button type="default" form-type="submit" @click="createWallet">确认修改</button>
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<!-- 设置钱包密码 -->
|
||||
<view class="password">
|
||||
<view class="prompt">请设置6位数字密码,建议不要使用连续的数字</view>
|
||||
<view class="group">
|
||||
<view class="inputs" @click="onShowKet('password')">
|
||||
<block v-if="password.length > 0">
|
||||
<text v-for="item in password.length" :key="item">•</text>
|
||||
</block>
|
||||
<block v-if="keyShow && valKye === 'password'">
|
||||
<text class="flicker-animation">|</text>
|
||||
</block>
|
||||
<block v-else>
|
||||
<text v-if="password.length === 0" class="placeholder">请设置密码</text>
|
||||
</block>
|
||||
</view>
|
||||
<view class="inputs" :class="{'hide': verify === ''}" @click="onShowKet('verify')">
|
||||
<block v-if="verify.length > 0">
|
||||
<text v-for="item in verify.length" :key="item">•</text>
|
||||
</block>
|
||||
<block v-if="keyShow && valKye === 'verify'">
|
||||
<text class="flicker-animation">|</text>
|
||||
</block>
|
||||
<block v-else>
|
||||
<text v-if="verify.length === 0" class="placeholder">请确认密码</text>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- key键盘 -->
|
||||
<u-keyboard mode="number" random dotDisabled :overlay="false" :show="keyShow" :showCancel="false"
|
||||
@change="keyValChange" @backspace="keyValBackspace" @confirm="keyShow = false"></u-keyboard>
|
||||
<!-- 按钮 -->
|
||||
<view class="buttons">
|
||||
<button type="default" form-type="submit" @click="createWallet">确认修改</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { securityReset } from '@/apis/interfaces/wallet'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
password: '',
|
||||
verify: '',
|
||||
oldPassword: '',
|
||||
|
||||
valKye : '',
|
||||
keyShow : false
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.oldPassword = this.$Route.query.password
|
||||
},
|
||||
methods: {
|
||||
// 唤起key
|
||||
onShowKet(key){
|
||||
this.valKye = key
|
||||
this.keyShow = true
|
||||
},
|
||||
// 键盘输入
|
||||
keyValChange(e){
|
||||
if(this[this.valKye].length >= 6) return
|
||||
this[this.valKye] += e
|
||||
},
|
||||
// 键盘删除
|
||||
keyValBackspace(e){
|
||||
if(this[this.valKye].length) this[this.valKye] = this[this.valKye].substr(0, this[this.valKye].length - 1)
|
||||
},
|
||||
// 修改密码
|
||||
createWallet() {
|
||||
if (this.password === '' || this.verify === '') {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '请设置密码'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (this.password !== this.verify) {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '两次输入密码不一致'
|
||||
})
|
||||
return
|
||||
}
|
||||
securityReset({
|
||||
new_code: this.password,
|
||||
code: this.oldPassword
|
||||
}).then(res => {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '密码已重置',
|
||||
showCancel:false,
|
||||
success: res=> {
|
||||
uni.navigateBack()
|
||||
}
|
||||
})
|
||||
}).catch(err => {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: err.message
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style>
|
||||
.flicker-animation{
|
||||
animation: flicker .8s infinite;
|
||||
}
|
||||
@keyframes flicker{
|
||||
0%{opacity: 0;}
|
||||
100{opacity: 1;}
|
||||
}
|
||||
import {
|
||||
securityReset
|
||||
} from '@/apis/interfaces/wallet'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
password: '',
|
||||
verify: '',
|
||||
oldPassword: '',
|
||||
valKye: '',
|
||||
keyShow: false
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.oldPassword = this.$Route.query.password
|
||||
},
|
||||
methods: {
|
||||
// 唤起key
|
||||
onShowKet(key) {
|
||||
this.valKye = key
|
||||
this.keyShow = true
|
||||
},
|
||||
// 键盘输入
|
||||
keyValChange(e) {
|
||||
if (this[this.valKye].length >= 6) return
|
||||
this[this.valKye] += e
|
||||
},
|
||||
// 键盘删除
|
||||
keyValBackspace(e) {
|
||||
if (this[this.valKye].length) this[this.valKye] = this[this.valKye].substr(0, this[this.valKye].length -
|
||||
1)
|
||||
},
|
||||
// 修改密码
|
||||
createWallet() {
|
||||
if (this.password === '' || this.verify === '') {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '请设置密码'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (this.password !== this.verify) {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '两次输入密码不一致'
|
||||
})
|
||||
return
|
||||
}
|
||||
securityReset({
|
||||
new_code: this.password,
|
||||
code: this.oldPassword
|
||||
}).then(res => {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '密码已重置',
|
||||
showCancel: false,
|
||||
success: res => {
|
||||
uni.navigateBack()
|
||||
}
|
||||
})
|
||||
}).catch(err => {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: err.message
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style>
|
||||
.flicker-animation {
|
||||
animation: flicker .8s infinite;
|
||||
}
|
||||
|
||||
@keyframes flicker {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100 {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 副标题
|
||||
.sub-title {
|
||||
color: $text-gray;
|
||||
text-align: center;
|
||||
margin: $margin * 2 $margin;
|
||||
font-size: $title-size-m;
|
||||
}
|
||||
|
||||
// 设置密码
|
||||
.password {
|
||||
padding: 0 $padding * 2;
|
||||
.prompt {
|
||||
margin-top: $margin * 2;
|
||||
font-size: $title-size-m;
|
||||
color: $main-color;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.group {
|
||||
padding-top: $padding;
|
||||
.inputs {
|
||||
padding: 10rpx $padding + 10;
|
||||
margin-top: $margin;
|
||||
border-radius: $radius-m;
|
||||
background-color: $window-color;
|
||||
height: 70rpx;
|
||||
line-height: 70rpx;
|
||||
font-size: $title-size-lg;
|
||||
text-align: center;
|
||||
text{
|
||||
padding: 0 10rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.placeholder{
|
||||
color: $text-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按钮
|
||||
.buttons {
|
||||
padding: $padding * 2;
|
||||
.text {
|
||||
text-align: center;
|
||||
line-height: 90rpx;
|
||||
height: 90rpx;
|
||||
margin-bottom: $margin * 2;
|
||||
font-size: $title-size-lg;
|
||||
color: $main-color;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
button {
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
background-color: $main-color;
|
||||
border-radius: $radius-m;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: $title-size;
|
||||
&::after{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
<style lang="scss" scoped>
|
||||
// 副标题
|
||||
.sub-title {
|
||||
color: $text-gray;
|
||||
text-align: center;
|
||||
margin: $margin * 2 $margin;
|
||||
font-size: $title-size-m;
|
||||
}
|
||||
|
||||
// 设置密码
|
||||
.password {
|
||||
padding: 0 $padding * 2;
|
||||
|
||||
.prompt {
|
||||
margin-top: $margin * 2;
|
||||
font-size: $title-size-m;
|
||||
color: $main-color;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.group {
|
||||
padding-top: $padding;
|
||||
|
||||
.inputs {
|
||||
padding: 10rpx $padding + 10;
|
||||
margin-top: $margin;
|
||||
border-radius: $radius-m;
|
||||
background-color: $window-color;
|
||||
height: 70rpx;
|
||||
line-height: 70rpx;
|
||||
font-size: $title-size-lg;
|
||||
text-align: center;
|
||||
|
||||
text {
|
||||
padding: 0 10rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: $text-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按钮
|
||||
.buttons {
|
||||
padding: $padding * 2;
|
||||
|
||||
.text {
|
||||
text-align: center;
|
||||
line-height: 90rpx;
|
||||
height: 90rpx;
|
||||
margin-bottom: $margin * 2;
|
||||
font-size: $title-size-lg;
|
||||
color: $main-color;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
button {
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
background-color: $main-color;
|
||||
border-radius: $radius-m;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: $title-size;
|
||||
|
||||
&::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,170 +1,178 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 提示信息 -->
|
||||
<view class="prompt">
|
||||
验证您的钱包助记词
|
||||
</view>
|
||||
<!-- 助记词 -->
|
||||
<view class="mnemonic">
|
||||
<view
|
||||
class="item"
|
||||
v-for="(item, index) in validation"
|
||||
:key="index"
|
||||
:class="item === null ? 'hide': ''"
|
||||
@click="onKeys('removeKey', index)"
|
||||
>{{ item }}</view>
|
||||
</view>
|
||||
<!-- 选择助记词 -->
|
||||
<block v-if="mnemonic.length > 0">
|
||||
<view class="mnemonic-title">
|
||||
按顺序填写助记词
|
||||
</view>
|
||||
<view class="mnemonic-select">
|
||||
<view class="item" v-for="(item, index) in mnemonic" :key="index" @click="onKeys('addKey', index)">{{ item }}</view>
|
||||
</view>
|
||||
</block>
|
||||
<!-- 按钮 -->
|
||||
<view class="buttons">
|
||||
<button type="default" @click="verifyMnemonic">验证</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { hash } from "../../apis/interfaces/wallet"
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
validation : new Array(12).fill(null), // 验证key
|
||||
mnemonic : [], // 助记词key
|
||||
sign : '', // 助记词校验签名
|
||||
seedString : '', // 助记词原词
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let seed = this.$Route.query.seed.split(',')
|
||||
seed.sort(() => {
|
||||
return Math.random() - .5
|
||||
});
|
||||
console.log(seed)
|
||||
// this.mnemonic = seed
|
||||
// this.sign = this.$Route.query.sign
|
||||
// this.seedString = this.$Route.query.seed
|
||||
},
|
||||
methods: {
|
||||
// 填写助记词
|
||||
onKeys(type, index){
|
||||
if(type === 'addKey') {
|
||||
this.$set(this.validation, this.validation.findIndex(val => val === null), this.mnemonic[index])
|
||||
this.$delete(this.mnemonic, index)
|
||||
return
|
||||
}
|
||||
if(type === 'removeKey' && this.validation[index] !== null) {
|
||||
this.mnemonic.push(this.validation[index])
|
||||
this.$delete(this.validation, index)
|
||||
this.validation.push(null)
|
||||
}
|
||||
},
|
||||
// 验证助记词
|
||||
verifyMnemonic(){
|
||||
if(this.validation.findIndex(val => val === null) > -1){
|
||||
uni.showToast({
|
||||
title: '请完整填写助记词',
|
||||
icon : 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
let seed = this.validation.toString().replace(/,/g, ',')
|
||||
if (this.seedString !== seed) {
|
||||
uni.showToast({
|
||||
title: '验证失败,请确认您的助记词',
|
||||
icon : 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
uni.redirectTo({
|
||||
url: './create'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 提示信息
|
||||
.prompt{
|
||||
color: $text-gray;
|
||||
text-align: center;
|
||||
line-height: 90rpx;
|
||||
font-size: $title-size-m;
|
||||
}
|
||||
// 选择助记词
|
||||
.mnemonic-title{
|
||||
padding-top: $padding * 2;
|
||||
margin: 0 $margin * 2;
|
||||
font-size: $title-size-m;
|
||||
color: $main-color;
|
||||
}
|
||||
.mnemonic-select{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: $padding $padding + $padding / 2;
|
||||
.item{
|
||||
background-color: white;
|
||||
line-height: 68rpx;
|
||||
height: 68rpx;
|
||||
width: 68rpx;
|
||||
text-align: center;
|
||||
margin: $margin / 2;
|
||||
border-radius: $radius-m;
|
||||
box-shadow: 0 0 4rpx 4rpx rgba($color: $text-color, $alpha: .02);
|
||||
}
|
||||
}
|
||||
// 助记词
|
||||
.mnemonic{
|
||||
margin: $margin ($margin * 2);
|
||||
border-radius: $radius-m;
|
||||
box-shadow: 0 0 4rpx 4rpx rgba($color: $text-color, $alpha: .02);
|
||||
background-color: white;
|
||||
padding: $padding;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
.item{
|
||||
background: rgba($color: $border-color, $alpha: .4);
|
||||
min-width: 58rpx;
|
||||
height: 58rpx;
|
||||
line-height: 58rpx;
|
||||
text-align: center;
|
||||
color: $text-color;
|
||||
margin: $margin / 2;
|
||||
&.hide{
|
||||
border:dashed 1px $border-color;
|
||||
box-sizing: border-box;
|
||||
background-color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 按钮
|
||||
.buttons{
|
||||
padding: $padding $padding * 2;
|
||||
.text{
|
||||
text-align: center;
|
||||
margin-bottom: $margin * 2;
|
||||
font-size: $title-size-lg;
|
||||
color: $text-price;
|
||||
}
|
||||
button{
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
background-color: $main-color;
|
||||
border-radius: $radius-lg;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: $title-size;
|
||||
&[disabled]{
|
||||
background: rgba($color: $main-color, $alpha: .8);
|
||||
}
|
||||
}
|
||||
}
|
||||
<template>
|
||||
<view>
|
||||
<!-- 提示信息 -->
|
||||
<view class="prompt">
|
||||
验证您的钱包助记词
|
||||
</view>
|
||||
<!-- 助记词 -->
|
||||
<view class="mnemonic">
|
||||
<view class="item" v-for="(item, index) in validation" :key="index" :class="item === null ? 'hide': ''"
|
||||
@click="onKeys('removeKey', index)">{{ item }}</view>
|
||||
</view>
|
||||
<!-- 选择助记词 -->
|
||||
<block v-if="mnemonic.length > 0">
|
||||
<view class="mnemonic-title">
|
||||
按顺序填写助记词
|
||||
</view>
|
||||
<view class="mnemonic-select">
|
||||
<view class="item" v-for="(item, index) in mnemonic" :key="index" @click="onKeys('addKey', index)">
|
||||
{{ item }}</view>
|
||||
</view>
|
||||
</block>
|
||||
<!-- 按钮 -->
|
||||
<view class="buttons">
|
||||
<button type="default" @click="verifyMnemonic">验证</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
hash
|
||||
} from "@/apis/interfaces/wallet"
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
validation: new Array(12).fill(null), // 验证key
|
||||
mnemonic: [], // 助记词key
|
||||
sign: '', // 助记词校验签名
|
||||
seedString: '', // 助记词原词
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let seed = this.$Route.query.seed.split(',')
|
||||
seed.sort(() => {
|
||||
return Math.random() - .5
|
||||
});
|
||||
console.log(seed)
|
||||
// this.mnemonic = seed
|
||||
// this.sign = this.$Route.query.sign
|
||||
// this.seedString = this.$Route.query.seed
|
||||
},
|
||||
methods: {
|
||||
// 填写助记词
|
||||
onKeys(type, index) {
|
||||
if (type === 'addKey') {
|
||||
this.$set(this.validation, this.validation.findIndex(val => val === null), this.mnemonic[index])
|
||||
this.$delete(this.mnemonic, index)
|
||||
return
|
||||
}
|
||||
if (type === 'removeKey' && this.validation[index] !== null) {
|
||||
this.mnemonic.push(this.validation[index])
|
||||
this.$delete(this.validation, index)
|
||||
this.validation.push(null)
|
||||
}
|
||||
},
|
||||
// 验证助记词
|
||||
verifyMnemonic() {
|
||||
if (this.validation.findIndex(val => val === null) > -1) {
|
||||
uni.showToast({
|
||||
title: '请完整填写助记词',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
let seed = this.validation.toString().replace(/,/g, ',')
|
||||
if (this.seedString !== seed) {
|
||||
uni.showToast({
|
||||
title: '验证失败,请确认您的助记词',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
uni.redirectTo({
|
||||
url: './create'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 提示信息
|
||||
.prompt {
|
||||
color: $text-gray;
|
||||
text-align: center;
|
||||
line-height: 90rpx;
|
||||
font-size: $title-size-m;
|
||||
}
|
||||
|
||||
// 选择助记词
|
||||
.mnemonic-title {
|
||||
padding-top: $padding * 2;
|
||||
margin: 0 $margin * 2;
|
||||
font-size: $title-size-m;
|
||||
color: $main-color;
|
||||
}
|
||||
|
||||
.mnemonic-select {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: $padding $padding + $padding / 2;
|
||||
|
||||
.item {
|
||||
background-color: white;
|
||||
line-height: 68rpx;
|
||||
height: 68rpx;
|
||||
width: 68rpx;
|
||||
text-align: center;
|
||||
margin: $margin / 2;
|
||||
border-radius: $radius-m;
|
||||
box-shadow: 0 0 4rpx 4rpx rgba($color: $text-color, $alpha: .02);
|
||||
}
|
||||
}
|
||||
|
||||
// 助记词
|
||||
.mnemonic {
|
||||
margin: $margin ($margin * 2);
|
||||
border-radius: $radius-m;
|
||||
box-shadow: 0 0 4rpx 4rpx rgba($color: $text-color, $alpha: .02);
|
||||
background-color: white;
|
||||
padding: $padding;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
|
||||
.item {
|
||||
background: rgba($color: $border-color, $alpha: .4);
|
||||
min-width: 58rpx;
|
||||
height: 58rpx;
|
||||
line-height: 58rpx;
|
||||
text-align: center;
|
||||
color: $text-color;
|
||||
margin: $margin / 2;
|
||||
|
||||
&.hide {
|
||||
border: dashed 1px $border-color;
|
||||
box-sizing: border-box;
|
||||
background-color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按钮
|
||||
.buttons {
|
||||
padding: $padding $padding * 2;
|
||||
|
||||
.text {
|
||||
text-align: center;
|
||||
margin-bottom: $margin * 2;
|
||||
font-size: $title-size-lg;
|
||||
color: $text-price;
|
||||
}
|
||||
|
||||
button {
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
background-color: $main-color;
|
||||
border-radius: $radius-lg;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: $title-size;
|
||||
|
||||
&[disabled] {
|
||||
background: rgba($color: $main-color, $alpha: .8);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user