5-03 成人体验版

This commit is contained in:
qiaocl 2022-05-03 21:35:39 +08:00
parent 6670db5c19
commit 4797787bca
1102 changed files with 66693 additions and 0 deletions

56
App.vue Normal file
View File

@ -0,0 +1,56 @@
<script>
export default {
methods: {},
onLaunch() {
//
const updateManager = wx.getUpdateManager()
//
updateManager.onCheckForUpdate(function(res) {
console.log("是否有新版本", res.hasUpdate)
})
//
updateManager.onUpdateReady(function() {
wx.showModal({
title: '更新提示',
content: '新版本已经准备好,是否重启应用?',
success: function(res) {
if (res.confirm) {
// applyUpdate
updateManager.applyUpdate()
}
}
})
})
//
updateManager.onUpdateFailed(function() {
wx.showModal({
title: '新版本更新失败',
content: '请退出并移除小程序,重新打开...',
})
})
//
// uni.getSystemInfo({
// success: e => {
// let res = uni.getMenuButtonBoundingClientRect()
// let statusBarHeight = {
// BarTopHeight: res.top,
// BarTopLineHeight: res.height + 10,
// BarMarginTop: Number(res.top + res.height + 10)
// }
// this.$store.commit("handleBarHeight", statusBarHeight);
// console.log("", e, res)
// }
// })
},
mounted() {},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style lang="scss">
</style>

429
BLEPages/adult/F01B.vue Normal file
View File

@ -0,0 +1,429 @@
<template>
<view>
<view class="content weightPages">
<view class="title" v-if="isConnection == 0">连接中请稍后</view>
<view class="title" v-if="isConnection == 1">连接成功请开始测量</view>
<view class="title" v-if="isConnection == 2" @click="openBluetoothAdapter">连接失败点击重新连接</view>
<view class="text">{{text}}</view>
<view class="image">
<image src="/BLEPages/static/F018P01.gif" v-if="type==1"></image>
<image src="/BLEPages/static/F018P01.gif" v-if="type==2"></image>
</view>
<view class="tips">
<text>提示</text>
<text>1.请确定设备是开机状态</text>
<text>2.请确定手机蓝牙位置信息已打开</text>
<text>3.ios系统需打开设置>应用>微信里的蓝牙权限</text>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
var myTime;
export default {
data() {
return {
text: "",
height: "",
weight: "",
imp: 0,
type: 1,
uuid1: "",
uuid2: "",
uuid3: "",
macAddr: "",
deviceId: "",
serviceId: "",
Unload: false,
isConnection: 0, //
}
},
computed: {
...mapState(["user", "isConnected", "isBluetoothTyle"]),
info() {
return this.user
}
},
onUnload: function() {
let that = this
if (!that.Unload) {
that.stopBluetoothDevicesDiscovery() //
clearTimeout(myTime);
that.closeBLEConnection()
that.closeBluetoothAdapter()
console.log("返回上一个页面")
}
},
onLoad(options) {
let that = this
that.text = ""
if (options && options.deviceId) {
that.macAddr = options.deviceId
that.deviceId = options.deviceId
that.createBLEConnection()
}
that.onBLEConnectionStateChange()
uni.onBluetoothAdapterStateChange(function(res) {
that.$store.commit("changeBluetooth", res.available);
})
},
watch: {
isConnected: function() {
let that = this
if (!that.isConnected) {
that.handleBack()
that.isConnection = 2
}
},
isBluetoothTyle: function() {
let that = this
if (!that.isBluetoothTyle) {
that.handleBack()
that.isConnection = 2
}
},
},
methods: {
//
openBluetoothAdapter() {
let that = this
that.type = 1
uni.openBluetoothAdapter({
success: e => {
that.isConnection = 0
that.startBluetoothDeviceDiscovery()
},
fail: e => {
that.isConnection = 2
that.$tools.msg("请确定设备是开机状态、手机蓝牙权限已打开!")
}
});
},
//
startBluetoothDeviceDiscovery() {
let that = this
uni.startBluetoothDevicesDiscovery({
allowDuplicatesKey: false,
interval: 500, //
services: [
"FFE0",
],
success: res => {
that.isConnection = 0
that.onBluetoothDeviceFound();
},
fail: res => {
that.isConnection = 2
that.$tools.msg("请确定设备是开机状态、手机蓝牙权限已打开!")
}
});
},
/**
* 发现外围设备
*/
onBluetoothDeviceFound() {
var that = this;
that.isConnection = 0
uni.onBluetoothDeviceFound(res => {
res.devices.forEach(device => {
if (!device.name && !device.localName) {
return
}
if (device.deviceId.indexOf(that.deviceId) != -1) {
that.stopBluetoothDevicesDiscovery()
clearTimeout(myTime);
let buff = device.advertisData.slice(-6)
device.mac = new Uint8Array(buff) // 广maciOSmac
let tempMac = Array.from(device.mac)
tempMac.reverse()
device.macAddr = that.$tools.ab2hex(tempMac, ':').toUpperCase()
that.macAddr = device.macAddr
that.deviceId = device.deviceId;
that.createBLEConnection()
return;
}
})
});
that.handleMyTime()
},
handleMyTime() {
var that = this;
myTime = setTimeout(function() {
if (!that.macAddr) {
clearTimeout(myTime);
that.Unload = true
that.isConnection = 2
that.closeBLEConnection()
that.closeBluetoothAdapter()
}
}, 20000);
},
/**
* 停止搜索蓝牙设备
*/
stopBluetoothDevicesDiscovery() {
uni.stopBluetoothDevicesDiscovery({
success: e => {
console.log("停止搜索蓝牙设备", e)
},
});
},
//
onBLEConnectionStateChange() {
let that = this
uni.onBLEConnectionStateChange(function(res) {
console.log("监听蓝牙连接状态", res.connected)
if (!res.connected) {
clearTimeout(myTime);
that.Unload = true
that.isConnection = 2
that.closeBLEConnection()
that.closeBluetoothAdapter()
}
that.$store.commit("changeConnected", res.connected);
})
},
//
createBLEConnection() {
let that = this;
uni.createBLEConnection({
deviceId: that.deviceId,
success: res => {
that.isConnection = 0
that.getBLEDeviceServices();
},
fail: res => {
that.isConnection = 2
console.log("设备连接失败,请重新连接", res);
}
});
},
/**
* 获取设备的UUID
*/
getBLEDeviceServices() {
let serviceList = [];
let that = this;
uni.getBLEDeviceServices({
deviceId: that.deviceId,
success: res => {
console.log("获取设备的UUID成功", res)
serviceList = res.services;
for (let i = 0; i < serviceList.length; i++) {
let service = serviceList[i];
if (service.uuid.indexOf("FFE0") != -1) {
that.isConnection = 1
that.serviceId = service.uuid;
that.getBLEDeviceCharacteristics();
console.log("设备的FFE0的serviceId " + that.serviceId);
break;
}
}
},
fail: res => {
console.log('获取设备的UUID失败:', res)
}
});
},
/**
* 获取指定服务的特征值
*/
getBLEDeviceCharacteristics() {
let characteristicsList = [];
let that = this;
uni.getBLEDeviceCharacteristics({
deviceId: that.deviceId,
serviceId: that.serviceId,
success: res => {
console.log("服务的特征值成功", res)
for (let i = 0; i < res.characteristics.length; i++) {
let item = res.characteristics[i];
if (item.uuid.indexOf('0000FFE1') != -1) {
that.uuid1 = item.uuid //
} else if (item.uuid.indexOf('0000FFE2') != -1) {
that.uuid2 = item.uuid //
} else if (item.uuid.indexOf('0000FFE3') != -1) {
that.uuid3 = item.uuid //
that.notifyBLECharacteristicValue()
}
}
},
fail: res => {
console.log('获取特征值失败:', JSON.stringify(res))
}
})
},
/**
* 开启订阅特征值
* read: true, //,write: true, //,notify: true, //广
*/
notifyBLECharacteristicValue() {
let that = this;
uni.notifyBLECharacteristicValueChange({
state: true, // notify
deviceId: that.deviceId,
serviceId: that.serviceId,
characteristicId: that.uuid3,
success(res) {
uni.onBLECharacteristicValueChange(function(res) {
let value = that.$tools.ab2hex(res.value, "");
let num = value.substring(18, 19)
let dw = value.substring(19, 20)
let type = value.substring(8, 10)
let typeInfo = value.substring(10, 12)
if (type == "10") {
let data = parseInt(value.substring(13, 18), 16)
let dw1 = "kg"
let dw2 = "kg"
if (dw == "1") {
dw1 = "斤"
dw2 = "jin"
}
if (dw == "4") {
dw1 = "st:lb"
dw2 = "st"
data = 1 * data + 5
}
if (dw == "6") {
dw1 = "lb"
dw2 = "lb"
}
if (num == "1") {
data = parseInt(value.substring(13, 18), 16) / 10
}
if (num == "2") {
data = parseInt(value.substring(13, 18), 16) / 100
}
if (num == "3") {
data = parseInt(value.substring(13, 18), 16) / 1000
}
if (typeInfo == "01") {
that.text = "您的实时体重是:" + data + dw1
}
if (typeInfo == "02") {
that.text = "您的体重是:" + data + dw1
that.weight = data + dw2
console.log("稳定体重:", value, that.weight)
}
}
if (type == "11") {
if (typeInfo == "03") {
that.imp = parseInt(value.substring(17, 22), 16)
}
console.log("体脂:", that.imp)
}
if (type == "14") { //
that.height = parseInt(value.substring(10, 14), 16) / 10
that.type = 2
console.log("身高模式:", that.height)
}
if (type == "30") {
console.log("测量完成", that.weight, that.height, that.imp)
if (that.imp == 0) {
uni.showModal({
title: '提示',
content: "体脂测量失败,是否保存本次测量结果?",
cancelText: "放弃",
confirmText: "保存",
success(res) {
if (res.confirm) {
that.imp = 0
that.handleGetMeasure()
} else {
that.Unload = true
that.closeBLEConnection()
that.closeBluetoothAdapter()
uni.navigateBack({
delta: 1
})
}
}
})
} else {
that.handleGetMeasure()
}
}
});
},
fail(res) {
console.log("测量失败", res.value);
}
});
},
//
handleGetMeasure() {
let that = this
that.$model.getmeasure({
weight: that.weight,
imp: that.imp,
ecode: that.macAddr,
height: that.height,
familyid: that.info.familyid,
}).then(res => {
if (res.code == 0) {
that.$tools.msg("测量成功")
that.$store.dispatch("getUserInfo", {
familyid: that.info.familyid,
});
that.$store.dispatch("getResult", {
birthday: that.info.birthday,
familyid: that.info.familyid,
height: that.height,
sex: that.info.sex,
});
} else {
console.log("测量失败", res.message)
that.$tools.msg(res.message)
}
that.Unload = true
setTimeout(function() {
that.closeBLEConnection()
that.closeBluetoothAdapter()
uni.switchTab({
url: "/pages/index/index"
})
}, 200)
})
},
handleBack(ind) {
let that = this
that.text = ""
that.Unload = true
that.stopBluetoothDevicesDiscovery() //
that.closeBLEConnection()
that.closeBluetoothAdapter()
clearTimeout(myTime)
},
/**
* 断开蓝牙模块
*/
closeBluetoothAdapter() {
let that = this;
uni.closeBluetoothAdapter({
success: res => {
console.log('蓝牙模块关闭成功');
}
})
},
/**
* 断开蓝牙连接
*/
closeBLEConnection() {
var that = this;
uni.closeBLEConnection({
deviceId: that.deviceId,
success: res => {
console.log('断开蓝牙连接成功');
}
});
},
},
}
</script>
<style scoped lang="scss">
</style>

383
BLEPages/adult/H01pro.vue Normal file
View File

@ -0,0 +1,383 @@
<template>
<view class="content weightPages">
<view class="title" v-if="isConnection == 0">连接中请稍后</view>
<view class="title" v-if="isConnection == 1">连接成功请开始测量</view>
<view class="title" v-if="isConnection == 2" @click="openBluetoothAdapter">连接失败点击重新连接</view>
<view class="text">{{textW}}</view>
<view class="text">{{textH}}</view>
<view class="image">
<image src="/BLEPages/static/H01pro.gif"></image>
</view>
<view class="tips">
<text>请确保</text>
<text>1.请确定设备是开机状态</text>
<text>2.请确定手机蓝牙位置信息已打开</text>
<text>3.ios系统需打开设置>应用>微信里的蓝牙权限</text>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
var myTime;
export default {
data() {
return {
textW: "",
textH: "",
height: "",
weight: "",
imp: 0,
macAddr: "",
deviceId: "",
serviceId: "",
readId: "",
writeId: "",
notifyId: "",
Unload: false,
isConnection: 0,
}
},
computed: {
...mapState(["user", "isConnected", "isBluetoothTyle"]),
info() {
return this.user
}
},
onUnload: function() {
let that = this
if (!that.Unload) {
that.stopBluetoothDevicesDiscovery() //
clearTimeout(myTime);
that.closeBLEConnection()
that.closeBluetoothAdapter()
console.log("页面返回onUnload")
}
},
watch: {
isConnected: function() {
let that = this
if (!that.isConnected) {
that.handleBack()
that.isConnection = 2
}
},
isBluetoothTyle: function() {
let that = this
if (!that.isBluetoothTyle) {
that.handleBack()
that.isConnection = 2
}
},
},
onLoad(options) {
let that = this
that.textW = ""
that.textH = ""
if (options && options.deviceId) {
that.macAddr = options.deviceId
that.deviceId = options.deviceId
that.createBLEConnection()
}
that.onBLEConnectionStateChange()
uni.onBluetoothAdapterStateChange(function(res) {
that.$store.commit("changeBluetooth", res.available);
})
},
methods: {
//
openBluetoothAdapter() {
let that = this
uni.openBluetoothAdapter({
success: e => {
that.isConnection = 0
that.startBluetoothDeviceDiscovery()
},
fail: e => {
that.isConnection = 2
that.$tools.msg("请确定设备是开机状态、手机蓝牙权限已打开!")
}
});
},
//
onBLEConnectionStateChange() {
let that = this
uni.onBLEConnectionStateChange(function(res) {
console.log("监听蓝牙连接状态", res.connected)
if (!res.connected) {
that.Unload = true
that.isConnection = 2
clearTimeout(myTime);
that.closeBLEConnection()
that.closeBluetoothAdapter()
}
that.$store.commit("changeConnected", res.connected);
})
},
//
startBluetoothDeviceDiscovery() {
let that = this
uni.startBluetoothDevicesDiscovery({
allowDuplicatesKey: false,
interval: 500, //
success: res => {
that.isConnection = 0
that.onBluetoothDeviceFound();
},
fail: res => {
that.isConnection = 2
that.$tools.msg("请确定设备是开机状态、手机蓝牙权限已打开!")
}
});
},
/**
* 发现外围设备
*/
onBluetoothDeviceFound() {
var that = this;
that.isConnection = 0
uni.onBluetoothDeviceFound(res => {
console.log('开始监听寻找到新设备的事件', res);
res.devices.forEach(device => {
if (!device.name && !device.localName) {
return
}
if (device.deviceId.indexOf(that.deviceId) != -1) {
that.stopBluetoothDevicesDiscovery() //
clearTimeout(myTime);
let buff = device.advertisData.slice(-6)
device.mac = new Uint8Array(buff) // 广maciOSmac
let tempMac = Array.from(device.mac)
device.macAddr = that.$tools.ab2hex(tempMac, ':').toUpperCase()
that.deviceId = device.macAddr
that.macAddr = device.macAddr
that.createBLEConnection()
return;
}
})
});
that.handleMyTime()
},
handleMyTime() {
var that = this;
myTime = setTimeout(function() {
if (!that.macAddr) {
clearTimeout(myTime);
that.Unload = true
that.isConnection = 2
that.closeBLEConnection()
that.closeBluetoothAdapter()
}
}, 20000);
},
/**
* 停止搜索蓝牙设备
*/
stopBluetoothDevicesDiscovery() {
uni.stopBluetoothDevicesDiscovery({
success: e => {
console.log("停止搜索蓝牙设备", e)
},
});
},
//
createBLEConnection() {
let that = this;
uni.createBLEConnection({
deviceId: that.deviceId,
success: res => {
that.isConnection = 0
that.getBLEDeviceServices();
},
fail: res => {
that.isConnection = 2
console.log("设备连接失败,请重新连接", res);
}
});
},
/**
* 获取设备的UUID
*/
getBLEDeviceServices() {
let serviceList = [];
let that = this;
uni.getBLEDeviceServices({
deviceId: that.deviceId,
success: res => {
console.log("获取设备的UUID成功", res)
serviceList = res.services;
for (let i = 0; i < serviceList.length; i++) {
let service = serviceList[i];
if (service.uuid.indexOf('FFE0') != -1) {
that.serviceId = service.uuid;
that.isConnection = 1
that.getBLEDeviceCharacteristics(that.deviceId, service.uuid);
console.log("设备的FFE0的serviceId ", that.serviceId);
break;
}
}
},
fail: res => {
console.log('获取设备的UUID失败:', res)
}
});
},
/**
* 获取指定服务的特征值
*/
getBLEDeviceCharacteristics(deviceId, serviceId) {
let characteristicsList = [];
let that = this;
uni.getBLEDeviceCharacteristics({
deviceId: deviceId,
serviceId: serviceId,
success: res => {
console.log("服务的特征值成功", res)
characteristicsList = res.characteristics;
for (let i = 0; i < characteristicsList.length; i++) {
let item = characteristicsList[i];
if (item.uuid.indexOf("FFE1") != -1) {
if (item.properties.notify == true) {
that.notifyId = item.uuid
}
if (item.properties.write == true) {
that.writeId = item.uuid
}
if (item.properties.read) {
that.readId = item.uuid
}
}
}
//
uni.notifyBLECharacteristicValueChange({
deviceId,
serviceId,
characteristicId: that.notifyId,
state: true,
})
uni.notifyBLECharacteristicValueChange({
deviceId,
serviceId,
characteristicId: that.writeId,
state: true,
})
uni.onBLECharacteristicValueChange(function(res) {
let value = that.$tools.ab2hex(res.value, '');
let weight = parseInt(value.substring(4, 8), 16) / 100
let height = parseInt(value.substring(30, 34), 16) / 10
let imp0 = value.substring(28, 30) + value.substring(34, 36)
let imp = parseInt(imp0, 16)
that.imp = imp
that.textW = "您的体重是:" + weight + 'kg'
that.textH = "您的身高是:" + height + 'cm'
that.weight = weight + 'kg'
that.height = height
console.log("测量完成", that.weight, that.height, that.imp)
if (imp == 0) {
uni.showModal({
title: '提示',
content: "体脂测量失败,是否保存本次测量结果?",
cancelText: "放弃",
confirmText: "保存",
success(res) {
if (res.confirm) {
that.handleGetMeasure()
} else {
that.Unload = true
that.closeBLEConnection()
that.closeBluetoothAdapter()
uni.navigateBack({
delta: 1
})
}
}
})
} else {
that.handleGetMeasure()
}
});
},
fail: res => {
console.log('获取特征值失败:', JSON.stringify(res))
}
})
},
//
handleGetMeasure() {
console.log("保存结果")
let that = this
that.$model.getmeasure({
weight: that.weight,
imp: that.imp,
ecode: that.macAddr,
height: that.height ? that.height : that.info.height,
familyid: that.info.familyid,
}).then(res => {
if (res.code == 0) {
that.$tools.msg("测量成功")
that.$store.dispatch("getUserInfo", {
familyid: that.info.familyid,
});
that.$store.dispatch("getResult", {
birthday: that.info.birthday,
familyid: that.info.familyid,
height: that.height ? that.height : that.info.height,
sex: that.info.sex,
});
} else {
console.log("测量失败", res.message)
that.$tools.msg(res.message)
}
that.Unload = true
setTimeout(function() {
that.closeBLEConnection()
that.closeBluetoothAdapter()
uni.switchTab({
url: "/pages/index/index"
})
}, 200)
})
},
handleBack() {
let that = this
that.textW = ""
that.textH = ""
that.Unload = true
that.Unload = true
that.stopBluetoothDevicesDiscovery() //
that.closeBLEConnection()
that.closeBluetoothAdapter()
},
/**
* 断开蓝牙模块
*/
closeBluetoothAdapter() {
let that = this;
uni.closeBluetoothAdapter({
success: res => {
console.log('蓝牙模块关闭成功');
}
})
},
/**
* 断开蓝牙连接
*/
closeBLEConnection() {
var that = this;
uni.closeBLEConnection({
deviceId: that.deviceId,
success: res => {
console.log('断开蓝牙连接成功');
}
});
},
},
}
</script>
<style scoped lang="scss">
</style>

449
BLEPages/adult/H09B.vue Normal file
View File

@ -0,0 +1,449 @@
<template>
<view>
<view class="content weightPages">
<view class="title" v-if="isConnection == 0">连接中请稍后</view>
<view class="title" v-if="isConnection == 1">连接成功请开始测量</view>
<view class="title" v-if="isConnection == 2" @click="openBluetoothAdapter">连接失败点击重新连接</view>
<view class="text">{{text}}</view>
<view class="text">{{textH}}</view>
<view class="image">
<image src="/BLEPages/static/H09B.gif" v-if="type == 1"></image>
<image src="/BLEPages/static/H09B2.gif" v-if="type == 2"></image>
</view>
<view class="tips">
<text>提示</text>
<text>1.请确定设备是开机状态</text>
<text>2.请确定手机蓝牙位置信息已打开</text>
<text>3.ios系统需打开设置>应用>微信里的蓝牙权限</text>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
var myTime;
export default {
data() {
return {
text: "",
textH: "",
height: "",
weight: "",
imp: 0,
type: 1,
uuid1: "",
uuid2: "",
uuid3: "",
macAddr: "",
deviceId: "",
serviceId: "",
Unload: false,
isConnection: 0, //
}
},
computed: {
...mapState(["user", "isConnected", "isBluetoothTyle"]),
info() {
return this.user
}
},
onUnload: function() {
let that = this
if (!that.Unload) {
that.stopBluetoothDevicesDiscovery() //
clearTimeout(myTime);
that.closeBLEConnection()
that.closeBluetoothAdapter()
}
},
onLoad(options) {
let that = this
that.text = ""
that.textH = ""
that.imp = 0
if (options && options.deviceId) {
that.macAddr = options.deviceId
that.deviceId = options.deviceId
that.createBLEConnection()
}
that.onBLEConnectionStateChange()
uni.onBluetoothAdapterStateChange(function(res) {
that.$store.commit("changeBluetooth", res.available);
})
},
watch: {
isConnected: function() {
let that = this
if (!that.isConnected) {
that.handleBack()
that.isConnection = 2
}
},
isBluetoothTyle: function() {
let that = this
if (!that.isBluetoothTyle) {
that.handleBack()
that.isConnection = 2
}
},
},
methods: {
//
openBluetoothAdapter() {
let that = this
that.type = 1
uni.openBluetoothAdapter({
success: e => {
that.isConnection = 0
that.startBluetoothDeviceDiscovery()
},
fail: e => {
that.isConnection = 2
that.$tools.msg("请确定设备是开机状态、手机蓝牙权限已打开!")
}
});
},
//
startBluetoothDeviceDiscovery() {
let that = this
uni.startBluetoothDevicesDiscovery({
allowDuplicatesKey: false,
interval: 500, //
services: [
"FFE0",
],
success: res => {
that.isConnection = 0
that.onBluetoothDeviceFound();
},
fail: res => {
that.isConnection = 2
that.$tools.msg("请确定设备是开机状态、手机蓝牙权限已打开!")
}
});
},
/**
* 发现外围设备
*/
onBluetoothDeviceFound() {
var that = this;
that.isConnection = 0
uni.onBluetoothDeviceFound(res => {
res.devices.forEach(device => {
if (!device.name && !device.localName) {
return
}
if (device.deviceId.indexOf(that.deviceId) != -1) {
that.stopBluetoothDevicesDiscovery()
clearTimeout(myTime);
let buff = device.advertisData.slice(-6)
device.mac = new Uint8Array(buff) // 广maciOSmac
let tempMac = Array.from(device.mac)
tempMac.reverse()
device.macAddr = that.$tools.ab2hex(tempMac, ':').toUpperCase()
that.macAddr = device.macAddr
that.deviceId = device.deviceId;
that.createBLEConnection()
return;
}
})
});
that.handleMyTime()
},
handleMyTime() {
var that = this;
myTime = setTimeout(function() {
if (!that.macAddr) {
clearTimeout(myTime);
that.Unload = true
that.isConnection = 2
that.closeBLEConnection()
that.closeBluetoothAdapter()
}
}, 20000);
},
/**
* 停止搜索蓝牙设备
*/
stopBluetoothDevicesDiscovery() {
uni.stopBluetoothDevicesDiscovery({
success: e => {
console.log("停止搜索蓝牙设备", e)
},
});
},
//
onBLEConnectionStateChange() {
let that = this
uni.onBLEConnectionStateChange(function(res) {
console.log("监听蓝牙连接状态", res.connected)
if (!res.connected) {
that.Unload = true
that.isConnection = 2
clearTimeout(myTime);
that.closeBLEConnection()
that.closeBluetoothAdapter()
}
that.$store.commit("changeConnected", res.connected);
})
},
//
createBLEConnection() {
let that = this;
uni.createBLEConnection({
deviceId: that.deviceId,
success: res => {
that.isConnection = 0
that.getBLEDeviceServices();
},
fail: res => {
that.isConnection = 2
console.log("设备连接失败,请重新连接", res);
}
});
},
/**
* 获取设备的UUID
*/
getBLEDeviceServices() {
let serviceList = [];
let that = this;
uni.getBLEDeviceServices({
deviceId: that.deviceId,
success: res => {
console.log("获取设备的UUID成功", res)
serviceList = res.services;
for (let i = 0; i < serviceList.length; i++) {
let service = serviceList[i];
if (service.uuid.indexOf("FFE0") != -1) {
that.isConnection = 1
that.serviceId = service.uuid;
that.getBLEDeviceCharacteristics();
console.log("设备的FFE0的serviceId " + that.serviceId);
break;
}
}
},
fail: res => {
console.log('获取设备的UUID失败:', res)
}
});
},
/**
* 获取指定服务的特征值
*/
getBLEDeviceCharacteristics() {
let characteristicsList = [];
let that = this;
uni.getBLEDeviceCharacteristics({
deviceId: that.deviceId,
serviceId: that.serviceId,
success: res => {
console.log("服务的特征值成功", res)
for (let i = 0; i < res.characteristics.length; i++) {
let item = res.characteristics[i];
if (item.uuid.indexOf('0000FFE1') != -1) {
that.uuid1 = item.uuid //
} else if (item.uuid.indexOf('0000FFE2') != -1) {
that.uuid2 = item.uuid //
} else if (item.uuid.indexOf('0000FFE3') != -1) {
that.uuid3 = item.uuid //
}
}
that.sendData()
uni.notifyBLECharacteristicValueChange({
deviceId: that.deviceId,
serviceId: that.serviceId,
characteristicId: that.uuid2,
state: true,
})
uni.notifyBLECharacteristicValueChange({
deviceId: that.deviceId,
serviceId: that.serviceId,
characteristicId: that.uuid3,
state: true,
})
uni.onBLECharacteristicValueChange(function(res) {
let value = that.$tools.ab2hex(res.value, "");
let num = value.substring(18, 19)
let dw = value.substring(19, 20)
let type = value.substring(8, 10)
let typeInfo = value.substring(10, 12)
if (type == "10") {
let data = parseInt(value.substring(13, 18), 16)
let dw1 = "kg"
let dw2 = "kg"
if (dw == "1") {
dw1 = "斤"
dw2 = "jin"
}
if (dw == "4") {
dw1 = "st:lb"
dw2 = "st"
data = 1 * data + 5
}
if (dw == "6") {
dw1 = "lb"
dw2 = "lb"
}
if (num == "1") {
data = parseInt(value.substring(13, 18), 16) / 10
}
if (num == "2") {
data = parseInt(value.substring(13, 18), 16) / 100
}
if (num == "3") {
data = parseInt(value.substring(13, 18), 16) / 1000
}
if (typeInfo == "01") {
that.text = "您的实时体重是:" + data + dw1
}
if (typeInfo == "02") {
that.text = "您的体重是:" + data + dw1
that.weight = data + dw2
console.log("稳定体重:", value, that.weight)
}
}
if (type == "14") {
that.height = parseInt(value.substring(10, 14), 16) / 10
that.textH = "您的身高是:" + that.height + "cm"
that.type = 2
console.log("稳定身高:", that.height)
}
if (type == "11") {
if (typeInfo == "03" || typeInfo == "04") {
that.imp = parseInt(value.substring(17, 22), 16)
}
console.log("阻抗:", typeInfo, parseInt(value.substring(17, 22), 16))
}
if (type == "30") {
console.log("测量完成", that.weight, that.imp, that.height)
if (that.imp == 0) {
uni.showModal({
title: '提示',
content: "体脂测量失败,是否保存本次测量结果?",
cancelText: "放弃",
confirmText: "保存",
success(res) {
if (res.confirm) {
that.imp = 0
that.handleGetMeasure()
} else {
console.log("放弃保存")
that.Unload = true
that.closeBLEConnection()
that.closeBluetoothAdapter()
uni.navigateBack({
delta: 1
})
}
}
})
} else {
that.handleGetMeasure()
}
}
});
},
fail: res => {
console.log('获取特征值失败:', JSON.stringify(res))
}
})
},
//
sendData() {
let that = this
let j = Number(26 + 3 + 6 + 1).toString(16)
let str = "A9002603060100" + j.substr(j.length - 2, 2) + "9A"
let buf = new Uint8Array(str.match(/[\da-f]{2}/gi).map(function(h) {
return parseInt(h, 16)
}))
uni.writeBLECharacteristicValue({
deviceId: that.deviceId,
serviceId: that.serviceId,
characteristicId: that.uuid1,
value: buf.buffer,
success: res => {
console.log('下发指令成功', res.errMsg)
},
fail: res => {
console.log("下发指令失败", res);
},
})
},
//
handleGetMeasure() {
let that = this
that.$model.getmeasure({
weight: that.weight,
imp: that.imp,
ecode: that.macAddr,
height: that.height,
familyid: that.info.familyid,
}).then(res => {
if (res.code == 0) {
that.$store.dispatch("getUserInfo", {
familyid: that.info.familyid,
});
that.$store.dispatch("getResult", {
birthday: that.info.birthday,
familyid: that.info.familyid,
height: that.height,
sex: that.info.sex,
});
that.$tools.msg("测量成功")
} else {
console.log("测量失败", res.message)
that.$tools.msg(res.message)
}
that.Unload = true
setTimeout(function() {
that.closeBLEConnection()
that.closeBluetoothAdapter()
uni.switchTab({
url: "/pages/index/index"
})
}, 200)
})
},
handleBack(ind) {
let that = this
that.text = ""
that.textH = ""
that.Unload = true
that.stopBluetoothDevicesDiscovery() //
that.closeBLEConnection()
that.closeBluetoothAdapter()
},
/**
* 断开蓝牙模块
*/
closeBluetoothAdapter() {
let that = this;
uni.closeBluetoothAdapter({
success: res => {
console.log('蓝牙模块关闭成功');
}
})
},
/**
* 断开蓝牙连接
*/
closeBLEConnection() {
var that = this;
uni.closeBLEConnection({
deviceId: that.deviceId,
success: res => {
console.log('断开蓝牙连接成功');
}
});
},
},
}
</script>
<style scoped lang="scss">
</style>

432
BLEPages/adult/PCD01pro.vue Normal file
View File

@ -0,0 +1,432 @@
<template>
<view>
<view class="content weightPages">
<view class="title" v-if="isConnection == 0">连接中请稍后</view>
<view class="title" v-if="isConnection == 1">连接成功请开始测量</view>
<view class="title" v-if="isConnection == 2" @click="openBluetoothAdapter">连接失败点击重新连接</view>
<view class="text">{{text}}</view>
<view class="image">
<image src="/BLEPages/static/Hd01bt01.gif" v-if="type==1"></image>
<image src="/BLEPages/static/Hd01bt02.gif" v-if="type==2"></image>
</view>
<view class="tips">
<text>提示</text>
<text>1.请确定设备是开机状态</text>
<text>2.请确定手机蓝牙位置信息已打开</text>
<text>3.ios系统需打开设置>应用>微信里的蓝牙权限</text>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
var myTime;
let cnt = 0
export default {
data() {
return {
text: "",
height: "",
weight: "",
imp: 0,
type: 1,
uuid1: "",
uuid2: "",
uuid3: "",
macAddr: "",
deviceId: "",
serviceId: "",
Unload: false,
pageNav: false,
isConnection: 0, //
}
},
computed: {
...mapState(["user", "isConnected", "isBluetoothTyle"]),
info() {
return this.user
}
},
onUnload: function() {
let that = this
if (!that.Unload) {
that.stopBluetoothDevicesDiscovery() //
clearTimeout(myTime);
that.closeBLEConnection()
that.closeBluetoothAdapter()
console.log("测量页返回1")
}
},
onLoad(options) {
let that = this
cnt = 0
that.text = ""
if (options && options.deviceId) {
that.macAddr = options.deviceId
that.deviceId = options.deviceId
that.createBLEConnection()
}
that.onBLEConnectionStateChange()
uni.onBluetoothAdapterStateChange(function(res) {
that.$store.commit("changeBluetooth", res.available);
})
},
watch: {
isConnected: function() {
let that = this
if (!that.isConnected) {
that.handleBack()
that.isConnection = 2
}
},
isBluetoothTyle: function() {
let that = this
if (!that.isBluetoothTyle) {
that.handleBack()
that.isConnection = 2
}
},
},
methods: {
//
openBluetoothAdapter() {
let that = this
cnt = 0
that.type = 1
uni.openBluetoothAdapter({
success: e => {
that.isConnection = 0
that.startBluetoothDeviceDiscovery()
},
fail: e => {
that.isConnection = 2
that.$tools.msg("请确定设备是开机状态、手机蓝牙权限已打开!")
}
});
},
//
startBluetoothDeviceDiscovery() {
let that = this
uni.startBluetoothDevicesDiscovery({
allowDuplicatesKey: false,
interval: 500, //
services: [
"FFE0",
],
success: res => {
that.isConnection = 0
that.onBluetoothDeviceFound();
},
fail: res => {
that.isConnection = 2
that.$tools.msg("请确定设备是开机状态、手机蓝牙权限已打开!")
}
});
},
/**
* 发现外围设备
*/
onBluetoothDeviceFound() {
var that = this;
that.isConnection = 0
uni.onBluetoothDeviceFound(res => {
res.devices.forEach(device => {
if (!device.name && !device.localName) {
return
}
if (device.deviceId.indexOf(that.deviceId) != -1) {
that.stopBluetoothDevicesDiscovery()
clearTimeout(myTime);
let buff = device.advertisData.slice(-6)
device.mac = new Uint8Array(buff) // 广maciOSmac
let tempMac = Array.from(device.mac)
tempMac.reverse()
device.macAddr = that.$tools.ab2hex(tempMac, ':').toUpperCase()
that.macAddr = device.macAddr
that.deviceId = device.deviceId;
that.createBLEConnection()
return;
}
})
});
that.handleMyTime()
},
handleMyTime() {
var that = this;
myTime = setTimeout(function() {
if (!that.macAddr) {
clearTimeout(myTime);
that.Unload = true
that.isConnection = 2
that.closeBLEConnection()
that.closeBluetoothAdapter()
}
}, 20000);
},
/**
* 停止搜索蓝牙设备
*/
stopBluetoothDevicesDiscovery() {
uni.stopBluetoothDevicesDiscovery({
success: e => {
console.log("停止搜索蓝牙设备", e)
},
});
},
//
onBLEConnectionStateChange() {
let that = this
uni.onBLEConnectionStateChange(function(res) {
console.log("监听蓝牙连接状态", res.connected)
if (!res.connected) {
that.Unload = true
that.isConnection = 2
clearTimeout(myTime);
that.closeBLEConnection()
that.closeBluetoothAdapter()
}
that.$store.commit("changeConnected", res.connected);
})
},
//
createBLEConnection() {
let that = this;
uni.createBLEConnection({
deviceId: that.deviceId,
success: res => {
that.isConnection = 0
that.getBLEDeviceServices();
},
fail: res => {
that.isConnection = 2
console.log("设备连接失败,请重新连接", res);
}
});
},
/**
* 获取设备的UUID
*/
getBLEDeviceServices() {
let serviceList = [];
let that = this;
uni.getBLEDeviceServices({
deviceId: that.deviceId,
success: res => {
console.log("获取设备的UUID成功", res)
serviceList = res.services;
for (let i = 0; i < serviceList.length; i++) {
let service = serviceList[i];
if (service.uuid.indexOf("FFE0") != -1) {
that.isConnection = 1
that.serviceId = service.uuid;
that.getBLEDeviceCharacteristics();
console.log("设备的FFE0的serviceId " + that.serviceId);
break;
}
}
},
fail: res => {
console.log('获取设备的UUID失败:', res)
}
});
},
/**
* 获取指定服务的特征值
*/
getBLEDeviceCharacteristics() {
let characteristicsList = [];
let that = this;
uni.getBLEDeviceCharacteristics({
deviceId: that.deviceId,
serviceId: that.serviceId,
success: res => {
console.log("服务的特征值成功", res)
for (let i = 0; i < res.characteristics.length; i++) {
let item = res.characteristics[i];
if (item.uuid.indexOf('FFE1') != -1) {
that.uuid1 = item.uuid //
} else if (item.uuid.indexOf('FFE2') != -1) {
that.uuid2 = item.uuid //
that.notifyBLECharacteristicValue()
} else if (item.uuid.indexOf('FFE3') != -1) {
that.uuid3 = item.uuid //
}
}
},
fail: res => {
console.log('获取特征值失败:', JSON.stringify(res))
}
})
},
/**
* 开启订阅特征值
* read: true, //,write: true, //,notify: true, //广
*/
notifyBLECharacteristicValue() {
let that = this;
uni.notifyBLECharacteristicValueChange({
state: true, // notify
deviceId: that.deviceId,
serviceId: that.serviceId,
characteristicId: that.uuid2,
success(res) {
uni.onBLECharacteristicValueChange(function(res) {
let value = that.$tools.ab2hex(res.value, "");
let num = value.substring(18, 19)
let dw = value.substring(19, 20)
let type = value.substring(8, 10)
let typeInfo = value.substring(10, 12)
console.log("value", value)
if (type == "10") {
let data = parseInt(value.substring(13, 18), 16)
let dw1 = "kg"
let dw2 = "kg"
if (dw == "1") {
dw1 = "斤"
dw2 = "jin"
}
if (dw == "4") {
dw1 = "st:lb"
dw2 = "st"
data = 1 * data + 5
}
if (dw == "6") {
dw1 = "lb"
dw2 = "lb"
}
if (num == "1") {
data = parseInt(value.substring(13, 18), 16) / 10
}
if (num == "2") {
data = parseInt(value.substring(13, 18), 16) / 100
}
if (num == "3") {
data = parseInt(value.substring(13, 18), 16) / 1000
}
if (typeInfo == "01") {
that.text = "您的实时体重是:" + data + dw1
}
if (typeInfo == "02") {
that.text = "您的体重是:" + data + dw1
that.weight = data + dw2
console.log("稳定体重:", value, that.weight)
}
}
if (type == "11") {
that.type = 2
if (typeInfo == "02") {
cnt = cnt + 1;
}
if (typeInfo == "03") {
that.imp = parseInt(value.substring(17, 22), 16)
}
if (cnt >= 2) {
console.log("阻抗值shibai", cnt)
that.imp = 0
uni.showModal({
title: '提示',
content: "体脂测量失败,是否保存本次测量结果?",
cancelText: "放弃",
confirmText: "保存",
success(res) {
if (res.confirm) {
that.imp = 0
that.handleGetMeasure()
} else {
that.Unload = true
that.closeBLEConnection()
that.closeBluetoothAdapter()
uni.navigateBack({
delta: 1
})
}
}
})
}
}
if (type == "30") {
console.log("测量完成", that.weight)
that.handleGetMeasure()
}
});
},
fail(res) {
console.log("测量失败", res.value);
}
});
},
//
handleGetMeasure() {
let that = this
that.$model.getmeasure({
weight: that.weight,
imp: that.imp,
ecode: that.macAddr,
height: that.info.height,
familyid: that.info.familyid,
}).then(res => {
if (res.code == 0) {
that.$tools.msg("测量成功")
that.$store.dispatch("getUserInfo", {
familyid: that.info.familyid,
});
that.$store.dispatch("getResult", {
birthday: that.info.birthday,
familyid: that.info.familyid,
height: that.info.height,
sex: that.info.sex,
});
} else {
console.log("测量失败", res.message)
that.$tools.msg(res.message)
}
that.Unload = true
setTimeout(function() {
that.closeBLEConnection()
that.closeBluetoothAdapter()
uni.switchTab({
url: "/pages/index/index"
})
}, 200)
})
},
handleBack() {
let that = this
that.Unload = true
clearTimeout(myTime)
that.stopBluetoothDevicesDiscovery() //
that.closeBLEConnection()
that.closeBluetoothAdapter()
},
/**
* 断开蓝牙模块
*/
closeBluetoothAdapter() {
let that = this;
uni.closeBluetoothAdapter({
success: res => {
console.log('蓝牙模块关闭成功');
}
})
},
/**
* 断开蓝牙连接
*/
closeBLEConnection() {
var that = this;
uni.closeBLEConnection({
deviceId: that.deviceId,
success: res => {
console.log('断开蓝牙连接成功');
}
});
},
},
}
</script>
<style scoped lang="scss">
</style>

313
BLEPages/adult/PCL01.vue Normal file
View File

@ -0,0 +1,313 @@
<template>
<view>
<view class="content weightPages">
<view class="title" v-if="isConnection == 0">连接中请稍后</view>
<view class="title" v-if="isConnection == 1">连接成功请开始测量</view>
<view class="title" v-if="isConnection == 2" @click="openBluetoothAdapter">连接失败点击重新连接</view>
<view class="text">{{text}}</view>
<view class="image">
<image src="/BLEPages/static/L01.gif"></image>
</view>
<view class="tips">
<text>提示</text>
<text>1.请确定设备是开机状态</text>
<text>2.请确定手机蓝牙位置信息已打开</text>
<text>3.ios系统需打开设置>应用>微信里的蓝牙权限</text>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
let myTime
const plugin = requirePlugin("sdkPlugin").AiLink;
export default {
data() {
return {
text: "",
height: "",
weight: "",
imp: 0,
macAddr: "",
deviceId: "",
serviceId: "",
Unload: false,
stopblue: true,
isConnection: 0, //
}
},
computed: {
...mapState(["user", "isConnected", "isBluetoothTyle"]),
info() {
return this.user
}
},
onUnload: function() {
let that = this
if (!that.Unload) {
that.stopBluetoothDevicesDiscovery() //
clearTimeout(myTime);
that.closeBLEConnection()
that.closeBluetoothAdapter()
console.log("测量页返回1")
}
},
onLoad(options) {
let that = this
that.text = ""
if (options && options.deviceId) {
that.deviceId = options.deviceId
console.log(0)
that.openBluetoothAdapter()
}
uni.onBluetoothAdapterStateChange(function(res) {
that.$store.commit("changeBluetooth", res.available);
})
},
watch: {
isConnected: function() {
let that = this
if (!that.isConnected) {
that.handleBack()
that.isConnection = 2
}
},
isBluetoothTyle: function() {
let that = this
if (!that.isBluetoothTyle) {
that.handleBack()
that.isConnection = 2
}
},
stopblue: function() {
let that = this
if (!that.stopblue) {
console.log("停止成功", that.weight, that.imp)
if (that.imp == 0) {
uni.showModal({
title: '提示',
content: "体脂测量失败,是否保存本次测量结果?",
cancelText: "放弃",
confirmText: "保存",
success(res) {
if (res.confirm) {
that.imp = 0
that.handleGetMeasure()
} else {
that.Unload = true
that.startBluetoothDeviceDiscovery()
that.closeBLEConnection()
that.closeBluetoothAdapter()
uni.navigateBack({
delta: 1
})
}
}
})
} else {
that.handleGetMeasure()
}
}
}
},
methods: {
//
openBluetoothAdapter() {
let that = this
that.text = ""
that.stopblue = true
uni.openBluetoothAdapter({
success: e => {
that.isConnection = 0
that.startBluetoothDeviceDiscovery()
},
fail: e => {
that.isConnection = 2
that.$tools.msg("请确定设备是开机状态、手机蓝牙权限已打开!")
}
});
},
//
startBluetoothDeviceDiscovery() {
let that = this
uni.startBluetoothDevicesDiscovery({
allowDuplicatesKey: true,
services: [
"F0A0",
],
success: res => {
that.isConnection = 0
that.onBluetoothDeviceFound();
},
fail: res => {
that.isConnection = 2
that.$tools.msg("请确定设备是开机状态、手机蓝牙权限已打开!")
}
});
},
/**
* 停止搜索蓝牙设备
*/
stopBluetoothDevicesDiscovery() {
uni.stopBluetoothDevicesDiscovery({
success: e => {
console.log("停止搜索蓝牙设备", e)
},
});
},
/**
* 发现外围设备
*/
onBluetoothDeviceFound() {
var that = this;
that.isConnection = 1
uni.onBluetoothDeviceFound(res => {
res.devices.forEach(device => {
if (!device.name && !device.localName) {
return
}
if (device.advertisServiceUUIDs[0].indexOf("F0A0") !== -1) {
clearTimeout(myTime);
let value = that.$tools.ab2hex(device.advertisData)
let parseDataRes = plugin.parseBroadcastData(device.advertisData)
let analyzeData = plugin.analyzeBroadcastScaleData(parseDataRes)
let analyzeDataText = analyzeData.text
let data = analyzeData.data
console.log("analyzeData", parseDataRes, analyzeData)
if (parseDataRes.status == 1) {
let dw1 = "kg"
let dw2 = "kg"
if (data.weightUnit == "1") {
dw1 = "斤"
dw2 = "jin"
}
if (data.weightUnit == "4") {
dw1 = "st:lb"
dw2 = "st"
data = 1 * data + 5
}
if (data.weightUnit == "6") {
dw1 = "lb"
dw2 = "lb"
}
if (data.weightDecimal == "1") {
data.weight = data.weight / 10
}
if (data.weightDecimal == "2") {
data.weight = data.weight / 100
}
if (data.weightDecimal == "3") {
data.weight = data.weight / 1000
}
that.text = "您的体重是:" + data.weight + dw1
if (data.weightStatus == 1 || analyzeDataText.indexOf('阻抗测量失败') != -1) {
let buffer = device.advertisData.slice(0, 8)
device.mac = new Uint8Array(buffer)
let tempMac = Array.from(device.mac)
tempMac.reverse()
device.macAddr = that.$tools.ab2hex(tempMac, ':').toUpperCase()
that.macAddr = device.macAddr
that.deviceId = device.deviceId;
that.weight = data.weight + dw2
that.imp = data.adc
uni.stopBluetoothDevicesDiscovery({
success: e => {
return that.stopblue = false
},
});
return
}
}
}
})
});
that.handleMyTime()
},
handleMyTime() {
var that = this;
myTime = setTimeout(function() {
if (!that.macAddr) {
clearTimeout(myTime);
that.Unload = true
that.isConnection = 2
that.closeBLEConnection()
that.closeBluetoothAdapter()
}
}, 20000);
},
//
handleGetMeasure() {
let that = this
that.$model.getmeasure({
weight: that.weight,
imp: that.imp,
ecode: that.macAddr,
height: that.info.height,
familyid: that.info.familyid,
}).then(res => {
if (res.code == 0) {
that.$tools.msg("测量成功")
that.$store.dispatch("getUserInfo", {
familyid: that.info.familyid,
});
that.$store.dispatch("getResult", {
birthday: that.info.birthday,
familyid: that.info.familyid,
height: that.info.height,
sex: that.info.sex,
});
} else {
console.log("测量失败", res.message)
that.$tools.msg(res.message)
}
that.Unload = true
setTimeout(function() {
that.closeBLEConnection()
that.closeBluetoothAdapter()
uni.switchTab({
url: "/pages/index/index"
})
}, 200)
})
},
handleBack() {
let that = this
that.Unload = true
clearTimeout(myTime)
that.stopBluetoothDevicesDiscovery() //
that.closeBLEConnection()
that.closeBluetoothAdapter()
},
/**
* 断开蓝牙模块
*/
closeBluetoothAdapter() {
let that = this;
uni.closeBluetoothAdapter({
success: res => {
console.log('蓝牙模块关闭成功');
}
})
},
/**
* 断开蓝牙连接
*/
closeBLEConnection() {
var that = this;
uni.closeBLEConnection({
deviceId: that.deviceId,
success: res => {
console.log('断开蓝牙连接成功');
}
});
},
},
}
</script>
<style scoped lang="scss">
</style>

BIN
BLEPages/static/F018P01.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
BLEPages/static/F018P02.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
BLEPages/static/H01pro.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
BLEPages/static/H09B.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
BLEPages/static/H09B2.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
BLEPages/static/L01.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

1570
assets/common.scss Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

363
assets/iconfont.css Normal file
View File

@ -0,0 +1,363 @@
@font-face {
font-family: 'iconfont'; /* Project id 2887906 */
src: url('https://at.alicdn.com/t/font_2887906_wl80j95s0c.woff2?t=1648878564422') format('woff2'),
url('https://at.alicdn.com/t/font_2887906_wl80j95s0c.woff?t=1648878564422') format('woff'),
url('https://at.alicdn.com/t/font_2887906_wl80j95s0c.ttf?t=1648878564422') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-biaozhunhua:before {
content: "\e60b";
}
.icon-shejiguifan:before {
content: "\e640";
}
.icon-tizhongcheng:before {
content: "\e63f";
}
.icon-baogao1:before {
content: "\e620";
}
.icon-tizhong1:before {
content: "\e616";
}
.icon-sharpicons_checklist:before {
content: "\e804";
}
.icon-hengxian:before {
content: "\e657";
}
.icon-lbm:before {
content: "\e6b7";
}
.icon-fatlevel:before {
content: "\e63d";
}
.icon-fat_r:before {
content: "\e62d";
}
.icon-fat_w:before {
content: "\e78e";
}
.icon-bone:before {
content: "\e610";
}
.icon-kcal:before {
content: "\e60c";
}
.icon-visceral:before {
content: "\e60d";
}
.icon-muscle:before {
content: "\e60e";
}
.icon-body:before {
content: "\e638";
}
.icon-water:before {
content: "\e651";
}
.icon-muscleval:before {
content: "\e949";
}
.icon-protein:before {
content: "\e94a";
}
.icon-proteinval:before {
content: "\e60f";
}
.icon-bodyage:before {
content: "\e6b2";
}
.icon-height1:before {
content: "\e6eb";
}
.icon-shang:before {
content: "\e68a";
}
.icon-xia:before {
content: "\e798";
}
.icon-sfr:before {
content: "\e617";
}
.icon-yisheng3:before {
content: "\e6a3";
}
.icon-yisheng_1:before {
content: "\e633";
}
.icon-switch-ON-copy-copy:before {
content: "\fc23";
}
.icon-switch-ON-copy-copy1:before {
content: "\fc25";
}
.icon-shuzhuangtu:before {
content: "\e604";
}
.icon-jilu:before {
content: "\e69e";
}
.icon-lishixiao:before {
content: "\e8bd";
}
.icon-jiantou_xiangxia:before {
content: "\eb0a";
}
.icon-jiantou_xiangshang:before {
content: "\eb0b";
}
.icon-tizhong:before {
content: "\e682";
}
.icon-jiaoxuepinggu-01:before {
content: "\e63b";
}
.icon-qiehuan1:before {
content: "\e7d7";
}
.icon-head:before {
content: "\e8d1";
}
.icon-quxiao:before {
content: "\e664";
}
.icon-fenxiang:before {
content: "\e60a";
}
.icon-touxiang:before {
content: "\e61f";
}
.icon-pingtai:before {
content: "\f4ec";
}
.icon-dianhuatianchong:before {
content: "\e678";
}
.icon-xinxi:before {
content: "\e648";
}
.icon-bianji3:before {
content: "\e62b";
}
.icon-gonglve:before {
content: "\f4e4";
}
.icon-shoucang:before {
content: "\f4f8";
}
.icon-pinglun:before {
content: "\f5b0";
}
.icon-shijian-mianxing-0:before {
content: "\e6a2";
}
.icon-hezuo:before {
content: "\f4e5";
}
.icon-shouhou:before {
content: "\f5dd";
}
.icon-pinglun-08:before {
content: "\fc1d";
}
.icon-weixin:before {
content: "\e637";
}
.icon-QQ:before {
content: "\e667";
}
.icon-weight:before {
content: "\e62a";
}
.icon-height:before {
content: "\e609";
}
.icon-bmi:before {
content: "\e785";
}
.icon-shoucang1:before {
content: "\e603";
}
.icon-qiehuan:before {
content: "\f4ee";
}
.icon-yazi-copy:before {
content: "\f5b6";
}
.icon-hear:before {
content: "\e8af";
}
.icon-zanwu:before {
content: "\e626";
}
.icon-shuimian:before {
content: "\e959";
}
.icon-wenjian-xinliweiji:before {
content: "\e72d";
}
.icon-yundong:before {
content: "\e810";
}
.icon-yinshi2:before {
content: "\e607";
}
.icon-gerendingzhi:before {
content: "\e605";
}
.icon-top-chengchangquxian:before {
content: "\e61e";
}
.icon-duibi2:before {
content: "\e6b8";
}
.icon-tubiao--copy:before {
content: "\ec58";
}
.icon-jilu1:before {
content: "\e686";
}
.icon-xiangxia:before {
content: "\e601";
}
.icon-kongradio:before {
content: "\e602";
}
.icon-radio:before {
content: "\e653";
}
.icon-arrow-left:before {
content: "\e685";
}
.icon-arrow-down:before {
content: "\e687";
}
.icon-arrow-right:before {
content: "\e688";
}
.icon-tishi:before {
content: "\e797";
}
.icon-yazi:before {
content: "\e612";
}
.icon-shengao:before {
content: "\e739";
}
.icon-liangdu-:before {
content: "\e606";
}
.icon-aixin:before {
content: "\f4cf";
}
.icon-yqfqiehuan:before {
content: "\e61b";
}
.icon-female:before {
content: "\e600";
}
.icon-dangao:before {
content: "\e608";
}
.icon-quxian:before {
content: "\e629";
}
.icon-baogao:before {
content: "\e630";
}

BIN
components/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,146 @@
<template>
<view>
<view class="wrapper" v-if="isDrawe">
<view class="bg" @click="clear"></view>
<view class="wrapper_box">
<view class="top">
<image class="headimage mt-10" v-if="userinfo.headimg" :src="userinfo.headimg"></image>
<view class="overflow">{{userinfo.nickname||userinfo.name}}</view>
</view>
<view class="drawerList">
<view v-if="List.length">
<view class="drawerList_item" v-for="(item, index) in List" :key="index" @click="toggle(item)">
<image v-if="item.headimg" :src="item.headimg" class="image1"></image>
<view class="right">
<view class="name">
<view class="overflow">
{{item.name}}
</view>
<view class="dangqian" v-if="item.id == userinfo.familyid">当前</view>
</view>
<view class="info">
<view>{{item.mage}}</view>
<view>{{item.sex==0?'未知':item.sex==1?'男':'女'}}</view>
<view>{{item.type}}</view>
</view>
</view>
</view>
</view>
<view class="add">
<view @click="addInfo('add')">
+
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
export default {
data() {
return {};
},
computed: {
...mapState(["user", "familayList", "isDrawe"]),
userinfo() {
return this.user
},
List() {
return this.familayList
},
},
methods: {
//
toggle(val) {
let that = this
uni.setStorageSync('familyid', val.familyid)
that.$store.dispatch("getResult", {
birthday: val.birthday,
familyid: val.familyid,
height: val.height,
sex: val.sex,
});
that.$store.dispatch("getUserInfo", {
familyid: val.familyid,
});
that.$store.commit("changeDrawe", false);
},
//
addInfo(type) {
uni.navigateTo({
url: "/pageTwo/me/adduser?type=" + type
})
},
clear() {
this.$store.commit("changeDrawe", false);
},
}
}
</script>
<style lang="scss" scoped>
.wrapper {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 999;
}
.bg {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
height: 100vh;
background-color: rgba(0, 0, 0, 0.4);
z-index: 99;
}
.uniDrawer {
width: 220px;
background-color: #fff;
z-index: 1000;
}
@keyframes uniDrawer {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(0%);
}
}
.list {
position: relative;
top: 0;
left: 0;
flex-direction: column;
flex: 1;
justify-content: flex-end;
margin-bottom: 20rpx;
width: 220px;
height: calc(100vh - 100px);
overflow-y: scroll;
}
.name {
width: 100%;
display: flex;
justify-content: space-between;
.overflow {
width: 60%;
}
}
</style>

105
components/header/head.vue Normal file
View File

@ -0,0 +1,105 @@
<template>
<view>
<view class="header-con">
<view class="header" v-if="token">
<view class="left">
<image :src="user.headimg" class="headimage mr-10" @click="handleDrawer"></image>
<view>
<view class="name" @click="handleDrawer">
<text class="overflow">{{user.name}}</text>
<icon class="iconfont icon-yqfqiehuan"></icon>
</view>
<view class="age">
<view>
性别:{{!user.sex?"未知":user.sex==1?'男':'女'}}
</view>
<view>
年龄:{{user.mage?user.mage:"0岁"}}
</view>
</view>
</view>
</view>
<view class="celiang_r" @click="handleBluetoothClick">
<icon class="t-icon t-icon-tizhongcheng"></icon>
<text>上秤测量</text>
</view>
</view>
<view class="header2" v-else @click="handleLogin">
<view class="text"><text>登录</text>查看更多信息</view>
</view>
</view>
<!-- denglu -->
<userLogin></userLogin>
<!-- 左侧 -->
<leftdrawer></leftdrawer>
</view>
</template>
<script>
import {
mapState
} from "vuex";
import userLogin from '@/components/userLogin.vue'
import leftdrawer from "@/components/drawer/drawer.vue"
export default {
components: {
userLogin,
leftdrawer
},
data() {
return {
devType: "",
deviceId: ""
}
},
props: {
token: {
type: String,
default: null
},
},
computed: {
...mapState(["user"]),
},
mounted() {
// this.token = uni.getStorageSync('token')
},
methods: {
//
handleBluetoothClick() {
let that = this
if (!that.token) {
that.$store.commit("changeUserLogin", true)
return
}
uni.openBluetoothAdapter({
success: e => {
that.$store.commit("changeBluetooth", true);
if (that.devType && that.deviceId) {
that.$tools.handlePages(that.devType, that.deviceId)
return
}
uni.navigateTo({
url: "/pages/search/devType"
})
console.log('初始化蓝牙成功:' + e.errMsg);
},
fail: err => {
console.log('初始化蓝牙失败:' + err.errMsg);
return this.$tools.getBluetoothAdapter(err)
}
});
},
//
handleLogin() {
this.$store.commit("changeUserLogin", true);
},
handleDrawer() {
this.$store.commit("changeDrawe", true);
},
}
}
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,351 @@
<template>
<view class="container">
<view class="slide-box" v-for="(item, index) in listData" :key="index">
<view class="slide-list" @touchstart="touchStart($event, index)" @touchend="touchEnd($event, index)"
@touchmove="touchMove($event, index)" @tap="recover(index)"
:style="{ transform: 'translate3d(' + item.slide_x + 'px, 0, 0)' }">
<view class="now-message-info" hover-class="uni-item--hover" :style="{ width: windowWidth + 'px' }"
@click="clickItemMethod(item)">
<view class="list">
<view class="item" :class="[type!=1?'leftChild':'']">
<view class="time">
<icon class="t-icon t-icon-shijian-mianxing-0"></icon>
<text>{{item.createtime}}</text>
</view>
<view v-if="type!=1">{{item.height}}<text>身高</text></view>
<view>{{item.weight}}<text>体重</text></view>
<view>{{item.bmi}}<text>BMI</text></view>
<view v-if="type==1">{{item.fat_r}}<text>脂肪率</text></view>
<icon v-if="type==1" class="iconfont icon-arrow-right"></icon>
</view>
</view>
</view>
<view class="group-btn">
<view class="btn-div" v-for="(value, key) in button" :key="key" @click="clickMethod(item)"
:style="{background: value.background}">
{{value.title}}
</view>
</view>
<view style="clear:both"></view>
</view>
<view class="list-item-border" v-if="border"></view>
</view>
<!-- <view class="endtext" v-if="!lastPage || page >= lastPage"> 到底了看看别的吧 </view> -->
</view>
</template>
<script>
/**
* m-slide-list 滑动操作列表
* @description 滑动操作列表组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=209
* @property {Array} list 数据源格式为[{title: 'xxx', image:'xxx', surname: 'xxx',detail:'xxx', rightDetail: 'xxx', slide_x: 0},{title: 'xxx', image:'xxx', surname: 'xxx',detail:'xxx', rightDetail: 'xxx', slide_x: 0}]
* @property {Array} button 按钮数据源格式为[{title: 'xxx', background:'xxx'},{title: 'xxx', background:'xxx'}]
* @property {Boolean} border 边框
*/
export default {
name: 'mark-slide-list',
props: {
list: { //list
type: Array,
default () {
return [];
}
},
button: { //list
type: Array,
default () {
return [{
title: '删除',
background: '#ff3b32'
}];
}
},
border: { //
type: Boolean,
default: false
},
type: {
type: String,
default: null
},
id: {
type: String,
default: null
}
},
computed: {
windowWidth() {
return uni.getSystemInfoSync().windowWidth;
}
},
data() {
return {
listData: [],
start_slide_x: 0,
btnWidth: 0,
startX: 0,
LastX: 0,
startTime: 0,
itemIndex: 0,
};
},
mounted() {
this.listData = this.clone(this.list)
// this.getList(1)
},
watch: {
list: {
handler: function(val, oldval) {
this.listData = this.clone(this.list)
},
deep: true
}
},
methods: {
clone(data) {
const type = typeof data
let obj;
if (type === 'array') {
obj = [];
} else if (type === 'object') {
obj = {};
} else {
//
return data;
}
if (type === 'array') {
for (let i = 0, len = data.length; i < len; i++) {
obj.push(this.clone(data[i]));
}
} else if (type === 'object') {
// ....
for (const key in data) {
obj[key] = this.clone(data[key]);
}
}
return obj;
},
//
touchStart(e, index) {
if (this.itemIndex == index) {
this.itemIndex = index
}
//
this.startTime = e.timeStamp;
//
this.start_slide_x = this.listData[index].slide_x;
//
//#ifdef MP-WEIXIN
uni.createSelectorQuery().in(this).selectAll('.group-btn').boundingClientRect(res => {
if (res != null) {
this.btnWidth = res[index].width * -1;
}
}).exec();
//#endif
//#ifdef H5 || APP-PLUS
uni.createSelectorQuery()
.selectAll('.group-btn')
.boundingClientRect()
.exec(res => {
if (res[0] != null) {
this.btnWidth = res[0][index].width * -1;
}
});
//#endif
//
this.startX = e.touches[0].pageX;
//
this.lastX = this.startX;
//
for (var i in this.listData) {
if (index != i) {
this.listData[i].slide_x = 0;
}
}
},
//
touchMove(e, index) {
const endX = e.touches[0].pageX;
const distance = endX - this.lastX;
//
const duang = this.listData[index].slide_x + distance;
//
if (duang <= 0 && duang >= this.btnWidth) {
this.listData[index].slide_x = duang;
}
//
this.lastX = endX;
},
//
touchEnd(e, index) {
let distance = 10;
const endTime = e.timeStamp;
const x_end_distance = this.startX - this.lastX;
if (Math.abs(endTime - this.startTime) > 200) {
distance = this.btnWidth / -2;
}
//
if (x_end_distance > distance) {
this.listData[index].slide_x = this.btnWidth;
} else if (x_end_distance < distance * -1) {
this.listData[index].slide_x = 0;
} else {
this.listData[index].slide_x = this.start_slide_x;
}
},
//
recover(index) {
this.listData[index].slide_x = 0;
},
/**
* 点击按钮触发事件
* @param {Object} item 列表数据
* @param {Object} buttonItem 按钮数据
* @param {Object} index 列表数据key
*/
clickMethod(item) {
if (this.list.length == 1) {
this.$tools.msg("只剩一条记录了,不可以删除!")
return
}
this.$emit("changeDelete", item)
},
//
clickItemMethod(item) {
if (this.type == 1) {
uni.navigateTo({
url: "/pageTwo/me/info?index=" + JSON.stringify(item)
})
}
// this.$emit("click", item)
}
}
};
</script>
<style lang="scss" scoped>
.container {
.slide-box {
width: 100%;
overflow: hidden;
.list-item-border {
width: 100%;
}
.slide-list {
transition: all 100ms;
transition-timing-function: ease-out;
min-width: 200%;
.now-message-info {
position: relative;
box-sizing: border-box;
display: flex;
align-items: center;
font-size: 16px;
clear: both;
padding: 0 30rpx;
background: #f7f7f7;
float: left;
.icon-image {
border-radius: 10rpx;
width: 100rpx;
height: 100rpx;
float: left;
}
.icon-circle {
background: #3396fb;
border-radius: 100%;
width: 100rpx;
height: 100rpx;
line-height: 100rpx;
text-align: center;
color: #ffffff;
font-weight: bold;
font-size: 20px;
float: left;
}
.list-right {
float: left;
margin-left: 25rpx;
margin-right: 30rpx;
.list-title {
width: 350rpx;
line-height: 1.5;
overflow: hidden;
margin-bottom: 10rpx;
color: #333;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
}
.list-detail {
width: 350rpx;
font-size: 14px;
color: #a9a9a9;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
}
}
.list-right-1 {
float: right;
position: absolute;
right: 30rpx;
color: #a9a9a9;
}
}
.group-btn {
float: left;
display: flex;
flex-direction: row;
min-width: 100rpx;
align-items: center;
margin-top: 6rpx;
.btn-div {
height: 100rpx;
color: #fff;
text-align: center;
padding: 0 50rpx;
font-size: 34rpx;
line-height: 100rpx;
border-radius: 5px 0 0 5px;
}
.top {
background-color: #c4c7cd;
}
.removeM {
background-color: #ff3b32;
}
}
}
}
}
.leftChild {
view {
width: 18%;
}
.time {
width: 32% !important;
}
}
</style>

View File

@ -0,0 +1,438 @@
<template>
<view class="calendar-wrapper">
<view class="header">
<view class="pre" @click="changeMonth('pre')">
<icon class="iconfont icon-arrow-left"></icon>
</view>
<view>{{y+'年'+formatNum(m)+'月'}}</view>
<view class="next" @click="changeMonth('next')">
<icon class="iconfont icon-arrow-right"></icon>
</view>
</view>
<view class="week">
<view class="week-day" v-for="(item, index) in weekDay" :key="index">{{ item }}</view>
</view>
<view :class="{ hide: !monthOpen }" class="content0" :style="{ height: height }">
<view :style="{ top: positionTop + 'rpx' }" class="days">
<view class="item" v-for="(item, index) in dates" :key="index">
<view class="day" @click="selectOne(item, $event)" :class="{
choose: choose == `${item.year}-${item.month}-${item.date}`&&item.isCurM,
nolm: !item.isCurM,
today: isToday(item.year, item.month, item.date),
isWorkDay: isWorkDay(item.year, item.month, item.date)
}">
{{ Number(item.date) }}
</view>
<view class="markDay" v-if="isMarkDay(item.year, item.month, item.date)&&item.isCurM"></view>
<!-- <view class="today-text" v-if="isToday(item.year, item.month, item.date)"></view> -->
</view>
</view>
</view>
<image src="https://i.loli.net/2020/07/16/2MmZsucVTlRjSwK.png" mode="scaleToFill" v-if="collapsible"
@click="toggle" class="weektoggle" :class="{ down: monthOpen }"></image>
</view>
</template>
<script>
export default {
name: 'ren-calendar',
props: {
// (0)
weekstart: {
type: Number,
default: 0
},
//
markDays: {
type: Array,
default: () => {
return [];
}
},
//
headerBar: {
type: Boolean,
default: true
},
//
open: {
type: Boolean,
default: true
},
//
collapsible: {
type: Boolean,
default: true
},
//
disabledAfter: {
type: Boolean,
default: true
}
},
data() {
return {
weektext: ['日', '一', '二', '三', '四', '五', '六'],
y: new Date().getFullYear(), //
m: new Date().getMonth() + 1, //
dates: [], //
positionTop: 0,
monthOpen: true,
choose: '',
month: null,
};
},
created() {
this.dates = this.monthDay(this.y, this.m);
!this.open && this.toggle();
},
mounted() {
this.y = new Date().getFullYear()
this.m = new Date().getMonth() + 1
this.month = this.$tools.getDate("m")
this.choose = this.getToday().date;
},
computed: {
//
weekDay() {
return this.weektext.slice(this.weekstart).concat(this.weektext.slice(0, this.weekstart));
},
height() {
return (this.dates.length / 7) * 80 + 'rpx';
},
},
methods: {
formatNum(num) {
let res = Number(num);
return res < 10 ? '0' + res : res;
},
getToday() {
let date = new Date();
let y = date.getFullYear();
let m = date.getMonth();
let d = date.getDate();
let week = new Date().getDay();
let weekText = ['日', '一', '二', '三', '四', '五', '六'];
let formatWeek = '星期' + weekText[week];
let today = {
date: y + '-' + this.formatNum(m + 1) + '-' + this.formatNum(d),
week: formatWeek
};
return today;
},
//
monthDay(y, month) {
let dates = [];
let m = Number(month);
let firstDayOfMonth = new Date(y, m - 1, 1).getDay(); //
let lastDateOfMonth = new Date(y, m, 0).getDate(); //
let lastDayOfLastMonth = new Date(y, m - 1, 0).getDate(); //
let weekstart = this.weekstart == 7 ? 0 : this.weekstart;
let startDay = (() => {
//
if (firstDayOfMonth == weekstart) {
return 0;
} else if (firstDayOfMonth > weekstart) {
return firstDayOfMonth - weekstart;
} else {
return 7 - weekstart + firstDayOfMonth;
}
})();
let endDay = 7 - ((startDay + lastDateOfMonth) % 7); //
if (endDay == 7) {
endDay = 0;
}
for (let i = 1; i <= startDay; i++) {
dates.push({
date: this.formatNum(lastDayOfLastMonth - startDay + i),
day: weekstart + i - 1 || 7,
month: m - 1 >= 0 ? this.formatNum(m - 1) : 12,
year: m - 1 >= 0 ? y : y - 1
});
}
for (let j = 1; j <= lastDateOfMonth; j++) {
dates.push({
date: this.formatNum(j),
day: (j % 7) + firstDayOfMonth - 1 || 7,
month: this.formatNum(m),
year: y,
isCurM: true //
});
}
for (let k = 1; k <= endDay; k++) {
dates.push({
date: this.formatNum(k),
day: (lastDateOfMonth + startDay + weekstart + k - 1) % 7 || 7,
month: m + 1 <= 11 ? this.formatNum(m + 1) : 0,
year: m + 1 <= 11 ? y : y + 1
});
}
return dates;
},
isWorkDay(y, m, d) {
//
let ymd = `${y}/${m}/${d}`;
let formatDY = new Date(ymd.replace(/-/g, '/'));
let week = formatDY.getDay();
if (week == 0 || week == 6) {
return false;
} else {
return true;
}
},
isFutureDay(y, m, d) {
//
let ymd = `${y}/${m}/${d}`;
let formatDY = new Date(ymd.replace(/-/g, '/'));
let showTime = formatDY.getTime();
let curTime = new Date().getTime();
if (showTime > curTime) {
return true;
} else {
return false;
}
},
//
isMarkDay(y, m, d) {
let flag = false;
for (let i = 0; i < this.markDays.length; i++) {
let dy = `${y}-${m}-${d}`;
if (this.markDays[i] == dy) {
flag = true;
break;
}
}
return flag;
},
isToday(y, m, d) {
let checkD = y + '-' + m + '-' + d;
let today = this.getToday().date;
if (checkD == today) {
return true;
} else {
return false;
}
},
//
toggle() {
this.monthOpen = !this.monthOpen;
if (this.monthOpen) {
this.positionTop = 0;
} else {
let index = -1;
this.dates.forEach((i, x) => {
this.isToday(i.year, i.month, i.date) && (index = x);
});
this.positionTop = -((Math.ceil((index + 1) / 7) || 1) - 1) * 80;
}
},
//
selectOne(i, event) {
let date = `${i.year}-${i.month}-${i.date}`;
let selectD = new Date(date).getTime();
let curTime = new Date().getTime();
let week = new Date(date).getDay();
let weekText = ['日', '一', '二', '三', '四', '五', '六'];
let formatWeek = '星期' + weekText[week];
let response = {
date: date,
week: formatWeek
};
if (!i.isCurM) {
// console.log('');
return false;
}
if (selectD > curTime) {
if (this.disabledAfter) {
console.log('未来日期不可选');
return false;
} else {
this.choose = date;
this.$emit('onDayClick', response);
}
} else {
this.choose = date;
this.$emit('onDayClick', response);
}
console.log(response);
},
//
changYearMonth(y, m) {
this.dates = this.monthDay(y, m);
this.y = y;
this.m = m;
},
changeMonth(type) {
let that = this
if (!uni.getStorageSync('token')) {
this.$store.commit("changeUserLogin", true);
return
}
if (type == 'pre') {
if (that.m + 1 == 2) {
that.m = 12;
that.y = that.y - 1;
} else {
that.m = that.m - 1;
}
that.month = this.$tools.getMonth(that.month, -1)
that.$emit('onMonthClickPre', that.month)
} else {
if (this.m + 1 == 13) {
this.m = 1;
this.y = this.y + 1;
} else {
this.m = this.m + 1;
}
that.month = this.$tools.getMonth(that.month, +1)
that.$emit('onMonthClickPre', that.month)
}
this.dates = this.monthDay(this.y, this.m);
}
}
};
</script>
<style lang="scss" scoped>
.calendar-wrapper {
color: #bbb7b7;
border-radius: 10px;
font-size: 28rpx;
text-align: center;
background-color: #fff;
padding-bottom: 10rpx;
.header {
display: flex;
align-items: center;
justify-content: center;
height: 88rpx;
color: #42464A;
font-size: 32rpx;
font-weight: bold;
justify-content: space-around;
.pre,
.next {
color: $btncolor;
font-size: 28rpx;
}
}
.week {
display: flex;
align-items: center;
height: 80rpx;
line-height: 80rpx;
border-bottom: 1rpx solid rgba(255, 255, 255, 0.2);
view {
flex: 1;
}
}
.content0 {
position: relative;
overflow: hidden;
transition: height 0.4s ease;
.days {
transition: top 0.3s;
display: flex;
align-items: center;
flex-wrap: wrap;
position: relative;
.item {
position: relative;
display: block;
height: 80rpx;
line-height: 80rpx;
width: calc(100% / 7);
.day {
font-style: normal;
display: inline-block;
vertical-align: middle;
width: 60rpx;
height: 60rpx;
line-height: 60rpx;
overflow: hidden;
border-radius: 60rpx;
&.choose {
background-color: $btncolor;
color: #fff;
}
&.nolm {
color: #fff;
opacity: 0.3;
}
}
.isWorkDay {
color: #42464a;
}
.notSigned {
font-style: normal;
width: 8rpx;
height: 8rpx;
background: #fa7268;
border-radius: 10rpx;
position: absolute;
left: 50%;
bottom: 0;
pointer-events: none;
}
.today {
color: #fff;
background-color: #a8c0ff;
}
.workDay {
font-style: normal;
width: 8rpx;
height: 8rpx;
background: #4d7df9;
border-radius: 10rpx;
position: absolute;
left: 50%;
bottom: 0;
pointer-events: none;
}
.markDay {
font-style: normal;
width: 8rpx;
height: 8rpx;
background: #fa7268;
border-radius: 10rpx;
position: absolute;
left: 50%;
bottom: 0;
pointer-events: none;
}
}
}
}
.hide {
height: 80rpx !important;
}
.weektoggle {
width: 85rpx;
height: 32rpx;
position: relative;
bottom: -42rpx;
&.down {
transform: rotate(180deg);
bottom: 0;
}
}
}
</style>

View File

@ -0,0 +1,128 @@
<template>
<view class="wrapper" v-if="isedit">
<view class="bg" @click="onTap">
<view class="edit" @click.stop>
<view class="title">
健康资料
</view>
<!-- -->
<view class="editem">
<view class="name">性别</view>
<view class="radio mr-10" @click="selectsex(1)">
<icon class="iconfont radioimg" :class="[info.sex==1?'icon-radio':'icon-kongradio']">
</icon>
<view class="ml-10"></view>
</view>
<view class="radio" @click="selectsex(2)">
<icon class="iconfont radioimg" :class="[info.sex==2?'icon-radio':'icon-kongradio']">
</icon>
<view class="ml-10"></view>
</view>
</view>
<!-- -->
<view class="editem">
<view class="name">身高</view>
<view class="right">
<input type="digit" v-model="info.height" placeholder="请输入身高" />cm
</view>
</view>
<view class="editem">
<view class="name">出生日期</view>
<view class="right">
<picker mode="date" :end="startDate" class="f-r" :value="info.birthday" @change="onBirthdayArr">
<view class="uni-input">{{info.birthday?info.birthday:"请选择"}}
<icon class="iconfont icon-arrow-down"></icon>
</view>
</picker>
</view>
</view>
<view class="tips">
请准确填写信息方便我们给您更精确的报告
</view>
<view class="btn mt-15" @click="handleCloseClick">保存信息</view>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
export default {
data() {
return {
info: {
height: "",
birthday: "",
sex: 0,
},
ageArr: [],
}
},
computed: {
...mapState(["user", "isedit"]),
userInfo: function() {
return this.user
},
},
mounted() {
var agedata = []
for (var i = 12; i <= 80; i++) {
agedata.push(i);
}
this.ageArr = agedata
this.info = this.user
},
methods: {
onTap() {
// this.isHeight = false
// this.slideheight = this.userInfo.height
// this.$store.commit("changeEdit", false);
},
//
selectsex(e) {
this.info.sex = e
},
//
onBirthdayArr(e) {
this.info.birthday = e.target.value
},
//
handleCloseClick() {
let that = this
if (!that.info.sex) {
that.$tools.msg("请选择性别")
return
}
if (!that.info.height) {
that.$tools.msg("请选择身高")
return
}
if (!that.info.birthday) {
that.$tools.msg("请选择出生日期")
return
}
that.$store.commit("changeEdit", false);
that.getResult()
},
getResult() {
let that = this
that.$model.getResult({
birthday: that.userInfo.birthday,
familyid: that.userInfo.familyid,
height: that.userInfo.height,
sex: that.userInfo.sex,
}).then((res) => {
that.$store.dispatch("getUserInfo", {
familyid: that.userInfo.familyid,
})
that.$store.dispatch("getFamilyList");
})
},
},
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,102 @@
<template>
<view v-if="isFirst" class="wrapper">
<view class="bg" @click="onTap">
<view class="edit" @click.stop>
<view class="title">初始体重</view>
<view class="editem" @click="hideKeyboard">
<view class="name">日期</view>
<view class="right">
<picker mode="date" :value="user.firstresulttime" :end="endDate" @change="bindDateChange">
<view class="text">{{regTime?regTime:user.firstresulttime?user.firstresulttime:"请选择"}}
</view>
</picker>
</view>
</view>
<view class="editem">
<view class="name">体重</view>
<view class="right">
<input v-model="weight" type="digit" placeholder="请输入体重" />kg
</view>
</view>
<view class="btn close" @click="onTap()">取消</view>
<view class="btn" @click="handleTarget">确定</view>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
export default {
data() {
return {
regTime: "",
weight: "",
}
},
computed: {
...mapState(["user", "isFirst"]),
endDate() {
return this.$tools.getDate("start")
}
},
methods: {
//
handleTarget() {
let that = this
if (!that.regTime) {
that.$tools.msg("请选择测量日期")
return
}
if (!that.weight) {
that.$tools.msg("请输入测量体重")
return
}
that.$model.getfirstweight({
familyid: that.user.familyid,
time: that.regTime,
weight: that.weight,
}).then(res => {
that.$tools.msg(res.message)
if (res.code == 0) {
that.$store.commit("changeFirst", false);
that.$store.dispatch("getUserInfo", {
familyid: that.user.familyid,
})
}
})
},
//
bindDateChange(e) {
this.regTime = e.target.value
},
onTap() {
this.regTime = ""
this.weight = ""
this.$store.commit("changeFirst", false);
},
hideKeyboard() {
uni.hideKeyboard()
},
}
}
</script>
<style scoped>
.btn {
width: 40%;
float: right;
margin-top: 15px;
}
.edit {
top: 20%
}
.close {
background: #dfdfdf !important;
float: left;
}
</style>

View File

@ -0,0 +1,112 @@
<template>
<view v-if="isRecord" class="wrapper">
<view class="bg" @click="onTap">
<view class="edit" @click.stop>
<view class="title">手动记录</view>
<view class="editem" @click="hideKeyboard">
<view class="left">日期</view>
<view class="right">
<picker mode="date" :value="regTime" :end="endDate" @change="bindDateChange">
<view class="text">{{regTime?regTime:"请选择"}}</view>
</picker>
</view>
</view>
<view class="editem">
<view class="left">体重</view>
<view class="right">
<input v-model="weight" type="digit" placeholder="请输入体重" />kg
</view>
</view>
<view class="btn close" @click="onTap()">取消</view>
<view class="btn" @click="handleTarget">确定</view>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
export default {
data() {
return {
regTime: "",
weight: "",
}
},
computed: {
...mapState(["user", "isRecord"]),
endDate() {
return this.$tools.getDate("start")
},
startDate() {
return this.$tools.GetDateStr(-90);
},
},
methods: {
//
handleTarget() {
let that = this
if (!that.regTime) {
that.$tools.msg("请选择测量日期")
return
}
if (!that.weight) {
that.$tools.msg("请输入测量体重")
return
}
that.$model.getinsertmeasure({
familyid: that.user.familyid,
time: that.regTime,
weight: that.weight,
}).then(res => {
if (res.code != 0) return
that.$tools.msg(res.message)
that.$store.commit("changeRecord", false);
that.$store.dispatch("getResult", {
birthday: that.user.birthday,
familyid: that.user.familyid,
height: that.user.height,
sex: that.user.sex,
})
that.$store.dispatch("getUserInfo", {
familyid: that.user.familyid,
})
that.$emit("getList", this.startDate, this.endDate)
that.regTime = ""
that.weight = ""
})
},
//
bindDateChange(e) {
this.regTime = e.target.value
},
onTap() {
this.regTime = ""
this.weight = ""
this.$store.commit("changeRecord", false);
},
hideKeyboard() {
uni.hideKeyboard()
},
}
}
</script>
<style scoped>
.btn {
width: 40%;
float: right;
margin-top: 15px;
}
.edit {
top: 20%
}
.close {
background: #dfdfdf !important;
float: left;
}
</style>

View File

@ -0,0 +1,80 @@
<template>
<view v-if="isTarget" class="wrapper">
<view class="bg" @click="onTap">
<view class="edit" @click.stop>
<view class="title">目标体重</view>
<view class="editem">
<view class="left">目标体重</view>
<view class="right">
<input class="text" type="digit" placeholder="请输入目标体重" v-model="inputvalue" />kg
</view>
</view>
<view class="btn close" @click="onTap()">取消</view>
<view class="btn" @click="handleWeight">确定</view>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
export default {
data() {
return {
inputvalue: "",
}
},
computed: {
...mapState(["user", "isTarget"]),
startDate() {
return this.$tools.getDate('start');
}
},
methods: {
//
handleWeight() {
let that = this
console.log("startDate", that.startDate)
if (!that.inputvalue) {
that.$tools.msg("请输入目标体重")
return
}
that.$model.setTarget({
familyid: that.user.familyid,
time: that.startDate,
weight: that.inputvalue,
}).then(res => {
if (res.code != 0) return
that.$tools.msg(res.message)
that.$store.commit("changeTarget", false);
that.$store.dispatch("getUserInfo", {
familyid: that.user.familyid,
})
})
},
onTap() {
this.inputvalue = ""
this.$store.commit("changeTarget", false);
}
}
}
</script>
<style scoped>
.btn {
width: 40%;
float: right;
margin-top: 15px;
}
.edit {
top: 20%
}
.close {
background: #dfdfdf !important;
float: left;
}
</style>

View File

@ -0,0 +1,27 @@
<template>
<!--增加audio标签支持-->
<audio
:id="node.attr.id"
:class="node.classStr"
:style="node.styleStr"
:src="node.attr.src"
:loop="node.attr.loop"
:poster="node.attr.poster"
:name="node.attr.name"
:author="node.attr.author"
controls></audio>
</template>
<script>
export default {
name: 'wxParseAudio',
props: {
node: {
type: Object,
default() {
return {};
},
},
},
};
</script>

View File

@ -0,0 +1,87 @@
<template>
<image
:mode="node.attr.mode"
:lazy-load="node.attr.lazyLoad"
:class="node.classStr"
:style="newStyleStr || node.styleStr"
:data-src="node.attr.src"
:src="node.attr.src"
@tap="wxParseImgTap"
@load="wxParseImgLoad"
/>
</template>
<script>
export default {
name: 'wxParseImg',
data() {
return {
newStyleStr: '',
preview: true,
};
},
props: {
node: {
type: Object,
default() {
return {};
},
},
},
methods: {
wxParseImgTap(e) {
if (!this.preview) return;
const { src } = e.currentTarget.dataset;
if (!src) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {// TODO
parent = parent.$parent;
}
parent.preview(src, e);
},
//
wxParseImgLoad(e) {
const { src } = e.currentTarget.dataset;
if (!src) return;
const { width, height } = e.mp.detail;
const recal = this.wxAutoImageCal(width, height);
const { imageheight, imageWidth } = recal;
const { padding, mode } = this.node.attr;
const { styleStr } = this.node;
const imageHeightStyle = mode === 'widthFix' ? '' : `height: ${imageheight}px;`;
this.newStyleStr = `${styleStr}; ${imageHeightStyle}; width: ${imageWidth}px; padding: 0 ${+padding}px;`;
},
//
wxAutoImageCal(originalWidth, originalHeight) {
//
const { padding } = this.node.attr;
// const windowWidth = this.node.$screen.width - (2 * padding);
const windowWidth = this.node.$screen.width - 30;
const results = {};
if (originalWidth < 60 || originalHeight < 60) {
const { src } = this.node.attr;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.removeImageUrl(src);
this.preview = false;
}
//
if (originalWidth > windowWidth) {
// widthwidth
results.imageWidth = windowWidth;
results.imageheight = windowWidth * (originalHeight / originalWidth);
} else {
//
results.imageWidth = originalWidth;
results.imageheight = originalHeight;
}
return results;
},
},
};
</script>

View File

@ -0,0 +1,107 @@
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--table类型-->
<block v-else-if="node.tag == 'table'">
<view :class="node.classStr" class="table" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate1';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate0',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;// TODO currentTargetdataset
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {// TODO
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>

View File

@ -0,0 +1,99 @@
<template>
<view :class="(node.tag == 'li' ? node.classStr : (node.node==='text'?'text':''))">
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<!-- <view :class="node.classStr" :style="node.styleStr"> -->
<view :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate2';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate1',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>

View File

@ -0,0 +1,97 @@
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate11';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate10',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>

View File

@ -0,0 +1,87 @@
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<!--button类型-->
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
{{node.text}}
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
{{node.text}}
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
{{node.text}}
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate11',
props: {
node: {},
},
components: {
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>

View File

@ -0,0 +1,98 @@
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate3';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate2',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>

View File

@ -0,0 +1,98 @@
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate4';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate3',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>

View File

@ -0,0 +1,98 @@
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate5';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate4',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>

View File

@ -0,0 +1,98 @@
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate6';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate5',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>

View File

@ -0,0 +1,98 @@
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate7';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate6',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>

View File

@ -0,0 +1,98 @@
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate8';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate7',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>

View File

@ -0,0 +1,98 @@
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate9';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate8',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>

View File

@ -0,0 +1,98 @@
<template>
<view>
<!--判断是否是标签节点-->
<block v-if="node.node == 'element'">
<block v-if="node.tag == 'button'">
<button type="default" size="mini">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</button>
</block>
<!--li类型-->
<block v-else-if="node.tag == 'li'">
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--video类型-->
<block v-else-if="node.tag == 'video'">
<wx-parse-video :node="node" />
</block>
<!--audio类型-->
<block v-else-if="node.tag == 'audio'">
<wx-parse-audio :node="node" />
</block>
<!--img类型-->
<block v-else-if="node.tag == 'img'">
<wx-parse-img :node="node" />
</block>
<!--a类型-->
<block v-else-if="node.tag == 'a'">
<view @click="wxParseATap" :class="node.classStr" :data-href="node.attr.href" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
<!--br类型-->
<block v-else-if="node.tag == 'br'">
<text>\n</text>
</block>
<!--其他标签-->
<block v-else>
<view :class="node.classStr" :style="node.styleStr">
<block v-for="(node, index) of node.nodes" :key="index">
<wx-parse-template :node="node" />
</block>
</view>
</block>
</block>
<!--判断是否是文本节点-->
<block v-else-if="node.node == 'text'">{{node.text}}</block>
</view>
</template>
<script>
import wxParseTemplate from './wxParseTemplate10';
import wxParseImg from './wxParseImg';
import wxParseVideo from './wxParseVideo';
import wxParseAudio from './wxParseAudio';
export default {
name: 'wxParseTemplate9',
props: {
node: {},
},
components: {
wxParseTemplate,
wxParseImg,
wxParseVideo,
wxParseAudio,
},
methods: {
wxParseATap(e) {
const {
href
} = e.currentTarget.dataset;
if (!href) return;
let parent = this.$parent;
while(!parent.preview || typeof parent.preview !== 'function') {
parent = parent.$parent;
}
parent.navigate(href, e);
},
},
};
</script>

View File

@ -0,0 +1,15 @@
<template>
<!--增加video标签支持并循环添加-->
<view :class="node.classStr" :style="node.styleStr">
<video :class="node.classStr" class="video-video" :src="node.attr.src"></video>
</view>
</template>
<script>
export default {
name: 'wxParseVideo',
props: {
node: {},
},
};
</script>

View File

@ -0,0 +1,261 @@
/**
* html2Json 改造来自: https://github.com/Jxck/html2json
*
*
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
import wxDiscode from './wxDiscode';
import HTMLParser from './htmlparser';
function makeMap(str) {
const obj = {};
const items = str.split(',');
for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
return obj;
}
// Block Elements - HTML 5
const block = makeMap('br,code,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video');
// Inline Elements - HTML 5
const inline = makeMap('a,abbr,acronym,applet,b,basefont,bdo,big,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var');
// Elements that you can, intentionally, leave open
// (and which close themselves)
const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
function removeDOCTYPE(html) {
const isDocument = /<body.*>([^]*)<\/body>/.test(html);
return isDocument ? RegExp.$1 : html;
}
function trimHtml(html) {
return html
.replace(/<!--.*?-->/gi, '')
.replace(/\/\*.*?\*\//gi, '')
.replace(/[ ]+</gi, '<')
.replace(/<script[^]*<\/script>/gi, '')
.replace(/<style[^]*<\/style>/gi, '');
}
function getScreenInfo() {
const screen = {};
wx.getSystemInfo({
success: (res) => {
screen.width = res.windowWidth;
screen.height = res.windowHeight;
},
});
return screen;
}
function html2json(html, customHandler, imageProp, host) {
// 处理字符串
html = removeDOCTYPE(html);
html = trimHtml(html);
html = wxDiscode.strDiscode(html);
// 生成node节点
const bufArray = [];
const results = {
nodes: [],
imageUrls: [],
};
const screen = getScreenInfo();
function Node(tag) {
this.node = 'element';
this.tag = tag;
this.$screen = screen;
}
HTMLParser(html, {
start(tag, attrs, unary) {
// node for this element
const node = new Node(tag);
if (bufArray.length !== 0) {
const parent = bufArray[0];
if (parent.nodes === undefined) {
parent.nodes = [];
}
}
if (block[tag]) {
node.tagType = 'block';
} else if (inline[tag]) {
node.tagType = 'inline';
} else if (closeSelf[tag]) {
node.tagType = 'closeSelf';
}
node.attr = attrs.reduce((pre, attr) => {
const { name } = attr;
let { value } = attr;
if (name === 'class') {
node.classStr = value;
}
// has multi attibutes
// make it array of attribute
if (name === 'style') {
node.styleStr = value;
}
if (value.match(/ /)) {
value = value.split(' ');
}
// if attr already exists
// merge it
if (pre[name]) {
if (Array.isArray(pre[name])) {
// already array, push to last
pre[name].push(value);
} else {
// single value, make it array
pre[name] = [pre[name], value];
}
} else {
// not exist, put it
pre[name] = value;
}
return pre;
}, {});
// 优化样式相关属性
if (node.classStr) {
node.classStr += ` ${node.tag}`;
} else {
node.classStr = node.tag;
}
if (node.tagType === 'inline') {
node.classStr += ' inline';
}
// 对img添加额外数据
if (node.tag === 'img') {
let imgUrl = node.attr.src;
imgUrl = wxDiscode.urlToHttpUrl(imgUrl, imageProp.domain);
Object.assign(node.attr, imageProp, {
src: imgUrl || '',
});
if (imgUrl) {
results.imageUrls.push(imgUrl);
}
}
// 处理a标签属性
if (node.tag === 'a') {
node.attr.href = node.attr.href || '';
}
// 处理font标签样式属性
if (node.tag === 'font') {
const fontSize = [
'x-small',
'small',
'medium',
'large',
'x-large',
'xx-large',
'-webkit-xxx-large',
];
const styleAttrs = {
color: 'color',
face: 'font-family',
size: 'font-size',
};
if (!node.styleStr) node.styleStr = '';
Object.keys(styleAttrs).forEach((key) => {
if (node.attr[key]) {
const value = key === 'size' ? fontSize[node.attr[key] - 1] : node.attr[key];
node.styleStr += `${styleAttrs[key]}: ${value};`;
}
});
}
// 临时记录source资源
if (node.tag === 'source') {
results.source = node.attr.src;
}
if (customHandler.start) {
customHandler.start(node, results);
}
if (unary) {
// if this tag doesn't have end tag
// like <img src="hoge.png"/>
// add to parents
const parent = bufArray[0] || results;
if (parent.nodes === undefined) {
parent.nodes = [];
}
parent.nodes.push(node);
} else {
bufArray.unshift(node);
}
},
end(tag) {
// merge into parent tag
const node = bufArray.shift();
if (node.tag !== tag) {
console.error('invalid state: mismatch end tag');
}
// 当有缓存source资源时于于video补上src资源
if (node.tag === 'video' && results.source) {
node.attr.src = results.source;
delete results.source;
}
if (customHandler.end) {
customHandler.end(node, results);
}
if (bufArray.length === 0) {
results.nodes.push(node);
} else {
const parent = bufArray[0];
if (!parent.nodes) {
parent.nodes = [];
}
parent.nodes.push(node);
}
},
chars(text) {
if (!text.trim()) return;
const node = {
node: 'text',
text,
};
if (customHandler.chars) {
customHandler.chars(node, results);
}
if (bufArray.length === 0) {
results.nodes.push(node);
} else {
const parent = bufArray[0];
if (parent.nodes === undefined) {
parent.nodes = [];
}
parent.nodes.push(node);
}
},
});
return results;
}
export default html2json;

View File

@ -0,0 +1,156 @@
/**
*
* htmlParser改造自: https://github.com/blowsie/Pure-JavaScript-HTML5-Parser
*
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
// Regular Expressions for parsing tags and attributes
const startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z0-9_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
const endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/;
const attr = /([a-zA-Z0-9_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
function makeMap(str) {
const obj = {};
const items = str.split(',');
for (let i = 0; i < items.length; i += 1) obj[items[i]] = true;
return obj;
}
// Empty Elements - HTML 5
const empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr');
// Block Elements - HTML 5
const block = makeMap('address,code,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video');
// Inline Elements - HTML 5
const inline = makeMap('a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var');
// Elements that you can, intentionally, leave open
// (and which close themselves)
const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
// Attributes that have their values filled in disabled="disabled"
const fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected');
function HTMLParser(html, handler) {
let index;
let chars;
let match;
let last = html;
const stack = [];
stack.last = () => stack[stack.length - 1];
function parseEndTag(tag, tagName) {
// If no tag name is provided, clean shop
let pos;
if (!tagName) {
pos = 0;
} else {
// Find the closest opened tag of the same type
tagName = tagName.toLowerCase();
for (pos = stack.length - 1; pos >= 0; pos -= 1) {
if (stack[pos] === tagName) break;
}
}
if (pos >= 0) {
// Close all the open elements, up the stack
for (let i = stack.length - 1; i >= pos; i -= 1) {
if (handler.end) handler.end(stack[i]);
}
// Remove the open elements from the stack
stack.length = pos;
}
}
function parseStartTag(tag, tagName, rest, unary) {
tagName = tagName.toLowerCase();
if (block[tagName]) {
while (stack.last() && inline[stack.last()]) {
parseEndTag('', stack.last());
}
}
if (closeSelf[tagName] && stack.last() === tagName) {
parseEndTag('', tagName);
}
unary = empty[tagName] || !!unary;
if (!unary) stack.push(tagName);
if (handler.start) {
const attrs = [];
rest.replace(attr, function genAttr(matches, name) {
const value = arguments[2] || arguments[3] || arguments[4] || (fillAttrs[name] ? name : '');
attrs.push({
name,
value,
escaped: value.replace(/(^|[^\\])"/g, '$1\\"'), // "
});
});
if (handler.start) {
handler.start(tagName, attrs, unary);
}
}
}
while (html) {
chars = true;
if (html.indexOf('</') === 0) {
match = html.match(endTag);
if (match) {
html = html.substring(match[0].length);
match[0].replace(endTag, parseEndTag);
chars = false;
}
// start tag
} else if (html.indexOf('<') === 0) {
match = html.match(startTag);
if (match) {
html = html.substring(match[0].length);
match[0].replace(startTag, parseStartTag);
chars = false;
}
}
if (chars) {
index = html.indexOf('<');
let text = '';
while (index === 0) {
text += '<';
html = html.substring(1);
index = html.indexOf('<');
}
text += index < 0 ? html : html.substring(0, index);
html = index < 0 ? '' : html.substring(index);
if (handler.chars) handler.chars(text);
}
if (html === last) throw new Error(`Parse Error: ${html}`);
last = html;
}
// Clean up any remaining tags
parseEndTag();
}
export default HTMLParser;

View File

@ -0,0 +1,195 @@
// HTML 支持的数学符号
function strNumDiscode(str) {
str = str.replace(/&forall;/g, '∀');
str = str.replace(/&part;/g, '∂');
str = str.replace(/&exist;/g, '∃');
str = str.replace(/&empty;/g, '∅');
str = str.replace(/&nabla;/g, '∇');
str = str.replace(/&isin;/g, '∈');
str = str.replace(/&notin;/g, '∉');
str = str.replace(/&ni;/g, '∋');
str = str.replace(/&prod;/g, '∏');
str = str.replace(/&sum;/g, '∑');
str = str.replace(/&minus;/g, '');
str = str.replace(/&lowast;/g, '');
str = str.replace(/&radic;/g, '√');
str = str.replace(/&prop;/g, '∝');
str = str.replace(/&infin;/g, '∞');
str = str.replace(/&ang;/g, '∠');
str = str.replace(/&and;/g, '∧');
str = str.replace(/&or;/g, '');
str = str.replace(/&cap;/g, '∩');
str = str.replace(/&cup;/g, '');
str = str.replace(/&int;/g, '∫');
str = str.replace(/&there4;/g, '∴');
str = str.replace(/&sim;/g, '');
str = str.replace(/&cong;/g, '≅');
str = str.replace(/&asymp;/g, '≈');
str = str.replace(/&ne;/g, '≠');
str = str.replace(/&le;/g, '≤');
str = str.replace(/&ge;/g, '≥');
str = str.replace(/&sub;/g, '⊂');
str = str.replace(/&sup;/g, '⊃');
str = str.replace(/&nsub;/g, '⊄');
str = str.replace(/&sube;/g, '⊆');
str = str.replace(/&supe;/g, '⊇');
str = str.replace(/&oplus;/g, '⊕');
str = str.replace(/&otimes;/g, '⊗');
str = str.replace(/&perp;/g, '⊥');
str = str.replace(/&sdot;/g, '⋅');
return str;
}
// HTML 支持的希腊字母
function strGreeceDiscode(str) {
str = str.replace(/&Alpha;/g, 'Α');
str = str.replace(/&Beta;/g, 'Β');
str = str.replace(/&Gamma;/g, 'Γ');
str = str.replace(/&Delta;/g, 'Δ');
str = str.replace(/&Epsilon;/g, 'Ε');
str = str.replace(/&Zeta;/g, 'Ζ');
str = str.replace(/&Eta;/g, 'Η');
str = str.replace(/&Theta;/g, 'Θ');
str = str.replace(/&Iota;/g, 'Ι');
str = str.replace(/&Kappa;/g, 'Κ');
str = str.replace(/&Lambda;/g, 'Λ');
str = str.replace(/&Mu;/g, 'Μ');
str = str.replace(/&Nu;/g, 'Ν');
str = str.replace(/&Xi;/g, 'Ν');
str = str.replace(/&Omicron;/g, 'Ο');
str = str.replace(/&Pi;/g, 'Π');
str = str.replace(/&Rho;/g, 'Ρ');
str = str.replace(/&Sigma;/g, 'Σ');
str = str.replace(/&Tau;/g, 'Τ');
str = str.replace(/&Upsilon;/g, 'Υ');
str = str.replace(/&Phi;/g, 'Φ');
str = str.replace(/&Chi;/g, 'Χ');
str = str.replace(/&Psi;/g, 'Ψ');
str = str.replace(/&Omega;/g, 'Ω');
str = str.replace(/&alpha;/g, 'α');
str = str.replace(/&beta;/g, 'β');
str = str.replace(/&gamma;/g, 'γ');
str = str.replace(/&delta;/g, 'δ');
str = str.replace(/&epsilon;/g, 'ε');
str = str.replace(/&zeta;/g, 'ζ');
str = str.replace(/&eta;/g, 'η');
str = str.replace(/&theta;/g, 'θ');
str = str.replace(/&iota;/g, 'ι');
str = str.replace(/&kappa;/g, 'κ');
str = str.replace(/&lambda;/g, 'λ');
str = str.replace(/&mu;/g, 'μ');
str = str.replace(/&nu;/g, 'ν');
str = str.replace(/&xi;/g, 'ξ');
str = str.replace(/&omicron;/g, 'ο');
str = str.replace(/&pi;/g, 'π');
str = str.replace(/&rho;/g, 'ρ');
str = str.replace(/&sigmaf;/g, 'ς');
str = str.replace(/&sigma;/g, 'σ');
str = str.replace(/&tau;/g, 'τ');
str = str.replace(/&upsilon;/g, 'υ');
str = str.replace(/&phi;/g, 'φ');
str = str.replace(/&chi;/g, 'χ');
str = str.replace(/&psi;/g, 'ψ');
str = str.replace(/&omega;/g, 'ω');
str = str.replace(/&thetasym;/g, 'ϑ');
str = str.replace(/&upsih;/g, 'ϒ');
str = str.replace(/&piv;/g, 'ϖ');
str = str.replace(/&middot;/g, '·');
return str;
}
function strcharacterDiscode(str) {
// 加入常用解析
str = str.replace(/&nbsp;/g, ' ');
str = str.replace(/&ensp;/g, '');
str = str.replace(/&emsp;/g, ' ');
str = str.replace(/&quot;/g, "'");
str = str.replace(/&amp;/g, '&');
str = str.replace(/&lt;/g, '<');
str = str.replace(/&gt;/g, '>');
str = str.replace(/&#8226;/g, '•');
return str;
}
// HTML 支持的其他实体
function strOtherDiscode(str) {
str = str.replace(/&OElig;/g, 'Œ');
str = str.replace(/&oelig;/g, 'œ');
str = str.replace(/&Scaron;/g, 'Š');
str = str.replace(/&scaron;/g, 'š');
str = str.replace(/&Yuml;/g, 'Ÿ');
str = str.replace(/&fnof;/g, 'ƒ');
str = str.replace(/&circ;/g, 'ˆ');
str = str.replace(/&tilde;/g, '˜');
str = str.replace(/&ensp;/g, '');
str = str.replace(/&emsp;/g, '');
str = str.replace(/&thinsp;/g, '');
str = str.replace(/&zwnj;/g, '');
str = str.replace(/&zwj;/g, '');
str = str.replace(/&lrm;/g, '');
str = str.replace(/&rlm;/g, '');
str = str.replace(/&ndash;/g, '');
str = str.replace(/&mdash;/g, '—');
str = str.replace(/&lsquo;/g, '');
str = str.replace(/&rsquo;/g, '');
str = str.replace(/&sbquo;/g, '');
str = str.replace(/&ldquo;/g, '“');
str = str.replace(/&rdquo;/g, '”');
str = str.replace(/&bdquo;/g, '„');
str = str.replace(/&dagger;/g, '†');
str = str.replace(/&Dagger;/g, '‡');
str = str.replace(/&bull;/g, '•');
str = str.replace(/&hellip;/g, '…');
str = str.replace(/&permil;/g, '‰');
str = str.replace(/&prime;/g, '');
str = str.replace(/&Prime;/g, '″');
str = str.replace(/&lsaquo;/g, '');
str = str.replace(/&rsaquo;/g, '');
str = str.replace(/&oline;/g, '‾');
str = str.replace(/&euro;/g, '€');
str = str.replace(/&trade;/g, '™');
str = str.replace(/&larr;/g, '←');
str = str.replace(/&uarr;/g, '↑');
str = str.replace(/&rarr;/g, '→');
str = str.replace(/&darr;/g, '↓');
str = str.replace(/&harr;/g, '↔');
str = str.replace(/&crarr;/g, '↵');
str = str.replace(/&lceil;/g, '⌈');
str = str.replace(/&rceil;/g, '⌉');
str = str.replace(/&lfloor;/g, '⌊');
str = str.replace(/&rfloor;/g, '⌋');
str = str.replace(/&loz;/g, '◊');
str = str.replace(/&spades;/g, '♠');
str = str.replace(/&clubs;/g, '♣');
str = str.replace(/&hearts;/g, '♥');
str = str.replace(/&diams;/g, '♦');
str = str.replace(/&#39;/g, "'");
return str;
}
function strDiscode(str) {
str = strNumDiscode(str);
str = strGreeceDiscode(str);
str = strcharacterDiscode(str);
str = strOtherDiscode(str);
return str;
}
function urlToHttpUrl(url, domain) {
if (/^\/\//.test(url)) {
return `https:${url}`;
} else if (/^\//.test(url)) {
return `https://${domain}${url}`;
}
return url;
}
export default {
strDiscode,
urlToHttpUrl,
};

View File

@ -0,0 +1,102 @@
## uParse 适用于 uni-app/mpvue 的富文本解析组件
> 支持 Html、Markdown 解析Fork自: [mpvue-wxParse](https://github.com/F-loat/mpvue-wxParse)
## 属性
| 名称 | 类型 | 默认值 | 描述 |
| -----------------|--------------- | ------------- | ---------------- |
| loading | Boolean | false | 数据加载状态 |
| className | String | — | 自定义 class 名称 |
| content | String | — | 渲染内容 |
| noData | String | 数据不能为空 | 空数据时的渲染展示 |
| startHandler | Function | 见源码 | 自定义 parser 函数 |
| endHandler | Function | null | 自定义 parser 函数 |
| charsHandler | Function | null | 自定义 parser 函数 |
| imageProp | Object | 见下文 | 图片相关参数 |
### 自定义 parser 函数具体介绍
* 传入的参数为当前节点 `node` 对象及解析结果 `results` 对象,例如 `startHandler(node, results)`
* 无需返回值,通过对传入的参数直接操作来完成需要的改动
* 自定义函数会在原解析函数处理之后执行
### imageProp 对象具体属性
| 名称 | 类型 | 默认值 | 描述 |
| -----------------|--------------- | ------------- | ------------------ |
| mode | String | 'aspectFit' | 图片裁剪、缩放的模式 |
| padding | Number | 0 | 图片内边距 |
| lazyLoad | Boolean | false | 图片懒加载 |
| domain | String | '' | 图片服务域名 |
## 事件
| 名称 | 参数 | 描述 |
| -----------------|----------------- | ---------------- |
| preview | 图片地址,原始事件 | 预览图片时触发 |
| navigate | 链接地址,原始事件 | 点击链接时触发 |
## 基本使用方法
``` vue
<template>
<div>
<u-parse :content="article" @preview="preview" @navigate="navigate" />
</div>
</template>
<script>
import uParse from '@/components/u-parse/u-parse.vue'
export default {
components: {
uParse
},
data () {
return {
article: '<div>我是HTML代码</div>'
}
},
methods: {
preview(src, e) {
// do something
},
navigate(href, e) {
// do something
}
}
}
</script>
<style>
@import url("@/components/u-parse/u-parse.css");
</style>
```
## 渲染 Markdown
> 先将 markdown 转换为 html 即可
```
npm install marked
```
``` js
import marked from 'marked'
import uParse from '@/components/u-parse/u-parse.vue'
export default {
components: {
uParse
},
data () {
return {
article: marked(`#hello, markdown!`)
}
}
}
```

View File

@ -0,0 +1,232 @@
/**
* author: Di (微信小程序开发工程师)
* organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
* 垂直微信小程序开发交流社区
*
* github地址: https://github.com/icindy/wxParse
*
* for: 微信小程序富文本解析
* detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
*/
.wxParse {
width: 100%;
font-family: Helvetica, sans-serif;
font-size: 30upx;
color: #666;
line-height: 1.8;
}
.wxParse view {
word-break: hyphenate;
}
.wxParse .inline {
display: inline;
margin: 0;
padding: 0;
}
.wxParse .div {
margin: 0;
padding: 0;
}
.wxParse .h1 .text {
font-size: 2em;
margin: 0.67em 0;
}
.wxParse .h2 .text {
font-size: 1.5em;
margin: 0.83em 0;
}
.wxParse .h3 .text {
font-size: 1.17em;
margin: 1em 0;
}
.wxParse .h4 .text {
margin: 1.33em 0;
}
.wxParse .h5 .text {
font-size: 0.83em;
margin: 1.67em 0;
}
.wxParse .h6 .text {
font-size: 0.67em;
margin: 2.33em 0;
}
.wxParse .h1 .text,
.wxParse .h2 .text,
.wxParse .h3 .text,
.wxParse .h4 .text,
.wxParse .h5 .text,
.wxParse .h6 .text,
.wxParse .b,
.wxParse .strong {
font-weight: bolder;
}
.wxParse .p {
margin: 1em 0;
}
.wxParse .i,
.wxParse .cite,
.wxParse .em,
.wxParse .var,
.wxParse .address {
font-style: italic;
}
.wxParse .pre,
.wxParse .tt,
.wxParse .code,
.wxParse .kbd,
.wxParse .samp {
font-family: monospace;
}
.wxParse .pre {
overflow: auto;
background: #f5f5f5;
padding: 16upx;
white-space: pre;
margin: 1em 0upx;
}
.wxParse .code {
display: inline;
background: #f5f5f5;
}
.wxParse .big {
font-size: 1.17em;
}
.wxParse .small,
.wxParse .sub,
.wxParse .sup {
font-size: 0.83em;
}
.wxParse .sub {
vertical-align: sub;
}
.wxParse .sup {
vertical-align: super;
}
.wxParse .s,
.wxParse .strike,
.wxParse .del {
text-decoration: line-through;
}
.wxParse .strong,
.wxParse .s {
display: inline;
}
.wxParse .a {
color: deepskyblue;
}
.wxParse .video {
text-align: center;
margin: 22upx 0;
}
.wxParse .video-video {
width: 100%;
}
.wxParse .img {
display: inline-block;
width: 0;
height: 0;
max-width: 100%;
overflow: hidden;
}
.wxParse .blockquote {
margin: 10upx 0;
padding: 22upx 0 22upx 22upx;
font-family: Courier, Calibri, "宋体";
background: #f5f5f5;
border-left: 6upx solid #dbdbdb;
}
.wxParse .blockquote .p {
margin: 0;
}
.wxParse .ul, .wxParse .ol {
display: block;
margin: 1em 0;
padding-left: 33upx;
}
.wxParse .ol {
list-style-type: disc;
}
.wxParse .ol {
list-style-type: decimal;
}
.wxParse .ol>weixin-parse-template,.wxParse .ul>weixin-parse-template {
display: list-item;
align-items: baseline;
text-align: match-parent;
}
.wxParse .ol>.li,.wxParse .ul>.li {
display: list-item;
align-items: baseline;
text-align: match-parent;
}
.wxParse .ul .ul, .wxParse .ol .ul {
list-style-type: circle;
}
.wxParse .ol .ol .ul, .wxParse .ol .ul .ul, .wxParse .ul .ol .ul, .wxParse .ul .ul .ul {
list-style-type: square;
}
.wxParse .u {
text-decoration: underline;
}
.wxParse .hide {
display: none;
}
.wxParse .del {
display: inline;
}
.wxParse .figure {
overflow: hidden;
}
.wxParse .table {
width: 100%;
}
.wxParse .thead, .wxParse .tfoot, .wxParse .tr {
display: flex;
flex-direction: row;
}
.wxParse .tr {
width:100%;
display: flex;
border-right: 2upx solid #e0e0e0;
border-bottom: 2upx solid #e0e0e0;
}
.wxParse .th,
.wxParse .td {
display: flex;
width: 1276upx;
overflow: auto;
flex: 1;
padding: 11upx;
border-left: 2upx solid #e0e0e0;
}
.wxParse .td:last {
border-top: 2upx solid #e0e0e0;
}
.wxParse .th {
background: #f0f0f0;
border-top: 2upx solid #e0e0e0;
}

View File

@ -0,0 +1,118 @@
<!--**
* forked fromhttps://github.com/F-loat/mpvue-wxParse
*
* github地址: https://github.com/dcloudio/uParse
*
* for: uni-app框架下 富文本解析
*/-->
<template>
<!--基础元素-->
<div class="wxParse" :class="className" v-if="!loading">
<block v-for="(node,index) of nodes" :key="index">
<wxParseTemplate :node="node" />
</block>
</div>
</template>
<script>
import HtmlToJson from './libs/html2json';
import wxParseTemplate from './components/wxParseTemplate0';
export default {
name: 'wxParse',
props: {
loading: {
type: Boolean,
default: false,
},
className: {
type: String,
default: '',
},
content: {
type: String,
default: '',
},
noData: {
type: String,
default: '',
},
startHandler: {
type: Function,
default() {
return (node) => {
node.attr.class = null;
node.attr.style = null;
};
},
},
endHandler: {
type: Function,
default: null,
},
charsHandler: {
type: Function,
default: null,
},
imageProp: {
type: Object,
default() {
return {
mode: 'aspectFit',
padding: 0,
lazyLoad: false,
domain: '',
};
},
},
},
components: {
wxParseTemplate,
},
data() {
return {
imageUrls: [],
};
},
computed: {
nodes() {
const {
content,
noData,
imageProp,
startHandler,
endHandler,
charsHandler,
} = this;
const parseData = content || noData;
const customHandler = {
start: startHandler,
end: endHandler,
chars: charsHandler,
};
const results = HtmlToJson(parseData, customHandler, imageProp, this);
this.imageUrls = results.imageUrls;
console.log(results)
return results.nodes;
},
},
methods: {
navigate(href, $event) {
this.$emit('navigate', href, $event);
},
preview(src, $event) {
if (!this.imageUrls.length) return;
wx.previewImage({
current: src,
urls: this.imageUrls,
});
this.$emit('preview', src, $event);
},
removeImageUrl(src) {
const { imageUrls } = this;
imageUrls.splice(imageUrls.indexOf(src), 1);
},
},
};
</script>

167
components/userLogin.vue Normal file
View File

@ -0,0 +1,167 @@
<template>
<view class="wrapper" v-if="isLogin">
<view class="popup" @click="onTap">
<view class="block" @click.stop>
<view class="item" @click="getUserInfo">
<image src="../static/2253.png" class="image1"></image>
<view class="text">
<view><text></text>体重体脂测量与记录</view>
<view><text></text>18项身体数据分析身体评分</view>
<view><text></text>满足所有人群检测</view>
</view>
<view class="pbtn">立即体验</view>
</view>
<icon class="t-icon t-icon-quxiao image2" @click="onTap"></icon>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
export default {
data() {
return {}
},
props: {
url: {
type: String,
default: ''
}
},
mounted() {},
computed: {
...mapState(["user", "isLogin"]),
},
methods: {
onTap() {
this.$store.commit("changeUserLogin", false);
},
getUserInfo() {
let that = this
uni.getUserProfile({
desc: '登录',
success: (infoRes) => {
console.log("getUserProfile授权成功", infoRes, that.url);
uni.redirectTo({
url: `/pageTwo/login/login?name=` + infoRes.userInfo.nickName +
"&headimg=" + infoRes.userInfo.avatarUrl + "&url=" + that.url
})
// that.DecodeEncryptedData(infoRes)
that.$store.commit("changeUserLogin", false);
},
fail: (res) => {
console.log("授权失败", res)
}
});
},
//
DecodeEncryptedData(data) {
let that = this
that.$model.getDecryptdata({
encryptedData: data.encryptedData,
iv: data.iv,
tenantid: uni.getStorageSync('tenantid'),
sessionid: uni.getStorageSync('sessionid'),
}).then(res => {
if (res.code != 0) return
uni.redirectTo({
url: `/pageTwo/login/login`
})
console.log("解密成功", res)
}).catch(e => {
console.log("解密失败", e)
})
},
}
}
</script>
<style scoped lang="scss">
.wrapper {
width: 100%;
height: 100%;
}
.popup {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 99;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.4);
}
.item {
width: 291px;
height: 324px;
position: relative;
left: 0;
right: 0;
top: 0;
margin: auto;
bottom: 0;
padding: 0;
border-radius: 15px;
text {
width: 8px;
height: 8px;
background: $greencolor;
display: inline-block;
border-radius: 50%;
margin-right: 5px;
}
.image1 {
width: 291px;
height: 324px;
}
.text {
position: absolute;
top: 60%;
font-size: 12px;
color: #666;
line-height: 28px;
right: 10px;
left: 30px;
text-align: left;
}
}
.pbtn {
background: $btncolor;
text-align: center;
border-radius: 10px;
margin: 5px auto;
width: 50%;
color: #fff;
position: absolute;
bottom: 10px;
left: 0;
right: 0;
margin: auto;
padding: 5px 0;
}
.image2 {
width: 30px;
height: 30px;
font-size: 30px;
color: #666;
background-color: #fff;
border-radius: 50%;
position: absolute;
left: 0;
right: 0;
margin: 20px auto;
}
</style>

31
main.js Normal file
View File

@ -0,0 +1,31 @@
import Vue from 'vue'
import App from './App'
import './uni.scss';
import './assets/common.scss'
import './assets/iconfont-weapp-icon.css'
import './assets/iconfont.css'
import store from './store'
Vue.prototype.$store = store;
// js
import tools from '@/tools/tools.js'
Vue.prototype.$tools = tools;
// json
import data4 from '@/tools/data4.js'
Vue.prototype.weightInfo = data4;
//请求
import http from '@/tools/https.js'
Vue.prototype.$http = http;
//接口
import model from '@/tools/model.js'
Vue.prototype.$model = model;
Vue.config.productionTip = false
App.mpType = 'app'
//让页面onLoad在onLaunch后执行
Vue.prototype.$onLaunched = new Promise(resolve => {
Vue.prototype.$isResolve = resolve
})
const app = new Vue({
...App
})
app.$mount()

92
manifest.json Normal file
View File

@ -0,0 +1,92 @@
{
"name" : "每日一称成人",
"appid" : "__UNI__1EBB7E8",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
/* 5+App */
"app-plus" : {
"usingComponents" : true,
"nvueCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* */
"modules" : {},
/* */
"distribute" : {
/* android */
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
/* ios */
"ios" : {},
/* SDK */
"sdkConfigs" : {}
}
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "wx3e83b37ba682faf5",
"setting" : {
"urlCheck" : true,
"minified" : true,
"es6" : true,
"postcss" : true
},
"usingComponents" : true,
//
"optimization" : {
"Package8s" : true
},
"plugins" : {
"sdkPlugin" : {
// 线
"version" : "2.1.0", //
"provider" : "wx17e93aad47cdae1a" //appid
}
}
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
}
}

3
package-lock.json generated Normal file
View File

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

3
package.json Normal file
View File

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

177
pageTwo/compk/pkdetail.vue Normal file
View File

@ -0,0 +1,177 @@
<template>
<view class="content pkconp">
<view class="header">
<view class="left">
<image :src="memInfo.headimg" class="image1"></image>
</view>
<view class="right">
<view class="name">{{memInfo.name?memInfo.name:memInfo.nickname}}</view>
<view class="top">
<view class="age">性别{{memInfo.sex==0?'未知':memInfo.sex==1?'男':'女'}}</view>
<view>年龄{{user.age}}</view>
</view>
</view>
<!-- <button class="pkclass" @click="handleImage">保存图片</button> -->
</view>
<view class="box">
<view class="item">
<view>{{memInfo.day?memInfo.day:'0'}}</view>
<text>时间()</text>
</view>
<view class="item">
<view>{{Math.abs(memInfo.weightdiff)}}</view>
<text v-if="Number(memInfo.weightdiff)>0">增重(kg)</text>
<text v-else>减重(kg)</text>
</view>
<view class="item">
<view>{{Math.abs(memInfo.fat_wdiff)}}</view>
<text v-if="Number(memInfo.fat_wdiff)>0">增脂(kg)</text>
<text v-else>减脂(kg)</text>
</view>
<view class="time">
<view>
<icon class="yuanxing"></icon>{{memInfo.time}}
</view>数据变化
</view>
</view>
<view class="control">
<!-- 名称 -->
<view class="title">
<view class="name"></view>
<view>趋势</view>
<view>之前</view>
<view>之后</view>
</view>
<view v-for="(ite,ind) in listStr" :key="ind" class="li">
<view class="name">
<view class="icon">
<icon class="t-icon" :class="'t-icon-'+ite.key"></icon>
</view>
<text>{{ite.title}}</text>
</view>
<view class="num" v-if="ite.title=='体型'||ite.title=='肥胖等级'">
<icon class="t-icon t-icon-hengxian"></icon>
</view>
<view class="num" v-else>
{{ite.num}}
<icon class="t-icon t-icon-shang" v-if="ite.vs=='1'"></icon>
<icon class="t-icon t-icon-xia" v-if="ite.vs=='-1'"></icon>
<icon class="t-icon t-icon-hengxian" v-if="!ite.vs||ite.vs=='0'||ite.num=='0.00'"></icon>
</view>
<view class="f0" v-if="ite.title=='体型'||ite.title=='肥胖等级'">
<text>{{ite.fevaluation}}</text>
</view>
<view class="f" v-else>
<view>{{ite.fvalue}}</view>
<text v-if="ite.fevaluation">{{ite.fevaluation}}</text>
</view>
<view class="f0" v-if="ite.title=='体型'||ite.title=='肥胖等级'">
<text>{{ite.sevaluation}}</text>
</view>
<view class="f" v-else>
<view>{{ite.svalue}}</view>
<text v-if="ite.fevaluation">{{ite.sevaluation}}</text>
</view>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
export default {
onLoad(options) {
let that = this
console.log("options", options)
if (options.info) {
that.infoID = JSON.parse(options.info)
that.handleSharepic(that.infoID)
}
},
computed: {
...mapState(["user"]),
},
methods: {
handleSharepic(id) {
let that = this
that.$model.getresultdiff({
familyid: id.familyid,
firstId: id.firstId,
secondId: id.secondId,
}).then(res => {
console.log("res", res)
if (res.code != 0) {
this.$tools.msg(res.message)
return
}
that.handleInfoList(res.data)
})
},
handleInfoList(data) {
let that = this
that.memInfo = data
let listStr = that.weightInfo.infoList(data.firstresult)
let str = that.memInfo.secondresult
for (var i = 0; i < listStr.length; i++) {
listStr[i].svalue = str[listStr[i].key];
let num = listStr[i].svalue - listStr[i].fvalue
if (num < 0) {
listStr[i].vs = '-1'
} else if (num > 0) {
listStr[i].vs = '1'
} else {
listStr[i].vs = '0'
}
listStr[i].num = Math.abs(num).toFixed(2)
if (str[listStr[i].level]) {
listStr[i].sevaluation = str[listStr[i].level];
}
console.log("listStr[i].title", listStr[i].title)
// if (listStr[i].title == "") {
// if (listStr[i].svalue > Number(str.standardweight)) {
// listStr[i].sevaluation = ""
// } else if (listStr[i].svalue < Number(str.standardweight)) {
// listStr[i].sevaluation = ""
// } else {
// listStr[i][i].sevaluation = ""
// }
// }
}
that.listStr = listStr
console.log("listStr[i]", that.memInfo, listStr)
},
},
data() {
return {
infoID: {},
memInfo: {},
listStr: [],
}
},
}
</script>
<style scoped lang="scss">
.age {
margin-right: 20px;
}
.icon {
width: 18px;
height: 18px;
padding: 3px;
margin-right: 7px;
background-color: #aaa;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.t-icon-hengxian {
height: 4px !important;
}
</style>

217
pageTwo/home/index.vue Normal file
View File

@ -0,0 +1,217 @@
<template>
<view class="common homePage">
<!-- 头部 -->
<headTop :token="token"></headTop>
<!-- 健康报告 -->
<view class="myinfo myinfoPage">
<view class="mt-15" v-show="MeasureResult&&MeasureResult.muscle==0">
<view class="unusual">体脂测量异常请重新测量</view>
</view>
<view v-if="infoList.length">
<view class="box">
<view class="left">
<text class="text">本次健康评分</text>
<view class="circleprogress">
<view class="wrapper">
<view class="leftprogress" :style="{ width: MeasureResult.cmi + '%'}">
</view>
</view>
<view class="fen">
<view>{{MeasureResult.cmi}}</view>
</view>
</view>
</view>
<view class="right">
<view class="item">
<view><text>{{MeasureResult.height}}</text>cm</view>
<view class="tivon">身高</image>
</view>
</view>
<view class="item">
<view><text>{{MeasureResult.weight}}</text>kg</view>
<view>体重</view>
</view>
<!-- <view class="item">
<view><text>{{MeasureResult.lbm}}</text>kg</view>
<view class="tivon">去脂体重</image>
</view>
</view> -->
<view class="item">
<view><text>{{MeasureResult.bodyage}}</text></view>
<view>体龄</view>
</view>
<view class="item">
<view><text class="f-14">{{MeasureResult.body}}</text></view>
<view>体型</view>
</view>
</view>
</view>
<view class="box1">
<view class="h2">
<icon class="yuanxing"></icon>其他人体成分分析
</view>
<view class="list" v-for="(item,index) in infoList" :key="index" @click="handleToggle(index)">
<view class="block">
<view class="name">
<icon class="t-icon iconfont" :class="'t-icon-'+item.key"></icon>
{{item.title}}
</view>
<view class="val" v-if="item.title!='肥胖等级'">
{{item.fvalue?item.fvalue:'0'}}{{item.dw}}
</view>
<view class="val0" v-else>{{item.fevaluation}}</view>
<view class="level" v-if="item.title!='肥胖等级'">
<view class="btnf" :style="{backgroundColor:item.color}">{{item.fevaluation}}</view>
</view>
<view class="icon">
<icon class="iconfont icon-arrow-down" v-if="item.desc"></icon>
</view>
</view>
<view class="desc" v-if="item.showCon">
<view v-if="item.desc">{{item.desc}}</view>
<view class="statuevue" v-if="item.slist">
<view class="bi" v-if="item.title!='基础代谢'">
<view class="item" v-for="(ite , ind) in item.slist" :key="ind"
:style="{backgroundColor:ite.color}">
<view class="span1">{{ite.text}}</view>
<view v-if="ite.text==item.fevaluation&&item.fvalue>ite.maxvalue"
style="right: 10px" class="peobox">
<view class="xx"></view>
</view>
<view v-if="ite.text==item.fevaluation&&item.fvalue<=ite.maxvalue"
:style="'left:'+item.leftval+'rem'" class="peobox">
<view class="xx"></view>
</view>
<view class="span" v-if="ind<item.slist.length-1">{{ite.maxvalue}}</view>
</view>
</view>
<view v-else>
<view class="kcalClass">
标准值:{{item.slist[0].maxvalue}}kcal
</view>
</view>
</view>
</view>
</view>
</view>
<view class="introction">
<icon class="t-icon t-icon-tishi"></icon>
<span>此测量数据仅供参考不可代替医学专业测试</span>
</view>
</view>
<view v-else class="nolist">
<icon class="iconfont icon-zanwu"></icon>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
import headTop from "@/components/header/head.vue"
export default {
components: {
headTop
},
data() {
return {
token: null,
devtype: 0,
infoList: [],
deviceId: null,
};
},
computed: {
...mapState(["user", "MeasureResult"]),
},
onUnload: function() {
let that = this
uni.switchTab({
url: "/pages/index/index"
})
},
onShow() {
let that = this;
that.token = uni.getStorageSync('token')
uni.onBluetoothAdapterStateChange(function(res) {
that.$store.commit("changeBluetooth", res.available);
console.log("报告页监听蓝牙状态openBluetoothAdapter", res.available)
})
},
onLoad(options) {
let that = this;
console.log("options", options)
if (options) {
that.devtype = options.t
that.deviceId = options.sn
}
this.$nextTick(() => {
that.handleToggle(0)
})
},
watch: {
MeasureResult() {
this.handleToggle(0)
}
},
methods: {
//
handleToggle(index) {
let that = this
if (!that.MeasureResult) return
let str = this.weightInfo.infoList(that.MeasureResult).slice(1, 14)
for (var i = 0; i < str.length; i++) {
if (i == index) {
str[i].showCon = !str[i].showCon
} else {
str[i].showCon = false
}
}
that.infoList = this.weightInfo.infoList(that.MeasureResult).slice(1, 14)
},
},
}
</script>
<style lang="scss" scoped>
.myinfo {
margin-top: 105px;
}
.val0 {
position: absolute;
left: 40%;
margin-left: 3px;
}
.wrapper {
z-index: 9 !important;
}
.unusual {
font-size: 14px;
border-radius: 8px;
text-align: center;
color: #e83a1e;
margin: 15px;
background: #f7e4c8;
padding: 5px 0;
}
.introction {
display: flex;
margin-left: 15px;
margin-bottom: 20px;
font-size: 12px;
color: #666;
.t-icon {
width: 15px;
height: 15px;
margin-right: 5px;
}
}
</style>

76
pageTwo/login/detail.vue Normal file
View File

@ -0,0 +1,76 @@
<template>
<view class="content">
<view>
<view class="title">{{content.title}}</view>
<view class="time">发布时间{{content.createtime}}</view>
<u-parse :content="content.content" @preview="preview" @navigate="navigate"></u-parse>
</view>
</view>
</template>
<script>
import uParse from '@/components/u-parse/u-parse.vue'
export default {
data() {
return {
content: "",
url: null
}
},
components: {
uParse
},
onLoad(option) {
console.log(option)
if (option.id) {
this.getOrderDetail(option.id);
}
if (option.url) {
this.url = option.url
} else {
this.url = null
}
},
methods: {
getOrderDetail(orderno) {
this.$model.GetAdListDetail({
id: orderno
}).then(res => {
if (res.code != 0) return
this.content = res.data
console.log("资讯详情", res)
});
},
preview(src, e) {
// do something
},
navigate(href, e) {
// do something
}
}
}
</script>
<style scoped>
@import url("@/components/u-parse/u-parse.css");
.content {
padding: 30rpx;
}
.title {
width: 100%;
margin-bottom: 15px;
text-align: left;
font-size: 18px;
font-weight: bold;
}
.time {
width: 100%;
text-align: left;
margin-bottom: 15px;
color: #666;
}
</style>

340
pageTwo/login/login.vue Normal file
View File

@ -0,0 +1,340 @@
<template>
<view class="content">
<view class="top">
<image src="@/static/logo.png"></image>
<text>每日一称-成人</text>
</view>
<view class="edit">
<view class="ts">
<view>短信验证码登录</view>
</view>
<view class="editem">
<view class="input">
<input class="uni-input" v-model="phone" placeholder="请输入手机号" />
</view>
<view class="input yanzheng">
<view class="yanzhengma">
<input class="uni-input" v-model="code" placeholder="请输入验证码" />
</view>
<button class="code" type="none" @tap="handleCode" v-model="codeInfo"
:disabled="disabled">{{second<60 ? second+'S后重发':'获取验证码'}}
</button>
</view>
</view>
<view class="btnlogin" @click="handleTelLogin">登录</view>
</view>
<view class="btnGroup">
<view class="wxbtn" v-if="iswxphone">
<button open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
<icon class="iconfont icon-weixin"></icon>
<text>微信登录</text>
</button>
</view>
<view class="xieyi">
<checkbox-group @change="checkboxChange" class="group">
<checkbox :value="1" checked="true" style="transform:scale(0.7)" />同意每日一称<text
@click="handlexieyi">个人信息保护政策</text>
</checkbox-group>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
phone: "",
code: "",
disabled: false,
second: 60,
value: 1,
iswxphone: true,
infoRes: {}
}
},
onLoad(options) {
let that = this
if (options) {
that.infoRes = options
console.log("登录信息", options, that.infoRes)
}
this.iswxphone = uni.getStorageSync('iswxphone')
},
methods: {
checkboxChange(e) {
this.value = e.detail.value.length ? e.detail.value[0] : "0"
},
//
handleTelLogin() {
let that = this
if (this.value == 0) {
that.$tools.msg("请先勾选同意每日一称《个人信息保护政策》")
return
}
if (!this.phone) {
that.$tools.msg("请输入手机号")
return
}
if (!(/^1[3456789]\d{9}$/.test(that.phone))) {
that.$tools.msg("请输入正确的手机号码")
return
}
if (!that.code) {
that.$tools.msg("请输入验证码")
return
}
this.$model.getRegister({
phone: that.phone,
tenantId: uni.getStorageSync('tenantid'),
sessionId: uni.getStorageSync('sessionid'),
name: that.infoRes.name,
headImg: that.infoRes.headimg,
code: that.code,
isvrcode: true,
}).then(res => {
if (res.code != 0) {
that.$tools.msg(res.message)
return
}
uni.setStorageSync('token', res.data.token)
uni.setStorageSync('iswxphone', res.data.iswxphone)
uni.setStorageSync('refreshtoken', res.data.refreshtoken)
uni.setStorageSync('sessionid', res.data.sessionid)
if (that.infoRes.url == 'active') {
uni.reLaunch({
url: "/pages/index/active"
})
} else {
uni.reLaunch({
url: "/pages/index/index"
})
}
}).catch(err => {})
},
//
handleCode() {
let that = this
if (!that.phone) {
that.$tools.msg("请输入手机号")
return
}
if (!(/^1[3456789]\d{9}$/.test(that.phone))) {
that.$tools.msg("请输入正确的手机号码")
return
}
//
that.$model.getSendCode({
phone: that.phone
}).then(res => {
console.log(res)
if (res.code != 0) {
that.$tools.msg(res.message)
return
}
that.disabled = true
let interval = setInterval(() => {
--that.second
}, 1000)
setTimeout(() => {
clearInterval(interval)
that.disabled = false
that.second = 60
}, 60000)
}).catch(err => {})
},
//
getPhoneNumber(res) {
const that = this
if (this.value == 0) {
that.$tools.msg("请先勾选同意每日一称《个人信息保护政策")
return
}
if (res.detail.errMsg == 'getPhoneNumber:ok') {
console.log("res", res)
this.$model.getregister({
tenantId: uni.getStorageSync('tenantid'),
sessionId: uni.getStorageSync('sessionid'),
encryptedData: res.detail.encryptedData,
iv: res.detail.iv,
name: that.infoRes.name,
headImg: that.infoRes.headimg,
fansid: uni.getStorageSync('fansid')
}).then(res => {
if (res.code != 0) return
that.value = 1
uni.setStorageSync('token', res.data.token)
uni.setStorageSync('iswxphone', res.data.iswxphone)
uni.setStorageSync('refreshtoken', res.data.refreshtoken)
uni.setStorageSync('sessionid', res.data.sessionid)
if (that.infoRes.url == 'active') {
uni.reLaunch({
url: "/pages/index/active"
})
} else {
uni.reLaunch({
url: "/pages/index/index"
})
}
})
}
},
//
handlexieyi() {
uni.navigateTo({
url: "/pageTwo/login/detail?id=08DA1796-2FEE-4813-8B0C-8A45E7A57E70"
})
}
}
}
</script>
<style lang="scss" scoped>
.content {
padding: 0;
height: 100vh;
background-color: #fff;
}
.top {
width: 100%;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
padding: 80px 0 0;
image {
width: 70px;
height: 70px;
margin: auto;
margin-bottom: 15px;
border-radius: 50%;
}
text {
display: block;
width: 100%;
text-align: center;
}
}
.edit {
width: 75%;
height: auto;
background: #fff;
border-radius: 10px;
padding: 15px;
margin: 40px auto 15px;
.ts {
text-align: left;
margin-bottom: 10px;
color: #999;
}
.editem {
position: relative;
display: flex;
align-items: center;
font-size: 28upx;
justify-content: space-between;
flex-wrap: wrap;
}
.input {
width: 100%;
border: #dfdfdf 1px solid;
padding: 0 10px;
height: 35px;
line-height: 35px;
margin-bottom: 15px;
display: flex;
border-radius: 10px;
position: relative;
input {
height: 35px;
line-height: 35px;
width: 100%;
}
}
.btnlogin {
width: 100%;
margin: 20px 0;
height: 38px;
line-height: 38px;
background: $btncolor;
font-weight: 700;
border-radius: 10px;
text-align: center;
color: #fff !important;
}
.code {
width: 110px;
background: #dfdfdf;
font-size: 12px;
margin: 0;
border-radius: 10px;
text-align: center;
position: absolute;
right: 2.5px;
top: 2.5px;
}
}
.btnGroup {
width: 100%;
display: flex;
justify-content: center;
flex-wrap: wrap;
background-color: inherit;
line-height: inherit;
position: absolute;
bottom: 80rpx;
.wxbtn {
width: 100%;
icon {
font-size: 25px;
color: #28c445;
}
text {
display: block;
width: 100%;
margin-top: 5px;
font-size: 12px;
color: #666;
text-align: center;
}
button {
line-height: initial;
background: #fff;
display: flex;
flex-wrap: wrap;
padding: 0;
justify-content: center;
}
button::after {
display: none;
}
}
.xieyi {
font-size: 14px;
margin-top: 20px;
color: #333;
text {
border-bottom: 1px solid #333;
}
}
}
</style>

262
pageTwo/login/userinfo.vue Normal file
View File

@ -0,0 +1,262 @@
<template>
<view class="box">
<view class="lanBox">
<form action>
<view class="headbox">
<view class="touxiang">
<icon class="t-icon t-icon-touxiang headimage"></icon>
</view>
</view>
<view class="lan2">
请补充信息帮助我们更准确的分析数据
</view>
<view class="lan border-bottom">
<view class="left">用户名/昵称</view>
<view class="right">
<input name="name" type="text" v-model="name" placeholder="请输入用户名/昵称" />
</view>
</view>
<view class="lan border-bottom">
<view class="left">性别</view>
<view class="right">
<picker mode="selector" :range="sexItem" @change="onsexArr">
<view class="uni-input">{{sex==0?'请选择':sex==1?'男':'女'}}</view>
<icon class="iconfont icon-arrow-down"></icon>
</picker>
</view>
</view>
<view class="lan border-bottom">
<view class="left">身高</view>
<view class="right">
<input type="digit" class="mr-5" v-model="height" placeholder="请输入身高" />cm
<!-- <view class="uni-input">{{height?height+"cm":"请选择"}}</view>
<icon class="iconfont icon-arrow-down ml-15"></icon> -->
<!-- <picker mode="selector" class="f-r" value="85" :range="heightArr" @change="onheightArr">
<view class="uni-input">{{height!=0?height:"请选择"}}</view>
<icon class="iconfont icon-arrow-down"></icon>
</picker> -->
</view>
</view>
<view class="lan border-bottom">
<view class="left">出生日期</view>
<view class="right">
<picker class="picker" mode="date" :end="startDate" :value="birthday" @change="bindDateChange">
<view class="uni-input">{{birthday?birthday:"请选择"}}</view>
<icon class="iconfont icon-arrow-down"></icon>
</picker>
</view>
</view>
</form>
</view>
<view v-if="isHeight" class="slidePopup">
<view class="bg" @click="onTap">
<view class="slide-box" @click.stop>
<view class="btnGroup">
<view class="subtn close" @click="onTap">取消</view>
<view class="heightVal">{{height}}cm</view>
<view class="subtn" @click="isHeight = false">确定</view>
</view>
<slide-choose v-model="height" ref="slide"></slide-choose>
</view>
</view>
</view>
<view class="btn" @click="confirmInfo">提交</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
export default {
data() {
return {
ageArr: [],
sexItem: [
"男",
"女"
],
sex: 0,
name: null,
birthday: "",
height: "",
isHeight: false,
};
},
computed: {
...mapState(["user"]),
userInfo() {
return this.user
},
startDate() {
return this.$tools.getDate('start');
}
},
methods: {
//
confirmInfo() {
let data = {};
if (!this.name) {
this.$tools.msg("请输入用户名")
return;
}
if (!this.sex) {
this.$tools.msg("请选择性别")
return;
}
if (!this.height) {
this.$tools.msg("请选择身高")
return;
}
if (!this.birthday) {
this.$tools.msg("请选择出生日期")
return;
}
data.name = this.name
data.sex = this.sex;
data.height = this.height;
data.birthday = this.birthday;
data.id = this.user.familyid
console.log("提交", data)
this.subInfo(data);
},
subInfo(data) {
let that = this
that.$model.getsubmit(data).then(res => {
if (res.code == 0) {
that.$tools.msg("提交成功");
uni.reLaunch({
url: "/pages/index/index"
})
} else {
that.$tools.msg(res.message);
}
});
},
//
bindDateChange(e) {
console.log(e.target.value, this.startDate)
this.birthday = e.target.value
},
onAgeArr(e) {
this.age = this.ageArr[e.target.value]
},
//
onsexArr(e) {
this.sex = this.sexItem[e.target.value] == "男" ? 1 : 2
},
onTap() {
this.height = ""
this.isHeight = false
},
},
onLoad(options) {
var agedata = []
for (var i = 12; i <= 80; i++) {
agedata.push(i);
}
this.ageArr = agedata
},
};
</script>
<style scoped="scoped" lang="scss">
.box {
height: 100vh;
// padding: 0 15px;
background-color: #fff;
}
.touxiang {
position: absolute;
top: 0;
margin: 0 auto;
z-index: 2;
}
input {
border: none;
background: inherit;
}
.headbox {
text-align: center;
position: relative;
display: flex;
justify-content: center;
height: 70px;
margin: 15px 0 30px;
}
.headimage,
.icontouxiang {
display: block;
width: 70px;
height: 70px;
border-radius: 50%;
}
.icontouxiang {
font-size: 70px;
color: $btncolor;
}
.lanBox {
padding: 15px 0;
}
.lan {
display: flex;
align-items: center;
font-size: 14px;
padding: 5px 0;
margin: 5px 15px;
border-bottom: 1px solid #f7f7f7;
}
.lan .left {
width: 24%;
text-align: left;
}
.lan .right {
display: flex;
align-items: center;
justify-content: flex-end;
width: 72%;
min-height: 38px;
box-sizing: border-box;
line-height: 36px;
position: relative;
text-align: right;
picker {
width: 100%;
text-align: right;
border: none;
margin-right: 8px;
}
.iconfont {
color: #333333;
font-size: 16px;
position: absolute;
right: -10px;
top: 0;
}
}
.btn {
width: auto;
margin: 40px 15px 0;
}
.lan2 {
height: 35px;
line-height: 35px;
background: #f7f7f7;
font-size: 12px;
padding-left: 15px;
color: #999;
}
</style>

253
pageTwo/me/adduser.vue Normal file
View File

@ -0,0 +1,253 @@
<template>
<view class="box">
<view class="lanBox">
<form action>
<view class="headbox">
<view class="touxiang">
<image v-if="memInfo.headimg" :src="memInfo.headimg" class="headimage" />
<icon v-else class="t-icon t-icon-touxiang headimage"></icon>
</view>
</view>
<view class="lan border-bottom">
<view class="left">用户名</view>
<view class="right">
<input name="name" type="text" v-model="memInfo.name" placeholder="请输入用户名/昵称" />
</view>
</view>
<view class="lan border-bottom">
<view class="left">性别</view>
<view class="right">
<picker mode="selector" :range="sexItem" @change="onsexArr">
<view class="uni-input">{{!memInfo.sex?'请选择':memInfo.sex==1?'男':'女'}}</view>
<icon class="iconfont icon-arrow-down"></icon>
</picker>
</view>
</view>
<view class="lan border-bottom">
<view class="left">身高</view>
<view class="right">
<input type="digit" class="mr-5" v-model="memInfo.height" placeholder="请输入身高"/> cm
</view>
</view>
<view class="lan border-bottom">
<view class="left">出生日期</view>
<view class="right">
<picker class="picker" mode="date" :end="startDate" :value="memInfo.birthday"
@change="bindDateChange">
<view class="uni-input">{{memInfo.birthday?memInfo.birthday:"请选择"}}</view>
<icon class="iconfont icon-arrow-down"></icon>
</picker>
</view>
</view>
</form>
</view>
<view v-if="isHeight" class="slidePopup">
<view class="bg" @click="onTap">
<view class="slide-box" @click.stop>
<view class="btnGroup">
<view class="subtn close" @click="onTap">取消</view>
<view class="heightVal">{{memInfo.height}}cm</view>
<view class="subtn" @click="isHeight = false">确定</view>
</view>
<slide-choose v-model="memInfo.height" ref="slide"></slide-choose>
</view>
</view>
</view>
<view class="btn" @click="confirmInfo">提交</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
export default {
data() {
return {
ageArr: [],
sexItem: [
"男",
"女"
],
isHeight: false,
isEdit: false,
memInfo: {
birthday: "",
height: "",
sex: "",
name: ""
},
};
},
computed: {
...mapState(["user"]),
startDate() {
return this.$tools.getDate('start');
}
},
methods: {
//
confirmInfo() {
let that = this
that.isHeight = false
if (!this.memInfo.name) {
this.$tools.msg("请输入用户名")
return;
}
if (!this.memInfo.sex) {
this.$tools.msg("请选择性别")
return;
}
if (!this.memInfo.height) {
this.$tools.msg("请选则身高")
return;
}
if (!this.memInfo.birthday) {
this.$tools.msg("请选择出生日期")
return;
}
// console.log("", this.memInfo)
that.subInfo(this.memInfo)
},
subInfo(data) {
let that = this
data.fansid = uni.getStorageSync("unionid");
that.$model.getsubmit(data).then(res => {
if (res.code == 0) {
if (that.isEdit) {
that.$store.dispatch("getUserInfo", {
familyid: that.user.id
})
}
that.$store.dispatch("getFamilyList")
that.$tools.msg("提交成功");
uni.navigateBack({
delta: 1
});
} else {
that.$tools.msg(res.message);
}
});
},
//
bindDateChange(e) {
// console.log("", e)
this.memInfo.birthday = e.target.value
},
//
onsexArr(e) {
// console.log("", e)
this.memInfo.sex = this.sexItem[e.target.value] == "男" ? 1 : 2
},
//
ontypeArr(e) {
this.type = this.typeItem[e.target.value] == "成人" ? 1 : this.typeItem[e.target.value] == "儿童" ? 2 : 3
},
},
onLoad(options) {
var agedata = []
for (var i = 12; i <= 80; i++) {
agedata.push(i);
}
this.ageArr = agedata
//
if (options.familayData) {
let info = options.familayData
this.memInfo = JSON.parse(info)
this.isEdit = true
// console.log("", this.memInfo)
}
//
if (options.type) {
this.isEdit = false
this.memInfo = {
birthday: "",
height: "",
sex: "",
name: ""
}
}
},
};
</script>
<style scoped="scoped" lang="scss">
.box {
height: 100vh;
padding: 0 15px;
background-color: #fff;
}
.headimage,
.icontouxiang {
display: block;
width: 65px;
height: 65px;
font-size: 65px;
color: $btncolor;
border-radius: 50%;
}
.headbox {
text-align: center;
position: relative;
display: flex;
justify-content: center;
height: 65px;
margin: 15px;
}
.lanBox {
padding: 15px 0;
}
.lan {
display: flex;
align-items: center;
font-size: 14px;
padding: 5px 0;
margin: 4px auto;
border-bottom: 1px solid #f7f7f7;
input {
border: none;
background: inherit;
}
}
.lan .left {
width: 24%;
text-align: left;
}
.lan .right {
display: flex;
align-items: center;
justify-content: flex-end;
width: 72%;
min-height: 38px;
box-sizing: border-box;
line-height: 36px;
position: relative;
text-align: right;
picker {
width: 100%;
text-align: right;
border: none;
margin-right: 8px;
}
.iconfont {
color: #333333;
font-size: 16px;
position: absolute;
right: -10px;
top: 0;
}
}
.btn {
margin: 10px auto 0;
}
</style>

319
pageTwo/me/detail.vue Normal file
View File

@ -0,0 +1,319 @@
<template>
<view class="common">
<view class="header" v-if="info">
<view class="left">
<image :src="info.headimg" class="image1" />
<view class="left_sm">
<view class="name">
<view>{{info.name?info.name:""}}</view>
<view class="right">
<view v-if="info.isself != 1" @click="deldet(Infoid)" class="guanliyuan">删除</view>
<view @click="editorInfo()" class="guanliyuan">编辑</view>
</view>
</view>
<view class="mt-5">
<text>{{info.sex==0?'未知':info.sex==2?'女':'男'}}</text>
<text>{{info.height}}cm</text>
<text>{{info.mage?info.mage:"0岁"}}</text>
</view>
</view>
</view>
</view>
<scroll-view scroll-y class="list ">
<view class="history" v-if="ranklist.length">
<view class="list-item" v-for="(item ,index) in ranklist" :key="index">
<view class="item">
<view class="time">
<icon class="t-icon t-icon-shijian-mianxing-0"></icon>
<text>{{item.createtime}}</text>
</view>
<view>{{item.height}}<text>身高</text></view>
<view>{{item.weight}}<text>体重</text></view>
<view>{{item.bmi}}<text>BMI</text></view>
</view>
</view>
<view class="endtext" v-if="!lastPage || page >= lastPage"> 到底了看看别的吧 </view>
</view>
<view class="nolist" v-else>
<icon class="iconfont icon-zanwu"></icon>
</view>
</scroll-view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
export default {
data() {
return {
ranklist: [],
info: {},
memberText: null,
memberType: [],
page: 1,
lastPage: '',
}
},
computed: {
...mapState(["user"])
},
onLoad(option) {
this.page = 1
this.ranklist = []
console.log("id", option)
if (option.id) {
this.Infoid = option.id
}
},
onShow() {
this.ranklist = []
this.gethistory(this.Infoid)
this.getHistoryList(this.Infoid)
},
onReachBottom() {
console.log(this.lastPage, this.page)
if (!this.lastPage || this.page >= this.lastPage) {
uni.showToast({
title: '没有更多数据!',
icon: 'none'
})
return
}
this.page++
this.getHistoryList(this.Infoid)
},
methods: {
//
getHistoryList(id) {
this.$model.getHistoryList({
familyId: id,
pageNo: this.page,
pageSize: 10,
}).then((res) => {
if (res.code != 0) {
return
}
this.ranklist = this.ranklist.concat(res.data.rows)
this.lastPage = res.data.totalpage
})
},
//
gethistory(id) {
this.$model.getdetail({
id: id
}).then((res) => {
if (res.code != 0) {
return
}
this.info = res.data
})
},
//
editorInfo() {
uni.navigateTo({
url: "/pageTwo/me/adduser?familayData=" + JSON.stringify(this.info),
})
},
//
deldet(id) {
let that = this
uni.showModal({
title: '友情提示',
content: '确定删除该成员吗',
success: function(res) {
if (res.confirm) {
that.$model.getdelete({
id: id,
}).then(res => {
if (res.code != 0) return
that.$tools.msg("删除成功!");
that.getFamilyList()
})
} else if (res.cancel) {
that.$tools.msg("您已取消删除!");
}
}
});
},
getFamilyList() {
let that = this
that.$model.getFamilyList({}).then(res => {
that.$store.commit("changeFamilay", res)
that.$store.dispatch("getUserInfo", {
familyid: res[0].familyid
})
uni.switchTab({
url: '/pages/me/me'
});
}).catch(e => {})
},
},
}
</script>
<style scoped="scoped" lang="scss">
.list {
margin-top: 80px;
}
.list-item {
width: 100%;
height: auto;
text-align: center;
margin: 10px 0 15px;
}
.item {
background-color: #fff;
padding: 5px 10px;
display: flex;
justify-content: space-between;
border-radius: 10px;
align-items: center;
text-align: center;
font-size: 32rpx;
font-weight: 700;
margin-bottom: 30rpx;
line-height: 40rpx;
text {
width: 100%;
font-size: 24rpx;
display: block;
color: #666;
text-align: center;
font-weight: 400;
}
view {
width: 18%;
}
.time {
width: 32% !important;
font-size: 28rpx;
color: #666;
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
image {
width: 40rpx;
height: 40rpx;
margin-right: 5px;
}
text {
width: 100%;
font-size: 28rpx;
margin-top: 3px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
//
.common {
padding: 0 15px;
min-height: calc(100vh - 90px);
height: 100%;
}
.header {
height: 90px;
background: $mainColor;
position: fixed;
top: 0rem;
left: 0;
right: 0;
display: flex;
z-index: 99;
padding: 0 10px;
justify-content: space-between;
.left {
width: 100%;
display: flex;
justify-content: start;
align-items: center;
position: relative;
.left_sm {
text-align: left;
color: #FFFFFF;
position: absolute;
left: 60px;
top: 25px;
right: 0;
.name {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
text {
display: inline-block;
padding-right: 10px;
font-size: 14px;
}
}
.type,
.type2 {
background: #fff;
text-align: center;
display: inline-block;
padding: 0 3px !important;
font-size: 12px !important;
border-radius: 10px;
line-height: initial;
color: $btncolor;
}
.image1 {
width: 50px;
height: 50px;
float: left;
border-radius: 50%;
}
p {
text-align: left;
margin-top: 5px;
}
}
.right {
display: flex;
align-items: center;
color: #fff;
text-align: right;
font-size: 14px;
.guanliyuan {
border: 1px solid #fff;
padding: 2px 6px;
border-radius: 10px;
font-size: 12px;
margin-left: 10px;
}
}
}
.leftChild {
width: 100% !important;
padding: 10px 0 !important;
view {
min-width: auto !important;
}
}
</style>

103
pageTwo/me/feedBack.vue Normal file
View File

@ -0,0 +1,103 @@
<template>
<view class="content">
<view class="formbox">
<view class="input">
<view class="t-icon t-icon-dianhuatianchong"></view>
<input type="text" v-model="formdata.phone" placeholder="在此输入您的联系方式" />
</view>
<view class="input textarea">
<view class="t-icon t-icon-xinxi"></view>
<textarea v-model="formdata.content" name="content" placeholder-style="font-size:13px;margin-top:10px;"
placeholder="有什么想说的,尽管来吧..." />
</view>
<view class="btn " type="button" @click="submit">提交</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
formdata: {
phone: "",
content: ""
},
}
},
methods: {
submit() {
if (!this.formdata.phone.trim()) {
this.$tools.msg("请输入联系方式");
return
}
if (!/(^1[3|4|5|7|8][0-9]{9}$)/.test(this.formdata.phone)) {
this.$tools.msg('请输入正确的联系方式');
return;
}
if (!this.formdata.content.trim()) {
this.$tools.msg("请输入建议");
return
}
this.$model.submitadvice(this.formdata).then((res) => {
this.$tools.msg(res.message)
setTimeout(function() {
uni.switchTab({
url: "/pages/me/me"
})
}, 500)
}).catch((res) => {
this.$tools.msg('提交失败,请稍后重试!')
});
}
},
}
</script>
<style lang="scss" scoped>
.content {
background: #fff;
}
.formbox {
padding: 15px;
}
.input {
margin: 0;
display: flex;
border-radius: 5px;
padding: 10px;
margin-bottom: 1rem;
border: 1px solid #f7f7f7;
input {
width: 100%;
height: 1.5rem;
line-height: 1.5rem;
background: none;
border: none;
font-size: 14px;
margin-left: 10px;
}
/deep/textarea {
width: 100%;
height: 6.5rem;
line-height: 0;
background: none;
border: none;
font-size: 14px;
margin-left: 10px;
}
}
.btn {
display: block;
margin: 30px auto;
font-size: 14px;
}
</style>

165
pageTwo/me/history.vue Normal file
View File

@ -0,0 +1,165 @@
<template>
<view class="common">
<view class="history" v-if="ranklist.length">
<delectList :list="ranklist" :type="user.type" :border="false" @changeDelete="changeDelete"></delectList>
<view class="endtext" v-if="!lastPage || page >= lastPage"> 到底了看看别的吧 </view>
</view>
<view class="nolist" v-if="!lastPage">
<icon class="iconfont icon-zanwu"></icon>
</view>
</view>
</template>
<script>
import delectList from "@/components/mark-slide-list/mark-slide-list.vue"
import {
mapState
} from "vuex";
export default {
components: {
delectList
},
computed: {
...mapState(['user']),
},
data() {
return {
buttonList: [{
title: '删除',
background: '#ff3b32'
}],
list: [
"测量时间",
"体重",
"BMI",
"操作",
],
ranklist: [],
page: 1,
lastPage: 1,
type: null,
id: null,
startX: 0,
endX: 0
}
},
onLoad() {
let that = this
that.getList(1)
},
onReachBottom() {
let that = this
console.log("this.lastPage", this.lastPage)
if (!this.lastPage || this.page >= this.lastPage) {
uni.showToast({
title: '没有更多数据!',
icon: 'none'
})
return
}
this.page++
this.getList(this.page)
},
methods: {
changeDelete(item) {
let that = this
uni.showModal({
title: '友情提示',
content: '是否删除当前测量记录?',
success: function(res) {
if (res.confirm) {
that.$model.gethistorydelete({
id: item.id,
}).then((res) => {
if (res.code != 0) {
that.$tools.msg(res.message)
return
}
that.ranklist.splice(that.ranklist.findIndex(ite => ite.id === item
.id), 1)
that.$store.dispatch("getUserInfo", {
familyid: that.user.familyid,
})
that.$store.dispatch("getResult", {
birthday: that.user.birthday,
familyid: that.user.familyid,
height: that.user.height,
sex: that.user.sex,
})
that.$tools.msg("删除成功")
})
} else if (res.cancel) {
that.$tools.msg("您已取消操作!");
}
},
})
},
getList(page) {
let that = this
that.$model.getHistoryList({
familyId: that.user.familyid,
pageNo: page,
pageSize: 10
}).then((res) => {
console.log("历史记录", res)
if (res.code != 0) return
res.data.rows.forEach(item => {
item.slide_x = 0
})
this.ranklist = this.ranklist.concat(res.data.rows)
this.lastPage = res.data.totalpage
})
},
//
touchStart(e) {
//
this.startX = e.touches[0].clientX
},
//
touchEnd(e) {
console.log("2", e)
//
let parentElement = e.currentTarget
//
this.endX = e.changedTouches[0].clientX
//
if (parentElement.dataset.type == 0 && this.startX - this.endX > 30) {
this.restSlide()
parentElement.dataset.type = 1
}
//
if (parentElement.dataset.type == 1 && this.startX - this.endX < -30) {
this.restSlide()
parentElement.dataset.type = 0
}
this.startX = 0
this.endX = 0
},
//
checkSlide() {
let listItems = document.querySelectorAll('.list')
for (let i = 0; i < listItems.length; i++) {
if (listItems[i].dataset.type == 1) {
return true
}
}
return false
},
//
restSlide() {
let listItems = document.querySelectorAll('list')
//
for (let i = 0; i < listItems.length; i++) {
listItems[i].dataset.type = 0
}
},
}
}
</script>
<style scoped="scoped" lang="scss">
.common {
min-height: calc(100vh - 40px);
padding-bottom: 15px
}
</style>

199
pageTwo/me/info.vue Normal file
View File

@ -0,0 +1,199 @@
<template>
<view>
<view class="box">
<view class="form lanBox">
<view class="lan border-bottom" v-for="(item,index) in list" :key="index">
<view class="left">
<view class="icon">
<icon class="t-icon" :class="'t-icon-'+item.key"></icon>
</view>
{{item.title}}
</view>
<view class="center">
<view v-if="item.title!='肥胖等级'">
<text>{{item.fvalue?item.fvalue:"0"}}</text><text v-if="item.dw">{{item.dw}}</text>
</view>
<view v-if="item.title=='肥胖等级'"><text>{{item.fevaluation}}</text></view>
</view>
</view>
<!-- <view class="lan border-bottom">
<view class="left">
<image src="@/static/weight.png"></image>体重
</view>
<view class="right">{{memInfo.weight?memInfo.weight:"-"}}kg</view>
</view>
<view class="lan border-bottom">
<view class="left">
<image src="@/static/height.png"></image>身高
</view>
<view class="right">{{memInfo.height?memInfo.height:"-"}}cm</view>
</view>
<view class="lan border-bottom">
<view class="left">
<image src="@/static/bmi.png"></image>BMI
</view>
<view class="right">{{memInfo.bmi?memInfo.bmi:"-"}}</view>
</view>
<view class="lan border-bottom">
<view class="left">
<image src="@/static/fat_r.png"></image>体脂率
</view>
<view class="right">{{memInfo.fat_r?memInfo.fat_r:"-"}}%</view>
</view>
<view class="lan border-bottom">
<view class="left">
<image src="@/static/fat_w.png"></image>脂肪量
</view>
<view class="right">{{memInfo.fat_w?memInfo.fat_w:"-"}}%</view>
</view>
<view class="lan border-bottom">
<view class="left">
<image src="@/static/muscle.png"></image>肌肉率
</view>
<view class="right">{{memInfo.muscle?memInfo.muscle:"-"}}%</view>
</view>
<view class="lan border-bottom">
<view class="left">
<image src="@/static/water.png"></image>水分
</view>
<view class="right">{{memInfo.water?memInfo.water:"-"}}</view>
</view>
<view class="lan border-bottom">
<view class="left">
<image src="@/static/bone.png"></image>骨重
</view>
<view class="right">{{memInfo.bone?memInfo.bone:"-"}}kg</view>
</view>
<view class="lan border-bottom">
<view class="left">
<image src="@/static/visceral.png"></image>内脏指数
</view>
<view class="right">{{memInfo.visceral?memInfo.visceral:"-"}}</view>
</view>
<view class="lan border-bottom">
<view class="left">
<image src="@/static/sfr.png"></image>皮下脂肪
</view>
<view class="right">{{memInfo.sfr?memInfo.sfr:"-"}}%</view>
</view>
<view class="lan border-bottom">
<view class="left">
<image src="@/static/protein.png"></image>蛋白率
</view>
<view class="right">{{memInfo.protein?memInfo.protein:"-"}}%</view>
</view>
<view class="lan border-bottom">
<view class="left">
<image src="@/static/bodyage.png"></image>身体年龄
</view>
<view class="right">{{memInfo.bodyage?memInfo.bodyage:"-"}}</view>
</view>
<view class="lan border-bottom">
<view class="left">
<image src="@/static/kcal.png"></image>基础代谢率
</view>
<view class="right">{{memInfo.kcal?memInfo.kcal:'0'}}kcal</view>
</view>
<view class="lan border-bottom">
<view class="left">
<image src="@/static/muscleval.png"></image>肌肉量
</view>
<view class="right">{{memInfo.muscleval?memInfo.muscleval:"-"}}kg</view>
</view>
<view class="lan border-bottom">
<view class="left">
<image src="@/static/lbm.png"></image>去脂体重
</view>
<view class="right">{{memInfo.lbm?memInfo.lbm:"-"}}kg</view>
</view>
<view class="lan border-bottom">
<view class="left">
<image src="@/static/proteinval.png"></image>蛋白量
</view>
<view class="right">{{memInfo.proteinval?memInfo.proteinval:'0'}}kg</view>
</view>
<view class="lan border-bottom">
<view class="left">
<image src="@/static/fat.png"></image>肥胖等级
</view>
<view class="right">{{memInfo.fatlevel?memInfo.fatlevel:'0'}}</view>
</view>
<view class="lan border-bottom">
<view class="left">
<image src="@/static/body.png"></image>体型
</view>
<view class="right">{{memInfo.body?memInfo.body:'0'}}</view>
</view> -->
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
list: {},
};
},
onLoad(options) {
let info = options.index
let memInfo = JSON.parse(info)
this.list = this.weightInfo.infoList(memInfo)
console.log(this.list)
}
};
</script>
<style scoped="scoped" lang="scss">
.box {
min-height: 100vh;
background-color: #fff;
}
.lanBox {
padding: 0px 15px 0;
}
.lan {
display: flex;
align-items: center;
font-size: 14px;
height: 50px;
line-height: 50px;
justify-content: space-between;
border-bottom: 1px solid #f7f7f7;
.left {
display: flex;
align-items: center;
text-align: left;
font-size: 14px;
padding-left: 30px;
.icon {
width: 18px;
height: 18px;
position: absolute;
left: 15px;
padding: 3px;
background-color: #aaa;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
}
.right {
display: flex;
align-items: center;
justify-content: flex-end;
width: 50%;
min-height: 38px;
box-sizing: border-box;
line-height: 36px;
}
}
</style>

115
pageTwo/me/manage.vue Normal file
View File

@ -0,0 +1,115 @@
<template>
<view class="common">
<view class="add" @click="addInfo('add')">
<icon class="iconfont icon-tianjia"></icon>添加成员
</view>
<view class="box" v-if="familayList.lenght!=0">
<view class="list" v-for="(item ,index) in familayList" :key="index" @click="datail(item.id)">
<image :src="item.headimg" class="image1" />
<view class="left">
<view class="title">{{item.name?item.name:""}}</view>
<view class="title2">
<text>{{item.sex==0?'未知':item.sex==1?'男':'女'}}</text>
<text>{{item.mage?item.mage:'0岁'}}</text>
<text>{{item.type}}</text>
</view>
<view class="title2">最后测量时间{{item.lasthearttime||'-'}}</view>
</view>
</view>
</view>
<view v-else>
没有数据了
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
export default {
data() {
return {
visible: false,
ranklist: [],
}
},
computed: {
...mapState(["familayList", "user"])
},
onLoad() {},
methods: {
//
addInfo(type) {
uni.navigateTo({
url: "/pageTwo/me/adduser?type=${type}"
})
},
//
datail(id) {
uni.navigateTo({
url: `/pageTwo/me/detail?id=` + id,
})
},
}
}
</script>
<style scoped="scoped" lang="scss">
.common {
padding: 15px;
height: calc(100vh - 30px);
}
.add {
width: 135px;
height: 30px;
line-height: 30px;
font-size: 14px;
margin-bottom: 10px;
color: #fff;
border-radius: 15px;
display: flex;
justify-content: center;
background: $btncolor;
}
.list {
width: auto;
background: #fff;
display: flex;
border-radius: 10px;
margin-bottom: 15px;
flex-wrap: wrap;
padding: 10px 15px;
font-size: 14px;
align-items: center;
.image1 {
width: 55px;
height: 55px;
border-radius: 50%;
margin-right: 15px;
}
}
.left {
width: 70%;
.title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.title2 {
margin-top: 5px;
font-size: 12px;
color: #999;
text {
margin-right: 10px;
}
}
}
</style>

380
pageTwo/survey/survey.vue Normal file
View File

@ -0,0 +1,380 @@
<template>
<view class="content">
<view class="bgheight" v-if="!isShowA">
<view v-if="listA">
<view class="btn" @tap="handleListx(1)">重新测评</view>
<view class="box">
<view class="name">
<view>本次体质评估结果为</view>
</view>
<view class="conbt">
{{listA.bodytype}}
</view>
</view>
<view class="box" v-if="listA.list.length">
<view class="h2">体质解读</view>
<view v-for="(item,index) in listA.list" :key="index">
<view class="title">{{item.bodytype}}</view>
<view class="con">
<view class="text" v-show="item.feature"><text>特征</text>{{item.feature}}</view>
<view class="text" v-show="item.people"><text>重点人群</text>{{item.people}}</view>
<view class="text" v-show="item.sick"><text>患病倾向</text>{{item.sick}}</view>
<view class="text" v-show="item.health"><text>调养方式</text>{{item.health}}</view>
</view>
</view>
<view class="tips" v-if="listA.referlist">
{{listA.referlist}}
</view>
</view>
</view>
</view>
<!-- 评估 -->
<view class="commonAll" v-else>
<view class="h2">请根据近一年的体验和感觉回答以下问题</view>
<view class="box" v-for="(item,index) in infoListA.slice((currpage-1)*eachpage,currpage*eachpage)"
:key="index">
<view v-for="(ite, ind) in item.qalist" :key="ind">
<view class="h5">{{ite.title}}</view>
<view class="item">
<view class="group" v-for="(it, id) in ite.data" :key="id" @click="Changeradio(it)">
<icon class="iconfont radioimg"
:class="[dasC.indexOf(it.val)!=-1?'icon-radio':'icon-kongradio']">
</icon>
<view>{{it.name}}</view>
</view>
</view>
</view>
</view>
</view>
<view class="page" v-if='!listA'>
<view class="pre" v-if="currpage>1" @click="pre">上一页</view>
<view v-if="currpage<pagesum" @click="next">下一页</view>
<view class="btn" v-if="currpage==pagesum" @click="handlesub">
提交
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
export default {
computed: {
...mapState(["user"]),
info() {
return this.user
}
},
onShow() {
let that = this
that.handleTypeInfo()
},
methods: {
//
handleTypeInfo() {
let that = this
that.$model.getbodyinfo({
familyid: that.user.familyid,
}).then(res => {
if (res.code != 0) {
that.handleListx(1)
return
}
that.listA = res.data
that.isShowA = false
console.log("计算成功,去查看结果吧!")
})
},
//
handleListx(ind) {
let that = this
that.isShowA = true
that.currpage = 1
that.dasA = []
that.dasC = []
that.listA = ""
that.tmidlistA = []
that.infoListA = []
that.$model.getbodylist({
isrestart: ind,
familyid: that.user.familyid,
}).then(res => {
console.log(123, res)
if (res.code != 0) return
that.pagesum = Math.ceil(res.data.length / that.eachpage);
that.infoListA = res.data
})
},
//
Changeradio(tmitem) {
let that = this
if (that.tmidlistA.indexOf(tmitem.id) == -1) {
console.log(0)
that.tmidlistA.push(tmitem.id)
that.dasC.push(tmitem.val);
that.dasA.push(tmitem)
} else {
for (var n = 0; n < that.tmidlistA.length; n++) {
if (tmitem.id == that.tmidlistA[n]) {
console.log(1)
if (that.dasC.indexOf(tmitem.val) == -1) {
that.tmidlistA.push(tmitem.id)
that.dasC.push(tmitem.val);
that.dasA.push(tmitem)
console.log(2)
}
that.tmidlistA.splice(n, 1)
that.dasC.splice(n, 1);
that.dasA.splice(n, 1);
}
}
}
},
//
handlesub() {
let that = this
var obj = {}
let newArr = []
that.dasA.forEach(function(item, suffix) {
if (!obj[item.valId]) {
var arr = {
id: '',
list: []
};
arr.id = item.valId
arr.list.push({
id: item.id,
score: item.value
})
newArr.push(arr);
obj[item.valId] = item;
} else {
for (var q = 0; q < newArr.length; q++) {
if (newArr[q].id == item.valId) {
newArr[q].list.push({
id: item.id,
score: item.value
})
}
}
}
})
// for (var i = 0; i < that.infoListA.length; i++) {
// var arr = {
// id: '',
// list: []
// };
// arr.id = that.infoListA[i].id
// for (var e = 0; e < that.infoListA[i].qalist.length; e++) {
// arr.list.push({
// id: that.infoListA[i].qalist[e].Id,
// score: 3
// })
// }
// newArr.push(arr)
// }
console.log("去计算", newArr)
// if (newArr.length < 7 || newArr.length < 9) {
// that.$api.msg("")
// return
// }
that.$model.getbodyresultinfo({
appid: uni.getStorageSync("appid"),
familyid: that.user.familyid,
data: newArr
})
.then(res => {
console.log('res', res)
that.tmidlistA = []
that.dasA = []
that.dasC = []
if (res.code != 0) {
that.$tools.msg(res.message)
return
}
that.listA = res.data
that.isShowA = false
that.currpage = 1
console.log("计算成功,去查看结果吧!")
})
},
pre() {
this.currpage--
},
next() {
let that = this
that.currpage++
},
},
data() {
return {
isShowA: true,
dasA: [],
dasC: [],
listA: [],
infoListA: [],
tmidlistA: [],
pagesum: null, //
currpage: 1, //
eachpage: 2, //
}
},
}
</script>
<style scoped lang="scss">
.content {
font-size: 14px;
color: #666;
background-color: #fff;
padding: 15px;
min-height: calc(100vh - 30px);
}
.h2 {
font-size: 16px;
font-weight: bold;
}
.h5 {
margin: 15px 0 10px;
}
.bgheight {
.name {
font-size: 16px;
font-weight: bold;
color: #f19601;
margin-bottom: 15px;
display: flex;
justify-content: space-between;
}
.conbt {
font-size: 14px;
line-height: 25px;
width: 100%;
margin-bottom: 15px;
}
.box .conbt:nth-last-child(1) text {
display: none;
}
.title {
width: 100%;
font-size: 16px;
text-align: left;
font-weight: bold;
margin: 15px 0;
color: #333;
}
.con {
line-height: 25px;
text {
color: #333;
font-weight: bold;
}
}
.btn {
display: block;
height: 30px;
line-height: 30px;
border: none;
background: #f19601;
color: #fff;
margin: 0;
width: 100px;
border-radius: 10px;
text-align: center;
font-size: 14px;
float: right;
// margin-bottom: 10px;
}
}
.uni-list-cell {
display: flex;
width: 60%;
margin-bottom: 10px;
margin-left: 10px;
}
:nth-child(even).uni-list-cell {
width: 30%;
margin-left: 0;
}
.commonAll {
background-color: #fff;
}
.page {
width: 100%;
height: 35px;
text-align: center;
margin: 20px auto;
display: flex;
justify-content: space-around;
view {
width: 150px;
background: #dfdfdf;
padding: 5px 0;
border-radius: 5px;
}
.btn {
background: #f19601;
color: #fff;
margin: 0;
height: auto;
line-height: inherit;
}
}
.item {
display: flex;
flex-wrap: wrap;
}
.group {
display: flex;
align-items: center;
align-content: center;
width: 50%;
justify-content: end;
flex-wrap: wrap;
margin-top: 8px;
}
.iconfont {
width: 22px;
height: 22px;
font-size: 20px;
color: #dfdfdf;
display: flex;
margin-right: 3px;
}
.icon-radio {
color: #f19601;
}
.tips {
font-size: 12px;
color: #999;
margin-top: 10px;
line-height: 22px;
}
</style>

208
pages.json Normal file
View File

@ -0,0 +1,208 @@
{
"pages": [ //pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "pages/target/target",
"style": {
"navigationBarTitleText": "目标"
}
},
{
"path": "pages/compk/compk",
"style": {
"navigationBarTitleText": "对比"
}
},
{
"path": "pages/me/me",
"style": {
"navigationBarTitleText": "我的"
}
},
{
"path": "pages/index/active",
"style": {
"navigationBarTitleText": "设备激活",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
},
{
"path": "pages/search/devType",
"style": {
"navigationBarTitleText": "设备搜索"
}
}
],
"subPackages": [{
"root": "pageTwo",
"pages": [{
"path": "login/login",
"style": {
"navigationBarTitleText": "登录",
"navigationStyle": "custom"
}
},
{
"path": "login/detail",
"style": {
"navigationBarTitleText": "协议"
}
},
{
"path": "login/userinfo",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
},
{
"path": "home/index",
"style": {
"navigationBarTitleText": "报告页"
}
},
{
"path": "compk/pkdetail",
"style": {
"navigationBarTitleText": "对比详情"
}
},
{
"path": "me/history",
"style": {
"navigationBarTitleText": "历史记录"
}
},
{
"path": "me/feedBack",
"style": {
"navigationBarTitleText": "意见反馈"
}
},
{
"path": "me/manage",
"style": {
"navigationBarTitleText": "用户管理"
}
},
{
"path": "me/adduser",
"style": {
"navigationBarTitleText": ""
}
}, {
"path": "me/detail",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
},
{
"path": "me/info",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
},
{
"path": "survey/survey",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}
]
}, {
"root": "BLEPages",
"pages": [{
"path": "adult/H01pro",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
},
{
"path": "adult/PCD01pro",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
},
{
"path": "adult/PCL01",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
},
{
"path": "adult/H09B",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}
, {
"path": "adult/F01B",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}
]
}],
"globalStyle": {
"navigationBarTextStyle": "#fff",
"navigationBarBackgroundColor": "#00c6c6",
"backgroundColor": "#fff"
},
//
"tabBar": {
"color": "#333",
"selectedColor": "#00c6c6",
"backgroundColor": "#fff",
"list": [{
"pagePath": "pages/index/index",
"iconPath": "static/tab_sy.png",
"selectedIconPath": "static/tab_sy01.png",
"text": "首页"
},
{
"pagePath": "pages/target/target",
"iconPath": "static/tab_sj.png",
"selectedIconPath": "static/tab_sj01.png",
"text": "目标"
},
{
"pagePath": "pages/compk/compk",
"iconPath": "static/tab_db.png",
"selectedIconPath": "static/tab_db01.png",
"text": "对比"
},
{
"pagePath": "pages/me/me",
"iconPath": "static/tab_me.png",
"selectedIconPath": "static/tab_me01.png",
"text": "我的"
}
]
}
}

173
pages/compk/compk.vue Normal file
View File

@ -0,0 +1,173 @@
<template>
<view class="content">
<view class=" calendar">
<!-- 日历 -->
<ren-calendar ref='ren' :markDays='markDays' @onDayClick='onDayClick' @onMonthClickPre='onMonthClickPre'
@onMonthClickNext="onMonthClickNext" v-if="isShow">
</ren-calendar>
<!-- -->
<view class="box" v-if="infoList.length">
<view class="list" v-for="(item,index) in infoList" :key="index" @click="addMemberTags(item.id,item)">
<!-- 成人 -->
<view class="item">
<view class="check">
<icon class="iconfont" :class="isActive.indexOf(item.id)!=-1?'icon-radio':'icon-kongradio'">
</icon>
</view>
<view>{{item.height}}<text>身高</text></view>
<view>{{item.weight}}<text>体重</text></view>
<view>{{item.bmi}}<text>BMI</text></view>
</view>
</view>
</view>
<!-- -->
<view class="bottom">
<view class="list" v-for="(ite,ind) in ActiveDays" :key="ind" v-if="isActive"
@click="addMemberTags(ite.id,ite)">
<view class="item borderRadius">
<view class="time">{{ite.createtime}}</view>
<view>{{ite.height}}<text>身高</text></view>
<view>{{ite.weight}}<text>体重</text></view>
<view>{{ite.bmi}}<text>BMI</text></view>
<view class="check">
<icon class="iconfont icon-quxiao"></icon>
</view>
</view>
</view>
<view class="pkclass" v-if="length==2">vs</view>
<view :class="{'active':length!=2}" class="btn" @click="handlePK">减脂对比</view>
</view>
</view>
<userPopup></userPopup>
</view>
</template>
<script>
import userPopup from '@/components/userLogin.vue'
import RenCalendar from '@/components/ren-calendar/ren-calendar.vue';
import {
mapState
} from "vuex";
export default {
components: {
userPopup,
RenCalendar,
},
computed: {
...mapState(["user", "TrendPk"]),
length() {
return this.isActive.length
},
endDate() {
return this.$tools.getDate("start")
},
},
onLoad() {
this.token = uni.getStorageSync("token")
},
onShow() {
let that = this
that.startM = that.$tools.getDate("m").substring(0, 10)
that.endM = that.$tools.getDate("m").substring(11, 21)
that.infoList = []
that.markDays = []
that.list = []
that.isActive = []
that.ActiveDays = []
that.isShow = false
this.$nextTick(() => {
that.isShow = true
that.getList(that.startM, that.endM)
})
},
methods: {
getList(start, end) {
let that = this
that.$model.GetTrendList({
familyid: uni.getStorageSync('familyid'),
starttime: start,
endtime: end,
}).then(res => {
if (res) {
that.markDays = res.pkList.Dlist
that.list = res.pkList.list
for (var i = 0; i < res.pkList.list.length; i++) {
if (Date.parse(that.endDate) == Date.parse(res.pkList.list[i].createtime)) {
that.infoList.push(res.pkList.list[i]);
}
}
}
})
},
onMonthClickPre(data) {
console.log("onMonthClickPre", data)
let that = this
let start = data.substring(0, 10)
let end = data.substring(11, 21)
that.infoList = []
that.markDays = []
that.list = []
that.getList(start, end)
},
onDayClick(data) {
let that = this
this.infoList = []
for (var i = 0; i < that.list.length; i++) {
if (Date.parse(data.date) == Date.parse(that.list[i].createtime)) { //includes
this.infoList.push(that.list[i]);
}
}
},
addMemberTags(index, item) {
var that = this;
console.log("addMemberTags", index, item)
// if (this.user.type != 1) return
if (that.isActive.indexOf(index) == -1) {
that.isActive.push(index);
that.ActiveDays.push(item);
} else {
that.isActive.splice(that.isActive.indexOf(index), 1);
that.ActiveDays.splice(that.ActiveDays.indexOf(item), 1);
}
if (that.isActive.length > 2) {
that.isActive.splice(0, 1)
that.ActiveDays.splice(0, 1);
}
},
handlePK() {
let that = this
if (!uni.getStorageSync('token')) {
this.$store.commit("changeUserLogin", true);
return
}
if (that.isActive.length != 2) {
that.$tools.msg("请先选择数据!")
return
}
let info = {}
info.familyid = uni.getStorageSync('familyid')
info.firstId = that.isActive[0]
info.secondId = that.isActive[1]
uni.navigateTo({
url: "/pageTwo/compk/pkdetail?info=" + JSON.stringify(info)
})
},
},
data() {
return {
markDays: [],
infoList: [],
list: [],
isActive: [],
ActiveDays: [],
token: null,
startM: null,
endM: null,
isShow: true,
}
},
}
</script>
<style scoped lang="scss">
</style>

379
pages/index/active.vue Normal file
View File

@ -0,0 +1,379 @@
<template>
<view class="content">
<view class="tips">请在设备开机状态下搜索设备</view>
<view class="item" @click="handleWeight">开始搜索设备</view>
<view class="devices_summary">已发现 {{devices.length}} 个设备</view>
<view>
<scroll-view class="device_list" scroll-y scroll-with-animation v-if="popup">
<view v-for="(item,index) in devices" :key="index" @tap="createBLEConnection(item)" class="device_item">
<view>
<text>{{item.name|| item.localName}}</text>
</view>
<view>mac地址:{{item.macAddr || item.deviceId}}</view>
</view>
</scroll-view>
</view>
<view class="tishi">
<view class="text">
<icon class="t-icon t-icon-tishi"></icon> 设备激活流程说明
</view>
<view class="dv">
<text>1打开手机蓝牙和位置信息</text>
<text>2ios系统需打开设置>应用>微信里的蓝牙权限</text>
<text>3设备亮屏状态下搜索蓝牙</text>
<text>4选择蓝牙进行激活</text>
</view>
</view>
<userLogin :url="'active'"></userLogin>
</view>
</template>
<script>
var myTime;
import {
mapState
} from "vuex";
import userLogin from "@/components/userLogin.vue"
export default {
data() {
return {
token: "",
macAddr: "",
code: "",
deviceId: "",
popup: false,
devices: [],
}
},
components: {
userLogin
},
computed: {
...mapState(["user", "isBluetoothTyle"])
},
onLoad(options) {
let that = this
console.log("设备code码", options)
if (options) {
that.code = options.code
}
that.token = uni.getStorageSync('token')
that.login()
uni.onBluetoothAdapterStateChange(function(res) {
that.$store.commit("changeBluetooth", res.available);
})
},
methods: {
login() {
let that = this
uni.login({
success(res) {
if (res.code) {
if (res.errMsg = "login:ok") {
that.$model.onlogin({
code: res.code,
}).then(res => {
if (res.code == 2) {
uni.clearStorageSync()
uni.removeStorageSync('token')
uni.removeStorageSync('changeUser')
uni.setStorageSync('tenantid', res.data.tenantid)
uni.setStorageSync('sessionid', res.data.sessionid)
uni.setStorageSync('iswxphone', res.data.iswxphone)
that.$store.commit("changeUserLogin", true)
return
} else {
uni.setStorageSync('sessionid', res.data.sessionid)
uni.setStorageSync('token', res.data.token)
uni.setStorageSync('iswxphone', res.data.iswxphone)
uni.setStorageSync('tenantid', res.data.tenantid)
uni.setStorageSync('refreshtoken', res.data.refreshtoken)
}
}).catch(e => {})
}
}
}
})
},
handleWeight() {
let that = this
that.devices = []
if (!that.token) {
that.$store.commit("changeUserLogin", true)
return
}
uni.openBluetoothAdapter({
success: e => {
that.$store.commit("changeBluetooth", true);
that.startBluetoothDeviceDiscovery()
},
fail: e => {
wx.hideLoading()
console.log("openBluetoothAdapter失败", e)
return that.$tools.getBluetoothAdapter(e)
}
});
},
startBluetoothDeviceDiscovery() {
let that = this;
wx.showLoading({
title: '设备搜索中',
})
uni.startBluetoothDevicesDiscovery({
allowDuplicatesKey: true,
success: res => {
that.onBluetoothDeviceFound();
},
fail: res => {
wx.hideLoading()
console.log("startBluetoothDeviceDiscovery失败", res)
}
});
},
onBluetoothDeviceFound() {
var that = this;
const foundDevices = []
uni.onBluetoothDeviceFound(res => {
res.devices.forEach(device => {
if (!device.name && !device.localName) {
return
}
if (device.name.indexOf('AiLink_') != -1) {
const foundDevices = that.devices
const idx = that.$tools.inArray(foundDevices, "deviceId", device.deviceId)
let buff = device.advertisData.slice(-6)
device.mac = new Uint8Array(buff) // 广maciOSmac
let tempMac = Array.from(device.mac)
tempMac.reverse()
device.macAddr = that.$tools.ab2hex(tempMac, ':').toUpperCase()
that.deviceId = device.deviceId
that.macAddr = device.macAddr
console.log("device0", device.macAddr, that.deviceId, )
if (idx === -1) {
that.devices.push(device);
} else {
that.devices[idx] = device
}
that.popup = true
return
}
if (device.advertisServiceUUIDs[0].indexOf("F0A0") !== -1) {
const foundDevices = that.devices
const idx = that.$tools.inArray(foundDevices, "deviceId", device.deviceId)
let buffer = device.advertisData.slice(0, 8)
device.mac = new Uint8Array(buffer)
let tempMac = Array.from(device.mac)
tempMac.reverse()
device.macAddr = that.$tools.ab2hex(tempMac, ':').toUpperCase()
that.deviceId = device.deviceId;
that.macAddr = device.macAddr
console.log("device1", device.macAddr, that.deviceId)
if (idx === -1) {
that.devices.push(device);
} else {
that.devices[idx] = device
}
that.popup = true
return
}
})
});
that.handleMyTime()
},
handleMyTime() {
var that = this;
myTime = setTimeout(function() {
if (!that.devices.length) {
clearTimeout(myTime);
wx.hideLoading()
that.stopBluetoothDevicesDiscovery() //
uni.showModal({
title: '提示',
content: '请确定蓝牙和手机位置信息已打开请确定设备已开机ios系统需打开设置——>应用——>微信里的蓝牙权限!是否继续?',
cancelText: "取消",
confirmText: "继续",
success(res) {
if (res.confirm) {
that.startBluetoothDeviceDiscovery()
} else {
that.$tools.msg("您已取消操作")
}
}
})
} else {
clearTimeout(myTime);
that.stopBluetoothDevicesDiscovery()
}
}, 30000);
},
/**
* 停止搜索蓝牙设备
*/
stopBluetoothDevicesDiscovery() {
uni.stopBluetoothDevicesDiscovery({
success: e => {
console.log("停止搜索蓝牙设备", e)
},
});
},
//
createBLEConnection(e) {
let that = this;
that.stopBluetoothDevicesDiscovery()
that.macAddr = e.macAddr
that.getCode()
},
getCode() {
let that = this;
clearTimeout(myTime);
wx.hideLoading()
uni.showModal({
title: '提示',
content: '是否激活该设备?',
cancelText: "取消",
confirmText: "确定",
success: (res) => {
if (res.confirm) {
that.getActive()
} else {
that.$tools.msg("您已取消操作")
}
}
})
},
getActive() {
let that = this
that.$model.getdevactive({
code: that.code,
sn: that.macAddr
}).then(res => {
that.$tools.msg(res.message)
that.closeBluetoothAdapter()
that.closeBLEConnection()
that.devices = []
if (res.code == 0) {
setTimeout(function() {
uni.reLaunch({
url: "/pages/index/index?t=" + that.devtype
})
}, 500)
}
})
},
/**
* 断开蓝牙模块
*/
closeBluetoothAdapter() {
let that = this;
uni.closeBluetoothAdapter({
success: res => {
console.log('蓝牙模块关闭成功');
}
})
},
/**
* 断开蓝牙连接
*/
closeBLEConnection() {
var that = this;
uni.closeBLEConnection({
deviceId: that.deviceId,
success: res => {
console.log('断开蓝牙连接成功');
}
});
},
}
}
</script>
<style scoped lang="scss">
.content {
min-height: 100vh;
padding: 0;
border-top: 66px solid #75DAD0;
background-color: #fff;
}
.tishi {
width: 100%;
font-size: 14px;
line-height: 25px;
font-weight: bold;
position: absolute;
bottom: 30px;
padding-left: 15px;
.text {
display: flex;
align-items: center;
icon {
margin-right: 5px;
}
}
text {
font-weight: 500;
font-size: 12px;
color: #999;
width: 100%;
display: block;
}
}
.item {
width: 70%;
height: 40px;
line-height: 38px;
text-align: center;
background: #f7f7f7;
border: 1px solid #dfdfdf;
font-weight: bold;
margin: auto;
border-radius: 15px;
margin-top: 15px;
}
.devices_summary {
width: 100%;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 16px;
color: #666;
}
.device_list {
flex: 1;
width: 100%;
height: auto;
max-height: 200px;
margin-top: 0;
margin-bottom: 10px;
.device_item {
font-size: 14px;
padding: 10px;
color: #999;
border-bottom: 1px solid #dfdfdf;
text {
display: inline-block;
font-size: 14px;
font-weight: bold;
color: #666;
margin-bottom: 5px;
}
}
}
.tips {
font-size: 14px;
text-align: center;
color: #e83a1e;
background: #f7e4c8;
padding: 5px 0;
margin-top: 15px;
}
</style>

637
pages/index/index.vue Normal file
View File

@ -0,0 +1,637 @@
<template>
<view class="content">
<!-- 头部 -->
<view class="header-con">
<view class="header" v-if="token">
<view class="left">
<image :src="user.headimg" class="headimage mr-10" @click="handleDrawer"></image>
<view>
<view class="name" @click="handleDrawer">
<text class="overflow">{{user.name}}</text>
<icon class="iconfont icon-yqfqiehuan"></icon>
</view>
<view class="age">
<view>
性别{{!user.sex?"未知":user.sex==1?'男':'女'}}
</view>
<view>
年龄{{user.mage?user.mage:"0岁"}}
</view>
</view>
</view>
</view>
<view class="celiang_r" @click="handleBluetoothClick">
<icon class="t-icon t-icon-tizhongcheng"></icon>
<text>上秤测量</text>
</view>
</view>
<view class="header2" v-else @click="handleLogin">
<view class="text"><text>登录</text>查看更多信息</view>
</view>
</view>
<!-- 提示
<view class="mt-15" v-show="MeasureResult&&MeasureResult.muscle==0">
<view class="unusual">体脂测量异常请重新测量</view>
</view> -->
<!-- 工具 -->
<view class="tools_l">
<view v-for="(item,index) in toollist" :key="index" class="list" @click="clickTool(item.id)">
<image :src="item.icon"></image>
<view class="text">{{item.title}}</view>
</view>
</view>
<!-- 报告 -->
<view class="myinfo myinfoPage borderT15" v-if="infoList.length">
<view class="h2">
<view><text></text>健康评分</view>
</view>
<view class="box">
<view class="left">
<view class="circleprogress">
<view class="wrapper">
<view class="leftprogress" :style="{ width: MeasureResult.cmi + '%'}">
</view>
</view>
<view class="fen">
<view>{{MeasureResult.cmi}}</view>
</view>
</view>
</view>
<view class="right">
<view class="item">
<view><text>{{MeasureResult.height}}</text>cm</view>
<view class="tivon">身高</image>
</view>
</view>
<view class="item">
<view><text>{{MeasureResult.weight}}</text>kg</view>
<view>体重</view>
</view>
<view class="item">
<view><text>{{MeasureResult.bodyage}}</text></view>
<view>体龄</view>
</view>
<view class="item">
<view><text class="f-15">{{MeasureResult.body}}</text></view>
<view>体型</view>
</view>
</view>
</view>
</view>
<view class="myinfo myinfoPage borderT15">
<view class="h2">
<view><text></text>健康分析</view>
<view class="more" v-if="infoList.length">测量时间{{user.lasthearttime}}</view>
</view>
<view v-if="infoList.length">
<view class="box1">
<view class="list" v-for="(item,index) in infoList" :key="index" @click="handleToggle(index)">
<view class="block">
<view class="name">
<icon class="t-icon iconfont" :class="'t-icon-'+item.key"></icon>
{{item.title}}
</view>
<view class="val" v-if="item.title!='肥胖等级'">
{{item.fvalue?item.fvalue:'0'}}{{item.dw}}
</view>
<view class="val0" v-else>{{item.fevaluation}}</view>
<view class="level" v-if="item.title!='肥胖等级'">
<view class="btnf" :style="{backgroundColor:item.color}">{{item.fevaluation}}</view>
</view>
<view class="icon">
<icon class="iconfont icon-arrow-down" v-if="item.desc"></icon>
</view>
</view>
<view class="desc" v-if="item.showCon">
<view v-if="item.desc">{{item.desc}}</view>
<view class="statuevue" v-if="item.slist">
<view class="bi" v-if="item.title!='基础代谢'">
<view class="item" v-for="(ite , ind) in item.slist" :key="ind"
:style="{backgroundColor:ite.color}">
<view class="span1">{{ite.text}}</view>
<view v-if="ite.text==item.fevaluation&&item.fvalue>ite.maxvalue"
style="right: 10px" class="peobox">
<view class="xx"></view>
</view>
<view v-if="ite.text==item.fevaluation&&item.fvalue<=ite.maxvalue"
:style="'left:'+item.leftval+'rem'" class="peobox">
<view class="xx"></view>
</view>
<view class="span" v-if="ind<item.slist.length-1">{{ite.maxvalue}}</view>
</view>
</view>
<view v-else>
<view class="kcalClass">
标准值:{{item.slist[0].maxvalue}}kcal
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<view v-else class="nolist">
<icon class="iconfont icon-zanwu"></icon>
</view>
</view>
<view class="introction" v-if="infoList.length">
<icon class="t-icon t-icon-tishi"></icon>
<span>此测量数据仅供参考不可代替医学专业测试</span>
</view>
<!-- 提醒设置 -->
<view class="tipList borderRadius borderT15 mb-15">
<view class="h2">
<view><text></text>提醒设置</view>
</view>
<view class="item_box">
<view class="item_box_tips" v-for="(text,id) in checkList" :key="id" @click="switch1Change(text.index)">
{{text.title}}
<image class="iconfont"
:src="isShowEle == text.index?'../../static/switch-off.png':'../../static/switch-ON.png'" />
</view>
</view>
</view>
<!-- banner -->
<view class="f_banner borderT15" v-if="fimages.length">
<swiper class="swiper" indicator-dots="true" autoplay="true">
<swiper-item v-for="(image, index) in fimages" :key="index" @click="detail(image)">
<image :src="image.headimg" />
</swiper-item>
</swiper>
</view>
<view class="endtext" v-if="!lastPage || page >= lastPage"> 到底了看看别的吧 </view>
<!-- denglu -->
<userLogin></userLogin>
<!-- 手动记录 -->
<manuaRecord></manuaRecord>
<!-- 左侧 -->
<leftdrawer></leftdrawer>
</view>
</template>
<script>
import {
mapState
} from "vuex";
import userLogin from '@/components/userLogin.vue'
import leftdrawer from "@/components/drawer/drawer.vue"
import manuaRecord from '@/components/target/manuaRecord.vue';
export default {
components: {
leftdrawer,
userLogin,
manuaRecord
},
computed: {
...mapState(["user", "MeasureResult"]),
},
onLoad(options) {
let that = this;
that.token = uni.getStorageSync('token')
if (options && options.t) {
that.devType = options.t
that.deviceId = options.sn
}
that.login()
},
onShow() {
this.token = uni.getStorageSync('token')
},
onTabItemTap() {
this.$store.commit("changeDrawe", false)
this.$store.commit("changeRecord", false);
},
watch: {
MeasureResult() {
this.handleToggle(0)
}
},
methods: {
login() {
let that = this
uni.login({
success(res) {
if (res.code) {
if (res.errMsg = "login:ok") {
that.$model.onlogin({
code: res.code,
}).then(res => {
if (res.code == 2) {
uni.clearStorageSync()
uni.removeStorageSync('token')
uni.removeStorageSync('changeUser')
that.$store.commit("changeLogout", false);
uni.setStorageSync('tenantid', res.data.tenantid)
uni.setStorageSync('sessionid', res.data.sessionid)
uni.setStorageSync('iswxphone', res.data.iswxphone)
return
}
if (res.code == 0) {
that.token = res.data.token
uni.setStorageSync('token', res.data.token)
uni.setStorageSync('tenantid', res.data.tenantid)
uni.setStorageSync('sessionid', res.data.sessionid)
uni.setStorageSync('iswxphone', res.data.iswxphone)
uni.setStorageSync('refreshtoken', res.data.refreshtoken)
that.getFamilyList()
}
}).catch(e => {})
}
}
}
})
},
getFamilyList() {
let that = this
that.$model.getFamilyList({}).then(res => {
that.$store.commit("changeFamilay", res)
that.$store.dispatch("getUserInfo", {
familyid: res[0].familyid
})
that.$store.dispatch("getResult", {
birthday: res[0].birthday,
familyid: res[0].familyid,
height: res[0].height,
sex: res[0].sex,
})
that.GetTplList()
that.GetSubscribeInfo()
// that.getBannerList()
}).catch(e => {})
},
//
GetSubscribeInfo() {
let that = this
that.$model.GetSubscribeInfo({}).then(res => {
if (res.code == 0) {
console.log("获取消息订阅状态", res)
that.isShowEle = res.data.type
}
})
},
//
GetTplList() {
let that = this
that.$model.GetTplList({}).then(res => {
if (res.code == 0) {
res.data.forEach(item => {
that.tmplIdList.push(item.id)
})
}
})
},
//
switch1Change(ind) {
let that = this
if (that.isShowEle != ind) { //
wx.requestSubscribeMessage({
tmplIds: that.tmplIdList,
success(res) {
let list = {}
let subList = []
that.tmplIdList.forEach(item => {
list = {
"tplId": item,
"status": res[item],
}
})
subList.push(list)
that.$model.GetSubscribe({
type: ind,
list: subList,
}).then(res => {
console.log("res", res)
if (res.code != 0) return
that.isShowEle = ind
})
},
fail(res) {
console.log("res失败", res)
that.$tools.msg("订阅失败")
}
})
} else { //
that.$model.Getunsubscribe({
type: 1,
}).then(res => {
if (res.code == 0) {
that.$tools.msg("取消提醒成功")
that.isShowEle = 0
return
}
})
}
},
//
getBannerList() {
this.$model.GetAdBannerList({
page: 1,
pagesize: 10,
}).then(res => {
this.fimages = res.data.items
})
},
//
handleBluetoothClick() {
let that = this
if (!that.token) {
that.$store.commit("changeUserLogin", true)
return
}
uni.openBluetoothAdapter({
success: e => {
that.$store.commit("changeBluetooth", true);
if (that.devType && that.deviceId) {
that.$tools.handlePages(that.devType, that.deviceId)
return
}
uni.navigateTo({
url: "/pages/search/devType"
})
console.log('初始化蓝牙成功:' + e.errMsg);
},
fail: err => {
console.log('初始化蓝牙失败:' + err.errMsg);
return this.$tools.getBluetoothAdapter(err)
}
});
},
//
handleToggle(index) {
let that = this
if (!that.MeasureResult) return
let str = this.weightInfo.infoList(that.MeasureResult).slice(1, 14)
for (var i = 0; i < str.length; i++) {
if (i == index) {
str[i].showCon = !str[i].showCon
} else {
str[i].showCon = false
}
}
that.infoList = this.weightInfo.infoList(that.MeasureResult).slice(1, 14)
},
//
clickTool(ind) {
let that = this
if (!that.token) {
that.$store.commit("changeUserLogin", true);
return
}
if (ind == 0) {
that.$store.commit("changeRecord", true)
return
}
if (ind == 1) {
uni.navigateTo({
url: "/pageTwo/survey/survey"
})
return
}
if (ind == 2) {
uni.navigateToMiniProgram({
appId: 'wx3e83b37ba682faf5',
path: 'pages/index/index',
extraData: {},
})
return
}
if (ind == 3) {
uni.navigateTo({
url: "/pageTwo/me/history"
})
return
}
},
detail(e) {
if (e.type == 1) {
uni.navigateTo({
url: "/pageTwo/zixun/detail?id=" + e.id
})
return
}
if (e.type == 2) {
uni.navigateTo({
url: "/pageTwo/zixun/detail?url=" + e.content
})
return
}
if (e.type == 3) {
uni.navigateToMiniProgram({
appId: e.content,
path: '',
extraData: {},
})
return
}
},
//
handleLogin() {
this.$store.commit("changeUserLogin", true);
},
handleDrawer() {
this.$store.commit("changeDrawe", true);
},
},
data() {
return {
fimages: [],
token: null,
devType: "",
deviceId: "",
isShowEle: 0,
infoList: [],
tmplIdList: [],
toollist: [{
icon: '/static/tool1.png',
title: '手动记录',
id: 0
}, {
icon: '/static/tool2.png',
title: '体质评估',
id: 1
},
{
icon: '/static/tool3.png',
title: '儿童测量',
id: 2
},
{
icon: '/static/tool4.png',
title: '历史记录',
id: 3
},
],
checkList: [{
title: '每周提醒',
index: 1,
},
{
title: '每月提醒',
index: 2,
},
{
title: '半年提醒',
index: 3,
},
{
title: '一年提醒',
index: 4,
}
],
}
},
}
</script>
<style scoped lang="scss">
.content {
margin-top: 110px;
background-color: #f7f7f7;
padding-bottom: 15px;
//
.tools_l {
width: 100%;
display: flex;
flex-wrap: wrap;
padding-top: 10px;
background: #fff;
justify-content: space-between;
.list {
width: 25%;
text-align: center;
font-size: 14px;
margin-bottom: 15px;
.text {
margin-top: 5px;
color: #666;
font-size: 12px;
}
}
image {
width: 35px;
height: 35px;
}
}
.myinfo {
background: #fff;
margin-top: 15px;
}
//
.tipList {
background: #fff;
margin-top: 10px;
.item_box {
display: flex;
align-items: center;
align-content: center;
flex-wrap: wrap;
margin: 0 15px;
}
.item_box_tips {
width: 50%;
display: flex;
align-items: center;
justify-content: start;
margin-bottom: 10px;
.t-icon,
.iconfont {
width: 35px;
height: 35px;
margin-left: 10px;
}
}
:nth-child(even).item_box_tips {
text-align: right;
justify-content: flex-end;
}
}
//
.h2 {
color: #333;
font-weight: bold;
padding: 10px 15px;
font-size: 32rpx;
display: flex;
justify-content: space-between;
text {
display: inline-block;
background: $btncolor;
width: 8px;
height: 12px;
margin-right: 5px;
font-size: 32rpx;
}
.more {
font-size: 14px;
font-weight: 500;
color: #666;
}
}
// banner
.f_banner {
width: 100%;
height: 330rpx;
margin-top: 30rpx;
bottom: 52px;
/deep/swiper {
height: 330rpx;
}
image {
width: 100%;
height: 100%;
background-size: 100%;
}
}
.unusual {
font-size: 14px;
border-radius: 8px;
text-align: center;
color: #e83a1e;
background: #f7e4c8;
padding: 5px 0;
}
.introction {
display: flex;
margin-top: 10px;
margin-left: 15px;
font-size: 12px;
color: #666;
.t-icon {
width: 15px;
height: 15px;
margin-right: 5px;
}
}
.val0 {
position: absolute;
left: 40%;
margin-left: 3px;
}
}
</style>

307
pages/me/me.vue Normal file
View File

@ -0,0 +1,307 @@
<template>
<view class="content">
<view class="header-con">
<view class="header" v-if="token">
<image :src="user.headimg" class="headimage" />
<text>{{user.name||user.name}}</text>
</view>
<view class="header2" v-else @click="handleLogin">
<view class="text"><text>登录</text>查看更多信息</view>
</view>
</view>
<!-- 列表 -->
<view class="infolist">
<view class="item borderRadius" @click="handleEditClick">
<view class="left">
性别
</view>
<view class="right"><text>{{user.sex==0?"未知":user.sex==1?'男':'女'}}</text>
<icon class="t-icon t-icon-bianji3"></icon>
</view>
</view>
<view class="item borderRadius" @click="handleEditClick">
<view class="left">
年龄()
</view>
<view class="right"><text>{{user.age?user.age:user.mage?user.mage:0}}</text>
<icon class="t-icon t-icon-bianji3"></icon>
</view>
</view>
<view class="item borderRadius" @click="handleEditClick">
<view class="left">
身高(cm)
</view>
<view class="right"><text>{{user.height?user.height:0}}</text>
<icon class="t-icon t-icon-bianji3"></icon>
</view>
</view>
</view>
<!-- -->
<view class="wxlist borderRadius">
<view class="list" @tap="navTo('/pageTwo/me/manage')">
<view class="item border-bottom">
<view class="left">
<i class="t-icon t-icon-shoucang"></i>
<view class="name">成员管理</view>
</view>
<view class="right">
<icon class="icon iconfont icon-arrow-right" color="#999"></icon>
</view>
</view>
</view>
<!-- -->
<view class="list" @tap="navTo('/pageTwo/me/history')">
<view class="item border-bottom">
<view class="left">
<i class="t-icon t-icon-gonglve"></i>
<view class="name">历史记录</view>
</view>
<view class="right">
<icon class="icon iconfont icon-arrow-right" color="#999"></icon>
</view>
</view>
</view>
<!-- -->
<view class="list" @tap="navTo('/pageTwo/me/feedBack')">
<view class="item border-bottom">
<view class="left">
<i class="t-icon t-icon-pinglun"></i>
<view class="name">意见反馈</view>
</view>
<view class="right">
<icon class="icon iconfont icon-arrow-right" color="#999"></icon>
</view>
</view>
</view>
<!-- -->
<view class="list" @click="handleClick(1)">
<view class="item border-bottom">
<view class="left">
<icon class="t-icon t-icon-shouhou"></icon>
<view class="name">设备管理</view>
</view>
<view class="right">
<icon class="icon iconfont icon-arrow-right" color="#999"></icon>
</view>
</view>
</view>
<!-- -->
<view class="list" @click="handleClick(0)">
<view class="item border-bottom">
<view class="left">
<icon class="t-icon t-icon-hezuo"></icon>
<view class="name">儿童测量</view>
</view>
<view class="right">
<icon class="icon iconfont icon-arrow-right" color="#999"></icon>
</view>
</view>
</view>
</view>
<view class="btn ml-15 mr-15" v-if="token" @click="handleOutLogin">退出登录</view>
<SignUp></SignUp>
<userPopup></userPopup>
</view>
</template>
<script>
import {
mapState
} from "vuex";
import SignUp from '@/components/signup/signup.vue';
import userPopup from '@/components/userLogin.vue'
export default {
data() {
return {
token: null,
}
},
components: {
userPopup,
SignUp,
},
computed: {
...mapState(["user"]),
},
onTabItemTap() {
this.$store.commit("changeEdit", false);
},
onLoad() {
this.token = uni.getStorageSync("token")
},
methods: {
handleLogin() {
if (!uni.getStorageSync('token')) {
this.$store.commit("changeUserLogin", true);
return
}
},
handleOutLogin() {
let that = this
uni.showModal({
title: '友情提示',
content: '是否退出登录?',
success: function(res) {
if (res.confirm) {
that.$model.getoutlogin({
sessionid: uni.getStorageSync('sessionid')
}).then((res) => {
that.$tools.msg(res.message)
if (res.code != 0) return
console.log('确定退出', res)
uni.clearStorageSync()
uni.setStorageSync('sessionid', null)
that.$store.commit("changeLogout", false);
uni.reLaunch({
url: "/pages/index/index"
})
})
} else if (res.cancel) {
that.$tools.msg("您已取消操作!");
}
},
})
},
handleClick(ind) {
if (!uni.getStorageSync('token')) {
this.$store.commit("changeUserLogin", true);
return
}
//
if (ind == 0) {
uni.navigateToMiniProgram({
appId: 'wx3e83b37ba682faf5',
path: 'pages/index/index',
extraData: {},
})
return
}
//
if (ind == 1) {
uni.navigateToMiniProgram({
appId: 'wx6f48cc32c5c0a4a2',
path: 'pages/index/index',
extraData: {},
})
return
}
},
navTo(url) {
if (!uni.getStorageSync('token')) {
this.$store.commit("changeUserLogin", true);
return
}
uni.navigateTo({
url
})
},
handleEditClick() {
if (!uni.getStorageSync('token')) {
this.$store.commit("changeUserLogin", true);
return
}
this.$store.commit("changeEdit", true);
},
}
}
</script>
<style scoped="scoped" lang="scss">
.content {
min-height: 100vh;
margin-top: 110px;
}
.header-con {
height: 95px !important;
}
.wxlist {
height: auto;
overflow: hidden;
position: relative;
margin: 0 15px;
padding: 0 15px;
background: #fff;
border-radius: 10px;
.item {
width: auto;
font-size: 14px;
line-height: 55px;
height: 55px;
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
// border-bottom: 1px solid #dfdfdf;
.left {
display: flex;
.name {
float: left;
color: #333;
position: absolute;
left: 27px;
top: 0;
}
}
}
}
.infolist {
display: flex;
justify-content: space-between;
align-items: center;
margin: 15px;
.item {
width: 30%;
padding: 10px 0;
text-align: center;
background: #fff;
border-radius: 10px;
position: relative;
}
.right {
display: flex;
justify-content: center;
margin-top: 5px;
text {
display: inline-block;
font-size: 16px;
color: #666;
font-weight: 700;
}
icon {
position: absolute;
right: 7px;
bottom: 9px;
}
}
}
.btn {
width: auto;
margin-top: 50px;
}
/deep/ .header {
justify-content: center;
flex-wrap: wrap;
margin-top: 0;
}
/deep/ .header text {
background: inherit;
border: none;
width: 100%;
display: block;
color: #fff;
text-align: center;
margin-right: 0;
font-size: 16px;
}
</style>

469
pages/search/devType.vue Normal file
View File

@ -0,0 +1,469 @@
<template>
<view class="container">
<view class="text" @click="openBluetoothAdapter" v-if="issearch">没有搜到想要的点击重新搜索</view>
<view class="point-area">
<view class="point point-10"></view>
<view class="point point-40"></view>
<view class="point point-80"></view>
<view class="point point-100"></view>
<view class="point point-120"></view>
</view>
<view class="list">
<view class="item" v-for="(item,index) in devList" :key="index" @click="handleWeight(item)">
<image :src="item.img"></image>
<text>{{item.faccode}}</text>
</view>
</view>
<view class="tips" v-if="isdevTip">
<view>提示</view>
<text>1.请确保设备是已激活</text>
<text>2.请确保设备是开机状态</text>
<text>3.请确定手机蓝牙位置信息已打开</text>
<text>4.ios系统需打开设置>应用>微信里的蓝牙权限</text>
</view>
</view>
</template>
<script>
let that;
let myTime;
import {
mapState
} from "vuex";
export default {
data() {
return {
Unload: false,
issearch: false,
isdevTip: false,
devList: []
}
},
computed: {
...mapState(["user", "isConnected", "isBluetoothTyle"]),
},
onLoad() {
that = this
that.openBluetoothAdapter()
that.onBLEConnectionStateChange()
uni.onBluetoothAdapterStateChange(function(res) {
that.$store.commit("changeBluetooth", res.available);
})
},
onUnload: function() {
let that = this
if (!that.Unload) {
that.stopBluetoothDevicesDiscovery() //
that.closeBLEConnection()
that.closeBluetoothAdapter()
console.log("搜索页返回")
}
},
watch: {
isBluetoothTyle: function() {
let that = this
if (!that.isBluetoothTyle) {
that.issearch = true
that.isdevTip = true
that.devList = []
clearTimeout(myTime);
that.closeBLEConnection()
that.closeBluetoothAdapter()
that.stopBluetoothDevicesDiscovery()
}
}
},
methods: {
//
openBluetoothAdapter() {
let that = this
uni.openBluetoothAdapter({
success: e => {
console.log("蓝牙初始化成功")
that.issearch = false
that.isdevTip = false
that.devList = []
that.startBluetoothDeviceDiscovery()
},
fail: e => {
that.$tools.msg("请打开蓝牙安卓系统需打开蓝牙、定位权限ios系统需打开设置——>应用——>微信里的蓝牙权限!")
}
});
},
//
onBLEConnectionStateChange() {
let that = this
uni.onBLEConnectionStateChange(function(res) {
console.log("蓝牙连接状态", res.connected)
that.$store.commit("changeConnected", res.connected);
})
},
/**
* 停止搜索蓝牙设备
*/
stopBluetoothDevicesDiscovery() {
uni.stopBluetoothDevicesDiscovery({
success: e => {
console.log("停止搜索蓝牙设备", e)
},
});
},
//
startBluetoothDeviceDiscovery() {
let that = this
uni.startBluetoothDevicesDiscovery({
// allowDuplicatesKey: false, //
success: res => {
that.onBluetoothDeviceFound();
},
fail: res => {
that.$tools.msg("请打开蓝牙安卓系统需打开蓝牙、定位权限ios系统需打开设置——>应用——>微信里的蓝牙权限!")
}
});
},
/**
* 发现外围设备
*/
onBluetoothDeviceFound() {
var that = this;
uni.onBluetoothDeviceFound(res => {
res.devices.forEach(device => {
if (!device.name && !device.localName) {
return
}
if (device.advertisServiceUUIDs[0].indexOf("F0A0") !== -1) {
let buffer = device.advertisData.slice(0, 8)
device.mac = new Uint8Array(buffer)
let tempMac = Array.from(device.mac)
tempMac.reverse()
device.macAddr = that.$tools.ab2hex(tempMac, ':').toUpperCase()
if (device.macAddr != "") {
that.handleDevType(device.macAddr)
}
return
}
let buff = device.advertisData.slice(-6)
device.mac = new Uint8Array(buff)
let tempMac = Array.from(device.mac)
if (device.name.indexOf('My') == -1) {
tempMac.reverse()
}
device.macAddr = that.$tools.ab2hex(tempMac, ':').toUpperCase()
if (device.macAddr != "") {
that.handleDevType(device.macAddr)
}
})
});
that.handleMyTime()
},
handleMyTime() {
var that = this;
myTime = setTimeout(function() {
if (!that.devList.length) {
that.isdevTip = true
that.devList = []
}
that.issearch = true
clearTimeout(myTime);
that.closeBLEConnection()
that.closeBluetoothAdapter()
that.stopBluetoothDevicesDiscovery() //
}, 30000);
},
//
handleDevType(sn) {
that = this
that.$model.getdevdetail({
sn: sn
}).then(res => {
if (res.code == 0) {
res.data.deviceId = sn
that.devList.push(res.data);
}
})
},
handleWeight(item) {
let that = this
that.Unload = true
clearTimeout(myTime);
if (item.type != 4 || item.type != 5 || item.type != 16) {
that.stopBluetoothDevicesDiscovery()
}
that.$tools.handlePages(item.type, item.deviceId)
},
/**
* 断开蓝牙模块
*/
closeBluetoothAdapter() {
let that = this;
uni.closeBluetoothAdapter({
success: res => {
console.log('蓝牙模块关闭成功');
}
})
},
/**
* 断开蓝牙连接
*/
closeBLEConnection() {
var that = this;
uni.closeBLEConnection({
success: res => {
console.log('断开蓝牙连接成功');
}
});
},
handleBack() {
let that = this
that.Unload = true
that.stopBluetoothDevicesDiscovery() //
that.closeBLEConnection()
that.closeBluetoothAdapter()
uni.navigateBack({
delta: 1
})
},
}
}
</script>
<style scoped lang="scss">
.text {
position: absolute;
top: 0px;
width: 100%;
text-align: center;
height: 50px;
line-height: 50px;
font-size: 16px;
color: $greencolor;
font-weight: bold;
}
.tips {
position: absolute;
width: 100%;
bottom: 15px;
line-height: 24px;
view {
font-size: 14px;
color: $greencolor;
font-weight: bold;
margin-left: 15px;
}
text {
font-size: 12px;
width: 100%;
display: block;
margin-left: 20px;
color: #999;
}
}
.list {
position: absolute;
width: 100%;
display: flex;
align-items: center;
flex-wrap: wrap;
.item {
width: 30%;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
position: absolute;
left: 55%;
top: -10px;
image {
width: 45px;
height: 45px;
border-radius: 50%;
}
text {
display: block;
width: 100%;
font-size: 12px;
color: #666;
margin-top: 5px;
text-align: center;
}
}
.item:nth-of-type(2) {
left: calc(55% - 60px);
top: 50px;
}
.item:nth-of-type(3) {
left: calc(50% - 140px);
top: 90px;
}
.item:nth-of-type(4) {
left: calc(61% + 20px);
top: 70px;
}
.item:nth-of-type(5) {
left: 20%;
top: -100px;
}
.item:nth-of-type(6) {
left: calc(20% - 16px);
top: -38px;
}
.item:nth-of-type(7) {
left: 0;
top: 15px;
}
.item:nth-of-type(8) {
left: calc(20% + 75px);
top: -150px;
}
.item:nth-of-type(9) {
left: calc(20% + 96px);
top: -80px;
}
.item:nth-of-type(10) {
left: 37px;
top: -170px;
}
.item:nth-of-type(11) {
left: calc(20% + 75px);
top: 130px;
}
.item:nth-of-type(12) {
left: -10px;
top: -104px;
}
.item:nth-of-type(13) {
left: calc(47% + 75px);
top: -150px;
}
.item:nth-of-type(14) {
left: calc(53% + 75px);
top: -50px;
}
}
.container {
width: 100%;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
}
//
.container::after {
content: "";
width: 20px;
height: 20px;
border-radius: 50%;
background-color: #fbb780;
position: absolute;
z-index: 9;
}
/* 定义范围*/
.point-area {
text-align: center;
position: relative;
width: 400rpx;
height: 400rpx;
transition: opacity 0.5s ease-out;
}
.point-10,
.point-40,
.point-80,
.point-100,
.point-120 {
width: 100%;
height: 100%;
}
.point-10:after,
.point-40:after,
.point-80:after,
.point-100:after,
.point-120:after {
content: '';
display: block;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
border-radius: 50%;
opacity: 0;
border: 1px solid #f7cb6b;
animation-play-state: paused;
-webkit-animation-play-state: paused;
}
.point-10:after {
content: '';
animation: ripple 3000ms linear 0ms infinite;
}
.point-40:after {
content: '';
animation: ripple 3000ms linear 600ms infinite;
}
.point-80:after {
content: '';
animation: ripple 3000ms linear 1200ms infinite;
}
.point-100:after {
content: '';
animation: ripple 3000ms linear 1800ms infinite;
}
.point-120:after {
content: '';
animation: ripple 3000ms linear 2400ms infinite;
}
@keyframes ripple {
0% {
opacity: 0;
transform: scale(0.1);
}
50% {
opacity: 0.8;
transform: scale(1);
}
100% {
opacity: 0.2;
transform: scale(2.2);
}
}
</style>

312
pages/target/target.vue Normal file
View File

@ -0,0 +1,312 @@
<template>
<view class="content">
<!-- 时间选择 -->
<view class="TrendPage">
<view class="TrendTime">
<view class="boxTime">
<view class="one">
<picker mode="date" class="f-l" :value="startTime?startTime:startDate" @change="handStartTimeH">
<view class="uni-input">{{startTime?startTime:startDate}}
<icon class="iconfont iconDown"></icon>
</view>
</picker>
<picker mode="date" :end="endDate" class="f-r" :value="endDate" @change="handEndTimeH">
<view class="uni-input">~ {{endTime?endTime:endDate}}
<icon class="iconfont iconDown"></icon>
</view>
</picker>
</view>
<view class="tow" @click="handAllTime(0)" :class="{style:active==0}">
近3月
</view>
<view class="tow" @click="handAllTime(1)" :class="{style:active==1}">
近半年
</view>
</view>
</view>
<!-- 曲线图 -->
<view class="box boxList">
<view class="listC">
<view :class="{active:index==active1}" class="name" v-for="(item,index) in weightList" :key="index"
@click="showbox(index)">
{{item.title}}
</view>
</view>
<view class="blockC">
<view v-if="lineData&&lineData.categories.length&&handTrue">
<qiun-data-charts type="area" :chartData="lineData" :canvas2d="true" canvasId="charts09"
:cHeight="480" :cWidth="640" :animation="false"
:opts="{enableScroll:true,xAxis:{scrollShow:false,itemCount:3}}" :ontouch="true" />
</view>
<view class="nolist" v-else>
<icon class="iconfont icon-zanwu"></icon>
</view>
</view>
</view>
<!-- 目标-->
<view class="box">
<view class="data">
<view class="item" @click="handleClick(0)">
<view class="val">{{userInfo.targetweight?userInfo.targetweight:0}}<text>kg</text>
</view>
<view class="name">目标体重<icon class="t-icon t-icon-bianji3"></icon>
</view>
</view>
<view class="item">
<view class="val">{{userInfo.totalweight?Math.abs(userInfo.totalweight):0}}<text>kg</text>
</view>
<view class="name" v-if="Number(userInfo.totalweight)<0">累计增重</view>
<view class="name" v-else>累计减重</view>
</view>
<view class="item" @click="handleClick(1)">
<view class="val">{{userInfo.firstweight?userInfo.firstweight:0}}<text>kg</text>
</view>
<view class="name">初始体重<icon class="t-icon t-icon-bianji3"></icon>
</view>
</view>
<view class="item">
<view class="val">{{userInfo.day?userInfo.day:0}}<text></text></view>
<view class="name">减重天数</view>
</view>
<view class="item" @click="handleClick(2)">
<view class="val"></view>
<view class="name">
<icon class="iconfont icon-tianjia">手动记录</icon>
</view>
</view>
</view>
</view>
<!-- 手动 -->
<manuaRecord @getList="getList"></manuaRecord>
<!-- 初始 -->
<firstweight></firstweight>
<!-- 目标 -->
<targetWeight></targetWeight>
<!-- 登录 -->
<userPopup></userPopup>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
import userPopup from '@/components/userLogin.vue'
import targetWeight from '@/components/target/targetWeight.vue';
import firstweight from '@/components/target/firstweight.vue';
import manuaRecord from '@/components/target/manuaRecord.vue';
import qiunDataCharts from '@/uni_modules/qiun-data-charts/components/qiun-data-charts.vue';
export default {
components: {
targetWeight,
firstweight,
manuaRecord,
userPopup,
qiunDataCharts,
},
computed: {
...mapState(["user", "Trend"]),
userInfo: function() {
return this.user
},
endDate() {
return this.$tools.getDate("start")
},
startDate() {
return this.$tools.GetDateStr(-90);
},
},
onShow() {
let that = this
this.token = uni.getStorageSync('token')
this.active = 0
this.startTime = ""
this.endTime = ""
that.getList(this.startDate, this.endDate)
},
methods: {
getList(start, end) {
console.log("fanhui", start, end)
let that = this
that.$model.getTrendList({
familyid: uni.getStorageSync('familyid'),
starttime: start,
endtime: end,
}).then(res => {
if (res) {
for (var i = 0; i < that.weightList.length; i++) {
that.weightList[i].Line = res[that.weightList[i].key];
}
that.showbox(0)
}
})
},
showbox(index) {
let that = this
that.handTrue = false
this.$nextTick(function() {
that.handTrue = true
that.lineData = that.weightList[index].Line
})
that.active1 = index
},
//
handStartTimeH(e) {
let that = this
if (this.endTime) {
if (Date.parse(e.target.value) > Date.parse(this.endTime)) {
this.$tools.msg("请选择正确的时间")
return
}
} else {
if (Date.parse(e.target.value) > Date.parse(this.endDate)) {
this.$tools.msg("请选择正确的时间")
return
}
}
this.startTime = e.target.value
let endtime = that.endTime ? that.endTime : that.endDate
this.getList(that.startTime, endtime)
},
//
handEndTimeH(e) {
let that = this
if (this.startTime) {
if (Date.parse(e.target.value) < Date.parse(this.startTime)) {
this.$tools.msg("请选择正确的时间")
return
}
} else {
if (Date.parse(e.target.value) < Date.parse(this.startDate)) {
this.$tools.msg("请选择正确的时间")
return
}
}
this.endTime = e.target.value
let startTime = that.startTime ? that.startTime : that.startDate
this.getList(startTime, this.endTime)
},
//
handAllTime(ind) {
let that = this
if (!uni.getStorageSync('token')) {
this.$store.commit("changeUserLogin", true);
return
}
this.active = ind
if (ind == 0) {
this.startTime = that.$tools.GetDateStr(-90)
} else {
this.startTime = that.$tools.GetDateStr(-180)
}
this.getList(this.startTime, this.endDate)
},
handleClick(ind) {
if (!uni.getStorageSync('token')) {
this.$store.commit("changeUserLogin", true);
return
}
if (ind == 0) {
this.$store.commit("changeTarget", true);
return
}
if (ind == 1) {
this.$store.commit("changeFirst", true);
return
}
if (ind == 2) {
this.$store.commit("changeRecord", true);
return
}
},
},
data() {
return {
lineData: null,
type: null,
active1: 0,
weight: "",
startTime: "",
endTime: "",
active: 0,
token: null,
handTrue: true,
weightList: [{
title: '体重',
key: 'weight',
showCon: false,
Line: {
"categories": [],
"series": [{
"color": "#fb7b92",
"name": "体重",
"data": []
}]
},
},
{
title: 'BMI',
key: 'bmi',
Line: {
"categories": [],
"series": [{
"color": "#6bb0fe",
"name": "bmi",
"data": []
}]
},
}, {
title: '肌肉',
key: 'muscle',
showCon: false,
Line: {
"categories": [],
"series": [{
"color": "#ff9f40",
"name": "肌肉率",
"data": []
}]
},
},
{
title: '脂肪',
key: 'fat_r',
showCon: false,
Line: {
"categories": [],
"series": [{
"color": "#3fcba7",
"name": "脂肪率",
"data": []
}]
},
}
],
};
}
}
</script>
<style lang="scss" scoped>
.TrendTime {
background: #fff;
padding: 10px;
margin-bottom: 15px;
border-radius: 10px;
}
.listC {
margin: 10px;
}
.boxList {
background-color: #fff;
border-radius: 10px;
.list {
margin: 10px;
}
}
</style>

68
project.config.json Normal file
View File

@ -0,0 +1,68 @@
{
"description": "项目配置文件",
"packOptions": {
"ignore": []
},
"setting": {
"bundle": false,
"userConfirmedBundleSwitch": false,
"urlCheck": true,
"scopeDataCheck": false,
"coverView": true,
"es6": true,
"postcss": true,
"compileHotReLoad": false,
"lazyloadPlaceholderEnable": false,
"preloadBackgroundData": false,
"minified": true,
"autoAudits": false,
"newFeature": false,
"uglifyFileName": false,
"uploadWithSourceMap": true,
"useIsolateContext": true,
"nodeModules": false,
"enhance": true,
"useMultiFrameRuntime": true,
"useApiHook": true,
"useApiHostProcess": true,
"showShadowRootInWxmlPanel": true,
"packNpmManually": false,
"enableEngineNative": false,
"packNpmRelationList": [],
"minifyWXSS": true,
"showES6CompileOption": false
},
"compileType": "miniprogram",
"libVersion": "2.20.2",
"appid": "wx920fdb58338cc50a",
"projectname": "miniprogram-2",
"debugOptions": {
"hidedInDevtools": []
},
"scripts": {},
"staticServerOptions": {
"baseURL": "",
"servePath": ""
},
"isGameTourist": false,
"condition": {
"search": {
"list": []
},
"conversation": {
"list": []
},
"game": {
"list": []
},
"plugin": {
"list": []
},
"gamePlugin": {
"list": []
},
"miniprogram": {
"list": []
}
}
}

BIN
static/2253.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
static/bg0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
static/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
static/switch-ON.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
static/switch-off.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
static/tab_db.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
static/tab_db01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
static/tab_me.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
static/tab_me01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
static/tab_sj.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
static/tab_sj01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
static/tab_sy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

BIN
static/tab_sy01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
static/tool1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

BIN
static/tool2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

BIN
static/tool3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
static/tool4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

83
store/actions.js Normal file
View File

@ -0,0 +1,83 @@
import model from "../tools/model.js"
import tools from '@/tools/tools.js'
// Action 包含异步操作请求API方法、回调函数提交mutaions更改state数据状态使之可以异步
export default {
// 用户信息
getUserInfo({
commit
},
account) {
return model.getUserInfo(account).then(res => {
commit('changeUser', res.data)
if (!res.data.height || !res.data.mage || !res.data.birthday) {
uni.redirectTo({
url: `/pageTwo/login/userinfo`
})
return
}
});
},
// 获取称重结果
getResult({
commit
}, account) {
return model.getResult(account).then((res) => {
console.log("报告", res)
if (res.code == 0) {
commit('changeMeasureResult', res.data)
} else {
commit('changeMeasureResult', null)
}
return res.data
})
},
// 获取历史记录
gethistoryList({
commit
}, account) {
return model.getHistoryList(account).then((res) => {
if (res.data && res.data.items) {
commit('changehistoryList', res.data.items)
} else {
commit('changehistoryList', null)
}
return res
})
},
//趋势
GetBodyTrendList({
commit
}, account) {
return model.GetBodyTrendList(account).then((res) => {
if (res) {
commit('changeTrend', res.cidata)
}
return res
})
},
// 更新家庭成员
getFamilyList({
commit
}) {
return model.getFamilyList({
pagenum: 20,
pagesize: 1
}).then((res) => {
commit('changeFamilay', res)
return res
})
},
// 获取历史记录
gethistoryList({
commit
}, account) {
return model.getHistoryList(account).then((res) => {
if (res.data && res.data.rows) {
commit('changehistoryList', res.data.rows)
} else {
commit('changehistoryList', null)
}
return res
})
},
}

132
store/index.js Normal file
View File

@ -0,0 +1,132 @@
import Vue from 'vue'
import Vuex from 'vuex'
import actions from './actions.js'
Vue.use(Vuex)
export default new Vuex.Store({
// state: 存储基本数据
state: {
user: {
headimg: null,
name: "",
nickname: "",
targetweight: 0, //目标体重
firstweight: 0, //初始体重
weight: 0,
birthday: "",
height: 0,
age: "0",
sex: 0,
familyid: 0,
mage: "",
firstresulttime: ""
},
MeasureResult: {},
isedit: false,
isDrawe: false,
isConnected: false,
isBluetoothTyle: false,
familayList: [],
historyList: [],
Banner: [],
Trend: {},
TrendPk: {},
isTarget: false,
isFirst: false,
isRecord: false,
isLogin: false,
isLogout: true,
},
// mutations: Store中更改state数据状态的唯一方法(必须是同步函数)
mutations: {
/* 用户信息 */
changeUser(state, newData) {
if (newData.familyid) {
uni.setStorageSync('familyid', newData.familyid);
}
Object.assign(state.user, newData)
},
//登录弹框
changeUserLogin(state, newData) {
state.isLogin = newData
},
//历史记录
changehistoryList(state, newData) {
state.historyList = newData
},
// 获取称重数据
changeMeasureResult(state, newData) {
state.MeasureResult = newData
},
// 信息弹框
changeEdit(state, newData) {
state.isedit = newData
},
// 目标体重
changeTarget(state, newData) {
state.isTarget = newData
},
// 初始体重
changeFirst(state, newData) {
state.isFirst = newData
},
// 手动记录
changeRecord(state, newData) {
state.isRecord = newData
},
// 左侧菜单弹框
changeDrawe(state, newData) {
state.isDrawe = newData
},
//获取家庭成员
changeFamilay(state, newData) {
state.familayList = newData
},
//蓝牙状态
changeBluetooth(state, newData) {
state.isBluetoothTyle = newData
},
// 蓝牙连接状态
changeConnected(state, newData) {
state.isConnected = newData
},
//趋势
changeTrend(state, newData) {
state.Trend = newData
},
//对比
changeTrendPk(state, newData) {
state.TrendPk = newData
},
// banner
changeBanner(state, newData) {
state.Banner = newData
},
// 退出登录
changeLogout(state, newData) {
if (newData == false) {
state.user = {
headimg: null,
nickname: "",
name: "",
targetweight: 0, //目标体重
firstweight: 0, //初始体重
weight: 0,
birthday: "",
height: 0,
age: 0,
sex: 0,
familyid: 0,
firstresulttime: ""
}
state.Trend = null
state.historyList = null
state.devTypeList = null
}
state.isLogout = newData
},
},
// 模块化vuex
modules: {},
actions
})

296
tools/data4.js Normal file
View File

@ -0,0 +1,296 @@
let data = [{
title: '体重',
showCon: false,
key: 'weight',
dw: 'kg',
fvalue: null,
svalue: null,
fevaluation: null,
sevaluation: null,
vs: 0,
num: 0,
color: "#ff4239",
desc: "反映和衡量一个人健康状况的重要标志之一",
},
{
title: 'BMI',
color: "#ff4239",
showCon: false,
key: 'bmi',
level: "bmilevel",
dw: '',
slist: [],
fvalue: null,
svalue: null,
fevaluation: null,
sevaluation: null,
vs: 0,
num: 0,
desc: 'BMI是身体质量指数,是目前国际上常用的衡量人体胖瘦程度以及是否健康的一个标准。',
}, {
title: '脂肪率',
showCon: false,
color: "#ff4239",
key: 'fat_r',
level: "fat_rlevel",
dw: '%',
slist: [],
fvalue: null,
svalue: null,
fevaluation: null,
sevaluation: null,
vs: 0,
num: 0,
desc: '体脂率是指身体成分中,脂肪组织所占的比率。测量体脂率比单纯的只测量体重更能反映我们身体的脂肪水平(肥胖程度)。',
},
//
{
title: '脂肪量',
key: 'fat_w',
color: "#ff4239",
scope: '',
showCon: false,
level: "fat_wlevel",
dw: 'kg',
leftval: 0,
desc: '人体脂肪的重量',
fvalue: null,
svalue: null,
fevaluation: null,
sevaluation: null,
vs: 0,
num: 0,
},
{
title: '肌肉率',
key: 'muscle',
showCon: false,
color: "#ff4239",
level: "musclelevel",
dw: '%',
slist: [],
leftval: 0,
fvalue: null,
svalue: null,
fevaluation: null,
sevaluation: null,
vs: 0,
num: 0,
desc: '根据人体肌肉总量和人体体重、身高等相结合得到的人体的一个比例值,这个值的范围决定一个人的身体健康状况以及力量的多少。',
},
{
title: '肌肉量',
color: "#ff4239",
key: 'muscleval',
level: "musclelevel",
showCon: false,
dw: 'kg',
slist: [],
fvalue: null,
svalue: null,
fevaluation: null,
sevaluation: null,
vs: 0,
num: 0,
desc: '肌肉量=实际体重*肌肉率',
},
{
title: '水分',
key: 'water',
color: "#ff4239",
level: "waterlevel",
showCon: false,
dw: '%',
desc: '指人体内水分比例。',
slist: [],
fvalue: null,
svalue: null,
fevaluation: null,
sevaluation: null,
vs: 0,
num: 0,
},
{
title: '蛋白量',
color: "#ff4239",
level: "proteinlevel",
key: 'proteinval',
showCon: false,
dw: 'kg',
desc: '蛋白量=实际体重*蛋白率',
slist: [],
fvalue: null,
svalue: null,
fevaluation: null,
sevaluation: null,
vs: 0,
num: 0,
},
{
title: '骨重',
color: "#ff4239",
key: 'bone',
showCon: false,
level: "bonelevel",
dw: '',
slist: [],
fvalue: null,
svalue: null,
fevaluation: null,
sevaluation: null,
vs: 0,
num: 0,
desc: '单位体积内,骨组织、骨矿物质(钙、磷等)和骨基质(骨胶原、蛋白率、无机盐等等)]含量,骨量代表它们骨骼健康的情况。',
},
{
title: '蛋白率',
color: "#ff4239",
key: 'protein',
level: "proteinlevel",
showCon: false,
dw: '%',
desc: '人体内蛋白率含量。',
slist: [],
fvalue: null,
svalue: null,
fevaluation: null,
sevaluation: null,
vs: 0,
num: 0,
},
{
title: '基础代谢',
key: 'kcal',
color: "#ff4239",
level: "kcallevel",
showCon: false,
dw: 'kcal',
slist: [],
fvalue: null,
svalue: null,
fevaluation: null,
sevaluation: null,
vs: 0,
num: 0,
desc: '指人体在清醒而又极端安静的状态下,不受肌肉活动、环境温度、食物及精神紧张等影响时的能量代谢率',
},
//
{
title: '内脏指数',
color: "#ff4239",
key: 'visceral',
showCon: false,
level: "viscerallevel",
dw: '',
desc: '内脏脂肪指数',
slist: [],
fvalue: null,
svalue: null,
fevaluation: null,
sevaluation: null,
vs: 0,
num: 0,
},
{
title: '皮下脂肪',
key: 'sfr',
color: "#ff4239",
showCon: false,
level: "sfrlevel",
dw: '%',
desc: '皮下脂脂肪就是贮存于皮下的脂肪组织人体的脂肪大约有2/3贮存在皮下组织',
slist: [],
fvalue: null,
svalue: null,
fevaluation: null,
sevaluation: null,
vs: 0,
num: 0,
},
{
title: '肥胖等级',
key: 'fatlevel',
level: "fatlevel",
showCon: false,
leftval: 0,
fvalue: null,
svalue: null,
fevaluation: null,
sevaluation: null,
vs: 0,
num: 0,
desc: '肥胖的程度,表现实际体重与理想体重的差距。肥胖等级是判定肥胖症的一个指标。',
},
//
{
title: '去脂体重',
key: 'lbm',
showCon: false,
dw: 'kg',
fvalue: null,
svalue: null,
fevaluation: null,
sevaluation: null,
vs: 0,
num: 0,
},
{
title: '体龄',
key: 'bodyage',
showCon: false,
dw: '岁',
fvalue: null,
svalue: null,
fevaluation: null,
sevaluation: null,
vs: 0,
num: 0,
},
{
title: '体型',
key: 'body',
level: "bodylevel",
showCon: false,
fvalue: null,
svalue: null,
fevaluation: null,
sevaluation: null,
vs: 0,
num: 0,
},
]
function infoList(str) {
let listStr = [...data];
let leftval = 0
if (!str) return
for (var i = 0; i < listStr.length; i++) {
listStr[i].fvalue = str[listStr[i].key];
listStr[i].fevaluation = str[listStr[i].level];
if (str.list && str.list.length) {
for (var k = 0; k < str.list.length; k++) {
if (listStr[i].key == str.list[k].name) {
listStr[i].slist = str.list[k].list
listStr[i].color = str.list[k].color
listStr[i].fvalue = str.list[k].value
listStr[i].fevaluation = str.list[k].level
}
}
for (let j in listStr[i].slist) {
if (listStr[i].fevaluation == listStr[i].slist[j].text) {
listStr[i].leftval = (listStr[i].fvalue - listStr[i].slist[j].minvalue) / (listStr[i].slist[j]
.maxvalue - listStr[i].slist[j].minvalue) * 4.2
}
}
} else {
listStr[i].slist = null
}
}
return listStr
}
export default {
data,
infoList,
}

66
tools/https.js Normal file
View File

@ -0,0 +1,66 @@
import tools from '@/tools/tools.js'
import store from '../store'
// 获取appid
const accountInfo = wx.getAccountInfoSync();
const appid = accountInfo.miniProgram.appId
uni.setStorageSync('appid', accountInfo.miniProgram.appId)
const baseUrl = 'https://ttybapi.pcxbc.com';
// const baseUrl = 'https://ybapi.pcxbc.com';
const httpRequest = (url, method = "get", data) => {
let httpDefaultOpts = {
url: baseUrl + url,
data: data,
method: method,
header: {
'Authorization': "Bearer " + uni.getStorageSync('token'),
'X-Authorization': "Bearer " + uni.getStorageSync('refreshtoken'),
'X-Requested-With': 'XMLHttpRequest',
'content-type': 'application/json;charset=UTF-8',
},
}
let promise = new Promise(function(resolve, reject) {
if (httpDefaultOpts.url.indexOf("/api/device/detail") == -1) {
uni.showLoading({
title: '加载中...'
})
}
uni.request(httpDefaultOpts).then(
(res) => {
uni.hideLoading()
if (res[1].data.code == 401) {
uni.clearStorageSync()
uni.setStorageSync('token', "")
store.commit("changeLogout", false);
return
}
if (res[1].statusCode != 200) {
tools.msg(res[1].data.message)
return
}
resolve(res[1].data)
}
).catch(
(response) => {
uni.hideLoading()
reject(response)
}
)
})
return promise
};
const get = (url, data) => {
data.appid = appid
return httpRequest(url, 'get', data)
}
const post = (url, data) => {
data.appid = appid
return httpRequest(url, 'post', data)
}
export default {
baseUrl,
get,
post
}

330
tools/model.js Normal file
View File

@ -0,0 +1,330 @@
import http from './https.js'
export default {
onlogin(param) { // 登录
return http.post("/api/wxopen/onlogin", param).then(res => {
return res
})
},
getSendCode(param) { // 验证码
return http.get("/api/wxopen/sendcode", param).then(res => {
return res
})
},
getRegister(param) { // 手机号进行注册
return http.post("/api/wxopen/deregister", param).then(res => {
return res
})
},
getregister(param) { // 微信授权登录
return http.post('/api/wxopen/register', param).then(res => {
return res
})
},
getWxOpenPhone(param) { // 解密手机号
return http.post('/api/wxopen/deuserphone', param).then(res => {
return res
})
},
getDecryptdata(param) { // 解密用户资料
return http.post("/api/wxopen/deuserinfo", param).then(res => {
return res
})
},
getoutlogin(param) { // 退出登录
return http.get("/api/wxopen/outlogin", param).then(res => {
return res
})
},
submitadvice(param) { // 意见反馈
return http.post("/api/wxopen/submitadvice", param).then(res => {
return res
})
},
//
getUserInfo(param) { //获取用户信息
return http.post("/api/adult/info", param).then(res => {
if (res.code == 0) {
res.data.name = res.data.nickname
// res.data.firstresulttime = res.data.firstresulttime.substring(0, 10)
}
return res
})
},
getResult(param) { //获取成人测量信息
return http.post("/api/adult/measureinfo", param).then(res => {
return res
})
},
getfirstweight(param) { //修改初始体重
return http.post("/api/adult/submitfirstweight", param).then(res => {
return res
})
},
setTarget(param) { //设置目标体重
return http.post("/api/family/settarget", param).then(res => {
return res
})
},
getbodylist(param) { //测评列表
return http.post("/api/adult/getbodylist", param).then(res => {
if (res.code == 0) {
let box = res.data
let k = 1
for (var n = 0; n < box.length; n++) {
for (var i = 0; i < box[n].qalist.length; i++) {
let info = box[n].qalist[i]
box[n].qalist[i] = {
Id: info.id,
title: info.title,
data: [{
id: info.id,
val: k++,
value: info.nonevalue,
valId: box[n].id,
name: '没有',
},
{
id: info.id,
val: k++,
value: info.littlevalue,
valId: box[n].id,
name: '很少',
},
{
id: info.id,
val: k++,
value: info.somevalue,
valId: box[n].id,
name: '有时',
},
{
id: info.id,
val: k++,
value: info.oftenvalue,
valId: box[n].id,
name: '经常',
},
{
id: info.id,
val: k++,
value: info.alwaysvalue,
valId: box[n].id,
name: '总是',
}
]
}
}
}
res.data = box
}
return res
})
},
getbodyinfo(param) { //体质测评结果
return http.post("/api/adult/getbodyinfo", param).then(res => {
return res
})
},
getbodyresultinfo(param) { //体质测评计算
return http.post("/api/adult/getbodyresultinfo", param).then(res => {
return res
})
},
//
getFamilyList(param) { // 获取家庭成员列表
return http.post('/api/family/getlist', param).then(res => {
if (res.data) {
for (let i = 0; i < res.data.length; i++) {
res.data[i].familyid = res.data[i].id
res.data[i].type = res.data[i].type == 1 ? "成人" : res.data[i].type == 2 ? "儿童" : "婴儿"
}
}
return res.data
})
},
getsubmit(param) { //家庭成员信息修改
return http.post('/api/family/submit', param).then(res => {
return res
})
},
getdelete(param) { //删除家庭成员
return http.get('/api/family/delete', param).then(res => {
return res
})
},
getdetail(param) { //家庭成员详情
return http.get('/api/family/detail', param).then(res => {
return res
})
},
getHistoryList(param) { //获取指定家庭成员历史记录
return http.post('/api/family/gethistorylist', param).then(res => {
return res
})
},
getaddlist(param) { //手动添加记录列表
return http.post('/api/family/getaddlist', param).then(res => {
return res
})
},
//
getinsertmeasure(param) { //手动记录
return http.post('/api/result/insertmeasure', param).then(res => {
return res
})
},
getmeasure(param) { //新增蓝牙测量记录
return http.post('/api/result/measure', param).then(res => {
return res
})
},
getmeasuredata(param) { //新增蓝牙测量记录,适用于f01pro
return http.post('/api/result/measuredata', param).then(res => {
return res
})
},
getmeasurefunit(param) { //新增蓝牙测量记录,身高带单位
return http.post('/api/result/measureofunit', param).then(res => {
return res
})
},
gethistorydelete(param) { //删除历史记录
return http.post("/api/result/delete", param).then(res => {
return res
})
},
getTrendList(param) { //趋势
return http.post("/api/result/trendlist", param).then(res => {
if (res.code == 0) {
let list = res.data
let cidata = {
weight: {
categories: [],
series: [{
color: "#ff9f40",
name: "体重",
data: [],
}]
},
bmi: {
categories: [],
series: [{
name: "bmi",
color: "#5ba7ff",
data: [],
}]
},
muscle: {
categories: [],
series: [{
color: "#ff7f91",
name: "肌肉",
data: [],
}]
},
fat_r: {
categories: [],
series: [{
color: "#3fcba7",
name: "脂肪",
data: [],
}]
}
}
for (var i = 0; i < list.length; i++) {
cidata.weight.categories.push(list[i].time);
cidata.bmi.categories.push(list[i].time);
cidata.muscle.categories.push(list[i].time);
cidata.fat_r.categories.push(list[i].time);
cidata.weight.series.forEach(item => {
item.data.push(list[i].weight)
})
cidata.bmi.series.forEach(item => {
item.data.push(list[i].bmi)
})
cidata.muscle.series.forEach(item => {
item.data.push(list[i].muscle)
})
cidata.fat_r.series.forEach(item => {
item.data.push(list[i].fat_r)
})
}
res.data = cidata
}
return res.data
})
},
//对比列表
GetTrendList(param) {
return http.post("/api/result/trendlist", param).then(res => {
if (res.code == 0) {
let pkList = {
list: [],
Dlist: []
}
for (var i = 0; i < res.data.length; i++) {
pkList.list.push(res.data[i])
if (!pkList.Dlist.includes(res.data[i].createtime)) { //includes 检测数组是否有某个值
pkList.Dlist.push(res.data[i].createtime);
}
}
res.data.pkList = pkList
}
return res.data
})
},
getresultdiff(param) { //记录对比
return http.post("/api/result/resultdiff", param).then(res => {
return res
})
},
//
getdevactive(param) { //设备激活
return http.post('/api/device/active', param).then(res => {
return res
})
},
getdevstatus(param) { //检查设备状态
return http.get('/api/device/checkdevstatus', param).then(res => {
return res
})
},
getdevdetail(param) { //设备详情
return http.post('/api/device/detail', param).then(res => {
return res
})
},
//
GetTplList(param) { //获取消息模板列表
return http.get('/api/message/gettplList', param).then(res => {
return res
})
},
GetSubscribe(param) { //消息订阅
return http.post('/api/message/subscribe', param).then(res => {
return res
})
},
GetSubscribeInfo(param) { //获取订阅状态
return http.get('/api/message/getsubscribeinfo', param).then(res => {
return res
})
},
Getunsubscribe(param) { //取消订阅
return http.post('/api/message/unsubscribe', param).then(res => {
return res
})
},
// 协议
GetAdListDetail(param) {
return http.get('/api/zx/infodetail', param).then(res => {
return res
})
},
}

296
tools/tools.js Normal file
View File

@ -0,0 +1,296 @@
import $store from '@/store'
export default {
msg,
str2hex,
hex2str,
ab2hex,
inArray,
getAge,
getTime,
getDate,
getMonth,
GetDateStr,
handlePages,
getBluetoothAdapter
}
function inArray(arr, key, val) {
if (!arr || !arr.length || typeof arr != 'object' || !Array.isArray(arr)) {
return -1
}
for (let i = 0; i < arr.length; i++) {
if (!key) {
if (arr[i] == val) {
return i
}
} else if (arr[i][key] === val) {
return i
}
}
return -1;
}
function msg(str) {
uni.showToast({
title: str,
icon: 'none'
})
}
function ab2hex(buffer, split) {
var hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function(bit) {
return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join(split);
}
function hex2str(arr) {
let decoder = new TextDecoder('utf8')
let uint8 = new Uint8Array(arr)
let res = decoder.decode(uint8)
return res
}
function str2hex(str) {
let encoder = new TextEncoder('utf8')
return encoder.encode(str)
}
function getBluetoothAdapter(err) {
if (err.errMsg == "openBluetoothAdapter:fail auth denied" || err.errMsg ===
"openBluetoothAdapter:fail auth deny" ||
err.errMsg === "openBluetoothAdapter:fail authorize no response"
) {
uni.showModal({
title: "提示",
content: "需要您授权使用手机蓝牙",
showCancel: false,
success(modalSuccess) {
uni.openSetting({
success(settingdata) {
if (settingdata.authSetting["scope.bluetooth"]) {
uni.openBluetoothAdapter({
success: e => {
uni.showToast({
title: "获取权限成功,请继续去测量",
icon: "none"
})
$store.commit("changeBluetooth", true);
},
fail: err => {
uni.showToast({
title: "请打开手机蓝牙",
icon: "none",
duration: 1000,
})
console.log('初始化蓝牙失败:' + err.errMsg);
}
});
} else {
uni.showToast({
title: "获取权限失败,将无法使用手机蓝牙进行测量",
icon: "none"
})
}
}
})
}
})
} else {
uni.showToast({
title: "请打开手机蓝牙",
icon: "none",
duration: 1000,
})
}
}
function getDate(type) {
const date = new Date();
let year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
month = month > 9 ? month : '0' + month;;
day = day > 9 ? day : '0' + day;
if (type === 'tow') {
year = year - 2;
return `${year}-${month}-${day}`;
}
if (type === 'start') {
year = year;
return `${year}-${month}-${day}`;
}
if (type === 'end') {
year = year + 60;
return `${year}-${month}-${day}`;
}
if (type == "m") {
if (month == "01" || month == "03" || month == "05" || month == "07" || month == "08" || month == "10" ||
month == "12") {
return year + "/" + month + "/01" + "~" + year + "/" + month + "/31";
} else if (month == "02") {
if ((year % 4 == 0 && year % 100 != 0) || (year % 100 == 0 && year % 400 == 0)) {
return year + "/" + month + "/01" + "~" + year + "/" + month + "/29";
} else {
return year + "/" + month + "/01" + "~" + year + "/" + month + "/28";
};
} else {
return year + "/" + month + "/01" + "~" + year + "/" + month + "/30";
};
}
}
function GetDateStr(AddDayCount) {
var dd = new Date();
dd.setDate(dd.getDate() + AddDayCount); //获取AddDayCount天后的日期
var y = dd.getFullYear();
var m = (dd.getMonth() + 1) < 10 ? "0" + (dd.getMonth() + 1) : (dd.getMonth() + 1); //获取当前月份的日期不足10补0
var d = dd.getDate() < 10 ? "0" + dd.getDate() : dd.getDate(); //获取当前几号不足10补0
return y + "-" + m + "-" + d;
}
// 获取当前日期
function getTime() {
var date = new Date()
var todate =
((date.getMonth() + 1) < 10 ? ('0' + (date.getMonth() + 1)) : date.getMonth() +
1) + '月' + (date.getDate() < 10 ? ('0' + date.getDate()) : date.getDate() + '日')
return todate
}
// 根据出生日期获取年龄
function getAge(str) {
var r = str.match(/^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2})/);
if (r == null) return false;
var d = new Date(r[1], r[3] - 1, r[4]);
var returnStr = "输入的日期格式错误!";
if (d.getFullYear() == r[1] && (d.getMonth() + 1) == r[3] && d.getDate() == r[4]) {
var date = new Date();
var yearNow = date.getFullYear();
var monthNow = date.getMonth() + 1;
var dayNow = date.getDate();
var largeMonths = [1, 3, 5, 7, 8, 10, 12], //大月, 用于计算天,只在年月都为零时,天数有效
lastMonth = monthNow - 1 > 0 ? monthNow - 1 : 12, // 上一个月的月份
isLeapYear = false, // 是否是闰年
daysOFMonth = 0; // 当前日期的上一个月多少天
if ((yearNow % 4 === 0 && yearNow % 100 !== 0) || yearNow % 400 === 0) { // 是否闰年, 用于计算天,只在年月都为零时,天数有效
isLeapYear = true;
}
if (largeMonths.indexOf(lastMonth) > -1) {
daysOFMonth = 31;
} else if (lastMonth === 2) {
if (isLeapYear) {
daysOFMonth = 29;
} else {
daysOFMonth = 28;
}
} else {
daysOFMonth = 30;
}
var Y = yearNow - parseInt(r[1]);
var M = monthNow - parseInt(r[3]);
var D = dayNow - parseInt(r[4]);
if (D < 0) {
D = D + daysOFMonth; //借一个月
M--;
}
if (M < 0) { // 借一年 12个月
Y--;
M = M + 12; //
}
if (Y < 0) {
returnStr = "出生日期有误!";
} else if (Y === 0) {
if (M === 0) {
returnStr = D + "天";
} else {
returnStr = M + "个月";
}
} else {
if (M === 0) {
returnStr = Y + "岁";
} else {
returnStr = Y + "岁" + M + "个月";
}
}
}
return returnStr;
}
function getMonth(dates, months) {
var d = new Date(dates.substring(0, 10));
let year = d.getFullYear();
var month = d.getMonth() + 1;
if (Math.abs(months) > 12) {
months = months % 12;
};
if (months != 0) {
if (month + months > 12) {
year++;
month = (month + months) % 12;
} else if (month + months < 1) {
year--;
month = 12 + month + months;
} else {
month = month + months;
};
};
month = month < 10 ? "0" + month : month;
var date = d.getDate();
if (month == "01" || month == "03" || month == "05" || month == "07" || month == "08" || month == "10" ||
month == "12") {
return year + "/" + month + "/01" + "~" + year + "/" + month + "/31";
} else if (month == "02") {
if ((year % 4 == 0 && year % 100 != 0) || (year % 100 == 0 && year % 400 == 0)) {
return year + '/' + month + "/01" + "~" + year + "/" + year + "/" + month + "/29";
} else {
return year + '/' + month + "/01" + "~" + year + "/" + month + "/28";
};
} else {
return year + '/' + month + "/01" + "~" + year + "/" + month + "/30";
};
};
// 页面跳转
function handlePages(type, deviceId) {
if (type == 1) {
uni.redirectTo({
url: "/BLEPages/adult/PCD01pro?deviceId=" + deviceId
})
return
}
if (type == 4) {
uni.redirectTo({
url: "/BLEPages/adult/PCL01?deviceId=" + deviceId
})
return
}
if (type == 8) {
uni.redirectTo({
url: "/BLEPages/adult/H01pro?deviceId=" + deviceId
})
return
}
if (type == 14) {
uni.redirectTo({
url: "/BLEPages/adult/F01B?deviceId=" + deviceId
})
return
}
if (type == 21) {
uni.redirectTo({
url: "/BLEPages/adult/H09B?deviceId=" + deviceId
})
return
}
}

81
uni.scss Normal file
View File

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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,578 @@
/*
* uCharts®
* 高性能跨平台图表库支持H5APP小程序微信/支付宝/百度/头条/QQ/360VueTaro等支持canvas的框架平台
* Copyright (c) 2021 QIUN®秋云 https://www.ucharts.cn All rights reserved.
* Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
* 复制使用请保留本段注释感谢支持开源
*
* uCharts®官方网站
* https://www.uCharts.cn
*
* 开源地址:
* https://gitee.com/uCharts/uCharts
*
* uni-app插件市场地址
* http://ext.dcloud.net.cn/plugin?id=271
*
*/
// 主题颜色配置如每个图表类型需要不同主题请在对应图表类型上更改color属性
const color = ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'];
//事件转换函数主要用作格式化x轴为时间轴根据需求自行修改
const formatDateTime = (timeStamp, returnType) => {
var date = new Date();
date.setTime(timeStamp * 1000);
var y = date.getFullYear();
var m = date.getMonth() + 1;
m = m < 10 ? ('0' + m) : m;
var d = date.getDate();
d = d < 10 ? ('0' + d) : d;
var h = date.getHours();
h = h < 10 ? ('0' + h) : h;
var minute = date.getMinutes();
var second = date.getSeconds();
minute = minute < 10 ? ('0' + minute) : minute;
second = second < 10 ? ('0' + second) : second;
if (returnType == 'full') {
return y + '-' + m + '-' + d + ' ' + h + ':' + minute + ':' + second;
}
if (returnType == 'y-m-d') {
return y + '-' + m + '-' + d;
}
if (returnType == 'h:m') {
return h + ':' + minute;
}
if (returnType == 'h:m:s') {
return h + ':' + minute + ':' + second;
}
return [y, m, d, h, minute, second];
}
module.exports = {
//demotype为自定义图表类型一般不需要自定义图表类型只需要改根节点上对应的类型即可
"type": ["pie", "ring", "rose", "word", "funnel", "map", "arcbar", "line", "column", "area", "radar", "gauge",
"candle", "mix", "tline", "tarea", "scatter", "bubble", "demotype"
],
"range": ["饼状图", "圆环图", "玫瑰图", "词云图", "漏斗图", "地图", "圆弧进度条", "折线图", "柱状图", "区域图", "雷达图", "仪表盘", "K线图", "混合图",
"时间轴折线", "时间轴区域", "散点图", "气泡图", "自定义类型"
],
//增加自定义图表类型如果需要categories请在这里加入您的图表类型例如最后的"demotype"
//自定义类型时需要注意"tline","tarea","scatter","bubble"等时间轴矢量x轴类图表没有categories不需要加入categories
"categories": ["line", "column", "area", "radar", "gauge", "candle", "mix", "demotype"],
//instance为实例变量承载属性不要删除
"instance": {},
//option为opts及eopts承载属性不要删除
"option": {},
//下面是自定义format配置因除H5端外的其他端无法通过props传递函数只能通过此属性对应下标的方式来替换
"formatter": {
"yAxisDemo1": function(val) {
return val + '元'
},
"yAxisDemo2": function(val) {
return val.toFixed(2)
},
"xAxisDemo1": function(val) {
return val + '年'
},
"xAxisDemo2": function(val) {
return formatDateTime(val, 'h:m')
},
"seriesDemo1": function(val) {
return val + '元'
},
"tooltipDemo1": function(item, category, index, opts) {
if (index == 0) {
return '随便用' + item.data + '年'
} else {
return '其他我没改' + item.data + '天'
}
},
"pieDemo": function(val, index, series) {
if (index !== undefined) {
return series[index].name + '' + series[index].data + '元'
}
},
},
//这里演示了自定义您的图表类型的option可以随意命名之后在组件上 type="demotype" 后组件会调用这个花括号里的option如果组件上还存在opts参数会将demotype与opts中option合并后渲染图表。
"demotype": {
//我这里把曲线图当做了自定义图表类型,您可以根据需要随意指定类型或配置
"type": "line",
"color": color,
"padding": [15, 10, 0, 15],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"gridType": "dash",
"dashLength": 2,
},
"legend": {},
"extra": {
"line": {
"type": "curve",
"width": 2
},
}
},
//下面是自定义配置,请添加项目所需的通用配置
"pie": {
"type": "pie",
"color": color,
"padding": [5, 5, 5, 5],
"extra": {
"pie": {
"activeOpacity": 0.5,
"activeRadius": 10,
"offsetAngle": 0,
"labelWidth": 15,
"border": true,
"borderWidth": 3,
"borderColor": "#FFFFFF"
},
}
},
"ring": {
"type": "ring",
"color": color,
"padding": [5, 5, 5, 5],
"rotate": false,
"dataLabel": true,
"legend": {
"show": true,
"position": "right",
"lineHeight": 25,
},
"title": {
"name": "收益率",
"fontSize": 15,
"color": "#666666"
},
"subtitle": {
"name": "70%",
"fontSize": 25,
"color": "#7cb5ec"
},
"extra": {
"ring": {
"ringWidth": 30,
"activeOpacity": 0.5,
"activeRadius": 10,
"offsetAngle": 0,
"labelWidth": 15,
"border": true,
"borderWidth": 3,
"borderColor": "#FFFFFF"
},
},
},
"rose": {
"type": "rose",
"color": color,
"padding": [5, 5, 5, 5],
"legend": {
"show": true,
"position": "left",
"lineHeight": 25,
},
"extra": {
"rose": {
"type": "area",
"minRadius": 50,
"activeOpacity": 0.5,
"activeRadius": 10,
"offsetAngle": 0,
"labelWidth": 15,
"border": false,
"borderWidth": 2,
"borderColor": "#FFFFFF"
},
}
},
"word": {
"type": "word",
"color": color,
"extra": {
"word": {
"type": "normal",
"autoColors": false
}
}
},
"funnel": {
"type": "funnel",
"color": color,
"padding": [15, 15, 0, 15],
"extra": {
"funnel": {
"activeOpacity": 0.3,
"activeWidth": 10,
"border": true,
"borderWidth": 2,
"borderColor": "#FFFFFF",
"fillOpacity": 1,
"labelAlign": "right"
},
}
},
"map": {
"type": "map",
"color": color,
"padding": [0, 0, 0, 0],
"dataLabel": true,
"extra": {
"map": {
"border": true,
"borderWidth": 1,
"borderColor": "#666666",
"fillOpacity": 0.6,
"activeBorderColor": "#F04864",
"activeFillColor": "#FACC14",
"activeFillOpacity": 1
},
}
},
"arcbar": {
"type": "arcbar",
"color": color,
"title": {
"name": "百分比",
"fontSize": 25,
"color": "#00FF00"
},
"subtitle": {
"name": "默认标题",
"fontSize": 15,
"color": "#666666"
},
"extra": {
"arcbar": {
"type": "default",
"width": 12,
"backgroundColor": "#E9E9E9",
"startAngle": 0.75,
"endAngle": 0.25,
"gap": 2
}
}
},
"line": {
"type": "line",
"color": color,
"padding": [15, 10, 0, 15],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"gridType": "dash",
"dashLength": 2,
},
"legend": {},
"extra": {
"line": {
"type": "straight",
"width": 2
},
}
},
"tline": {
"type": "line",
"color": color,
"padding": [15, 10, 0, 15],
"xAxis": {
"disableGrid": false,
"boundaryGap": "justify",
},
"yAxis": {
"gridType": "dash",
"dashLength": 2,
"data": [{
"min": 0,
"max": 80
}]
},
"legend": {},
"extra": {
"line": {
"type": "curve",
"width": 2
},
}
},
"tarea": {
"type": "area",
"color": color,
"padding": [0, 15, 15, 5],
"xAxis": {
"disableGrid": true,
"boundaryGap": "justify",
},
"yAxis": {
"gridType": "dash",
"dashLength": 2,
"data": [{
"min": 0,
"max": 80
}]
},
"legend": {},
"extra": {
"area": {
"type": "curve",
"opacity": 0.2,
"addLine": true,
"width": 2,
"gradient": true
},
}
},
"column": {
"type": "column",
"color": color,
"padding": [15, 15, 0, 5],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"gridType": "dash",
"disableGrid": true,
"gridColor": '#ffffff',
"data": [{
"tofix": 1,
"min": 0
}],
},
"legend": {},
"extra": {
"column": {
"type": "group",
"width": 20,
"seriesGap": 5,
"meterFillColor": "#FFFFFF",
"activeBgColor": "#000000",
"activeBgOpacity": 0.5,
"barBorderCircle": true,
"linearType": "opacity",
// "customColor": "#ff9f40",
"linearOpacity": 1,
},
}
},
"area": {
"type": "area",
"color": color,
"padding": [20, 15, 5, 10],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"gridType": "dash",
"disableGrid": true,
"gridColor": '#ffffff',
"data": [{
"tofix": 1,
"min": 0
}],
},
"legend": {
"show": false,
},
"extra": {
"area": {
"type": "curve",
"opacity": 0.2,
"addLine": true,
"width": 1,
"gradient": true
},
}
},
"radar": {
"type": "radar",
"color": color,
"padding": [5, 5, 5, 5],
"legend": {
"show": true,
"position": "right",
"lineHeight": 25,
},
"extra": {
"radar": {
"gridType": "radar",
"gridColor": "#CCCCCC",
"gridCount": 3,
"opacity": 0.2,
"max": 200
},
}
},
"gauge": {
"type": "gauge",
"color": color,
"title": {
"name": "66Km/H",
"fontSize": 25,
"color": "#2fc25b",
"offsetY": 50
},
"subtitle": {
"name": "实时速度",
"fontSize": 15,
"color": "#1890ff",
"offsetY": -50
},
"extra": {
"gauge": {
"type": "default",
"width": 30,
"labelColor": "#666666",
"startAngle": 0.75,
"endAngle": 0.25,
"startNumber": 0,
"endNumber": 100,
"labelFormat": "",
"splitLine": {
"fixRadius": 0,
"splitNumber": 10,
"width": 30,
"color": "#FFFFFF",
"childNumber": 5,
"childWidth": 12
},
"pointer": {
"width": 24,
"color": "auto"
}
}
}
},
"candle": {
"type": "candle",
"color": color,
"padding": [15, 15, 0, 15],
"enableScroll": true,
"enableMarkLine": true,
"dataLabel": false,
"xAxis": {
"labelCount": 4,
"itemCount": 40,
"disableGrid": true,
"gridColor": "#CCCCCC",
"gridType": "solid",
"dashLength": 4,
"scrollShow": true,
"scrollAlign": "left",
"scrollColor": "#A6A6A6",
"scrollBackgroundColor": "#EFEBEF"
},
"yAxis": {},
"legend": {},
"extra": {
"candle": {
"color": {
"upLine": "#f04864",
"upFill": "#f04864",
"downLine": "#2fc25b",
"downFill": "#2fc25b"
},
"average": {
"show": true,
"name": ["MA5", "MA10", "MA30"],
"day": [5, 10, 20],
"color": ["#1890ff", "#2fc25b", "#facc14"]
}
},
"markLine": {
"type": "dash",
"dashLength": 5,
"data": [{
"value": 2150,
"lineColor": "#f04864",
"showLabel": true
},
{
"value": 2350,
"lineColor": "#f04864",
"showLabel": true
}
]
}
}
},
"mix": {
"type": "mix",
"color": color,
"padding": [15, 15, 0, 15],
"xAxis": {
"disableGrid": true,
},
"yAxis": {
"disabled": false,
"disableGrid": false,
"splitNumber": 5,
"gridType": "dash",
"dashLength": 4,
"gridColor": "#CCCCCC",
"padding": 10,
"showTitle": true,
"data": []
},
"legend": {},
"extra": {
"mix": {
"column": {
"width": 20
}
},
}
},
"scatter": {
"type": "scatter",
"color": color,
"padding": [15, 15, 0, 15],
"dataLabel": false,
"xAxis": {
"disableGrid": false,
"gridType": "dash",
"splitNumber": 5,
"boundaryGap": "justify",
"min": 0
},
"yAxis": {
"disableGrid": false,
"gridType": "dash",
},
"legend": {},
"extra": {
"scatter": {},
}
},
"bubble": {
"type": "bubble",
"color": color,
"padding": [15, 15, 0, 15],
"xAxis": {
"disableGrid": false,
"gridType": "dash",
"splitNumber": 5,
"boundaryGap": "justify",
"min": 0,
"max": 250
},
"yAxis": {
"disableGrid": false,
"gridType": "dash",
"data": [{
"min": 0,
"max": 150
}]
},
"legend": {},
"extra": {
"bubble": {
"border": 2,
"opacity": 0.5,
},
}
}
}

File diff suppressed because it is too large Load Diff

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