first commit

This commit is contained in:
2023-09-07 00:56:03 +08:00
commit c0ca154d31
718 changed files with 56107 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
/unpackage
/.hbuilderx
/node_modules

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,33 @@
/* 1. 背景色 */
.page{
background-color: #EDEDED;
/* #ifndef APP-PLUS-NVUE */
min-height: 100vh;
height: auto;
/* #endif */
/* #ifdef APP-PLUS-NVUE */
flex: 1;
/* #endif */
}
/* 2. 主背景色 绿 */
.main-bg-color{
background-color: #06a1c0;
}
.main-bg-hover-color{
background-color: #06a1c0;
}
/* 3. 主文字色(绿) */
.main-text-color{
color: #06a1c0;
}
.border-main{
border-color: #06a1c0!important;
}
.bg-chat-item{
background-color: #06a1c0;
}
.text-chat-item{
color: #06a1c0;
}

View File

@@ -0,0 +1,394 @@
.view,.text{
font-size:28rpx;
line-height:1.8;
color:#0E151D;
}
/* 宽度 */
.w-100{ width: 750rpx; }
.row {
margin-right: -20rpx;
margin-left: -20rpx;
/* #ifndef APP-PLUS-NVUE */
display: flex;
/* #endif */
flex-wrap: wrap;
flex-direction: row;
}
.col-1,
.col-2,
.col-3,
.col-4,
.col-5,
.col-6,
.col-7,
.col-8,
.col-9,
.col-10,
.col-11,
.col-12{
position: relative;
padding-right: 20rpx;
padding-left: 20rpx;
}
.col-12 { width: 750rpx;}
.col-11 { width: 687.5rpx; }
.col-10 { width: 625rpx; }
.col-9 { width: 562.5rpx; }
.col-8 { width: 500rpx; }
.col-7 { width: 437.5rpx; }
.col-6 { width: 375rpx; }
.col-5 { width: 312.5rpx;}
.col-4 {width: 250rpx;}
.col-3 {width: 187.5rpx;}
.col-2 {width: 125rpx;}
.col-1 {width: 62.5rpx;}
.col-offset-12 { margin-left: 750rpx;}
.col-offset-11 { margin-left: 687.5rpx; }
.col-offset-10 { margin-left: 625rpx; }
.col-offset-9 { margin-left: 562.5rpx; }
.col-offset-8 { margin-left: 500rpx; }
.col-offset-7 { margin-left: 437.5rpx; }
.col-offset-6 { margin-left: 375rpx; }
.col-offset-5 { margin-left: 312.5rpx;}
.col-offset-4 {margin-left: 250rpx;}
.col-offset-3 {margin-left: 187.5rpx;}
.col-offset-2 {margin-left: 125rpx;}
.col-offset-1 {margin-left: 62.5rpx;}
.col-offset-0 {margin-left: 0;}
/* 背景颜色 */
.bg-primary { background-color: #007bff;}
.bg-hover-primary:hover{ background-color: #0062cc;}
.bg-secondary { background-color: #6c757d;}
.bg-hover-secondary:hover{ background-color: #545b62;}
.bg-success { background-color: #28a745;}
.bg-hover-success { background-color: #1e7e34;}
.bg-info { background-color: #17a2b8;}
.bg-hover-info { background-color: #117a8b;}
.bg-warning { background-color: #ffc107;}
.bg-hover-warning { background-color: #d39e00;}
.bg-danger { background-color: #dc3545;}
.bg-hover-danger{ background-color: #bd2130;}
.bg-light { background-color: #f8f9fa;}
.bg-hover-light{ background-color: #dae0e5;}
.bg-dark { background-color: #343a40;}
.bg-hover-dark { background-color: #1d2124;}
.bg-white { background-color: #ffffff;}
.bg-transparent { background-color: transparent;}
/* flex 布局 */
.flex{
/* #ifndef APP-PLUS-NVUE */
display:flex;
/* #endif */
flex-direction:row;
}
.flex-row{ flex-direction:row!important; }
.flex-column{ flex-direction:column!important; }
.flex-row-reverse{ flex-direction:row-reverse!important; }
.flex-column-reverse{ flex-direction:column-reverse!important; }
.flex-wrap{ flex-wrap:wrap;}
.flex-nowrap{ flex-wrap:nowrap;}
.justify-start{justify-content:flex-start;}
.justify-end{justify-content:flex-end;}
.justify-between{justify-content:space-between;}
.justify-center{justify-content:center;}
.align-center{ align-items: center; }
.align-stretch{ align-items: stretch; }
.align-start{ align-items: flex-start; }
.align-end{ align-items: flex-end; }
/* #ifndef APP-PLUS-NVUE */
.content-start {align-content: flex-start;}
.content-end {align-content: flex-end;}
.content-center {align-content: center;}
.content-between {align-content: space-between;}
.content-around {align-content: space-around;}
.content-stretch {align-content: stretch;}
/* #endif */
.flex-1{ flex: 1; }
.flex-2{ flex: 2; }
.flex-3{ flex: 3; }
.flex-4{ flex: 4; }
.flex-5{ flex: 5; }
/* #ifndef APP-PLUS-NVUE */
.flex-shrink{ flex-shrink: 0; }
/* #endif */
.container {
padding-right: 20rpx;
padding-left: 20rpx;
}
/* -- 内外边距 -- */
.m-0 { margin: 0; }
/* #ifndef APP-PLUS-NVUE */
.m-auto{ margin: auto; }
/* #endif */
.m-1 { margin: 10rpx; }
.m-2 { margin: 20rpx; }
.m-3 { margin: 30rpx; }
.m-4 { margin: 40rpx; }
.m-5 { margin: 50rpx; }
.mt-0 { margin-top: 0; }
/* #ifndef APP-PLUS-NVUE */
.mt-auto { margin-top: auto; }
/* #endif */
.mt-1 { margin-top: 10rpx; }
.mt-2 { margin-top: 20rpx; }
.mt-3 { margin-top: 30rpx; }
.mt-4 { margin-top: 40rpx; }
.mt-5 { margin-top: 50rpx; }
.mb-0 { margin-bottom: 0; }
/* #ifndef APP-PLUS-NVUE */
.mb-auto { margin-bottom: auto; }
/* #endif */
.mb-1 { margin-bottom: 10rpx; }
.mb-2 { margin-bottom: 20rpx; }
.mb-3 { margin-bottom: 30rpx; }
.mb-4 { margin-bottom: 40rpx; }
.mb-5 { margin-bottom: 50rpx; }
.ml-0 { margin-left: 0; }
/* #ifndef APP-PLUS-NVUE */
.ml-auto { margin-left: auto; }
/* #endif */
.ml-1 { margin-left: 10rpx; }
.ml-2 { margin-left: 20rpx; }
.ml-3 { margin-left: 30rpx; }
.ml-4 { margin-left: 40rpx; }
.ml-5 { margin-left: 50rpx; }
.mr-0 { margin-right: 0; }
/* #ifndef APP-PLUS-NVUE */
.mr-auto { margin-right: auto; }
/* #endif */
.mr-1 { margin-right: 10rpx; }
.mr-2 { margin-right: 20rpx; }
.mr-3 { margin-right: 30rpx; }
.mr-4 { margin-right: 40rpx; }
.mr-5 { margin-right: 50rpx; }
.my-0 { margin-top: 0; margin-bottom: 0; }
/* #ifndef APP-PLUS-NVUE */
.my-auto { margin-top: auto; margin-bottom: auto; }
/* #endif */
.my-1 { margin-top: 10rpx; margin-bottom: 10rpx; }
.my-2 { margin-top: 20rpx; margin-bottom: 20rpx; }
.my-3 { margin-top: 30rpx; margin-bottom: 30rpx; }
.my-4 { margin-top: 40rpx; margin-bottom: 40rpx; }
.my-5 { margin-top: 50rpx; margin-bottom: 50rpx; }
.mx-0 { margin-left: 0; margin-right: 0; }
/* #ifndef APP-PLUS-NVUE */
.mx-auto { margin-left: auto; margin-right: auto; }
/* #endif */
.mx-1 { margin-left: 10rpx; margin-right: 10rpx;}
.mx-2 { margin-left: 20rpx; margin-right: 20rpx;}
.mx-3 { margin-left: 30rpx; margin-right: 30rpx;}
.mx-4 { margin-left: 40rpx; margin-right: 40rpx;}
.mx-5 { margin-left: 50rpx; margin-right: 50rpx;}
.p-0 { padding: 0; }
.p { padding: 5rpx; }
.p-1 { padding: 10rpx; }
.p-2 { padding: 20rpx; }
.p-3 { padding: 30rpx; }
.p-4 { padding: 40rpx; }
.p-5 { padding: 50rpx; }
.pt-0 { padding-top: 0; }
.pt { padding-top: 5rpx; }
.pt-1 { padding-top: 10rpx; }
.pt-2 { padding-top: 20rpx; }
.pt-3 { padding-top: 30rpx; }
.pt-4 { padding-top: 40rpx; }
.pt-5 { padding-top: 50rpx; }
.pb-0 { padding-bottom: 0; }
.pb-1 { padding-bottom: 10rpx; }
.pb { padding-bottom: 5rpx; }
.pb-2 { padding-bottom: 20rpx; }
.pb-3 { padding-bottom: 30rpx; }
.pb-4 { padding-bottom: 40rpx; }
.pb-5 { padding-bottom: 50rpx; }
.pl-0 { padding-left: 0; }
.pl { padding-left: 5rpx; }
.pl-1 { padding-left: 10rpx; }
.pl-2 { padding-left: 20rpx; }
.pl-3 { padding-left: 30rpx; }
.pl-4 { padding-left: 40rpx; }
.pl-5 { padding-left: 50rpx; }
.pr-0 { padding-right: 0; }
.pr { padding-right: 5rpx; }
.pr-1 { padding-right: 10rpx; }
.pr-2 { padding-right: 20rpx; }
.pr-3 { padding-right: 30rpx; }
.pr-4 { padding-right: 40rpx; }
.pr-5 { padding-right: 50rpx; }
.py-0 { padding-top: 0; padding-bottom: 0; }
.py { padding-top: 5rpx; padding-bottom: 5rpx; }
.py-1 { padding-top: 10rpx; padding-bottom: 10rpx; }
.py-2 { padding-top: 20rpx; padding-bottom: 20rpx; }
.py-3 { padding-top: 30rpx; padding-bottom: 30rpx; }
.py-4 { padding-top: 40rpx; padding-bottom: 40rpx; }
.py-5 { padding-top: 50rpx; padding-bottom: 50rpx; }
.px-0 { padding-left: 0; padding-right: 0; }
.px-1 { padding-left: 10rpx; padding-right: 10rpx;}
.px { padding-left: 5rpx; padding-right: 5rpx;}
.px-2 { padding-left: 20rpx; padding-right: 20rpx;}
.px-3 { padding-left: 30rpx; padding-right: 30rpx;}
.px-4 { padding-left: 40rpx; padding-right: 40rpx;}
.px-5 { padding-left: 50rpx; padding-right: 50rpx;}
/* 文字大小 */
.font-small { font-size: 20upx;}
.font-sm { font-size: 25upx;}
.font { font-size: 30upx;}
.font-md { font-size: 35upx;}
.font-lg { font-size: 40upx;}
.h1{font-size:80upx; line-height:1.8;}
.h2{font-size:60upx; line-height:1.8;}
.h3{font-size:45upx; line-height:1.8;}
.h4{font-size:32upx; line-height:1.8;}
.h5{font-size:30upx; line-height:1.8;}
.h6{font-size:28upx; line-height:1.8;}
/* 文字缩进 */
/* #ifndef APP-PLUS-NVUE */
.text-indent{text-indent:2;}
/* #endif */
/* 文字划线 */
.text-through{text-decoration:line-through;}
/* 文字对齐 */
.text-left { text-align: left;}
.text-right { text-align: right;}
.text-center { text-align: center;}
/* 文字换行溢出处理 */
.text-ellipsis {
/* #ifndef APP-PLUS-NVUE */
overflow: hidden;text-overflow: ellipsis;white-space: nowrap;
/* #endif */
/* #ifdef APP-PLUS-NVUE */
lines: 1;
/* #endif */
}
/* 文字粗细和斜体 */
.font-weight-light {font-weight: 300;} /*细*/
.font-weight-lighter {font-weight: 100;}/*更细*/
.font-weight-normal { font-weight: 400;} /*正常*/
.font-weight-bold { font-weight: 700;} /*粗*/
.font-weight-bolder { font-weight: bold;} /*更粗*/
.font-italic { font-style: italic;} /*斜体*/
/* 文字颜色 */
.text-white {color: #ffffff;}
.text-primary {color: #007bff;}
.text-hover-primary { color: #0056b3;}
.text-secondary {color: #6c757d;}
.text-hover-secondary { color: #494f54;}
.text-success {color: #28a745;}
.text-hover-success{color: #19692c;}
.text-info { color: #17a2b8;}
.text-hover-info {color: #0f6674;}
.text-warning {color: #ffc107;}
.text-hover-warning { color: #ba8b00;}
.text-danger { color: #dc3545;}
.text-hover-danger { color: #a71d2a;}
.text-light { color: #f8f9fa;}
.text-hover-light { color: #cbd3da;}
.text-dark { color: #343a40;}
.text-hover-dark{ color: #121416;}
.text-body { color: #212529;}
.text-muted { color: #6c757d;}
.text-light-muted { color: #A9A5A0;}
.text-light-black { color: rgba(0, 0, 0, 0.5);}
.text-light-white { color: rgba(255, 255, 255, 0.5);}
/* 边框 */
.border { border-width: 1rpx;border-style: solid;border-color: #dee2e6;}
.border-top {
border-top-width: 1rpx;
border-top-style: solid;
border-top-color: #dee2e6;
}
.border-right {
border-right-width: 1rpx;
border-right-style: solid;
border-right-color: #dee2e6;
}
.border-bottom {
border-bottom-width: 1rpx;
border-bottom-style: solid;
border-bottom-color: #dee2e6;
}
.border-left {
border-left-width: 1rpx;
border-left-style: solid;
border-left-color: #dee2e6;
}
.border-0 { border-width: 0!important;}
.border-top-0 { border-top-width: 0!important;}
.border-right-0 {border-right-width: 0!important;}
.border-bottom-0 {border-bottom-width: 0!important;}
.border-left-0 {border-left-width: 0!important;}
.border-primary { border-color: #007bff;}
.border-secondary {border-color: #6c757d;}
.border-light-secondary {border-color: #E9E8E5;}
.border-success {border-color: #28a745;}
.border-info {border-color: #17a2b8;}
.border-warning {border-color: #ffc107;}
.border-danger {border-color: #dc3545;}
.border-light {border-color: #f8f9fa;}
.border-dark {border-color: #343a40;}
.border-white {border-color: #FFFFFF;}
/* 圆角 */
.rounded { border-radius: 8rpx;}
.rounded-top {
border-top-left-radius: 8rpx;
border-top-right-radius: 8rpx;
}
.rounded-right {
border-top-right-radius: 8rpx;
border-bottom-right-radius: 8rpx;
}
.rounded-bottom {
border-bottom-right-radius: 8rpx;
border-bottom-left-radius: 8rpx;
}
.rounded-left {
border-top-left-radius: 8rpx;
border-bottom-left-radius: 8rpx;
}
.rounded-circle { border-radius: 100rpx;}
.rounded-0 { border-radius: 0;}
/* 显示 */
/* #ifndef APP-PLUS-NVUE */
.d-none{ display: none; }
.d-inline-block{ display: inline-block; }
.d-block{ display: block; }
/* #endif */
/* 内容溢出 */
.overflow-hidden { overflow: hidden;}
/* 定位 */
.position-relative { position: relative;}
.position-absolute { position: absolute;}
.position-fixed { position: fixed;}
/* 定位 - 固定顶部 */
.fixed-top {
position: fixed;
top: 0;
right: 0;
left: 0;
z-index: 1030;
}
/* 定位 - 固定底部 */
.fixed-bottom {
position: fixed;
right: 0;
bottom: 0;
left: 0;
z-index: 1030;
}
.top-0 { top: 0; }
.left-0 { left: 0; }
.right-0 { right: 0; }
.bottom-0 { bottom: 0; }
/* 图标 */
.iconfont{
font-family:iconfont;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,15 @@
function getIM(){
// UNIAPP 环境
if(typeof uni !== 'undefined'){
return {im:uni['im'], im_webtoolkit:uni['im_webtoolkit']};
}
throw Error(" Couldn't not fetch lim.");
}
const lim = {
im: getIM().im,
};
module.exports = lim;

View File

@@ -0,0 +1,6 @@
export default {
baseUrl:"http://127.0.0.1:8989",
version: "/v1",
}

View File

@@ -0,0 +1,91 @@
import $C from './config.js';
import $store from '@/store/index.js';
export default {
// 全局配置
common: {
baseUrl: $C.baseUrl + $C.version,
header: {
'Content-Type': 'application/json;charset=UTF-8',
},
data: {},
method: 'GET',
dataType: 'json',
token: true,
},
// get请求
get(url, data = {}, options = {}) {
options.url = url
options.data = data
options.method = 'GET'
return this.request(options)
},
// post请求
post(url, data = {}, options = {}) {
options.url = url
options.data = data
options.method = 'POST'
return this.request(options)
},
// delete请求
del(url, data = {}, options = {}) {
options.url = url
options.data = data
options.method = 'DELETE'
return this.request(options)
},
// 请求 返回promise
request(options = {}) {
// 组织参数
options.url = this.common.baseUrl + options.url
options.header = options.header || this.common.header
options.data = options.data || this.common.data
options.method = options.method || this.common.method
options.dataType = options.dataType || this.common.dataType
options.token = options.token === false ? false : this.common.token
// 请求
return new Promise((res, rej) => {
// 请求中...
uni.request({
...options,
success: (result) => {
// 返回原始数据
if (options.native) {
return res(result)
}
// 服务端失败
if (result.statusCode !== 200) {
if (options.toast !== false) {
uni.showToast({
title: result.data.data || '服务器失败',
icon: 'none'
});
}
// token不合法直接退出登录
if (result.data.code === 401) {
return uni.reLaunch({
url: '/pages/common/login/login',
})
}
return rej(result.data)
}
// 成功
let data = result.data
res(data)
},
fail: (error) => {
uni.showToast({
title: '请求失败',
icon: 'none'
});
return rej(error)
}
});
})
}
}

View File

@@ -0,0 +1,65 @@
export default{
// 获取聊天时间相差300s内的信息不会显示时间
getChatTime(v1,v2){
v1=v1.toString().length<13 ? v1*1000 : v1;
v2=v2.toString().length<13 ? v2*1000 : v2;
if(((parseInt(v1)-parseInt(v2))/1000) > 300){
return this.gettime(v1);
}
},
// 人性化时间格式
gettime(shorttime){
shorttime=shorttime.toString().length<13 ? shorttime*1000 : shorttime;
let now = (new Date()).getTime();
let cha = (now-parseInt(shorttime))/1000;
if (cha < 43200) {
// 当天
return this.dateFormat(new Date(shorttime),"{A} {t}:{ii}");
} else if(cha < 518400){
// 隔天 显示日期+时间
return this.dateFormat(new Date(shorttime),"{Mon}月{DD}日 {A} {t}:{ii}");
} else {
// 隔年 显示完整日期+时间
return this.dateFormat(new Date(shorttime),"{Y}-{MM}-{DD} {A} {t}:{ii}");
}
},
parseNumber(num) {
return num < 10 ? "0" + num : num;
},
dateFormat(date, formatStr) {
let dateObj = {},
rStr = /\{([^}]+)\}/,
mons = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'];
dateObj["Y"] = date.getFullYear();
dateObj["M"] = date.getMonth() + 1;
dateObj["MM"] = this.parseNumber(dateObj["M"]);
dateObj["Mon"] = mons[dateObj['M'] - 1];
dateObj["D"] = date.getDate();
dateObj["DD"] = this.parseNumber(dateObj["D"]);
dateObj["h"] = date.getHours();
dateObj["hh"] = this.parseNumber(dateObj["h"]);
dateObj["t"] = dateObj["h"] > 12 ? dateObj["h"] - 12 : dateObj["h"];
dateObj["tt"] = this.parseNumber(dateObj["t"]);
dateObj["A"] = dateObj["h"] > 12 ? '下午' : '上午';
dateObj["i"] = date.getMinutes();
dateObj["ii"] = this.parseNumber(dateObj["i"]);
dateObj["s"] = date.getSeconds();
dateObj["ss"] = this.parseNumber(dateObj["s"]);
while(rStr.test(formatStr)) {
formatStr = formatStr.replace(rStr, dateObj[RegExp.$1]);
}
return formatStr;
},
// 获取年龄
getAgeByBirthday(data){
let birthday=new Date(data.replace(/-/g, "\/"));
let d=new Date();
return d.getFullYear()-birthday.getFullYear()-((d.getMonth()<birthday.getMonth()|| d.getMonth()==birthday.getMonth() && d.getDate()<birthday.getDate())?1:0);
}
}

View File

@@ -0,0 +1,30 @@
export default {
onShow() {
var lim = this.imsdk
var sdk = lim.im;
let uid = sdk.getUserId();
if(uid == '' || uid == undefined){
uni.navigateTo({
url: '/pages/common/login/login'
});
}
},
methods:{
navigate(path){
uni.navigateTo({
url: '/pages/'+path,
});
},
// 返回并提示
backToast(msg = '非法参数'){
uni.showToast({
title: msg,
icon:"none"
});
uni.navigateBack({
delta: 1,
});
}
}
}

View File

@@ -0,0 +1,8 @@
import $Time from "@/common/lib/time.js"
export default {
filters: {
formatTime(value) {
return $Time.gettime(value);
}
},
}

View File

@@ -0,0 +1,50 @@
<template>
<image :src="src ? src : '/static/images/userpic.png'" mode="widthFix" :style="getStyle" :class="type" @click="clickEvent"></image>
</template>
<script>
export default {
props: {
size:{
type:[String,Number],
default:90
},
src: {
type: String,
default: ""
},
type:{
type:String,
default:"rounded"
},
clickType:{
type:String,
default:"none"
}
},
computed: {
getStyle() {
return `width: ${this.size}rpx;height: ${this.size}rpx;`
}
},
methods: {
clickEvent() {
switch (this.clickType){
case 'navigate':
// console.log(this.clickType)
uni.navigateTo({
url: '/pages/mail/user-base/user-base'
});
break;
default:
this.$emit('click')
break;
}
}
},
}
</script>
<style>
</style>

View File

@@ -0,0 +1,28 @@
<template>
<text class="badge bg-danger text-white rounded-circle font-sm" :class="badgeClass" :style="badgeStyle">{{value}}</text>
</template>
<script>
export default {
props: {
badgeClass: {
type: String,
default: ""
},
badgeStyle:{
type:String,
default:""
},
value:{
type:[Number,String],
default:""
}
},
}
</script>
<style scoped>
.badge{
padding-left: 14rpx;padding-right: 14rpx;padding-bottom: 3rpx;padding-top: 3rpx;
}
</style>

View File

@@ -0,0 +1,159 @@
<template>
<div class="" @longpress="long">
<view v-if="showTime" class="flex align-center justify-center pb-4 pt-2">
<text class="font-sm text-light-muted">{{showTime}}</text>
</view>
<view v-if="item.isRemove" ref="isRemove" class="flex align-center justify-center pb-4 pt-1 chat-animate">
<text class="font-sm text-light-muted">你撤回了一条消息</text>
</view>
<!-- 气泡 -->
<view v-else class="flex align-start position-relative mb-3"
:class="!isself ? 'justify-start' : 'justify-end'">
<!-- 好友 -->
<template v-if="!isself">
<avater size="70" :src="item.avatar" clickType="navigate"></avater>
<text v-if="hasLabelClass" class="iconfont text-white font-md position-absolute chat-left-icon"
style="">&#xe609;</text>
</template>
<div style="max-width: 500rpx;" class="p-2 rounded " :class="labelClass" :style="labelStyle">
<!-- 文字 -->
<text v-if="item.type === 'text'" class="font-md ">{{item.data}}</text>
</div>
<!-- 本人 -->
<template v-if="isself">
<text v-if="hasLabelClass" class="iconfont text-chat-item font-md position-absolute chat-right-icon"
style="">&#xe640;</text>
<avater size="70" :src="item.avatar" clickType="navigate"></avater>
</template>
</view>
</div>
</template>
<script>
import avater from "@/components/ui/avater.vue"
import fImage from "@/components/ui/fImage.vue"
import $T from "@/common/lib/time.js"
import {
mapState,
mapActions
} from 'vuex'
// #ifdef APP-PLUS-NVUE
const animation = weex.requireModule('animation')
// #endif
export default {
components: {
avater,
fImage
},
props: {
item: Object,
index: Number,
pretime: [Number, String]
},
computed: {
// 是否为本人
isself() {
var lim = this.imsdk
var sdk = lim.im;
let uid = sdk.getUserId();
// console.log(uid)
return this.item.userId === uid;
},
// 显示的时间
showTime() {
return $T.getChatTime(this.item.createTime, this.pretime)
},
// 是否需要气泡样式
hasLabelClass() {
return this.item.type === 'text'
},
// 气泡的样式
labelClass() {
let label = this.hasLabelClass ? 'bg-chat-item mr-3' : 'mr-3'
return this.isself ? label : 'bg-white ml-3'
},
labelStyle(){
}
},
methods: {
long(e) {
let x = 0
let y = 0
// #ifdef APP-PLUS-NVUE
if (Array.isArray(e.changedTouches) && e.changedTouches.length > 0) {
x = e.changedTouches[0].screenX
y = e.changedTouches[0].screenY
}
// #endif
// #ifdef H5
x = e.changedTouches[0].pageX
y = e.changedTouches[0].pageY
// #endif
// #ifdef MP
x = e.detail.x
y = e.detail.y
// #endif
this.$emit('long', {
x,
y,
index: this.index
})
},
preview(url) {
this.$emit("preview", url)
},
loadImage(e) {
let w = e.detail.width
let h = e.detail.height
// 按照宽度来
let maxW = uni.upx2px(500)
//按照高度来
let maxH = uni.upx2px(350)
if (h <= maxH) {
this.w = w <= maxW ? w : maxW;
this.h = h;
return;
}
this.h = maxH
let w2 = maxH * (w / h)
this.w = w2 <= maxW ? w2 : maxW
}
},
destroyed() {
},
data() {
return {
w: 100,
h: 100
}
},
mounted() {
// 注册全局事件
}
}
</script>
<style scoped>
.chat-left-icon {
left: 80rpx;
}
.chat-right-icon {
right: 80rpx;
}
.chat-animate {
/* #ifndef APP-PLUS-NVUE */
opacity: 0;
/* #endif */
}
</style>

View File

@@ -0,0 +1,62 @@
<template>
<popup ref="confirm" center maskColor transformOrigin="center center">
<view class="bg-white rounded" style="width: 600rpx;">
<view class="p-4 flex flex-column">
<text class="font-md font-weight-bold mb-3">{{title}}</text>
<slot></slot>
</view>
<!-- 底部 -->
<view style="height: 100rpx;" class="border-top flex align-stretch">
<view class="flex-1 border-right flex align-center justify-center" @click="cancel">
<text class="font-md text-muted">取消</text>
</view>
<view class="flex-1 flex align-center justify-center"
@click="confirm">
<text class="font-md main-text-color">确定</text>
</view>
</view>
</view>
</popup>
</template>
<script>
import popup from '@/components/ui/popup.vue';
export default {
components: {
popup
},
props: {
title: {
type: String,
default: "提示"
},
},
data() {
return {
callback: false
}
},
methods: {
// 显示
show(callback = false){
this.callback = callback
this.$refs.confirm.show()
},
// 取消
cancel() {
this.$refs.confirm.hide()
},
// 确定
confirm(){
if(typeof this.callback === 'function'){
this.callback(()=>{
this.cancel()
})
}
}
},
}
</script>
<style>
</style>

View File

@@ -0,0 +1,26 @@
<template>
<view :style="getStyle"></view>
</template>
<script>
export default {
props: {
color:{
type:String,
default:"#EFEDE9"
}
},
computed: {
getStyle(){
return `height: 18rpx;background-color: ${this.color}rpx`
}
},
methods: {
},
}
</script>
<style>
</style>

View File

@@ -0,0 +1,69 @@
<template>
<image :src="src" lazy-load :style="imageStyle" :class="imageClass" @tap="$emit('click')"
@longpress="$emit('longpress')" @load="loadImage" class="bg-hover-light"></image>
</template>
<script>
export default {
props: {
src: {
type: String,
default: ""
},
imageClass: {
type: String,
default: ""
},
maxWidth: {
type: Number,
default: 500 // rpx
},
maxHeight: {
type: Number,
default: 350 // rpx
}
},
data() {
return {
h: 100,
w: 100
}
},
computed: {
imageStyle() {
return `width:${this.w}px;height:${this.h}px;`
}
},
methods: {
// 加载图片
loadImage(e) {
let w = e.detail.width
let h = e.detail.height
// // 最大宽度 px
let maxW = uni.upx2px(this.maxWidth)
// 最大高度
let maxH = uni.upx2px(this.maxHeight)
if (h <= maxH) {
// 用原来的宽高
this.w = w <= maxW ? w : maxW
this.h = h
this.$emit('load', {
w: this.w,
h: this.h
})
return;
}
this.h = maxH
let w2 = maxH * (w / h)
this.w = w2 <= maxW ? w2 : maxW
this.$emit('load', {
w: this.w,
h: this.h
})
},
},
}
</script>
<style>
</style>

View File

@@ -0,0 +1,21 @@
<template>
<view class="flex align-center justify-center"
hover-class="bg-hover-light" @click="$emit('click')"
style="height: 90rpx;width: 90rpx;">
<text class="iconfont font-md">{{icon}}</text>
</view>
</template>
<script>
export default {
props: {
icon: {
type: String,
default: ''
},
},
}
</script>
<style>
</style>

View File

@@ -0,0 +1,71 @@
<template>
<view class="bg-white flex align-stretch" hover-class="bg-light"
@click="$emit('click')">
<view class="flex align-center justify-center py-2 pl-3"
v-if="showLeftIcon">
<slot name="icon"></slot>
<image :src="cover" v-if="cover"
mode="widthFix" :style="coverStyle"></image>
</view>
<view class="flex-1 flex align-center justify-between pr-3 py-3 pl-3" :class="border ? 'border-bottom' : ''">
<slot>
<text class="font-md text-dark">{{title}}</text>
</slot>
<view class="flex align-center" v-if="showRight">
<slot name="right"></slot>
<!-- 右箭头 -->
<text v-if="showRightIcon" class="iconfont text-light-muted font-md">&#xe60c;</text>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
// 是否开启下边线
border:{
type:Boolean,
default:true
},
// 封面
cover: {
type: String,
default: ""
},
// 封面大小
coverSize:{
type: [String,Number],
default:75
},
// 标题
title:{
type:String,
default:""
},
// 显示右边
showRight:{
type:Boolean,
default:false
},
// 显示左边图标
showLeftIcon:{
type:Boolean,
default:true
},
// 是否显示箭头
showRightIcon:{
type:Boolean,
default:true
}
},
computed: {
coverStyle() {
return `width: ${this.coverSize}rpx;height: ${this.coverSize}rpx;`
}
},
}
</script>
<style>
</style>

View File

@@ -0,0 +1,34 @@
<template>
<view class="rounded mr-2 px-2 py-1"
@click="clickEvent"
:class="disabled ? 'bg-light border' : 'main-bg-color'">
<text class="font"
:class="disabled ? 'text-light-muted':'text-white'">{{name}}</text>
</view>
</template>
<script>
export default {
props: {
name: {
type: String,
default: ""
},
disabled:{
type:Boolean,
default:false
}
},
methods: {
clickEvent() {
console.log("clickEvent")
if(!this.disabled){
this.$emit('click')
}
}
},
}
</script>
<style>
</style>

View File

@@ -0,0 +1,76 @@
<template>
<view :class="item.istop ? 'bg-light' : 'bg-white'" hover-class="bg-hover-light">
<div class="flex align-stretch" @click="onClick" @longpress="long">
<view class="flex align-center justify-center position-relative" style="width: 145rpx;">
<avater :src="item.avatar" size="92"></avater>
<badge badgeClass="position-absolute" badgeStyle="top:15rpx;right:15rpx" v-if="item.noreadnum"
:value="item.noreadnum"></badge>
</view>
<view class="flex flex-column border-bottom flex-1 py-3 pr-3 border-light-secondary">
<view class="flex align-center justify-between mb-1">
<text class="font-md">{{item.nickname}}</text>
<text class="font-sm text-light-muted">{{item.updateTime|formatTime}}</text>
</view>
<text class="font-sm text-ellipsis text-light-muted">{{item.data}}</text>
</view>
</div>
</view>
</template>
<script>
import base from "@/common/mixin/base.js"
import avater from "@/components/ui/avater.vue"
import badge from "@/components/ui/badge.vue"
export default {
mixins:[base],
components: {
avater,
badge
},
props: {
item: Object,
index:Number
},
methods:{
onClick(){
uni.navigateTo({
url: '/pages/chat/chat/chat?params='+encodeURIComponent(JSON.stringify({
id:this.item.id
}))
});
},
long(e){
let x = 0
let y = 0
// #ifdef APP-PLUS-NVUE
if (Array.isArray(e.changedTouches) && e.changedTouches.length > 0) {
x = e.changedTouches[0].screenX
y = e.changedTouches[0].screenY
}
// #endif
// #ifdef H5
x = e.changedTouches[0].pageX
y = e.changedTouches[0].pageY
// #endif
// #ifdef MP
x = e.detail.x
y = e.detail.y
// #endif
console.log(this.index)
this.$emit('long',{
x,
y,
index:this.index
})
}
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,182 @@
<template>
<view>
<view :class="getClass">
<!-- 状态栏 -->
<view :style="'height:'+statusBarHeight+'px'"></view>
<!-- 导航 -->
<view class="w-100 flex align-center justify-between" style="height: 90rpx;">
<!-- 左边 -->
<view class="flex align-center">
<!-- 返回按钮 -->
<!-- #ifndef MP -->
<icon-button v-if="showBack" @click="back"
:icon="'\ue60d'"></icon-button>
<!-- #endif -->
<!-- 标题 -->
<slot>
<text v-if="title" class="font-md ml-3">{{getTitle}}</text>
</slot>
</view>
<!-- 右边 -->
<view class="flex align-center" v-if="showRight">
<slot name="right">
<icon-button @click="search" :icon="'\ue6e3'"></icon-button>
<icon-button @click="openExtend" :icon="'\ue682'"></icon-button>
</slot>
</view>
</view>
</view>
<!-- 占位 -->
<view v-if="fixed" :style="fixedStyle"></view>
<!-- 扩展菜单 -->
<popup v-if="showRight" ref="extend" :bodyWidth="320" :bodyHeight="525"
bodyBgColor="bg-dark" transformOrigin="right top">
<view class="flex flex-column"
style="width: 320rpx;height: 525rpx;">
<view class="flex-1 flex align-center"
hover-class="bg-hover-dark"
v-for="(item,index) in menus"
:key="index"
@click="clickEvent(item)">
<text class="iconfont pl-3 pr-2 font-md text-white">{{item.icon}}</text>
<text class="font-md text-white">{{item.name}}</text>
</view>
</view>
</popup>
</view>
</template>
<script>
import iconButton from "./icon-button.vue"
import popup from "./popup.vue"
import $H from '@/common/lib/request.js';
export default {
props: {
showBack:{
type:Boolean,
default:false
},
backEvent:{
type:Boolean,
default:true
},
title: {
type: [String,Boolean],
default:false
},
fixed:{
type:Boolean,
default:true
},
noreadnum:{
type:[Number,String],
default:0
},
bgColor:{
type:String,
default:"bg-light"
},
showRight:{
type:Boolean,
default:true
}
},
components:{
iconButton,
popup
},
data() {
return {
statusBarHeight:0,
navBarHeight:0,
menus:[
{
name:"发起群聊",
event:"navigateTo",
path:'',
icon:"\ue633"
},
{
name:"添加好友",
event:"navigateTo",
path:'',
icon:"\ue65d"
},
{
name:"扫一扫",
event:"scan",
icon:"\ue614"
},
{
name:"收付款",
event:"",
icon:"\ue66c"
},
{
name:"帮助与反馈",
event:"",
icon:"\ue66c"
}
],
}
},
mounted() {
// #ifdef APP-PLUS-NVUE
this.statusBarHeight = plus.navigator.getStatusbarHeight()
// #endif
this.navBarHeight = this.statusBarHeight + uni.upx2px(90)
},
computed: {
fixedStyle() {
return `height:${this.navBarHeight}px`
},
getTitle(){
let noreadnum = this.noreadnum > 0 ? '('+this.noreadnum+')' : ''
return this.title + noreadnum
},
getClass(){
let fixed = this.fixed?'fixed-top':''
return `${fixed} ${this.bgColor}`
}
},
methods: {
openExtend() {
this.$refs.extend.show(uni.upx2px(415),uni.upx2px(150))
},
// 返回
back(){
if(this.backEvent){
return uni.navigateBack({
delta: 1
});
}
this.$emit('back')
},
search(){
console.log("search")
},
clickEvent(e){
this.$refs.extend.hide()
switch (e.event){
case 'navigateTo':
uni.navigateTo({
url: e.path,
});
break;
default:
uni.showToast({
title: '自己发挥',
icon: 'none'
});
break;
}
}
},
}
</script>
<style>
</style>

View File

@@ -0,0 +1,157 @@
<template>
<div style="z-index:9999;overflow:hidden;" v-if="status">
<!-- 蒙版 -->
<view v-if="mask" class="position-fixed top-0 left-0 right-0 bottom-0 z-index" :style="getMaskColor" @click="hide"></view>
<!-- 弹出框内容 -->
<div ref="popup" class="position-fixed animated z-index" :class="getBodyClass" :style="getBodyStyle">
<slot></slot>
</div>
</div>
</template>
<script>
// #ifdef APP-PLUS-NVUE
const animation = weex.requireModule('animation')
// #endif
export default {
props: {
// 是否开启蒙版颜色
maskColor: {
type: Boolean,
default: false
},
// 是否开启蒙版
mask:{
type:Boolean,
default:true
},
// 是否居中
center:{
type:Boolean,
default:false
},
// 是否处于底部
bottom:{
type:Boolean,
default:false
},
// 弹出层内容宽度
bodyWidth:{
type:Number,
default:0
},
// 弹出层内容高度
bodyHeight:{
type:Number,
default:0
},
bodyBgColor:{
type:String,
default:"bg-white"
},
transformOrigin:{
type:String,
default:"left top"
},
// tabbar高度
tabbarHeight:{
type:Number,
default:0
}
},
data() {
return {
status: false,
x:-1,
y:1,
maxX:0,
maxY:0
}
},
mounted() {
try {
const res = uni.getSystemInfoSync();
this.maxX = res.windowWidth - uni.upx2px(this.bodyWidth)
this.maxY = res.windowHeight - uni.upx2px(this.bodyHeight) - uni.upx2px(this.tabbarHeight)
} catch (e) {
// error
}
},
computed: {
getMaskColor() {
let i = this.maskColor ? 0.5 : 0
return `background-color: rgba(0,0,0,${i});`
},
getBodyClass(){
if(this.center){
return 'left-0 right-0 bottom-0 top-0 flex align-center justify-center'
}
let bottom = this.bottom ? 'left-0 right-0 bottom-0' : 'rounded border'
return `${this.bodyBgColor} ${bottom}`
},
getBodyStyle(){
let left = this.x > -1 ? `left:${this.x}px;` : ''
let top = this.y > -1 ? `top:${this.y}px;` : ''
return left + top
}
},
methods:{
show(x = -1 ,y = -1){
if (this.status) {
return;
}
this.x = (x > this.maxX) ? this.maxX : x
this.y = (y > this.maxY) ? this.maxY : y
this.status = true
// #ifdef APP-PLUS-NVUE
this.$nextTick(()=>{
animation.transition(this.$refs.popup, {
styles: {
transform: 'scale(1,1)',
transformOrigin:this.transformOrigin,
opacity:1
},
duration: 100, //ms
timingFunction: 'ease',
}, function () {
// console.log('动画执行结束');
})
})
// #endif
},
hide(){
this.$emit('hide')
// #ifdef APP-PLUS-NVUE
animation.transition(this.$refs.popup, {
styles: {
transform: 'scale(0,0)',
transformOrigin:this.transformOrigin,
opacity:0
},
duration: 100, //ms
timingFunction: 'ease',
}, ()=> {
this.status = false
// console.log('动画执行结束');
})
// #endif
this.status = false
}
}
}
</script>
<style scoped>
.animated{
/* #ifdef APP-PLUS-NVUE */
/* transform: scale(0,0);
opacity: 0; */
/* #endif */
}
.z-index{
/* #ifndef APP-NVUE */
z-index: 9999;
/* #endif */
}
</style>

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/main.js"></script>
</body>
</html>

View File

@@ -0,0 +1,21 @@
import Vue from 'vue'
import App from './App'
import store from './store';
Vue.prototype.$store = store
Vue.config.productionTip = false
const sdk = require("@/common/imSdk/lim-sdk.js");
const lim = require("@/common/imSdk/sdk-bridge.js");
uni.lim = lim;
App.mpType = 'app'
Vue.prototype.imsdk = lim
const app = new Vue({
store,
...App
})
app.$mount()

View File

@@ -0,0 +1,100 @@
{
"name" : "l-im-app",
"appid" : "__UNI__621989A",
"description" : "l-im-app",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
/* 5+App */
"app-plus" : {
"nvueCompiler" : "uni-app",
"usingComponents" : true,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* */
"modules" : {
"VideoPlayer" : {}
},
/* */
"distribute" : {
/* android */
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
/* ios */
"ios" : {
"UIBackgroundModes" : "audio",
"idfa" : false
},
/* SDK */
"sdkConfigs" : {}
},
"compilerVersion" : 3
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "2"
,
"h5": {
"devServer": {
"https": false,
"proxy": {
"/v1": {
"target": "http://127.0.0.1:8000/",
"changeOrigin": true,
"ws": true,
"pathRewrite": {
"^/v1": ""
}
}
}
}
}
}

View File

@@ -0,0 +1,3 @@
{
"lockfileVersion": 1
}

View File

@@ -0,0 +1,85 @@
{
"pages": [ //pages数组中第一项表示应用启动页参考https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/common/login/login",
"style": {}
}, {
"path": "pages/tabbar/index/index",
"style": {
"navigationBarTitleText": "uni-app"
}
}, {
"path": "pages/tabbar/mail/mail",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}, {
"path": "pages/chat/chat/chat",
"style": {}
}, {
"path": "pages/tabbar/find/find",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}, {
"path": "pages/tabbar/my/my",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}, {
"path": "pages/my/userinfo/userinfo",
"style": {}
}, {
"path": "pages/my/setting/setting",
"style": {}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "l-im-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8",
"app-plus": {
"titleNView": false,
"scrollIndicator": "none"
}
},
"tabBar": {
"color": "#000000",
"selectedColor": "#06a1c0",
"borderStyle": "black",
"backgroundColor": "#F7F7F7",
"list": [{
"iconPath": "static/tabbar/index.png",
"selectedIconPath": "static/tabbar/index-select.png",
"pagePath": "pages/tabbar/index/index",
"text": "首页"
},
{
"iconPath": "static/tabbar/mail.png",
"selectedIconPath": "static/tabbar/mail-select.png",
"pagePath": "pages/tabbar/mail/mail",
"text": "通讯录"
},
{
"iconPath": "static/tabbar/find.png",
"selectedIconPath": "static/tabbar/find-select.png",
"pagePath": "pages/tabbar/find/find",
"text": "发现"
},
{
"iconPath": "static/tabbar/my.png",
"selectedIconPath": "static/tabbar/my-select.png",
"pagePath": "pages/tabbar/my/my",
"text": "我的"
}
]
},
"uniIdRouter": {}
}

View File

@@ -0,0 +1,433 @@
<template>
<view>
<!-- 导航栏 -->
<nav-bar :title="detail.name" :noreadnum="999" showBack>
<icon-button slot="right" :icon="'\ue6fd'" ></icon-button>
</nav-bar>
<!-- 聊天内容区域 -->
<scroll-view scroll-y class="bg-light position-fixed left-0 right-0 px-3"
style="bottom: 105rpx;box-sizing: border-box;" :style="chatBodyBottom" :show-scrollbar="false"
:scroll-into-view="scrollIntoView" :scroll-with-animation="true" @click="clickPage">
<!-- 聊天信息列表组件 -->
<view v-for="(item,index) in list" :key="index" :id="'chatItem_'+index">
<chat-item :item="item" :index="index" ref="chatItem"
:pretime=" index > 0 ? list[index-1].createTime : 0" @long="long"
:shownickname="currentChatItem.shownickname"></chat-item>
</view>
</scroll-view>
<!-- #ifdef APP-PLUS-NVUE -->
<div v-if="mode === 'action' || mode === 'emoticon'" class="position-fixed top-0 right-0 left-0"
:style="'bottom:'+maskBottom+'px;'" @click="clickPage"></div>
<!-- #endif -->
<!-- 底部输入框 -->
<view class="position-fixed left-0 right-0 border-top flex align-center"
style="background-color: #F7F7F6;height: 105rpx;" :style="'bottom:'+KeyboardHeight+'px;'">
<icon-button :icon="'\ue606'" @click="changeVoiceOrText"></icon-button>
<view class="flex-1">
<textarea fixed class="bg-white rounded p-2 font-md" style="height: 50rpx;max-width: 450rpx;"
:adjust-position="false" v-model="text" @focus="mode = 'text'" />
</view>
<!-- 表情 -->
<!-- <icon-button :icon="'\ue605'"></icon-button> -->
<template v-if="text.length === 0">
<!-- 扩展菜单 -->
<icon-button :icon="'\ue603'" @click="openActionOrEmoticon('action')"></icon-button>
</template>
<view v-else class="flex-shrink">
<!-- 发送按钮 -->
<main-button name="发送" @click="send('text')"></main-button>
</view>
</view>
<!-- 扩展菜单 -->
<popup ref="action" bottom transformOrigin="center bottom" @hide="KeyboardHeight = 0" :mask="false">
<view style="height: 580rpx;" class="border-top border-light-secondary bg-light">
<swiper :indicator-dots="actionLists.length > 1" style="height: 510rpx;">
<swiper-item class="row pl-5" v-for="(item,index) in actionLists" :key="index">
<view class="col-3 flex flex-column align-center justify-center" style="height: 255rpx;"
v-for="(item2,index2) in item" :key="index2" @click="actionEvent(item2)">
<image :src="item2.icon" mode="widthFix" style="width: 100rpx;height: 100rpx;"></image>
<text class="font-sm text-muted mt-2">{{item2.name}}</text>
</view>
</swiper-item>
</swiper>
</view>
</popup>
<!-- 弹出层 -->
<popup ref="extend" :bodyWidth="240" :bodyHeight="450" :tabbarHeight="105">
<view class="flex flex-column" style="width: 240rpx;" :style="getMenusStyle">
<view class="flex-1 flex align-center" hover-class="bg-light" v-for="(item,index) in menusList"
:key="index" @click="clickEvent(item.event)">
<text class="font-md pl-3">{{item.name}}</text>
</view>
</view>
</popup>
</view>
</template>
<script>
// #ifdef APP-PLUS-NVUE
const dom = weex.requireModule('dom')
// #endif
const sdk = uni.lim.im;
import navBar from "@/components/ui/nav-bar.vue"
import iconButton from "@/components/ui/icon-button.vue"
import chatItem from '@/components/ui/chat-item.vue';
import popup from "@/components/ui/popup.vue"
import mainButton from '@/components/ui/main-button.vue';
import {
mapState,
mapMutations
} from 'vuex'
import auth from '@/common/mixin/auth.js';
import $H from '@/common/lib/request.js';
import $C from '@/common/lib/config.js';
export default {
mixins: [auth],
components: {
navBar,
iconButton,
chatItem,
popup,
mainButton
},
data() {
return {
scrollIntoView: "",
toId: "",
// 模式 text输入文字emoticon表情action操作audio音频
mode: "text",
// 扩展菜单列表
actionList: [
[{
name: "相册",
icon: "/static/images/extends/pic.png",
event: "uploadImage"
}, {
name: "拍摄",
icon: "/static/images/extends/video.png",
event: "uploadVideo"
}, {
name: "收藏",
icon: "/static/images/extends/shoucan.png",
event: "openFava"
}, {
name: "名片",
icon: "/static/images/extends/man.png",
event: "sendCard"
}, {
name: "语音通话",
icon: "/static/images/extends/phone.png",
event: ""
}, {
name: "位置",
icon: "/static/images/extends/path.png",
event: ""
}]
],
emoticonList: [],
// 键盘高度
KeyboardHeight: 0,
menusList: [],
navBarHeight: 0,
list: [{
userId: 'lld',
avatar: "/static/images/userpic.png",
data: "你好啊你好啊你好啊你好啊你好啊你好啊你好啊",
nickname: "lld",
type: "text",
createTime: 1657465771,
isRemove: false
}, {
userId: 'lld2',
avatar: "/static/images/userpic.png",
data: "1234567890",
nickname: "lld2",
type: "text",
createTime: 1658329771,
isRemove: false
}, {
userId: 'lld',
avatar: "/static/images/userpic.png",
data: "你好啊你好啊你好啊你好啊你好啊你好啊你好啊",
nickname: "lld",
type: "text",
createTime: 1657465771,
isRemove: false
}, {
userId: 'lld2',
avatar: "/static/images/userpic.png",
data: "1234567890",
nickname: "lld2",
type: "text",
createTime: 1658329771,
isRemove: false
}],
// 当前操作的气泡索引
propIndex: -1,
// 输入文字
text: "",
detail: {
id: 0,
name: "",
avatar: "",
chat_type: "user"
}
}
},
mounted() {
var statusBarHeight = 0
// #ifdef APP-PLUS-NVUE
statusBarHeight = plus.navigator.getStatusbarHeight()
// #endif
this.navBarHeight = statusBarHeight + uni.upx2px(90)
// 监听键盘高度变化
uni.onKeyboardHeightChange(res => {
if (this.mode !== 'action' && this.mode !== 'emoticon') {
this.KeyboardHeight = res.height
}
if (this.KeyboardHeight > 0) {
this.pageToBottom()
}
})
this.pageToBottom()
},
computed: {
...mapState({
}),
// 当前会话配置信息
currentChatItem() {
return {}
},
// 获取蒙版的位置
maskBottom() {
return this.KeyboardHeight + uni.upx2px(105)
},
// 动态获取菜单高度
getMenusHeight() {
let H = 100
return this.menusList.length * H
},
// 获取菜单的样式
getMenusStyle() {
return `height: ${this.getMenusHeight}rpx;`
},
// 判断是否操作本人信息
isdoSelf() {
// 获取本人id假设拿到了
let id = 1
let user_id = this.propIndex > -1 ? this.list[this.propIndex].user_id : 0
return user_id === id
},
// 聊天区域bottom
chatBodyBottom() {
return `bottom:${uni.upx2px(105) + this.KeyboardHeight}px;top:${this.navBarHeight}px;`
},
// 获取操作或者表情列表
actionLists() {
return (this.mode === 'emoticon' || this.mode === 'action') ? this[this.mode + 'List'] : []
},
// 所有信息的图片地址
imageList() {
let arr = []
this.list.forEach((item) => {
if (item.type === 'emoticon' || item.type === 'image') {
arr.push(item.data)
}
})
return arr
}
},
watch: {
mode(newValue, oldValue) {
if (newValue !== 'action' && newValue !== 'emoticon') {
this.$refs.action.hide()
}
if (newValue !== 'text') {
uni.hideKeyboard()
}
}
},
onLoad(e) {
var toIdObj = JSON.parse(decodeURIComponent(e.params))
this.toId = toIdObj.id;
// // 监听接收聊天信息
uni.$on('P2PMessage', this.onMessage)
},
destroyed() {
// // 销毁监听接收聊天消息
uni.$off('P2PMessage',this.onMessage)
},
methods: {
onMessage(message) {
if(message.fromId != this.toId){
return;
}
console.log('[聊天页] 监听接收聊天信息', message);
var messageBody = JSON.parse(message.messageBody);
if(messageBody.type == 1){
let msg = {
userId:message.fromId,
avatar: "/static/images/userpic.png",
data: messageBody.content == '' ? '空消息' : messageBody.content,
nickname:message.fromId,
type: "text",
createTime: message.messageTime / 1000,
isRemove: false
}
this.list.push(msg)
}
this.pageToBottom()
},
__init() {},
// 打开扩展菜单或者表情包
openActionOrEmoticon(mode = 'action') {
this.mode = mode
this.$refs.action.show()
uni.hideKeyboard()
this.KeyboardHeight = uni.upx2px(580)
},
// 发送
send(type, data = '', options = {}) {
// 组织数据格式
if (type == 'text') {
sdk.sendP2PMessage(sdk.createP2PTextMessage(this.toId, this.text))
let uid = sdk.getUserId();
let msg = {
userId:uid,
avatar: "/static/images/userpic.png",
data: this.text,
nickname:uid,
type: "text",
createTime: Date.parse(new Date()) / 1000,
isRemove: false
}
this.list.push(msg)
}
// 发送文字成功,清空输入框
if (type === 'text') {
this.text = ''
}
// 置于底部
this.pageToBottom()
},
// 回到底部
pageToBottom() {
// #ifdef APP-PLUS-NVUE
let chatItem = this.$refs.chatItem
let lastIndex = chatItem.length > 0 ? chatItem.length - 1 : 0
if (chatItem[lastIndex]) {
dom.scrollToElement(chatItem[lastIndex], {})
}
// #endif
// #ifndef APP-NVUE
setTimeout(() => {
let lastIndex = this.list.length - 1
this.scrollIntoView = 'chatItem_' + lastIndex
}, 300)
// #endif
},
// 长按消息气泡
long({
x,
y,
index
}) {
// 初始化 索引
this.propIndex = index
// 组装菜单
let menus = [{
name: "发送给朋友",
event: 'sendToChatItem'
}, {
name: "收藏",
event: 'fava'
}, {
name: "删除",
event: 'delete'
}]
let item = this.list[this.propIndex]
menus.push({
name: "撤回",
event: 'removeChatItem'
})
// #ifndef H5
if (item.type === 'text') {
menus.unshift({
name: "复制",
event: 'copy',
})
}
// #endif
this.menusList = menus
// 显示扩展菜单
this.$refs.extend.show(x, y)
},
// 操作菜单方法分发
clickEvent(event) {
// 关闭菜单
this.$refs.extend.hide()
},
// 扩展菜单
actionEvent(e) {
switch (e.event) {
case 'uploadImage': // 选择相册
uni.chooseImage({
count: 9,
success: (res) => {
// 发送到服务器
// 渲染到页面
res.tempFilePaths.forEach((item) => {
this.send('image', item)
})
}
})
break;
case 'uploadVideo': // 发送短视频
uni.chooseVideo({
maxDuration: 10,
success: (res) => {
this.send('video', res.tempFilePath)
// 渲染页面
// 发送到服务端获取视频封面返回url
// 修改本地的发送状态
}
})
break;
}
},
// 点击页面
clickPage() {
this.mode = ''
},
// 切换音频录制和文本输入
changeVoiceOrText() {
this.mode = this.mode !== 'audio' ? 'audio' : 'text'
}
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,144 @@
<template>
<view>
<view>
<view class="flex align-center justify-center"
style="height: 350rpx;">
<text style="font-size: 50rpx;">LOGO</text>
</view>
<view class="px-3">
<input type="text" class="bg-light px-3 mb-3 font" :placeholder=getUserNameText style="height: 100rpx;" v-model="form.userName"/>
<input type="text" class="bg-light px-3 mb-3 font" placeholder="请输入密码" style="height: 100rpx;" v-model="form.password"/>
<input v-if="type === 'reg'" type="text" class="bg-light px-3 mb-3 font" placeholder="请输入确认密码" style="height: 100rpx;" v-model="form.repassword"/>
</view>
<view class="p-3 flex align-center justify-center">
<view class="main-bg-color rounded p-3 flex align-center justify-center flex-1"
hover-class="main-bg-hover-color" @click="submit">
<text class="text-white font-md">{{type === 'login' ? '登 录' : '注 册'}}</text>
</view>
</view>
<view class="flex align-center justify-center">
<text class="text-light-muted font p-2" @click="changeType">{{type === 'login' ? '注册账号' : '马上登录'}}</text>
<text class="text-light-muted font">|</text>
<text class="text-light-muted font p-2">忘记密码</text>
</view>
</view>
</view>
</template>
<script>
import $H from '@/common/lib/request.js';
import Vue from 'vue'
const ListenerMap = {
onSocketConnectEvent: (option, status, data) => {
console.log("已建立连接:" + JSON.stringify(status));
},
onSocketErrorEvent: (error) => {
console.log("连接出现错误:" + userId);
},
onSocketReConnectEvent: () => {
console.log("正在重连:" );
},
onSocketCloseEvent: () => {
console.log("连接关闭:" );
},onSocketReConnectSuccessEvent: () => {
console.log("重连成功" );
},
onTestMessage: (e) => {
console.log("onTestMessage " + e );
},
onP2PMessage: (e) => {
console.log("onP2PMessage " + e );
e = JSON.parse(e)
uni.$emit('P2PMessage', e.data);
},
onLogin: (uid) => {
console.log("用户"+uid+"登陆sdk成功" );
}
};
export default {
data() {
return {
type:"login",
form: {
userName:"lld",
password:"lld",
repassword:"",
loginType:1
},
show:true
}
},
created() {
},
methods: {
changeType(){
// this.type = this.type === 'login' ? 'reg' : 'login'
// this.form = {
// username:"",
// password:"",
// repassword:""
// }
},
submit() {
if(this.type === 'login'){
$H.post('/login',this.form,{
token:false
}).then(res=>{
console.log(res)
if(res.code !== 200){
uni.showToast({
title: res.msg,
icon: 'none'
});
}else{
//app服务登录成功去登录im
const lim = this.imsdk
const sdk = lim.im;
var userId = this.form.userName;
var listeners = {};
for (const v in ListenerMap) {
listeners[v] = ListenerMap[v];
}
sdk.init("http://127.0.0.1:8000/v1",res.data.appId,res.data.userId,res.data.imUserSign,listeners,function (sdk) {
if(sdk){
console.log('sdk 成功连接的回调, 可以使用 sdk 请求数据了.');
return uni.switchTab({
url:"/pages/tabbar/index/index"
})
}
else {
console.log('sdk 初始化失败.');
}
});
}
})
}
}
},
computed:{
getUserNameText(){
if(this.type === 'login'){
return "请输入用户名";
}
else if(this.type === 'reg'){
return "请输入手机号";
}
}
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,40 @@
<template>
<view class="page">
<!-- 导航栏 -->
<nav-bar title="我的设置" showBack :showRight="false"></nav-bar>
<!-- 退出登录 -->
<divider></divider>
<view class="py-3 flex align-center justify-center bg-white" hover-class="bg-light" @click="logout">
<text class="font-md text-primary">退出登录</text>
</view>
</view>
</template>
<script>
import navBar from "@/components/ui/nav-bar.vue"
import divider from "@/components/ui/divider.vue"
import $H from '@/common/lib/request.js';
export default {
components: {
navBar,
divider
},
data() {
return {
}
},
methods: {
logout() {
// 跳转到登录页
uni.reLaunch({
url: "/pages/common/login/login"
})
}
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,63 @@
<template>
<view class="page">
<!-- 导航栏 -->
<nav-bar title="个人资料" showBack :showRight="false"></nav-bar>
<list-item title="头像" showRight :showLeftIcon="false">
<avater slot="right" :src="user.avatar"></avater>
</list-item>
<list-item title="昵称" showRight :showLeftIcon="false">
<text slot="right" class="font text-muted">{{user.nickname}}</text>
</list-item>
<list-item title="账号" showRight :showLeftIcon="false">
<text slot="right" class="font text-muted">{{user.username}}</text>
</list-item>
<confirm ref="confirm" :title="confirmTitle">
<input type="text" v-model="confirmText" :placeholder="placeholder" class="border-bottom font-md"/>
</confirm>
</view>
</template>
<script>
import navBar from "@/components/ui/nav-bar.vue"
import avater from '@/components/ui/avater.vue';
import listItem from "@/components/ui/list-item.vue"
import confirm from '@/components/ui/confirm.vue';
import $H from '@/common/lib/request.js';
export default {
components: {
navBar,
avater,
listItem,
confirm
},
data() {
return {
confirmText:"",
confirmType:"",
user:{
avatar:"",
nickname:"lld",
username:"lld"
}
}
},
computed: {
confirmTitle() {
return this.confirmType == 'username' ? '修改账号' :'修改昵称'
},
placeholder(){
return this.confirmType == 'username' ? '输入账号' :'输入昵称'
}
},
methods: {
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,71 @@
<template>
<view class="page">
<!-- 导航栏 -->
<nav-bar title="发现"></nav-bar>
<!-- 通讯录列表 -->
<list-item title="朋友圈" showRight>
<text slot="icon" class="iconfont font-lg py-1">&#xe667;</text>
<view slot="right" class="p-1">
<view class="position-relative" v-if="!notice.num">
<text class="rounded-circle bg-danger position-absolute" style="width: 20rpx;height: 20rpx;top: 0;right: 0;"></text>
</view>
<badge v-if="notice.num" :value="notice.num"></badge>
</view>
</list-item>
<divider></divider>
<list-item title="扫一扫" showRight>
<text slot="icon" class="iconfont font-lg py-1">&#xe86d;</text>
</list-item>
<list-item title="摇一摇" showRight>
<text slot="icon" class="iconfont font-lg py-1">&#xe63d;</text>
</list-item>
<divider></divider>
<list-item title="看一看" showRight>
<text slot="icon" class="iconfont font-lg py-1">&#xe610;</text>
</list-item>
<list-item title="搜一搜" showRight>
<text slot="icon" class="iconfont font-lg py-1">&#xe611;</text>
</list-item>
<divider></divider>
<list-item title="购物" showRight>
<text slot="icon" class="iconfont font-lg py-1">&#xe658;</text>
</list-item>
</view>
</template>
<script>
import navBar from "@/components/ui/nav-bar.vue"
import listItem from "@/components/ui/list-item.vue"
import divider from "@/components/ui/divider.vue"
import badge from "@/components/ui/badge.vue"
import auth from '@/common/mixin/auth.js'
export default {
mixins:[auth],
components: {
navBar,
listItem,
divider,
badge
},
data() {
return {
notice:{
num: 1,
userId:"lld",
avatar:"/static/images/userpic.png"
}
}
},
methods: {
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,151 @@
<template>
<view>
<!-- 导航栏 -->
<nav-bar title="微信(10)">
</nav-bar>
<!-- 置顶列表 -->
<block v-for="(item,index) in list" :key="index">
<media-list v-if="item.istop" :item="item" :index="index" @long="long"></media-list>
</block>
<!-- 非置顶列表 -->
<block v-for="(item,index) in list" :key="index">
<media-list v-if="!item.istop" :item="item" :index="index" @long="long"></media-list>
</block>
<!-- 弹出层 -->
<popup ref="extend" :bodyWidth="240" :bodyHeight="getMenusHeight">
<view class="flex flex-column" style="width: 240rpx;" :style="getMenusStyle">
<view class="flex-1 flex align-center" hover-class="bg-light" v-for="(item,index) in menus" :key="index"
@click="clickEvent(item.event)">
<text class="font-md pl-3">{{item.name}}</text>
</view>
</view>
</popup>
</view>
</template>
<script>
import navBar from "@/components/ui/nav-bar.vue"
import mediaList from "@/components/ui/media-list.vue"
import popup from "@/components/ui/popup.vue"
import auth from '@/common/mixin/auth.js'
export default {
mixins:[auth],
components: {
navBar,
mediaList,
popup
},
data() {
return {
propIndex: -1,
list: [{
avatar: "/static/images/userpic.png",
nickname: "lld",
id: "lld",
updateTime: 1657554934224,
data: "我是lld",
istop: true,
noreadnum: 1
},
{
avatar: "/static/images/userpic.png",
nickname: "lld2",
id: "lld2",
updateTime: 1654962934000,
data: "我是lld2",
istop: false,
noreadnum: 0
},
{
avatar: "../../../static/images/userpic.png",
nickname: "lld3",
id: "lld3",
updateTime: 1626018934000,
data: "我是lld3",
istop: true,
noreadnum: 1
}
],
menus: [{
name: "设为置顶",
event: "setTop"
},
{
name: "删除该聊天",
event: "delChat"
}
]
}
},
onLoad() {
},
onShow() {
},
computed:{
// 动态获取菜单高度
getMenusHeight(){
let H = 100
return this.menus.length * H
},
// 获取菜单的样式
getMenusStyle(){
return `height: ${this.getMenusHeight}rpx;`
}
},
methods: {
openExtend() {
this.$refs.extend.show();
},
long({
x,
y,
index
}) {
// 初始化 索引
this.propIndex = index
// 拿到当前对象
let item = this.list[index]
// 判断之前是否处于置顶状态
this.menus[0].name = item.istop ? '取消置顶' : '设为置顶'
this.$refs.extend.show(x, y)
},
// 分发菜单事件
clickEvent(event){
switch (event){
case "setTop": // 置顶/取消置顶会话
this.setTop()
break;
case "delChat": // 删除当前会话
this.delChat()
break;
}
this.$refs.extend.hide()
},
// 置顶/取消置顶会话
setTop(){
let item = this.list[this.propIndex]
item.istop = !item.istop
},
// 删除当前会话
delChat(){
this.list.splice(this.propIndex,1);
}
},
}
</script>
<style>
</style>

View File

@@ -0,0 +1,166 @@
<template>
<view>
<!-- 导航栏 -->
<nav-bar title="通讯录" :showBack="false" :showRight="false">
</nav-bar>
<scroll-view scroll-y="true" :style="'height:'+scrollHeight+'px;'" :scroll-into-view="scrollInto">
<!-- 通讯录列表 :showRight="item.id === 'friend' && applyCount > 0" -->
<list-item v-for="(item,index) in topList" :title="item.title" :key="item.id" :cover="item.cover">
</list-item>
</scroll-view>
<!-- 侧边导航条 -->
<view class="position-fixed right-0 bottom-0 bg-light flex flex-column" :style="'top:' +top+ 'px'"
style="width: 50rpx;">
</view>
<!-- 侧边导航条 -->
<!-- <view class="position-fixed right-0 bottom-0 bg-light flex flex-column" :style="'top:'+top+'px;'"
style="width: 50rpx;" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend">
<view class="flex-1 flex align-center justify-center" v-for="(item,index) in list.keys()" :key="index">
<text class="font-sm text-muted">{{item}}</text>
</view>
</view> -->
<!-- <view class="position-fixed rounded-circle bg-light border flex align-center justify-center" v-if="current"
style="width: 150rpx;height: 150rpx;left: 300rpx;"
:style="'top:'+modalTop+'px;'">
<text class="font-lg">{{current}}</text>
</view> -->
</view>
</template>
<script>
import navBar from "@/components/ui/nav-bar.vue"
import listItem from "@/components/ui/list-item.vue"
import auth from '@/common/mixin/auth.js'
import badge from "@/components/ui/badge.vue"
export default {
mixins:[auth],
components: {
navBar,
listItem,
badge
},
data() {
return {
top: 0,
friendRequestNum: 0,
topList: [{
id: "friend",
title: "新的朋友",
cover: "/static/images/mail/friend.png",
path: "mail/apply-list/apply-list"
},
{
id: "group",
title: "群聊",
cover: "/static/images/mail/group.png",
path: "mail/group-list/group-list"
},
{
id: "tag",
title: "标签",
cover: "/static/images/mail/tag.png",
path: "mail/tag-list/tag-list"
}
],
// list: new Map(),
list:
[{
"letter": "A",
"data": [
"AAAAA微商",
"a ",
"澳门风云"
]
},
{
"letter": "B",
"data": [
"宝贝",
]
},
{
"letter": "C",
"data": [
"草原",
]
},
{
"letter": "D",
"data": []
},
{
"letter": "E",
"data": []
},
{
"letter": "F",
"data": []
},
{
"letter": "G",
"data": []
},
{
"letter": "H",
"data": [
"黄飞鸿",
"黄继光"
]
},
{
"letter": "I",
"data": [
"ICON",
"icc",
"icc",
"icc",
"icc"
]
}
]
,
top: 0,
scrollHeight: 0,
scrollInto: '',
current: ''
}
},
methods: {
},
onLoad() {
let res = uni.getSystemInfoSync()
this.top = res.statusBarHeight + uni.upx2px(90)
this.scrollHeight = res.windowHeight - this.top
},
onShow() {
},
computed: {
// 每个索引的高度
itemHeight() {
let count = this.list.size
// debugger;
if (count < 1) {
return 0
}
return this.scrollHeight / count
},
modalTop(){
return (this.scrollHeight - uni.upx2px(150)) / 2
}
}
}
</script>
<style>
</style>

View File

@@ -0,0 +1,77 @@
<template>
<view class="page">
<!-- 导航栏 -->
<nav-bar bgColor="bg-white">
<icon-button slot="right" :icon="'\ue6ed'"></icon-button>
</nav-bar>
<list-item :cover="user.photo ? user.photo : '/static/images/userpic.jpg'"
coverSize="120" :title="user.nickName" showRight @click="open('my/userinfo/userinfo')">
<view class="flex flex-column">
<text class="text-dark font-lg font-weight-bold">{{user.nickName}}</text>
<text class="text-light-muted font mt-2">仿微信号{{user.nickName}}</text>
</view>
<view slot="right">
<text class="iconfont font-md text-light-muted">&#xe614;</text>
</view>
</list-item>
<divider></divider>
<list-item title="支付" showRight>
<text slot="icon" class="iconfont font-lg py-1">&#xe66c;</text>
</list-item>
<divider></divider>
<list-item title="相册" showRight
@click="open()">
<text slot="icon" class="iconfont font-lg py-1">&#xe608;</text>
</list-item>
<divider></divider>
<list-item title="设置" showRight @click="open('my/setting/setting')">
<text slot="icon" class="iconfont font-lg py-1">&#xe612;</text>
</list-item>
</view>
</template>
<script>
import navBar from "@/components/ui/nav-bar.vue"
import iconButton from "@/components/ui/icon-button.vue"
import listItem from "@/components/ui/list-item.vue"
import divider from "@/components/ui/divider.vue"
import auth from '@/common/mixin/auth.js'
import { mapState } from 'vuex'
export default {
components:{
navBar,
listItem,
iconButton,
divider
},
data() {
return {
user:{
nickName:"lld"
}
}
},
methods: {
open(path){
uni.navigateTo({
url: '/pages/'+path
});
},
},
computed:{
}
}
</script>
<style>
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 964 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,12 @@
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
import common from '@/store/modules/common.js';
export default new Vuex.Store({
modules:{
common
}
})

View File

@@ -0,0 +1,10 @@
export default {
state:{
keyboardHeight:0
},
mutations:{
changeKeyboardHeight(state,h){
state.keyboardHeight = h
}
}
}

View File

@@ -0,0 +1,76 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场https://ext.dcloud.net.cn上很多三方插件均使用了这些样式变量
* 如果你是插件开发者建议你使用scss预处理并在插件代码中直接使用这些变量无需 import 这个文件方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者插件使用者你可以通过修改这些变量来定制自己的插件主题实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
*/
/* 颜色变量 */
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* 文字基本颜色 */
$uni-text-color:#333;//基本色
$uni-text-color-inverse:#fff;//反色
$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable:#c0c0c0;
/* 背景颜色 */
$uni-bg-color:#ffffff;
$uni-bg-color-grey:#f8f8f8;
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
/* 边框颜色 */
$uni-border-color:#c8c7cc;
/* 尺寸变量 */
/* 文字尺寸 */
$uni-font-size-sm:12px;
$uni-font-size-base:14px;
$uni-font-size-lg:16;
/* 图片尺寸 */
$uni-img-size-sm:20px;
$uni-img-size-base:26px;
$uni-img-size-lg:40px;
/* Border Radius */
$uni-border-radius-sm: 2px;
$uni-border-radius-base: 3px;
$uni-border-radius-lg: 6px;
$uni-border-radius-circle: 50%;
/* 水平间距 */
$uni-spacing-row-sm: 5px;
$uni-spacing-row-base: 10px;
$uni-spacing-row-lg: 15px;
/* 垂直间距 */
$uni-spacing-col-sm: 4px;
$uni-spacing-col-base: 8px;
$uni-spacing-col-lg: 12px;
/* 透明度 */
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
/* 文章场景相关 */
$uni-color-title: #2C405A; // 文章标题颜色
$uni-font-size-title:20px;
$uni-color-subtitle: #555555; // 二级标题颜色
$uni-font-size-subtitle:26px;
$uni-color-paragraph: #3F536E; // 文章段落颜色
$uni-font-size-paragraph:15px;