调整iconfont图标缺失

This commit is contained in:
唐明明
2022-02-14 17:16:27 +08:00
71 changed files with 6023 additions and 3894 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -14,6 +14,10 @@
{
"launchtype" : "local"
},
"mp-weixin" :
{
"launchtype" : "local"
},
"type" : "uniCloud"
}
]

View File

@@ -1,5 +1,7 @@
<script>
import { getVersions } from './apis/interfaces/versions'
import {
getVersions
} from './apis/interfaces/versions'
import im from '@/utils/im/index.js'
export default {

View File

@@ -9,9 +9,10 @@ import { request } from '../index'
/**
* @description:饮水记录首页
*/
const waters = () => {
const waters = (data) => {
return request({
url: 'health/waters',
data:data
})
}
/**
@@ -29,10 +30,11 @@ const setWaters = (data) => {
* @description:喝水
* @Date: 2022-01-12 125600
*/
const drinkWater = () => {
const drinkWater = (data) => {
return request({
url: 'health/waters/drink',
method: 'POST',
data:data
})
}
/**
@@ -46,10 +48,24 @@ const delDrinkWater = (id) => {
})
}
/**
* @description:饮食运动日历
* @params {日期}
* @method {get}
* @Date: 2022-02-08 11点18分
*/
const dateList = (data) => {
return request({
url: 'health/calendar/water',
data:data
})
}
export {
waters,
setWaters,
drinkWater,
delDrinkWater
delDrinkWater,
dateList
}

View File

@@ -78,11 +78,24 @@ const delHealthFoods = (intake_id) => {
})
}
/**
* @description:饮食运动日历
* @params {日期}
* @method {get}
* @Date: 2022-02-07 15点18分
*/
const dateList = (data) => {
return request({
url: 'health/calendar/intake',
data:data
})
}
export {
positions,
plans,
healthFoods,
addHealthFoods,
editHealthFoods,
delHealthFoods
delHealthFoods,
dateList
}

View File

@@ -11,6 +11,13 @@ import {
// 获取好友列表
const getFriends = () => {
return request({
url: 'im/friends',
}, true)
}
// 获取好友列表
const getFriendsLetter = () => {
return request({
url: 'im/friends/letter',
}, true)
@@ -85,55 +92,121 @@ const pedingFriend = (recipient) => {
})
}
/**
* 好友申请数量
*/
const getPendingCount = () => {
// 以下是群组相关业务的接口
const getMyGroups = () => {
return request({
url: 'im/friends/pending/count'
url: 'im/groups'
})
}
/**
* 上传聊天附件
* 图片
* 语音
* 视频
* 获取群信息,包含基础信息和 14 个用户
*/
// 基础配置
const config = {
apiUrl: 'http://api.zh.shangkelian.cn/api/', // 正式环境
timeout: 60000
const getGroupInfo = (groupId) => {
return request({
url: 'im/groups/' + groupId
})
}
const uploadMessageFile = (file, type) => {
config.header = {
'Accept': 'application/json',
'Authorization': store.getters.getToken || ''
}
return new Promise((resolve, reject) => {
uni.uploadFile({
url: config.apiUrl + 'im/upload',
filePath: file,
name: 'upload',
formData: {
type
},
header: config.header || {},
success: (res) => {
if (res.statusCode === 200) {
let updData = JSON.parse(res.data)
if (updData.status_code === 200) {
resolve(updData.data)
} else {
reject(updData)
}
}
},
fail: (err) => {
console.log('ERR', err);
}
})
/**
* 群组基础信息
*/
const getGroupBase = (groupId) => {
return request({
url: 'im/groups/' + groupId + '/base'
})
}
const getGroupUsers = (groupId) => {
return request({
url: 'im/groups/' + groupId + '/users'
})
}
const getGroupAnnouncements = (groupId) => {
return request({
url: 'im/groups/' + groupId + '/announcements'
})
}
const createGroupAnnouncement = (groupId, content) => {
return request({
method: 'POST',
url: 'im/groups/' + groupId + '/announcements',
data: {
content: content
}
})
}
const deleteGroupAnnouncement = (groupId, announcementId) => {
return request({
method: 'DELETE',
url: 'im/groups/' + groupId + '/announcements/' + announcementId
})
}
/**
* 创建群聊
*/
const createGroup = (data) => {
return request({
method: 'POST',
url: 'im/groups',
data: data
})
}
const updateGroup = (groupId, data) => {
return request({
method: 'PUT',
url: 'im/groups/' + groupId,
data: data
})
}
/**
* 搜索群聊
*/
const searchGroup = (name) => {
return request({
url: 'im/groups/search?name=' + name
})
}
/**
* 加群前,获取的群信息
*/
const joinGroupPre = (groupId) => {
return request({
url: 'im/groups/' + groupId + '/join'
})
}
const joinGroup = (groupId, message) => {
return request({
method: 'POST',
url: 'im/groups/' + groupId + '/join',
data: {
message
}
})
}
const quitGroup = (groupId) => {
return request({
method: 'POST',
url: 'im/groups/' + groupId + '/quit'
})
}
/**
* 解散群聊
*/
const dismissGroup = (groupId) => {
return request({
method: 'DELETE',
url: 'im/groups/' + groupId
})
}
@@ -141,6 +214,7 @@ export {
getImToken,
deleteFriend,
getFriends,
getFriendsLetter,
getUserInfo,
getFriendInfo,
getPedings,
@@ -148,6 +222,18 @@ export {
rejectFriend,
searchFriend,
pedingFriend,
getPendingCount,
uploadMessageFile
getMyGroups,
createGroup,
updateGroup,
getGroupInfo,
getGroupBase,
getGroupUsers,
getGroupAnnouncements,
createGroupAnnouncement,
deleteGroupAnnouncement,
searchGroup,
joinGroupPre,
joinGroup,
quitGroup,
dismissGroup
}

View File

@@ -6,6 +6,7 @@
* @LastEditTime: 2022-01-12 17:13:45
*/
import { request } from '../index'
/**
* @description:称量体重模块首页
*/
@@ -15,6 +16,16 @@ const weights = (page) => {
data: { page: page }
})
}
/**
* @description:获取曲线进度
*/
const curves = () => {
return request({
url: 'health/weights/bight'
})
}
/**
* @description:记录体重
* @Date: 2022-01-12 16:46:19
@@ -26,7 +37,9 @@ const addWeight = (data) => {
data: data
})
}
export {
weights,
addWeight
addWeight,
curves
}

View File

@@ -0,0 +1,330 @@
<!--
* @Description:日历模板
* @Author: Aimee·Zhang
* @Date: 2022-02-08 09:06:45
* @LastEditors: Aimee·Zhang
* @LastEditTime: 2022-02-08 09:06:45
-->
<template>
<view class="date">
<u-popup :show="dateShow" zIndex="10099890" @close="closeDate" mode="bottom" :safeAreaInsetBottom="true">
<view class="date-content">
<view class="title"><span @click="datePreNext('before')">上一月</span>{{month}}<span
@click="datePreNext('after')">下一月</span></view>
<view class="date-item">
<view class="week">
<view class="week-item" v-for="(item,index) in weekList" :key="index">{{item}}</view>
</view>
<!-- 饮食模块 -->
<block v-if="type === 'foods'">
<view class="week" style="padding-top: 30rpx;">
<view v-for="item in lists" :key="item.today" @click="dateClick(item)"
:class="['week-item',{'is_past':!item.is_month},{'is_today':item.today === today},{'is_intake0':item.intake === 1},{'is_intake1':item.intake === 2},{'is_intake2':item.intake === 3}]">
{{item.day}}
</view>
</view>
<view class="des">
<block> <view class="des-item">吃少了</view> <view class="des-item">正好</view> <view class="des-item">吃多了</view> </block>
<view class="back" @click="backDate"> 回今天 </view>
</view>
</block>
<!-- 喝水模块 -->
<block v-if="type === 'drink'">
<view class="week" style="padding-top: 30rpx;">
<view v-for="item in lists" :key="item.today" @click="dateClick(item)" :class="['week-item',{'is_past':!item.is_month},{'is_today':item.today === today}]">
{{item.day}}
<u-image class='waterIcon' :src="require('@/static/imgs/water-1.png')" v-if="item.drink === 2" :lazy-load="true" width="20rpx" radius="10rpx" mode="widthFix" />
<u-image class='waterIcon' :src="require('@/static/imgs/water-2.png')" v-if="item.drink === 1" :lazy-load="true" width="20rpx" radius="10rpx" mode="widthFix" />
</view>
</view>
<view class="drink">
<block>
<view class="drink-item">
<u-image class='waterIcon' :src="require('@/static/imgs/water-1.png')" :lazy-load="true" width="22rpx" radius="10rpx" mode="widthFix" />未完成指标
</view>
<view class="drink-item">
<u-image class='waterIcon' :src="require('@/static/imgs/water-2.png')" :lazy-load="true" width="22rpx" radius="10rpx" mode="widthFix" /> 完成指标
</view>
</block>
<view class="back" @click="backDate"> 回今天 </view>
</view>
</block>
</view>
</view>
</u-popup>
</view>
</template>
<script>
import moment from 'moment';
export default {
data() {
return {
weekList: ['日', '一', '二', '三', '四', '五', '六'],
};
},
props: {
/**
* lists 传过来的列表
* type foods食物运动 drink饮水weight体重
* today 勾选时间
* month 勾选日期
* dateShow 页面是否显示
**/
lists: {
type: Array,
default: [],
},
type: {
type: String,
default: "",
},
today: {
type: String,
default: moment(new Date()).format('YYYY-MM-DD')
},
month: {
type: String,
default: moment(new Date()).format('YYYY-MM')
},
dateShow: {
type: Boolean,
default: false
}
},
methods: {
// 选择日期
dateClick(item) {
this.$emit('dateClick', item)
},
// 返回今天
backDate() {
this.$emit('backDate', '')
},
// 点击上一个月或者下一个月 before 上一月 after下一个月
datePreNext(type) {
this.$emit('datePreNext', type)
},
// 关闭日历
closeDate() {
this.$emit('closeDate')
}
},
};
</script>
<style lang="scss" scoped>
.date {
// 日历弹窗
.date-content {
width: 100%;
padding: $padding *2;
min-height: 800rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
box-sizing: border-box;
.title {
font-size: $title-size + 4;
color: #20845f;
font-weight: bold;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
width: 100%;
span {
display: inline-block;
padding: $padding;
font-size: $title-size-m;
color: #cacaca;
font-weight: normal;
}
}
.date-item {
padding-top: $padding;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
.drink {
display: flex;
color: #cacaca;
flex-direction: row;
align-items: center;
box-sizing: border-box;
font-size: $title-size-m;
justify-content: center;
margin-top: $margin;
width: 100%;
.drink-item {
padding-right: 40rpx;
position: relative;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-sizing: border-box;
u-image{
padding-right: 10rpx;
}
}
}
.des {
display: flex;
color: #cacaca;
flex-direction: row;
align-items: center;
box-sizing: border-box;
font-size: $title-size-m;
justify-content: center;
margin-top: $margin;
width: 100%;
.des-item {
padding-left: 40rpx;
padding-right: 10rpx;
position: relative;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-sizing: border-box;
&:before {
content: '';
position: absolute;
left: 14rpx;
width: 20rpx;
height: 20rpx;
border-radius: 50%;
background: #fa624d;
}
&:nth-child(2):before {
background: #fbbf0f;
}
&:nth-child(1):before {
background: #02c7bd;
}
}
}
.back {
margin-left: 100rpx;
background-color: rgba($color: $main-color, $alpha: 1);
color: #fff;
padding: 10rpx $padding;
border-radius: $radius + 10;
}
}
.week {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
box-sizing: border-box;
flex-wrap: wrap;
width: 100%;
.week-item {
width: 14.28%;
height: 90rpx;
line-height: 90rpx;
font-size: $title-size-m + 2;
color: #888;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
&::before {
content: '';
width: 14rpx;
height: 14rpx;
border-radius: 50%;
position: absolute;
bottom: 0;
// background: #02c7bd;
}
}
.waterIcon {
position: absolute;
width: 30rpx !important;
bottom: -12rpx;
padding-left: 10rpx;
}
&:nth-child(1),
&:nth-child(7),
&:nth-child(8),
&:nth-child(14),
&:nth-child(15),
&:nth-child(21),
&:nth-child(22),
&:nth-child(28),
&:nth-child(29),
&:nth-child(35),
{
color: rgba($color: #000000, $alpha: 0.4);
}
}
// 吃饭样式
.is_intake0::before {
background: #02c7bd !important;
}
.is_intake1::before {
background: #fbbf0f !important;
}
.is_intake2::before {
background: #fa624d !important;
}
.is_today {
color: #fff !important;
position: relative;
z-index: 1;
&:after {
content: '';
width: 50rpx;
height: 50rpx;
position: absolute;
border-radius: 50%;
background-color: $main-color;
color: #Fff;
z-index: -1;
}
}
.is_past {
color: rgba($color: #000000, $alpha: 0.1) !important;
}
}
}
</style>

View File

@@ -2,8 +2,8 @@
"name" : "ZH-HEALTH",
"appid" : "__UNI__C29473D",
"description" : "ZH-HEALTH您手上的健康管理专家",
"versionName" : "1.0.7",
"versionCode" : 107,
"versionName" : "1.0.8",
"versionCode" : 108,
"transformPx" : false,
/* 5+App */
"app-plus" : {

View File

@@ -35,9 +35,8 @@
"path": "pages/record/drink",
"name": "Drink",
"style": {
"navigationBarTitleText": "记录喝水",
"navigationBarBackgroundColor": "#34CE98",
"navigationBarTextStyle": "white"
"navigationBarTitleText": "记录",
"navigationStyle": "custom"
}
},
{
@@ -53,9 +52,8 @@
"path": "pages/record/foods",
"name": "RecordFoods",
"style": {
"navigationBarTitleText": "食物记录",
"navigationBarBackgroundColor": "#34CE98",
"navigationBarTextStyle": "white"
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
@@ -80,7 +78,7 @@
"path": "pages/evaluation/list",
"name": "EvaluationList",
"style": {
"navigationBarTitleText": "评测列表",
"navigationBarTitleText": "健康评测",
"navigationBarBackgroundColor": "#34CE98",
"navigationBarTextStyle": "white"
}
@@ -369,10 +367,18 @@
"path": "pages/im/index",
"name": "IM",
"style": {
"navigationBarBackgroundColor": "#FFFFFF",
"navigationStyle": "custom"
}
},
{
"path": "pages/im/private/chat",
"style": {
"disableScroll": true,
"navigationBarTitleText": "聊天",
"enablePullDownRefresh": false,
"navigationBarBackgroundColor": "#F3F6FB"
}
},
{
"path": "pages/im/private/call",
"name": "imPrivateCall",
@@ -402,40 +408,110 @@
"path": "pages/im/friends/pending",
"name": "imFriendsPending",
"style": {
"navigationBarTitleText": "新朋友",
"navigationBarBackgroundColor": "#F3F6FB"
"navigationBarTitleText": "新朋友"
}
},
{
"path": "pages/im/friends/search",
"name": "SearchFriend",
"style": {
"navigationBarTitleText": "好友搜索",
"navigationBarBackgroundColor": "#F3F6FB"
"navigationBarTitleText": "好友搜索"
}
},
{
"path": "pages/im/friends/info",
"name": "imFriendsInfo",
"style": {
"navigationBarTitleText": "好友资料",
"navigationBarBackgroundColor": "#FFFFFF"
"navigationBarTitleText": "用户资料"
}
},
{
"path": "pages/im/friends/mine",
"name": "imFriendsMine",
"style": {
"navigationBarTitleText": "我的二维码",
"navigationBarBackgroundColor": "#34CE98",
"navigationBarTextStyle": "white"
"navigationBarTitleText": "我的资料"
}
},
{
"path": "pages/im/group/index",
"name": "imGroup",
"name": "imGroups",
"style": {
"navigationBarTitleText": "我的群聊"
"navigationBarTitleText": "我的群聊",
"app-plus": {
"titleNView": {
"type": "default",
"buttons": [{
"float": "right",
"fontSrc": "/static/iconfont.ttf",
"text": "\ue60a",
"fontSize": "20px"
}]
}
}
}
},
{
"path": "pages/im/group/chat",
"name": "imGroupChat",
"style": {
"navigationBarTitleText": "群聊",
"app-plus": {
"titleNView": {
"type": "default",
"buttons": [{
"float": "right",
"fontSrc": "/static/iconfont.ttf",
"text": "\ue607",
"fontSize": "20px"
}]
}
}
}
},
{
"path": "pages/im/group/apply",
"name": "imGroupApply",
"style": {
"navigationBarTitleText": "申请加群"
}
},
{
"path": "pages/im/group/info",
"name": "imGroupInfo",
"style": {
"navigationBarTitleText": "群信息"
}
},
{
"path": "pages/im/group/users",
"name": "imGroupUsers",
"style": {
"navigationBarTitleText": "群成员"
}
},
{
"path": "pages/im/group/announcement",
"name": "imGroupAnnouncement",
"style": {
"navigationBarTitleText": "群公告",
"app-plus": {
"titleNView": {
"type": "default",
"buttons": [{
"float": "right",
"fontSrc": "/static/iconfont.ttf",
"text": "\ue60a",
"fontSize": "20px"
}]
}
}
}
},
{
"path": "pages/im/group/announceCreate",
"name": "imGroupAnnouncementCreate",
"style": {
"navigationBarTitleText": "发布群公告"
}
},
{
@@ -548,14 +624,6 @@
"navigationBarBackgroundColor": "#34CE98",
"navigationBarTextStyle": "white"
}
}, {
"path": "pages/im/private/chat",
"style": {
"disableScroll": true,
"navigationBarTitleText": "聊天",
"enablePullDownRefresh": false,
"navigationBarBackgroundColor": "#F3F6FB"
}
}
],
"tabBar": {

View File

@@ -2,21 +2,10 @@
<view class="content">
<!-- tool -->
<view class="tool-flex">
<view
class="tool-flex-item"
@click="$Router.back()"
>
<uni-icons
type="closeempty"
size="22"
color="#666"
></uni-icons>
<view class="tool-flex-item" @click="$Router.back()">
<uni-icons type="closeempty" size="22" color="#666"></uni-icons>
</view>
<view
class="tool-flex-item"
@click="onKeyAuth()"
v-if="$Route.query.keyPhone == 1"
>一键登录</view>
<view class="tool-flex-item" @click="onKeyAuth()" v-if="$Route.query.keyPhone == 1">一键登录</view>
</view>
<!-- 欢迎使用 -->
<view class="header">
@@ -26,34 +15,14 @@
<!-- 输入手机号相关 -->
<view class="inputs phone">
<label class="label">+86</label>
<input
type="number"
placeholder="输入您的手机号码"
maxlength="11"
v-model="phone"
/>
<input type="number" placeholder="输入您的手机号码" maxlength="11" v-model="phone" />
</view>
<view class="inputs sms">
<input
type="number"
placeholder="输入短信验证码"
maxlength="4"
v-model="code"
/>
<button
class="sms-btn"
type="default"
size="mini"
:disabled="phone == '' || getSms"
@click="getPhoneCode"
>{{getSms ? '重新发送' + smsTime + 's': '发送验证码'}}</button>
<input type="number" placeholder="输入短信验证码" maxlength="4" v-model="code" />
<button class="sms-btn" type="default" size="mini" :disabled="phone == '' || getSms"
@click="getPhoneCode">{{getSms ? '重新发送' + smsTime + 's': '发送验证码'}}</button>
</view>
<button
class="btn"
type="default"
:disabled="phone == '' || code == ''"
@click="login"
>登录</button>
<button class="btn" type="default" :disabled="phone == '' || code == ''" @click="login">登录</button>
<!-- 用户登录注册协议 -->
<view class="agreement">
未注册的手机号码验证后自动创建账号登录即表示同意接受平台
@@ -65,203 +34,220 @@
</template>
<script>
import { getSms, smsAuth } from "@/apis/interfaces/auth";
import userAuth from "@/public/userAuth";
export default {
data() {
return {
phone: "",
code: "",
smsTime: 60,
getSms: false,
};
},
methods: {
// 用户登录
login() {
smsAuth({
mobileNo: this.phone,
code: this.code,
}).then((res) => {
console.log(111)
this.$store.commit(
"setToken",
res.token_type + " " + res.access_token
);
this.$Router.back();
}).catch((err) => {
console.log(2222)
uni.showToast({
title: err.message,
icon: "none",
});
});
import {
getSms,
smsAuth
} from "@/apis/interfaces/auth";
import userAuth from "@/public/userAuth";
export default {
data() {
return {
phone: "",
code: "",
smsTime: 60,
getSms: false,
};
},
// 获取验证码
getPhoneCode() {
let outTime;
getSms({
mobileNo: this.phone,
})
.then((res) => {
uni.showToast({
title: res,
icon: "none",
});
this.getSms = true;
outTime = setInterval(() => {
if (this.smsTime <= 1) {
this.getSms = false;
this.smsTime = 60;
clearInterval("outTime");
}
this.smsTime -= 1;
}, 1000);
})
.catch((err) => {
methods: {
// 用户登录
login() {
smsAuth({
mobileNo: this.phone,
code: this.code,
}).then((res) => {
this.$store.commit(
"setToken",
res.token_type + " " + res.access_token
);
this.$Router.back();
}).catch((err) => {
uni.showToast({
title: err.message,
icon: "none",
});
});
},
// 获取验证码
getPhoneCode() {
let outTime;
getSms({
mobileNo: this.phone,
})
.then((res) => {
uni.showToast({
title: res,
icon: "none",
});
this.getSms = true;
outTime = setInterval(() => {
if (this.smsTime <= 1) {
this.getSms = false;
this.smsTime = 60;
clearInterval("outTime");
}
this.smsTime -= 1;
}, 1000);
})
.catch((err) => {
uni.showToast({
title: err.message,
icon: "none",
});
});
},
// 一键登录
onKeyAuth() {
const Auth = new userAuth();
this.$Router.back();
Auth.Login();
},
},
// 一键登录
onKeyAuth() {
const Auth = new userAuth();
this.$Router.back();
Auth.Login();
},
},
};
};
</script>
<style lang="scss" scoped>
.content {
height: 100vh;
width: 100vw;
padding: $padding * 3;
box-sizing: border-box;
background: white;
@extend .vertical;
// 操作栏
.tool-flex {
position: fixed;
top: 0;
left: 0;
right: 0;
display: flex;
justify-content: space-between;
padding-left: $padding * 2;
padding-right: $padding * 2;
.content {
height: 100vh;
width: 100vw;
padding: $padding * 3;
box-sizing: border-box;
background: white;
@extend .ios-top;
&-item {
line-height: 90rpx;
color: $text-gray;
font-size: $title-size-lg;
}
}
// 表单
.inputs {
background: $window-color;
position: relative;
margin-top: $margin;
height: 90rpx;
line-height: 90rpx;
border-radius: 45rpx;
input {
width: 100%;
height: 90rpx;
line-height: 90rpx;
padding: 0 $padding;
border: none;
box-sizing: border-box;
font-size: $title-size-lg;
}
@extend .vertical;
&.phone {
padding-left: 120rpx;
.label {
position: absolute;
left: 0;
top: 0;
width: 120rpx;
text-align: center;
border-right: solid 1rpx $border-color;
// 操作栏
.tool-flex {
position: fixed;
top: 0;
left: 0;
right: 0;
display: flex;
justify-content: space-between;
padding-left: $padding * 2;
padding-right: $padding * 2;
background: white;
@extend .ios-top;
&-item {
line-height: 90rpx;
color: $text-gray;
font-size: $title-size-lg;
}
}
&.sms {
padding-right: 200rpx;
.sms-btn[size='mini'] {
width: 200rpx;
height: 90rpx;
line-height: 90rpx;
position: absolute;
top: 0;
right: 0;
padding: 0;
margin: 0;
border-radius: 0 45rpx 45rpx 0;
color: $main-color;
font-size: $title-size-lg;
background: $window-color;
&::after {
border: none;
}
&[disabled] {
color: rgba($color: $main-color, $alpha: .6);
background: rgba($color: $window-color, $alpha: 0);
}
}
}
}
// 头部
.header{
text-align: center;
margin-bottom: 5vh;
.title {
font-size: $title-size + 10;
font-weight: bold;
color: $text-color;
line-height: 70rpx;
}
.sumbit{
line-height: 50rpx;
font-size: $title-size-m;
color: $text-gray-m;
}
}
// 登录按钮
.btn {
margin: 0;
margin-top: $margin*2;
height: 90rpx;
line-height: 90rpx;
padding: 0;
font-size: $title-size;
border-radius: 45rpx;
background: $main-color;
color: white;
font-weight: bold;
&::after{
display: none;
}
&[disabled]{
background: rgba($color: $main-color, $alpha: .5);
}
}
// 协议
.agreement {
padding-top: 5vh;
font-size: $title-size-sm;
color: $text-gray-m;
view {
color: $main-color;
display: inline-block;
padding: 0 10rpx;
}
}
}
// 表单
.inputs {
background: $window-color;
position: relative;
margin-top: $margin;
height: 90rpx;
line-height: 90rpx;
border-radius: 45rpx;
input {
width: 100%;
height: 90rpx;
line-height: 90rpx;
padding: 0 $padding;
border: none;
box-sizing: border-box;
font-size: $title-size-lg;
}
&.phone {
padding-left: 120rpx;
.label {
position: absolute;
left: 0;
top: 0;
width: 120rpx;
text-align: center;
border-right: solid 1rpx $border-color;
font-size: $title-size-lg;
}
}
&.sms {
padding-right: 200rpx;
.sms-btn[size='mini'] {
width: 200rpx;
height: 90rpx;
line-height: 90rpx;
position: absolute;
top: 0;
right: 0;
padding: 0;
margin: 0;
border-radius: 0 45rpx 45rpx 0;
color: $main-color;
font-size: $title-size-lg;
background: $window-color;
&::after {
border: none;
}
&[disabled] {
color: rgba($color: $main-color, $alpha: .6);
background: rgba($color: $window-color, $alpha: 0);
}
}
}
}
// 头部
.header {
text-align: center;
margin-bottom: 5vh;
.title {
font-size: $title-size + 10;
font-weight: bold;
color: $text-color;
line-height: 70rpx;
}
.sumbit {
line-height: 50rpx;
font-size: $title-size-m;
color: $text-gray-m;
}
}
// 登录按钮
.btn {
margin: 0;
margin-top: $margin*2;
height: 90rpx;
line-height: 90rpx;
padding: 0;
font-size: $title-size;
border-radius: 45rpx;
background: $main-color;
color: white;
font-weight: bold;
&::after {
display: none;
}
&[disabled] {
background: rgba($color: $main-color, $alpha: .5);
}
}
// 协议
.agreement {
padding-top: 5vh;
font-size: $title-size-sm;
color: $text-gray-m;
view {
color: $main-color;
display: inline-block;
padding: 0 10rpx;
}
}
}
</style>

View File

@@ -11,21 +11,18 @@
<!-- 进度 -->
<view class="plan">
<view class="plan-1">
<span>基本信息</span>
<u-line-progress :percentage="percentplan1" activeColor="#34ce98" class="line-progress" :showText="false" />
<span>基本信息</span> <u-line-progress :percentage="percentplan1" activeColor="#34ce98" class="line-progress" :showText="false" />
</view>
<view class="plan-2">
<span>健康目标</span>
<u-line-progress :percentage="percentplan2" activeColor="#34ce98" width="200rpx" class="line-progress" :showText="false" />
<span>健康目标</span> <u-line-progress :percentage="percentplan2" activeColor="#34ce98" width="200rpx" class="line-progress" :showText="false" />
</view>
<view class="plan-3">
<span>行为习惯</span>
<u-line-progress :percentage="percentplan3" activeColor="#34ce98" width="200rpx" class="line-progress" :showText="false" />
<span>行为习惯</span> <u-line-progress :percentage="percentplan3" activeColor="#34ce98" width="200rpx" class="line-progress" :showText="false" />
</view>
</view>
<!-- 进度1 基本信息 -->
<view>
<block>
<!-- 进度1 基本信息页面展示 性别 -->
<view class="plan-content" v-if="sexShow">
<view class="info-des">生理性别和激素会影响我们的身体代谢食物的方式</view>
@@ -47,19 +44,7 @@
<view class="age">
<view class="info-title">你的出生日期是</view>
<view class="year" @change="dateShow = true">{{ showBirthday }}</view>
<u-datetime-picker
confirmColor="#34ce98"
ref="datetimePicker"
v-model="birthday"
mode="date"
:show="dateShow"
:formatter="formatter"
:minDate="-302688000"
:maxDate="maxDate"
:closeOnClickOverlay="true"
@confirm="confirmBirthday"
@cancel="camcelBirthday"
/>
<u-datetime-picker confirmColor="#34ce98" ref="datetimePicker" v-model="birthday" mode="date" :show="dateShow" :formatter="formatter" :minDate="-302688000" :maxDate="maxDate" :closeOnClickOverlay="true" @confirm="confirmBirthday" @cancel="camcelBirthday" />
</view>
</view>
@@ -68,7 +53,6 @@
<u-image class="sex-item-avatar" width="100rpx" height="100rpx" :src="require('../../static/imgs/avatar-1.png')" :lazy-load="true" shape="circle" />
<view class="info-des">身高体重信息对健康信息有重要参考价值</view>
<view class="info-title">您的身高是</view>
<!-- -->
<view class="weight">
<view class="count"><span>{{ heightU }}</span>厘米</view>
<vue-scale :min="10" :max="100" :int="false" :single="10" :h="80" :styles="styles" @scroll="scrollHeight" :scrollLeft="Number(heightU)" />
@@ -84,51 +68,18 @@
<view class="next" @click="weightClick(2)">下一步</view>
</view>
</view>
</view>
</block>
<!-- 进度2 健康目标 -->
<view>
<block>
<!-- 减脂类型 -->
<view v-if="targetShow" class="plan-content target-content">
<u-image class="sex-item-avatar" width="100rpx" height="100rpx" :src="require('../../static/imgs/avatar-1.png')" :lazy-load="true" shape="circle" />
<view class="info-title">您的目标是</view>
<view class="target-type">
<view class="target-type-item">
<u-image
class="target-img"
width="160rpx"
height="160rpx"
@click="activedTarget = '1'"
:src="activedTarget === '1' ? require('../../static/imgs/ic-w-s.png') : require('../../static/imgs/ic-w-n.png')"
:lazy-load="true"
shape="circle"
/>
减肥
</view>
<view class="target-type-item">
<u-image
class="target-img"
width="160rpx"
height="160rpx"
@click="activedTarget = '2'"
:src="activedTarget === '2' ? require('../../static/imgs/ic-b-s.png') : require('../../static/imgs/ic-b-n.png')"
:lazy-load="true"
shape="circle"
/>
保持体重
</view>
<view class="target-type-item">
<u-image
class="target-img"
width="160rpx"
height="160rpx"
@click="activedTarget = '3'"
:src="activedTarget === '3' ? require('../../static/imgs/ic-m-s.png') : require('../../static/imgs/ic-m-n.png')"
:lazy-load="true"
shape="circle"
/>
增肌
</view>
<view class="target-type-item"> <u-image class="target-img" width="160rpx" height="160rpx" @click="activedTarget = '1'" :src="activedTarget === '1' ? require('../../static/imgs/ic-w-s.png') : require('../../static/imgs/ic-w-n.png')" :lazy-load="true" shape="circle" /> 减肥 </view>
<view class="target-type-item"> <u-image class="target-img" width="160rpx" height="160rpx" @click="activedTarget = '2'" :src="activedTarget === '2' ? require('../../static/imgs/ic-b-s.png') : require('../../static/imgs/ic-b-n.png')" :lazy-load="true" shape="circle" /> 保持体重 </view>
<view class="target-type-item"> <u-image class="target-img" width="160rpx" height="160rpx" @click="activedTarget = '3'" :src="activedTarget === '3' ? require('../../static/imgs/ic-m-s.png') : require('../../static/imgs/ic-m-n.png')" :lazy-load="true" shape="circle" /> 增肌 </view>
</view>
<view class="pre-next">
<view class="pro" @click="targetClick(1)">上一步</view>
@@ -141,10 +92,7 @@
<view class="info-title">您的打算减脂多少</view>
<view class="target-type">
<view class="target-type-item">
<view class="count">
<span>{{ weightTargetU }}</span>
公斤
</view>
<view class="count"> <span>{{ weightTargetU }}</span> 公斤 </view>
<vue-scale :min="10" :max="100" :int="false" :single="10" :h="80" :styles="styles" @scroll="scrollTargetWeight" :scrollLeft="Number(weightTargetU)" />
</view>
</view>
@@ -153,7 +101,7 @@
<view class="next" @click="targetWeightClick(2)">下一步</view>
</view>
</view>
</view>
</block>
<!-- 进度3 行为习惯 -->
<!-- 减脂类型 -->
@@ -162,51 +110,19 @@
<view class="info-title">您的运动量是</view>
<view class="target-type">
<view class="target-type-item">
<u-image
class="target-img"
width="120rpx"
height="120rpx"
@click="activedbehaviarTarget = '1'"
:src="activedbehaviarTarget === '1' ? require('../../static/imgs/ic-w-01.png') : require('../../static/imgs/ic-w-02.png')"
:lazy-load="true"
shape="circle"
/>
<u-image class="target-img" width="120rpx" height="120rpx" @click="activedbehaviarTarget = '1'" :src="activedbehaviarTarget === '1' ? require('../../static/imgs/ic-w-01.png') : require('../../static/imgs/ic-w-02.png')" :lazy-load="true" shape="circle" />
久坐不动
</view>
<view class="target-type-item">
<u-image
class="target-img"
width="120rpx"
height="120rpx"
@click="activedbehaviarTarget = '2'"
:src="activedbehaviarTarget === '2' ? require('../../static/imgs/ic-w-03.png') : require('../../static/imgs/ic-w-04.png')"
:lazy-load="true"
shape="circle"
/>
<u-image class="target-img" width="120rpx" height="120rpx" @click="activedbehaviarTarget = '2'" :src="activedbehaviarTarget === '2' ? require('../../static/imgs/ic-w-03.png') : require('../../static/imgs/ic-w-04.png')" :lazy-load="true" shape="circle" />
少量运动
</view>
<view class="target-type-item">
<u-image
class="target-img"
width="120rpx"
height="120rpx"
@click="activedbehaviarTarget = '3'"
:src="activedbehaviarTarget === '3' ? require('../../static/imgs/ic-w-05.png') : require('../../static/imgs/ic-w-06.png')"
:lazy-load="true"
shape="circle"
/>
<u-image class="target-img" width="120rpx" height="120rpx" @click="activedbehaviarTarget = '3'" :src="activedbehaviarTarget === '3' ? require('../../static/imgs/ic-w-05.png') : require('../../static/imgs/ic-w-06.png')" :lazy-load="true" shape="circle" />
中等运动量
</view>
<view class="target-type-item">
<u-image
class="target-img"
width="120rpx"
height="120rpx"
@click="activedbehaviarTarget = '4'"
:src="activedbehaviarTarget === '4' ? require('../../static/imgs/ic-w-07.png') : require('../../static/imgs/ic-w-08.png')"
:lazy-load="true"
shape="circle"
/>
<u-image class="target-img" width="120rpx" height="120rpx" @click="activedbehaviarTarget = '4'" :src="activedbehaviarTarget === '4' ? require('../../static/imgs/ic-w-07.png') : require('../../static/imgs/ic-w-08.png')" :lazy-load="true" shape="circle" />
超强度运动
</view>
</view>
@@ -274,7 +190,6 @@ export default {
},
computed: {
showBirthday() {
console.log(moment(this.birthday).format('YYYY年MM月DD日'));
return moment(this.birthday).format('YYYY年MM月DD日');
}
},
@@ -297,6 +212,7 @@ export default {
this.percentplan1 = uni.$u.range(0, 100, this.percentplan1 + 33.33); // 增加进度
this.heightWeightShow = true; // 展示身高体重模块
},
// 年龄 ----- 取消选择年龄
camcelBirthday() {
this.birthdayShow = false; // // 年龄页面弹窗不显示
@@ -304,6 +220,7 @@ export default {
this.percentplan1 = 0; // 进度为0
this.sexShow = true; // 显示性别页面
},
//年龄------------- 过滤出生年月日
formatter(type, value) {
if (type === 'year') {return `${value}`;}
@@ -311,6 +228,8 @@ export default {
if (type === 'day') {return `${value}`;}
return value;
},
// 体重---------标尺滚动
scrollWeight(msg) {
this.weightU = msg;
@@ -332,6 +251,8 @@ export default {
this.targetShow = true; // 目标页面展示
}
},
// 目标 ------------点击 1上一页 2 下一页
targetClick(type) {
if (type === 1) {
@@ -368,6 +289,8 @@ export default {
this.behaviorShow = true; // 打开行为习惯页面
}
},
// 目标 运动量--------- 1上一页 2 下一页
targetBehaviorClick(type) {
if (type === 1) {
@@ -391,7 +314,6 @@ export default {
exercise: this.activedbehaviarTarget, // 运动量
days: 1
};
console.log(params, 'params.....');
recordsHealth(params)
.then(res => {
uni.showModal({
@@ -406,10 +328,12 @@ export default {
});
})
.catch(err => {
uni.showToast({
title: err.message,
icon: 'none'
});
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
});
}
}

View File

@@ -6,172 +6,175 @@
* @LastEditTime: 2022-01-13 17:16:09
-->
<template>
<view class="evaluation">
<!-- 进度 -->
<view class="percent">
<u-icon
name="arrow-left"
:color="colorList[colorIndex]"
size="14"
label="上一题"
:labelColor="colorList[colorIndex]"
labelSize="14"
:bold="true"
space="3"
v-if="page !== 1"
@click="preQ"
/>
<u-line-progress class="pre-ico" :percentage="percent" height="10" :showText="false" :activeColor="colorList[colorIndex]" />
<span :style="{ color: colorList[colorIndex] }">{{ percent }}%</span>
</view>
<!-- 标题 -->
<view class="title">{{ page }}.{{ currentInfo.title }}</view>
<!-- 题目列表 -->
<view class="lists">
<view class="list-item">
<u-radio-group placement="column" @change="groupChange" iconPlacement="right" class="radio-g" :value="currentId">
<u-radio
class="radio-item"
:customStyle="{ marginBottom: '8px' }"
v-for="(item, index) in currentInfo.options"
:key="index"
:label="item.title"
:name="item.option_id"
:activeColor="colorList[colorIndex]"
></u-radio>
</u-radio-group>
</view>
<!-- 底部确认按钮 -->
<view class="bottom-btn" :style="{ background: colorList[colorIndex] }" @click="next">下一步</view>
</view>
</view>
<view class="evaluation">
<!-- 进度 -->
<view class="percent">
<u-icon name="arrow-left" :color="colorList[colorIndex]" size="14" label="上一题" :labelColor="colorList[colorIndex]" labelSize="14" :bold="true" space="3" v-if="page !== 1" @click="preQ" />
<u-line-progress class="pre-ico" :percentage="percent" height="10" :showText="false" :activeColor="colorList[colorIndex]" />
<span :style="{ color: colorList[colorIndex] }">{{ percent }}%</span>
</view>
<!-- 标题 -->
<view class="title">{{ page }}.{{ currentInfo.title }}</view>
<!-- 题目列表 -->
<view class="lists">
<view class="list-item">
<u-radio-group placement="column" @change="groupChange" iconPlacement="right" class="radio-g" :value="currentId">
<u-radio class="radio-item" :customStyle="{ marginBottom: '8px' }" v-for="(item, index) in currentInfo.options" :key="index" :label="item.title" :name="item.option_id" :activeColor="colorList[colorIndex]" />
</u-radio-group>
</view>
<!-- 底部确认按钮 -->
<view class="bottom-btn" :style="{ background: colorList[colorIndex] }" @click="next">下一步</view>
</view>
</view>
</template>
<script>
import { evaluationsQuestion, evaluationsAnswers } from '@/apis/interfaces/evaluation.js';
export default {
components: {},
data() {
return {
percent: 70,
colorList: ['#34ce98', '#b6c29a', '#f4d000', '#8a977b', '#e58308', '#dc5712'],
colorIndex: Math.floor(Math.random() * 6), // 基本案列数据
currentInfo: {}, //当前题目的内容
option_ids: [], // 答案id的数组
has_more: false, // 是否有下一页
page: 1,
currentId: '' // 默认值
};
},
onShow() {
this.getList();
uni.setNavigationBarColor({
frontColor: '#ffffff', //文字颜色
backgroundColor: `${this.colorList[this.colorIndex]}` //底部背景色
});
},
methods: {
getList() {
evaluationsQuestion(this.$Route.query.id, this.page).then(res => {
this.currentInfo = res.data[0];
this.percent = Number(((res.page.current - 1) / res.page.total).toFixed(2)) * 100;
this.has_more = res.page.has_more;
});
},
groupChange(n) {
this.currentId = n;
},
// 上一题
preQ() {
this.option_ids.pop();
this.currentId = '';
this.page = this.page - 1;
this.getList();
},
//下一题
next() {
if (this.has_more) {
if (this.currentId === '') {
uni.showToast({ title: '请选择答案', icon: 'none' });
return;
}
this.option_ids.push(this.currentId);
this.currentId = '';
this.page = this.page + 1;
this.getList();
} else {
if (this.option_ids.length !== this.page) {
this.option_ids.push(this.currentId);
this.currentId = '';
}
let data = {
option_ids: this.option_ids.toString(),
id: this.$Route.query.id
};
evaluationsAnswers(data)
.then(res => {
console.log(res);
this.parent = 100;
uni.showToast({
title: '答题完成,立即查看结果',
icon: 'none',
mask: true
});
setTimeout(() => {
uni.navigateTo({
url: `/pages/evaluation/result?id=${this.$Route.query.id}`
});
}, 1000);
})
.catch(err => {
uni.showToast({
title: err.message
});
});
}
}
}
};
import {
evaluationsQuestion,
evaluationsAnswers
} from '@/apis/interfaces/evaluation.js';
export default {
components: {},
data() {
return {
percent: 70,
colorList: ['#34ce98', '#d04500', '#f4d000', '#55aa00', '#e58308', '#dc5a1d'],
colorIndex: Math.floor(Math.random() * 6), // 基本案列数据
currentInfo: {}, //当前题目的内容
option_ids: [], // 答案id的数组
has_more: false, // 是否有下一页
page: 1,
currentId: '' // 默认值
};
},
onShow() {
this.getList();
uni.setNavigationBarColor({
frontColor: '#ffffff', //文字颜色
backgroundColor: `${this.colorList[this.colorIndex]}` //底部背景色
});
},
methods: {
// 答题列表
getList() {
evaluationsQuestion(this.$Route.query.id, this.page).then(res => {
this.currentInfo = res.data[0];
this.percent = Number(((res.page.current - 1) / res.page.total).toFixed(2)) * 100;
this.has_more = res.page.has_more;
}).catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
});
},
groupChange(n) {
this.currentId = n;
},
// 上一题
preQ() {
this.option_ids.pop();
this.currentId = '';
this.page = this.page - 1;
this.getList();
},
//下一题
next() {
if (this.has_more) {
if (this.currentId === '') {
uni.showToast({
title: '请选择答案',
icon: 'none'
});
return;
}
this.option_ids.push(this.currentId);
this.currentId = '';
this.page = this.page + 1;
this.getList();
} else {
if (this.option_ids.length !== this.page) {
this.option_ids.push(this.currentId);
this.currentId = '';
}
let data = {
option_ids: this.option_ids.toString(),
id: this.$Route.query.id
};
evaluationsAnswers(data)
.then(res => {
this.parent = 100;
uni.showToast({
title: '答题完成,立即查看结果',
icon: 'none',
mask: true
});
setTimeout(() => {
uni.navigateTo({
url: `/pages/evaluation/result?id=${this.$Route.query.id}`
});
}, 1000);
})
.catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
});
}
}
}
};
</script>
<style lang="scss" scoped>
.evaluation {
padding: $padding $padding $padding * 4 $padding;
.percent {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-sizing: border-box;
font-size: $title-size - 2;
.pre-ico {
margin: $padding;
}
}
.title {
font-size: $title-size + 10;
font-weight: bold;
padding-top: $padding;
}
.lists {
.radio-g {
padding-top: $padding * 2;
.radio-item {
background: #f9f9f9;
padding: $padding;
border-radius: $radius;
flex: 1;
}
}
.bottom-btn {
text-align: center;
padding: 24rpx $padding;
border-radius: $radius + 40;
color: #fff;
font-size: $title-size;
position: fixed;
bottom: $padding;
width: calc(100% - 60rpx);
box-sizing: border-box;
}
}
}
.evaluation {
padding: $padding $padding $padding * 4 $padding;
.percent {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-sizing: border-box;
font-size: $title-size - 2;
.pre-ico {
margin: $padding;
}
}
.title {
font-size: $title-size + 10;
font-weight: bold;
padding-top: $padding;
}
.lists {
.radio-g {
padding-top: $padding * 2;
.radio-item {
background: #f9f9f9;
padding: $padding;
border-radius: $radius;
flex: 1;
}
}
.bottom-btn {
text-align: center;
padding: 24rpx $padding;
border-radius: $radius + 40;
color: #fff;
font-size: $title-size;
position: fixed;
bottom: $padding;
width: calc(100% - 60rpx);
box-sizing: border-box;
}
}
}
</style>

View File

@@ -6,129 +6,138 @@
* @LastEditTime: 2022-01-13 17:26:38
-->
<template>
<view class="introduce">
<view class="intro-history" v-if="info.is_answer" @click="toResult">测评记录</view>
<view class="intro-history" v-else @click="toResult">暂未测评</view>
<view class="intro-content">
<view class="intro-title">{{ info.title }}</view>
<u-read-more class="intro-des" :toggle="true" showHeight="140" ref="uReadMore" :shadowStyle="shadowStyle" color="#34ce98" textIndent="0">
<rich-text :nodes="content"></rich-text>
</u-read-more>
<u-image class="intro-img" width="100%" radius="20rpx" height="700rpx" :src="info.cover ? info.cover : require('../../static/imgs/indro.png')" :lazy-load="true" />
<view class="answer" @click="nowAn">开始测评</view>
</view>
<view class="remark">本评测会收集孕产情况健康状况家族病史用药情况信息用于开展相关评测为你生成分析报告</view>
</view>
<view class="introduce">
<view class="intro-history" v-if="info.is_answer" @click="toResult">测评记录</view>
<view class="intro-history" v-else @click="toResult">暂未测评</view>
<view class="intro-content">
<view class="intro-title">{{ info.title }}</view>
<u-read-more class="intro-des" :toggle="true" showHeight="140" ref="uReadMore" :shadowStyle="shadowStyle" color="#34ce98" textIndent="0">
<rich-text :nodes="content"></rich-text>
</u-read-more>
<u-image class="intro-img" width="100%" radius="20rpx" height="700rpx" :src="info.cover ? info.cover : require('../../static/imgs/indro.png')" :lazy-load="true" />
<view class="answer" @click="nowAn">开始测评</view>
</view>
<view class="remark">本评测会收集孕产情况健康状况家族病史用药情况信息用于开展相关评测为你生成分析报告</view>
</view>
</template>
<script>
import { evaluationsInfo } from '@/apis/interfaces/evaluation.js';
export default {
data() {
return {
info: {},
content: `本测试预计完成时间5-8分钟
import {evaluationsInfo} from '@/apis/interfaces/evaluation.js';
export default {
data() {
return {
info: {},
content: `本测试预计完成时间5-8分钟
<br/>
<br/>
适用于18-65岁存在亚健康或尿酸偏高人群`,
shadowStyle: {
backgroundImage: 'none',
paddingTop: '0',
marginTop: '20rpx'
}
};
},
onShow() {
evaluationsInfo(this.$Route.query.id).then(res => {
this.content = res.content;
this.info = res;
});
},
methods: {
nowAn() {
uni.navigateTo({
url: `/pages/evaluation/index?id=${this.$Route.query.id}`
});
},
toResult() {
console.log('点击了测试');
uni.navigateTo({
url: `/pages/evaluation/result?id=${this.$Route.query.id}`
});
}
}
};
shadowStyle: {backgroundImage: 'none',paddingTop: '0',marginTop: '20rpx'}
};
},
onShow() {
evaluationsInfo(this.$Route.query.id).then(res => {
this.content = res.content;
this.info = res;
}).catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
});
},
methods: {
nowAn() {
uni.navigateTo({
url: `/pages/evaluation/index?id=${this.$Route.query.id}`
});
},
toResult() {
uni.navigateTo({
url: `/pages/evaluation/result?id=${this.$Route.query.id}`
});
}
}
};
</script>
<style lang="scss" scoped>
.introduce {
background-color: $main-color;
min-height: 100vh;
.intro-history {
padding: $padding * 1.5 $padding;
color: $window-color;
text-decoration: underline;
font-size: $title-size-lg;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
box-sizing: border-box;
}
// 测评展示
.intro-content {
background: rgba($color: #fff, $alpha: 1);
min-height: 30vh;
padding: 0 $padding;
margin: $margin * 1.5;
border-radius: $radius;
position: relative;
box-shadow: 0 0 10rpx 4rpx rgba($color: $main-color, $alpha: 0.1);
// 标题
.intro-title {
font-size: $title-size * 1.8;
font-weight: bold;
color: $text-color;
position: relative;
top: -40rpx;
}
// 介绍
.intro-des {
line-height: $title-size * 1.8;
color: $text-color;
position: relative;
top: -10rpx;
font-size: $title-size-m;
padding-bottom: 20rpx;
}
// 图片
.intro-img {
margin-top: $padding * 0.8;
}
// 开始测评
.answer {
position: absolute;
bottom: -30rpx;
width: 400rpx;
height: 90rpx;
line-height: 90rpx;
left: 50%;
text-align: center;
background: rgba($color: #fff, $alpha: 0.94);
margin-left: -200rpx;
border-radius: $radius-m * 4;
font-weight: bold;
color: $text-color;
font-size: $title-size-m + 6;
}
}
// 备注信息
.remark {
color: $text-gray;
font-size: $title-size - 6;
padding: $padding * 2 $padding;
line-height: $title-size * 1.3;
}
}
.introduce {
background-color: $main-color;
min-height: 100vh;
.intro-history {
padding: $padding * 1.5 $padding;
color: $window-color;
text-decoration: underline;
font-size: $title-size-lg;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
box-sizing: border-box;
}
// 测评展示
.intro-content {
background: rgba($color: #fff, $alpha: 1);
min-height: 30vh;
padding: 0 $padding;
margin: $margin * 1.5;
border-radius: $radius;
position: relative;
box-shadow: 0 0 10rpx 4rpx rgba($color: $main-color, $alpha: 0.1);
// 标题
.intro-title {
font-size: $title-size * 1.8;
font-weight: bold;
color: $text-color;
position: relative;
top: -40rpx;
}
// 介绍
.intro-des {
line-height: $title-size * 1.8;
color: $text-color;
position: relative;
top: -10rpx;
font-size: $title-size-m;
padding-bottom: 20rpx;
}
// 图片
.intro-img {
margin-top: $padding * 0.8;
}
// 开始测评
.answer {
position: absolute;
bottom: -30rpx;
width: 400rpx;
height: 90rpx;
line-height: 90rpx;
left: 50%;
text-align: center;
background: rgba($color: #fff, $alpha: 0.94);
margin-left: -200rpx;
border-radius: $radius-m * 4;
font-weight: bold;
color: $text-color;
font-size: $title-size-m + 6;
}
}
// 备注信息
.remark {
color: $text-gray;
font-size: $title-size - 6;
padding: $padding * 2 $padding;
line-height: $title-size * 1.3;
}
}
</style>

View File

@@ -11,44 +11,20 @@
<!-- 评测列表主要内容 标题 图片 描述 -->
<view class="--content">
<u-image class="content-img" width="170rpx" height="170rpx" radius="20rpx" :src="item.cover ? item.cover : require('../../static/imgs/test.png')" :lazy-load="true" />
<view class="title-des">
<view class="title">{{ item.title }}</view>
<view class="des">{{ item.description || '--' }}</view>
</view>
<view class="title-des"> <view class="title">{{ item.title }}</view> <view class="des">{{ item.description || '--' }}</view> </view>
</view>
<!-- 分数 -->
<view class="score" v-if="item.is_answer">
<span>{{ item.answer.total }}</span>
</view>
<view class="score" v-if="item.is_answer"> <span>{{ item.answer.total }}</span> </view>
<!-- 评测状态 -->
<view class="--status">
<!-- 已测试展示 状态-->
<view class="status" v-if="item.is_answer">
<span class="dian">·</span>
{{ item.remark }}
</view>
<view class="status" v-if="item.is_answer"> <span class="dian">·</span> {{ item.remark }} </view>
<view v-if="item.is_answer" class="history" @click="toResult(item)">查看历史结果</view>
<!-- 未测试展示 状态-->
<view class="status" v-if="!item.is_answer">
<span class="dian">·</span>
<span class="person">{{ item.remark }}</span>
人已测 | 约4~8分钟
</view>
<u-icon
name="arrow-right"
:color="item.is_answer ? '#26a377' : '#faa81a'"
size="14"
:bold="true"
:label="item.is_answer ? '重新评测' : '开始测评'"
labelPos="left"
labelSize="14"
space="1"
:labelColor="item.is_answer ? '#26a377' : '#faa81a'"
@click="nowEva(item)"
/>
<view class="status" v-if="!item.is_answer"> <span class="dian">·</span> <span class="person">{{ item.remark }}</span> 人已测 | 约4~8分钟 </view>
<u-icon name="arrow-right" :color="item.is_answer ? '#26a377' : '#faa81a'" size="14" :bold="true" :label="item.is_answer ? '重新评测' : '开始测评'" labelPos="left" labelSize="14" space="1" :labelColor="item.is_answer ? '#26a377' : '#faa81a'" @click="nowEva(item)" />
</view>
</view>
<!-- 没有更多 -->
@@ -72,7 +48,14 @@ export default {
getList() {
evaluations().then(res => {
this.evalList = res;
});
}).catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
});
},
// nowEva
nowEva(item) {

View File

@@ -53,9 +53,7 @@
<!-- 标题 -->
<view class="title-content"><view class="title">营养建议</view></view>
<block v-for="(item, index) in 3" :key="index">
<view class="title2">
<span>{{ item }}. 低Gi</span>
</view>
<view class="title2"> <span>{{ item }}. 低Gi</span> </view>
<!-- 描述 -->
<view class="des">饮食营养及生活方式对维持面部年轻态影响较大建议注意食材选择逐步清淡口味规律作息逐个改善不良生活习惯帮助改善当前皮肤状态</view>
</block>
@@ -63,10 +61,7 @@
<!-- 更多 -->
<view class="answer-item">
<!-- 标题 -->
<view class="title-content">
<view class="title">更多护肤知识</view>
<u-icon name="arrow-right" color="#333" size="20" />
</view>
<view class="title-content"> <view class="title">更多护肤知识</view> <u-icon name="arrow-right" color="#333" size="20" /> </view>
<!-- 横向滚动推荐 -->
<scroll-view class="scroll-view_H" scroll-x="true">
<view v-for="(item, index) in 6" :key="index" id="demo1" class="scroll-view-item_H">
@@ -109,7 +104,14 @@ export default {
]
};
this.loaded = true;
});
}).catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
});
},
reEva() {
uni.navigateTo({

View File

@@ -0,0 +1,163 @@
<template>
<view>
<view v-for="(item, index) in conversations" :key="index" :class="['message', { 'is-top': item.isTop }]"
:data-item="item" @longpress="onLongPress" @click="toDetail(item)">
<message-cell :item="item" />
</view>
<view class="shade" @click="hidePop" v-show="showPop">
<view class="pop" :style="popStyle" :class="{'show':showPop}">
<view v-for="(item, index) in popButton" :key="index" @click="pickerMenu" :data-index="index">
{{item}}
</view>
</view>
</view>
</view>
</template>
<script>
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import im from '@/utils/im/index.js'
import messageCell from './messageCell'
export default {
props: {
conversations: {
type: Array,
default: function() {
return []
}
}
},
components: {
messageCell
},
data() {
return {
/* 窗口尺寸 */
winSize: {},
/* 显示操作弹窗 */
showPop: false,
/* 弹窗按钮列表 */
popButton: ['置顶聊天', '删除该聊天'],
/* 弹窗定位样式 */
popStyle: "",
pickedItem: {},
}
},
methods: {
// 隐藏功能菜单
hidePop() {
this.showPop = false
this.pickedItem = {}
setTimeout(() => {
this.showShade = false
}, 250)
},
// 点击会话功能菜单
pickerMenu(e) {
const index = Number(e.currentTarget.dataset.index)
if (index == 0) {
RongIMLib.setConversationToTop(this.pickedItem.conversationType, this.pickedItem.targetId, !this
.pickedItem.isTop)
} else {
RongIMLib.removeConversation(this.pickedItem.conversationType, this.pickedItem.targetId)
RongIMLib.deleteMessages(this.pickedItem.conversationType, this.pickedItem.targetId)
}
this.$emit('refresh')
im.setNotifyBadge()
this.hidePop()
},
// 长按会话,展示功能菜单
onLongPress(e) {
let [touches, style, item] = [e.touches[0], "", e.currentTarget.dataset.item]
if (touches.clientY > (this.winSize.height / 2)) {
style = `bottom:${this.winSize.height-touches.clientY}px;`
} else {
style = `top:${touches.clientY}px;`
}
if (touches.clientX > (this.winSize.witdh / 2)) {
style += `right:${this.winSize.witdh-touches.clientX}px`
} else {
style += `left:${touches.clientX}px`
}
this.popButton[0] = item.isTop ? '取消置顶' : '置顶聊天'
this.popStyle = style
this.pickedItem = item
this.$nextTick(() => {
setTimeout(() => {
this.showPop = true;
}, 10)
})
},
toDetail(item) {
if (item.conversationType == 1) {
uni.navigateTo({
url: '/pages/im/private/chat?targetId=' + item.targetId
})
} else if (item.conversationType == 3) {
uni.navigateTo({
url: '/pages/im/group/chat?targetId=' + item.targetId
})
}
this.hidePop()
}
}
}
</script>
<style lang="scss" scoped>
.message {
background: white;
&.is-top {
background: $window-color;
}
}
/* 遮罩 */
.shade {
position: fixed;
width: 100%;
height: 100%;
.pop {
position: fixed;
z-index: 101;
width: 200rpx;
box-sizing: border-box;
font-size: 28rpx;
text-align: left;
color: #333;
background-color: #fff;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
line-height: 80rpx;
transition: transform 0.15s ease-in-out 0s;
user-select: none;
-webkit-touch-callout: none;
transform: scale(0, 0);
&.show {
transform: scale(1, 1);
}
&>view {
padding: 0 20rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
user-select: none;
-webkit-touch-callout: none;
&:active {
background-color: #f3f3f3;
}
}
}
}
</style>

View File

@@ -0,0 +1,112 @@
<template>
<view class="apply--cell u-border-bottom">
<view class="avatar">
<u-avatar :src="user.portraitUrl" shape="square" size="46" />
</view>
<view class="info">
<view class="name">
{{ user.name }}
</view>
<view class="message">
{{ message.message }}
</view>
</view>
<view class="action">
<u-button type="success" size="mini" @click="resolve">通过</u-button>
<u-button type="warning" size="mini" @click="reject">拒绝</u-button>
</view>
</view>
</template>
<script>
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import {
resolveFriend,
rejectFriend
} from '@/apis/interfaces/im.js'
export default {
props: {
message: {
type: Object,
default: {}
}
},
computed: {
user() {
return JSON.parse(this.message.extra)
}
},
methods: {
resolve() {
resolveFriend(this.message.sourceUserId).then(res => {
this.clearMessages()
uni.showToast({
icon: 'none',
title: '通过好友申请'
})
}).catch(err => {
uni.showToast({
icon: 'none',
title: err.message
})
})
},
reject() {
uni.showModal({
title: '拒绝申请',
success: (res) => {
if (res.confirm) {
rejectFriend(this.message.sourceUserId).then(res => {
this.clearMessages()
}).catch(err => {
uni.showToast({
icon: 'none',
title: err.message
})
})
}
}
})
},
// 不管是通过还是拒绝,都要把相关的信息清理
clearMessages() {
RongIMLib.deleteMessages(RongIMLib.ConversationType.SYSTEM, this.message.sourceUserId)
this.$emit('success')
uni.$emit('onContactNotification')
}
}
}
</script>
<style lang="scss" scoped>
.apply--cell {
display: flex;
padding: $padding;
align-items: center;
.info {
flex: 1;
margin-left: $padding;
.name {
font-size: $title-size + 2;
}
.message {
color: $text-gray-m;
font-size: $title-size-m;
margin-top: 10rpx;
}
}
.action {
justify-content: space-between;
.u-button+.u-button {
margin-top: 10rpx;
}
}
}
</style>

View File

@@ -1,15 +1,14 @@
<template>
<view class="friend-apply">
<block v-for="item in lists" v-if="lists.length > 0" :key="item.userId">
<block v-for="(item, index) in lists" v-if="lists.length > 0" :key="index">
<view class="lists">
<view class="" style="width: 100rpx;height: 100rpx;">
<u-image class="cover" radius="4" width="100rpx" height="100rpx" :src="item.portraitUrl || require('@/static/user/cover.png')" :lazy-load="true" />
<u-avatar :src="JSON.parse(item.latestMessage.extra).portraitUrl" shape="square" size="44" />
</view>
<view class="right">
<view class="title">
<view class="name">{{ item.name }}</view>
<view class="des" v-if="isApply">{{ item.address || '这家伙很懒什么都没有添加~' }}</view>
<view class="des" v-else>{{ item.remark || '你好,听说你很优秀想认识~' }}</view>
<view class="des">{{ item.latestMessage.message }}</view>
</view>
<view class="agress-btn">
<span v-if="isAgree" @click="action('agree', item)">通过</span>
@@ -44,8 +43,8 @@ export default {
default: false
}
},
data() {
return {};
created() {
console.log(this.lists);
},
methods: {
action(type, item) {

View File

@@ -0,0 +1,93 @@
<template>
<view class="message--cell">
<view class="avatar">
<u-badge max="99" shape="horn" absolute :offset="[-5, -8]" :value="item.unreadMessageCount" />
<u-avatar :src="contact(item.targetId).portraitUrl" shape="square" size="44" />
</view>
<view class="content">
<view class="header">
<view class="name">{{ contact(item.targetId).name }} <text v-if="item.conversationType === 3"
class='qun'>[]</text></view>
<view class="time">{{ item.sentTime|timeCustomCN }}</view>
</view>
<message-preview class="preview" :msg="item.latestMessage" :conversationType="item.conversationType"
:user="item.latestMessage.userInfo" />
</view>
</view>
</template>
<script>
import messagePreview from './messagePreview'
export default {
props: {
item: {
type: Object,
default: function() {
return {}
}
}
},
computed: {
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
}
},
components: {
messagePreview
}
}
</script>
<style lang="scss" scoped>
.message--cell {
display: flex;
padding: 20rpx 0 0 20rpx;
.avatar {
position: relative;
.u-badge {
z-index: 998;
}
}
.content {
margin-left: 30rpx;
box-sizing: border-box;
position: relative;
flex: 1;
border-bottom-width: 0.5px !important;
border-color: $u-border-color !important;
border-bottom-style: solid;
.header {
display: flex;
justify-content: space-between;
.name {
font-size: $title-size + 2;
color: #454545;
display: flex;
align-items: center;
.qun {
color: $main-color;
font-size: $title-size-m;
margin-left: 4px;
}
}
.time {
font-size: $title-size-sm;
color: $text-gray-m;
position: absolute;
right: 30rpx;
}
}
}
}
</style>

View File

@@ -1,28 +1,28 @@
<template>
<view>
<view v-if="msg.objectName=='RC:TxtMsg'">
{{ msg.content || '' }}
<view class="preview" v-if="msg.objectName=='RC:TxtMsg'">
<text v-if="conversationType == 3">{{ user.name }}: </text>{{ msg.content || '' }}
</view>
<view v-if="msg.objectName=='RC:HQVCMsg'">
[语音]
<view class="preview" v-if="msg.objectName=='RC:HQVCMsg'">
<text v-if="conversationType == 3">{{ user.name }}: </text>[语音]
</view>
<view v-if="msg.objectName=='RC:ImgMsg'">
[图片]
<view class="preview" v-if="msg.objectName=='RC:ImgMsg'">
<text v-if="conversationType == 3">{{ user.name }}: </text>[图片]
</view>
<view v-if="msg.objectName=='RC:GIFMsg'">
[表情]
<view class="preview" v-if="msg.objectName=='RC:GIFMsg'">
<text v-if="conversationType == 3">{{ user.name }}: </text>[表情]
</view>
<view v-if="msg.objectName=='RC:FileMsg'">
[文件]
<view class="preview" v-if="msg.objectName=='RC:FileMsg'">
<text v-if="conversationType == 3">{{ user.name }}: </text>[文件]
</view>
<view v-if="msg.objectName=='RC:LBSMsg'">
[位置]
<view class="preview" v-if="msg.objectName=='RC:LBSMsg'">
<text v-if="conversationType == 3">{{ user.name }}: </text>[位置]
</view>
<view v-if="msg.objectName=='RC:AudioMsg'">
[语音通话]
<view class="preview" v-if="msg.objectName=='RC:AudioMsg'">
<text v-if="conversationType == 3">{{ user.name }}: </text>[语音通话]
</view>
<view v-if="msg.objectName=='RC:VideoMsg'">
[视频通话]
<view class="preview" v-if="msg.objectName=='RC:VideoMsg'">
<text v-if="conversationType == 3">{{ user.name }}: </text>[视频通话]
</view>
</view>
</template>
@@ -33,11 +33,33 @@
msg: {
type: Object,
default: {}
},
conversationType: {
type: Number,
default: 0
},
user: {
type: Object,
default: function() {
return {
name: ''
}
}
}
}
}
</script>
<style>
<style lang="scss" scoped>
.preview {
word-break: break-all;
color: $text-gray-m;
padding-top: $padding - 20;
padding-bottom: $padding;
font-size: $title-size-m;
height: 32rpx;
line-height: 32rpx;
width: 520rpx;
@extend .nowrap;
}
</style>

View File

@@ -0,0 +1,83 @@
<template>
<view class="">
<!-- footer -->
<view class="footer">
<view class="msg-type" @click="changeMessageType">
<image class="icon" src="@/static/icon/key-icon.png" v-if="chatType === 0" mode="widthFix">
</image>
<image class="icon" src="@/static/icon/msg-icon.png" v-if="chatType === 1" mode="widthFix">
</image>
</view>
<sent-voice v-if="chatType === 0" :conversationType="conversationType" :targetId="targetId"
@success="onSuccess" />
<sent-text v-if="chatType === 1" :conversationType="conversationType" :targetId="targetId"
@success="onSuccess" />
<view class="msg-type msg-popups" @click="showPopups = !showPopups">
<image class="icon" src="@/static/icon/popups-icon.png"></image>
</view>
</view>
<!-- 弹出层 -->
<sent-popups :show="showPopups" :conversationType="conversationType" :targetId="targetId"
@success="() => {showPopups = false, onSuccess()}"></sent-popups>
</view>
</template>
<script>
import sentText from '../components/sentText'
import sentVoice from '../components/sentVoice'
import sentPopups from '../components/sentPopups'
export default {
props: {
conversationType: {
type: Number,
default: 0
},
targetId: {
type: String,
default: ''
}
},
components: {
sentText,
sentVoice,
sentPopups
},
data() {
return {
chatType: 1, // 0 语音1 文本
showPopups: false
}
},
methods: {
// 切换聊天类型,语音/文本
changeMessageType() {
this.chatType = this.chatType === 1 ? 0 : 1
},
onSuccess() {
this.$emit('onSuccess')
}
}
}
</script>
<style lang="scss" scoped>
.footer {
background: white;
padding: 20rpx 30rpx;
display: flex;
justify-content: space-between;
flex-direction: row;
.msg-type {
width: 70rpx;
height: 70rpx;
.icon {
margin: 5rpx;
width: 60rpx;
height: 60rpx;
}
}
}
</style>

View File

@@ -63,6 +63,11 @@
default: ''
}
},
computed: {
user() {
return this.$store.getters.sender
}
},
methods: {
singleCall(e) {
uni.showToast({
@@ -81,10 +86,11 @@
count: 9,
sourceType: ['album'],
success: res => {
im.sentImage(this.conversationType, this.targetId, res.tempFilePaths[0], (
res) => {
this.success()
})
im.sentImage(this.conversationType, this.targetId, res.tempFilePaths[0],
this.user, (
res) => {
this.success()
})
}
})
break;
@@ -92,10 +98,11 @@
uni.chooseImage({
sourceType: ['camera'],
success: res => {
im.sentImage(this.conversationType, this.targetId, res.tempFilePaths[0], (
res) => {
this.success()
})
im.sentImage(this.conversationType, this.targetId, res.tempFilePaths[0],
this.user, (
res) => {
this.success()
})
}
})
break;

View File

@@ -1,15 +1,7 @@
<template>
<view class="sent--text">
<input
class="input"
type="text"
@focus="focus"
@blur="blur"
v-model="inputTxt"
confirm-type="send"
@confirm="sent"
cursor-spacing="10"
/>
<input class="input" type="text" @focus="focus" @blur="blur" v-model="inputTxt" confirm-type="send"
@confirm="sent" cursor-spacing="10" />
<!-- <button class="button" size="mini" :disabled="disabled" @click="sent">发送</button> -->
</view>
</template>
@@ -36,6 +28,9 @@
computed: {
disabled() {
return this.inputTxt.length === 0
},
user() {
return this.$store.getters.sender
}
},
created() {
@@ -55,7 +50,7 @@
sent() {
if (!this.disabled) {
RongIMLib.clearTextMessageDraft(this.conversationType, this.targetId)
im.sentText(this.conversationType, this.targetId, this.inputTxt, () => {
im.sentText(this.conversationType, this.targetId, this.inputTxt, this.user, () => {
this.$emit('success')
this.inputTxt = ''
})
@@ -65,13 +60,13 @@
this.$emit('focus')
},
blur() {
this.$emit('blur')
this.$emit('blur')
}
}
}
</script>
<style scoped lang="less">
<style scoped lang="scss">
.sent--text {
display: flex;
flex-direction: row;
@@ -85,20 +80,5 @@
margin-right: 15rpx;
padding: 0 20rpx;
}
.button {
border: none;
background: #34CE98;
color: white;
width: 120rpx;
line-height: 70rpx;
text-align: center;
border-radius: 10rpx;
font-size: 30rpx;
font-weight: bold;
}
// .button[disabled] {
// background-color: #555555;
// }
}
</style>

View File

@@ -35,6 +35,11 @@
recorderManager: null
}
},
computed: {
user() {
return this.$store.getters.sender
}
},
created() {
this.recorderManager = uni.getRecorderManager()
},
@@ -81,7 +86,7 @@
this.recorderManager.onStop(res => {
im.sentVoice(this.conversationType, this.targetId, res.tempFilePath, (this.maxRecordTime -
this
.recordTime), () => {
.recordTime), this.user, () => {
setTimeout(() => {
this.$emit('success')
}, 500)

View File

@@ -1,6 +1,9 @@
<template>
<view class="msg--image" :class="guest ? 'right': 'left'">
<image class="img" :src="msg.thumbnail" @click="previewImage" mode="widthFix"></image>
<view class="">
<text class="name" v-if="!guest && name">{{ name }}</text>
<view class="msg--image" :class="guest ? 'right': 'left'">
<image class="img" :src="msg.thumbnail" @click="previewImage" mode="widthFix"></image>
</view>
</view>
</template>
@@ -23,6 +26,10 @@
guest: {
type: Boolean,
default: true
},
name: {
type: String,
default: ''
}
},
methods: {
@@ -39,17 +46,24 @@
</script>
<style scoped lang="scss">
.name {
font-size: 24rpx;
line-height: 34rpx;
color: $text-gray-m;
padding-bottom: 10rpx;
}
.msg--image {
padding: 20rpx;
// padding: 20rpx;
&.left {
border-radius: 0 20rpx 20rpx 20rpx;
background: white;
// background: white;
}
&.right {
border-radius: 20rpx 0 20rpx 20rpx;
background: #34CE98;
// background: #34CE98;
}
.img {

View File

@@ -1,5 +1,6 @@
<template>
<view class="msg--text">
<text class="name" v-if="!guest && name">{{ name }}</text>
<text class="im--text" :class="guest ? 'right': 'left'">{{ msg.content }}</text>
</view>
</template>
@@ -12,6 +13,10 @@
type: Object,
default: {}
},
name: {
type: String,
default: ''
},
guest: {
type: Boolean,
default: true
@@ -21,21 +26,30 @@
</script>
<style scoped lang="scss">
.im--text {
max-width: 400rpx;
padding: 20rpx;
font-size: 28rpx;
line-height: 40rpx;
&.left {
border-radius: 0 20rpx 20rpx 20rpx;
background: white;
.msg--text {
.name {
font-size: 26rpx;
padding-bottom: 10rpx;
color: $text-gray-m;
}
&.right {
border-radius: 20rpx 0 20rpx 20rpx;
background: $main-color;
color: white;
.im--text {
max-width: 508rpx;
padding: 20rpx;
line-height: 46rpx;
font-size: 32rpx;
color: $text-color;
&.left {
border-radius: 0 20rpx 20rpx 20rpx;
background: white;
}
&.right {
border-radius: 20rpx 0 20rpx 20rpx;
background: $main-color;
color: white;
}
}
}
</style>

View File

@@ -1,8 +1,11 @@
<template>
<view class="msg--voice" :class="guest ? 'right': 'left'" @click="onPlayMsg">
<image v-if="!guest" class="icon" src="@/static/icon/audio_green.png" mode="widthFix"></image>
<text class="duration">{{msg.duration}}"</text>
<image v-if="guest" class="icon" src="@/static/icon/audio_white.png" mode="widthFix"></image>
<view class="">
<text class="name" v-if="!guest && name">{{ name }}</text>
<view class="msg--voice" :class="guest ? 'right': 'left'" @click="onPlayMsg">
<image v-if="!guest" class="icon" src="@/static/icon/audio_green.png" mode="widthFix"></image>
<text class="duration">{{msg.duration}}"</text>
<image v-if="guest" class="icon" src="@/static/icon/audio_white.png" mode="widthFix"></image>
</view>
</view>
</template>
@@ -21,6 +24,10 @@
}
}
},
name: {
type: String,
default: ''
},
guest: {
type: Boolean,
default: true
@@ -56,6 +63,12 @@
</script>
<style scoped lang="scss">
.name {
font-size: 24rpx;
line-height: 34rpx;
color: $text-gray-m;
}
.msg--voice {
flex-direction: row;
justify-content: space-between;

View File

@@ -1,47 +1,32 @@
<template>
<view>
<u-index-list :index-list="indexs" inactiveColor="#666" activeColor="#34CE98">
<view>
<view class="friend-flex u-border-bottom" @click="toPending">
<u-avatar class="cover" size="40" shape="square" :src="require('@/static/im/im_01.png')"></u-avatar>
<view class="name">
新的朋友 ({{ pendingCount }})
</view>
</view>
<view class="friend-flex" @click="showToast">
<u-avatar class="cover" size="40" shape="square" :src="require('@/static/im/im_00.png')"></u-avatar>
<view class="name">我的群聊</view>
</view>
<view class="friend-flex u-border-bottom" @click="toPending">
<u-avatar class="cover" size="40" shape="square" :src="require('@/static/im/im_01.png')"></u-avatar>
<u-badge max="99" absolute :offset="[23, 20]" :value="pendingCount" />
<view class="info">新的朋友</view>
</view>
<view class="friend-flex" @click="toGroup">
<u-avatar class="cover" size="40" shape="square" :src="require('@/static/im/im_00.png')"></u-avatar>
<view class="info">我的群聊</view>
</view>
<block v-if="friends.length > 0">
<template v-for="(item, friend) in friends">
<!-- #ifdef APP-NVUE -->
<u-index-anchor :text="indexs[friend]" bgColor="#F3F6FB" height="20" size="12" color="#666">
<u-index-item v-for="(item, fkey) in friends" :key="fkey">
<u-index-anchor :text="indexs[fkey]" bgColor="#F3F6FB" height="20" size="12" color="#666">
</u-index-anchor>
<!-- #endif -->
<u-index-item>
<!-- #ifndef APP-NVUE -->
<u-index-anchor :text="indexs[friend]" bgColor="#F3F6FB" height="20" size="12" color="#666">
</u-index-anchor>
<!-- #endif -->
<view v-for="(friendItem, index) in item" :key="friendItem.userId"
class="friend-flex u-border-bottom"
@click="$Router.push({ name: 'imFriendsInfo', params: { targetId: friendItem.userId } })">
<block v-if="friendItem.portraitUrl != ''">
<u-avatar class="cover" size="40" shape="square" :src="friendItem.portraitUrl || ''"
:default-url="require('@/static/user/cover.png')"></u-avatar>
</block>
<block v-else>
<u-avatar class="cover" size="40" shape="square"
:src="require('@/static/user/cover.png')"></u-avatar>
</block>
<view class="name">{{ friendItem.name }}</view>
<view v-for="(friendItem, index) in item" :key="index" class="friend-flex u-border-bottom"
@click="toFriend(friendItem.targetId)">
<u-avatar size="40" shape="square" :src="contact(friendItem.targetId).portraitUrl" />
<view class="info">
<view class="name">{{ contact(friendItem.targetId).name }}</view>
<view class="address">{{ friendItem.address }}</view>
</view>
</u-index-item>
</template>
</view>
</u-index-item>
</block>
<block v-else>
<u-empty class="pages-null" mode="data" icon="http://cdn.uviewui.com/uview/empty/data.png" text="暂无好友">
<u-empty class="pages-null" mode="data" text="暂无好友">
</u-empty>
</block>
</u-index-list>
@@ -50,9 +35,9 @@
<script>
import {
getFriends,
getPendingCount
getFriendsLetter
} from '@/apis/interfaces/im';
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
export default {
data() {
@@ -62,22 +47,53 @@
pendingCount: 0
};
},
onShow() {
getFriends().then(res => {
this.indexs = res.indexList
this.friends = res.itemArr
})
getPendingCount().then(res => {
console.log(res);
this.pendingCount = res
computed: {
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
}
},
onLoad() {
this.getFriendList()
this.checkNewFriendPending()
uni.$on('onContactNotification', () => {
this.checkNewFriendPending()
this.getFriendList()
})
},
onUnload() {
uni.$off('onContactNotification')
},
methods: {
showToast() {
uni.showToast({
title: '群聊功能暂未开放,敬请期待',
icon: 'none'
});
getFriendList() {
getFriendsLetter().then(res => {
this.indexs = res.indexList
this.friends = res.itemArr
})
},
checkNewFriendPending() {
// 获取是否有新的好友申请
RongIMLib.getConversationList([RongIMLib.ConversationType.SYSTEM], 1000, 0, (res) => {
if (res.code === 0) {
this.pendingCount = res.conversations.filter((item) => {
return item.objectName == RongIMLib.ObjectName.ContactNotification
}).length
}
})
},
toGroup() {
uni.navigateTo({
url: '/pages/im/group/index',
fail(err) {
console.log(err);
}
})
},
toFriend(targetId) {
uni.navigateTo({
url: '/pages/im/friends/info?targetId=' + targetId
})
},
// 新朋友
toPending() {
@@ -108,14 +124,21 @@
flex-direction: row;
align-items: center;
// .cover
.name {
.info {
flex: 1;
padding-left: $padding;
font-size: $title-size + 2;
font-size: $title-size + 2;
color: #454545 !important;
@extend .nowrap;
margin-left: $padding;
.name {
font-size: $title-size + 2;
font-size: $title-size + 2;
color: #454545 !important;
@extend .nowrap;
}
.address {
color: $text-gray-m;
font-size: $title-size-m - 5;
}
}
}
</style>

View File

@@ -2,10 +2,11 @@
<view class="content">
<!-- 用户信息 -->
<view class="info-flex">
<u-avatar :src="userInfo.portraitUrl || require('@/static/user/cover.png')" shape="square" size="50" bg-color="#fff"></u-avatar>
<u-avatar :src="userInfo.portraitUrl || require('@/static/user/cover.png')" shape="square" size="50"
bg-color="#fff"></u-avatar>
<view class="info-text">
<view class="nickname">{{userInfo.name}}</view>
<view class="address" @longpress="copyAddress">地址{{userInfo.address}}</view>
<view class="nickname">{{ userInfo.name }}</view>
<view class="address" @longpress="copyAddress">地址{{ userInfo.address }}</view>
</view>
</view>
<!-- 用户资料 -->
@@ -105,10 +106,11 @@
}
},
onLoad(e) {
console.log(e);
this.targetId = e.targetId
getFriendInfo(e.targetId).then(res => {
this.userInfo = res
// 获取到用户信息之后,去检查一下要不要更新
this.$store.dispatch('updateContact', res)
uni.setNavigationBarTitle({
title: res.name
})
@@ -125,7 +127,7 @@
if (code == 0) {
this.isTop = conversation.isTop
}
});
})
},
methods: {
copyAddress() {
@@ -141,7 +143,7 @@
},
toPrivate() {
uni.redirectTo({
url: '/pages/im/private/chat?conversationType=1&targetId=' + this.targetId
url: '/pages/im/private/chat?targetId=' + this.targetId
});
},
setRemark() {
@@ -157,6 +159,7 @@
success: e => {
if (e.confirm) {
deleteFriend(this.targetId).then(res => {
uni.$emit('onContactNotification')
// 删除聊天记录
RongIMLib.deleteMessages(1, this.targetId);
RongIMLib.removeConversation(1, this.targetId);
@@ -313,14 +316,16 @@
background: white;
margin: $margin;
border-radius: $radius;
.u-border-bottom{
.u-border-bottom {
border-bottom: solid 1rpx #f9f9f9 !important;
}
.item {
line-height: 100rpx;
display: flex;
align-items: center;
padding:10rpx $padding;
padding: 10rpx $padding;
justify-content: space-between;
font-size: $title-size-lg;

View File

@@ -17,13 +17,13 @@
<view class="text" v-if="infoObj.gender === 2"></view>
</view>
<view class="item">
<label>HASH</label>
<view class="text">{{infoObj.hash}}</view>
<label>地址</label>
<view class="text">{{infoObj.address}}</view>
</view>
</view>
<!-- 二维码 -->
<view class="info-code">
<uqrcode class="info-code-src" :size="198" ref="uQRCode" :text="qrContent" />
<uqrcode class="info-code-src" :size="198" :text="qrContent" />
<view class="info-code-text">
<view>ZH-HEALTH扫一扫上面的二维码</view>
<view>添加我的好友</view>
@@ -51,11 +51,10 @@
qrContent: 'ADDFRIEND|'
}
},
onLoad(e) {},
mounted() {
getUserInfo(this.$Route.query.targetId).then(res => {
onLoad(e) {
this.qrContent += e.targetId
getUserInfo(e.targetId).then(res => {
this.infoObj = res
this.qrContent += res.userId
})
},
methods: {

View File

@@ -1,11 +1,3 @@
<!--
* @Description:新朋友即新增好友申请列表 可以搜索跳转
* @Author: Aimee·Zhang
* @Date: 2022-01-24 10:49:15
* @LastEditors: Aimee·Zhang
* @LastEditTime: 2022-01-25 10:18:26
-->
<template>
<view class="pending">
<u-sticky>
@@ -14,66 +6,36 @@
:disabled="true" :show-action="false" />
</view>
</u-sticky>
<block v-if="pedings.length > 0">
<applyFriend :lists="pedings" :isAgree="true" :isReject="false" @action="action" />
</block>
<view class="no-lists" v-else>
<u-image class="cover" radius="4" width="400rpx" height="400rpx"
:src="require('@/static/imgs/no-friend.png')" :lazy-load="true" />
<span>暂无申请记录~</span>
<view v-for="(item, index) in pendings" :key="index">
<apply-cell :message="item.latestMessage" @success="getPendingList" />
</view>
</view>
</template>
<script>
import {
getPedings,
resolveFriend,
rejectFriend
} from '@/apis/interfaces/im.js'
import * as RongIMLib from "@/uni_modules/RongCloud-IMWrapper/js_sdk/index"
import applyFriend from '@/components/friend-apply-reject-agree'
import applyCell from '../components/friendApplyCell'
import im from '@/utils/im/index.js'
export default {
components: {
applyFriend
applyCell
},
data() {
return {
pedings: []
pendings: []
}
},
onLoad() {
this.getPeddingList()
this.getPendingList()
uni.$on('onContactNotification', this.getPendingList)
},
onUnload() {
uni.$off('onContactNotification')
},
methods: {
// 操作同意或拒绝
action(e) {
let url = e.type === 'agree' ? resolveFriend : rejectFriend
uni.showModal({
title: e.type === 'agree' ? '通过' : '拒绝',
content: e.type === 'agree' ? '通过后即可与该用户畅所欲言' : '拒绝后将不会收到该用户发来信息',
success: res => {
if (res.confirm) {
url(e.item.userId).then(res => {
this.getPeddingList()
})
}
}
})
},
getPeddingList() {
// 获取系统中的好友关系会话列表
// RongIMLib.getConversationList([RongIMLib.ConversationType.SYSTEM], 50, 0, (res) => {
// if (res.code === 0) {
// this.pedings = res.conversations.filter((item) => {
// return item.objectName == RongIMLib.ObjectName.ContactNotification
// })
// }
// })
getPedings().then(res => {
console.log(res)
this.pedings = res
getPendingList() {
im.getPendingList((pendings) => {
this.pendings = pendings
})
}
}

View File

@@ -12,7 +12,7 @@
<u-sticky>
<view class="header-search">
<u-search placeholder="输入用户账号、手机号" height="74" searchIcon="search" @custom="search"
v-model="searchValue" @search="search" inputAlign="center" bgColor="#f9f9f9" :focus="focused" />
v-model="searchValue" @search="search" bgColor="#f9f9f9" :focus="focused" />
</view>
</u-sticky>
<block v-if="searchResult.length > 0">
@@ -31,7 +31,7 @@
searchFriend,
pedingFriend
} from '@/apis/interfaces/im.js';
import applyFriend from '@/components/friend-apply-reject-agree';
import applyFriend from '../components/friendApplyList.vue';
export default {
components: {
applyFriend

View File

@@ -0,0 +1,60 @@
<template>
<view class="create">
<u--textarea v-model="content" count height="200" maxlength="200" placeholder="请输入公告内容"></u--textarea>
<u-button type="primary" text="发布" :disabled="disabled" @click="onCreate" color="#34CE98"></u-button>
</view>
</template>
<script>
import {
createGroupAnnouncement
} from '@/apis/interfaces/im.js'
export default {
data() {
return {
targetId: '',
content: ''
}
},
onLoad(e) {
this.targetId = e.targetId
},
computed: {
disabled() {
return this.content.length == 0 || this.content.length > 200
}
},
methods: {
onCreate() {
createGroupAnnouncement(this.targetId, this.content).then(res => {
uni.$emit('groupAnnouncementCreated')
uni.showToast({
title: '发布成功',
success: () => {
setTimeout(() => {
uni.navigateBack()
}, 1000)
}
})
}).catch(err => {
uni.showToast({
icon: 'none',
title: err.message
})
})
}
}
}
</script>
<style lang="scss" scoped>
.create {
padding: $padding;
.u-button {
margin-top: $padding;
}
}
</style>

View File

@@ -0,0 +1,125 @@
<template>
<view class="announce">
<u-skeleton rows="2" :loading="loading" avatar :rows="5">
<view v-for="(item,index) in announcements" :key="index" class="item">
<view class="header">
<u-avatar :src="item.user.portraitUrl"></u-avatar>
<view class="user">
<view class="name">{{ item.user.name }}</view>
<view class="time">{{ item.created_at }}</view>
</view>
<view class="delete" v-if="isAdmin" @click="onDelete(item.announcement_id)">删除</view>
</view>
<view class="content">{{ item.content }}</view>
</view>
</u-skeleton>
</view>
</template>
<script>
import {
getGroupInfo,
getGroupAnnouncements,
deleteGroupAnnouncement
} from '@/apis/interfaces/im.js'
export default {
data() {
return {
targetId: '',
announcements: [],
loading: true,
isAdmin: false
}
},
onLoad(e) {
this.targetId = e.targetId
getGroupInfo(this.targetId).then(res => {
this.isAdmin = res.group.is_admin
})
this.initData()
uni.$on('groupAnnouncementCreated', this.initData)
},
onUnload() {
uni.$off('groupAnnouncementCreated')
},
onNavigationBarButtonTap() {
if (this.isAdmin) {
uni.navigateTo({
url: '/pages/im/group/announceCreate?targetId=' + this.targetId
})
} else {
uni.showToast({
icon: 'none',
title: '没有权限'
})
}
},
methods: {
initData() {
getGroupAnnouncements(this.targetId).then(res => {
this.announcements = res
this.loading = false
})
},
onDelete(aId) {
uni.showModal({
title: '删除公告',
success: (res) => {
if (res.confirm) {
deleteGroupAnnouncement(this.targetId, aId).then(res => {
uni.showToast({
icon: 'none',
title: '删除成功'
})
this.initData()
})
}
}
})
}
}
}
</script>
<style lang="scss" scoped>
.announce {
padding: 0 $padding $padding $padding;
.item {
border-bottom: solid 1rpx #f9f9f9 !important;
padding-top: $padding;
.header {
display: flex;
flex-direction: row;
align-items: center;
.user {
margin-left: $padding;
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
.name {}
.time {
font-size: 24rpx;
color: $text-gray-m;
}
}
.delete {
color: $text-price;
font-size: 28rpx;
}
}
.content {
padding: $padding;
font-size: 34rpx;
}
}
}
</style>

91
pages/im/group/apply.vue Normal file
View File

@@ -0,0 +1,91 @@
<template>
<view class="apply">
<u-avatar :src="group.cover" size="128" shape="square"></u-avatar>
<view class="name">
{{ group.name }}
</view>
<u-button v-if="group.can_join" @click="applyGroup" text="申请加群" :disabled="disabled" color="#34CE98" />
<view class="" v-else>
<view class="" v-if="group.is_full">群已满员</view>
<view class="" v-if="group.deny_apply">禁止申请</view>
<u-button v-if="group.state === 'accepted'" color="#34CE98" text="进入群聊" @click="toGroupChat" />
</view>
<u-modal negativeTop="300" :show="modalShow" title="申请原因" showCancelButton @cancel="onHideModal"
@confirm="onJoinGroup">
<view class="slot-content">
<u--input placeholder="申请原因" border="surround" focus v-model="message"></u--input>
</view>
</u-modal>
</view>
</template>
<script>
import {
joinGroupPre,
joinGroup
} from '@/apis/interfaces/im.js'
export default {
data() {
return {
targetId: '',
group: {},
modalShow: false,
message: '',
disabled: false
}
},
onLoad(e) {
this.targetId = e.targetId
joinGroupPre(this.targetId).then(res => {
console.log(res);
this.group = res
})
},
methods: {
toGroupChat() {
uni.redirectTo({
url: '/pages/im/group/chat?targetId=' + this.targetId
})
},
applyGroup() {
this.modalShow = true
},
onHideModal() {
this.message = ''
this.modalShow = false
},
onJoinGroup() {
joinGroup(this.targetId, this.message).then(res => {
console.log('申请结果', res);
uni.showToast({
icon: 'none',
title: '申请成功'
})
}).catch(err => {
uni.showToast({
icon: 'none',
title: err.message
})
})
this.disabled = true
this.onHideModal()
}
}
}
</script>
<style lang="scss" scoped>
.apply {
display: flex;
flex-direction: column;
align-items: center;
.u-avatar {
width: 200rpx;
height: 200rpx;
}
}
</style>

197
pages/im/group/chat.nvue Normal file
View File

@@ -0,0 +1,197 @@
<template>
<view class="group--chat">
<list class="body" :show-scrollbar="false">
<cell class="cell" v-for="(item, index) in messages" :key="index">
<view class="cell-item" :class="item.messageDirection == 1 ? 'right' : 'left'">
<u-avatar class="avatar" @click="toUser(item)" size="36" shape="square" :src="item.content.userInfo.portraitUrl" />
<view class="msg">
<show-voice v-if="item.objectName === 'RC:HQVCMsg'" :guest="item.messageDirection == 1"
:msg="item.content" :name="item.content.userInfo.name" />
<show-image v-if="item.objectName === 'RC:ImgMsg'" :guest="item.messageDirection == 1"
:msg="item.content" :name="item.content.userInfo.name" />
<show-text v-if="item.objectName === 'RC:TxtMsg'" :guest="item.messageDirection == 1"
:msg="item.content" :name="item.content.userInfo.name" />
</view>
</view>
</cell>
<cell class="cell-footer" ref="chatBottom"></cell>
</list>
<sent-message-bar :conversationType="conversationType" :targetId="targetId" @onSuccess="getMessageList()" />
</view>
</template>
<script>
import {
timeCustomCN
} from '@/utils/filters.js'
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import im from '@/utils/im/index.js'
import showVoice from '../components/showVoice'
import showImage from '../components/showImage'
import showText from '../components/showText'
import sentMessageBar from '../components/sentMessageBar'
const ChatList = uni.requireNativePlugin('dom')
export default {
components: {
showVoice,
showImage,
showText,
sentMessageBar
},
data() {
return {
targetId: '',
conversationType: 3,
messages: [],
groupInfo: {
name: ''
}
}
},
onLoad(e) {
this.targetId = e.targetId
this.groupInfo = this.$store.getters.contactInfo(this.targetId)
uni.setNavigationBarTitle({
title: this.groupInfo.name
})
this.getMessageList()
uni.$on('onReceiveMessage', (msg) => {
if (msg.targetId == this.targetId) {
this.getMessageList()
}
})
uni.$once('cleanGroupMessage', this.getMessageList)
},
onBackPress() {
uni.$off('onReceiveMessage')
console.log('Off onReceiveMessage');
},
onNavigationBarButtonTap() {
uni.navigateTo({
url: '/pages/im/group/info?targetId=' + this.targetId
})
},
methods: {
toUser(item) {
if (item.senderUserId == '__system__') {
return
}
if (item.messageDirection == 1) {
uni.navigateTo({
url: '/pages/im/friends/mine?targetId=' + item.senderUserId
})
} else{
uni.navigateTo({
url: '/pages/im/friends/info?targetId=' + item.senderUserId
})
}
},
// 获取消息列表
getMessageList() {
im.getMessageList(
this.conversationType,
this.targetId,
new Date().getTime(),
20,
true,
(messages) => {
this.messages = messages.reverse()
this.scrollBottom()
})
},
// 滚动到底部
scrollBottom(type) {
// 清理当前会话,未读消息数量
RongIMLib.clearMessagesUnreadStatus(this.conversationType, this.targetId, new Date().getTime() + 1100)
// 发送消息已读状态给对方
RongIMLib.sendReadReceiptMessage(this.conversationType, this.targetId, new Date().getTime())
// 更新badge提醒数量
im.setNotifyBadge()
setTimeout(() => {
let el = this.$refs.chatBottom
ChatList.scrollToElement(el, {
offset: 0,
animated: false
})
}, 50)
}
}
}
</script>
<style lang="scss" scoped>
.group--chat {
background: $window-color;
flex: 1;
.body {
flex: 1;
.cell {
padding: 10rpx 30rpx;
.cell-item {
width: 690rpx;
justify-content: flex-start;
align-items: flex-start;
margin-top: 20rpx;
&.left {
flex-direction: row;
}
&.right {
flex-direction: row-reverse;
.state {
flex-direction: row;
justify-content: flex-end;
}
}
.avatar {
width: 78rpx;
height: 78rpx;
background-color: white;
border-radius: 10rpx;
}
.msg {
margin: 0 20rpx;
.user {
font-size: 18rpx;
line-height: 40rpx;
}
}
}
.cell-footer {
height: 20rpx;
}
}
}
.footer {
background: white;
padding: 20rpx 30rpx;
display: flex;
justify-content: space-between;
flex-direction: row;
.msg-type {
width: 70rpx;
height: 70rpx;
.icon {
margin: 5rpx;
width: 60rpx;
height: 60rpx;
}
}
}
}
</style>

View File

@@ -1,11 +1,109 @@
<template>
<view class="">
<view>
<view v-for="(item, index) in groups" :key="index" class="friend-flex u-border-bottom"
@click="toGroup(item.targetId)">
<u-avatar size="40" shape="square" :src="contact(item.targetId).portraitUrl" />
<view class="info">
<view class="name">{{ item.name }}</view>
</view>
</view>
<u-modal negativeTop="300" :show="createModal" title="创建群聊" showCancelButton @cancel="onHideModal"
@confirm="onCreateGroup">
<view class="slot-content">
<u--input placeholder="群名称" border="surround" focus v-model="groupName"></u--input>
</view>
</u-modal>
</view>
</template>
<script>
import {
getMyGroups,
createGroup
} from '@/apis/interfaces/im.js'
export default {
data() {
return {
groups: [],
createModal: false,
groupName: ''
}
},
computed: {
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
}
},
onNavigationBarButtonTap() {
this.createModal = true
},
onLoad() {
this.initData()
},
methods: {
initData() {
getMyGroups().then((res) => {
this.groups = res
res.map(item => {
this.$store.dispatch('updateContact', item)
})
})
},
onHideModal() {
this.createModal = false
this.groupName = ''
},
onCreateGroup() {
createGroup({
name: this.groupName
}).then(res => {
uni.showToast({
title: '创建成功'
})
this.initData()
this.onHideModal()
}).catch(err => {
uni.showToast({
icon: 'none',
title: err
})
})
},
toGroup(targetId) {
uni.navigateTo({
url: '/pages/im/group/chat?targetId=' + targetId
})
}
}
}
</script>
<style>
<style lang="scss" scoped>
// 好友列表
.friend-flex {
position: relative;
padding: 20rpx $padding;
display: flex;
flex-direction: row;
align-items: center;
.info {
flex: 1;
margin-left: $padding;
.name {
font-size: $title-size + 2;
font-size: $title-size + 2;
color: #454545 !important;
}
.address {
color: $text-gray-m;
font-size: $title-size-m - 5;
}
}
}
</style>

399
pages/im/group/info.vue Normal file
View File

@@ -0,0 +1,399 @@
<template>
<view class="container">
<view class="members u-border-bottom">
<view class="users">
<view class="user" v-for="(item, index) in users" :key="index" @click="toUser(item)">
<u-avatar size="44" shape="square" :src="item.portraitUrl"></u-avatar>
<view class="name">{{ item.name }}</view>
</view>
<view class="user">
<u-avatar @click="inviteUser" size="44" shape="square" icon="plus" bg-color="#eeeeee"
color="#999999"></u-avatar>
<view class="name">邀请好友</view>
</view>
</view>
<view @click="loadMore" v-if="members > users.length" class="loadmore">查看更多群成员 ></view>
</view>
<u-cell-group class="cells">
<u-cell isLink title="群公告" :label="announcement" @click="toAnnouncement"></u-cell>
<u-cell isLink title="二维码" @click="showGroupQrCode"></u-cell>
<u-cell title="聊天置顶">
<u-switch slot="value" size="20" v-model="isTop" activeColor="#34CE98" @change="setTop"></u-switch>
</u-cell>
<u-cell title="免打扰">
<u-switch slot="value" size="20" v-model="status" activeColor="#34CE98" @change="setStatus"></u-switch>
</u-cell>
</u-cell-group>
<u-cell-group class="cells" v-if="group.is_admin">
<u-cell isLink title="修改群聊名称" :value="groupName" @click="onGroupName"></u-cell>
<u-cell isLink title="修改群头像">
<u-avatar slot="value" size="25" shape="square" @click="onGroupAvatar" :src="group.cover"></u-avatar>
</u-cell>
<u-cell isLink v-if="group.is_owner" title="准入方式" :value="joinType" @click="onChangeJoinType"></u-cell>
</u-cell-group>
<view class="cells actions u-border-top" v-if="loaded">
<view class="action u-border-bottom" @click="onClean">清空聊天记录</view>
<view class="action u-border-bottom" v-if="group.is_owner" @click="onDismiss">解散群聊</view>
<view class="action u-border-bottom" v-else @click="onQuite">删除并退出</view>
</view>
<u-modal negativeTop="300" :show="modalShow" title="修改群名称" showCancelButton @cancel="onHideModal"
@confirm="onChangeGroupName">
<view class="slot-content">
<u--input placeholder="群名称" border="surround" focus v-model="groupName"></u--input>
</view>
</u-modal>
<u-modal :show="qrCodeShow" :title="group.name" @confirm="qrCodeShow = false">
<view class="slot-content">
<uqrcode class="info-code-src" :size="198" :text="qrContent" />
</view>
</u-modal>
<u-action-sheet @select="doAction" :actions="joinTypeMap" cancelText="取消" :show="showActions"
@close="showActions=false">
</u-action-sheet>
</view>
</template>
<script>
import {
getGroupInfo,
updateGroup,
quitGroup,
dismissGroup
} from '@/apis/interfaces/im.js'
import {
uploads
} from '@/apis/interfaces/uploading'
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
export default {
data() {
return {
targetId: '',
group: {},
conversationType: 3,
announcement: '',
users: [],
status: false,
isTop: false,
loaded: false,
modalShow: false,
groupName: '',
qrCodeShow: false,
qrContent: 'JOINGROUP|',
joinType: '',
joinTypeMap: [],
showActions: false
}
},
onLoad(e) {
this.targetId = e.targetId
this.qrContent += e.targetId
RongIMLib.getConversationNotificationStatus(this.conversationType, this.targetId, ({
status
}) => {
this.status = !Boolean(status)
})
RongIMLib.getConversation(this.conversationType, this.targetId, ({
code,
conversation
}) => {
if (code == 0) {
this.isTop = conversation.isTop
}
})
this.initData()
uni.$on('groupAnnouncementCreated', this.initData)
},
onUnload() {
uni.$off('groupAnnouncementCreated')
},
methods: {
initData() {
getGroupInfo(this.targetId).then(res => {
this.group = res.group
this.groupName = res.group.name
this.announcement = res.announcement
this.users = res.users
this.members = res.members
this.loaded = true
this.joinTypeMap = res.join_type_map.map(item => {
if (item.key == res.join_type) {
item.disabled = true
}
return item
})
this.joinType = res.join_type_map.filter(item => item.key == res.join_type)[0].name
}).catch(err => {
uni.showToast({
icon: 'none',
title: '群不存在'
})
})
},
setStatus() {
RongIMLib.setConversationNotificationStatus(this.conversationType, this.targetId, this.status,
({
status
}) => {
this.status = !Boolean(status)
})
},
setTop() {
RongIMLib.setConversationToTop(this.conversationType, this.targetId, this.isTop, (res) => {
RongIMLib.getConversation(this.conversationType, this.targetId, ({
conversation
}) => {
this.isTop = conversation.isTop
})
})
},
toUser(item) {
if (item.targetId == this.$store.getters.sender.userId) {
uni.navigateTo({
url: '/pages/im/friends/mine?targetId=' + item.targetId
})
} else {
uni.navigateTo({
url: '/pages/im/friends/info?targetId=' + item.targetId
})
}
},
inviteUser() {
},
loadMore() {
uni.navigateTo({
url: '/pages/im/group/users?targetId=' + this.targetId
})
},
toAnnouncement() {
uni.navigateTo({
url: '/pages/im/group/announcement?targetId=' + this.targetId
})
},
showGroupQrCode() {
this.qrCodeShow = true
},
onGroupName() {
this.modalShow = true
console.log(this.$refs.groupNameRef);
},
onChangeGroupName() {
if (this.groupName != this.group.name) {
updateGroup(this.targetId, {
name: this.groupName
}).then(res => {
this.modalShow = false
uni.showToast({
icon: 'none',
title: '群名称修改成功'
})
})
} else {
uni.showToast({
icon: 'none',
title: '无修改'
})
}
},
onHideModal() {
this.modalShow = false
this.groupName = this.group.name
},
// 修改群头像
onGroupAvatar() {
console.log('onGroupAvatar');
uni.chooseImage({
count: 1,
sourceType: ['album'],
crop: {
quality: 100,
width: 128,
height: 128,
resize: true
},
success: res => {
console.log(res);
let path = res.tempFiles.map((val, index) => {
return {
name: 'uploads' + index,
uri: val.path
}
})
uploads(path).then(path => {
updateGroup(this.targetId, {
cover: path.path[0]
}).then(res => {
uni.showToast({
icon: 'none',
title: '群头像修改成功'
})
this.modalShow = false
this.group.cover = path.url[0]
})
}).catch(err => {
uni.showToast({
title: err.message,
icon: 'none'
})
})
},
fail: (err) => {
console.log(err);
}
})
},
onChangeJoinType() {
this.showActions = true
},
doAction(e) {
updateGroup(this.targetId, {
join_type: e.key
}).then(res => {
uni.showToast({
icon: 'none',
title: '修改成功'
})
this.joinTypeMap = this.joinTypeMap.map(item => {
if (item.key == e.key) {
item.disabled = true
} else {
item.disabled = false
}
return item
})
this.joinType = e.name
this.showActions = false
}).catch(err => {
console.log(err);
uni.showToast({
icon: 'error',
title: err.message
})
})
},
onClean() {
uni.showModal({
title: '清空聊天记录',
content: '清空聊天记录,只会清空本地的记录,其他成员不会变化',
success: (res) => {
if (res.confirm) {
RongIMLib.deleteMessages(3, this.targetId, () => {
uni.showToast({
icon: 'none',
title: '清空成功'
})
uni.$emit('cleanGroupMessage')
})
}
}
})
},
onDismiss() {
uni.showModal({
title: '解散群聊',
success: (res) => {
if (res.confirm) {
dismissGroup(this.targetId).then(res => {
uni.showToast({
icon: 'none',
title: '解散成功'
})
uni.switchTab({
url: '/pages/im/index'
})
})
}
}
})
},
onQuite() {
uni.showModal({
title: '退出群聊',
success: (res) => {
if (res.confirm) {
quitGroup(this.targetId).then(res => {
uni.showToast({
icon: 'none',
title: '退出群聊成功'
})
uni.switchTab({
url: '/pages/im/index'
})
})
}
}
})
}
}
}
</script>
<style lang="scss" scoped>
.container {
min-height: 100vh;
background: $window-color;
}
.cells {
margin-top: $padding;
background-color: white;
}
.members {
background-color: white;
padding-bottom: 40rpx;
.users {
flex-direction: row;
flex-wrap: wrap;
display: flex;
padding: 20rpx 0;
.user {
width: 126rpx;
margin-left: 20rpx;
margin-bottom: 20rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.name {
color: $text-gray-m;
width: 126rpx;
text-align: center;
font-size: 26rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
word-break: break-word;
}
}
}
.loadmore {
font-size: 26rpx;
color: $text-gray-m;
text-align: center;
}
}
.actions {
margin-top: $padding;
text-align: center;
.action {
padding: $padding;
color: $text-price;
justify-content: center;
}
}
</style>

164
pages/im/group/users.vue Normal file
View File

@@ -0,0 +1,164 @@
<template>
<view class="members">
<view class="users">
<view class="user" v-if="isAdmin">
<u-avatar @click="inviteUser" size="44" shape="square" icon="plus" bg-color="#eeeeee" color="#999999">
</u-avatar>
<view class="name">邀请好友</view>
</view>
<view :class="['user', {'active': item.targetId == currentUser.targetId}]" @longpress="showAction(item)"
v-for="(item, index) in members" :key="index" @click="toUser(item)">
<u-avatar size="44" shape="square" :src="item.portraitUrl"></u-avatar>
<view class="name">{{ item.name }}</view>
</view>
</view>
<view class="loadmore">成员总数{{ members.length }}</view>
<u-action-sheet :actions="userActions" :title="actionTitle" cancelText="取消" @close="hideAction"
@select="doAction" :show="actionShow">
</u-action-sheet>
</view>
</template>
<script>
import {
getGroupBase,
getGroupUsers
} from '@/apis/interfaces/im.js'
export default {
data() {
return {
targetId: '',
members: [],
isOwner: false,
isAdmin: false,
actionShow: false,
userActions: [{
type: 0,
name: '设置管理员',
disabled: false
},
{
type: 1,
name: '解除管理员',
disabled: false
},
{
type: 2,
name: '移除成员',
disabled: false
}
],
actionTitle: '',
currentUser: {}
}
},
onLoad(e) {
this.targetId = e.targetId
getGroupBase(this.targetId).then(res => {
this.isOwner = res.is_owner
this.isAdmin = res.is_admin
if (this.isOwner) {
this.userActions.push({
type: 3,
name: '转移群主',
disabled: false
})
}
})
this.getUserList()
},
methods: {
getUserList() {
getGroupUsers(this.targetId).then(res => {
this.members = res
})
},
toUser(item) {
uni.navigateTo({
url: '/pages/im/friends/info?targetId=' + item.targetId
})
},
showAction(item) {
this.currentUser = item
this.actionTitle = item.name
this.actionShow = true
// 根据当前用户,是不是管理,来控制按钮的可用性
this.userActions[0].disabled = true
},
hideAction(item) {
this.actionShow = false
this.actionTitle = ''
this.currentUser = {}
this.userActions[0].disabled = false
this.userActions[1].disabled = false
},
doAction(e) {
switch (e.type) {
case 0:
// 设置管理
break;
case 1:
// 取消管理
break;
case 2:
// 移除成员
break;
case 3:
// 转移管理员
break;
}
this.getUserList()
},
inviteUser() {
}
}
}
</script>
<style lang="scss" scoped>
.members {
background-color: white;
padding-bottom: 40rpx;
.users {
flex-direction: row;
flex-wrap: wrap;
display: flex;
padding: 20rpx 0;
.user {
width: 126rpx;
margin-left: 20rpx;
margin-bottom: 20rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
&.active {
background-color: $window-color;
}
.name {
color: $text-gray-m;
width: 126rpx;
text-align: center;
font-size: 26rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
word-break: break-word;
}
}
}
.loadmore {
font-size: 26rpx;
color: $text-gray-m;
text-align: center;
}
}
</style>

View File

@@ -5,60 +5,23 @@
<view class="custom-header">
<view class="header-flex">
<view class="tabs">
<view class="item show">
<u-badge max="99" value="99" absolute :offset="[0, -10]"/>私聊
</view>
<view class="item" @click="onNav('', {})">
<u-badge max="99" value="99" absolute :offset="[0, -10]"/>群聊
</view>
<view class="item active">聊聊</view>
</view>
<view class="btns">
<view class="item" @click="scanQrCode">
<uni-icons color="#555" type="scan" size="22"></uni-icons>
<uni-icons color="#555" type="scan" size="22" />
</view>
<view class="item" @click="onNav('imFriends', {})">
<uni-icons color="#555" custom-prefix="iconfont" type="icon-tuandui" size="22"></uni-icons>
<view class="item" @click="toFriendList">
<u-badge absolute max="99" :offset="[-5, -5]" :value="hasNewFriends" />
<uni-icons color="#555" custom-prefix="iconfont" type="icon-tuandui" size="22" />
</view>
<!-- <view class="item" @click="onNav('', {})">
<uni-icons color="#555" custom-prefix="iconfont" type="icon-gengduo2" size="22"></uni-icons>
</view> -->
</view>
</view>
</view>
<u-alert type="warning" v-if="connection != 0" description="网络似乎断开了,请检查网络" :show-icon="true" />
<!-- content -->
<view v-if="$store.state.token != ''">
<block v-if="conversations.length < 1">
<view class="vertical null-list">
<u-empty mode="message" textColor="#999" text="暂无好友消息" />
</view>
</block>
<block v-else>
<u-alert type="warning" v-if="connection != 0" description="网络似乎断开了,请检查网络" :show-icon="true" />
<view v-for="(item, index) in conversations" :key="index" :class="['message', { 'is-top': item.isTop }]"
@click="toDetail(item)" @longpress="onLongPress" :data-item="item">
<view class="avatar" @click="toFriend(item.targetId)">
<u-badge numberType="ellipsis" max="99" shape="horn" absolute :offset="[-5, -5]"
:value="item.unreadMessageCount" />
<u-avatar :src="friend(item.targetId).portraitUrl || require('@/static/user/cover.png')"
shape="square" size="44" />
</view>
<view class="content u-border-bottom">
<view class="header">
<view class="name">{{ friend(item.targetId).name || '未知用户' }}</view>
<view class="time">{{ item.sentTime|timeCustomCN }}</view>
</view>
<message-preview class="preview" :msg="item.latestMessage" />
</view>
</view>
<!-- TODO 长按的弹出框怎么点击隐藏没搞明白 -->
<view class="shade" @click="hidePop" v-show="showPop">
<view class="pop" :style="popStyle" :class="{'show':showPop}">
<view v-for="(item, index) in popButton" :key="index" @click="pickerMenu" :data-index="index">
{{item}}
</view>
</view>
</view>
</block>
<view v-if="$store.state.token !== ''">
<conversation-list @refresh="getConversationList()" :conversations="conversations" />
</view>
<!-- 未登录 -->
<view v-else class="vertical null-list">
@@ -72,119 +35,46 @@
</template>
<script>
import * as RongIMLib from "@/uni_modules/RongCloud-IMWrapper/js_sdk/index"
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import im from '@/utils/im/index.js'
import userAuth from '@/public/userAuth'
import messagePreview from './components/messagePreview'
import {
getImToken
} from '@/apis/interfaces/im.js'
import conversationList from './components/conversationList'
export default {
data() {
return {
isShown: true, // 当前页面显示状态
conversations: [], // 会话列表
connection: 0,
/* 窗口尺寸 */
winSize: {},
/* 显示操作弹窗 */
showPop: false,
/* 弹窗按钮列表 */
popButton: ['置顶聊天', '删除该聊天'],
/* 弹窗定位样式 */
popStyle: "",
pickedItem: {}
hasNewFriends: 0
}
},
components: {
messagePreview
},
computed: {
friend() {
return function(targetId) {
return this.$store.getters.userInfo(targetId)
}
}
conversationList
},
onLoad() {
// 好友申请数量
this.checkNewFriendPending()
uni.$on('onConnectionStatusChange', (status) => {
this.connection = status
})
uni.$on('onContactNotification', this.checkNewFriendPending)
},
onShow() {
if (this.$store.state.token !== '') {
this.getConversationList()
}
// 监听新消息
uni.$on('onReceiveMessage', (msg) => {
console.log('收到消息,刷新列表');
this.getConversationList()
})
this.isShown = true
},
onHide() {
uni.$off('onReceiveMessage')
this.isShown = false
},
onNavigationBarButtonTap(e) {
if (e.index == 0) {
uni.showToast({
title: '开发中暂未开放,敬请期待',
icon: 'none'
})
}
if (e.index == 1) {
if (this.toLogin()) {
this.$Router.push({
name: 'imFriends'
})
}
}
},
methods: {
// 隐藏功能菜单
hidePop() {
this.showPop = false
this.pickedItem = {}
setTimeout(() => {
this.showShade = false
}, 250)
},
// 点击会话功能菜单
pickerMenu(e) {
const index = Number(e.currentTarget.dataset.index)
if (index == 0) {
RongIMLib.setConversationToTop(this.pickedItem.conversationType, this.pickedItem.targetId, !this
.pickedItem.isTop)
} else {
RongIMLib.removeConversation(this.pickedItem.conversationType, this.pickedItem.targetId)
}
im.setNotifyBadge()
this.getConversationList()
this.hidePop()
},
// 长按会话,展示功能菜单
onLongPress(e) {
let [touches, style, item] = [e.touches[0], "", e.currentTarget.dataset.item]
if (touches.clientY > (this.winSize.height / 2)) {
style = `bottom:${this.winSize.height-touches.clientY}px;`
} else {
style = `top:${touches.clientY}px;`
}
if (touches.clientX > (this.winSize.witdh / 2)) {
style += `right:${this.winSize.witdh-touches.clientX}px`
} else {
style += `left:${touches.clientX}px`
}
this.popButton[0] = item.isTop ? '取消置顶' : '置顶聊天'
this.popStyle = style
this.pickedItem = item
this.$nextTick(() => {
setTimeout(() => {
this.showPop = true;
}, 10)
checkNewFriendPending() {
im.getPendingList((pendings) => {
this.hasNewFriends = pendings.length
})
},
// 检查登录
@@ -196,108 +86,48 @@
}
return true
},
// 获取私聊的会话列表
getConversationList() {
const count = 1000
const timestamp = 0
RongIMLib.getConversationList([RongIMLib.ConversationType.PRIVATE], count, timestamp, (res) => {
RongIMLib.getConversationList([1, 3], count, timestamp, (res) => {
if (res.code === 0) {
console.log(res.conversations);
this.conversations = res.conversations
}
})
},
// 进入聊天的详情页面,清理未读消息数量
toDetail(item) {
this.hidePop()
uni.navigateTo({
url: '/pages/im/private/chat?targetId=' + item.targetId + '&conversationType=' + item
.conversationType
})
},
toFriend(targetId) {
uni.navigateTo({
url: '/pages/im/friends/info?targetId=' + targetId
})
},
// 点击按钮
onNav(name, params) {
if (this.toLogin) {
if (name === '') {
uni.showToast({
title: '开发中,敬请期待',
icon: 'none'
})
return
}
this.$Router.push({
name,
params
})
}
},
// 调起扫码
scanQrCode() {
uni.scanCode({
success: (res) => {
if (res.scanType == 'QR_CODE') {
res.result.substr(0, 10) == 'ADDFRIEND|'
uni.navigateTo({
url: '/pages/im/friends/info?targetId=' + res.result.substr(10)
})
if (res.result.substr(0, 10) == 'ADDFRIEND|') {
uni.navigateTo({
url: '/pages/im/friends/info?targetId=' + res.result.substr(10)
})
} else if (res.result.substr(0, 10) == 'JOINGROUP|') {
uni.navigateTo({
url: '/pages/im/group/apply?targetId=' + res.result.substr(10)
})
} else {
uni.showToast({
title: '暂不支持的二维码'
})
}
}
}
})
},
toFriendList() {
uni.navigateTo({
url: '/pages/im/friends/index'
})
}
}
}
</script>
<style lang="scss" scoped>
// header
.custom-header {
@extend .ios-top;
background: $window-color;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 9999;
.header-flex {
padding: 20rpx $padding;
display: flex;
justify-content: space-between;
height: 60rpx;
line-height: 60rpx;
.tabs {
.item {
position: relative;
margin-left: $margin;
display: inline-block;
font-size: $title-size-lg;
color: $text-gray;
padding: 0 ($padding - 10);
border-radius: 30rpx;
&:first-child {
margin: 0;
}
&.show {
background: rgba($color: $main-color, $alpha: .1);
color: $main-color;
font-weight: bold;
}
}
}
.btns {
.item {
display: inline-block;
margin-left: $margin;
}
}
}
}
// contents
.contents {
background-color: $window-color;
@@ -305,6 +135,50 @@
padding-top: 90rpx + 20rpx;
box-sizing: border-box;
.custom-header {
@extend .ios-top;
background: $window-color;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 9999;
.header-flex {
padding: 20rpx $padding;
display: flex;
justify-content: space-between;
height: 60rpx;
line-height: 60rpx;
.tabs {
.item {
position: relative;
display: inline-block;
font-size: $title-size-lg;
color: $text-gray;
padding: 0 ($padding - 10);
border-radius: 30rpx;
&.active {
background: rgba($color: $main-color, $alpha: .1);
color: $main-color;
font-weight: bold;
}
}
}
.btns {
.item {
position: relative;
display: inline-block;
margin-left: $margin;
}
}
}
}
.null-list {
height: 100vh;
text-align: center;
@@ -320,105 +194,6 @@
box-sizing: border-box;
}
}
.message {
background: white;
padding: 20rpx 0 0 20rpx;
position: relative;
display: flex;
&.is-top {
background: $window-color;
border-bottom: #e8e8e8;
}
.avatar {
position: relative;
.u-badge {
z-index: 998;
}
}
.content {
margin-left: 30rpx;
width: calc(100% - 46px);
box-sizing: border-box;
position: relative;
.header {
display: flex;
justify-content: space-between;
.name {
font-size: $title-size + 2;
color: #454545;
color: #454545;
}
.time {
font-size: $title-size-sm;
color: $text-gray-m;
position: absolute;
right: 30rpx;
}
}
.preview {
word-break: break-all;
color: $text-gray-m;
padding-top: $padding - 20;
padding-bottom: $padding;
font-size: $title-size-m;
height: 32rpx;
line-height: 32rpx;
width: 500rpx;
@extend .nowrap;
}
}
}
}
/* 遮罩 */
.shade {
position: fixed;
width: 100%;
height: 100%;
.pop {
position: fixed;
z-index: 101;
width: 200rpx;
box-sizing: border-box;
font-size: 28rpx;
text-align: left;
color: #333;
background-color: #fff;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
line-height: 80rpx;
transition: transform 0.15s ease-in-out 0s;
user-select: none;
-webkit-touch-callout: none;
transform: scale(0, 0);
&.show {
transform: scale(1, 1);
}
&>view {
padding: 0 20rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
user-select: none;
-webkit-touch-callout: none;
&:active {
background-color: #f3f3f3;
}
}
}
}
.u-border-bottom {

View File

@@ -7,8 +7,7 @@
<text class="text">{{ customCN(item.sentTime) }}</text>
</view>
<view class="cell-item" :class="item.messageDirection == 1 ? 'right' : 'left'">
<image class="avatar" :src="userInfo.portraitUrl" mode="aspectFill"
@click="showUser(targetId, item.messageDirection)"></image>
<u-avatar class="avatar" size="36" shape="square" @click="showUser(targetId, item.messageDirection)" :src="userInfo.portraitUrl" />
<view class="msg">
<show-voice v-if="item.objectName === 'RC:HQVCMsg'" :guest="item.messageDirection == 1"
:msg="item.content" />
@@ -24,24 +23,7 @@
</cell>
<cell class="cell-footer" ref="chatBottom"></cell>
</list>
<!-- footer -->
<view class="footer">
<view class="msg-type" @click="changeMessageType">
<image class="icon" src="@/static/icon/key-icon.png" v-if="chatType === 0" mode="widthFix">
</image>
<image class="icon" src="@/static/icon/msg-icon.png" v-if="chatType === 1" mode="widthFix">
</image>
</view>
<sent-voice v-if="chatType === 0" :conversationType="conversationType" :targetId="targetId"
@success="getMessageList" />
<sent-text v-if="chatType === 1" :conversationType="conversationType" :targetId="targetId"
@success="getMessageList" />
<view class="msg-type msg-popups" @click="scrollBottom('msgPopups')">
<image class="icon" src="@/static/icon/popups-icon.png"></image>
</view>
</view>
<!-- 弹出层 -->
<sent-popups :show="showPopups" :conversationType="conversationType" :targetId="targetId" @success="() => {showPopups = false, getMessageList()}"></sent-popups>
<sent-message-bar :conversationType="conversationType" :targetId="targetId" @onSuccess="getMessageList()" />
</view>
</template>
@@ -54,9 +36,7 @@
import showVoice from '../components/showVoice'
import showImage from '../components/showImage'
import showText from '../components/showText'
import sentText from '../components/sentText'
import sentVoice from '../components/sentVoice'
import sentPopups from '../components/sentPopups'
import sentMessageBar from '../components/sentMessageBar'
const ChatList = uni.requireNativePlugin('dom')
@@ -70,31 +50,23 @@
name: '',
userId: '',
portraitUrl: ''
},
chatType: 1, // 0 语音1 文本
showPopups: false,
inputFocus: false // 输入框是否获得了焦点
}
}
},
components: {
sentMessageBar,
showVoice,
showImage,
showText,
sentText,
sentVoice,
sentPopups
showText
},
onLoad(e) {
this.targetId = e.targetId
this.conversationType = e.conversationType // 会话类型
this.userInfo = this.$store.getters.userInfo(this.targetId)
// 获取消息列表
this.initMessageList()
this.userInfo = this.$store.getters.contactInfo(this.targetId)
uni.setNavigationBarTitle({
title: this.userInfo.name
})
// 获取消息列表
this.getMessageList()
// 监听消息已读状态
uni.$on('onReadReceiptReceived', (data) => {
if (data.targetId == this.targetId) {
@@ -104,27 +76,17 @@
// 监听收到新消息,判断是否是当前会话,更新会话内容
uni.$on('onReceiveMessage', (msg) => {
if (msg.targetId == this.targetId) {
this.initMessageList()
this.getMessageList()
}
})
},
onBackPress() {
uni.$off('onReceiveMessage')
},
methods: {
initMessageList() {
this.getMessageList()
// 清理当前会话,未读消息数量
RongIMLib.clearMessagesUnreadStatus(this.conversationType, this.targetId, new Date().getTime())
// 发送消息已读状态给对方
RongIMLib.sendReadReceiptMessage(this.conversationType, this.targetId, new Date().getTime())
// 更新badge提醒数量
im.setNotifyBadge()
},
customCN(val) {
return timeCustomCN(val)
},
// 切换聊天类型,语音/文本
changeMessageType() {
this.chatType = this.chatType === 1 ? 0 : 1
},
// 获取消息列表
getMessageList() {
im.getMessageList(
@@ -134,7 +96,6 @@
10,
true,
(messages) => {
console.log('获取到的消息', messages);
this.messages = messages.reverse()
this.scrollBottom()
})
@@ -148,9 +109,12 @@
},
// 滚动到底部
scrollBottom(type) {
if(type === 'msgPopups'){
this.showPopups = !this.showPopups
}
// 清理当前会话,未读消息数量
RongIMLib.clearMessagesUnreadStatus(this.conversationType, this.targetId, new Date().getTime() + 1100)
// 发送消息已读状态给对方
RongIMLib.sendReadReceiptMessage(this.conversationType, this.targetId, new Date().getTime())
// 更新badge提醒数量
im.setNotifyBadge()
setTimeout(() => {
let el = this.$refs.chatBottom
ChatList.scrollToElement(el, {
@@ -168,14 +132,18 @@
.chat {
background: $window-color;
flex: 1;
.body {
flex: 1;
.cell {
padding: 10rpx 30rpx;
.time {
justify-content: center;
align-items: center;
padding-bottom: 20rpx;
.text {
background: #fff;
font-size: 24rpx;
@@ -204,13 +172,6 @@
}
}
.avatar {
width: 78rpx;
height: 78rpx;
background-color: white;
border-radius: 10rpx;
}
.msg {
margin: 0 20rpx;
@@ -230,22 +191,5 @@
}
}
}
.footer {
background: white;
padding: 20rpx 30rpx;
display: flex;
justify-content: space-between;
flex-direction: row;
.msg-type {
width: 70rpx;
height: 70rpx;
.icon {
margin: 5rpx;
width: 60rpx;
height: 60rpx;
}
}
}
}
</style>

View File

@@ -60,11 +60,17 @@ export default {
healthSports(data).then(res => {
this.lists = this.lists.concat(res.data);
this.has_more = res.page.has_more;
});
}).catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
});
},
// 显示弹窗内容
addSport(item) {
console.log(item);
this.selectSports = item;
this.selectSports.duration = 60;
this.addSportsShow = true;
@@ -99,7 +105,6 @@ export default {
//#region 搜索相关方法 start
// 点击搜索左侧按钮
searchCustom(e) {
console.log(e);
this.name = e;
this.reset();
},

View File

@@ -8,186 +8,187 @@
<template>
<view class="add-foods">
<view class="re">
<view>低等热量</view>
<view>中等热量</view>
<view>高等热量</view>
</view>
<view class="re"> <view>低等热量</view> <view>中等热量</view> <view>高等热量</view> </view>
<!-- 搜索页面 -->
<u-search
:show-action="true"
actionText="搜索"
:animation="true"
:clearabled="true"
placeholder="请输入食品名称"
@custom="searchCustom"
@clear="clearSearch"
v-model="name"
/>
<u-search :show-action="true" actionText="搜索" :animation="true" :clearabled="true" placeholder="请输入食品名称"
@custom="searchCustom" @clear="clearSearch" v-model="name" />
<!-- 食品列表 -->
<goodsList
:lists="lists"
type="dian"
@addGoods="addGoods"
/>
<goodsList :lists="lists" type="dian" @addGoods="addGoods" />
<!-- 添加食谱弹窗 -->
<addFoods
v-if="addShow"
:addShow="addShow"
:selectGoods="selectGoods"
:decimals="true"
@confirm="confirmHandle"
@close="closeHandle"
@tabGoodsInfo="tabGoodsInfo"
max="999"
/>
<addFoods v-if="addShow" :addShow="addShow" :selectGoods="selectGoods" :decimals="true" @confirm="confirmHandle"
@close="closeHandle" @tabGoodsInfo="tabGoodsInfo" max="999" />
</view>
</template>
<script>
import goodsList from "@/components/foods";
import addFoods from "@/components/add-goods-template/add-goods-template";
import { healthFoods, addHealthFoods } from "@/apis/interfaces/foods.js";
import moment from "moment";
import goodsList from "@/components/foods";
import addFoods from "@/components/add-goods-template/add-goods-template";
import {
healthFoods,
addHealthFoods
} from "@/apis/interfaces/foods.js";
import moment from "moment";
export default {
components: { goodsList, addFoods },
data() {
return {
addShow: false, // 添加食品显示
selectGoods: [], // 选择新增的食品
editGoodsId: "", // 编辑食物
type: "", // 新增食品时候 1早2午3晚4早加5午加6晚加
lists: [], // 食品列表
page: 1,
has_more: true,
name: "", // 搜索食品名称
date: moment(new Date()).format("YYYY-MM-DD"),
};
},
onShow() {
// 有id就是编辑不需要重新处理type了
if (this.$Route.query.id) {
this.editGoodsId = this.$Route.query.id;
return;
}
//没有id的时候就是新增要处理type
this.type = this.$Route.query.type;
// this.getFoods();
},
onLoad() {
this.getFoods();
},
// 触底加载更多
onReachBottom() {
if (!this.has_more) {
uni.showToast({
title: "没有更多啦~",
icon: "none",
});
} else {
this.page = this.page + 1;
export default {
components: {
goodsList,
addFoods
},
data() {
return {
addShow: false, // 添加食品显示
selectGoods: [], // 选择新增的食品
editGoodsId: "", // 编辑食物
type: "", // 新增食品时候 1早2午3晚4早加5午加6晚加
lists: [], // 食品列表
page: 1,
has_more: true,
name: "", // 搜索食品名称
date: moment(new Date()).format("YYYY-MM-DD"),
};
},
onShow() {
// 有id就是编辑不需要重新处理type了
if (this.$Route.query.id) {
this.editGoodsId = this.$Route.query.id;
return;
}
//没有id的时候就是新增要处理type
this.type = this.$Route.query.type;
this.date = this.$Route.query.date;
},
onLoad() {
this.getFoods();
}
},
methods: {
// 获取食品列表
getFoods() {
let data = {
page: this.page,
name: this.name,
};
healthFoods(data).then((res) => {
console.log(res);
this.lists = this.lists.concat(res.data);
this.has_more = res.page.has_more;
});
},
// 监听点击键盘触发返回值新增食品
confirmHandle(value) {
console.log(value);
// 新添加食物
let data = {
type: this.type,
ser: 1,
weight: value,
food_id: this.selectGoods[0].food_id,
date: this.date,
};
this.addHealthFoods(data);
// 触底加载更多
onReachBottom() {
if (!this.has_more) {
uni.showToast({
title: "没有更多啦~",
icon: "none",
});
} else {
this.page = this.page + 1;
this.getFoods();
}
},
// 添加食物
addHealthFoods(data) {
addHealthFoods(data).then((res) => {
console.log(res);
methods: {
// 获取食品列表
getFoods() {
let data = {
page: this.page,
name: this.name,
};
healthFoods(data).then((res) => {
this.lists = this.lists.concat(res.data);
this.has_more = res.page.has_more;
}).catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
});
},
// 监听点击键盘触发返回值新增食品
confirmHandle(value) {
// 新添加食物
let data = {
type: this.type,
ser: 1,
weight: value,
food_id: this.selectGoods[0].food_id,
date: this.date,
};
this.addHealthFoods(data);
},
// 添加食物
addHealthFoods(data) {
addHealthFoods(data).then((res) => {
this.addShow = false;
this.$Router.back();
}).catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration:2000,
mask:true
})
setTimeout(()=>{
this.$Router.back();
},2000)
});
},
closeHandle() {
//键盘关闭的回调函数
this.addShow = false;
this.$Router.back();
});
},
// 监听子组件的新增方法
addGoods(e) {
this.addShow = true;
this.selectGoods = [e];
},
// 点击搜索左侧按钮
searchCustom(e) {
this.name = e;
this.reset();
},
// 清空数组重新请求数据
reset() {
this.page = 1;
this.has_more = true;
this.lists = [];
this.getFoods();
},
// 点击搜索后面按钮触发事件事件
clearSearch() {
this.name = "";
this.reset();
},
// 跳转到食品详情
tabGoodsInfo(e) {
this.$Router.push({
name: "rankingDetails",
params: e,
});
},
},
closeHandle() {
//键盘关闭的回调函数
this.addShow = false;
},
// 监听子组件的新增方法
addGoods(e) {
this.addShow = true;
this.selectGoods = [e];
},
// 点击搜索左侧按钮
searchCustom(e) {
console.log(e);
this.name = e;
this.reset();
},
// 清空数组重新请求数据
reset() {
this.page = 1;
this.has_more = true;
this.lists = [];
this.getFoods();
},
// 点击搜索后面按钮触发事件事件
clearSearch() {
this.name = "";
this.reset();
},
// 跳转到食品详情
tabGoodsInfo(e) {
this.$Router.push({
name: "rankingDetails",
params: e,
});
},
},
};
};
</script>
<style lang="scss" scoped>
.add-foods {
padding: $padding;
.add-foods {
padding: $padding;
.re {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-around;
box-sizing: border-box;
padding: $padding $padding * 2;
font-size: $title-size-m;
view:before {
width: 20rpx;
height: 20rpx;
border-radius: 50%;
display: inline-block;
margin-right: 10rpx;
content: "";
}
view:nth-child(3):before {
background: #fa624d;
}
view:nth-child(2):before {
background: #fbbf0f;
}
view:nth-child(1):before {
background: #02c7bd;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-around;
box-sizing: border-box;
padding: $padding $padding * 2;
font-size: $title-size-m;
view:before {
width: 20rpx;
height: 20rpx;
border-radius: 50%;
display: inline-block;
margin-right: 10rpx;
content: "";
}
view:nth-child(3):before {
background: #fa624d;
}
view:nth-child(2):before {
background: #fbbf0f;
}
view:nth-child(1):before {
background: #02c7bd;
}
}
}
}
</style>

View File

@@ -7,402 +7,543 @@
-->
<template>
<view class="drink" v-if="loaded">
<!-- 喝水及水杯文字 -->
<view class="drink-content">
<view class="title" v-if="!water.is_complete">
再喝
<span class="num">{{ water.lack.cup }}</span>
<span class="total">{{ water.lack.value }}ml</span>
</view>
<view class="title" v-if="water.is_complete">
已喝
<span class="num">{{ water.total }}ml</span>
<u-image class="is_complete" :src="require('../../static/imgs/target.png')" :lazy-load="true" mode="widthFix" width="140rpx" />
</view>
<!-- 水杯动态图片 -->
<view class="wave-content">
<u-image class="grass" :src="require('../../static/imgs/gress.png')" :lazy-load="true" mode="scaleToFill" width="320rpx" height="520rpx" />
<view class="wave" :style="{ '--ballPercent': -ballPercent + 40 + '%' }"></view>
</view>
<!-- 目标 -->
<view class="water-target">
<view class="target-item" @click="targetShow = true">
今日目标
<u-icon
class="target-icon"
name="arrow-right"
color="#666"
size="14"
:bold="true"
:label="water.target + 'ml'"
labelPos="left"
labelSize="16"
labelColor="#666"
space="6"
/>
</view>
<view class="target-item" @click="waterCShow = true">
水杯容量
<u-icon class="target-icon" name="arrow-right" color="#666" size="14" :bold="true" :label="water.ml + 'ml'" labelPos="left" labelSize="16" labelColor="#666" space="6" />
</view>
</view>
<!-- 目标弹出层 -->
<view>
<u-picker
:show="targetShow"
:columns="tagerts"
title="每天喝水目标"
keyName="label"
confirmColor="#34ce98"
:closeOnClickOverlay="true"
@close="targetShow = false"
@confirm="targetSure('1', $event)"
:defaultIndex="tagertsDefaultIndex"
/>
<u-picker
:show="waterCShow"
:columns="cup_mls"
title="设置水杯容量"
keyName="label"
confirmColor="#34ce98"
:closeOnClickOverlay="true"
@close="waterCShow = false"
@confirm="targetSure('2', $event)"
:defaultIndex="cupDefaultIndex"
/>
</view>
<!-- 加水 -->
<view class="add-water" @click="drinkWater">
<u-image class="grass" :src="require('../../static/imgs/gress2.png')" :lazy-load="true" mode="scaleToFill" width="60rpx" height="80rpx" />
<span>一杯水</span>
<u-icon class="add-icon" name="plus-circle-fill" color="#34ce98" size="24" />
</view>
</view>
<!-- 喝水记录 -->
<view class="--history">
<view class="title">喝水记录</view>
<template v-if="logs.length > 0">
<view class="lists" v-for="item in logs" :key="item.water_log_id" @longpress="delWater(item.water_log_id)">
<view class="lists-water"><u-icon size="30" :name="require('../../static/icon/water-icon.png')" /></view>
<view class="list-item">
<view class="list-item-title">
<span>{{ item.time }}</span>
</view>
{{ item.ml }}ml
</view>
</view>
</template>
<view v-else class="no-drink">今天一杯水还没有喝呢来一杯吧~</view>
</view>
</view>
<view class="drink" v-if="loaded">
<!-- 自定义导航部分 -->
<u-navbar :safeAreaInsetTop="true" :fixed='true' bgColor="#34ce98" :autoBack="true">
<view class="u-nav-slot" slot="left">
<u-icon name="arrow-leftward" :bold="true" size="20" color="#fff" />
</view>
<view class="u-nav-slot u-center" slot="center" @click="dateShow = true,dateLists()">
<u-icon name="play-left-fill" size="14" color="#fff" @click="datePreNext('before')" />
<view class="date">
<u-icon name="calendar" color="#fff" label-color="#fff" width="150" :label="today" label-size="14"
size="20" />
</view>
<u-icon name="play-right-fill" size="14" color="#fff" @click="datePreNext('after')" />
</view>
<view class="u-nav-slot" slot="right">
<u-icon :name="require('@/static/icon/sign-icon.gif')" :bold="true" size="30"
@click="$Router.push({name:'signIndex'})" />
</view>
</u-navbar>
<!-- 喝水及水杯文字 -->
<view class="drink-content">
<view class="title" v-if="!water.is_complete"> 再喝 <span class="num">{{ water.lack.cup }}</span> <span
class="total">{{ water.lack.value }}ml</span> </view>
<view class="title" v-if="water.is_complete">
已喝 <span class="num">{{ water.total }}ml</span>
<u-image class="is_complete" :src="require('../../static/imgs/target.png')" :lazy-load="true"
mode="widthFix" width="140rpx" />
</view>
<!-- 水杯动态图片 -->
<view class="wave-content">
<u-image class="grass" :src="require('../../static/imgs/gress.png')" :lazy-load="true"
mode="scaleToFill" width="320rpx" height="520rpx" />
<view class="wave" :style="{ '--ballPercent': -ballPercent + 40 + '%' }"></view>
</view>
<!-- 目标 -->
<view class="water-target">
<view class="target-item" @click="targetShow = true"> 今日目标
<u-icon class="target-icon" name="arrow-right" color="#666" size="14" :bold="true"
:label="water.target + 'ml'" labelPos="left" labelSize="16" labelColor="#666" space="6" />
</view>
<view class="target-item" @click="waterCShow = true"> 水杯容量
<u-icon class="target-icon" name="arrow-right" color="#666" size="14" :bold="true"
:label="water.ml + 'ml'" labelPos="left" labelSize="16" labelColor="#666" space="6" />
</view>
</view>
<!-- 目标弹出层 -->
<view>
<u-picker :show="targetShow" :columns="tagerts" title="每天喝水目标" keyName="label" confirmColor="#34ce98"
:closeOnClickOverlay="true" @close="targetShow = false" @confirm="targetSure('1', $event)"
:defaultIndex="tagertsDefaultIndex" />
<u-picker :show="waterCShow" :columns="cup_mls" title="设置水杯容量" keyName="label" confirmColor="#34ce98"
:closeOnClickOverlay="true" @close="waterCShow = false" @confirm="targetSure('2', $event)"
:defaultIndex="cupDefaultIndex" />
</view>
<!-- 加水 -->
<view class="add-water" @click="drinkWater">
<u-image class="grass" :src="require('../../static/imgs/gress2.png')" :lazy-load="true"
mode="scaleToFill" width="60rpx" height="80rpx" />
<span>一杯水</span>
<u-icon class="add-icon" name="plus-circle-fill" color="#34ce98" size="24" />
</view>
</view>
<!-- 喝水记录 -->
<view class="--history">
<view class="title">喝水记录</view>
<template v-if="logs.length > 0">
<view class="lists" v-for="item in logs" :key="item.water_log_id"
@longpress="delWater(item.water_log_id)">
<view class="lists-water">
<u-icon size="30" :name="require('../../static/icon/water-icon.png')" />
</view>
<view class="list-item">
<view class="list-item-title"> <span>{{ item.time }}</span> </view> {{ item.ml }}ml
</view>
</view>
</template>
<view v-else class="no-drink">今天一杯水还没有喝呢来一杯吧~</view>
</view>
<!-- 选择日历 -->
<dateTemplate :lists="calendarList" :today="today" :month="month" :dateShow="dateShow" type='drink'
@backDate="backDate" @dateClick="dateClick" @closeDate="closeDate" @datePreNext="datePreNext" />
</view>
</template>
<script>
import { waters, setWaters, drinkWater, delDrinkWater } from '@/apis/interfaces/drink';
import moment from 'moment';
export default {
data() {
return {
ballPercent: 0, // 喝水比例
logs: [], // 水记录
water: {}, // 水基本信息
targetShow: false,
tagerts: [], // 目标列表
tagertsDefaultIndex: ['1'], // 目标默认index
waterCShow: false,
cup_mls: [], // 水杯列表
cupDefaultIndex: ['2'], // 目标默认index
loaded: false
};
},
onShow() {
this.getWaters();
},
methods: {
// 获取喝水页面信息
getWaters() {
waters().then(res => {
this.cup_mls = [res.cup_mls];
this.tagerts = [res.tagerts];
this.water = res.water;
this.logs = res.logs;
this.ballPercent = res.water.lack.ratio;
this.cupDefaultIndex = [res.cup_mls.findIndex(item => item.number === res.water.ml)];
this.tagertsDefaultIndex = [res.tagerts.findIndex(item => item.number === res.water.target)];
this.loaded = true;
});
},
// 确认方法index===1 每日目标 2水杯容量
targetSure(index, e) {
// console.log("触发了targetSure", index, e.value[0]);
// let date = moment(new Date()).format("YYYY--MM--DD");
let params = {};
if (index === '1') {
params = {
type: 'target',
ml: e.value[0].number,
date: moment(new Date()).format('YYYY-MM-DD')
};
} else {
params = {
type: 'ml',
ml: e.value[0].number,
date: moment(new Date()).format('YYYY-MM-DD')
};
}
setWaters(params).then(res => {
this.getWaters();
this.waterCShow = false;
this.targetShow = false;
});
},
// 喝水
drinkWater() {
drinkWater().then(res => {
this.getWaters();
});
},
// 删除和喝水记录
delWater(id) {
uni.showModal({
content: '确认删除么?',
confirmText: '确认删除',
confirmColor: '#34ce98',
cancelText: '再想想',
cancelColor: '#ddd',
success: res => {
if (res.confirm) {
delDrinkWater(id)
.then(res => {
this.getWaters();
})
.catch(err => {
uni.showToast({
title: err.message,
icon: 'none'
});
});
}
}
});
}
}
};
import {
waters,
setWaters,
drinkWater,
delDrinkWater,
dateList
} from '@/apis/interfaces/drink';
import moment from 'moment';
import dateTemplate from '@/components/date-template/index.vue'
export default {
components: {
dateTemplate
},
data() {
return {
ballPercent: 0, // 喝水比例
logs: [], // 水记录
water: {}, // 水基本信息
targetShow: false,
tagerts: [], // 目标列表
tagertsDefaultIndex: ['1'], // 目标默认index
waterCShow: false,
cup_mls: [], // 水杯列表
cupDefaultIndex: ['2'], // 目标默认index
loaded: false,
today: moment(new Date()).format('YYYY-MM-DD'), // 当前时间
month: moment(new Date()).format('YYYY-MM'), //当前月份
dateShow: false, // 日历展示
calendarList: [],
dateType: '', // before after ''
};
},
onShow() {
this.getWaters();
this.dateLists();
},
methods: {
// 获取喝水页面信息
getWaters() {
let data = {
date: this.today,
// type:this.dateType
}
waters(data).then(res => {
this.cup_mls = [res.cup_mls];
this.tagerts = [res.tagerts];
this.water = res.water;
this.logs = res.logs;
this.ballPercent = res.water.lack.ratio;
this.cupDefaultIndex = [res.cup_mls.findIndex(item => item.number === res.water.ml)];
this.tagertsDefaultIndex = [res.tagerts.findIndex(item => item.number === res.water
.target)];
this.loaded = true;
}).catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
});
},
// 确认方法index===1 每日目标 2水杯容量
targetSure(index, e) {
let params = {};
if (index === '1') {
params = {
type: 'target',
ml: e.value[0].number,
date: moment(new Date()).format('YYYY-MM-DD')
};
} else {
params = {
type: 'ml',
ml: e.value[0].number,
date: moment(new Date()).format('YYYY-MM-DD')
};
}
setWaters(params).then(res => {
this.getWaters();
this.waterCShow = false;
this.targetShow = false;
}).catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
});
},
// 喝水
drinkWater() {
let data = {
date: this.today
}
drinkWater(data).then(res => {
this.getWaters();
this.dateLists()
}).catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
});
},
// 删除和喝水记录
delWater(id) {
uni.showModal({
content: '确认删除么?',
confirmText: '确认删除',
confirmColor: '#34ce98',
cancelText: '再想想',
cancelColor: '#ddd',
success: res => {
if (res.confirm) {
delDrinkWater(id)
.then(res => {
this.getWaters();
})
.catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
});
}
}
});
},
//#region 日历操作相关
// 日历列表
dateLists() {
let data = {
month: this.month,
type: this.dateType
}
dateList(data).then(res => {
this.calendarList = res.calendar
this.dateType = ''
this.month = res.month
}).catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
})
},
// 选择日期
dateClick(item) {
this.today = item.today
this.month = item.today
this.reset()
},
// 返回到今日
backDate() {
this.today = moment(new Date()).format('YYYY-MM-DD')
this.reset()
},
// 上一个月或者下一个月
datePreNext(type) {
this.dateType = type
this.dateLists()
},
// 关闭日历
closeDate() {
this.month = this.today
this.dateShow = false
},
// 重置日历数据
reset() {
this.calendarList = []
this.dateLists()
this.getWaters()
this.closeDate()
}
//#endregion 日历操作相关
}
};
</script>
<style lang="scss" scoped>
.drink {
// 喝水 水杯及文字
.drink {
padding-top: 120rpx;
.drink-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
// padding: $padding 0;
position: relative;
// 标题 再喝水
.title {
font-size: $title-size + 4;
color: $main-color;
font-weight: normal;
margin: $margin * 2;
position: relative;
.is_complete {
position: absolute;
top: 30rpx;
right: -120rpx;
}
.num {
font-size: $title-size * 2.3;
padding: 0 $padding * 0.3;
font-weight: bold;
}
.total {
font-size: $title-size;
color: $text-gray-m;
padding-left: $padding * 0.2;
}
}
// 加一杯水
.add-water {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
font-size: $title-size;
color: $text-color;
margin-top: $margin * 2;
position: relative;
span {
padding-top: $padding * 0.4;
color:$text-gray-m;
font-size: $title-size;
}
.add-icon {
position: absolute;
top: $margin + 8;
right: 0;
}
}
// 目标
.water-target {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
color: $text-gray-m;
font-size: $title-size;
position: absolute;
z-index: 110;
right: $padding * 1.4;
top: 50%;
.target-item {
margin-top: $margin * 1.6;
.target-icon {
padding-top: $padding * 0.5;
}
}
}
}
// 喝水记录
.--history {
padding: $padding;
.no-drink {
color: $text-gray-m;
font-size: $title-size-m;
padding-top: $padding + 10;
}
// 标题
.title {
font-size: $title-size + 4;
font-weight: bold;
color: $text-color;
position: relative;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
box-sizing: border-box;
padding-left: $padding;
padding-bottom: $padding;
&::before {
position: absolute;
content: '';
width: 8rpx;
height: 45rpx;
left: 0;
background-color: $main-color;
border-radius: 10rpx;
}
}
// 顶部日历筛选部分
.u-center {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-sizing: border-box;
// 列表
.lists {
// background-color: pink;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
border-bottom: solid 1rpx #f7f7f7;
.lists-water {
background-image: linear-gradient(to right, $main-color, $main-color);
width: 90rpx;
height: 90rpx;
border-radius: 50%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-sizing: border-box;
}
.list-item {
flex: 1;
margin-left: $margin * 0.7;
font-size: $title-size;
color: $text-gray-m;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
margin: $margin 0 $margin $margin * 0.7;
.list-item-title {
font-size: $title-size + 3;
color: $text-color;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
box-sizing: border-box;
font-weight: bold;
span {
margin-top: $margin * 0.4;
background-color: #f7f7f7;
padding: 4rpx 10rpx;
border-radius: 50rpx;
font-weight: normal;
font-size: $title-size - 3;
}
}
}
}
}
}
// 水杯动画
.wave-content {
position: relative;
z-index: 110;
.grass {
position: relative;
z-index: 120099;
}
.date {
background-color: rgba($color: #000000, $alpha: .1);
color: #fff;
min-width: 340rpx;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-sizing: border-box;
padding: 8rpx 20rpx;
border-radius: $radius * 2;
margin: 0 10rpx;
font-size: $title-size - 2;
}
.wave {
position: absolute;
width: 290rpx;
height: 500rpx;
background-color: rgba($color: $main-color, $alpha: 0.6);
background-size: 100%;
overflow: hidden;
top: 10rpx;
left: 20rpx;
z-index: 10;
&::before,
&::after {
content: '';
position: absolute;
width: 1000rpx;
height: 1000rpx;
top: var(--ballPercent);
left: 50%;
background-color: rgba(255, 255, 255, 0.4);
border-radius: 45%;
transform: translate(-50%, -70%) rotate(0);
animation: rotate 4s linear infinite;
z-index: 10;
}
&::after {
border-radius: 47%;
background-color: rgba(255, 255, 255, 0.9);
transform: translate(-50%, -70%) rotate(0);
animation: rotate 6s linear -5s infinite;
z-index: 20;
}
}
.play-right-fill {
padding: $padding !important;
background-color: pink;
}
}
@keyframes rotate {
50% {
transform: translate(-50%, -73%) rotate(180deg);
}
100% {
transform: translate(-50%, -70%) rotate(360deg);
}
}
}
// 喝水 水杯及文字
.drink-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
// padding: $padding 0;
position: relative;
// 标题 再喝水
.title {
font-size: $title-size + 4;
color: $main-color;
font-weight: normal;
margin: $margin * 2;
position: relative;
.is_complete {
position: absolute;
top: 30rpx;
right: -120rpx;
}
.num {
font-size: $title-size * 2.3;
padding: 0 $padding * 0.3;
font-weight: bold;
}
.total {
font-size: $title-size;
color: $text-gray-m;
padding-left: $padding * 0.2;
}
}
// 加一杯水
.add-water {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
font-size: $title-size;
color: $text-color;
margin-top: $margin * 2;
position: relative;
span {
padding-top: $padding * 0.4;
color: $text-gray-m;
font-size: $title-size;
}
.add-icon {
position: absolute;
top: $margin + 8;
right: 0;
}
}
// 目标
.water-target {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
color: $text-gray-m;
font-size: $title-size;
position: absolute;
z-index: 110;
right: $padding * 1.4;
top: 50%;
.target-item {
margin-top: $margin * 1.6;
.target-icon {
padding-top: $padding * 0.5;
}
}
}
}
// 喝水记录
.--history {
padding: $padding;
.no-drink {
color: $text-gray-m;
font-size: $title-size-m;
padding-top: $padding + 10;
}
// 标题
.title {
font-size: $title-size + 4;
font-weight: bold;
color: $text-color;
position: relative;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
box-sizing: border-box;
padding-left: $padding;
padding-bottom: $padding;
&::before {
position: absolute;
content: '';
width: 8rpx;
height: 45rpx;
left: 0;
background-color: $main-color;
border-radius: 10rpx;
}
}
// 列表
.lists {
// background-color: pink;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
border-bottom: solid 1rpx #f7f7f7;
.lists-water {
background-image: linear-gradient(to right, $main-color, $main-color);
width: 90rpx;
height: 90rpx;
border-radius: 50%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-sizing: border-box;
}
.list-item {
flex: 1;
margin-left: $margin * 0.7;
font-size: $title-size;
color: $text-gray-m;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
margin: $margin 0 $margin $margin * 0.7;
.list-item-title {
font-size: $title-size + 3;
color: $text-color;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
box-sizing: border-box;
font-weight: bold;
span {
margin-top: $margin * 0.4;
background-color: #f7f7f7;
padding: 4rpx 10rpx;
border-radius: 50rpx;
font-weight: normal;
font-size: $title-size - 3;
}
}
}
}
}
}
// 水杯动画
.wave-content {
position: relative;
z-index: 1;
.grass {
position: relative;
z-index: 1;
}
.wave {
position: absolute;
width: 290rpx;
height: 500rpx;
background-color: rgba($color: $main-color, $alpha: 0.6);
background-size: 100%;
overflow: hidden;
top: 10rpx;
left: 20rpx;
z-index: 1;
&::before,
&::after {
content: '';
position: absolute;
width: 1000rpx;
height: 1000rpx;
top: var(--ballPercent);
left: 50%;
background-color: rgba(255, 255, 255, 0.4);
border-radius: 45%;
transform: translate(-50%, -70%) rotate(0);
animation: rotate 4s linear infinite;
z-index: 1;
}
&::after {
border-radius: 47%;
background-color: rgba(255, 255, 255, 0.9);
transform: translate(-50%, -70%) rotate(0);
animation: rotate 6s linear -5s infinite;
z-index: 20;
}
}
@keyframes rotate {
50% {
transform: translate(-50%, -73%) rotate(180deg);
}
100% {
transform: translate(-50%, -70%) rotate(360deg);
}
}
}
</style>

View File

@@ -3,450 +3,551 @@
* @Author: Aimee·Zhang
* @Date: 2022-01-11 08:54:49
* @LastEditors: Aimee·Zhang
* @LastEditTime: 2022-01-20 10:05:15
* @LastEditTime: 2022-02-08 10:41:15
-->
<template>
<view class="record--foods">
<!-- 饮食进度条 -->
<view class="cricle-content">
<view class="info">
饮食摄入
<span>{{ calorys.intake_total }}</span>
</view>
<arprogress
:percent="calorys.exceeds ? 100 : calorys.ratio"
inactiveColor="#f5f4f9"
:activeColor="calorys.exceeds ? '#f00' : '#34ce98'"
width="300"
class="cricle"
borderWidth="20"
>
<span>{{ calorys.exceeds ? '多吃了' : '还可以吃' }}</span>
<span :class="['num', calorys.exceeds ? 'num1' : '']">{{ calorys.amount }}</span>
<span>推荐预算{{ calorys.goal }}</span>
</arprogress>
<view class="info" @click="errToast">
运动消耗
<span>{{ calorys.exercise_total }}</span>
</view>
<view class="ic-left">摄入量推荐</view>
<u-icon class="ic-day" name="checkmark-circle" color="#34ce98" size="10" :label="`${calorys.days}天`" labelColor="#34ce98" labelSize="10" space="3" />
</view>
<view class="record--foods">
<!-- 自定义导航部分 -->
<u-navbar :safeAreaInsetTop="true" :fixed='true' bgColor="#34ce98" :autoBack="true">
<view class="u-nav-slot" slot="left"> <u-icon name="arrow-leftward" :bold="true" size="20" color="#fff" /> </view>
<view class="u-nav-slot u-center" slot="center" @click="dateShow = true,dateLists()">
<u-icon name="play-left-fill" size="14" color="#fff" @click="datePreNext('before')" />
<view class="date"> <u-icon name="calendar" color="#fff" label-color="#fff" width="150" :label="today" label-size="14" size="20" /> </view>
<u-icon name="play-right-fill" size="14" color="#fff" @click="datePreNext('after')" />
</view>
<view class="u-nav-slot" slot="right"> <u-icon :name="require('@/static/icon/sign-icon.gif')" :bold="true" size="30" @click="$Router.push({name:'signIndex'})" /> </view>
</u-navbar>
<!-- 饮食记录 -->
<template v-if="intakes.length > 0">
<view class="foods-add" v-for="(it, index) in intakes" :key="index">
<view class="foods-title">
<view class="title-left">
{{ it.name }}
<span v-if="it.remark">{{ it.remark || '' }}</span>
</view>
<view class="title-right">
{{ it.total }}
<span class="dw">千卡</span>
<u-icon name="arrow-right" color="#ddd" size="13" :bold="true" />
</view>
</view>
<goodsList :lists="it.intake" type="no-dian" @editGoods="editGoods" @longClickGoods="longClickGoods" />
</view>
</template>
<!-- 运动列表 -->
<template v-if="sportsTotal > 0">
<view class="foods-title" style="padding-top:50rpx;">
<view class="title-left">运动</view>
<view class="title-right">
{{ sportsTotal }}
<span class="dw">千卡</span>
<u-icon name="arrow-right" color="#ddd" size="13" :bold="true" />
</view>
</view>
<!-- 饮食进度条 -->
<view class="cricle-content">
<view class="info"> 饮食摄入 <span>{{ calorys.intake_total }}</span> </view>
<arprogress :percent="calorys.exceeds ? 100 : calorys.ratio" inactiveColor="#f5f4f9"
:activeColor="calorys.exceeds ? '#c50000' : '#34ce98'" width="300" class="cricle" borderWidth="20">
<span>{{ calorys.exceeds ? '多吃了' : '还可以吃' }}</span>
<span :class="['num', calorys.exceeds ? 'num1' : '']">{{ calorys.amount }}</span>
<span>推荐预算{{ calorys.goal }}</span>
</arprogress>
<view class="info" @click="errToast"> 运动消耗 <span>{{ calorys.exercise_total }}</span> </view>
<view class="ic-left">摄入量推荐</view>
<u-icon class="ic-day" name="checkmark-circle" color="#34ce98" size="10" :label="`${calorys.days}天`" labelColor="#34ce98" labelSize="10" space="3" />
</view>
<sports type="edit" :lists="sports" @editSport="editSport" @longClick="longClick" />
</template>
<!-- 有饮食记录 -->
<template v-if="intakes.length > 0">
<view class="foods-add" v-for="(it, index) in intakes" :key="index">
<view class="foods-title">
<view class="title-left"> {{ it.name }} <span v-if="it.remark">{{ it.remark || '' }}</span> </view>
<view class="title-right"> {{ it.total }} <span class="dw">千卡</span> <u-icon name="arrow-right" color="#ddd" size="13" :bold="true" /> </view>
</view>
<goodsList :lists="it.intake" type="no-dian" @editGoods="editGoods" @longClickGoods="longClickGoods" />
</view>
</template>
<!-- 没有饮食记录 -->
<view class="no-foods" v-if="sports.length === 0 && intakes.length === 0">
<u-image :src="require('../../static/imgs/no-foods.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="300rpx" class="no-foods-img" />
<view>还没有添加今日饮食记录</view>
<view>请点击屏幕下方按钮来添加</view>
</view>
<!-- 运动列表 -->
<template v-if="sportsTotal > 0">
<view class="foods-title" style="padding-top:50rpx;">
<view class="title-left">运动</view>
<view class="title-right"> {{ sportsTotal }} <span class="dw">千卡</span> <u-icon name="arrow-right" color="#ddd" size="13" :bold="true" /> </view>
</view>
<sports type="edit" :lists="sports" @editSport="editSport" @longClick="longClick" />
</template>
<!-- 加餐模块 -->
<u-action-sheet
:actions="addEatList"
title="加餐模块"
:closeOnClickOverlay="true"
:closeOnClickAction="true"
@select="selectClick"
cancelText="取消"
:show="addEatShow"
@close="addEatShow = false"
></u-action-sheet>
<!-- 底部 早餐等菜单 -->
<u-tabbar :fixed="true" :placeholder="true" :safeAreaInsetBottom="true" inactiveColor="#333" @click="tabbarClick">
<u-tabbar-item text="+早餐" @click="tabbarClick" :icon="require('../../static/imgs/foods-1.png')" />
<u-tabbar-item text="+午餐" @click="tabbarClick" :icon="require('../../static/imgs/foods-2.png')" />
<u-tabbar-item text="+晚餐" @click="tabbarClick" :icon="require('../../static/imgs/foods-3.png')" />
<u-tabbar-item text="+加餐" @click="tabbarClick" :icon="require('../../static/imgs/foods-4.png')" />
<u-tabbar-item text="+运动" @click="tabbarClick" :icon="require('../../static/imgs/foods-5.png')" />
</u-tabbar>
<!-- 没有饮食记录 -->
<view class="no-foods" v-if="sports.length === 0 && intakes.length === 0">
<u-image :src="require('../../static/imgs/no-foods.png')" :lazy-load="true" radius="10rpx" mode="widthFix" width="300rpx" class="no-foods-img" />
<view>还没有添加今日饮食记录</view>
<view>请点击屏幕下方按钮来添加</view>
</view>
<!-- 修改食品弹窗 -->
<!-- 添加食谱弹窗 -->
<addFoods
v-if="addShow"
:addShow="addShow"
:selectGoods="selectGoods"
:decimals="true"
@confirm="confirmHandle"
@close="closeHandle"
@delThis="delThis"
@tabGoodsInfo="tabGoodsInfo"
max="999"
/>
<!-- 加餐模块 -->
<u-action-sheet :actions="addEatList" title="加餐模块" :closeOnClickOverlay="true" :closeOnClickAction="true" @select="selectClick" cancelText="取消" :show="addEatShow" @close="addEatShow = false" />
<!-- 修改运动弹窗 -->
<addPopup :selectSports="selectSports" :addSportsShow="addSportsShow" @comfirmSport="comfirmSport" @cancleSport="cancleSport" @delSport="delSport" />
</view>
<!-- 底部 早餐等菜单 -->
<u-tabbar :fixed="true" :placeholder="true" :safeAreaInsetBottom="true" inactiveColor="#333" @click="tabbarClick">
<u-tabbar-item text="+早餐" @click="tabbarClick" :icon="require('../../static/imgs/foods-1.png')" />
<u-tabbar-item text="+午餐" @click="tabbarClick" :icon="require('../../static/imgs/foods-2.png')" />
<u-tabbar-item text="+晚餐" @click="tabbarClick" :icon="require('../../static/imgs/foods-3.png')" />
<u-tabbar-item text="+加餐" @click="tabbarClick" :icon="require('../../static/imgs/foods-4.png')" />
<u-tabbar-item text="+运动" @click="tabbarClick" :icon="require('../../static/imgs/foods-5.png')" />
</u-tabbar>
<!-- 添加食谱弹窗 -->
<addFoods v-if="addShow" :addShow="addShow" :selectGoods="selectGoods" :decimals="true" @confirm="confirmHandle" @close="closeHandle" @delThis="delThis" @tabGoodsInfo="tabGoodsInfo" max="999" />
<!-- 修改运动弹窗 -->
<addPopup :selectSports="selectSports" :addSportsShow="addSportsShow" @comfirmSport="comfirmSport" @cancleSport="cancleSport" @delSport="delSport" />
<!-- 选择日历 -->
<dateTemplate :lists="calendarList" :today="today" :month="month" :dateShow="dateShow" type='foods' @backDate="backDate" @dateClick="dateClick" @closeDate="closeDate" @datePreNext="datePreNext" />
</view>
</template>
<script>
import arprogress from '@/components/ar-circle-progress/index.vue';
import goodsList from '@/components/foods';
import { plans, editHealthFoods, delHealthFoods } from '@/apis/interfaces/foods.js';
import moment from 'moment';
import addFoods from '@/components/add-goods-template/add-goods-template';
import addPopup from '@/components/sports/addPopup';
import sports from '@/components/sports';
import { editHealthSports, delHealthSports } from '@/apis/interfaces/sport.js';
export default {
components: {
arprogress,
goodsList,
addFoods,
addPopup,
sports
},
data() {
return {
lists: [],
addShow: false, // 添加食品显示
selectGoods: [], // 选择新增的食品
addEatShow: false, // 加餐弹窗默认不显示
addEatList: [
{
name: '上午加餐',
type: 2
},
{
name: '下午加餐',
type: 4
},
{
name: '晚上加餐',
type: 6
}
],
today: moment(new Date()).format('YYYY-MM-DD'),
calorys: {}, // 当日食谱推荐页面的信息
intakes: [], // 当日摄入列表
sports: [], // 运动列表
sportsTotal: 0,
addSportsShow: false, // 添加运动弹窗显示
selectSports: {} // 选择新增的运动
};
},
onShow() {
this.getList();
},
methods: {
// 编辑运动
editSport(item) {
this.selectSports = {
name: item.sport.name,
calory: item.sport.calory,
cover: item.sport.cover,
duration: item.duration,
sport_id: item.sport.sport_id,
exercise_id: item.exercise_id,
title: '编辑运动'
};
// console.log(this.selectSports);
console.log('编辑运动', item);
this.addSportsShow = true;
},
import moment from 'moment';
import sports from '@/components/sports';
import goodsList from '@/components/foods';
import addPopup from '@/components/sports/addPopup';
import arprogress from '@/components/ar-circle-progress/index.vue';
import addFoods from '@/components/add-goods-template/add-goods-template';
import dateTemplate from '@/components/date-template/index.vue'
import {
editHealthSports,
delHealthSports
} from '@/apis/interfaces/sport.js';
import {
plans,
editHealthFoods,
delHealthFoods,
dateList
} from '@/apis/interfaces/foods.js';
export default {
components: {
arprogress,
goodsList,
addFoods,
addPopup,
sports,
dateTemplate
},
data() {
return {
addShow: false, // 添加食品显示
selectGoods: [], // 选择新增的食品
addEatShow: false, // 加餐弹窗默认不显示
addEatList: [{name: '上午加餐',type: 2},{name: '下午加餐',type: 4},{name: '晚上加餐',type: 6}],
calorys: {}, // 当日食谱推荐页面的信息
intakes: [], // 当日摄入列表
sports: [], // 运动列表
sportsTotal: 0,
addSportsShow: false, // 添加运动弹窗显示
selectSports: {}, // 选择新增的运动
today: moment(new Date()).format('YYYY-MM-DD'),// 当前时间
month: moment(new Date()).format('YYYY-MM'), //当前月份
dateShow: false, // 日历展示
calendarList: [],
dateType: '', // before after ''
};
},
onShow() {
this.getList();
this.dateLists(); // 日期列表
},
methods: {
// 获取当前统计页面基本数据
getList() {
plans(this.today).then(res => {
this.calorys = res.calorys;
this.calorys.ratio = Number(this.calorys.ratio);
this.intakes = res.intakes;
this.sports = res.exercises.lists;
this.sportsTotal = res.exercises.total;
}).catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
});
},
// 弹窗确认按钮新增 这里接口报错了
comfirmSport(show, duration) {
let params = {
unit: '1', // 时间单位:分钟 1 小时 2
duration: duration, // 时常
exercise_id: this.selectSports.exercise_id, //
sport_id: this.selectSports.sport_id, // 运动id
date: this.today // 日期
};
console.log(params);
editHealthSports(params).then(res => {
this.addSportsShow = false;
this.selectSports = {};
this.getList();
}).catch(err=>{
uni.showToast({
title:err.message,
icon:'none'
})
});
},
//#region 运动操作相关
// 编辑运动
editSport(item) {
this.selectSports = {
name: item.sport.name,
calory: item.sport.calory,
cover: item.sport.cover,
duration: item.duration,
sport_id: item.sport.sport_id,
exercise_id: item.exercise_id,
title: '编辑运动'
};
this.addSportsShow = true;
},
// 弹窗确认按钮新增 这里接口报错了
comfirmSport(show, duration) {
let params = {
unit: '1', // 时间单位:分钟 1 小时 2
duration: duration, // 时常
exercise_id: this.selectSports.exercise_id, //
sport_id: this.selectSports.sport_id, // 运动id
date: this.today // 日期
};
editHealthSports(params).then(res => {
this.addSportsShow = false;
this.selectSports = {};
this.getList();
}).catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
});
},
// 弹窗取消按钮
cancleSport(show) {
this.addSportsShow = show;
},
// 删除运动
delSport() {
let params = {
exercise_id: this.selectSports.exercise_id //
};
delHealthSports(params).then(res => {
this.addSportsShow = false;
this.selectSports = {};
this.getList();
}).catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
});
},
// 长按删除触发事件运动
longClick(item) {
this.selectSports = item;
uni.showModal({
content: '确认删除么?',
confirmText: '确认删除',
confirmColor: '#34ce98',
cancelText: '再想想',
cancelColor: '#ddd',
success: res => {
if (res.confirm) {
this.delSport();
}
}
});
},
//#endregion 运动操作相关
// 弹窗取消按钮
cancleSport(show) {
this.addSportsShow = show;
},
// 删除运动
delSport() {
let params = {
exercise_id: this.selectSports.exercise_id //
};
console.log(params);
delHealthSports(params).then(res => {
this.addSportsShow = false;
this.selectSports = {};
this.getList();
});
},
// 长按删除触发事件运动
longClick(item) {
this.selectSports = item;
uni.showModal({
content: '确认删除么?',
confirmText: '确认删除',
confirmColor: '#34ce98',
cancelText: '再想想',
cancelColor: '#ddd',
success: res => {
if (res.confirm) {
this.delSport();
}
}
});
},
// 长按删除食品
longClickGoods(e) {
this.selectGoods = [e];
uni.showModal({
content: '确认删除么?',
confirmText: '确认删除',
confirmColor: '#34ce98',
cancelText: '再想想',
cancelColor: '#ddd',
success: res => {
if (res.confirm) {
this.delThis();
}
}
});
},
// 错误提示
errToast() {
uni.showToast({
title: '努力开发中~',
icon: 'none'
});
},
getList() {
plans(this.today).then(res => {
this.calorys = res.calorys;
this.calorys.ratio = Number(this.calorys.ratio);
this.intakes = res.intakes;
this.sports = res.exercises.lists;
this.sportsTotal = res.exercises.total;
});
},
// 底部按钮点击触发的事件 早餐1 午餐3 晚餐5 加餐(早2中4晚6)
tabbarClick(e) {
console.log(e);
this.tabarIndex = e;
if (e === 3) {
this.addEatShow = true;
} else {
if (e === 4) {
// 新增运动
uni.navigateTo({
url: `/pages/record/addExercises`
});
} else {
uni.navigateTo({
url: `/pages/record/addFoods?type=${e === 0 ? 1 : e === 1 ? 3 : 5}`
});
}
}
},
// 选择了加餐跳转
selectClick(e) {
uni.navigateTo({
url: `/pages/record/addFoods?type=${e.type}`
});
// 选择加餐
},
// 编辑食品
editGoods(e) {
this.selectGoods = [e];
this.addShow = true;
},
closeHandle() {
//键盘关闭的回调函数
this.addShow = false;
},
// 监听点击键盘触发返回值新增食品
confirmHandle(value) {
// 新添加食物
let data = {
ser: 1,
weight: value,
food_id: this.selectGoods[0].food_id,
intake_id: this.selectGoods[0].intake_id
};
this.editHealthFoods(data);
},
// 添加食物
editHealthFoods(data) {
editHealthFoods(data).then(res => {
console.log(res);
this.addShow = false;
this.getList();
});
},
// 删除该食物
delThis(e) {
delHealthFoods(this.selectGoods[0].intake_id).then(res => {
this.addShow = false;
this.getList();
});
},
// 跳转到食品详情
tabGoodsInfo(e) {
this.$Router.push({
name: 'rankingDetails',
params: e
});
}
}
};
//#region 食物操作相关
// 长按删除食品
longClickGoods(e) {
this.selectGoods = [e];
uni.showModal({
content: '确认删除么?',
confirmText: '确认删除',
confirmColor: '#34ce98',
cancelText: '再想想',
cancelColor: '#ddd',
success: res => {
if (res.confirm) {
this.delThis();
}
}
});
},
// 错误提示
errToast() {
uni.showToast({
title: '努力开发中~',
icon: 'none'
});
},
// 底部按钮点击触发的事件 早餐1 午餐3 晚餐5 加餐(早2中4晚6)
tabbarClick(e) {
this.tabarIndex = e;
if (e === 3) {
this.addEatShow = true;
} else {
if (e === 4) {
// 新增运动
uni.navigateTo({
url: `/pages/record/addExercises`
});
} else {
uni.navigateTo({
url: `/pages/record/addFoods?type=${e === 0 ? 1 : e === 1 ? 3 : 5}&date=${this.today}`
});
}
}
},
// 选择了加餐跳转
selectClick(e) {
uni.navigateTo({
url: `/pages/record/addFoods?type=${e.type}&date=${this.today}`
});
// 选择加餐
},
// 编辑食品
editGoods(e) {
this.selectGoods = [e];
this.addShow = true;
},
closeHandle() {
//键盘关闭的回调函数
this.addShow = false;
},
// 监听点击键盘触发返回值新增食品
confirmHandle(value) {
// 新添加食物
let data = {
ser: 1,
weight: value,
food_id: this.selectGoods[0].food_id,
intake_id: this.selectGoods[0].intake_id
};
this.editHealthFoods(data);
},
// 添加食物
editHealthFoods(data) {
editHealthFoods(data).then(res => {
this.addShow = false;
this.getList();
}).catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
});
},
// 删除该食物
delThis(e) {
delHealthFoods(this.selectGoods[0].intake_id).then(res => {
this.addShow = false;
this.getList();
}).catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
});
},
// 跳转到食品详情
tabGoodsInfo(e) {
this.$Router.push({
name: 'rankingDetails',
params: e
});
},
//#endregion 食物操作相关
//#region 日历操作相关
// 日历列表
dateLists() {
let data = {
month: this.month,
type: this.dateType
}
dateList(data).then(res => {
this.calendarList = res.calendar
this.dateType = ''
this.month = res.month
}).catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
})
},
// 选择日期
dateClick(item) {
this.today = item.today
this.month = item.today
this.reset()
},
// 返回到今日
backDate() {
this.today = moment(new Date()).format('YYYY-MM-DD')
this.reset()
},
// 上一个月或者下一个月
datePreNext(type) {
this.dateType = type
this.dateLists()
},
// 关闭日历
closeDate() {
this.month = this.today
this.dateShow = false
},
// 重置日历数据
reset() {
this.calendarList = []
this.dateLists()
this.getList()
this.closeDate()
}
//#endregion 日历操作相关
}
};
</script>
<style lang="scss" scoped>
.record--foods {
padding: $padding $padding $padding * 7 $padding;
// background: green;
}
// 饮食进度条
.cricle-content {
box-shadow: 0 0 4rpx 4rpx rgba($color: $main-color, $alpha: 0.1);
font-size: $title-size-m - 6;
padding: $padding * 1.8 $padding;
border-radius: $radius;
color: $text-gray-m;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-around;
box-sizing: border-box;
position: relative;
.cricle {
.num {
color: $text-color;
font-size: $title-size * 1.8;
font-weight: bold;
padding: $padding * 0.2;
}
.num1 {
color: #f00;
}
}
.info {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
span {
font-size: $title-size + 10;
font-weight: bold;
color: $text-color;
padding-top: $padding * 0.5;
}
}
.ic-left {
position: absolute;
left: 0;
top: 0;
background-image: linear-gradient(to right, #ffebb9, #fbd57b);
color: #664710;
padding: 10rpx $padding * 0.6;
border-radius: 0 0 $radius 0;
}
.ic-day {
position: absolute;
right: $padding;
top: $padding;
}
}
// 没有饮食记录
.no-foods {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
font-size: $title-size-m - 4;
color: $text-gray-m;
min-height: 40vh;
// background: pink;
.no-foods-img {
opacity: 0.5;
}
view {
padding: $padding * 0.2;
}
}
// 饮食记录 早中晚加餐等
.foods-add {
border-bottom: solid 1rpx #f7f7f7;
margin-top: $margin;
}
// 主标题
.foods-title {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
color: $text-color;
padding: $padding * 0.5 0;
.title-left {
font-size: $title-size;
color: $text-color;
font-weight: bold;
span {
font-weight: normal;
font-size: $title-size-m - 6;
color: $text-gray-m;
margin-left: $margin - 10;
}
}
.title-right {
font-size: $title-size-m - 6;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-sizing: border-box;
color: $main-color;
.dw {
margin: 0 $margin * 0.6 0 $margin * 0.4;
color: $text-gray;
}
}
}
.record--foods {
padding: $padding $padding $padding * 7 $padding;
// background: green;
}
// 顶部日历筛选部分
.u-center {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-sizing: border-box;
.date {
background-color: rgba($color: #000000, $alpha: .1);
color: #fff;
min-width: 340rpx;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-sizing: border-box;
padding: 8rpx 20rpx;
border-radius: $radius * 2;
margin: 0 10rpx;
font-size: $title-size - 2;
}
.play-right-fill {
padding: $padding !important;
background-color: pink;
}
}
// 饮食进度条
.cricle-content {
box-shadow: 0 0 4rpx 4rpx rgba($color: $main-color, $alpha: 0.1);
font-size: $title-size-m - 6;
padding: $padding * 1.8 $padding;
border-radius: $radius;
color: $text-gray-m;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-around;
box-sizing: border-box;
position: relative;
margin-top: $margin * 5;
.cricle {
.num {
color: $text-color;
font-size: $title-size * 1.8;
font-weight: bold;
padding: $padding * 0.2;
}
.num1 {
color: #f00;
}
}
.info {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
span {
font-size: $title-size + 10;
font-weight: bold;
color: $text-color;
padding-top: $padding * 0.5;
}
}
.ic-left {
position: absolute;
left: 0;
top: 0;
background-image: linear-gradient(to right, #ffebb9, #fbd57b);
color: #664710;
padding: 10rpx $padding * 0.6;
border-radius: 0 0 $radius 0;
}
.ic-day {
position: absolute;
right: $padding;
top: $padding;
}
}
// 没有饮食记录
.no-foods {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
font-size: $title-size-m - 4;
color: $text-gray-m;
min-height: 40vh;
// background: pink;
.no-foods-img {
opacity: 0.5;
}
view {
padding: $padding * 0.2;
}
}
// 饮食记录 早中晚加餐等
.foods-add {
border-bottom: solid 1rpx #f7f7f7;
margin-top: $margin;
}
// 主标题
.foods-title {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
color: $text-color;
padding: $padding * 0.5 0;
.title-left {
font-size: $title-size;
color: $text-color;
font-weight: bold;
span {
font-weight: normal;
font-size: $title-size-m;
color: $text-gray-m;
margin-left: $margin - 10;
}
}
.title-right {
font-size: $title-size-m;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-sizing: border-box;
color: $main-color;
.dw {
margin: 0 $margin * 0.6 0 $margin * 0.4;
color: $text-gray;
}
}
}
</style>

View File

@@ -398,9 +398,6 @@ export default {
*/
logs() {
logs().then(res => {
console.log(res.is_login)
this.weight = res.weight;
this.water = res.water;
this.intake_run = res.intake_run;
@@ -410,7 +407,14 @@ export default {
this.banner = res.banner;
this.user = res.user;
this.notifications_count = res.notifications_count;
});
}).catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
});
},
/**
* @description:跳转登录页面

View File

@@ -8,231 +8,303 @@
<template>
<view class="weight">
<!-- 体重表 -->
<view class="progress-top">
<view class="unit">
<span
:class="isJin === 2?'active':''"
@click="isJin = 1"
></span>
<span
:class="isJin === 1?'active':''"
@click="isJin = 1"
>公斤</span>
</view>
<view class="progress">
<view>{{weightInfo.text}}</view>
<u-count-to
class="uCountTo"
:startVal="0"
:endVal="weightInfo.change"
:decimals="1"
color="#333"
fontSize="36"
:bold="true"
/>
<view>保持 / 塑性</view>
</view>
<view
class="add-weight"
@click="addWeightShow = true"
>记录体重</view>
<view class="des-title">以最后一次记录为主且每日只能更新一次</view>
</view>
<!-- 体重列表 -->
<view
class="weight-list"
v-if="lists.length>0"
>
<view
class="list-item"
v-for="item in lists"
:key="item.wight_id"
>
<view class="list-left">
<view class="list-title">
<span>{{item.weight}}</span>公斤
</view>
测量结果
<!-- 进度模块 -->
<block v-if="tabbarId === 0">
<!-- 体重表 -->
<view class="progress-top">
<view class="unit"> <span :class="isJin === 2?'active':''" @click="isJin = 1"></span> <span :class="isJin === 1?'active':''" @click="isJin = 1">公斤</span> </view>
<view class="progress">
<view>{{weightInfo.text}}</view>
<u-count-to class="uCountTo" :startVal="0" :endVal="weightInfo.change" :decimals="1" color="#333" fontSize="36" :bold="true" />
<view>保持 / 塑性</view>
</view>
<view class="list-right">
<span>开始保持 / 塑性</span>
{{item.created_at}}
<view class="add-weight" @click="addWeightShow = true">记录体重</view>
<view class="des-title">以最后一次记录为主且每日只能更新一次</view>
</view>
<!-- 体重列表 -->
<view class="weight-list" v-if="lists.length>0">
<view class="list-item">
<view class="list-left"> <view class="list-title"> <span>{{weightInfo.begin}}</span>公斤 </view> 初始体重 </view>
<view class="list-right"> <span>开始保持 / 塑性</span> {{weightInfo.first_weight_time}} </view>
</view>
<view class="list-item" v-for="item in lists" :key="item.wight_id">
<view class="list-left"> <view class="list-title"> <span>{{item.weight}}</span>公斤 </view> 测量结果 </view>
<view class="list-right"> <span>开始保持 / 塑性</span> {{item.created_at}} </view>
</view>
</view>
<view class="no-lists" v-else>还没有体重信息记录下呗~</view>
</block>
<!-- 曲线模块 -->
<view v-if="tabbarId === 1">
<!-- 健康测评 -->
<u-image v-if="chartData.categories.length>0" :src="require('@/static/imgs/health1.png')" class="eval-img" @click="$Router.push({ name: 'EvaluationList' })" :lazy-load="true" radius="10rpx" mode="widthFix" width="100%" />
<view class="curve" v-if="chartData.categories.length>0">
<view class="title"> 体重 <span>单位公斤</span> </view>
<u-icon @click="addWeightShow = true" name="edit-pen-fill" color="#34ce98" size="20" :bold="true" label="更新" labelPos="right" labelSize="13" labelColor="#999" space="4" />
</view>
<view class="charts-box" v-if="chartData.categories.length>0"> <qiun-data-charts type="area" :chartData="chartData" background="none" /> </view>
<view class="progress-top">
<view class="add-weight" @click="addWeightShow = true">记录体重</view>
<view class="des-title">只显示最近七次测量记录</view>
</view>
</view>
<view
class="no-lists"
v-else
>还没有体重信息记录下呗~</view>
<!-- 记录体重弹窗 -->
<u-popup
:show="addWeightShow"
:round="10"
@close="addWeightShow = false"
:closeable="true"
>
<u-popup :show="addWeightShow" :round="10" @close="addWeightShow = false" :closeable="true">
<view class="addWeightContent">
<view class="date">今天</view>
<view class='count'><span>{{weight}}</span>公斤</view>
<vue-scale
:min="10"
:max="100"
:int="false"
:single="10"
:h="80"
:styles="styles"
@scroll="scroll"
:scrollLeft="Number(weight)"
/>
<view
class="addBtn"
@click="addWeight"
>确认添加</view>
<vue-scale :min="10" :max="100" :int="false" :single="10" :h="80" :styles="styles" @scroll="scroll" :scrollLeft="Number(weight)" />
<view class="addBtn" @click="addWeight">确认添加</view>
</view>
</u-popup>
<!-- 底部 进度 曲线菜单 -->
<u-tabbar :value="tabbarId" :fixed="true" :placeholder="false" :safeAreaInsetBottom="false" activeColor="#34ce98">
<u-tabbar-item text="进度" :icon="tabbarId === 0 ?require('../../static/imgs/speed-2.png'):require('../../static/imgs/speed-1.png')" @click="tabbarClick" />
<u-tabbar-item text="曲线" :icon="tabbarId === 1 ?require('../../static/imgs/curve-2.png'):require('../../static/imgs/curve-1.png')" @click="tabbarClick" />
</u-tabbar>
</view>
</template>
<script>
import vueScale from "@/components/vueScale";
import { weights, addWeight } from "@/apis/interfaces/weight.js";
import moment from "moment";
import l from "../../uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center";
export default {
components: {
vueScale,
},
data() {
return {
isJin: 1, // 是公斤 2 是斤 所有用到斤的直接乘以这个字段即可
addWeightShow: false, // 是否添加体重展示
styles: {
line: "#dbdbdb",
bginner: "#fbfbfb",
bgoutside: "#ffffff",
font: "#404040",
fontColor: "#404040",
fontSize: 16,
},
weight: "",
date: "",
weightInfo: {},
lists: [],
has_more: true,
page: 1,
};
},
onShow() {
this.getWeights();
this.date = moment(new Date()).format("YYYY-MM-DD");
},
onReachBottom() {
if (!this.has_more) {
uni.showToast({
title: "没有更多啦~",
icon: "none",
});
} else {
this.page = this.page + 1;
this.getWeights();
}
},
methods: {
//获取体重首页接口
getWeights() {
weights(this.page).then((res) => {
if(res.lists.page.current === 1) {
this.lists = []
}
this.lists = this.lists.concat(res.lists.data);
this.has_more = res.lists.page.has_more;
this.weightInfo = res.weight;
this.weight = res.weight.now;
});
import vueScale from "@/components/vueScale";
import {
weights,
addWeight,
curves
} from "@/apis/interfaces/weight.js";
import moment from "moment";
import l from "../../uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center";
export default {
components: {
vueScale,
},
addWeight() {
let data = {
weight: this.weight,
date: this.date,
data() {
return {
isJin: 1, // 是公斤 2 是斤 所有用到斤的直接乘以这个字段即可
addWeightShow: false, // 是否添加体重展示
styles: {
line: "#dbdbdb",
bginner: "#fbfbfb",
bgoutside: "#ffffff",
font: "#404040",
fontColor: "#404040",
fontSize: 16,
},
weight: "",
date: "",
weightInfo: {},
lists: [],
has_more: true,
page: 1,
tabbarId: 0,
chartData: {
// "categories": ["1/1","1/2","1/3","1/4","1/5","1/6","1/7"],
// "series": [{"name": "最近七天进度","data": [55,51,53.3,50.3,53.3]}]
categories:[],
series:[{name: "",data: []}]
}, // 曲线部分 start
};
addWeight(data).then((res) => {
this.addWeightShow = false;
this.page = 1;
this.has_more = true;
this.lists = [];
},
onShow() {
this.getWeights();
this.getCurves();
this.date = moment(new Date()).format("YYYY-MM-DD");
},
onReachBottom() {
if (!this.has_more) {
uni.showToast({
title: "没有更多啦~",
icon: "none",
duration: 1000,
mask: true
});
} else {
this.page = this.page + 1;
this.getWeights();
});
}
},
// 滚动标尺触发事件
scroll(msg) {
this.weight = msg;
methods: {
//获取体重首页接口
getWeights() {
weights(this.page).then((res) => {
if (res.lists.page.current === 1) {
this.lists = []
}
this.lists = this.lists.concat(res.lists.data);
this.has_more = res.lists.page.has_more;
this.weightInfo = res.weight;
this.weight = res.weight.now;
}).catch(err=>{
uni.showToast({
title:err.message,
icon:"none",
mask:true,
duration:2000
})
});
},
// 获取曲线
getCurves() {
curves().then((res) => {
this.chartData={
categories:res.categories,
"series": [res.series]
}
}).catch(err=>{
uni.showToast({
title:err.message,
icon:"none",
mask:true,
duration:2000
})
});
},
// 更新体重
addWeight() {
let data = {
weight: this.weight,
date: this.date
};
addWeight(data).then((res) => {
this.addWeightShow = false;
this.page = 1;
this.has_more = true;
this.lists = [];
this.getWeights();
this.getCurves();
}).catch(err=>{
uni.showToast({
title:err.message,
icon:"none",
mask:true,
duration:2000
})
});
},
// 滚动标尺触发事件
scroll(msg) {
this.weight = msg;
},
// 点击底部切换
tabbarClick(e) {
this.tabbarId = Number(e)
}
},
},
};
};
</script>
<style lang="scss" scoped>
//体重top
.progress-top {
padding: $padding * 2 $padding;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
border-bottom: solid 1rpx #f7f7f7;
// 单位
.unit {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
width: 100%;
span {
display: inline-block;
width: 100rpx;
font-size: $title-size-m;
color: $border-color;
padding: $padding * 0.5 0;
text-align: center;
border: solid 1rpx $border-color;
border-radius: 50rpx 0 0 50rpx;
}
span:nth-child(1) {
border-radius: 50rpx 0 0 50rpx;
border-style: solid;
border-color: $border-color $main-color $border-color $border-color;
}
span:nth-child(2) {
border-radius: 0 50rpx 50rpx 0;
border-style: solid;
border-color: $border-color $border-color $border-color $main-color;
}
span.active {
background-color: $main-color;
color: #fff;
border: solid 1rpx $main-color;
}
.charts-box{
width: 100%;
height:500rpx;
margin-top: $margin;
}
// 展示圈
.progress {
width: 360rpx;
height: 360rpx;
border: solid $padding * 0.7 #f7f7f7;
border-radius: 50%;
.no-weight{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
color: $text-gray-m;
color: #999;
font-size: $title-size-m;
.uCountTo {
padding: $padding * 0.5;
}
// curve
.curve{
margin-top: $margin;
padding: $padding $padding + 10;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
font-size: $title-size + 5;
color: #333;
span{
color: #cacaca;
font-size: $title-size-m;
margin-left: 10rpx;
}
}
// 记录按钮
// 评测图片
.eval-img {
box-shadow: 0 0 10rpx 4rpx rgba($color: $main-color, $alpha: 0.1);
}
//体重top
.progress-top {
padding: $padding * 2 $padding;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
border-bottom: solid 1rpx #f7f7f7;
// 单位
.unit {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
width: 100%;
span {
display: inline-block;
width: 100rpx;
font-size: $title-size-m;
color: $border-color;
padding: $padding * 0.5 0;
text-align: center;
border: solid 1rpx $border-color;
border-radius: 50rpx 0 0 50rpx;
}
span:nth-child(1) {
border-radius: 50rpx 0 0 50rpx;
border-style: solid;
border-color: $border-color $main-color $border-color $border-color;
}
span:nth-child(2) {
border-radius: 0 50rpx 50rpx 0;
border-style: solid;
border-color: $border-color $border-color $border-color $main-color;
}
span.active {
background-color: $main-color;
color: #fff;
border: solid 1rpx $main-color;
}
}
// 展示圈
.progress {
width: 360rpx;
height: 360rpx;
border: solid $padding * 0.7 #f7f7f7;
border-radius: 50%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
color: $text-gray-m;
font-size: $title-size-m;
.uCountTo {
padding: $padding * 0.5;
}
}
// 记录按钮
.add-weight {
font-size: $title-size + 2;
border-radius: $radius * 3;
@@ -242,92 +314,106 @@ export default {
margin-top: $margin * 2;
font-weight: bold;
}
.des-title {
.des-title {
padding: $padding;
color: $text-gray-m;
font-size: $title-size-m - 4;
}
}
// 列表
.weight-list {
font-size: $title-size-m;
color: #cacaca;
padding: 0 $padding;
.list-item {
display: flex;
flex-direction: row;
align-items: center;
box-sizing: border-box;
justify-content: space-between;
border-bottom: solid 1rpx #f9f9f9;
padding: 20rpx 0;
font-size: $title-size-m - 2;
.list-title {
color: #555;
font-size: $title-size-m - 2;
span {
font-size: $title-size + 10;
font-weight: 500;
margin-right: 10rpx;
}
}
.list-right {
display: flex;
flex-direction: column;
align-items: flex-end;
justify-content: center;
box-sizing: border-box;
margin-top: $margin * 0.4;
color: #999;
span {
margin-bottom: 10rpx;
}
}
}
}
.no-lists {
padding: $padding;
color: $text-gray-m;
font-size: $title-size-m - 4;
font-size: $title-size-m;
}
}
// 列表
.weight-list {
font-size: $title-size-m;
color: $text-gray-m;
padding: $padding;
.list-item {
display: flex;
flex-direction: row;
align-items: center;
// 弹窗
.addWeightContent {
width: 100%;
height: 54vh;
padding: $padding * 4 0;
box-sizing: border-box;
color: $text-gray;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
justify-content: space-between;
border-bottom: solid 1rpx #f9f9f9;
padding: $padding 0;
.list-title {
color: $text-color;
font-size: $title-size-m;
margin-bottom: $margin * 0.4;
span {
font-size: $title-size + 14;
font-weight: 500;
margin-right: 10rpx;
}
}
.list-right {
display: flex;
flex-direction: column;
align-items: flex-end;
justify-content: center;
box-sizing: border-box;
margin-top: $margin * 0.4;
span {
margin-bottom: 10rpx;
}
}
}
}
.no-lists {
padding: $padding;
color: $text-gray-m;
font-size: $title-size-m;
}
// 弹窗
.addWeightContent {
width: 100%;
height: 54vh;
padding: $padding * 4 0;
box-sizing: border-box;
color: $text-gray;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
.date {
font-size: $title-size + 9;
text-align: center;
}
.count {
color: $main-color;
text-align: center;
margin-top: $margin * 2;
margin-bottom: $margin * 0.1;
font-size: $title-size + 2;
span {
font-weight: bold;
font-size: $title-size * 2.2;
margin-right: $margin * 0.3;
.date {
font-size: $title-size + 9;
text-align: center;
}
.count {
color: $main-color;
text-align: center;
margin-top: $margin * 2;
margin-bottom: $margin * 0.1;
font-size: $title-size + 2;
span {
font-weight: bold;
font-size: $title-size * 2.2;
margin-right: $margin * 0.3;
}
}
.addBtn {
background-color: $main-color;
color: #fff;
margin-top: $margin * 2;
font-size: $title-size * 1.2;
padding: $padding * 0.7 $padding * 4;
border-radius: $radius * 3;
font-size: $title-size + 6;
box-shadow: 0 0 10rpx 4rpx rgba($color: $main-color, $alpha: 0.1);
}
}
.addBtn {
background-color: $main-color;
color: #fff;
margin-top: $margin * 2;
font-size: $title-size * 1.2;
padding: $padding * 0.7 $padding * 4;
border-radius: $radius * 3;
font-size: $title-size + 6;
box-shadow: 0 0 10rpx 4rpx rgba($color: $main-color, $alpha: 0.1);
}
}
</style>

View File

@@ -3,18 +3,14 @@
<!-- 更多管理 -->
<view class="list">
<view class="list-item" @click="updImgs">
<view class="list-item-left">
<span>修改头像</span>
</view>
<view class="list-item-left"> <span>修改头像</span> </view>
<view class="avatar" >
<image :src="avatar.showPath || require('@/static/user/cover.png')" mode="aspectFill" />
<u-icon name="arrow-right" color="#999" size="20"></u-icon>
</view>
</view>
<view class="list-item">
<view class="list-item-left">
<span>修改昵称</span>
</view>
<view class="list-item-left"> <span>修改昵称</span> </view>
<view class="input">
<input type="text" :value="nickname" @blur='blur' placeholder="请输入用户的昵称" maxlength="12" />
<u-icon name="arrow-right" color="#999" size="20"></u-icon>
@@ -86,11 +82,13 @@
this.avatar.showPath = pathRes.url[0]
this.resetUserInfo('avatar',pathRes.url[0])
}).catch(err => {
uni.showToast({
title: err.message,
icon: 'none'
})
})
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
})
}
})
},
@@ -114,11 +112,13 @@
})
this.getUserInfo()
}).catch(err => {
uni.showToast({
title: err.message,
icon: 'none'
})
})
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
})
}
}
}

View File

@@ -1,282 +1,316 @@
<template>
<view class="content">
<!-- 性别start -->
<view class="files" @click="sexShow = true">
<view class="name">性别</view>
<view class="text">
<u-icon
class="target-icon"
:label="recordsData.sex == 1 ? '男士' : '女士'"
name="arrow-right"
color="#999"
size="14"
labelSize="14"
labelColor="#666"
labelPos="left"
space="10"
/>
</view>
</view>
<u-action-sheet
:actions="sexList"
title="你的性别是?"
:show="sexShow"
cancelText="暂不修改"
@select=" e => { (this.recordsData.sex = e.id), (this.sexShow = false); } "
@close="sexShow = false"
/>
<!-- 性别 end -->
<view class="content">
<!-- 性别start -->
<view class="files" @click="sexShow = true">
<view class="name">性别</view>
<view class="text">
<u-icon class="target-icon" :label="recordsData.sex == 1 ? '男士' : '女士'" name="arrow-right" color="#999"
size="14" labelSize="14" labelColor="#666" labelPos="left" space="10" />
</view>
</view>
<u-action-sheet :actions="sexList" title="你的性别是?" :show="sexShow" cancelText="暂不修改"
@select=" e => { (this.recordsData.sex = e.id), (this.sexShow = false); } " @close="sexShow = false" />
<!-- 性别 end -->
<!-- 生日 start -->
<view class="files" @click="birthdayShow = true">
<view class="name">生日</view>
<view class="text">
<u-icon class="target-icon" :label="showBirthday" name="arrow-right" color="#999" size="14" labelSize="14" labelColor="#666" labelPos="left" space="10" />
</view>
</view>
<u-datetime-picker
confirmColor="#34ce98"
v-model="recordsData.birthday"
mode="date"
:show="birthdayShow"
:formatter="formatter"
:minDate="-302688000"
:maxDate="maxDate"
@confirm=" e => { this.recordsData.birthday = e.value, this.birthdayShow = false } "
@cancel=" () => { this.birthdayShow = false; } "
/>
<!-- 生日 end -->
<!-- 生日 start -->
<view class="files" @click="birthdayShow = true">
<view class="name">生日</view>
<view class="text">
<u-icon class="target-icon" :label="showBirthday" name="arrow-right" color="#999" size="14"
labelSize="14" labelColor="#666" labelPos="left" space="10" />
</view>
</view>
<u-datetime-picker confirmColor="#34ce98" v-model="recordsData.birthday" mode="date" :show="birthdayShow"
:formatter="formatter" :minDate="-302688000" :maxDate="maxDate"
@confirm=" e => { this.recordsData.birthday = e.value, this.birthdayShow = false } "
@cancel=" () => { this.birthdayShow = false; } " />
<!-- 生日 end -->
<!-- 身高 start-->
<view class="files" @click="heightShow = true">
<view class="name">身高</view>
<view class="text">
<u-icon class="target-icon" :label="recordsData.height + ` CM`" name="arrow-right" color="#999" size="14" labelSize="14" labelColor="#666" labelPos="left" space="10" />
</view>
</view>
<u-popup :show="heightShow" @close="() => { heightShow = false }">
<view class="v-scale">
<view class="title"> 你的身高为?</view>
<view class="total"> {{recordsData.height}} CM </view>
<vue-scale :min="10" :max="100" :int="false" :single="10" :h="80" :styles="styles" @scroll="scrollAll('height',$event)" :scrollLeft="Number(recordsData.height)" />
</view>
</u-popup>
<!-- 身高 end -->
<!-- 身高 start-->
<view class="files" @click="heightShow = true">
<view class="name">身高</view>
<view class="text">
<u-icon class="target-icon" :label="recordsData.height + ` CM`" name="arrow-right" color="#999"
size="14" labelSize="14" labelColor="#666" labelPos="left" space="10" />
</view>
</view>
<u-popup :show="heightShow" @close="() => { heightShow = false }">
<view class="v-scale">
<view class="title"> 你的身高为?</view>
<view class="total"> {{recordsData.height}} CM </view>
<vue-scale :min="10" :max="100" :int="false" :single="10" :h="80" :styles="styles"
@scroll="scrollAll('height',$event)" :scrollLeft="Number(recordsData.height)" />
</view>
</u-popup>
<!-- 身高 end -->
<!-- 最新体重 start -->
<view class="files bt30" @click="weightShow = true">
<view class="name">最新体重</view>
<view class="text">
<u-icon class="target-icon" :label="recordsData.weight + ` KG`" name="arrow-right" color="#999" size="14" labelSize="14" labelColor="#666" labelPos="left" space="10" />
</view>
</view>
<u-popup :show="weightShow" @close="() => { weightShow = false }">
<view class="v-scale">
<view class="title"> 你的当前体重为?</view>
<view class="total"> {{recordsData.weight}} KG </view>
<vue-scale :min="10" :max="100" :int="false" :single="10" :h="80" :styles="styles" @scroll="scrollAll('weight',$event)" :scrollLeft="Number(recordsData.weight)" />
</view>
</u-popup>
<!-- 生日 end -->
<!-- 最新体重 start -->
<view class="files bt30" @click="weightShow = true">
<view class="name">最新体重</view>
<view class="text">
<u-icon class="target-icon" :label="recordsData.weight + ` KG`" name="arrow-right" color="#999"
size="14" labelSize="14" labelColor="#666" labelPos="left" space="10" />
</view>
</view>
<u-popup :show="weightShow" @close="() => { weightShow = false }">
<view class="v-scale">
<view class="title"> 你的当前体重为?</view>
<view class="total"> {{recordsData.weight}} KG </view>
<vue-scale :min="10" :max="100" :int="false" :single="10" :h="80" :styles="styles"
@scroll="scrollAll('weight',$event)" :scrollLeft="Number(recordsData.weight)" />
</view>
</u-popup>
<!-- 生日 end -->
<!-- 目标 start -->
<view class="files" @click="targetShow = true">
<view class="name">目标</view>
<view class="text">
<u-icon class="target-icon" :label="targetList[selectedTargetIndex].name" name="arrow-right" color="#999" size="14" labelSize="14" labelColor="#666" labelPos="left" space="10" />
</view>
</view>
<u-action-sheet
:actions="targetList"
title="你的目标是?"
:show="targetShow"
cancelText="暂不修改"
@select=" e => { (this.selectedTargetIndex = this.targetList.findIndex(item => e.id === item.id)), (this.targetShow = false); } "
@close="targetShow = false"
/>
<!-- 目标 end -->
<!-- 目标 start -->
<view class="files" @click="targetShow = true">
<view class="name">目标</view>
<view class="text">
<u-icon class="target-icon" :label="targetList[selectedTargetIndex].name" name="arrow-right"
color="#999" size="14" labelSize="14" labelColor="#666" labelPos="left" space="10" />
</view>
</view>
<u-action-sheet :actions="targetList" title="你的目标是?" :show="targetShow" cancelText="暂不修改"
@select=" e => { (this.selectedTargetIndex = this.targetList.findIndex(item => e.id === item.id)), (this.targetShow = false); } "
@close="targetShow = false" />
<!-- 目标 end -->
<!-- 目标体重 start-->
<view class="files" @click="targetWeightShow = true">
<view class="name">目标体重</view>
<view class="text"><u-icon class="target-icon" :label="recordsData.goal_weight + ` KG`" name="arrow-right" color="#999" size="14" labelSize="14" labelColor="#666" labelPos="left" space="10" /></view>
</view>
<u-popup :show="targetWeightShow" @close="() => { targetWeightShow = false }">
<view class="v-scale">
<view class="title"> 你的目标体重为?</view>
<view class="total"> {{recordsData.goal_weight}} KG </view>
<vue-scale :min="10" :max="100" :int="false" :single="10" :h="80" :styles="styles" @scroll="scrollAll('goalweight',$event)" :scrollLeft="Number(recordsData.goal_weight)" />
</view>
</u-popup>
<!-- 目标体重 end -->
<!-- 目标体重 start-->
<view class="files" @click="targetWeightShow = true">
<view class="name">目标体重</view>
<view class="text">
<u-icon class="target-icon" :label="recordsData.goal_weight + ` KG`" name="arrow-right" color="#999"
size="14" labelSize="14" labelColor="#666" labelPos="left" space="10" />
</view>
</view>
<u-popup :show="targetWeightShow" @close="() => { targetWeightShow = false }">
<view class="v-scale">
<view class="title"> 你的目标体重为?</view>
<view class="total"> {{recordsData.goal_weight}} KG </view>
<vue-scale :min="10" :max="100" :int="false" :single="10" :h="80" :styles="styles"
@scroll="scrollAll('goalweight',$event)" :scrollLeft="Number(recordsData.goal_weight)" />
</view>
</u-popup>
<!-- 目标体重 end -->
<!-- 运动量 start -->
<view class="files" @click="exerciseShow = true">
<view class="name">运动量</view>
<view class="text">
<u-icon class="target-icon" :label="exerciseList[selectExerciseIndex].name" name="arrow-right" color="#999" size="14" labelSize="14" labelColor="#666" labelPos="left" space="10" />
</view>
</view>
<u-action-sheet
:actions="exerciseList"
title="你的运动量是?"
:show="exerciseShow"
cancelText="暂不修改"
@select=" e => { (this.selectExerciseIndex = this.exerciseList.findIndex(item => e.id === item.id)), (this.exerciseShow = false); } "
@close="exerciseShow = false"
/>
<!-- 运动量 end -->
<view class="sureBtn" @click="sureBtn"> 确认修改 </view>
<view class="des">修改资料后可更新并查看最新方案预算热量可能会发生变化</view>
</view>
<!-- 运动量 start -->
<view class="files" @click="exerciseShow = true">
<view class="name">运动量</view>
<view class="text">
<u-icon class="target-icon" :label="exerciseList[selectExerciseIndex].name" name="arrow-right"
color="#999" size="14" labelSize="14" labelColor="#666" labelPos="left" space="10" />
</view>
</view>
<u-action-sheet :actions="exerciseList" title="你的运动量是?" :show="exerciseShow" cancelText="暂不修改"
@select=" e => { (this.selectExerciseIndex = this.exerciseList.findIndex(item => e.id === item.id)), (this.exerciseShow = false); } "
@close="exerciseShow = false" />
<!-- 运动量 end -->
<view class="sureBtn" @click="sureBtn"> 确认修改 </view>
<view class="des">修改资料后可更新并查看最新方案预算热量可能会发生变化</view>
</view>
</template>
<script>
import { editHealthBefore,editHealth } from '@/apis/interfaces/essentialInfo.js';
import moment from 'moment';
import vueScale from '@/components/vueScale'; // 体重标尺
export default {
components:{
vueScale
},
data() {
return {
recordsData: {},
birthdayShow: false, // 出生日期展示
maxDate: new Date().getTime(),
sexShow: false, // 性别弹窗是否显示
sexList: [{name: '男士',id: 1},{name: '女士',id: 2}],
targetShow: false, // 目标弹窗是否显示
targetList: [{name: '减脂',id: 1},{name: '保持体重',id: 2},{name: '增肌',id: 3}],
selectedTargetIndex: 0,// 默认选择了那个target
exerciseShow:false,// 运动量弹窗是否显示
exerciseList:[{name:'久坐不动',id:1},{name:'少量运动',id:2},{name:'中等运动量',id:3},{name:'超强度运动',id:4}],
selectExerciseIndex:0,//默认选择运动量是久坐不懂得
heightShow:false,
weightShow:false,
targetWeightShow:false,
styles: {
line: '#dbdbdb',
bginner: '#fbfbfb',
bgoutside: '#ffffff',
font: '#404040',
fontColor: '#404040',
fontSize: 16
},
};
},
computed: {
showBirthday() {
return moment(this.recordsData.birthday).format('YYYY年MM月DD日');
}
},
import {
editHealthBefore,
editHealth
} from '@/apis/interfaces/essentialInfo.js';
import moment from 'moment';
import vueScale from '@/components/vueScale'; // 体重标尺
export default {
components: {
vueScale
},
data() {
return {
recordsData: {},
birthdayShow: false, // 出生日期展示
maxDate: new Date().getTime(),
sexShow: false, // 性别弹窗是否显示
sexList: [{
name: '男士',
id: 1
}, {
name: '女士',
id: 2
}],
targetShow: false, // 目标弹窗是否显示
targetList: [{
name: '减脂',
id: 1
}, {
name: '保持体重',
id: 2
}, {
name: '增肌',
id: 3
}],
selectedTargetIndex: 0, // 默认选择了那个target
exerciseShow: false, // 运动量弹窗是否显示
exerciseList: [{
name: '久坐不动',
id: 1
}, {
name: '少量运动',
id: 2
}, {
name: '中等运动量',
id: 3
}, {
name: '超强度运动',
id: 4
}],
selectExerciseIndex: 0, //默认选择运动量是久坐不懂得
heightShow: false,
weightShow: false,
targetWeightShow: false,
styles: {
line: '#dbdbdb',
bginner: '#fbfbfb',
bgoutside: '#ffffff',
font: '#404040',
fontColor: '#404040',
fontSize: 16
},
};
},
computed: {
showBirthday() {
return moment(this.recordsData.birthday).format('YYYY年MM月DD日');
}
},
onShow() {
let id = this.$Route.query.id;
editHealthBefore(id)
.then(res => {
this.recordsData = res;
this.recordsData.birthday = moment(res.birthday).format('YYYY-MM-DD');
this.selectExerciseIndex = this.exerciseList.findIndex(item => item.id === res.exercise)
})
.catch(err => {
conso.log(err);
});
},
methods: {
// 身高 体重 目标体重 滚动
scrollAll(type,value) {
if(type === 'height'){
return this.recordsData.height = value;
}
if(type === 'weight'){
return this.recordsData.weight = value;
}
if(type === 'goalweight'){
return this.recordsData.goal_weight = value;
}
},
// 年龄 - 过滤 - 自定义 - 出生年月日
formatter(type, value) {
if (type === 'year') {return `${value}`;}
if (type === 'month') {return `${value}`;}
if (type === 'day') {return `${value}`;}
return value;
},
// 提交按钮
sureBtn(){
let params = {
record_id:this.recordsData.record_id,
birthday:moment(this.recordsData.birthday).format('YYYY-MM-DD'),
sex:this.recordsData.sex,
height:this.recordsData.height,
weight:this.recordsData.weight,
exercise:this.exerciseList[this.selectExerciseIndex].id,
goal_weight:this.recordsData.goal_weight,
days:1
}
editHealth(params.record_id,params).then(res=>{
this.$Router.back()
}).catch(err=>{
this.$Router.back()
})
}
}
};
onShow() {
let id = this.$Route.query.id;
editHealthBefore(id)
.then(res => {
this.recordsData = res;
this.recordsData.birthday = moment(res.birthday).format('YYYY-MM-DD');
this.selectExerciseIndex = this.exerciseList.findIndex(item => item.id === res.exercise)
})
.catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
});
},
methods: {
// 身高 体重 目标体重 滚动
scrollAll(type, value) {
if (type === 'height') {
return this.recordsData.height = value;
}
if (type === 'weight') {
return this.recordsData.weight = value;
}
if (type === 'goalweight') {
return this.recordsData.goal_weight = value;
}
},
// 年龄 - 过滤 - 自定义 - 出生年月日
formatter(type, value) {
if (type === 'year') {
return `${value}`;
}
if (type === 'month') {
return `${value}`;
}
if (type === 'day') {
return `${value}`;
}
return value;
},
// 提交按钮
sureBtn() {
let params = {
record_id: this.recordsData.record_id,
birthday: moment(this.recordsData.birthday).format('YYYY-MM-DD'),
sex: this.recordsData.sex,
height: this.recordsData.height,
weight: this.recordsData.weight,
exercise: this.exerciseList[this.selectExerciseIndex].id,
goal_weight: this.recordsData.goal_weight,
days: 1
}
editHealth(params.record_id, params).then(res => {
this.$Router.back()
}).catch(err => {
uni.showToast({
title: err.message,
icon: "none",
duration: 2000,
mask: true
})
this.$Router.back()
})
}
}
};
</script>
<style lang="scss" scoped>
.content {
padding: $padding;
}
.files {
display: flex;
padding: $padding + 10 $padding - 20;
box-sizing: border-box;
border-bottom: #f9f9f9 2rpx solid;
font-size: $title-size;
&:last-child {
border: none;
}
.name {
flex: 1;
}
.text {
color: $text-gray;
}
}
.v-scale{
padding: $padding * 2 0;
font-size: $title-size;
.title{
text-align: center;
font-size: $title-size + 10;
margin-bottom: $margin;
}
.total{
font-size: $title-size;
color: $main-color;
text-align: center;
}
}
.des {
color: $text-gray-m;
font-size: $title-size-m - 4;
margin-top: $margin * 2;
text-align: center;
}
.sureBtn{
background-color: $main-color;
color: #fff;
font-size: $title-size;
text-align: center;
padding: $padding;
border-radius: $radius;
margin-top: $margin * 2;
}
.bt30 {
border-bottom: #f9f9f9 20rpx solid;
}
.content {
padding: $padding;
}
.files {
display: flex;
padding: $padding + 10 $padding - 20;
box-sizing: border-box;
border-bottom: #f9f9f9 2rpx solid;
font-size: $title-size;
&:last-child {
border: none;
}
.name {
flex: 1;
}
.text {
color: $text-gray;
}
}
.v-scale {
padding: $padding * 2 0;
font-size: $title-size;
.title {
text-align: center;
font-size: $title-size + 10;
margin-bottom: $margin;
}
.total {
font-size: $title-size;
color: $main-color;
text-align: center;
}
}
.des {
color: $text-gray-m;
font-size: $title-size-m - 4;
margin-top: $margin * 2;
text-align: center;
}
.sureBtn {
background-color: $main-color;
color: #fff;
font-size: $title-size;
text-align: center;
padding: $padding;
border-radius: $radius;
margin-top: $margin * 2;
}
.bt30 {
border-bottom: #f9f9f9 20rpx solid;
}
</style>

View File

@@ -155,12 +155,10 @@
if (this.$store.state.token === '') return;
info()
.then(res => {
console.log(res);
uni.setNavigationBarTitle({
title: res.nickname
});
this.userInfo = res;
console.log(res);
})
.catch(err => {
uni.showToast({
@@ -318,7 +316,7 @@
.user-content {
padding-left: 158rpx;
height: 128rpx;
height: 140rpx;
display: flex;
flex-direction: column;
justify-content: center;

View File

@@ -4,16 +4,16 @@ import {
} from 'uni-simple-router';
import store from '@/store/index'
// #ifdef APP-NVUE
// CALL 页面必须是nvue但是NVUE 不支持webpack的 ROUTES 注入
// https://github.com/SilurianYang/uni-read-pages/issues/20
// #ifdef APP-NVUE
const ROUTES = [{
'path': '/pages/im/private/call',
'name': 'imPrivateCall'
},{
'path': '/pages/im/private/chat',
'name': 'imPrivateChat'
}]
"path": "/pages/im/private/call"
}, {
"path": "/pages/im/private/chat"
}, {
"path": "/pages/im/group/chat"
}];
// #endif
const router = createRouter({

View File

@@ -1,6 +1,6 @@
@font-face {
font-family: "iconfont"; /* Project id 2869797 */
src: url('@/static/iconfont.ttf') format('truetype');
src: url('@/static/iconfont.ttf');
}
.iconfont {
@@ -11,6 +11,10 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-jia:before {
content: "\e60a";
}
.icon-dui:before {
content: "\e609";
}

Binary file not shown.

BIN
static/imgs/curve-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
static/imgs/curve-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
static/imgs/no-weight.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

BIN
static/imgs/speed-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
static/imgs/speed-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
static/imgs/water-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
static/imgs/water-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -2,98 +2,144 @@ import im from "@/utils/im/index.js"
export default {
state: {
friends: {},
sender: {},
contacts: {},
myInfo: {}
},
getters: {
friends(state) {
return state.friends
contacts(state) {
return state.contacts
},
userInfo: (state) => (targetId) => {
if (state.friends[targetId]) {
return state.friends[targetId]
contactInfo: (state) => (targetId) => {
if (state.contacts[targetId]) {
const info = state.contacts[targetId]
return {
name: info.name,
hash: info.hash,
portraitUrl: info.localAvatar ? info.localAvatar : require('@/static/user/cover.png')
}
} else {
console.log('没找到,死循环了,得处理 todo', targetId);
// im.syncUserInfo(targetId)
return {
name: '',
address: '',
hash: '',
portraitUrl: ''
}
}
},
hasUser: (state) => (targetId) => {
return Boolean(state.friends[targetId])
// 联系人是否存在
contactIsExist: (state) => (targetId) => {
return Boolean(state.contacts[targetId])
},
sender(state) {
return state.sender
return state.myInfo
}
},
mutations: {
updateFriends(state, userInfo) {
Vue.set(state.friends, userInfo.userId, userInfo)
updateContactInfo(state, contactInfo) {
Vue.set(state.contacts, contactInfo.targetId, contactInfo)
},
SET_state_sender(state, userInfo) {
state.sender = userInfo
setSenderInfo(state, contactInfo) {
state.myInfo = {
userId: contactInfo.targetId,
name: contactInfo.name,
portraitUrl: contactInfo.portraitUrl
}
}
},
actions: {
setSenderInfo({
commit
}, userInfo) {
commit('SET_state_sender', userInfo)
}, contactInfo) {
commit('setSenderInfo', contactInfo)
},
updateFriends({
// 载入好友信息
launchContact({
commit
}, userInfo) {
commit('updateFriends', userInfo)
const model = uni.model.friendModel
model.find('userId=' + userInfo.userId, (err, user) => {
if (!err && user.length == 0) {
saveAvatar(userInfo, (savedFilePath) => {
model.insert({
userId: userInfo.userId,
name: userInfo.name,
hash: userInfo.hash,
address: userInfo.address,
portraitUrl: savedFilePath,
}, (err, result) => {})
userInfo.portraitUrl = savedFilePath
commit('updateFriends', userInfo)
})
} else if (!err && user[0].hash != userInfo.hash) {
saveAvatar(userInfo, (savedFilePath) => {
model.update('userId=' + userInfo.userId, {
name: userInfo.name,
hash: userInfo.hash,
portraitUrl: savedFilePath,
}, (err, result) => {})
userInfo.portraitUrl = savedFilePath
commit('updateFriends', userInfo)
})
} else if (!err && user[0].portraitUrl.length > 50) {
saveAvatar(userInfo, (savedFilePath) => {
model.update('userId=' + userInfo.userId, {
name: userInfo.name,
hash: userInfo.hash,
portraitUrl: savedFilePath,
}, (err, result) => {})
userInfo.portraitUrl = savedFilePath
commit('updateFriends', userInfo)
})
}, data) {
commit('updateContactInfo', data)
},
// 更新好友信息这个时候要校验hash值了
updateContact({
commit,
dispatch
}, contactInfo) {
const model = uni.model.contactModel
model.find('targetId="' + contactInfo.targetId + '"', (err, result) => {
if (result.length == 0) {
// 没有数据,直接新增一条
dispatch('initContact', contactInfo)
} else if (contactInfo.hash != result[0].hash) {
commit('updateContactInfo', contactInfo)
if (contactInfo.portraitUrl && contactInfo.portraitUrl != result[0].portraitUrl) {
saveAvatar(contactInfo, (savedFilePath) => {
const info = {
targetId: contactInfo.targetId,
name: contactInfo.name,
hash: contactInfo.hash,
portraitUrl: contactInfo.portraitUrl,
localAvatar: savedFilePath
}
model.update('targetId="' + contactInfo.targetId + '"', info, (err,
res) => {
console.log('UPDATE AVATAR, ERR', err);
})
commit('updateContactInfo', info)
})
} else {
const info = {
targetId: contactInfo.targetId,
name: contactInfo.name,
hash: contactInfo.hash,
portraitUrl: contactInfo.portraitUrl,
localAvatar: result[0].localAvatar
}
model.update('targetId="' + contactInfo.targetId + '"', info, (err, res) => {
console.log('UPDATE NAME, ERR', err);
})
}
} else {
console.log('不用操作', user[0]);
console.log('updateContact, 无操作');
}
})
},
// 初始化好友信息
initContact({
commit
}, contactInfo) {
// 将好友信息保存到vuex的内存中方便立即使用
commit('updateContactInfo', contactInfo)
const model = uni.model.contactModel
// 用户头像,是否需要下载到本地
if (contactInfo.portraitUrl) {
saveAvatar(contactInfo, (savedFilePath) => {
const info = {
targetId: contactInfo.targetId,
name: contactInfo.name,
hash: contactInfo.hash,
portraitUrl: contactInfo.portraitUrl,
localAvatar: savedFilePath
}
model.insert(info, (err, res) => {})
// 保存头像后,更新信息
commit('updateContactInfo', info)
})
} else {
// 直接将信息,写入数据库
const info = {
targetId: contactInfo.targetId,
name: contactInfo.name,
hash: contactInfo.hash,
portraitUrl: contactInfo.portraitUrl,
localAvatar: ''
}
model.insert(info, (err, res) => {})
}
}
}
}
const saveAvatar = (userInfo, callback) => {
const saveAvatar = (contactInfo, callback) => {
uni.downloadFile({
url: userInfo.portraitUrl,
url: contactInfo.portraitUrl,
success: ({
tempFilePath
}) => {
@@ -106,8 +152,6 @@ const saveAvatar = (userInfo, callback) => {
}
})
},
fail: (err) => {
console.log('头像保存失败', err);
}
fail: (err) => {}
})
}

File diff suppressed because it is too large Load Diff

16
utils/im/data.js Normal file
View File

@@ -0,0 +1,16 @@
// 获取新好友申请数量
const getPendingCount = (callback) => {
RongIMLib.getConversationList([RongIMLib.ConversationType.SYSTEM], 100, 0, (res) => {
if (res.code === 0) {
const pendingCount = res.conversations.filter((item) => {
return item.objectName == RongIMLib.ObjectName.ContactNotification
}).length
callback(pendingCount)
}
})
}
export default {
getPendingCount
}

View File

@@ -1,23 +0,0 @@
[{
"objectName": "RC:TxtMsg",
"receivedTime": 1643080237399,
"extra": "",
"messageUId": "BUFC-3FSU-OLE4-I31K",
"conversationType": 1,
"messageDirection": 2,
"senderUserId": "10041",
"content": {
"content": "你好,这是 1710 条消息条消息条消息条消息条消息条消息条消息条消息条消息0.97796900 1642741562",
"objectName": "RC:TxtMsg",
"userInfo": {
"userId": "10041",
"name": "我是eth",
"portraitUrl": "http://storage.zh.shangkelian.cn/images/2022/01/12/3d2a103386df6822db7e5290272e8bc2.png"
}
},
"targetId": "10041",
"sentTime": 1642741563003,
"messageId": 2,
"receivedStatus": 1,
"sentStatus": 30
}]

View File

@@ -2,6 +2,7 @@ import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import * as CallLib from '@/uni_modules/RongCloud-CallWrapper/lib/index'
import store from '@/store/index.js'
import message from './message.js'
import listeners from './listeners.js'
import {
getFriends,
getUserInfo,
@@ -10,7 +11,7 @@ import {
const initIm = (KEY) => {
RongIMLib.init(KEY)
CallLib.init()
// CallLib.init()
addListeners()
// 初始化的时候 自动链接
if (store.getters.getToken !== '') {
@@ -47,25 +48,37 @@ const setNotifyBadge = () => {
/**
* 连接IM服务
* @param {string} token token
* @param {object} userInfo {userId: string, name: string, portraitUrl: string}
* @param {object} userInfo {targetId: string, name: string, portraitUrl: string}
*/
const connect = (token, userInfo, callback) => {
RongIMLib.connect(token, res => {
console.log('连接结果', res);
callback(res)
})
// 更新个人信息
store.dispatch('setSenderInfo', userInfo)
// 设置未读消息数量
setNotifyBadge()
// 首次运行获取好友列表
const FK = 'IFT_' + userInfo.targetId
store.dispatch('setSenderInfo', userInfo)
setNotifyBadge()
const model = uni.model.friendModel
model.find((err, results) => {
console.log('好友列表', results);
results.map(item => {
store.dispatch('updateFriends', item)
uni.getStorage({
key: FK,
success: () => {
const model = uni.model.contactModel
model.find((err, results) => {
results.map(item => {
store.dispatch('launchContact', item)
})
})
},
fail: () => {
// 程序是首次运行,初始化加载好友信息
getFriends().then(res => {
res.map(item => {
store.dispatch('initContact', item)
})
uni.setStorageSync(FK, userInfo.targetId)
})
}
})
})
}
@@ -102,25 +115,42 @@ const notifyMsgTypes = [
function inArray(search, array) {
for (var i in array) {
if (array[i] == search) {
return true;
return true
}
}
return false;
return false
}
const addListeners = () => {
// 添加连接状态监听函数
RongIMLib.addConnectionStatusListener((res) => {
console.log('连接状态监听', res.data.status);
console.log('连接状态监听', res.data.status)
uni.$emit('onConnectionStatusChange', res.data.status)
})
// 添加消息监听函数
RongIMLib.addReceiveMessageListener((res) => {
console.log('收到消息', res.data.message);
const message = res.data.message
console.log('收到消息', message)
if (inArray(message.objectName, notifyMsgTypes)) {
console.log('new Message');
if (!store.getters.contactIsExist(message.targetId)) {
getUserInfo(message.targetId).then(res => {
store.dispatch('initContact', res)
}).catch(err => {
console.log('ERR', err)
})
}
newMessage(message)
} else if (message.objectName === RongIMLib.ObjectName.ProfileNotification) {
store.dispatch('updateContact', JSON.parse(message.content.data))
// 调用完更新之后,删除这条消息
RongIMLib.deleteMessagesByIds([message.messageId], ({
code
}) => {
console.log('消息删除结果', code)
})
} else if (message.objectName === RongIMLib.ObjectName.ContactNotification) {
// 触发一个新好友的通知事件
uni.$emit('onContactNotification', message.content)
}
})
@@ -133,40 +163,40 @@ const addListeners = () => {
// 音视频通话相关的
// 监听通话呼入
CallLib.onCallReceived(({
data
}) => {
uni.navigateTo({
url: '/pages/im/private/call?targetId=' + data.targetId + '&mediaType=' +
data.mediaType
})
})
// 通话建立成功
CallLib.onCallConnected(() => {
uni.$emit('onCallConnected');
})
// 外呼
CallLib.onCallOutgoing((res) => {
uni.$emit('onCallOutgoing');
})
// 远端响铃
CallLib.onRemoteUserRinging((res) => {
uni.$emit('onRemoteUserRinging');
})
// 远端加入
CallLib.onRemoteUserJoined((res) => {
uni.$emit('onRemoteUserJoined');
})
// 断开链接
CallLib.onCallDisconnected((res) => {
console.log('断开链接', res);
uni.$emit('onCallDisconnected');
})
// 远端挂断
CallLib.onRemoteUserLeft((res) => {
console.log('远端离开', res);
uni.$emit('onRemoteUserLeft');
})
// CallLib.onCallReceived(({
// data
// }) => {
// uni.navigateTo({
// url: '/pages/im/private/call?targetId=' + data.targetId + '&mediaType=' +
// data.mediaType
// })
// })
// // 通话建立成功
// CallLib.onCallConnected(() => {
// uni.$emit('onCallConnected')
// })
// // 外呼
// CallLib.onCallOutgoing((res) => {
// uni.$emit('onCallOutgoing')
// })
// // 远端响铃
// CallLib.onRemoteUserRinging((res) => {
// uni.$emit('onRemoteUserRinging')
// })
// // 远端加入
// CallLib.onRemoteUserJoined((res) => {
// uni.$emit('onRemoteUserJoined')
// })
// // 断开链接
// CallLib.onCallDisconnected((res) => {
// console.log('断开链接', res)
// uni.$emit('onCallDisconnected')
// })
// // 远端挂断
// CallLib.onRemoteUserLeft((res) => {
// console.log('远端离开', res)
// uni.$emit('onRemoteUserLeft')
// })
}
// 维护消息列表,检查是否需要通知声音,设置新消息提醒的数量
@@ -177,24 +207,13 @@ const newMessage = (msg) => {
}) => {
if (code === 0) {
if (status) {
uni.vibrateLong()
triTone()
}
}
});
setNotifyBadge()
if (!store.getters.hasUser(msg.targetId)) {
syncUserInfo(msg.targetId)
}
uni.$emit('onReceiveMessage', msg);
}
function syncUserInfo(targetId) {
getUserInfo(targetId).then(res => {
store.dispatch('updateFriends', res)
})
setNotifyBadge()
uni.$emit('onReceiveMessage', msg)
}
// 播放状态
@@ -215,23 +234,9 @@ const triTone = () => {
}
}
/**
* 同步好友信息,保存头像地址等
*/
const syncFriends = () => {
getFriends().then(res => {
res.map(item => {
console.log('item', item);
store.dispatch('updateFriends', item)
})
})
}
export default {
initIm,
connect,
setNotifyBadge,
syncFriends,
syncUserInfo,
...message
}

0
utils/im/listeners.js Normal file
View File

View File

@@ -1,8 +1,9 @@
import store from '@/store/index.js'
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
const getMessageList = (conversationType, targetId, timeStamp, count, isForward, callback) => {
// 获取消息列表
// 获取消息列表 https://doc.rongcloud.cn/imserver/server/v1/message/objectname#objectName
const objectNames = [
'RC:TxtMsg',
'RC:VcMsg',
@@ -40,6 +41,21 @@ const getMessageList = (conversationType, targetId, timeStamp, count, isForward,
)
}
// 获取好友申请列表
const getPendingList = (callback, total) => {
total = total || 100
RongIMLib.getConversationList([RongIMLib.ConversationType.SYSTEM], total, 0, (res) => {
if (res.code === 0) {
const pendings = res.conversations.filter((item) => {
return item.objectName == RongIMLib.ObjectName.ContactNotification &&
item.latestMessage.operation === 'Request'
})
callback(pendings)
}
})
}
/**
* 发送文本消息
* @param {number} conversationType 消息类型
@@ -47,17 +63,17 @@ const getMessageList = (conversationType, targetId, timeStamp, count, isForward,
* @param {string} content 消息内容
* @param {function} callback 回调函数
*/
const sentText = (conversationType, targetId, content, callback) => {
console.log('发送');
const sentText = (conversationType, targetId, content, user, callback) => {
const msg = {
conversationType: conversationType,
targetId: String(targetId),
content: {
objectName: 'RC:TxtMsg',
content: content,
user: store.getters.sender
userInfo: user
}
}
RongIMLib.sendMessage(msg, ({
code,
messageId
@@ -65,9 +81,10 @@ const sentText = (conversationType, targetId, content, callback) => {
if (code === 0) {
callback(messageId)
} else {
console.log('发送失败', msg);
uni.showToast({
icon: 'none',
title: '发送失败'
title: '发送失败' + code
})
}
})
@@ -81,14 +98,15 @@ const sentText = (conversationType, targetId, content, callback) => {
* @param {integer} time 录音时长
* @param {function} callback 录音时长
*/
const sentVoice = (conversationType, targetId, voiceUrl, time, callback) => {
const sentVoice = (conversationType, targetId, voiceUrl, time, user, callback) => {
const msg = {
conversationType: conversationType,
targetId: String(targetId),
content: {
objectName: 'RC:HQVCMsg',
local: 'file:///' + plus.io.convertLocalFileSystemURL(voiceUrl),
duration: time
duration: time,
userInfo: user
}
}
RongIMLib.sendMediaMessage(msg, {
@@ -107,13 +125,14 @@ const sentVoice = (conversationType, targetId, voiceUrl, time, callback) => {
})
}
const sentImage = (conversationType, targetId, imageUrl, callback) => {
const sentImage = (conversationType, targetId, imageUrl, user, callback) => {
const msg = {
conversationType: conversationType,
targetId: String(targetId),
content: {
objectName: 'RC:ImgMsg',
local: 'file:///' + plus.io.convertLocalFileSystemURL(imageUrl)
local: 'file:///' + plus.io.convertLocalFileSystemURL(imageUrl),
userInfo: user
}
}
RongIMLib.sendMediaMessage(msg, {
@@ -186,6 +205,7 @@ const sendFile = (conversationType, targetId, fileUrl, time, callback) => {
export default {
getMessageList,
getPendingList,
sentText,
sentVoice,
sentImage,

View File

@@ -2,21 +2,21 @@ import {
usqlite
} from '@/uni_modules/onemue-USQLite/js_sdk/usqlite.js'
const friendModel = usqlite.model('friends', {
userId: {
const contactModel = usqlite.model('contacts', {
targetId: {
type: String,
primaryKey: true,
unique: true
},
name: String,
address: String,
hash: {
type: String,
unique: true
},
portraitUrl: String
portraitUrl: String,
localAvatar: String
})
export default {
friendModel
contactModel
}

View File

@@ -1,51 +0,0 @@
{
"type": "Engine:OnCallReceived",
"module": "RongCloud-Call-RCUniCall",
"data": {
"endTime": 0,
"users": [{
"userId": "10051",
"enableCamera": false,
"mediaId": "420111350",
"mediaType": 1,
"userType": 0,
"enableMicrophone": false
}, {
"userId": "10047",
"enableCamera": false,
"mediaType": 1,
"userType": 0,
"enableMicrophone": false
}],
"inviter": {
"userId": "10051",
"enableCamera": false,
"mediaId": "420111350",
"mediaType": 1,
"userType": 0,
"enableMicrophone": false
},
"caller": {
"userId": "10051",
"enableCamera": false,
"mediaId": "420111350",
"mediaType": 1,
"userType": 0,
"enableMicrophone": false
},
"connectedTime": 0,
"extra": "",
"startTime": 0,
"mediaType": 1,
"callId": "c28cb9d8-6581-474c-bfa5-9872a4824b65",
"targetId": "10051",
"callType": 0,
"mine": {
"userId": "10047",
"enableCamera": false,
"mediaType": 1,
"userType": 0,
"enableMicrophone": false
}
}
}

View File

@@ -1,51 +0,0 @@
{
"type": "Engine:OnCallReceived",
"module": "RongCloud-Call-RCUniCall",
"data": {
"endTime": 0,
"users": [{
"userId": "10051",
"enableCamera": false,
"mediaId": "420068630",
"mediaType": 0,
"userType": 0,
"enableMicrophone": false
}, {
"userId": "10047",
"enableCamera": true,
"mediaType": 0,
"userType": 0,
"enableMicrophone": false
}],
"inviter": {
"userId": "10051",
"enableCamera": false,
"mediaId": "420068630",
"mediaType": 0,
"userType": 0,
"enableMicrophone": false
},
"caller": {
"userId": "10051",
"enableCamera": false,
"mediaId": "420068630",
"mediaType": 0,
"userType": 0,
"enableMicrophone": false
},
"connectedTime": 0,
"extra": "",
"startTime": 0,
"mediaType": 0,
"callId": "1a1462b8-b63b-40a9-bf95-963e810ac49a",
"targetId": "10051",
"callType": 0,
"mine": {
"userId": "10047",
"enableCamera": true,
"mediaType": 0,
"userType": 0,
"enableMicrophone": false
}
}
}