Browse Source

update ui

imndx 3 years ago
parent
commit
6cb67dc81d

+ 1 - 0
.gitignore

@@ -3,3 +3,4 @@ unpackage/resources/__UNI__*
 unpackage
 nativeplugins
 .hbuilderx
+.idea

+ 333 - 0
components/chunLei-popups/chunLei-popups.vue

@@ -0,0 +1,333 @@
+<template>
+	<view class="mask" :class="!show?'':'mask-show'" :style="{backgroundColor:show?maskBg:'rgba(0,0,0,0)'}" @tap="tapMask">
+		<view class="popups" :class="[theme]"
+			:style="{top: popupsTop ,left: popupsLeft,flexDirection:direction}">
+			<text :class="dynPlace" :style="{width:'0px',height:'0px'}" v-if="triangle"></text>
+			<view v-for="(item,index) in popData" :key="index" @tap.stop="tapItem(item)" 
+				class="itemChild view" :class="[direction=='row'?'solid-right':'solid-bottom',item.disabled?'disabledColor':'']">
+				<image class="image" :src="item.icon" v-if="item.icon"></image>{{item.title}}
+			</view>
+			<slot></slot>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default{
+		props:{
+			maskBg:{
+				type:String,
+				default:'rgba(0,0,0,0)'
+			},
+			placement:{
+				type:String,
+				default:'default' //default top-start top-end bottom-start bottom-end 
+			},
+			direction:{
+				type:String,
+				default:'column' //column row
+			},
+			x:{
+				type:Number,
+				default:0
+			},
+			y:{
+				type:Number,
+				default:0
+			},
+			value:{
+				type:Boolean,
+				default:false
+			},
+			popData:{
+				type:Array,
+				default:()=>[]
+			},
+			theme:{
+				type:String,
+				default:'light' //light dark
+			},
+			dynamic:{
+				type:Boolean,
+				default:false
+			},
+			gap:{
+				type:Number,
+				default:20
+			},
+			triangle:{
+				type:Boolean,
+				default:true
+			}
+		},
+		data(){
+			return{
+				popupsTop:'0px',
+				popupsLeft:'0px',
+				show:false,
+				dynPlace:''
+			}
+		},
+		mounted() {
+			this.popupsPosition()
+		},
+		methods:{
+			tapMask(){
+				
+				this.$emit('input',!this.value)
+			},
+			tapItem(item){
+				if(item.disabled) return
+				this.$emit('tapPopup',item)
+				this.$emit('input',!this.value)
+			},
+			getStatusBar(){
+				let promise = new Promise((resolve,reject)=>{
+					uni.getSystemInfo({
+						success: function(e) {
+							
+							let customBar
+							// #ifdef H5
+					
+							customBar = e.statusBarHeight + e.windowTop;
+
+							// #endif
+							resolve(customBar)
+						}
+					})
+				})
+				return promise
+			},
+			async popupsPosition(){
+				let statusBar = await this.getStatusBar()
+				let promise = new Promise((resolve,reject)=>{
+					let popupsDom = uni.createSelectorQuery().in(this).select(".popups")
+					popupsDom.fields({
+					    size: true,  
+					}, (data) => {
+						let width = data.width
+						let height = data.height
+						
+						let y = this.dynamic?this.dynamicGetY(this.y,this.gap):this.transformRpx(this.y)
+						
+						let x = this.dynamic?this.dynamicGetX(this.x,this.gap):this.transformRpx(this.x)
+					
+						
+						// #ifdef H5
+						y = this.dynamic?(this.y+statusBar): this.transformRpx(this.y+statusBar)
+						// #endif 
+						
+						this.dynPlace = this.placement=='default'?this.getPlacement(x,y):this.placement
+						
+						switch(this.dynPlace){
+							case 'top-start':
+								this.popupsTop = `${y+9}px`
+								this.popupsLeft = `${x-15}px`
+								break;
+							case 'top-end':
+								this.popupsTop = `${y+9}px`
+								this.popupsLeft = `${x+15-width}px`
+								break;
+							case 'bottom-start':
+								this.popupsTop = `${y-18-height}px`
+								this.popupsLeft = `${x-15}px`
+								break;
+							case 'bottom-end':
+								this.popupsTop = `${y-9-height}px`
+								this.popupsLeft = `${x+15-width}px`
+								break;
+						}
+						resolve()
+					}).exec();
+					
+				})
+				return promise
+				
+			},
+			getPlacement(x,y){
+				let width = uni.getSystemInfoSync().windowWidth
+				let height = uni.getSystemInfoSync().windowHeight
+				if(x>width/2&&y>height/2){
+					return 'bottom-end'
+				}else if(x<width/2&&y<height/2){
+					return 'top-start'
+				}else if(x>width/2&&y<height/2){
+					return 'top-end'
+				}else if(x<width/2&&y>height/2){
+					return 'bottom-start'
+				}else if(x>width/2){
+					return 'top-end'
+				}else{
+					return 'top-start'
+				}
+			},
+			dynamicGetY(y,gap){
+				
+				let height = uni.getSystemInfoSync().windowHeight
+				y = y<gap?gap:y
+				y = height - y <gap? (height - gap) : y
+				
+				return y
+			},
+			dynamicGetX(x,gap){
+				let width = uni.getSystemInfoSync().windowWidth
+				x = x< gap?gap:x
+				x = width - x <gap? (width - gap) : x
+				return x
+			},
+			transformRpx(params){
+				
+				return params*uni.getSystemInfoSync().screenWidth/375
+			}
+		},
+		watch:{
+			value:{
+				immediate:true,
+				handler:async function (newVal,oldVal){
+					if(newVal) await this.popupsPosition()
+					this.show = newVal
+				}
+			},
+			placement:{
+				immediate:true,
+				handler(newVal,oldVal){
+					this.dynPlace = newVal
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.mask{
+		position: fixed;
+		top: 0;
+		right: 0;
+		bottom: 0;
+		left: 0;
+		z-index: 9999;
+		transition: background 0.3s ease-in-out;
+		visibility: hidden;
+		
+		&.mask-show{
+			
+			visibility: visible;
+		}
+	}
+	.popups{
+		position: absolute;
+		padding: 20rpx;
+		border-radius: 5px;
+		display:flex;
+		.view{
+			padding: 10rpx;
+		}
+		.image{
+			display: inline-block;
+			vertical-align: middle;
+			width: 40rpx;
+			height: 40rpx;
+			margin-right: 20rpx;
+		}
+	}
+	.dark{
+		background-color: #4C4C4C;
+		color: #fff;
+		.top-start:after {
+			content: "";
+			position: absolute;
+			top: -18rpx;
+			left: 10rpx;
+			border-width: 0 20rpx 20rpx;
+			border-style: solid;
+			border-color: transparent transparent #4C4C4C;
+		}
+		.top-end:after {
+			content: "";
+			position: absolute;
+			top: -18rpx;
+			right: 10rpx;
+			border-width: 0 20rpx 20rpx;
+			border-style: solid;
+			border-color: transparent transparent #4C4C4C;
+		}
+		.bottom-start:after {
+			content: "";
+			position: absolute;
+			bottom: -18rpx;
+			left: 10rpx;
+			border-width: 20rpx 20rpx 0 ;
+			border-style: solid;
+			border-color: #4C4C4C transparent transparent ;
+			
+		}
+		.bottom-end:after {
+			content: "";
+			position: absolute;
+			bottom: -18rpx;
+			right: 10rpx;
+			border-width: 20rpx 20rpx 0 ;
+			border-style: solid;
+			border-color: #4C4C4C transparent transparent ;
+		}
+		.disabledColor{
+			color: #c5c8ce;
+		}
+	}
+	.light{
+		color: #515a6e;
+		box-shadow: 0upx 0upx 30upx rgba(0,0,0,0.2);
+		background: #fff;
+		.top-start:after {
+			content: "";
+			position: absolute;
+			top: -18rpx;
+			left: 10rpx;
+			border-width: 0 20rpx 20rpx;
+			border-style: solid;
+			border-color: transparent transparent #fff;
+		}
+		.top-end:after {
+			content: "";
+			position: absolute;
+			top: -18rpx;
+			right: 10rpx;
+			border-width: 0 20rpx 20rpx;
+			border-style: solid;
+			border-color: transparent transparent #fff;
+		}
+		.bottom-start:after {
+			content: "";
+			position: absolute;
+			bottom: -18rpx;
+			left: 10rpx;
+			border-width: 20rpx 20rpx 0 ;
+			border-style: solid;
+			border-color: #fff transparent transparent ;
+			
+		}
+		.bottom-end:after {
+			content: "";
+			position: absolute;
+			bottom: -18rpx;
+			right: 10rpx;
+			border-width: 20rpx 20rpx 0 ;
+			border-style: solid;
+			border-color: #fff transparent transparent ;
+		}
+		.disabledColor{
+			color: #c5c8ce;
+		}
+	}
+	.solid-bottom{
+		border-bottom: 1px solid #ccc;
+	}
+	.solid-right{
+		
+		border-right: 1px solid #ccc;
+	}
+	.popups .itemChild:last-child{
+		border: none;
+	}
+	
+</style>

+ 0 - 177
components/uni-list-chat-wf/context-menu.vue

@@ -1,177 +0,0 @@
-<template>
-  <view @touchmove.stop.prevent="moveHandle('touchmove')" @click="moveHandle('click')" v-if="show">
-    <view class="openTool-wx" :animation="animationData">
-      <view class="openTool-wx-list" v-if="data">
-        <view class="openTool-wx-list-item" @click="zhiding">
-          <view class="text" v-if="data.top=='Y'">取消置顶</view>
-          <view class="text" v-if="data.top=='N'">置顶该聊天</view>
-        </view>
-        <view class="openTool-wx-list-item" @click="shanchu">
-          <view class="text">删除该聊天</view>
-        </view>
-      </view>
-    </view>
-    <view class="openTool-wx-model"></view>
-  </view>
-</template>
-
-<script>
-export default {
-  data() {
-    return {
-      show: false,
-      animationData: {}
-    };
-  },
-  props: {
-    data: {
-      type: [Object, String]
-    },
-    itemKey: {
-      type: [Object, String, Number]
-    },
-    list: {
-      type: Array,
-      default() {
-        return [{}];
-      }
-    }
-  },
-  onShow() {
-
-  },
-  computed: {
-    chatList() {
-      return this.$store.state.chatlist
-    }
-  },
-  mounted() {
-    var animation = uni.createAnimation({
-      duration: 300,
-      timingFunction: 'linear'
-    });
-    this.animation = animation;
-  },
-  methods: {
-    zhiding() {
-      var data = JSON.parse(JSON.stringify(this.data))
-      var yn = data.top == 'N' ? 'Y' : 'N';
-      data.top = yn
-      this.$store.dispatch('updateChatListInfoById', {
-        userId: this.data.userId,
-        data: data
-      })
-      this.$store.dispatch('getChatList')
-      if (data.windowType == 'GROUP') {
-        var formData = {
-          groupId: this.data.userId,
-          top: yn
-        };
-        this.$http.request({
-          url: '/group/editTop',
-          method: 'POST',
-          data: JSON.stringify(formData),
-          success: res => {
-            if (res.data.code == 200) {
-            }
-          }
-        });
-      }
-      if (data.windowType == 'SINGLE') {
-        var formData = {
-          userId: this.data.userId,
-          top: yn
-        };
-        this.$http.request({
-          url: '/friend/top',
-          method: 'POST',
-          data: JSON.stringify(formData),
-          success: res => {
-            if (res.data.code == 200) {
-            }
-          }
-        });
-      }
-    },
-    shanchu() {
-      delete this.chatList[this.data.userId]
-      this.$store.dispatch('updateChatListInfoById', {
-        userId: this.data.userId,
-        data: {}
-      });
-      this.$store.dispatch('updateChatById', {
-        userId: this.data.userId,
-        data: []
-      });
-    },
-    showAnimation() {
-      this.animation.opacity(1).step();
-      this.animationData = this.animation.export();
-    },
-    hideAnimation() {
-      this.animation.opacity(0).step();
-      this.animationData = this.animation.export();
-    },
-    moveHandle(e) {
-      this.hiddenTab()
-    },
-    showTab() {
-      this.show = true
-      setTimeout(() => {
-        this.showAnimation()
-      }, 30)
-    },
-    hiddenTab() {
-      this.show = false
-      this.hideAnimation()
-    },
-  }
-};
-</script>
-<style scoped>
-.openTool-wx {
-  display: flex;
-  flex-direction: column;
-  flex-wrap: wrap;
-  opacity: 0;
-  position: relative;
-  z-index: 2;
-}
-
-.openTool-wx-model {
-  background-color: rgba(0, 0, 0, 0);
-  position: fixed;
-  top: 0;
-  bottom: 0;
-  right: 0;
-  left: 0;
-  z-index: 1;
-}
-
-.openTool-wx-list {
-  width: 100%;
-  box-sizing: border-box;
-  background-color: #fff;
-  box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
-  border-radius: 10rpx;
-  display: flex;
-  flex-direction: column;
-}
-
-.openTool-wx-list-item {
-  padding: 24rpx;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-}
-
-.openTool-wx-list-item .text {
-  color: #333;
-  font-size: 28rpx;
-  flex: 1;
-}
-
-.openTool-wx-list-item:nth-last-child(1) .text {
-  border: none;
-}
-</style>

+ 0 - 586
components/uni-list-chat-wf/uni-list-chat-wf.vue

@@ -1,586 +0,0 @@
-<template>
-    <!-- #ifdef APP-NVUE -->
-    <cell>
-        <!-- #endif -->
-        <view :hover-class="!clickable && !link ? '' : 'uni-list-chat--hover'" :style="{background:color}" class="uni-list-chat" @longpress="longpressItem($event,itemKey,item)">
-            <openTool class="openTool" :ref="'toolx'+itemKey" :data="item" :itemKey="itemKey"></openTool>
-            <view :class="{ 'uni-list--border': border, 'uni-list-chat--first': isFirstChild }"></view>
-            <view class="uni-list-chat__container" @click="onClick">
-                <view class="uni-list-chat__header-warp">
-                    <view v-if="avatarCircle || avatarList.length === 0" class="uni-list-chat__header" :class="{ 'header--circle': avatarCircle }">
-                        <image class="uni-list-chat__header-image" :class="{ 'header--circle': avatarCircle }" :src="avatar" mode="aspectFill"></image>
-                    </view>
-                    <!-- 头像组 -->
-                    <view v-else class="uni-list-chat__header">
-                        <view v-for="(item, index) in avatarList" :key="index" class="uni-list-chat__header-box" :class="computedAvatar"
-                              :style="{ width: imageWidth + 'px', height: imageWidth + 'px' }">
-                            <image class="uni-list-chat__header-image" :style="{ width: imageWidth + 'px', height: imageWidth + 'px' }" :src="item.url"
-                                   mode="aspectFill"></image>
-                        </view>
-                    </view>
-                </view>
-                <view v-if="badgeText && badgePositon === 'left'" class="uni-list-chat__badge uni-list-chat__badge-pos" :class="[isSingle]">
-                    <text class="uni-list-chat__badge-text">{{ badgeText === 'dot' ? '' : badgeText }}</text>
-                </view>
-                <view class="uni-list-chat__content">
-                    <view class="uni-list-chat__content-main">
-                        <text class="uni-list-chat__content-title uni-ellipsis">{{ title }}</text>
-                        <text class="uni-list-chat__content-note uni-ellipsis">{{ note }}</text>
-                    </view>
-                    <view class="uni-list-chat__content-extra">
-                        <slot>
-                            <text class="uni-list-chat__content-extra-text">{{ time }}</text>
-                            <view v-if="badgeText && badgePositon === 'right'" class="uni-list-chat__badge" :class="[isSingle, badgePositon === 'right' ? 'uni-list-chat--right' : '']">
-                                <text class="uni-list-chat__badge-text">{{ badgeText === 'dot' ? '' : badgeText }}</text>
-                            </view>
-                        </slot>
-                    </view>
-                </view>
-            </view>
-        </view>
-        <!-- #ifdef APP-NVUE -->
-    </cell>
-    <!-- #endif -->
-</template>
-
-<script>
-import openTool from './context-menu.vue'
-// 头像大小
-const avatarWidth = 45;
-
-/**
- * ListChat 聊天列表
- * @description 聊天列表,用于创建聊天类列表
- * @tutorial https://ext.dcloud.net.cn/plugin?id=24
- * @property {String}  title              标题
- * @property {String}  note              描述
- * @property {Boolean}  clickable = [true|false]    是否开启点击反馈,默认为false
- * @property {String}  badgeText            数字角标内容
- * @property {String}    badgePositon = [left|right]    角标位置,默认为 right
- * @property {String}  link = [false|navigateTo|redirectTo|reLaunch|switchTab] 是否展示右侧箭头并开启点击反馈,默认为false
- *  @value false    不开启
- *  @value navigateTo  同 uni.navigateTo()
- *  @value redirectTo  同 uni.redirectTo()
- *  @value reLaunch    同 uni.reLaunch()
- *  @value switchTab    同 uni.switchTab()
- * @property {String | PageURIString}  to        跳转目标页面
- * @property {String}  time              右侧时间显示
- * @property {Boolean}  avatarCircle = [true|false]    是否显示圆形头像,默认为false
- * @property {String}  avatar              头像地址,avatarCircle 不填时生效
- * @property {Array}  avatarList            头像组,格式为 [{url:''}]
- * @event {Function}  click              点击 uniListChat 触发事件
- */
-export default {
-    components: {
-        openTool
-    },
-    name: 'UniListChatWx',
-    emits: ['click', 'longpressItem'],
-    props: {
-        color: {
-            type: String,
-            default: '#fff'
-        },
-        title: {
-            type: String,
-            default: ''
-        },
-        note: {
-            type: String,
-            default: ''
-        },
-        clickable: {
-            type: Boolean,
-            default: false
-        },
-        link: {
-            type: [Boolean, String],
-            default: false
-        },
-        to: {
-            type: String,
-            default: ''
-        },
-        badgeText: {
-            type: [String, Number],
-            default: ''
-        },
-        badgePositon: {
-            type: String,
-            default: 'right'
-        },
-        time: {
-            type: String,
-            default: ''
-        },
-        avatarCircle: {
-            type: Boolean,
-            default: false
-        },
-        avatar: {
-            type: String,
-            default: ''
-        },
-        // avatarList: {
-        // 	type: Array,
-        // 	default () {
-        // 		return [];
-        // 	}
-        // },
-        item: {
-            type: Object,
-            default: {}
-        },
-        itemKey: {
-            type: Number
-        },
-        longTapItemKey: {
-            type: [Number, String],
-            default: ''
-        }
-    },
-    // inject: ['list'],
-    computed: {
-        isSingle() {
-            if (this.badgeText === 'dot') {
-                return 'uni-badge--dot';
-            } else {
-                const badgeText = this.badgeText.toString();
-                if (badgeText.length > 1) {
-                    return 'uni-badge--complex';
-                } else {
-                    return 'uni-badge--single';
-                }
-            }
-        },
-        avatarList() {
-            return this.returnAvatar(this.item.portrait)
-        },
-        computedAvatar() {
-            if (this.avatarList.length > 4) {
-                this.imageWidth = avatarWidth * 0.31;
-                return 'avatarItem--3';
-            } else if (this.avatarList.length > 1) {
-                this.imageWidth = avatarWidth * 0.47;
-                return 'avatarItem--2';
-            } else {
-                this.imageWidth = avatarWidth;
-                return 'avatarItem--1';
-            }
-        }
-    },
-    data() {
-        return {
-            isFirstChild: false,
-            border: true,
-            // avatarList: 3,
-            imageWidth: 50
-        };
-    },
-    mounted() {
-        this.list = this.getForm()
-        if (this.list) {
-            if (!this.list.firstChildAppend) {
-                this.list.firstChildAppend = true;
-                this.isFirstChild = true;
-            }
-            this.border = this.list.border;
-        }
-    },
-    methods: {
-        returnAvatar(text) {
-            var data = JSON.parse(text)
-            var avatars = []
-            for (var i = 0; i < data.length; i++) {
-                avatars.push({
-                    url: data[i]
-                })
-            }
-            return avatars
-        },
-        longpressItem(e, i, v) {//长按回调
-            this.$emit('longpressItem', e, i, v)
-            if (this.itemKey == this.longTapItemKey) {
-                this.$refs['toolx' + this.itemKey].showTab();
-            }
-        },
-        /**
-         * 获取父元素实例
-         */
-        getForm(name = 'uniList') {
-            let parent = this.$parent;
-            let parentName = parent.$options.name;
-            while (parentName !== name) {
-                parent = parent.$parent;
-                if (!parent) return false
-                parentName = parent.$options.name;
-            }
-            return parent;
-        },
-        onClick() {
-            if (this.to !== '') {
-                this.openPage();
-                return;
-            }
-
-            if (this.clickable || this.link) {
-                this.$emit('click', {
-                    data: {}
-                });
-            }
-        },
-        openPage() {
-            if (['navigateTo', 'redirectTo', 'reLaunch', 'switchTab'].indexOf(this.link) !== -1) {
-                this.pageApi(this.link);
-            } else {
-                this.pageApi('navigateTo');
-            }
-        },
-        pageApi(api) {
-            uni[api]({
-                url: this.to,
-                success: res => {
-                    this.$emit('click', {
-                        data: res
-                    });
-                },
-                fail: err => {
-                    this.$emit('click', {
-                        data: err
-                    });
-                    console.error(err.errMsg);
-                }
-            });
-        }
-    }
-};
-</script>
-
-<style lang="scss" scoped>
-$uni-font-size-lg: 16px;
-$uni-spacing-row-sm: 5px;
-$uni-spacing-row-base: 10px;
-$uni-spacing-row-lg: 15px;
-$background-color: #fff;
-$divide-line-color: #e5e5e5;
-$avatar-width: 45px;
-$avatar-border-radius: 5px;
-$avatar-border-color: #eee;
-$avatar-border-width: 1px;
-$title-size: 16px;
-$title-color: #3b4144;
-$title-weight: normal;
-$note-size: 12px;
-$note-color: #999;
-$note-weight: normal;
-$right-text-size: 12px;
-$right-text-color: #999;
-$right-text-weight: normal;
-$badge-left: 0px;
-$badge-top: 0px;
-$dot-width: 10px;
-$dot-height: 10px;
-$badge-size: 18px;
-$badge-font: 12px;
-$badge-color: #fff;
-$badge-background-color: #ff5a5f;
-$badge-space: 6px;
-$hover: #f5f5f5;
-.openTool {
-    width: 100%;
-    position: absolute;
-    top: 50%;
-    display: flex;
-    flex-direction: row;
-    justify-content: center;
-}
-
-.uni-list-chat {
-    font-size: $uni-font-size-lg;
-    position: relative;
-    flex-direction: column;
-    justify-content: space-between;
-    background-color: $background-color;
-    position: relative;
-}
-
-// .uni-list-chat--disabled {
-// 	opacity: 0.3;
-// }
-
-.uni-list-chat--hover {
-    background-color: $hover;
-}
-
-.uni-list--border {
-    position: relative;
-    margin-left: $uni-spacing-row-lg;
-    /* #ifdef APP-PLUS */
-    border-top-color: $divide-line-color;
-    border-top-style: solid;
-    border-top-width: 0.5px;
-    /* #endif */
-}
-
-/* #ifndef APP-NVUE */
-.uni-list--border:after {
-    position: absolute;
-    top: 0;
-    right: 0;
-    left: 0;
-    height: 1px;
-    content: '';
-    -webkit-transform: scaleY(0.5);
-    transform: scaleY(0.5);
-    background-color: $divide-line-color;
-}
-
-.uni-list-item--first:after {
-    height: 0px;
-}
-
-/* #endif */
-
-.uni-list-chat--first {
-    border-top-width: 0px;
-}
-
-.uni-ellipsis {
-    /* #ifndef APP-NVUE */
-    overflow: hidden;
-    white-space: nowrap;
-    text-overflow: ellipsis;
-    /* #endif */
-    /* #ifdef APP-NVUE */
-    lines: 1;
-    /* #endif */
-}
-
-.uni-ellipsis-2 {
-    /* #ifndef APP-NVUE */
-    overflow: hidden;
-    text-overflow: ellipsis;
-    display: -webkit-box;
-    -webkit-line-clamp: 2;
-    -webkit-box-orient: vertical;
-    /* #endif */
-
-    /* #ifdef APP-NVUE */
-    lines: 2;
-    /* #endif */
-}
-
-.uni-list-chat__container {
-    position: relative;
-    /* #ifndef APP-NVUE */
-    display: flex;
-    /* #endif */
-    flex-direction: row;
-    flex: 1;
-    padding: $uni-spacing-row-base $uni-spacing-row-lg;
-    position: relative;
-    overflow: hidden;
-}
-
-.uni-list-chat__header-warp {
-    position: relative;
-}
-
-.uni-list-chat__header {
-    /* #ifndef APP-NVUE */
-    display: flex;
-    align-content: center;
-    /* #endif */
-    flex-direction: row;
-    justify-content: center;
-    align-items: center;
-    flex-wrap: wrap-reverse;
-    /* #ifdef APP-NVUE */
-    width: 50px;
-    height: 50px;
-    /* #endif */
-    /* #ifndef APP-NVUE */
-    width: $avatar-width;
-    height: $avatar-width;
-    /* #endif */
-
-    border-radius: $avatar-border-radius;
-    border-color: $avatar-border-color;
-    border-width: $avatar-border-width;
-    border-style: solid;
-    overflow: hidden;
-}
-
-.uni-list-chat__header-box {
-    /* #ifndef APP-PLUS */
-    box-sizing: border-box;
-    display: flex;
-    width: $avatar-width;
-    height: $avatar-width;
-    /* #endif */
-    /* #ifdef APP-NVUE */
-    width: 50px;
-    height: 50px;
-    /* #endif */
-    overflow: hidden;
-    border-radius: 2px;
-}
-
-.uni-list-chat__header-image {
-    margin: 1px;
-    /* #ifdef APP-NVUE */
-    width: 50px;
-    height: 50px;
-    /* #endif */
-    /* #ifndef APP-NVUE */
-    width: $avatar-width;
-    height: $avatar-width;
-    /* #endif */
-}
-
-/* #ifndef APP-NVUE */
-.uni-list-chat__header-image {
-    display: block;
-    width: 100%;
-    height: 100%;
-}
-
-.avatarItem--1 {
-    width: 100%;
-    height: 100%;
-}
-
-.avatarItem--2 {
-    width: 47%;
-    height: 47%;
-}
-
-.avatarItem--3 {
-    width: 32%;
-    height: 32%;
-}
-
-/* #endif */
-.header--circle {
-    border-radius: 50%;
-}
-
-.uni-list-chat__content {
-    /* #ifndef APP-NVUE */
-    display: flex;
-    /* #endif */
-    flex-direction: row;
-    flex: 1;
-    overflow: hidden;
-    padding: 2px 0;
-}
-
-.uni-list-chat__content-main {
-    /* #ifndef APP-NVUE */
-    display: flex;
-    /* #endif */
-    flex-direction: column;
-    justify-content: space-between;
-    padding-left: $uni-spacing-row-base;
-    flex: 1;
-    overflow: hidden;
-}
-
-.uni-list-chat__content-title {
-    font-size: $title-size;
-    color: $title-color;
-    font-weight: $title-weight;
-    overflow: hidden;
-}
-
-.uni-list-chat__content-note {
-    margin-top: 3px;
-    color: $note-color;
-    font-size: $note-size;
-    font-weight: $title-weight;
-    overflow: hidden;
-}
-
-.uni-list-chat__content-extra {
-    /* #ifndef APP-NVUE */
-    flex-shrink: 0;
-    display: flex;
-    /* #endif */
-    flex-direction: column;
-    justify-content: space-between;
-    align-items: flex-end;
-    margin-left: 5px;
-}
-
-.uni-list-chat__content-extra-text {
-    color: $right-text-color;
-    font-size: $right-text-size;
-    font-weight: $right-text-weight;
-    overflow: hidden;
-}
-
-.uni-list-chat__badge-pos {
-    position: absolute;
-    /* #ifdef APP-NVUE */
-    left: 55px;
-    top: 3px;
-    /* #endif */
-    /* #ifndef APP-NVUE */
-    left: calc(#{$avatar-width} + 10px - #{$badge-space} + #{$badge-left});
-    top: calc(#{$uni-spacing-row-base} / 2 + 1px + #{$badge-top});
-    /* #endif */
-}
-
-.uni-list-chat__badge {
-    /* #ifndef APP-NVUE */
-    display: flex;
-    /* #endif */
-    justify-content: center;
-    align-items: center;
-    border-radius: 100px;
-    background-color: $badge-background-color;
-}
-
-.uni-list-chat__badge-text {
-    color: $badge-color;
-    font-size: $badge-font;
-}
-
-.uni-badge--single {
-    /* #ifndef APP-NVUE */
-    // left: calc(#{$avatar-width} + 7px + #{$badge-left});
-    /* #endif */
-    width: $badge-size;
-    height: $badge-size;
-}
-
-.uni-badge--complex {
-    /* #ifdef APP-NVUE */
-    left: 50px;
-    /* #endif */
-    /* #ifndef APP-NVUE */
-    width: auto;
-    /* #endif */
-    height: $badge-size;
-    padding: 0 $badge-space;
-}
-
-.uni-badge--dot {
-    /* #ifdef APP-NVUE */
-    left: 60px;
-    top: 6px;
-    /* #endif */
-    /* #ifndef APP-NVUE */
-    left: calc(#{$avatar-width} + 15px - #{$dot-width} / 2 + 1px + #{$badge-left});
-    /* #endif */
-    width: $dot-width;
-    height: $dot-height;
-    padding: 0;
-}
-
-.uni-list-chat--right {
-    /* #ifdef APP-NVUE */
-    left: 0;
-    /* #endif */
-}
-</style>

+ 0 - 953
pages/conversation/ConversationView-bk.vue

@@ -1,953 +0,0 @@
-<template>
-    <div>
-        <div v-if="true" class="conversation-empty-container">
-<!--            <div v-if="sharedConversationState.currentConversationInfo == null" class="conversation-empty-container">-->
-            <h1>^~^</h1>
-        </div>
-        <div v-else class="conversation-container">
-            <header>
-                <div class="title-container">
-                    <div>
-                        <h1 class="single-line" @click.stop="toggleConversationInfo">{{ conversationTitle }}</h1>
-                        <p class="single-line user-online-status">{{ targetUserOnlineStateDesc }}</p>
-                    </div>
-                    <a href="#"><i class="icon-ion-ios-settings-strong"
-                                   style="display: inline-block"
-                                   v-bind:style="{marginTop: '0'}"
-                                   ref="setting"
-                                   @click="toggleConversationInfo"/></a>
-                </div>
-            </header>
-            <div ref="conversationContentContainer" class="conversation-content-container"
-                 @dragover="dragEvent($event, 'dragover')"
-                 @dragleave="dragEvent($event, 'dragleave')"
-                 @dragenter="dragEvent($event,'dragenter')"
-                 @drop="dragEvent($event, 'drop')"
-                 :dummy_just_for_reactive="currentVoiceMessage"
-            >
-                <div v-show="dragAndDropEnterCount > 0" class="drag-drop-container">
-                    <div class="drag-drop">
-                        <p>{{ $t('conversation.drag_to_send_to', [conversationTitle]) }}</p>
-                    </div>
-                </div>
-                <div ref="conversationMessageList" class="conversation-message-list" v-on:scroll="onScroll"
-                     infinite-wrapper>
-                    <infinite-loading :identifier="loadingIdentifier" force-use-infinite-wrapper direction="top"
-                                      @infinite="infiniteHandler">
-                        <!--            <template slot="spinner">加载中...</template>-->
-                        <template slot="no-more">{{ $t('conversation.no_more_message') }}</template>
-                        <template slot="no-results">{{ $t('conversation.all_message_load') }}</template>
-                    </infinite-loading>
-                    <ul >
-                        <!--todo item.messageId or messageUid as key-->
-                        <li v-for="(message) in sharedConversationState.currentConversationMessageList"
-                            :key="message.messageId">
-                            <!--todo 不同的消息类型 notification in out-->
-
-                            <NotificationMessageContentView :message="message" v-if="isNotificationMessage(message)"/>
-                            <RecallNotificationMessageContentView :message="message" v-else-if="isRecallNotificationMessage(message)"/>
-                            <NormalOutMessageContentView
-                                @click.native.capture="sharedConversationState.enableMessageMultiSelection? clickMessageItem($event, message) : null"
-                                :message="message"
-                                v-else-if="message.direction === 0"/>
-                            <NormalInMessageContentView
-                                @click.native.capture="sharedConversationState.enableMessageMultiSelection ? clickMessageItem($event, message) : null"
-                                :message="message"
-                                v-else/>
-                        </li>
-                    </ul>
-                </div>
-                <div v-if="sharedConversationState.inputtingUser" class="inputting-container">
-                    <img class="avatar" :src="sharedConversationState.inputtingUser.portrait"/>
-                    <ScaleLoader :color="'#d2d2d2'" :height="'15px'" :width="'3px'"/>
-                </div>
-                <div v-show="!sharedConversationState.enableMessageMultiSelection" v-on:mousedown="dragStart"
-                     class="divider-handler"></div>
-                <MessageInputView :conversationInfo="sharedConversationState.currentConversationInfo"
-                                  v-show="!sharedConversationState.enableMessageMultiSelection"
-                                  ref="messageInputView"
-                                  class="message-input-container"/>
-                <MultiSelectActionView v-show="sharedConversationState.enableMessageMultiSelection"/>
-                <SingleConversationInfoView
-                    v-if="showConversationInfo &&  sharedConversationState.currentConversationInfo.conversation.type === 0"
-                    v-click-outside="hideConversationInfo"
-                    :conversation-info="sharedConversationState.currentConversationInfo"
-                    v-bind:class="{ active: showConversationInfo }"
-                    class="conversation-info-container"
-                />
-                <GroupConversationInfoView
-                    v-if="showConversationInfo &&  sharedConversationState.currentConversationInfo.conversation.type === 1"
-                    v-click-outside="hideConversationInfo"
-                    :conversation-info="sharedConversationState.currentConversationInfo"
-                    v-bind:class="{ active: showConversationInfo }"
-                    class="conversation-info-container"
-                />
-
-<!--                <vue-context ref="menu" v-slot="{data:message}" :close-on-scroll="true" v-on:close="onMenuClose">-->
-<!--                    &lt;!&ndash;          更多menu item&ndash;&gt;-->
-<!--                    <li v-if="isCopyable(message)">-->
-<!--                        <a @click.prevent="copy(message)">{{ $t('common.copy') }}</a>-->
-<!--                    </li>-->
-<!--                    <li v-if="isDownloadAble(message)">-->
-<!--                        <a @click.prevent="download(message)">{{ $t('common.save') }}</a>-->
-<!--                    </li>-->
-<!--                    <li>-->
-<!--                        <a @click.prevent="delMessage(message)">{{ $t('common.delete') }}</a>-->
-<!--                    </li>-->
-<!--                    <li v-if="isForwardable(message)">-->
-<!--                        <a @click.prevent="_forward(message)">{{ $t('common.forward') }}</a>-->
-<!--                    </li>-->
-<!--                    <li v-if="isFavable(message)">-->
-<!--                        <a @click.prevent="favMessage(message)">{{ $t('common.fav') }}</a>-->
-<!--                    </li>-->
-<!--                    <li v-if="isQuotable(message)">-->
-<!--                        <a @click.prevent="quoteMessage(message)">{{ $t('common.quote') }}</a>-->
-<!--                    </li>-->
-<!--                    <li>-->
-<!--                        <a @click.prevent="multiSelect(message)">{{ $t('common.multi_select') }}</a>-->
-<!--                    </li>-->
-<!--                    <li v-if="isRecallable(message)">-->
-<!--                        <a @click.prevent="recallMessage(message)">{{ $t('common.recall') }}</a>-->
-<!--                    </li>-->
-<!--                    <li v-if="isLocalFile(message)">-->
-<!--                        <a @click.prevent="openFile(message)">{{ $t('common.open') }}</a>-->
-<!--                    </li>-->
-<!--                    <li v-if="isLocalFile(message)">-->
-<!--                        <a @click.prevent="openDir(message)">{{ $t('common.open_dir') }}</a>-->
-<!--                    </li>-->
-<!--                </vue-context>-->
-<!--                <vue-context ref="messageSenderContextMenu" v-slot="{data: message}" :close-on-scroll="true" v-on:close="onMessageSenderContextMenuClose">-->
-<!--                    &lt;!&ndash;          更多menu item,比如添加到通讯录等&ndash;&gt;-->
-<!--                    <li>-->
-<!--                        <a @click.prevent="mentionMessageSender(message)">{{ mentionMessageSenderTitle(message) }}</a>-->
-<!--                    </li>-->
-<!--                </vue-context>-->
-            </div>
-        </div>
-    </div>
-</template>
-
-<script>
-import SingleConversationInfoView from "@/pages/conversation/SingleConversationInfoView";
-import GroupConversationInfoView from "@/pages/conversation/GroupConversationInfoView";
-import MessageInputView from "@/pages/conversation/MessageInputView";
-import ClickOutside from 'vue-click-outside'
-import NormalOutMessageContentView from "@/pages/conversation/message/NormalOutMessageContentContainerView";
-import NormalInMessageContentView from "@/pages/conversation/message/NormalInMessageContentContainerView";
-import NotificationMessageContentView from "@/pages/conversation/message/NotificationMessageContentView";
-import RecallNotificationMessageContentView from "@/pages/conversation/message/RecallNotificationMessageContentView";
-import NotificationMessageContent from "@/wfc/messages/notification/notificationMessageContent";
-import TextMessageContent from "@/wfc/messages/textMessageContent";
-import store from "@/store";
-import wfc from "@/wfc/client/wfc";
-import {numberValue} from "@/wfc/util/longUtil";
-import InfiniteLoading from 'vue-infinite-loading';
-import MultiSelectActionView from "@/pages/conversation/MessageMultiSelectActionView";
-import ForwardMessageByPickConversationView from "@/pages/conversation/message/forward/ForwardMessageByPickConversationView";
-import ForwardMessageByCreateConversationView from "@/pages/conversation/message/forward/ForwardMessageByCreateConversationView";
-import ScaleLoader from 'vue-spinner/src/ScaleLoader'
-import ForwardType from "@/pages/conversation/message/forward/ForwardType";
-import {fs, isElectron, shell} from "@/platform";
-import FileMessageContent from "@/wfc/messages/fileMessageContent";
-import ImageMessageContent from "@/wfc/messages/imageMessageContent";
-// import {copyImg, copyText} from "@/pages/util/clipboard";
-import Message from "@/wfc/messages/message";
-// import {downloadFile} from "@/platformHelper";
-import VideoMessageContent from "@/wfc/messages/videoMessageContent";
-// import localStorageEmitter from "../../../ipc/localStorageEmitter";
-import {remote} from "@/platform";
-import SoundMessageContent from "@/wfc/messages/soundMessageContent";
-import MessageContentType from "@/wfc/messages/messageContentType";
-// import BenzAMRRecorder from "benz-amr-recorder";
-// import axios from "axios";
-import FavItem from "@/wfc/model/favItem";
-import {stringValue} from "@/wfc/util/longUtil";
-import ConversationType from "@/wfc/model/conversationType";
-import GroupMemberType from "@/wfc/model/groupMemberType";
-import CompositeMessageContent from "@/wfc/messages/compositeMessageContent";
-
-var amr;
-export default {
-    components: {
-        MultiSelectActionView,
-        NotificationMessageContentView,
-        RecallNotificationMessageContentView,
-        NormalInMessageContentView,
-        NormalOutMessageContentView,
-        MessageInputView,
-        GroupConversationInfoView,
-        SingleConversationInfoView,
-        InfiniteLoading,
-        ScaleLoader,
-    },
-    // props: ["conversation"],
-    data() {
-        return {
-            conversationInfo: null,
-            showConversationInfo: false,
-            sharedConversationState: store.state.conversation,
-            sharedContactState: store.state.contact,
-            sharedPickState: store.state.pick,
-            sharedMiscState: store.state.misc,
-            isHandlerDragging: false,
-
-            savedMessageListViewHeight: -1,
-            saveMessageListViewFlexGrow: -1,
-
-            dragAndDropEnterCount: 0,
-            // FIXME 选中一个会话,然后切换到其他page,比如联系人,这时该会话收到新消息或发送消息,会导致新收到/发送的消息的界面错乱,尚不知道原因,但这么做能解决。
-        };
-    },
-
-    activated() {
-        console.log('conversationView', this.sharedConversationState.currentConversationMessageList);
-    },
-
-    deactivated() {
-    },
-
-    methods: {
-        dragEvent(e, v) {
-            if (v === 'dragenter') {
-                this.dragAndDropEnterCount++;
-            } else if (v === 'dragleave') {
-                this.dragAndDropEnterCount--;
-            } else if (v === 'drop') {
-                this.dragAndDropEnterCount--;
-                let isFile;
-                if (e.dataTransfer.items) {
-                    if (typeof (e.dataTransfer.items[0].webkitGetAsEntry) == "function") {
-                        isFile = e.dataTransfer.items[0].webkitGetAsEntry().isFile;
-                    } else if (typeof (e.dataTransfer.items[0].getAsEntry) == "function") {
-                        isFile = e.dataTransfer.items[0].getAsEntry().isFile;
-                    }
-                } else {
-                    return true;
-                }
-                if (!isFile) {
-                    this.$notify({
-                        // title: '不支持',
-                        text: this.$t('conversation.not_support_send_folder'),
-                        type: 'warn'
-                    });
-                    return true;
-                }
-
-                let length = e.dataTransfer.files.length;
-                if (length > 0 && length < 5) {
-                    for (let i = 0; i < length; i++) {
-                        this.$eventBus.$emit('uploadFile', e.dataTransfer.files[i])
-                        store.sendFile(this.sharedConversationState.currentConversationInfo.conversation, e.dataTransfer.files[i]);
-                    }
-                } else {
-                    this.$notify({
-                        // title: '大文件提示',
-                        text: this.$t('conversation.drag_to_send_limit_tip'),
-                        type: 'warn'
-                    });
-                }
-            } else if (v === 'dragover') {
-                // If not st as 'copy', electron will open the drop file
-                e.dataTransfer.dropEffect = 'copy';
-            }
-        },
-        toggleConversationInfo() {
-            this.showConversationInfo = !this.showConversationInfo;
-        },
-
-        toggleMessageMultiSelectionActionView(message) {
-            if (!this.sharedConversationState.enableMessageMultiSelection) {
-                this.saveMessageListViewFlexGrow = this.$refs['conversationMessageList'].style.flexGrow;
-                this.savedMessageListViewHeight = this.$refs['conversationMessageList'].style.height;
-                this.$refs['conversationMessageList'].style.flexGrow = 1;
-            } else {
-                if (this.saveMessageListViewFlexGrow !== -1 && this.savedMessageListViewHeight !== -1) {
-                    this.$refs['conversationMessageList'].style.height = this.savedMessageListViewHeight;
-                    this.$refs['conversationMessageList'].style.flexGrow = this.saveMessageListViewFlexGrow;
-                }
-            }
-            this.sharedPickState.messages.forEach(m => console.log(m.messageId));
-            store.toggleMessageMultiSelection(message);
-        },
-
-        clickMessageItem(event, message) {
-            if (message.messageContent instanceof NotificationMessageContent) {
-                return;
-            }
-            if (this.sharedConversationState.enableMessageMultiSelection) {
-                store.selectOrDeselectMessage(message);
-                event.stopPropagation();
-            }
-        },
-
-        hideConversationInfo() {
-            // TODO
-            // 是否在创建群聊,或者是在查看会话参与者信息
-            this.showConversationInfo && (this.showConversationInfo = false);
-        },
-
-        isNotificationMessage(message) {
-            return message && message.messageContent instanceof NotificationMessageContent && message.messageContent.type !== MessageContentType.RecallMessage_Notification;
-        },
-
-        isRecallNotificationMessage(message) {
-            return message && message.messageContent.type === MessageContentType.RecallMessage_Notification;
-        },
-
-        reedit(message) {
-            this.$refs.messageInputView.insertText(message.messageContent.originalSearchableContent);
-        },
-
-        onScroll(e) {
-            // hide tippy userCard
-            for (const popper of document.querySelectorAll('.tippy-popper')) {
-                const instance = popper._tippy;
-                if (instance.state.isVisible) {
-                    instance.hide();
-                }
-            }
-            // hide message context menu
-            this.$refs.menu && this.$refs.menu.close();
-
-            // 当用户往上滑动一段距离之后,收到新消息,不自动滚到到最后
-            if (e.target.scrollHeight > e.target.clientHeight + e.target.scrollTop + e.target.clientHeight / 2) {
-                store.setShouldAutoScrollToBottom(false)
-            } else {
-                store.setShouldAutoScrollToBottom(true)
-                store.clearConversationUnreadStatus(this.sharedConversationState.currentConversationInfo.conversation);
-            }
-        },
-
-        dragStart() {
-            this.isHandlerDragging = true;
-            console.log('drag start')
-        },
-
-        drag(e) {
-            // Don't do anything if dragging flag is false
-            if (!this.isHandlerDragging) {
-                return false;
-            }
-
-            // Get offset
-            let containerOffsetTop = this.$refs['conversationContentContainer'].offsetTop;
-
-            // Get x-coordinate of pointer relative to container
-            let pointerRelativeYpos = e.clientY - containerOffsetTop;
-
-            // Arbitrary minimum width set on box A, otherwise its inner content will collapse to width of 0
-            let boxAminHeight = 150;
-
-            // Resize box A
-            // * 8px is the left/right spacing between .handler and its inner pseudo-element
-            // * Set flex-grow to 0 to prevent it from growing
-            this.$refs['conversationMessageList'].style.height = (Math.max(boxAminHeight, pointerRelativeYpos)) + 'px';
-            this.$refs['conversationMessageList'].style.flexGrow = 0;
-
-        },
-
-        dragEnd() {
-            this.isHandlerDragging = false;
-        },
-
-        onMenuClose() {
-            this.$emit('contextMenuClosed')
-        },
-        onMessageSenderContextMenuClose() {
-            console.log('onMessageSenderContextMenuClose')
-        },
-
-        // message context menu
-        isCopyable(message) {
-            return message && (message.messageContent instanceof TextMessageContent || message.messageContent instanceof ImageMessageContent);
-        },
-        isDownloadAble(message) {
-            return message && (message.messageContent instanceof ImageMessageContent
-                || message.messageContent instanceof FileMessageContent
-                || message.messageContent instanceof VideoMessageContent);
-        },
-
-        isForwardable(message) {
-            if (message && message.messageContent instanceof SoundMessageContent) {
-                return false;
-            }
-            return true;
-        },
-
-        isFavable(message) {
-            if (!message) {
-                return false;
-            }
-            return [MessageContentType.VOIP_CONTENT_TYPE_START,
-                MessageContentType.CONFERENCE_CONTENT_TYPE_INVITE].indexOf(message.messageContent.type) <= -1;
-        },
-
-        isRecallable(message) {
-            if (message) {
-                if (message.conversation.type === ConversationType.Group) {
-                    let groupInfo = wfc.getGroupInfo(message.conversation.target);
-                    let selfUserId = wfc.getUserId();
-                    if (groupInfo && groupInfo.owner === selfUserId) {
-                        return true;
-                    }
-
-                    let groupMember = wfc.getGroupMember(message.conversation.target, selfUserId);
-                    if (groupMember && [GroupMemberType.Manager, GroupMemberType.Owner].indexOf(groupMember.type) > -1) {
-                        return true;
-                    }
-                }
-                let delta = wfc.getServerDeltaTime();
-                let now = new Date().getTime();
-                if (message.direction === 0 && now - (numberValue(message.timestamp) - delta) < 60 * 1000) {
-                    return true;
-                }
-            }
-            return false;
-        },
-
-        isLocalFile(message) {
-            if (message && isElectron()) {
-                let media = message.messageContent;
-                let localPath = media.localPath;
-                if (localPath) {
-                    return fs.existsSync(localPath);
-                }
-            }
-            return false;
-        },
-
-        isQuotable(message) {
-            if (!message) {
-                return false;
-            }
-            return [MessageContentType.VOIP_CONTENT_TYPE_START,
-                MessageContentType.Voice,
-                MessageContentType.Video,
-                MessageContentType.Composite_Message,
-                MessageContentType.CONFERENCE_CONTENT_TYPE_INVITE].indexOf(message.messageContent.type) <= -1;
-        },
-
-        copy(message) {
-            let content = message.messageContent;
-            if (content instanceof TextMessageContent) {
-                let selectedText = window.getSelection().toString()
-                if (selectedText) {
-                    copyText(selectedText);
-                } else {
-                    copyText(content.content)
-                }
-            } else {
-                copyImg(content.remotePath)
-            }
-        },
-        download(message) {
-            if (isElectron()) {
-                downloadFile(message);
-            } else {
-                if (!store.isDownloadingMessage(message.messageId)) {
-                    downloadFile(message)
-                    store.addDownloadingMessage(message.messageId)
-                } else {
-                    // TODO toast 下载中
-                    console.log('file isDownloading')
-                }
-            }
-        },
-
-        openFile(message) {
-            let file = message.messageContent;
-            shell.openItem(file.localPath);
-        },
-
-        openDir(message) {
-            let file = message.messageContent;
-            shell.showItemInFolder(file.localPath);
-        },
-
-        recallMessage(message) {
-            wfc.recallMessage(message.messageUid, null, null);
-        },
-
-        delMessage(message) {
-            this.$alert({
-                title: ' 删除消息',
-                content: '确定删除消息?',
-                confirmText: '本地删除',
-                cancelText: '远程删除',
-                cancelCallback: () => {
-                    wfc.deleteRemoteMessageByUid(message.messageUid, null, null)
-                },
-                confirmCallback: () => {
-                    wfc.deleteMessage(message.messageId);
-                }
-            })
-        },
-
-        forward(message) {
-            return this.pickConversationAndForwardMessage(ForwardType.NORMAL, [message]);
-        },
-
-        _forward(message) {
-            this.forward(message).catch(() => {
-                // do nothing
-            });
-        },
-
-        quoteMessage(message) {
-            store.quoteMessage(message);
-        },
-
-        // call from child
-        favMessages(messages) {
-            console.log('fav messages');
-            let compositeMessageContent = new CompositeMessageContent();
-            let title = '';
-            let msgConversation = messages[0].conversation;
-            if (msgConversation.type === ConversationType.Single) {
-                let users = store.getUserInfos([wfc.getUserId(), msgConversation.target], '');
-                title = users[0]._displayName + '和' + users[1]._displayName + '的聊天记录';
-            } else {
-                title = '群的聊天记录';
-            }
-            compositeMessageContent.title = title;
-            compositeMessageContent.messages = messages;
-
-            let message = new Message(msgConversation, compositeMessageContent);
-            message.from = wfc.getUserId();
-            this.favMessage(message);
-        },
-
-        favMessage(message) {
-            let favItem = FavItem.fromMessage(message);
-            axios.post('/fav/add', {
-                messageUid: stringValue(favItem.messageUid),
-                type: favItem.favType,
-                convType: favItem.conversation.type,
-                convTarget: favItem.conversation.target,
-                convLine: favItem.conversation.line,
-                origin: favItem.origin,
-                sender: favItem.sender,
-                title: favItem.title,
-                url: favItem.url,
-                thumbUrl: favItem.thumbUrl,
-                data: favItem.data,
-            }, {withCredentials: true})
-                .then(response => {
-                    if (response && response.data && response.data.code === 0) {
-                        this.$notify({
-                            // title: '收藏成功',
-                            text: '收藏成功',
-                            type: 'info'
-                        });
-                    } else {
-                        this.$notify({
-                            // title: '收藏成功',
-                            text: '收藏失败',
-                            type: 'error'
-                        });
-                    }
-                })
-                .catch(err => {
-                    this.$notify({
-                        // title: '收藏失败',
-                        text: '收藏失败',
-                        type: 'error'
-                    });
-
-                })
-        },
-
-        multiSelect(message) {
-            this.toggleMessageMultiSelectionActionView(message);
-        },
-
-        infiniteHandler($state) {
-            console.log('to load more message');
-            store.loadConversationHistoryMessages(() => {
-                console.log('loaded')
-                $state.loaded();
-            }, () => {
-                console.log('complete')
-                $state.complete()
-            });
-        },
-
-        pickConversationAndForwardMessage(forwardType, messages) {
-            return new Promise(((resolve, reject) => {
-                let beforeClose = (event) => {
-                    console.log('Closing...', event, event.params)
-                    // What a gamble... 50% chance to cancel closing
-                    if (event.params.toCreateConversation) {
-                        console.log('to show')
-                        Promise.race([this.createConversationAndForwardMessage(forwardType, messages)])
-                            .then(resolve)
-                            .catch(reject);
-                    } else if (event.params.confirm) {
-                        let conversations = event.params.conversations;
-                        let extraMessageText = event.params.extraMessageText;
-                        store.forwardMessage(forwardType, conversations, messages, extraMessageText)
-                        resolve();
-                    } else {
-                        console.log('cancel')
-                        reject();
-                    }
-                };
-
-                this.$modal.show(
-                    ForwardMessageByPickConversationView,
-                    {
-                        forwardType: forwardType,
-                        messages: messages
-                    }, {
-                        name: 'forward-by-pick-conversation-modal',
-                        width: 600,
-                        height: 480,
-                        clickToClose: false,
-                    }, {
-                        'before-close': beforeClose,
-                    })
-            }));
-        },
-
-        createConversationAndForwardMessage(forwardType, messages) {
-            return new Promise(((resolve, reject) => {
-
-                let beforeClose = (event) => {
-                    console.log('Closing...', event, event.params)
-                    if (event.params.backPickConversation) {
-                        Promise.race([this.pickConversationAndForwardMessage(forwardType, messages)])
-                            .then(resolve)
-                            .catch(reject);
-                    } else if (event.params.confirm) {
-                        let users = event.params.users;
-                        let extraMessageText = event.params.extraMessageText;
-                        store.forwardByCreateConversation(forwardType, users, messages, extraMessageText)
-                        resolve();
-                    } else {
-                        console.log('cancel')
-                        reject();
-                    }
-                };
-                this.$modal.show(
-                    ForwardMessageByCreateConversationView,
-                    {
-                        forwardType: forwardType,
-                        messages: messages,
-                        users: this.sharedContactState.friendList,
-                    }, {
-                        name: 'forward-by-create-conversation-modal',
-                        width: 600,
-                        height: 480,
-                        clickToClose: false,
-                    }, {
-                        'before-close': beforeClose,
-                    });
-            }));
-        },
-        playVoice(message) {
-            if (amr) {
-                amr.stop();
-            }
-            amr = new BenzAMRRecorder();
-            let voice = message.messageContent;
-            amr.initWithUrl(voice.remotePath).then(() => {
-                message._isPlaying = true;
-                amr.play();
-            });
-            amr.onEnded(() => {
-                message._isPlaying = false;
-                store.playVoice(null)
-            })
-        },
-        mentionMessageSenderTitle(message) {
-            if (!message) {
-                return ''
-            }
-            let displayName = wfc.getGroupMemberDisplayName(message.conversation.target, message.from);
-            return '@' + displayName;
-        },
-
-        mentionMessageSender(message) {
-            this.$refs.messageInputView.mention(message.conversation.target, message.from);
-        }
-    },
-
-    mounted() {
-        console.log('conversationView mounted', this.sharedConversationState, this.sharedConversationState.currentConversationMessageList);
-        // this.popupItem = this.$refs['setting'];
-        // document.addEventListener('mouseup', this.dragEnd);
-        // document.addEventListener('mousemove', this.drag);
-
-        // this.$on('openMessageContextMenu', (event, message) => {
-        //     this.$refs.menu.open(event, message);
-        // });
-        //
-        // this.$on('openMessageSenderContextMenu', (event, message) => {
-        //     // 目前只支持群会话里面,消息发送者右键@
-        //     if (message.conversation.type === ConversationType.Group) {
-        //         this.$refs.messageSenderContextMenu.open(event, message);
-        //     }
-        // });
-
-        // this.$eventBus.$on('send-file', args => {
-        //     let fileMessageContent = new FileMessageContent(null, args.remoteUrl, args.name, args.size);
-        //     let message = new Message(null, fileMessageContent);
-        //     this.forward(message)
-        // });
-        //
-        // this.$eventBus.$on('forward-fav', args => {
-        //     let favItem = args.favItem;
-        //     let message = favItem.toMessage();
-        //     this.forward(message);
-        // });
-        //
-        // localStorageEmitter.on('inviteConferenceParticipant', (ev, args) => {
-        //     if (isElectron()) {
-        //         remote.getCurrentWindow().focus();
-        //     }
-        //     let payload = args.messagePayload;
-        //     let messageContent = Message.messageContentFromMessagePayload(payload, wfc.getUserId());
-        //     let message = new Message(null, messageContent);
-        //     this.forward(message)
-        //         .then(() => {
-        //             ev.reply('inviteConferenceParticipantDone')
-        //         })
-        //         .catch(() => {
-        //             ev.reply('inviteConferenceParticipantCancel')
-        //         });
-        // });
-    },
-
-    beforeDestroy() {
-        document.removeEventListener('mouseup', this.dragEnd);
-        document.removeEventListener('mousemove', this.drag);
-        // this.$eventBus.$off('send-file')
-        // this.$eventBus.$off('forward-fav')
-    },
-
-    updated() {
-        if (!this.sharedConversationState.currentConversationInfo) {
-            return;
-        }
-        // this.popupItem = this.$refs['setting'];
-        // refer to http://iamdustan.com/smoothscroll/
-        console.log('conversationView updated', this.sharedConversationState.shouldAutoScrollToBottom)
-        if (this.sharedConversationState.shouldAutoScrollToBottom) {
-            let messageListElement = this.$refs['conversationMessageList'];
-            messageListElement.scroll({top: messageListElement.scrollHeight, left: 0, behavior: 'auto'})
-        } else {
-            // 用户滑动到上面之后,收到新消息,不自动滑动到最下面
-        }
-        if (this.sharedConversationState.currentConversationInfo) {
-            if (!this.sharedMiscState.isPageHidden) {
-                let unreadCount = this.sharedConversationState.currentConversationInfo.unreadCount;
-                if (unreadCount.unread > 0) {
-                    store.clearConversationUnreadStatus(this.sharedConversationState.currentConversationInfo.conversation);
-                }
-            }
-        }
-
-        if (this.conversationInfo && this.sharedConversationState.currentConversationInfo && !this.conversationInfo.conversation.equal(this.sharedConversationState.currentConversationInfo.conversation)) {
-            this.showConversationInfo = false;
-        }
-        this.conversationInfo = this.sharedConversationState.currentConversationInfo;
-    },
-
-    computed: {
-        conversationTitle() {
-            let info = this.sharedConversationState.currentConversationInfo;
-            return info.conversation._target._displayName;
-        },
-        targetUserOnlineStateDesc() {
-            let info = this.sharedConversationState.currentConversationInfo;
-            return info.conversation._targetOnlineStateDesc;
-        },
-        loadingIdentifier() {
-            let conversation = this.sharedConversationState.currentConversationInfo.conversation;
-            return conversation.type + '-' + conversation.target + '-' + conversation.line;
-        },
-        currentVoiceMessage() {
-            let voice = this.sharedConversationState.currentVoiceMessage;
-            if (voice) {
-                this.playVoice(voice);
-            } else {
-                if (amr) {
-                    amr.stop();
-                }
-            }
-            return null;
-        }
-    },
-
-    directives: {
-        ClickOutside
-    },
-};
-</script>
-
-<style lang="css" scoped>
-.conversation-empty-container {
-    height: 100%;
-    width: 100%;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    background-color: white;
-    border-top-right-radius: var(--main-border-radius);
-    border-bottom-right-radius: var(--main-border-radius);
-    /*border-left: 1px solid #e6e6e6;*/
-}
-
-.conversation-empty-container h1 {
-    font-size: 17px;
-    font-weight: normal;
-}
-
-.title-container {
-    width: 100%;
-    height: 60px;
-    display: flex;
-    padding: 0 0 0 20px;
-    justify-content: space-between;
-    align-items: center;
-    background-color: #f5f5f5;
-    border-bottom: 1px solid #e6e6e6;
-    border-top-right-radius: var(--main-border-radius);
-    position: relative;
-}
-
-
-.title-container h1 {
-    font-size: 16px;
-    font-weight: normal;
-}
-
-.title-container a {
-    text-decoration: none;
-    padding: 15px;
-    color: #181818;
-}
-
-.title-container a:active {
-    color: #d6d6d6;
-}
-
-.conversation-container {
-    height: 100%;
-    display: flex;
-    flex-direction: column;
-}
-
-.conversation-container header {
-    border-top-right-radius: var(--main-border-radius);
-}
-
-.conversation-container header {
-    width: 100%;
-    height: 60px;
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    background-color: #f5f5f5;
-    border-bottom: 1px solid #e6e6e6;
-}
-
-.conversation-content-container {
-    flex: 1;
-    height: calc(100% - 60px);
-    position: relative;
-    overflow-y: auto;
-    display: flex;
-    flex-direction: column;
-    background-color: #f3f3f3;
-    border-bottom-right-radius: var(--main-border-radius);
-}
-
-.conversation-content-container .drag-drop-container {
-    position: absolute;
-    background-color: #f2f2f2a5;
-    top: 0;
-    left: 0;
-    width: 100%;
-    z-index: 100;
-    height: 100%;
-    padding: 20px 15px 15px 15px;
-}
-
-.conversation-content-container .drag-drop {
-    border: 2px dashed #b2b2b2;
-    height: 100%;
-    width: 100%;
-    border-radius: 5px;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-}
-
-.conversation-content-container .drag-drop p {
-    padding-bottom: 100px;
-}
-
-.conversation-message-list {
-    flex: 1 1 auto;
-    overflow: auto;
-}
-
-.conversation-message-list ul {
-    list-style: none;
-}
-
-/*.handler {*/
-/*  height: 1px;*/
-/*  background-color: #e2e2e2;*/
-/*}*/
-
-.inputting-container {
-    display: flex;
-    padding: 10px 20px;
-    align-items: center;
-}
-
-.inputting-container .avatar {
-    width: 40px;
-    height: 40px;
-    border-radius: 3px;
-    margin-right: 20px;
-}
-
-.divider-handler::before {
-    cursor: row-resize;
-    content: '';
-    display: block;
-    width: 100%;
-    height: 3px;
-    border-top: 1px solid #e2e2e2;
-    margin: 0 auto;
-}
-
-.user-online-status {
-    color: gray;
-    font-size: 10px;
-}
-
-.message-input-container {
-    height: 200px;
-    min-height: 200px;
-}
-
-.conversation-info-container {
-    display: none;
-    width: 250px;
-    height: 100%;
-    top: 0;
-    right: 0;
-    position: absolute;
-    background-color: #ffffffe5;
-    backdrop-filter: blur(6px);
-    border-left: 1px solid #e6e6e6;
-}
-
-.conversation-info-container.active {
-    display: flex;
-}
-</style>

+ 94 - 59
pages/conversation/ConversationView.vue

@@ -6,9 +6,9 @@
         <view v-else ref="conversationContentContainer" class="conversation-content-container"
               :dummy_just_for_reactive="currentVoiceMessage"
         >
-            <uni-list ref="conversationMessageList" class="message-list" :border="false">
-                <block v-for="(message) in sharedConversationState.currentConversationMessageList"
-                       :key="message.messageId">
+            <uni-list ref="conversationMessageList" class="message-list" :border="false" @scroll="onScroll">
+                <view v-for="(message) in sharedConversationState.currentConversationMessageList"
+                      :key="message.messageId">
                     <!--todo 不同的消息类型 notification in out-->
 
                     <NotificationMessageContentView :message="message" v-if="isNotificationMessage(message)"/>
@@ -16,15 +16,19 @@
                     <NormalOutMessageContentView
                         @click.native.capture="sharedConversationState.enableMessageMultiSelection? clickMessageItem($event, message) : null"
                         :message="message"
+                        @longpress.native="onLongPressMessage($event, message)"
                         v-else-if="message.direction === 0"/>
                     <NormalInMessageContentView
                         @click.native.capture="sharedConversationState.enableMessageMultiSelection ? clickMessageItem($event, message) : null"
                         :message="message"
+                        @longpress.native="onLongPressMessage($event, message)"
                         v-else/>
-                </block>
+                </view>
             </uni-list>
-<!--            <view v-show="!sharedConversationState.enableMessageMultiSelection"-->
-<!--                  class="viewider-handler"></view>-->
+            <!--            <view v-show="!sharedConversationState.enableMessageMultiSelection"-->
+            <!--                  class="viewider-handler"></view>-->
+            <chunLei-popups v-model="showContextMenu" :popData="contextMenuItems" @tapPopup="tapPopup" :x="x" :y="y" direction="column" theme="dark" :triangle="false" placement="bottom-start" dynamic>
+            </chunLei-popups>
             <MessageInputView :conversationInfo="sharedConversationState.currentConversationInfo"
                               v-show="!sharedConversationState.enableMessageMultiSelection"
                               class="message-input-container"
@@ -43,46 +47,6 @@
             <!--                    v-bind:class="{ active: showConversationInfo }"-->
             <!--                    class="conversation-info-container"-->
             <!--                />-->
-
-            <!--                <vue-context ref="menu" v-slot="{data:message}" :close-on-scroll="true" v-on:close="onMenuClose">-->
-            <!--                    &lt;!&ndash;          更多menu item&ndash;&gt;-->
-            <!--                    <li v-if="isCopyable(message)">-->
-            <!--                        <a @click.prevent="copy(message)">{{ $t('common.copy') }}</a>-->
-            <!--                    </li>-->
-            <!--                    <li v-if="isDownloadAble(message)">-->
-            <!--                        <a @click.prevent="download(message)">{{ $t('common.save') }}</a>-->
-            <!--                    </li>-->
-            <!--                    <li>-->
-            <!--                        <a @click.prevent="delMessage(message)">{{ $t('common.delete') }}</a>-->
-            <!--                    </li>-->
-            <!--                    <li v-if="isForwardable(message)">-->
-            <!--                        <a @click.prevent="_forward(message)">{{ $t('common.forward') }}</a>-->
-            <!--                    </li>-->
-            <!--                    <li v-if="isFavable(message)">-->
-            <!--                        <a @click.prevent="favMessage(message)">{{ $t('common.fav') }}</a>-->
-            <!--                    </li>-->
-            <!--                    <li v-if="isQuotable(message)">-->
-            <!--                        <a @click.prevent="quoteMessage(message)">{{ $t('common.quote') }}</a>-->
-            <!--                    </li>-->
-            <!--                    <li>-->
-            <!--                        <a @click.prevent="multiSelect(message)">{{ $t('common.multi_select') }}</a>-->
-            <!--                    </li>-->
-            <!--                    <li v-if="isRecallable(message)">-->
-            <!--                        <a @click.prevent="recallMessage(message)">{{ $t('common.recall') }}</a>-->
-            <!--                    </li>-->
-            <!--                    <li v-if="isLocalFile(message)">-->
-            <!--                        <a @click.prevent="openFile(message)">{{ $t('common.open') }}</a>-->
-            <!--                    </li>-->
-            <!--                    <li v-if="isLocalFile(message)">-->
-            <!--                        <a @click.prevent="openDir(message)">{{ $t('common.open_dir') }}</a>-->
-            <!--                    </li>-->
-            <!--                </vue-context>-->
-            <!--                <vue-context ref="messageSenderContextMenu" v-slot="{data: message}" :close-on-scroll="true" v-on:close="onMessageSenderContextMenuClose">-->
-            <!--                    &lt;!&ndash;          更多menu item,比如添加到通讯录等&ndash;&gt;-->
-            <!--                    <li>-->
-            <!--                        <a @click.prevent="mentionMessageSender(message)">{{ mentionMessageSenderTitle(message) }}</a>-->
-            <!--                    </li>-->
-            <!--                </vue-context>-->
         </view>
     </view>
 </template>
@@ -91,7 +55,6 @@
 import SingleConversationInfoView from "@/pages/conversation/SingleConversationInfoView";
 import GroupConversationInfoView from "@/pages/conversation/GroupConversationInfoView";
 import MessageInputView from "@/pages/conversation/MessageInputView";
-// import ClickOutside from 'vue-click-outside'
 import NormalOutMessageContentView from "@/pages/conversation/message/NormalOutMessageContentContainerView";
 import NormalInMessageContentView from "@/pages/conversation/message/NormalInMessageContentContainerView";
 import NotificationMessageContentView from "@/pages/conversation/message/NotificationMessageContentView";
@@ -101,12 +64,10 @@ import TextMessageContent from "@/wfc/messages/textMessageContent";
 import store from "@/store";
 import wfc from "@/wfc/client/wfc";
 import {numberValue, stringValue} from "@/wfc/util/longUtil";
-// import InfiniteLoading from 'vue-infinite-loading';
 import MultiSelectActionView from "@/pages/conversation/MessageMultiSelectActionView";
 // import ForwardMessageByPickConversationView from "@/pages/conversation/message/forward/ForwardMessageByPickConversationView";
 // import ForwardMessageByCreateConversationView from "@/pages/conversation/message/forward/ForwardMessageByCreateConversationView";
 import ForwardType from "@/pages/conversation/message/forward/ForwardType";
-// import localStorageEmitter from "../../../ipc/localStorageEmitter";
 import {fs, isElectron, shell} from "@/platform";
 import FileMessageContent from "@/wfc/messages/fileMessageContent";
 import ImageMessageContent from "@/wfc/messages/imageMessageContent";
@@ -124,12 +85,10 @@ import GroupMemberType from "@/wfc/model/groupMemberType";
 import CompositeMessageContent from "@/wfc/messages/compositeMessageContent";
 import ConnectionStatus from "../../wfc/client/connectionStatus";
 import UniRefresh from "../../components/uni-list/uni-refresh";
-// import UniList from "../../components/uni-list/uni-list";
 
 var amr;
 export default {
     components: {
-        // UniList,
         UniRefresh,
         MultiSelectActionView,
         NotificationMessageContentView,
@@ -139,7 +98,6 @@ export default {
         MessageInputView,
         GroupConversationInfoView,
         SingleConversationInfoView,
-        // InfiniteLoading,
     },
     // props: ["conversation"],
     data() {
@@ -155,7 +113,10 @@ export default {
             saveMessageListViewFlexGrow: -1,
 
             dragAndDropEnterCount: 0,
-
+            showContextMenu: false,
+            x: 0,
+            y: 0,
+            contextMenuItems: [{title: '复制', disabled: true}, {title: '转发'}, {title: '回复'}, {title: '删除'}]
         };
     },
 
@@ -167,6 +128,9 @@ export default {
         });
     },
 
+    onLoad() {
+    },
+
     methods: {
         toggleConversationInfo() {
             this.showConversationInfo = !this.showConversationInfo;
@@ -226,8 +190,9 @@ export default {
             // hide message context menu
             // this.$refs.menu && this.$refs.menu.close();
 
+            console.log('onscroll');
+            this.showContextMenu = false;
             // 当用户往上滑动一段距离之后,收到新消息,不自动滚到到最后
-            // console.log('onscroll');
             if (e.target.scrollHeight > e.target.clientHeight + e.target.scrollTop + e.target.clientHeight / 2) {
                 store.setShouldAutoScrollToBottom(false)
             } else {
@@ -544,6 +509,72 @@ export default {
 
         mentionMessageSender(message) {
             this.$refs.messageInputView.mention(message.conversation.target, message.from);
+        },
+
+
+        onLongPressMessage(e, message) {
+            this.x = e.touches[0].clientX;
+            this.y = e.touches[0].clientY;
+
+            this.contextMenuItems = [];
+            if (this.isCopyable(message)) {
+                this.contextMenuItems.push({
+                    title: "复制",
+                    tag: 'copy',
+                })
+            }
+            if (this.isDownloadAble(message)) {
+                this.contextMenuItems.push({
+                    title: "下载",
+                    tag: 'copy'
+                })
+            }
+            this.contextMenuItems.push({
+                title: '删除',
+                tag: 'delete',
+            })
+            if (this.isForwardable(message)){
+                this.contextMenuItems.push({
+                    title: '转发',
+                    tag: 'forward',
+                })
+            }
+            this.showContextMenu = true;
+
+            // <!--                    <li v-if="isCopyable(message)">-->
+            //     <!--                        <a @click.prevent="copy(message)">{{ $t('common.copy') }}</a>-->
+            //     <!--                    </li>-->
+            //     <!--                    <li v-if="isDownloadAble(message)">-->
+            //     <!--                        <a @click.prevent="download(message)">{{ $t('common.save') }}</a>-->
+            //     <!--                    </li>-->
+            //     <!--                    <li>-->
+            //     <!--                        <a @click.prevent="delMessage(message)">{{ $t('common.delete') }}</a>-->
+            //     <!--                    </li>-->
+            //     <!--                    <li v-if="isForwardable(message)">-->
+            //     <!--                        <a @click.prevent="_forward(message)">{{ $t('common.forward') }}</a>-->
+            //     <!--                    </li>-->
+            //     <!--                    <li v-if="isFavable(message)">-->
+            //     <!--                        <a @click.prevent="favMessage(message)">{{ $t('common.fav') }}</a>-->
+            //     <!--                    </li>-->
+            //     <!--                    <li v-if="isQuotable(message)">-->
+            //     <!--                        <a @click.prevent="quoteMessage(message)">{{ $t('common.quote') }}</a>-->
+            //     <!--                    </li>-->
+            //     <!--                    <li>-->
+            //     <!--                        <a @click.prevent="multiSelect(message)">{{ $t('common.multi_select') }}</a>-->
+            //     <!--                    </li>-->
+            //     <!--                    <li v-if="isRecallable(message)">-->
+            //     <!--                        <a @click.prevent="recallMessage(message)">{{ $t('common.recall') }}</a>-->
+            //     <!--                    </li>-->
+            //     <!--                    <li v-if="isLocalFile(message)">-->
+            //     <!--                        <a @click.prevent="openFile(message)">{{ $t('common.open') }}</a>-->
+            //     <!--                    </li>-->
+            //     <!--                    <li v-if="isLocalFile(message)">-->
+            //     <!--                        <a @click.prevent="openDir(message)">{{ $t('common.open_dir') }}</a>-->
+            //     <!--                    </li>-->
+        },
+
+        tapPopup(t) {
+            console.log('xxx tapPopup', t)
         }
     },
 
@@ -562,7 +593,7 @@ export default {
             setTimeout(() => {
                 uni.pageScrollTo({
                     scrollTop: 999999,
-                    duration:10,
+                    duration: 10,
                 });
                 this.$forceUpdate()
 
@@ -627,11 +658,13 @@ export default {
 }
 
 .conversation-content-container {
-    /*position: relative;*/
-    /*display: flex;*/
-    /*flex-direction: column;*/
+    position: relative;
+    display: flex;
+    height: 100%;
+    overflow: hidden;
+    flex-direction: column;
     /*background-color: #f3f3f3;*/
-    padding: 0 12px;
+    /*padding: 0 12px;*/
     padding-bottom: 112rpx;
 }
 
@@ -648,6 +681,8 @@ export default {
 
 .message-list {
     /*padding-bottom: 112rpx;*/
+    flex: 1 1 auto;
+    overflow: auto;
 }
 
 </style>

+ 209 - 0
pages/conversation/contextMenu.vue

@@ -0,0 +1,209 @@
+<template>
+  <view @touchmove.stop.prevent="moveHandle('touchmove')" @click="moveHandle('click')" v-if="show">
+    <view class="openTool-wx" :animation="animationData">
+      <view class="openTool-wx-list" v-if="data">
+        <view class="openTool-wx-list-item" @click="copyText(data.content)" v-if="data.msgType == 'TEXT'">
+          <view class="openTool-wx-list-item-icon">
+            <view class="wxfont wxcopy"></view>
+          </view>
+          <view class="text">复制</view>
+        </view>
+        <view class="openTool-wx-list-item" @click="shoucang" v-if="data.msgType !== 'TRTC_VOICE_END'&&data.msgType !== 'TRTC_VIDEO_END'">
+          <view class="openTool-wx-list-item-icon">
+            <view class="wxfont shoucang"></view>
+          </view>
+          <view class="text">收藏</view>
+        </view>
+        <view class="openTool-wx-list-item" @click="shanchu">
+          <view class="openTool-wx-list-item-icon">
+            <view class="wxfont wxdelete"></view>
+          </view>
+          <view class="text">删除</view>
+        </view>
+      </view>
+      <view class="openTool-wx-icon"></view>
+    </view>
+    <view class="openTool-wx-model"></view>
+  </view>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      show: false,
+      animationData: {}
+    };
+  },
+  props: {
+    data: {
+      type: [Object, String]
+    },
+    talkTo: {
+      type: [Object, String, Number]
+    },
+    itemKey: {
+      type: [Object, String, Number]
+    },
+    list: {
+      type: Array,
+      default() {
+        return [{}];
+      }
+    }
+  },
+  onShow() {
+
+  },
+  computed: {
+    chatWindowData() {
+      return this.$store.state.chatDatalist[this.talkTo.userId]
+    }
+  },
+  mounted() {
+    var animation = uni.createAnimation({
+      duration: 300,
+      timingFunction: 'linear'
+    });
+    this.animation = animation;
+  },
+  methods: {
+    copyText(e) {
+      uni.setClipboardData({
+        data: e,
+        success: function () {
+          uni.showToast({
+            title: '复制成功',
+            icon: 'none',
+            position: 'bottom'
+          })
+        }
+      });
+    },
+    shoucang() {
+      this.$http.request({
+        url: '/collect/add',
+        method: 'POST',
+        data: JSON.stringify({
+          collectType: this.data.msgType,
+          content: this.data.content
+        }),
+        success: (res) => {
+          if (res.data.code == 200) {
+            uni.showToast({
+              title: '收藏成功',
+              icon: 'none'
+            })
+          }
+        }
+      });
+    },
+    shanchu() {
+      this.chatWindowData.splice(this.itemKey, 1);
+      this.$store.dispatch('updateChatById', {userId: this.data.userId, data: this.chatWindowData});
+    },
+    showAnimation() {
+        console.log('showAnimation')
+      this.animation.opacity(1).step();
+      this.animationData = this.animation.export();
+    },
+    hideAnimation() {
+      this.animation.opacity(0).step();
+      this.animationData = this.animation.export();
+    },
+    moveHandle(e) {
+      this.hiddenTab()
+    },
+    showTab() {
+      this.show = true
+        console.log('showTab')
+      setTimeout(() => {
+        this.showAnimation()
+      }, 30)
+    },
+    hiddenTab() {
+      this.show = false
+      this.hideAnimation()
+    },
+  }
+};
+</script>
+<style scoped>
+.openTool-wx {
+    height: 100rpx;
+    background: red;
+  width: 552rpx;
+  display: flex;
+  flex-direction: column;
+  flex-wrap: wrap;
+  opacity: 0;
+  position: relative;
+  z-index: 200;
+}
+
+.openTool-wx-model {
+  background-color: rgba(0, 0, 0, 0);
+  position: fixed;
+  top: 0;
+  bottom: 0;
+  right: 0;
+  left: 0;
+  z-index: 1;
+}
+
+.openTool-wx-icon {
+  width: 100px;
+  height: 100px;
+  border: 5px solid transparent;
+  border-top-color: #4C4C4C;
+  margin: 0 auto;
+  margin-bottom: -5px;
+}
+
+.openTool-wx-list {
+  width: 100%;
+  padding: 24rpx;
+  box-sizing: border-box;
+  background-color: #4C4C4C;
+  border-radius: 10rpx;
+  display: flex;
+  flex-direction: row;
+  justify-content: space-around;
+  flex-wrap: wrap;
+}
+
+.openTool-wx-list-item {
+  margin: 12rpx;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+
+.openTool-wx-list-item-icon {
+  color: #fff;
+  margin-bottom: 6rpx;
+}
+
+.openTool-wx-list-item-icon .wxfont {
+  font-size: 42rpx;
+}
+
+.openTool-wx-list-item .text {
+  color: #fff;
+  font-size: 28rpx;
+  border-bottom: 1px #535353 solid;
+  flex: 1;
+}
+
+.openTool-wx-list-item:nth-last-child(1) .text {
+  border: none;
+}
+
+.zfb-tk-msgright .openTool-wx-icon {
+  margin-right: 24rpx;
+}
+
+.zfb-tk-msgleft .openTool-wx-icon {
+  margin-left: 24rpx;
+}
+</style>

+ 1 - 9
pages/conversation/message/NormalInMessageContentContainerView.vue

@@ -10,7 +10,6 @@
                            v-model="sharedPickState.messages"/>
                     <img
                         @click="onClickUserPortrait(message.from)"
-                        @contextmenu.prevent="openMessageSenderContextMenu($event, message)"
                         class="avatar"
                         draggable="false"
                         :src="message._from.portrait" alt="">
@@ -23,7 +22,7 @@
                             <MessageContentContainerView class="message-content-container"
                                                          v-bind:class="{highlight:highLight}"
                                                          :message="message"
-                                                         @contextmenu.prevent.native="openMessageContextMenu($event, message)"/>
+                                                         />
                             <!--                            <LoadingView v-if="isDownloading"/>-->
                         </div>
                         <QuoteMessageView style="padding: 5px 0; max-width: 80%"
@@ -65,13 +64,6 @@ export default {
         onClickUserPortrait(userId) {
             wfc.getUserInfo(userId, true);
         },
-        openMessageContextMenu(event, message) {
-            this.$parent.$emit('openMessageContextMenu', event, message)
-            this.highLight = true;
-        },
-        openMessageSenderContextMenu(event, message) {
-            this.$parent.$emit('openMessageSenderContextMenu', event, message)
-        },
     },
     mounted() {
         if (this.message.messageContent.quoteInfo) {

+ 1 - 19
pages/conversation/message/content/TextMessageContentView.vue

@@ -1,7 +1,7 @@
 <template>
     <div class="text-message-container"
          v-bind:class="{out:message.direction === 0}">
-        <p class="text" v-html="this.textContent" @mouseup="mouseUp" @contextmenu="preventContextMenuTextSelection"></p>
+        <p class="text" v-html="this.textContent" ></p>
     </div>
 </template>
 
@@ -26,24 +26,6 @@ export default {
     },
 
     methods: {
-        mouseUp(event) {
-            let selection = window.getSelection().toString();
-            this.textSelected = !!selection;
-
-        },
-        preventContextMenuTextSelection(event) {
-            if (!this.textSelected) {
-                if (window.getSelection) {
-                    if (window.getSelection().empty) {  // Chrome
-                        window.getSelection().empty();
-                    } else if (window.getSelection().removeAllRanges) {  // Firefox
-                        window.getSelection().removeAllRanges();
-                    }
-                } else if (document.selection) {  // IE?
-                    document.selection.empty();
-                }
-            }
-        }
     },
 
     computed: {

+ 15 - 5
pages/conversationList/ConversationListView.vue

@@ -1,6 +1,6 @@
 <template>
-    <view class="conversation-list">
-        <uni-list :border="true">
+    <view class="conversation-list" @scroll="onScroll">
+        <uni-list :border="true" @scroll="onScroll">
             <view
                 @click="showConversation(conversationInfo)"
                 v-for="conversationInfo in sharedConversationState.conversationInfoList"
@@ -9,11 +9,11 @@
                           top:conversationInfo.isTop,
                           highlight:contextMenuConversationInfo && contextMenuConversationInfo.conversation.equal(conversationInfo.conversation) }"
             >
-                <ConversationItemView :conversation-info="conversationInfo"/>
+                <ConversationItemView :conversation-info="conversationInfo" @contextmenu.prevent.native="longpressItem(conversationInfo)"/>
             </view>
         </uni-list>
 
-<!--        <vue-context ref="menu" v-slot="{data:conversationInfo}" v-on:close="onConversationItemContextMenuClose">-->
+        <!--        <vue-context ref="menu" v-slot="{data:conversationInfo}" v-on:close="onConversationItemContextMenuClose">-->
 <!--            <li>-->
 <!--                <a @click.prevent="setConversationTop(conversationInfo)">{{-->
 <!--                        conversationInfo && conversationInfo.isTop ? $t('conversation.cancel_sticky_top') : $t('conversation.sticky_top')-->
@@ -116,6 +116,16 @@ export default {
         markConversationAsUnread(conversation) {
             wfc.markConversationAsUnread(conversation, true);
         },
+        longpressItem(conversationInfo){
+            console.log('xxxxx, lonp', conversationInfo, this.$refs.popup.open);
+            // let el = this.$refs['contextMenu-' + message.messageId][0]
+            // // console.log('xxxx', this.$refs, el, el.length, el.showTab)
+            // el.showTab();
+        },
+
+        onScroll(){
+            // TODO
+        }
     },
     activated() {
         this.scrollActiveElementCenter();
@@ -131,7 +141,7 @@ export default {
 <style lang="css" scoped>
 
 .conversation-list {
-    height: 100%;
+    height: 100vh;
     overflow: auto;
 }