Browse Source

'0812-1556-c01'

zory 1 month ago
parent
commit
9bdd1afe90

File diff suppressed because it is too large
+ 76 - 0
奥莱优品/components/chat/emoji.vue


+ 101 - 0
奥莱优品/components/chat/more.vue

@@ -0,0 +1,101 @@
+<template>
+	<view class="more" :style="{ height: value ? '430rpx' : '0px' }">
+		<view class="flex_r more-list">
+			<view class="flex_c_c more-item" v-for="(item, index) in list" :key="index" @click="onClick(item)">
+				<view class="icon_ more-item-icon">
+					<image class="img" :src="item.icon" mode="aspectFill"></image>
+				</view>
+				<view class="text_26" style="color: #686868">
+					{{ item.title }}
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+export default {
+	props: {
+		value: {
+			type: Boolean,
+			default: false
+		}
+	},
+	// #4c4c4c
+	data() {
+		return {
+			isShow: false,
+			list: [
+				{
+					type: 'img',
+					icon: 'https://jymini.oss-cn-guangzhou.aliyuncs.com/mini/pic.svg',
+					title: '照片'
+				},
+				{
+					type: 'order',
+					icon: 'https://jymini.oss-cn-guangzhou.aliyuncs.com/mini/order.svg',
+					title: '订单'
+				},
+				// {
+				// 	type: 'video',
+				// 	icon: 'https://jymini.oss-cn-guangzhou.aliyuncs.com/mini/video.svg',
+				// 	title: '视频'
+				// }
+			]
+		};
+	},
+	created() {},
+	watch: {
+		value: {
+			handler: function (newV) {
+				this.isShow = newV;
+			},
+			immediate: true
+		}
+	},
+	methods: {
+		onClick(item) {
+			this.$emit('onMore', item);
+		}
+	}
+};
+</script>
+
+<style lang="scss" scoped>
+.more {
+	position: relative;
+	box-sizing: border-box;
+	width: 100%;
+	background-color: #f6f6f6;
+	overflow: hidden;
+	transition: all 0.2s;
+	.more-line {
+		position: absolute;
+		top: 0;
+		left: 0;
+		right: 0;
+	}
+	.more-list {
+		box-sizing: border-box;
+		padding: 20rpx;
+		width: 100%;
+		height: 370rpx;
+		flex-wrap: wrap;
+	}
+	.more-item {
+		width: 25%;
+		height: 190rpx;
+		.more-item-icon {
+			width: 120rpx;
+			height: 120rpx;
+			background-color: #fff;
+			border-radius: 30rpx;
+			margin-bottom: 10rpx;
+			.img {
+				width: 50%;
+				height: 50%;
+			}
+		}
+	}
+}
+</style>

+ 4 - 0
奥莱优品/main.js

@@ -1,4 +1,8 @@
 import App from './App'
+
+
+import store from '@/store/index.js'; // 引入vuex
+Vue.prototype.$store = store
 
 import halfLogin from './components/login/halfScreen'
 Vue.component('half-login',halfLogin)

+ 377 - 8
奥莱优品/pages/service/chat.vue

@@ -1,27 +1,253 @@
 <template>
-	<view class="content">
-		<scroll-view class="chat-body" scroll-y scroll-with-animation>
-
-		</scroll-view>
+	<view class="content" @touchmove="touchmove">
+		<scroll-view class="chat-body" scroll-y scroll-with-animation :scroll-top="scrollTop" scroll-with-animation @scroll="scroll" @scrolltoupper="scrolltoupper" @scrolltolower="scrolltolower" upper-threshold="80" :scroll-into-view="scrollIntoViewId" refresher-background="transparent">
+			<view class="msgLoading" v-if="msgData.flag">数据加载中...</view>
+			<view class="scroll-view-msg" style="padding: 30rpx 30rpx;">
+				<template v-for="(item, index) in msgData.list">
+					<view class="msgContent" :id="'msg-' + item.messageId">
+						<view class="text_26 color__ time">
+							{{ renderMessageDate(item, index) }}
+						</view>
+						<view class="message" :class="[item.userType]">
+							<image :src="item.avatar" v-if="item.userType === 'friend'" class="avatar" mode="widthFix"></image>
+							<view class="message-con">
+								<view v-if="item.msgType == 'text'">
+									<view v-html="renderTextMessage(item.content)"></view>
+								</view>
+							</view>
+							<image :src="item.avatar" v-if="item.userType === 'self'" class="avatar" mode="widthFix"></image>
+						</view>
+					</view>
+				</template>
+			</view>
+		</scroll-view>
+		<view class="tool">
+			<view class="tool-bar">
+				<view class="bar-item">
+					<image src="https://jymini.oss-cn-guangzhou.aliyuncs.com/mini/order.svg"></image>
+					<view class="name">我的订单</view>
+				</view>
+				<view class="bar-item">
+					<image src="https://jymini.oss-cn-guangzhou.aliyuncs.com/mini/order.svg"></image>
+					<view class="name">转人工</view>
+				</view>
+			</view>
+			<view class="tool-option">
+				<view class="input-text">
+					<textarea class="input" placeholder="输入点什么呢..." auto-height="true" confirm-type="send" type="text"
+						:maxlength="-1" :adjust-position="false" v-model="text" confirm-hold
+						:show-confirm-bar="false" @confirm="sendingText" @keyboardheightchange="keyboardheightchange" />
+				</view>
+				<view class="check-img">
+					<view class="check-icon" @click="tapEmoji"><image src="@/static/image/face.svg" mode="aspectFill"></image></view>
+					<view class="check-icon" @click="tapMore"><image src="@/static/image/more.svg" mode="aspectFill"></image></view>
+				</view>
+			</view>
+		</view>
+		<template v-if="keyboardHeight>0">
+			<view class="keyboardheight" :style="{ height: keyboardHeight + 'px' }"></view>
+		</template>
+		<emoji v-model="isEmoji" @onEmoji="onEmoji" @deleteFn="deleteFn" @sendingText="sendingText" @sendingEmojiPack="sendingEmojiPack"></emoji>
+		<more v-model="isMore" @onMore="sendingMore"></more>
 	</view>
 </template>
 
 <script>
-var app;
-export default {
+var app;
+let cursor = 0; //输入框光标
+import { mapState } from 'vuex';
+import {
+	show,
+	formatDate,
+	throttle,
+	openimg,
+	getLocation,
+	to as tofn
+} from '@/utils/js/index.js';
+import { getHistoryMsg } from "@/utils/js/history-msg.js";
+
+import emoji from '@/components/chat/emoji';
+import more from '@/components/chat/more';
+import { EmojiDecoder, emojiMap } from '@/utils/js/EmojiDecoder.js';
+const emojiUrl = 'https://imgcache.qq.com/open/qcloud/tim/assets/emoji/';
+const decoder = new EmojiDecoder(emojiUrl, emojiMap);
+
+export default {
+	components: {
+		emoji,more
+	},
 	data() {
 		return {
-
+			scrollIntoViewId:"",
+			keyboardHeight:0,
+			isEmoji:false,
+			isMore:false,
+			isKeyboard:false,
+			text:"",
+			scrollTop:0,
+			msgData: {
+				list:[],
+				allLoaded:false, // 请求开关
+				rows:20,	//每页数量
+				page:1,	//页码
+				flag:true,	// 请求开关
+			},
+			screenWidth:0,
+			pushData: {
+				obj:null,
+				auth:"https://tran.jsshuita.cn/plugin/webman/push/auth",
+				url: 'wss://tran.jsshuita.cn/ws',
+			}
 		}
 	},
 	onLoad() {
 		app = this;
+		const systemInfo = uni.getSystemInfoSync();
+		app.screenWidth = systemInfo.screenWidth;
+		this.getMessage()
 		uni.setNavigationBarTitle({
 			title:"与xxx对话"
 		})
-	},
+	},
+	computed: mapState({
+		//显示时间
+		renderMessageDate() {
+			return (message, index) => {
+				if (this.msgData.list[index + 1]?.timestamp - message.timestamp  > 3 * 60 * 1000) {
+					return formatDate(message.timestamp, 'timestamp');
+				}
+				return '';
+			};
+		},
+	}),
 	methods: {
+		scroll(){},
+		// 滚动到顶部
+		scrolltoupper(){
+			if (this.msgData.allLoaded) return;
+			this.getMessage()
+		},
+		scrolltolower() {},
+		keyboardheightchange(e){
+			const height = e.detail.height;
+			if (height > 0) {
+				this.isEmoji = false;
+				this.isMore = false;
+				this.isKeyboard = true;
+			} else {
+				this.isKeyboard = false;
+			}
+			this.keyboardHeight = height;
+			setTimeout(()=>{
+				this.scrollToBottom()
+			}, 150)
+		},
+		tapEmoji() {
+			this.isEmoji = !this.isEmoji;
+			if (this.isEmoji) {
+				this.isKeyboard = true;
+			}
+			this.isMore = false;
+			setTimeout(()=>{
+				this.scrollToBottom()
+			}, 150)
+		},
+		tapMore(){
+			this.isMore = !this.isMore;
+			if (this.isMore) {
+				this.isKeyboard = true;
+			}
+			this.isEmoji = false;
+			setTimeout(()=>{
+				this.scrollToBottom()
+			}, 150)
+		},
+		sendingMore(data){
+			console.log("sendingMore",data)
+		},
+		scrollToBottom() {
+			if (this.isEmoji) {
+				var px = 600 * (app.screenWidth / 750)
+				this.scrollTop = (this.msgData.list.length + px) * 1000
+			} else if (this.isMore) {
+				var px = 430 * (app.screenWidth / 750)
+				this.scrollTop = (this.msgData.list.length + px) * 1000
+			} else {
+				this.scrollTop = (this.msgData.list.length + parseInt(this.keyboardHeight)) * 1000
+			}
+		},
+		touchmove(){
+			this.isFocus = false;
+			this.isFocisEmojius = false;
+			this.isEmoji = false;
+			this.isMore = false;
+			this.isKeyboard = false;
+			this.keyboardHeight = 0
+		},
+		onEmoji(key) {
+			const text = `${this.text.slice(0, cursor)}${key}${this.text.slice(cursor)}`;
+			this.text = text;
+		},
+		sendingEmojiPack(){},
+		// 删除表情
+		deleteFn() {
+			const str = this.text.charAt(this.text.length - 1);
+			if (str === ']') {
+				let metaChars = /\[.*?(\u4e00*\u597d*)\]/g;
+				let xstr = '';
+				this.text.replace(metaChars, (match) => {
+					xstr = match;
+				});
+				var text = this.text;
+
+				function del(str) {
+					return text.slice(0, text.length - str.length);
+				}
+				this.text = del(xstr);
+			} else {
+				this.text = this.text.substring(0, this.text.length - 1);
+			}
+		},
+		sendingText(){},
+		getMessage(){
+			let get = async ()=>{
+				this.msgData.allLoaded = true;
+				console.log("loading",{
+					page:this.msgData.page,
+					rows: this.msgData.page == 3 ? 5 : this.msgData.rows
+				})
+				let data = await getHistoryMsg({
+					page:this.msgData.page,
+					rows: this.msgData.page == 3 ? 5 : this.msgData.rows
+				});
+				const selector = `msg-${data?.[0]?.messageId}`;;
+				this.msgData.list = this.msgData.list.concat(data);
+				// 数据挂载后执行,不懂的请自行阅读 Vue.js 文档对 Vue.nextTick 函数说明。
+				this.$nextTick(()=>{
+					// 设置当前滚动的位置
+					this.scrollIntoViewId = selector;
+					if(data.length < this.msgData.rows){
+						this.msgData.allLoaded = true;
+						this.msgData.flag = false;
+						// 当前消息数据条数小于请求要求条数时,则无更多消息,不再允许请求。
+						// 可在此处编写无更多消息数据时的逻辑
+					}else{
+						console.log('到这了...')
+						this.msgData.flag = true;
+						this.msgData.allLoaded = false;
+						this.msgData.page ++;
+					}
 
+				})
+			}
+			get();
+		},
+		renderTextMessage(text) {
+			if (!text) return "";
+			text = text.replace(/\n/g, '');
+			if (!text) return '<span>' + '[未知内容]' + '</span>';
+			return '<span>' + decoder.decode(text) + '</span>';
+		},
 	}
 }
 </script>
@@ -38,9 +264,152 @@ export default {
 	display: flex;
 	flex-direction: column;
 }
+.msgLoading{
+	text-align: center;
+	padding: 10rpx 0;
+}
 .chat-body{
 	height: 0;
 	flex: 1;
+	.scroll-view-msg{
+		display: flex;
+		flex-direction: column-reverse;
+		flex-wrap: nowrap;
+		align-content: flex-start;
+		justify-content: flex-end;
+		align-items: stretch;
+	}
+	.message {
+		display: flex;
+		align-items: flex-start;
+		margin-bottom: 30rpx;
+		.quickList{
+			margin-top: 10upx;
+			.list-items {
+				color: blue;
+				font-size: 28upx;
+				line-height: 48upx;
+			}
+		}
+		.avatar {
+			width: 80rpx;
+			height: 80rpx;
+			border-radius: 10rpx;
+			margin-right: 30rpx;
+		}
+		.message-con {
+			min-height: 80rpx;
+			max-width: 80vw;
+			box-sizing: border-box;
+			font-size: 28rpx;
+			line-height: 1.3;
+			padding: 20rpx;
+			border-radius: 10rpx;
+			background: #fff;
+			image {
+				// width: 200rpx;
+			}
+		}
+		&.self {
+			justify-content: flex-end;
+			.avatar {
+				margin: 0 0 0 30rpx;
+			}
+			.message-con {
+				position: relative;
+				&::after {
+					position: absolute;
+					content: '';
+					width: 0;
+					height: 0;
+					border: 16rpx solid transparent;
+					border-left: 16rpx solid #fff;
+					right: -28rpx;
+					top: 24rpx;
+				}
+			}
+		}
+		&.friend {
+			.message-con {
+				position: relative;
+				&::after {
+					position: absolute;
+					content: '';
+					width: 0;
+					height: 0;
+					border: 16rpx solid transparent;
+					border-right: 16rpx solid #fff;
+					left: -28rpx;
+					top: 24rpx;
+				}
+			}
+		}
+	}
+}
+.tool {
+	background: #fff;
+	padding: 20rpx 0 20rpx 0;
+	padding-bottom: calc(20rpx + constant(safe-area-inset-bottom)/2) !important;
+	padding-bottom: calc(20rpx + env(safe-area-inset-bottom)/2) !important;
+	.tool-option{
+		display: flex;
+		align-items: flex-start;
+		box-sizing: border-box;
+		padding: 0 20rpx;
+	}
+	.tool-bar {
+		display: flex;
+		align-items: center;
+		gap: 20rpx;
+		padding: 0 20rpx;
+		.bar-item {
+			display: flex;
+			align-items: center;
+			font-size: 28rpx;
+			gap: 10rpx;
+			color: #333;
+			margin-bottom: 20rpx;
+			image{
+				width: 40rpx;
+				height: 40rpx;
+			}
+		}
+	}
+	.input-text{
+		flex: 1;width: 100%;
+		box-sizing: border-box;
+		padding: 10rpx 14rpx;
+		min-height: 84rpx;
+		max-height: 300rpx;
+		overflow: auto;
+		border-radius: 10rpx;
+		background-color: #eee;
+		.input{
+			margin: 10rpx 0;
+			width: 100%;
+			font-size: 28upx;
+			height: 100%;
+			background-color: #eee;
+			min-height: 48rpx;
+			max-height: 300rpx;
+		}
+	}
+	.check-img{
+		display: flex;align-items: center;justify-content: center;
+		.check-icon{width: 84rpx;height: 84rpx;display: flex;align-items: center;justify-content: center;}
+		image{width: 75%;height: 75%;}
+	}
+
+	.thumb {
+		width: 64rpx;
+	}
+}
+.time {
+	width: 100%;
+	color: #a3a3a3;
+	line-height: 100rpx;
+	text-align: center;
+	font-size: 24rpx;
 }
 
 </style>

+ 6 - 2
奥莱优品/pages/service/service.vue

@@ -12,7 +12,7 @@
 					<view class="name">聊天列表</view>
 				</view>
 				<view class="list-service">
-					<view class="service-item">
+					<view class="service-item" @click="toChat">
 						<view class="avatar"><image src="/static/logo.jpg"></image></view>
 						<view class="info">
 							<view class="name">桃奢妍奥莱城</view>
@@ -34,7 +34,11 @@ export default {
 		}
 	},
 	methods: {
-
+		toChat(){
+			uni.navigateTo({
+				url:"/pages/service/chat"
+			})
+		}
 	}
 }
 </script>

+ 1 - 0
奥莱优品/static/image/face.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M513 959c-60.4 0-118.9-11.8-174.1-35.2-53.3-22.5-101.1-54.8-142.1-95.8-41.1-41.1-73.3-88.9-95.8-142.1-23.3-55.2-35.2-113.7-35.2-174.1S77.6 392.9 101 337.7c22.5-53.3 54.8-101.1 95.8-142.1 41.1-41.1 88.9-73.3 142.1-95.8C394.1 76.4 452.6 64.6 513 64.6s118.9 11.8 174.1 35.2c53.3 22.5 101.1 54.8 142.1 95.8 41.1 41.1 73.3 88.9 95.8 142.1 23.3 55.2 35.2 113.7 35.2 174.1S948.4 630.7 925 685.9C902.5 739.1 870.3 787 829.2 828c-41.1 41.1-88.9 73.3-142.1 95.8C631.9 947.2 573.4 959 513 959zm0-838.4c-52.8 0-104.1 10.3-152.3 30.7-46.6 19.7-88.4 47.9-124.4 83.9-35.9 35.9-64.2 77.8-83.9 124.4-20.4 48.2-30.7 99.4-30.7 152.3S132 616 152.4 664.2c19.7 46.6 47.9 88.4 83.9 124.4 35.9 35.9 77.8 64.2 124.4 83.9C408.9 892.7 460.2 903 513 903s104.1-10.3 152.3-30.7c46.6-19.7 88.4-47.9 124.4-83.9 35.9-35.9 64.2-77.8 83.9-124.4 20.4-48.2 30.7-99.4 30.7-152.3S894 407.6 873.6 359.4c-19.7-46.6-47.9-88.4-83.9-124.4-35.9-35.9-77.8-64.2-124.4-83.9-48.2-20.2-99.5-30.5-152.3-30.5z" data-spm-anchor-id="a313x.collections_detail.0.i11.44233a81EDJLHA" class="selected"/><path d="M583.9 398.3a46.7 46.7 0 1 0 93.4 0 46.7 46.7 0 1 0-93.4 0zM347 398.3a46.7 46.7 0 1 0 93.4 0 46.7 46.7 0 1 0-93.4 0zM513 790c-55.2 0-110-18.4-154.3-51.8-42.4-31.9-72.5-74.9-84.9-120.9-4.7-17.4-1-35.6 10-50 11.1-14.5 27.9-22.8 46.1-22.8l366.3-.1c18.2 0 35 8.3 46.1 22.7 11 14.4 14.7 32.6 10 50-12.3 46-42.5 89-84.9 120.9-44.4 33.6-99.2 52-154.4 52zm183.1-189.6l-366.3.1c-.3 0-1 0-1.7.8-.5.7-.4 1.2-.3 1.4 9 33.5 32.5 66.5 64.5 90.6C427.1 719.6 469.9 734 513 734c43.1 0 85.9-14.4 120.7-40.6 32-24.1 55.5-57.2 64.5-90.7.1-.3.2-.7-.3-1.4-.7-.9-1.5-.9-1.8-.9z"/></svg>

+ 1 - 0
奥莱优品/static/image/more.svg

@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M511.3 959.7c-60.4 0-119-11.8-174.2-35.2-53.3-22.5-101.1-54.8-142.2-95.9-41.1-41.1-73.4-88.9-95.9-142.2-23.3-55.2-35.2-113.8-35.2-174.2S75.6 393.1 99 338c22.5-53.3 54.8-101.1 95.9-142.2 41.1-41.1 88.9-73.4 142.2-95.9 55.2-23.3 113.8-35.2 174.2-35.2 60.4 0 119 11.8 174.2 35.2 53.3 22.5 101.1 54.8 142.2 95.9 41.1 41.1 73.4 88.9 95.9 142.2 23.3 55.2 35.2 113.8 35.2 174.2s-11.8 119-35.2 174.2c-22.5 53.3-54.8 101.1-95.9 142.2-41.1 41.1-88.9 73.4-142.2 95.9-55.2 23.3-113.8 35.2-174.2 35.2zm0-839c-52.9 0-104.1 10.3-152.4 30.8-46.6 19.7-88.5 47.9-124.5 83.9-36 36-64.2 77.8-83.9 124.5-20.4 48.2-30.8 99.5-30.8 152.4s10.3 104.1 30.8 152.4c19.7 46.6 47.9 88.5 83.9 124.5 36 36 77.8 64.2 124.5 83.9 48.2 20.4 99.5 30.8 152.4 30.8 52.9 0 104.1-10.3 152.4-30.8 46.6-19.7 88.5-47.9 124.5-83.9s64.2-77.8 83.9-124.5c20.4-48.2 30.8-99.5 30.8-152.4S892.4 408 872 359.8c-19.7-46.6-47.9-88.5-83.9-124.5s-77.8-64.2-124.5-83.9c-48.2-20.4-99.5-30.7-152.3-30.7z"/><path d="M737.3 484.2h-198v-198c0-15.5-12.5-28-28-28s-28 12.5-28 28v198h-198c-15.5 0-28 12.5-28 28s12.5 28 28 28h198v198c0 15.5 12.5 28 28 28s28-12.5 28-28v-198h198c15.5 0 28-12.5 28-28s-12.6-28-28-28z"/></svg>

+ 29 - 0
奥莱优品/store/index.js

@@ -0,0 +1,29 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+Vue.use(Vuex)
+const store = new Vuex.Store({
+	state: {
+		// 文字大小
+		page_font_size: uni.getStorageSync('page_font_size') || 'page_font_size',
+		// 导航栏高度
+		StatusBar: {
+			statusBar: 0,
+			customBar: 0,
+		},
+	},
+	mutations: {
+		// 设置导航栏高度
+		SET_STATUSBAR(state, value) {
+			state.StatusBar = value
+		},
+		SET_page_font_size(state, value) {
+			state.page_font_size = value
+			uni.setStorage({
+				key: 'page_font_size',
+				data: value,
+				success: function() {}
+			});
+		}
+	}
+})
+export default store

+ 2 - 0
奥莱优品/uni.scss

@@ -78,3 +78,5 @@ $uni-font-size-paragraph:15px;
 $main-color:#ff5a25;
 $main-sub-color:#ffedd5;
 $main-text-color:#475569;
+
+@import "utils/css/index.scss";

+ 185 - 0
奥莱优品/utils/css/index.scss

@@ -0,0 +1,185 @@
+@for $i from 1 to 60 {
+	.text_#{$i} {
+		font-size: #{$i}rpx;
+	}
+}
+/* 小号 */
+#page_font_size_min {
+	@for $i from 1 to 60 {
+		.text_#{$i} {
+			font-size: calc(#{$i}rpx - 2rpx);
+		}
+	}
+}
+/* 标准 */
+#page_font_size {
+	@for $i from 1 to 60 {
+		.text_#{$i} {
+			font-size: #{$i}rpx;
+		}
+	}
+}
+
+/* 大 */
+#page_font_size_max {
+	$font_size: 6rpx;
+	@for $i from 1 to 60 {
+		.text_#{$i} {
+			font-size: calc(#{$i}rpx + #{$font_size});
+		}
+	}
+}
+
+/* 偏大 */
+#page_font_size_max_plus {
+	$font_size: 10rpx;
+	@for $i from 1 to 60 {
+		.text_#{$i} {
+			font-size: calc(#{$i}rpx + #{$font_size});
+		}
+	}
+}
+/* 特大 */
+#page_font_size_max_plus_pro {
+	$font_size: 16rpx;
+	@for $i from 1 to 60 {
+		.text_#{$i} {
+			font-size: calc(#{$i}rpx + #{$font_size});
+		}
+	}
+}
+
+.flex_r {
+	display: flex;
+	flex-direction: row;
+}
+
+.flex_c {
+	display: flex;
+	flex-direction: column;
+}
+.flex1 {
+	flex: 1;
+}
+.fj_b {
+	justify-content: space-between;
+}
+
+.fj_a {
+	justify-content: space-around;
+}
+
+.fj_c {
+	justify-content: center;
+}
+
+.fa_c {
+	align-items: center;
+}
+
+.flex_c_c {
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+	justify-content: center;
+}
+
+.icon_ {
+	display: flex;
+	flex-direction: row;
+	align-items: center;
+	justify-content: center;
+}
+
+.z_index2 {
+	position: relative;
+	z-index: 2;
+}
+
+.img {
+	width: 100%;
+	height: 100%;
+}
+
+.rotate_45 {
+	transform: rotate(45deg);
+}
+
+.rotate_90 {
+	transform: rotate(90deg);
+}
+
+.rotate_180 {
+	transform: rotate(180deg);
+}
+
+.text-indent {
+	text-indent: 2em;
+	text-align: justify;
+}
+
+/* 文本css */
+.nowrap_ {
+	text-overflow: ellipsis;
+	/* #ifndef APP-PLUS-NVUE*/
+	overflow: hidden;
+	white-space: nowrap;
+	/*  #endif  */
+
+	/*#ifdef APP-PLUS-NVUE*/
+	lines: 1;
+	/*  #endif  */
+}
+
+.ellipsis_2 {
+	text-overflow: ellipsis;
+	/* #ifndef APP-PLUS-NVUE*/
+	overflow: hidden;
+	display: -webkit-box;
+	-webkit-box-orient: vertical;
+	-webkit-line-clamp: 2;
+	/*  #endif  */
+
+	/* #ifdef  APP-PLUS-NVUE*/
+	lines: 2;
+	/*  #endif  */
+}
+
+.hover_class::after {
+	position: absolute;
+	z-index: 2;
+	content: '';
+	top: 0;
+	left: 0;
+	right: 0;
+	bottom: 0;
+	background-color: rgba(0, 0, 0, 0.1);
+}
+
+.size_white {
+	color: #fff;
+}
+
+.color_ {
+	color: #b5b5b6;
+}
+
+.color___ {
+	color: #7fade8;
+}
+
+.color__ {
+	color: #7e7e7e;
+}
+
+.color_4a {
+	color: #4a4a4a;
+}
+
+.color_rot {
+	color: #ff0000;
+}
+
+.bold_ {
+	font-weight: bold;
+}

+ 186 - 0
奥莱优品/utils/js/EmojiDecoder.js

@@ -0,0 +1,186 @@
+import store from '@/store/index.js';
+let font_size = {
+	page_font_size: 0,
+	page_font_size_max: 2,
+	page_font_size_max_plus: 4,
+	page_font_size_max_plus_pro: 6
+};
+export class EmojiDecoder {
+	emojiMap = null;
+	url = "";
+	patterns = [];
+	metaChars = /[[\]{}()*+?.\\|^$\-,&#\s]/g;
+
+	constructor(url, emojiMap) {
+		this.url = url || '';
+		this.emojiMap = emojiMap || {};
+		for (let i in this.emojiMap) {
+			if (this.emojiMap.hasOwnProperty(i)) {
+				this.patterns.push('(' + i.replace(this.metaChars, "\\$&") + ')');
+			}
+		}
+	}
+
+	decode(text, size, top = '4px') {
+		if (!size) {
+			size = `${22 + font_size[store.state.page_font_size]}px`
+		}
+		return text.replace(new RegExp(this.patterns.join('|'), 'g'), (match) => {
+			return typeof this.emojiMap[match] != 'undefined' ?
+				`<img style="position: relative;top: ${top};" height="${size}" width="${size}" src="${this.url}${this.emojiMap[match]}" />` :
+				match;
+		}).replace(/\n/g, '<br/>');
+	}
+	// 无需换行
+	decodeNo(text, size = '22rpx', top = '4px') {
+		return text.replace(new RegExp(this.patterns.join('|'), 'g'), (match) => {
+			return typeof this.emojiMap[match] != 'undefined' ?
+				`<img style="position: relative;top: ${top};" height="${size}" width="${size}" src="${this.url}${this.emojiMap[match]}" />` :
+				match;
+		});
+	}
+};
+export const emojiMap = {
+	"[微笑]": "emoji_49@2x.png",
+	"[NO]": "emoji_0@2x.png",
+	"[OK]": "emoji_1@2x.png",
+	"[下雨]": "emoji_2@2x.png",
+	"[么么哒]": "emoji_3@2x.png",
+	"[乒乓]": "emoji_4@2x.png",
+	"[便便]": "emoji_5@2x.png",
+	"[信封]": "emoji_6@2x.png",
+	"[偷笑]": "emoji_7@2x.png",
+	"[傲慢]": "emoji_8@2x.png",
+	"[再见]": "emoji_9@2x.png",
+	"[冷汗]": "emoji_10@2x.png",
+	"[凋谢]": "emoji_11@2x.png",
+	"[刀]": "emoji_12@2x.png",
+	"[删除]": "emoji_13@2x.png",
+	"[勾引]": "emoji_14@2x.png",
+	"[发呆]": "emoji_15@2x.png",
+	"[发抖]": "emoji_16@2x.png",
+	"[可怜]": "emoji_17@2x.png",
+	"[可爱]": "emoji_18@2x.png",
+	"[右哼哼]": "emoji_19@2x.png",
+	"[右太极]": "emoji_20@2x.png",
+	"[右车头]": "emoji_21@2x.png",
+	"[吐]": "emoji_22@2x.png",
+	"[吓]": "emoji_23@2x.png",
+	"[咒骂]": "emoji_24@2x.png",
+	"[咖啡]": "emoji_25@2x.png",
+	"[啤酒]": "emoji_26@2x.png",
+	"[嘘]": "emoji_27@2x.png",
+	"[回头]": "emoji_28@2x.png",
+	"[困]": "emoji_29@2x.png",
+	"[坏笑]": "emoji_30@2x.png",
+	"[多云]": "emoji_31@2x.png",
+	"[大兵]": "emoji_32@2x.png",
+	"[大哭]": "emoji_33@2x.png",
+	"[太阳]": "emoji_34@2x.png",
+	"[奋斗]": "emoji_35@2x.png",
+	"[奶瓶]": "emoji_36@2x.png",
+	"[委屈]": "emoji_37@2x.png",
+	"[害羞]": "emoji_38@2x.png",
+	"[尴尬]": "emoji_39@2x.png",
+	"[左哼哼]": "emoji_40@2x.png",
+	"[左太极]": "emoji_41@2x.png",
+	"[左车头]": "emoji_42@2x.png",
+	"[差劲]": "emoji_43@2x.png",
+	"[弱]": "emoji_44@2x.png",
+	"[强]": "emoji_45@2x.png",
+	"[彩带]": "emoji_46@2x.png",
+	"[彩球]": "emoji_47@2x.png",
+	"[得意]": "emoji_48@2x.png",
+	"[心碎了]": "emoji_50@2x.png",
+	"[快哭了]": "emoji_51@2x.png",
+	"[怄火]": "emoji_52@2x.png",
+	"[怒]": "emoji_53@2x.png",
+	"[惊恐]": "emoji_54@2x.png",
+	"[惊讶]": "emoji_55@2x.png",
+	"[憨笑]": "emoji_56@2x.png",
+	"[手枪]": "emoji_57@2x.png",
+	"[打哈欠]": "emoji_58@2x.png",
+	"[抓狂]": "emoji_59@2x.png",
+	"[折磨]": "emoji_60@2x.png",
+	"[抠鼻]": "emoji_61@2x.png",
+	"[抱抱]": "emoji_62@2x.png",
+	"[抱拳]": "emoji_63@2x.png",
+	"[拳头]": "emoji_64@2x.png",
+	"[挥手]": "emoji_65@2x.png",
+	"[握手]": "emoji_66@2x.png",
+	"[撇嘴]": "emoji_67@2x.png",
+	"[擦汗]": "emoji_68@2x.png",
+	"[敲打]": "emoji_69@2x.png",
+	"[晕]": "emoji_70@2x.png",
+	"[月亮]": "emoji_71@2x.png",
+	"[棒棒糖]": "emoji_72@2x.png",
+	"[汽车]": "emoji_73@2x.png",
+	"[沙发]": "emoji_74@2x.png",
+	"[流汗]": "emoji_75@2x.png",
+	"[流泪]": "emoji_76@2x.png",
+	"[激动]": "emoji_77@2x.png",
+	"[灯泡]": "emoji_78@2x.png",
+	"[炸弹]": "emoji_79@2x.png",
+	"[熊猫]": "emoji_80@2x.png",
+	"[爆筋]": "emoji_81@2x.png",
+	"[爱你]": "emoji_82@2x.png",
+	"[爱心]": "emoji_83@2x.png",
+	"[爱情]": "emoji_84@2x.png",
+	"[猪头]": "emoji_85@2x.png",
+	"[猫咪]": "emoji_86@2x.png",
+	"[献吻]": "emoji_87@2x.png",
+	"[玫瑰]": "emoji_88@2x.png",
+	"[瓢虫]": "emoji_89@2x.png",
+	"[疑问]": "emoji_90@2x.png",
+	"[白眼]": "emoji_91@2x.png",
+	"[皮球]": "emoji_92@2x.png",
+	"[睡觉]": "emoji_93@2x.png",
+	"[磕头]": "emoji_94@2x.png",
+	"[示爱]": "emoji_95@2x.png",
+	"[礼品袋]": "emoji_96@2x.png",
+	"[礼物]": "emoji_97@2x.png",
+	"[篮球]": "emoji_98@2x.png",
+	"[米饭]": "emoji_99@2x.png",
+	"[糗大了]": "emoji_100@2x.png",
+	"[红双喜]": "emoji_101@2x.png",
+	"[红灯笼]": "emoji_102@2x.png",
+	"[纸巾]": "emoji_103@2x.png",
+	"[胜利]": "emoji_104@2x.png",
+	"[色]": "emoji_105@2x.png",
+	"[药]": "emoji_106@2x.png",
+	"[菜刀]": "emoji_107@2x.png",
+	"[蛋糕]": "emoji_108@2x.png",
+	"[蜡烛]": "emoji_109@2x.png",
+	"[街舞]": "emoji_110@2x.png",
+	"[衰]": "emoji_111@2x.png",
+	"[西瓜]": "emoji_112@2x.png",
+	"[调皮]": "emoji_113@2x.png",
+	"[象棋]": "emoji_114@2x.png",
+	"[跳绳]": "emoji_115@2x.png",
+	"[跳跳]": "emoji_116@2x.png",
+	"[车厢]": "emoji_117@2x.png",
+	"[转圈]": "emoji_118@2x.png",
+	"[鄙视]": "emoji_119@2x.png",
+	"[酷]": "emoji_120@2x.png",
+	"[钞票]": "emoji_121@2x.png",
+	"[钻戒]": "emoji_122@2x.png",
+	"[闪电]": "emoji_123@2x.png",
+	"[闭嘴]": "emoji_124@2x.png",
+	"[闹钟]": "emoji_125@2x.png",
+	"[阴险]": "emoji_126@2x.png",
+	"[难过]": "emoji_127@2x.png",
+	"[雨伞]": "emoji_128@2x.png",
+	"[青蛙]": "emoji_129@2x.png",
+	"[面条]": "emoji_130@2x.png",
+	"[鞭炮]": "emoji_131@2x.png",
+	"[风车]": "emoji_132@2x.png",
+	"[飞吻]": "emoji_133@2x.png",
+	"[飞机]": "emoji_134@2x.png",
+	"[饥饿]": "emoji_135@2x.png",
+	"[香蕉]": "emoji_136@2x.png",
+	"[骷髅]": "emoji_137@2x.png",
+	"[麦克风]": "emoji_138@2x.png",
+	"[麻将]": "emoji_139@2x.png",
+	"[鼓掌]": "emoji_140@2x.png",
+	"[龇牙]": "emoji_141@2x.png"
+}

+ 49 - 0
奥莱优品/utils/js/formatDate.js

@@ -0,0 +1,49 @@
+// 格式化时间
+// this.timestampFormat('2022-07-05 15:10:10'); 
+// timestamp:时间戳
+// time:2022-07-05 15:10:10'
+export const formatDate = (date, type = "time") => {
+	let timestamp = null
+	if (type === "time") {
+		timestamp = Date.parse(date.replace(/-/g, '/')) / 1000 //可解析一个日期时间字符串,并返回 1970/1/1 午夜距离该日期时间的毫秒数。
+	} else {
+		timestamp = date / 1000
+	}
+
+	function zeroize(num) {
+		return (String(num).length == 1 ? '0' : '') + num;
+	}
+	let curTimestamp = parseInt(new Date().getTime() / 1000); //当前时间戳
+
+	let timestampDiff = curTimestamp - timestamp; // 参数时间戳与当前时间戳相差秒数
+	let curDate = new Date(curTimestamp * 1000); // 当前时间日期对象
+	let tmDate = new Date(timestamp * 1000); // 参数时间戳转换成的日期对象
+	let Y = tmDate.getFullYear(),
+		m = tmDate.getMonth() + 1,
+		d = tmDate.getDate();
+	let H = tmDate.getHours(),
+		i = tmDate.getMinutes(),
+		s = tmDate.getSeconds();
+	if (timestampDiff < 60) { // 一分钟以内
+		return "刚刚";
+	} else if (timestampDiff < 3600) { // 一小时前之内
+		return Math.floor(timestampDiff / 60) + "分钟前";
+	} else if (curDate.getFullYear() == Y && curDate.getMonth() + 1 == m && curDate.getDate() == d) {
+		if (H <= 12) {
+			return '上午' + zeroize(H) + ':' + zeroize(i);
+		}
+		return '下午' + zeroize(H) + ':' + zeroize(i);
+	} else {
+		let newDate = new Date((curTimestamp - 86400) * 1000); // 参数中的时间戳加一天转换成的日期对象
+		if (newDate.getFullYear() == Y && newDate.getMonth() + 1 == m && newDate.getDate() == d) {
+			if (H <= 12) {
+				return '昨天' + ' ' + '上午' + zeroize(H) + ':' + zeroize(i);
+			}
+			return '昨天' + ' ' + '下午' + zeroize(H) + ':' + zeroize(i);
+		} else if (curDate.getFullYear() == Y) {
+			return zeroize(m) + '月' + zeroize(d) + '日 ' + zeroize(H) + ':' + zeroize(i);
+		} else {
+			return Y + '年' + zeroize(m) + '月' + zeroize(d) + '日 ' + zeroize(H) + ':' + zeroize(i);
+		}
+	}
+}

+ 40 - 0
奥莱优品/utils/js/getStatusBar.js

@@ -0,0 +1,40 @@
+import store from '@/store/index.js';
+export const getStatusBar = () => {
+	return new Promise((success, fail) => {
+		uni.getSystemInfo({
+			success: (e) => {
+				// 获取手机状态栏高度
+				let statusBar = e.statusBarHeight
+				let customBar
+				// #ifndef MP
+				customBar = statusBar + (e.platform == 'android' ? 50 : 45)
+				// #endif
+				// #ifdef MP-WEIXIN
+				// 获取胶囊按钮的布局位置信息
+				let menu = wx.getMenuButtonBoundingClientRect()
+				// 导航栏高度 = 胶囊下距离 + 胶囊上距离 - 状态栏高度
+				customBar = menu.bottom + menu.top - statusBar
+				// #endif
+				// #ifdef MP-ALIPAY
+				customBar = statusBar + e.titleBarHeight
+				// #endif
+				const compensateHeight = 10; //非刘海屏状态栏高度偏低,补充10
+				store.commit('SET_STATUSBAR', {
+					statusBar: statusBar + compensateHeight,
+					customBar: customBar + compensateHeight,
+					// #ifdef MP
+					statusBar: statusBar + compensateHeight + 10,
+					customBar: customBar + compensateHeight + 10
+					// #endif
+				});
+				success({
+					statusBar,
+					customBar
+				})
+			}
+		})
+
+
+	})
+
+}

+ 39 - 0
奥莱优品/utils/js/history-msg.js

@@ -0,0 +1,39 @@
+export const getHistoryMsg = (params)=>{
+	const { page = 1,rows = 10 } = params ?? {};
+	let join = ()=>{
+		let arr = [];
+
+		//通过当前页码及页数,模拟数据内容
+		let startIndex = (page-1) * rows;
+		let endIndex = startIndex + rows;
+		for(let i = startIndex; i < endIndex; i++){
+			arr.push({
+				content: `这是历史记录的第${i+1}条消息,第${page}页,[微笑][NO][下雨][OK]`,
+				userType: Math.random() > 0.5 ? 'self' : 'friend',
+				avatar: '/static/logo.jpg',
+				msgType:'text',
+				list:[],
+				messageId: Date.now(),
+				timestamp: Date.now()
+			})
+		}
+
+		/*
+			颠倒数组中元素的顺序。将最新的数据排在本次接口返回数据的最后面。
+			后端接口按 消息的时间降序查找出当前页的数据后,再将本页数据按消息时间降序排序返回。
+			这是数据的重点,因为页面滚动条和上拉加载历史的问题。
+		 */
+		// arr.reverse();
+
+		return arr;
+	}
+
+	// 此处用到 ES6 的 Promise 知识,不懂的请自行学习。
+	return new Promise((done,fail)=>{
+		// 无数据请求接口,由 setTimeout 模拟,正式项目替换为 ajax 即可。
+		setTimeout(()=>{
+			let data = join();
+			done(data);
+		},1000);
+	})
+}

+ 30 - 0
奥莱优品/utils/js/index.js

@@ -0,0 +1,30 @@
+import {
+	to
+} from './to.js';
+import {
+	show
+} from './show.js';
+import {
+	jsonUrl
+} from './jsonUrl.js';
+import {
+	openimg
+} from './openimg.js';
+import {
+	formatDate
+} from './formatDate.js';
+import {
+	getStatusBar
+} from './getStatusBar.js';
+import {
+	throttle
+} from './throttle.js';
+export {
+	to,
+	show,
+	openimg,
+	jsonUrl,
+	formatDate,
+	getStatusBar,
+	throttle
+}

+ 30 - 0
奥莱优品/utils/js/jsonUrl.js

@@ -0,0 +1,30 @@
+function isObj(obj) {
+	let array = Object.keys(obj);
+	if (array.length === 0) { //如果数组array的长度为0 ,则返回为true,说明data对象为空
+		return false;
+	}
+	return true;
+};
+// 配合to方法使用
+export const jsonUrl = (e) => {
+	// #ifdef MP
+	if (e.data) {
+		e.data = decodeURIComponent(e.data)
+	}
+	// #endif
+	if (isObj(e)) {
+		if (e.data) {
+			var data = JSON.parse(e.data)
+		} else {
+			return e;
+		}
+		return data;
+	} else {
+		uni.showToast({
+			title: '参数错误',
+			duration: 1000,
+			icon: 'none',
+			mask: true,
+		});
+	}
+}

+ 29 - 0
奥莱优品/utils/js/openimg.js

@@ -0,0 +1,29 @@
+export const openimg = (index,item,attributes='') => {
+	if(item) {
+		// 数组对象请况
+		if (attributes) {
+			let arr = []
+			item.forEach((item,ix)=>{
+				if (item[attributes] ) {
+					arr.push(item[attributes])
+				}
+			})
+			uni.previewImage({
+				urls: arr,
+				current: arr[index]
+			});
+		} else {// 数组请况
+			uni.previewImage({
+				urls: item,
+				current: item[index]
+			});
+		}
+	} else if(!item) {//传入单张照片
+		let arr = []
+		arr.push(index)
+		uni.previewImage({
+			urls: arr,
+			current: arr[1]
+		});
+	}
+}

+ 833 - 0
奥莱优品/utils/js/push.js

@@ -0,0 +1,833 @@
+
+function Push(options) {
+    this.doNotConnect = 0;
+    options = options || {};
+    options.heartbeat  = options.heartbeat || 25000;
+    options.pingTimeout = options.pingTimeout || 10000;
+    this.config = options;
+    this.uid = 0;
+    this.channels = {};
+    this.connection = null;
+    this.pingTimeoutTimer = 0;
+    Push.instances.push(this);
+    this.createConnection();
+}
+
+Push.prototype.checkoutPing = function() {
+    var _this = this;
+    _this.checkoutPingTimer && clearTimeout(_this.checkoutPingTimer);
+    _this.checkoutPingTimer = setTimeout(function () {
+        _this.checkoutPingTimer = 0;
+        if (_this.connection.state === 'connected') {
+            _this.connection.send('{"event":"pusher:ping","data":{}}');
+            if (_this.pingTimeoutTimer) {
+                clearTimeout(_this.pingTimeoutTimer);
+                _this.pingTimeoutTimer = 0;
+            }
+            _this.pingTimeoutTimer = setTimeout(function () {
+                _this.connection.closeAndClean();
+                if (!_this.connection.doNotConnect) {
+                    _this.connection.waitReconnect();
+                }
+            }, _this.config.pingTimeout);
+        }
+    }, this.config.heartbeat);
+};
+
+Push.prototype.channel = function (name) {
+    return this.channels.find(name);
+};
+Push.prototype.allChannels = function () {
+    return this.channels.all();
+};
+Push.prototype.createConnection = function () {
+    if (this.connection) {
+        throw Error('Connection already exist');
+    }
+    var _this = this;
+    var url = this.config.url;
+    function updateSubscribed () {
+        for (var i in _this.channels) {
+            _this.channels[i].subscribed = false;
+        }
+    }
+    this.connection = new Connection({
+        url: url,
+        app_key: this.config.app_key,
+        onOpen: function () {
+            _this.connection.state  = 'connecting';
+            _this.checkoutPing();
+        },
+        onMessage: function(params) {
+            if(_this.pingTimeoutTimer) {
+                clearTimeout(_this.pingTimeoutTimer);
+                _this.pingTimeoutTimer = 0;
+            }
+
+            params = JSON.parse(params.data);
+            var event = params.event;
+            var channel_name = params.channel;
+
+            if (event === 'pusher:pong') {
+                _this.checkoutPing();
+                return;
+            }
+            if (event === 'pusher:error') {
+                throw Error(params.data.message);
+            }
+            var data = JSON.parse(params.data), channel;
+            if (event === 'pusher_internal:subscription_succeeded') {
+                channel = _this.channels[channel_name];
+                channel.subscribed = true;
+                channel.processQueue();
+                channel.emit('pusher:subscription_succeeded');
+                return;
+            }
+            if (event === 'pusher:connection_established') {
+                _this.connection.socket_id = data.socket_id;
+                _this.connection.updateNetworkState('connected');
+                _this.subscribeAll();
+            }
+            if (event.indexOf('pusher_internal') !== -1) {
+                console.log("Event '"+event+"' not implement");
+                return;
+            }
+            channel = _this.channels[channel_name];
+            if (channel) {
+                channel.emit(event, data);
+            }
+        },
+        onClose: function () {
+            updateSubscribed();
+        },
+        onError: function () {
+            updateSubscribed();
+        }
+    });
+};
+Push.prototype.disconnect = function () {
+    this.connection.doNotConnect = 1;
+    this.connection.close();
+};
+
+Push.prototype.subscribeAll = function () {
+    if (this.connection.state !== 'connected') {
+        return;
+    }
+    for (var channel_name in this.channels) {
+        //this.connection.send(JSON.stringify({event:"pusher:subscribe", data:{channel:channel_name}}));
+        this.channels[channel_name].processSubscribe();
+    }
+};
+
+Push.prototype.unsubscribe = function (channel_name) {
+    if (this.channels[channel_name]) {
+        delete this.channels[channel_name];
+        if (this.connection.state === 'connected') {
+            this.connection.send(JSON.stringify({event:"pusher:unsubscribe", data:{channel:channel_name}}));
+        }
+    }
+};
+Push.prototype.unsubscribeAll = function () {
+    var channels = Object.keys(this.channels);
+    if (channels.length) {
+        if (this.connection.state === 'connected') {
+            for (var channel_name in this.channels) {
+                this.unsubscribe(channel_name);
+            }
+        }
+    }
+    this.channels = {};
+};
+Push.prototype.subscribe = function (channel_name) {
+    if (this.channels[channel_name]) {
+        return this.channels[channel_name];
+    }
+    if (channel_name.indexOf('private-') === 0) {
+        return createPrivateChannel(channel_name, this);
+    }
+    if (channel_name.indexOf('presence-') === 0) {
+        return createPresenceChannel(channel_name, this);
+    }
+    return createChannel(channel_name, this);
+};
+Push.instances = [];
+
+function createChannel(channel_name, push)
+{
+    var channel = new Channel(push.connection, channel_name);
+    push.channels[channel_name] = channel;
+    channel.subscribeCb = function () {
+        push.connection.send(JSON.stringify({event:"pusher:subscribe", data:{channel:channel_name}}));
+    }
+    channel.processSubscribe();
+    return channel;
+}
+
+function createPrivateChannel(channel_name, push)
+{
+    var channel = new Channel(push.connection, channel_name);
+    push.channels[channel_name] = channel;
+    channel.subscribeCb = function () {
+        __ajax({
+            url: push.config.auth,
+            type: 'POST',
+            data: {channel_name: channel_name, socket_id: push.connection.socket_id},
+            success: function (data) {
+                data = JSON.parse(data);
+                data.channel = channel_name;
+                push.connection.send(JSON.stringify({event:"pusher:subscribe", data:data}));
+            },
+            error: function (e) {
+                throw Error(e);
+            }
+        });
+    };
+    channel.processSubscribe();
+    return channel;
+}
+
+function createPresenceChannel(channel_name, push)
+{
+    return createPrivateChannel(channel_name, push);
+}
+
+uni.onNetworkStatusChange(function (res) {
+    if(res.isConnected) {
+        for (var i in Push.instances) {
+            var con = Push.instances[i].connection;
+            con.reconnectInterval = 1;
+            if (con.state === 'connecting') {
+                con.connect();
+            }
+        }
+    }
+});
+
+function Connection(options) {
+    this.dispatcher = new Dispatcher();
+    __extends(this, this.dispatcher);
+    var properies = ['on', 'off', 'emit'];
+    for (var i in properies) {
+        this[properies[i]] = this.dispatcher[properies[i]];
+    }
+    this.options = options;
+    this.state = 'initialized'; //initialized connecting connected disconnected
+    this.doNotConnect = 0;
+    this.reconnectInterval = 1;
+    this.connection = null;
+    this.reconnectTimer = 0;
+    this.connect();
+}
+
+Connection.prototype.updateNetworkState = function(state){
+    var old_state = this.state;
+    this.state = state;
+    if (old_state !== state) {
+        this.emit('state_change', { previous: old_state, current: state });
+    }
+};
+
+Connection.prototype.connect = function () {
+    this.doNotConnect = 0;
+    if (this.networkState == 'connecting' || this.networkState == 'established') {
+        console.log('networkState is ' + this.networkState + ' and do not need connect');
+        return;
+    }
+    if (this.reconnectTimer) {
+        clearTimeout(this.reconnectTimer);
+        this.reconnectTimer = 0;
+    }
+
+    this.closeAndClean();
+
+    var options = this.options;
+    var _this = this;
+    _this.updateNetworkState('connecting');
+    var cb = function(){
+        uni.onSocketOpen(function (res) {
+            _this.reconnectInterval = 1;
+            if (_this.doNotConnect) {
+                _this.updateNetworkState('closing');
+                uni.closeSocket();
+                return;
+            }
+            _this.updateNetworkState('established');
+            if (options.onOpen) {
+                options.onOpen(res);
+            }
+        });
+
+        if (options.onMessage) {
+            uni.onSocketMessage(options.onMessage);
+        }
+
+        uni.onSocketClose(function (res) {
+            _this.updateNetworkState('disconnected');
+            if (!_this.doNotConnect) {
+                _this.waitReconnect();
+            }
+            if (options.onClose) {
+                options.onClose(res);
+            }
+        });
+
+        uni.onSocketError(function (res) {
+            _this.close();
+            if (!_this.doNotConnect) {
+                _this.waitReconnect();
+            }
+            if (options.onError) {
+                options.onError(res);
+            }
+        });
+    };
+    uni.connectSocket({
+        url: options.url,
+        fail: function (res) {
+            console.log('uni.connectSocket fail');
+            console.log(res);
+            _this.updateNetworkState('disconnected');
+            _this.waitReconnect();
+        },
+        success: function() {
+
+        }
+    });
+    cb();
+}
+
+Connection.prototype.connect = function () {
+    this.doNotConnect = 0;
+    if (this.state === 'connected') {
+        console.log('networkState is "' + this.state + '" and do not need connect');
+        return;
+    }
+    if (this.reconnectTimer) {
+        clearTimeout(this.reconnectTimer);
+        this.reconnectTimer = 0;
+    }
+
+    this.closeAndClean();
+
+    var options = this.options;
+
+    this.updateNetworkState('connecting');
+
+    var _this = this;
+    var cb = function(){
+        uni.onSocketOpen(function (res) {
+            _this.reconnectInterval = 1;
+            if (_this.doNotConnect) {
+                _this.updateNetworkState('disconnected');
+                uni.closeSocket();
+                return;
+            }
+            if (options.onOpen) {
+                options.onOpen(res);
+            }
+        });
+
+        if (options.onMessage) {
+            uni.onSocketMessage(options.onMessage);
+        }
+
+        uni.onSocketClose(function (res) {
+            _this.updateNetworkState('disconnected');
+            if (!_this.doNotConnect) {
+                _this.waitReconnect();
+            }
+            if (options.onClose) {
+                options.onClose(res);
+            }
+        });
+
+        uni.onSocketError(function (res) {
+            _this.close();
+            if (!_this.doNotConnect) {
+                _this.waitReconnect();
+            }
+            if (options.onError) {
+                options.onError(res);
+            }
+        });
+    };
+    uni.connectSocket({
+        url: options.url+'/app/'+options.app_key,
+        fail: function (res) {
+            console.log('uni.connectSocket fail');
+            console.log(res);
+            _this.updateNetworkState('disconnected');
+            _this.waitReconnect();
+        },
+        success: function() {
+
+        }
+    });
+    cb();
+}
+
+Connection.prototype.closeAndClean = function () {
+    if (this.state === 'connected') {
+        uni.closeSocket();
+    }
+    this.updateNetworkState('disconnected');
+};
+
+Connection.prototype.waitReconnect = function () {
+    if (this.state === 'connected' || this.state === 'connecting') {
+        return;
+    }
+    if (!this.doNotConnect) {
+        this.updateNetworkState('connecting');
+        var _this = this;
+        if (this.reconnectTimer) {
+            clearTimeout(this.reconnectTimer);
+        }
+        this.reconnectTimer = setTimeout(function(){
+            _this.connect();
+        }, this.reconnectInterval);
+        if (this.reconnectInterval < 1000) {
+            this.reconnectInterval = 1000;
+        } else {
+            // 每次重连间隔增大一倍
+            this.reconnectInterval = this.reconnectInterval * 2;
+        }
+        // 有网络的状态下,重连间隔最大2秒
+        if (this.reconnectInterval > 2000) {
+            uni.getNetworkType({
+                success: function (res) {
+                    if (res.networkType != 'none') {
+                        _this.reconnectInterval = 1000;
+                    }
+                }
+            });
+        }
+    }
+}
+
+Connection.prototype.send = function(data) {
+    if (this.state !== 'connected') {
+        console.trace('networkState is "' + this.state + '", can not send ' + data);
+        return;
+    }
+    uni.sendSocketMessage({
+        data: data
+    });
+}
+
+Connection.prototype.close = function(){
+    this.updateNetworkState('disconnected');
+    uni.closeSocket();
+}
+
+var __extends = (this && this.__extends) || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) {d[p] = b[p];}
+    function __() { this.constructor = d; }
+    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+};
+
+function Channel(connection, channel_name) {
+    this.subscribed = false;
+    this.dispatcher = new Dispatcher();
+    this.connection = connection;
+    this.channelName = channel_name;
+    this.subscribeCb = null;
+    this.queue = [];
+    __extends(this, this.dispatcher);
+    var properies = ['on', 'off', 'emit'];
+    for (var i in properies) {
+        this[properies[i]] = this.dispatcher[properies[i]];
+    }
+}
+
+Channel.prototype.processSubscribe = function () {
+    if (this.connection.state !== 'connected') {
+        return;
+    }
+    this.subscribeCb();
+};
+
+Channel.prototype.processQueue = function () {
+    if (this.connection.state !== 'connected' || !this.subscribed) {
+        return;
+    }
+    for (var i in this.queue) {
+        this.queue[i]();
+    }
+    this.queue = [];
+};
+
+Channel.prototype.trigger = function (event, data) {
+    if (event.indexOf('client-') !== 0) {
+        throw new Error("Event '" + event + "' should start with 'client-'");
+    }
+    var _this = this;
+    this.queue.push(function () {
+        _this.connection.send(JSON.stringify({ event: event, data: data, channel: _this.channelName }));
+    });
+    this.processQueue();
+};
+
+////////////////
+var Collections = (function () {
+    var exports = {};
+    function extend(target) {
+        var sources = [];
+        for (var _i = 1; _i < arguments.length; _i++) {
+            sources[_i - 1] = arguments[_i];
+        }
+        for (var i = 0; i < sources.length; i++) {
+            var extensions = sources[i];
+            for (var property in extensions) {
+                if (extensions[property] && extensions[property].constructor &&
+                    extensions[property].constructor === Object) {
+                    target[property] = extend(target[property] || {}, extensions[property]);
+                }
+                else {
+                    target[property] = extensions[property];
+                }
+            }
+        }
+        return target;
+    }
+
+    exports.extend = extend;
+    function stringify() {
+        var m = ["Push"];
+        for (var i = 0; i < arguments.length; i++) {
+            if (typeof arguments[i] === "string") {
+                m.push(arguments[i]);
+            }
+            else {
+                m.push(safeJSONStringify(arguments[i]));
+            }
+        }
+        return m.join(" : ");
+    }
+
+    exports.stringify = stringify;
+    function arrayIndexOf(array, item) {
+        var nativeIndexOf = Array.prototype.indexOf;
+        if (array === null) {
+            return -1;
+        }
+        if (nativeIndexOf && array.indexOf === nativeIndexOf) {
+            return array.indexOf(item);
+        }
+        for (var i = 0, l = array.length; i < l; i++) {
+            if (array[i] === item) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    exports.arrayIndexOf = arrayIndexOf;
+    function objectApply(object, f) {
+        for (var key in object) {
+            if (Object.prototype.hasOwnProperty.call(object, key)) {
+                f(object[key], key, object);
+            }
+        }
+    }
+
+    exports.objectApply = objectApply;
+    function keys(object) {
+        var keys = [];
+        objectApply(object, function (_, key) {
+            keys.push(key);
+        });
+        return keys;
+    }
+
+    exports.keys = keys;
+    function values(object) {
+        var values = [];
+        objectApply(object, function (value) {
+            values.push(value);
+        });
+        return values;
+    }
+
+    exports.values = values;
+    function apply(array, f, context) {
+        for (var i = 0; i < array.length; i++) {
+            f.call(context || (window), array[i], i, array);
+        }
+    }
+
+    exports.apply = apply;
+    function map(array, f) {
+        var result = [];
+        for (var i = 0; i < array.length; i++) {
+            result.push(f(array[i], i, array, result));
+        }
+        return result;
+    }
+
+    exports.map = map;
+    function mapObject(object, f) {
+        var result = {};
+        objectApply(object, function (value, key) {
+            result[key] = f(value);
+        });
+        return result;
+    }
+
+    exports.mapObject = mapObject;
+    function filter(array, test) {
+        test = test || function (value) {
+            return !!value;
+        };
+        var result = [];
+        for (var i = 0; i < array.length; i++) {
+            if (test(array[i], i, array, result)) {
+                result.push(array[i]);
+            }
+        }
+        return result;
+    }
+
+    exports.filter = filter;
+    function filterObject(object, test) {
+        var result = {};
+        objectApply(object, function (value, key) {
+            if ((test && test(value, key, object, result)) || Boolean(value)) {
+                result[key] = value;
+            }
+        });
+        return result;
+    }
+
+    exports.filterObject = filterObject;
+    function flatten(object) {
+        var result = [];
+        objectApply(object, function (value, key) {
+            result.push([key, value]);
+        });
+        return result;
+    }
+
+    exports.flatten = flatten;
+    function any(array, test) {
+        for (var i = 0; i < array.length; i++) {
+            if (test(array[i], i, array)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    exports.any = any;
+    function all(array, test) {
+        for (var i = 0; i < array.length; i++) {
+            if (!test(array[i], i, array)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    exports.all = all;
+    function encodeParamsObject(data) {
+        return mapObject(data, function (value) {
+            if (typeof value === "object") {
+                value = safeJSONStringify(value);
+            }
+            return encodeURIComponent(base64_1["default"](value.toString()));
+        });
+    }
+
+    exports.encodeParamsObject = encodeParamsObject;
+    function buildQueryString(data) {
+        var params = filterObject(data, function (value) {
+            return value !== undefined;
+        });
+        return map(flatten(encodeParamsObject(params)), util_1["default"].method("join", "=")).join("&");
+    }
+
+    exports.buildQueryString = buildQueryString;
+    function decycleObject(object) {
+        var objects = [], paths = [];
+        return (function derez(value, path) {
+            var i, name, nu;
+            switch (typeof value) {
+                case 'object':
+                    if (!value) {
+                        return null;
+                    }
+                    for (i = 0; i < objects.length; i += 1) {
+                        if (objects[i] === value) {
+                            return {$ref: paths[i]};
+                        }
+                    }
+                    objects.push(value);
+                    paths.push(path);
+                    if (Object.prototype.toString.apply(value) === '[object Array]') {
+                        nu = [];
+                        for (i = 0; i < value.length; i += 1) {
+                            nu[i] = derez(value[i], path + '[' + i + ']');
+                        }
+                    }
+                    else {
+                        nu = {};
+                        for (name in value) {
+                            if (Object.prototype.hasOwnProperty.call(value, name)) {
+                                nu[name] = derez(value[name], path + '[' + JSON.stringify(name) + ']');
+                            }
+                        }
+                    }
+                    return nu;
+                case 'number':
+                case 'string':
+                case 'boolean':
+                    return value;
+            }
+        }(object, '$'));
+    }
+
+    exports.decycleObject = decycleObject;
+    function safeJSONStringify(source) {
+        try {
+            return JSON.stringify(source);
+        }
+        catch (e) {
+            return JSON.stringify(decycleObject(source));
+        }
+    }
+
+    exports.safeJSONStringify = safeJSONStringify;
+    return exports;
+})();
+
+var Dispatcher = (function () {
+    function Dispatcher(failThrough) {
+        this.callbacks = new CallbackRegistry();
+        this.global_callbacks = [];
+        this.failThrough = failThrough;
+    }
+    Dispatcher.prototype.on = function (eventName, callback, context) {
+        this.callbacks.add(eventName, callback, context);
+        return this;
+    };
+    Dispatcher.prototype.on_global = function (callback) {
+        this.global_callbacks.push(callback);
+        return this;
+    };
+    Dispatcher.prototype.off = function (eventName, callback, context) {
+        this.callbacks.remove(eventName, callback, context);
+        return this;
+    };
+    Dispatcher.prototype.emit = function (eventName, data) {
+        var i;
+        for (i = 0; i < this.global_callbacks.length; i++) {
+            this.global_callbacks[i](eventName, data);
+        }
+        var callbacks = this.callbacks.get(eventName);
+        if (callbacks && callbacks.length > 0) {
+            for (i = 0; i < callbacks.length; i++) {
+                callbacks[i].fn.call(callbacks[i].context || (window), data);
+            }
+        }
+        else if (this.failThrough) {
+            this.failThrough(eventName, data);
+        }
+        return this;
+    };
+    return Dispatcher;
+}());
+
+var CallbackRegistry = (function () {
+    function CallbackRegistry() {
+        this._callbacks = {};
+    }
+    CallbackRegistry.prototype.get = function (name) {
+        return this._callbacks[prefix(name)];
+    };
+    CallbackRegistry.prototype.add = function (name, callback, context) {
+        var prefixedEventName = prefix(name);
+        this._callbacks[prefixedEventName] = this._callbacks[prefixedEventName] || [];
+        this._callbacks[prefixedEventName].push({
+            fn: callback,
+            context: context
+        });
+    };
+    CallbackRegistry.prototype.remove = function (name, callback, context) {
+        if (!name && !callback && !context) {
+            this._callbacks = {};
+            return;
+        }
+        var names = name ? [prefix(name)] : Collections.keys(this._callbacks);
+        if (callback || context) {
+            this.removeCallback(names, callback, context);
+        }
+        else {
+            this.removeAllCallbacks(names);
+        }
+    };
+    CallbackRegistry.prototype.removeCallback = function (names, callback, context) {
+        Collections.apply(names, function (name) {
+            this._callbacks[name] = Collections.filter(this._callbacks[name] || [], function (oning) {
+                return (callback && callback !== oning.fn) ||
+                    (context && context !== oning.context);
+            });
+            if (this._callbacks[name].length === 0) {
+                delete this._callbacks[name];
+            }
+        }, this);
+    };
+    CallbackRegistry.prototype.removeAllCallbacks = function (names) {
+        Collections.apply(names, function (name) {
+            delete this._callbacks[name];
+        }, this);
+    };
+    return CallbackRegistry;
+}());
+function prefix(name) {
+    return "_" + name;
+}
+
+function __ajax(options){
+    options=options||{};
+    options.type=(options.type||'GET').toUpperCase();
+    options.dataType=options.dataType||'json';
+    var params=formatParams(options.data);
+
+    var xhr;
+    if(window.XMLHttpRequest){
+        xhr=new XMLHttpRequest();
+    }else{
+        xhr=ActiveXObject('Microsoft.XMLHTTP');
+    }
+
+    xhr.onreadystatechange=function(){
+        if(xhr.readyState === 4){
+            var status=xhr.status;
+            if(status>=200 && status<300){
+                options.success&&options.success(xhr.responseText,xhr.responseXML);
+            }else{
+                options.error&&options.error(status);
+            }
+        }
+    }
+
+    if(options.type==='GET'){
+        xhr.open('GET',options.url+'?'+params,true);
+        xhr.send(null);
+    }else if(options.type==='POST'){
+        xhr.open('POST',options.url,true);
+        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+        xhr.send(params);
+    }
+}
+
+function formatParams(data){
+    var arr=[];
+    for(var name in data){
+        arr.push(encodeURIComponent(name)+'='+encodeURIComponent(data[name]));
+    }
+    return arr.join('&');
+}
+
+export default Push

+ 24 - 0
奥莱优品/utils/js/show.js

@@ -0,0 +1,24 @@
+// str 文案
+// time 时间
+// icon 图标
+// mask is防止触摸穿透
+export const show = (title = "文案", duration = 2000, icon = 'none', mask = true) => {
+	uni.showToast({
+		title,
+		duration,
+		icon,
+		mask,
+	});
+	return new Promise((r, e) => {
+		setTimeout(() => {
+			r()
+		}, duration)
+	})
+}
+// icon:
+// success		显示成功图标,此时 title 文本在小程序平台最多显示 7 个汉字长度
+// error		显示错误图标,此时 title 文本在小程序平台最多显示 7 个汉字长度。	
+// fail	 		显示对号图标,此时 title 文本无长度显示。	
+// exception	显示异常图标,此时 title 文本无长度显示。	
+// loading		显示加载图标,此时 title 文本在小程序平台最多显示 7 个汉字长度。
+// none			不显示图标,此时 title 文本在小程序最多可显示两行,App仅支持单行显示

+ 22 - 0
奥莱优品/utils/js/throttle.js

@@ -0,0 +1,22 @@
+// 节流函数
+let timer;
+let flag;
+export const throttle = (func, wait = 500, immediate = true) => {
+	if (immediate) {
+		if (!flag) {
+			flag = true
+			// 如果是立即执行,则在wait毫秒内开始时执行
+			typeof func === 'function' && func()
+			timer = setTimeout(() => {
+				flag = false
+			}, wait)
+		}
+	} else if (!flag) {
+		flag = true
+		// 如果是非立即执行,则在wait毫秒内的结束处执行
+		timer = setTimeout(() => {
+			flag = false
+			typeof func === 'function' && func()
+		}, wait)
+	}
+}

+ 57 - 0
奥莱优品/utils/js/to.js

@@ -0,0 +1,57 @@
+function isObj(obj) {
+	let array = Object.keys(obj);
+	if (array.length === 0) { //如果数组array的长度为0 ,则返回为true,说明data对象为空
+		return false;
+	}
+	return true;
+};
+
+export const to = (url = "", data = {}, type = 'navigateTo', oNexit = "/pages/home/index") => {
+	if (!url) {
+		let pages = getCurrentPages(); // 获取当前页面栈的实例
+		if (pages.length === 1) {
+			// 没有上一页就跳转oNexit
+			uni.reLaunch({
+				url: oNexit
+			})
+			return;
+		}
+		uni.navigateBack()
+		return;
+	};
+	if (isObj(data)) {
+		// #ifdef MP
+		const route_data = encodeURIComponent(JSON.stringify(data))
+		// #endif
+		// #ifndef MP
+		const route_data = JSON.stringify(data)
+		// #endif
+		if (type === 'navigateTo') {
+			uni.navigateTo({
+				url: `${url}?data=${route_data}`
+			})
+		} else if (type === 'redirectTo') {
+			uni.redirectTo({
+				url: `${url}?data=${route_data}`
+			})
+		} else {
+			uni.reLaunch({
+				url: `${url}?data=${route_data}`
+			})
+		}
+	} else {
+		if (type === 'navigateTo') {
+			uni.navigateTo({
+				url: `${url}`
+			})
+		} else if (type === 'redirectTo') {
+			uni.redirectTo({
+				url: `${url}`
+			})
+		} else {
+			uni.reLaunch({
+				url: `${url}`
+			})
+		}
+	}
+}

Some files were not shown because too many files changed in this diff