已对接广播秤

This commit is contained in:
qiaocl 2023-09-08 15:17:21 +08:00
commit 7d076ec1ac
271 changed files with 61679 additions and 0 deletions

16
.hbuilderx/launch.json Normal file
View File

@ -0,0 +1,16 @@
{ // launch.json configurations app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
// launchtypelocalremote, localremote
"version": "0.0",
"configurations": [{
"default" :
{
"launchtype" : "local"
},
"mp-weixin" :
{
"launchtype" : "local"
},
"type" : "uniCloud"
}
]
}

25
App.vue Normal file
View File

@ -0,0 +1,25 @@
<script>
export default {
onLaunch: function() {
console.log('App Launch')
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style>
/*每个页面公共css */
.content {
display: flex;
flex-direction: column;
align-items: center;
/* justify-content: center; */
background-color: #efefef;
min-height: 100vh;
}
</style>

621
assets/common.scss Normal file
View File

@ -0,0 +1,621 @@
page {
font-family: "Microsoft YaHei";
font-size: 14px;
color: #333;
background-color: #f7f7f7;
}
.mt-5 {
margin-top: 5px !important;
}
.mt-10 {
margin-top: 10px !important;
}
.mt-15 {
margin-top: 15px !important;
}
.mt-20 {
margin-top: 20px !important;
}
.bold {
font-weight: bold;
}
.overflow {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.btn{
width: auto;
border-radius: 10px;
background-color: #f0ae43;
text-align: center;
height: 40px;
line-height: 40px;
margin: 15px;
}
// .列表样式
.footlist {
margin: 15px 0;
width: 100%;
height: auto;
overflow: hidden;
column-gap: 20rpx;
column-count:2;
// display: flex;
// flex-wrap: wrap;
// justify-content: space-between;
.list {
margin-bottom: 10px;
// height: auto;
overflow: auto;
break-inside: avoid;
border-radius: 15rpx;
overflow: hidden;
-webkit-column-break-inside: avoid;
.item {
color: #666;
width: calc(100% - 10px);
position: initial;
background: #fff;
border-radius: 0 0 5px 5px;
font-size: 14px;
height: auto;
overflow: hidden;
}
.topimg{
width: auto;
height: auto;
overflow: hidden;
position: relative;
height: 370rpx;
}
.img {
width: 335rpx;
height: 370rpx;
display: block;
border-radius: 5px 5px 0 0;
}
.zan {
.iconfont {
font-size: 16px;
position: inherit !important;
}
}
}
.list:nth-of-type(2n) {
.topimg {
height: 300rpx;
display: flex;
align-items: center;
justify-content: center;
}
}
}
.footbox {
width: calc(100% - 30px);
margin-top: 40px;
.item {
position: absolute;
bottom: 0px;
color: #fff;
left: 5px;
right: 5px;
background: #403f3f5c;
padding: 5px;
font-size: 15px;
border-radius:0 0 10px 10px;
.title {
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.name {
display: flex;
align-items: center;
font-size: 12px;
float: left;
width: 70%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
height: 30px;
line-height: 30px;
image {
width: 20px;
height: 20px;
margin-right: 5px;
}
}
.zan {
width: 30%;
float: left;
font-size: 12px;
display: flex;
align-items: center;
height: auto;
overflow: auto;
height: 30px;
line-height: 30px;
.iconfont {
display: flex;
align-items: center;
position: absolute;
right: 15px;
bottom: 10px;
text-align: right;
z-index: 99;
}
}
.icon-icon3 {
color: $mainColor;
}
}
}
// 菜谱左侧导航
.menu {
width: calc(100% - 30px);
height: auto;
overflow: hidden;
.left {
position: absolute;
left: 0;
width: 100px;
bottom: 0;
top: 55px;
line-height: 45px;
font-size: 14px;
font-weight: bold;
overflow-y: scroll;
height: calc(100vh - 70px);
.name {
padding-left: 15px;
}
.active {
color: $mainColor;
background-color: #FFF;
border-left: 5px solid $mainColor;
}
}
.right {
position: absolute;
left: 100px;
right: 0;
top: 55px;
bottom: 0;
padding-bottom: 15px;
height: calc(100vh - 70px);
overflow-y: scroll;
background: #fff;
icon {
font-size: 14px;
}
.right_list {
padding: 0 10px;
.title {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
line-height: 45px;
font-weight: bold;
}
.list {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
image {
width: 140rpx;
height: 140rpx;
border-radius: 10px;
}
text {
display: block;
text-align: center;
margin-bottom: 10px;
}
}
}
}
}
// 添加食谱
.addFood {
.title,
.textarea {
width: calc(100% - 20px);
margin-bottom: 10px;
background: #fff;
padding: 0 10px;
border-radius: 10px;
}
.food,
.step {
width: calc(100% - 20px);
margin-bottom: 10px;
background: #fff;
padding: 10px;
border-radius: 10px;
.h4 {
height: 30px;
line-height: 30px;
font-size: 14px;
display: flex;
font-weight: bold;
justify-content: space-between;
text {
font-size: 14px;
border: 1px solid #dfdfdf;
border-radius: 15PX;
padding: 0 20px;
}
}
.foodlist {
column-count: 1;
.item {
display: flex;
justify-content: space-between;
width: calc(100% - 20px);
background: #f7f7f7;
border-radius: 10px;
padding: 8px 10px;
margin-top: 10px;
}
.name {
width: 30%;
border-right: 1px solid #999;
margin-right: 15px;
}
.input {
width: 30%;
display: flex;
align-items: center;
}
}
.edit {
width: 30%;
display: flex;
align-items: center;
justify-content: flex-end;
icon {
display: flex;
margin-right: 5px;
color: $uni-color-warning;
}
image {
width: 18px;
height: 18px;
margin: 0 5px;
}
.shang {
transform: rotate(180deg);
}
}
.add {
width: 100%;
text-align: center;
height: 35px;
line-height: 35px;
background: $mainColor;
margin-top: 15px;
border-radius: 10px;
color: #fff;
}
}
.step {
.top {
display: flex;
justify-content: space-between;
margin: 10px 0;
font-size: 14px;
font-weight: bold;
}
.textarea {
margin-top: 10px;
background-color: #f7f7f7;
}
.add {
color: #000;
background-color: #fff;
border: 1px solid #f0ad4e;
}
}
.groupbtn {
width: 100%;
margin-top: 5px;
display: flex;
justify-content: space-between;
align-items: center;
view {
width: 45%;
background-color: #fff;
border: 1px solid #f0ad4e;
text-align: center;
height: 35px;
line-height: 35px;
border-radius: 10px;
margin-bottom: 15px;
}
.subbtn {
color: #fff;
border-color: $mainColor;
background-color: $mainColor;
}
}
}
// 弹框
.wrapper {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 20;
.bg {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.4);
z-index: 99;
}
.list {
width: 100%;
max-height: 300px;
display: flex;
flex-wrap: wrap;
overflow: scroll;
padding-bottom: 50px;
.item {
width: calc(100% - 20px);
display: flex;
justify-content: space-between;
height: 33px;
align-items: center;
padding-bottom: 5px;
padding: 5px 10px;
border-bottom: 1px solid #dfdfdf;
text {
width: 40%;
}
icon {
color: $mainColor;
font-size: 16px;
}
}
}
.nolist {
padding-top: 50px;
display: flex;
align-items: center;
flex-wrap: wrap;
justify-content: center;
icon {
font-size: 70px;
color: #ccc;
}
text {
display: inline-block;
width: 100%;
text-align: center;
}
}
.box {
background-color: #fff;
position: absolute;
left: 0;
right: 0;
bottom: 0;
padding: 10px;
height: 630rpx;
border-radius: 10px 10px 0 0;
.title {
display: flex;
justify-content: space-between;
.cancel {
width: 80px;
display: flex;
justify-content: flex-end;
}
}
.weight {
width: auto;
display: flex;
font-size: 12px;
background: $uni-color-warning;
border-radius: 10px;
color: #fff;
padding: 3px 8px;
align-items: center;
icon {
margin-right: 5px;
}
}
.name {
width: 100%;
text-align: center;
font-size: 16px;
font-weight: bold;
// margin-top:-15px
}
.val {
text-align: center;
margin: 15px 0;
text {
display: inline-block;
width: 80px;
border-bottom: 1px solid #dfdfdf;
font-size: 22px;
font-weight: bold;
text-align: center;
}
}
}
.mybrankmask {
width: 100%;
height: 390rpx;
background-color: #EBEEF5;
position: fixed;
z-index: 999;
left: 0;
bottom: 0;
.MymaskAll {
width: 74%;
.MymaskList {
display: flex;
width: 100%;
justify-content: space-around;
margin-top: 20rpx;
.maskListItem {
width: 29%;
height: 70rpx;
background-color: #fff;
border-radius: 10rpx;
font-size: 18px;
display: flex;
justify-content: center;
align-items: center;
}
}
.text {
font-size: 14px !important;
}
}
image {
width: 25px;
height: 25px;
}
.MymaskList2 {
width: 22%;
display: flex;
flex-direction: column;
justify-content: space-between;
position: absolute;
right: 10px;
top: 10px;
bottom: 15px;
.maskListItem {
width: 100%;
background: #fff;
height: 70rpx;
border-radius: 5px;
display: flex;
justify-content: center;
align-items: center;
}
.width48 {
color: #fff;
height: 152rpx;
line-height: 152rpx;
background-color: $mainColor;
}
.close {
width: 32px;
height: 20px;
}
}
}
@keyframes mytreat {
/*开始画面*/
0% {
background-color: #000;
}
50% {
background: none;
}
100% {
background-color: #000;
}
}
}

File diff suppressed because one or more lines are too long

294
assets/iconfont.css Normal file
View File

@ -0,0 +1,294 @@
/* 在线链接服务仅供平台体验和调试使用,平台不承诺服务的稳定性,企业客户需下载字体包自行发布使用并做好备份。 */
@font-face {
font-family: 'iconfont';
/* Project id 4140635 */
src: url('https://at.alicdn.com/t/c/font_4140635_4zv7o50l4p3.woff2?t=1687915682269') format('woff2'),
url('https://at.alicdn.com/t/c/font_4140635_4zv7o50l4p3.woff?t=1687915682269') format('woff'),
url('https://at.alicdn.com/t/c/font_4140635_4zv7o50l4p3.ttf?t=1687915682269') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 20px;
font-style: normal;
display: flex;
align-items: center;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-yishoucang:before {
content: "\e632";
}
.icon-zanwushoucang:before {
content: "\e63c";
}
.icon-mc-scj2:before {
content: "\e87e";
}
.icon-shiwuqimin:before {
content: "\e741";
}
.icon-shoucang4:before {
content: "\e646";
}
.icon-shouyedaohangtubiao-jiankangshipin:before {
content: "\e613";
}
.icon-shiwureliang:before {
content: "\e615";
}
.icon-jidan:before {
content: "\e608";
}
.icon-xia:before {
content: "\e639";
}
.icon-shang-copy:before {
content: "\ffac";
}
.icon-shoucang-mian:before {
content: "\e644";
}
.icon-shoucang:before {
content: "\e645";
}
.icon-canguan:before {
content: "\e6b1";
}
.icon-canyin_kafeiguan:before {
content: "\e654";
}
.icon-canting:before {
content: "\e609";
}
.icon-kuaican:before {
content: "\e60b";
}
.icon-a-1-1xiaochikuaican:before {
content: "\e67e";
}
.icon-jiucan:before {
content: "\e653";
}
.icon-canpan:before {
content: "\e60d";
}
.icon-yingyangzaocan:before {
content: "\ffa9";
}
.icon-wancan1:before {
content: "\e635";
}
.icon-jiacan:before {
content: "\e638";
}
.icon-quxiao3:before {
content: "\e6e0";
}
.icon-a-24_nor:before {
content: "\e612";
}
.icon-jianpanshouqi:before {
content: "\e6b0";
}
.icon-quxiao3-copy:before {
content: "\eb0c";
}
.icon-jiantou_xiangxia:before {
content: "\eb0a";
}
.icon-jiantou_xiangshang:before {
content: "\eb0b";
}
.icon-Sm-danbaizhi:before {
content: "\e606";
}
.icon-zanwushuju:before {
content: "\e611";
}
.icon-w_fat_normal:before {
content: "\e78e";
}
.icon-tanshuihuahewu:before {
content: "\e605";
}
.icon-quxiao:before {
content: "\e61e";
}
.icon-tianjia:before {
content: "\e63e";
}
.icon-reset:before {
content: "\e62a";
}
.icon-nantouxiang:before {
content: "\e636";
}
.icon-nvtouxiang:before {
content: "\e601";
}
.icon-paixu:before {
content: "\e750";
}
.icon-shezhi1:before {
content: "\e637";
}
.icon-icon3:before {
content: "\e62b";
}
.icon-kongradio:before {
content: "\e604";
}
.icon-icon_collect:before {
content: "\e603";
}
.icon-xuanzhong:before {
content: "\e630";
}
.icon-add:before {
content: "\e664";
}
.icon-add-circle:before {
content: "\e665";
}
.icon-arrow-down:before {
content: "\e666";
}
.icon-ashbin:before {
content: "\e667";
}
.icon-arrow-left:before {
content: "\e668";
}
.icon-error:before {
content: "\e66f";
}
.icon-favorite:before {
content: "\e670";
}
.icon-search:before {
content: "\e67d";
}
.icon-arrow-top-copy:before {
content: "\ffaa";
}
.icon-arrow-right-copy:before {
content: "\ffab";
}
.icon-icon:before {
content: "\e65f";
}
.icon-jiushuishouru:before {
content: "\e643";
}
.icon-wancan:before {
content: "\e7da";
}
.icon-sousuo-copy:before {
content: "\e60a";
}
.icon-lianjie:before {
content: "\e69b";
}
.icon-bianji:before {
content: "\e607";
}
.icon-icon_duankailianjie:before {
content: "\e6b9";
}
.icon-zaocanbao:before {
content: "\e6c9";
}
.icon-link_line:before {
content: "\e6ff";
}
.icon-caidan:before {
content: "\e624";
}
.icon-wucan:before {
content: "\e63d";
}
.icon-fackbook:before {
content: "\e600";
}
.icon-jiacan-xian:before {
content: "\e660";
}
.icon-xihuan:before {
content: "\e61d";
}
.icon-a-fenxiang2:before {
content: "\e620";
}
.icon-weixin:before {
content: "\e602";
}

384
components/bluetooth.vue Normal file
View File

@ -0,0 +1,384 @@
<template>
<view class="weightPages">
<view class="table" v-if="isConnection == 0">称重中请将食物放到秤上</view>
<view class="table" v-if="isConnection == 1" @click="openBluetoothAdapter">连接失败点击重新连接</view>
<view class="image" v-if="isConnection != 3">
<image src="../static/cheng.png"></image>
</view>
<view v-if="isConnection == 3">
<view class="weight">
<view>重量<text>{{weight}}</text>{{dw}}</view>
<view>热量<text>{{kcal}}</text>千卡</view>
</view>
<view class="tips">
重新称重可更新当前数据
</view>
<view class="groupbtn" v-if="weightType!=2">
<view class="btn" @click="handleDetailSub">完成</view>
<view class="btn" @click="handleDetailNext" v-if="!stopblue">下一位</view>
</view>
<view class="btn" @click="handlesub" v-if="weightType==2">确认添加</view>
</view>
<view class="tips" v-if="isConnection == 1">
<uni-icons type="info-filled" color="#dd524d" size="20"></uni-icons>
请确定设备是开机状态手机蓝牙权限已打开
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
let myTime
let nextCnt = 0
const plugin = requirePlugin("sdkPlugin").AiLink;
export default {
data() {
return {
dw: "g",
kcal: "",
weight: "",
weightALL: "",
weight0: 0,
stopblue: false,
isConnection: 0, //
}
},
props: {
weightType: {
type: Number,
default: -1 //0,1,2
},
isLast: {
type: Boolean,
default: false
}
},
computed: {
...mapState(["user", 'isConnected', "isBluetoothTyle"]),
},
mounted() {
let that = this
console.log("mounted", that.weightType)
that.openBluetoothAdapter()
that.onBLEConnectionStateChange()
uni.onBluetoothAdapterStateChange(function(res) {
that.$store.commit("changeBluetooth", res.available);
})
},
watch: {
weightType: function() {
let that = this
that.openBluetoothAdapter()
},
isBluetoothTyle: function() {
let that = this
if (!that.isBluetoothTyle) {
that.handleBack()
}
},
isLast: function() {
let that = this
that.stopblue = that.isLast
console.log("最后", this.isLast)
}
},
methods: {
//
openBluetoothAdapter() {
let that = this
that.weight = ""
that.kcal = ""
uni.openBluetoothAdapter({
success: e => {
that.isConnection = 0
that.startBluetoothDeviceDiscovery()
},
fail: e => {
that.isConnection = 1
console.log('openBluetoothAdapter', e)
that.$tools.msg("请确定设备是开机状态、手机蓝牙权限已打开!")
}
});
},
//
startBluetoothDeviceDiscovery() {
let that = this
uni.startBluetoothDevicesDiscovery({
allowDuplicatesKey: true,
services: [
"F0A0",
],
success: res => {
that.isConnection = 0
that.onBluetoothDeviceFound();
},
fail: res => {
that.isConnection = 1
console.log('startBluetoothDeviceDiscovery', res)
that.$tools.msg("请确定设备是开机状态、手机蓝牙权限已打开!")
}
});
},
//
onBLEConnectionStateChange() {
let that = this
uni.onBLEConnectionStateChange(function(res) {
console.log("监听蓝牙连接状态", res.connected)
if (!res.connected) {
that.isConnection = 1
that.closeBLEConnection()
that.closeBluetoothAdapter()
}
that.$store.commit("changeConnected", res.connected);
})
},
/**
* 停止搜索蓝牙设备
*/
stopBluetoothDevicesDiscovery() {
uni.stopBluetoothDevicesDiscovery({
success: e => {
console.log("停止搜索蓝牙设备", e)
},
});
},
/**
* 发现外围设备
*/
onBluetoothDeviceFound() {
var that = this;
that.isConnection = 0
uni.onBluetoothDeviceFound(res => {
res.devices.forEach(device => {
device.advertisData = device.advertisData ? device.advertisData : ''
device.advertisServiceUUIDs = device.advertisServiceUUIDs ? device
.advertisServiceUUIDs : ""
if (!device.name && !device.localName) {
return
}
if (device.name.indexOf("EL") !== -1 && device.advertisServiceUUIDs != '') {
clearTimeout(myTime);
that.isConnection = 3
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
if (parseDataRes.status == 1) {
let data0 = parseDataRes.payload
let data = parseInt(data0[3]).toString(16)
let data1 = parseInt(data0[4]).toString(16)
let data2 = parseInt((data + data1), 16) //
//
let unit0 = parseInt(data0[5]).toString(16) //
let unit = unit0.length > 1 ? unit0.substring(1, 2) : unit0 //
let num = parseInt(unit0.substring(0, 1), 16).toString(8)
let dot = num.toString().substring(0, 1) //
let zfz = 0 //
if (num.toString().length > 1) {
dot = num.toString().substring(1, 2)
zfz = num.toString().substring(0, 1)
}
if (unit == "7") {
that.dw = "ml"
}
if (unit == "3") {
that.dw = "oz"
}
if (unit == "2") {
that.dw = "lb'oz"
}
if (dot == "1") {
data2 = data2 / 10
}
if (dot == "2") {
data2 = data2 / 100
}
if (zfz == "0") {
data2 = data2
}
if (zfz == "1") {
data2 = "-" + data2
}
that.weight = data2
console.log("analyzeData", data.weight, data2)
}
}
})
});
},
//
handlesub() {
let that = this
console.log("weight", that.weight)
if (Number(that.weight) > 0) {
that.$emit("handleBle", that.weight, that.dw, that.kcal)
that.stopBluetoothDevicesDiscovery() //
that.closeBLEConnection()
that.closeBluetoothAdapter()
} else {
that.$tools.msg("数据异常,请清零后重新称重!")
}
},
//
handleDetailSub() {
let that = this
if (that.weightType == 1) {
that.weight0 = Number(that.weight) - Number(that.weightALL)
that.weightALL = that.weight
} else {
that.weight0 = that.weight
}
if (Number(that.weight0) > 0) {
that.$emit("handleDetailSub", that.weight0, that.dw, that.kcal)
that.stopBluetoothDevicesDiscovery() //
that.closeBLEConnection()
that.closeBluetoothAdapter()
that.weight = 0
that.weight0 = 0
} else {
that.$tools.msg("数据异常,请清零后重新称重!")
}
},
//
handleDetailNext() {
let that = this
if (that.weightType == 1) {
that.weight0 = Number(that.weight) - Number(that.weightALL)
that.weightALL = that.weight
} else {
that.weight0 = that.weight
}
if (Number(that.weight0) > 0) {
that.$emit("handleDetailNext", that.weight0, that.dw, that.kcal)
that.weight = 0
that.weight0 = 0
} else {
that.$tools.msg("数据异常,请清零后重新称重!")
}
},
handleBack() {
let that = this
that.isConnection = 1
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">
.weightPages {
display: flex;
flex-wrap: wrap;
flex-direction: column;
position: absolute;
justify-content: space-around;
left: 0;
right: 0;
bottom: 20px;
top: 60px;
.weight {
background: #fff;
color: #666;
font-size: 16px;
flex-wrap: wrap;
text-align: center;
view {
width: 60%;
height: 50px;
display: flex;
margin-left: 25%;
align-items: flex-end;
margin-bottom: 15px;
text {
width: 80px;
display: inline-block;
border-bottom: 1px solid #dfdfdf;
margin: 0 10px;
font-size: 18px;
font-weight: bold;
color: #f0ae43;
}
}
}
.tips {
font-size: 12px;
text-align: center;
}
.btn {
color: #fff;
width: 80%;
margin-left: 10%
}
.groupbtn {
.btn {
color: #000 !important;
}
}
.table {
width: 100%;
font-size: 16px;
font-weight: bold;
text-align: center;
margin: 15px 0;
}
.image {
width: 160px;
height: 160px;
margin: auto;
image {
width: 100%;
height: 100%;
}
}
.tips {
margin-bottom: 15px;
margin-left: 15px;
display: flex;
color: #999;
}
}
</style>

53
components/list.vue Normal file
View File

@ -0,0 +1,53 @@
<template>
<view class="footlist">
<view class="list" v-for="(it,id) in footlist" :key="it" @click="handleDetail(it)">
<view class="topimg">
<image :src="it.image" class="img" mode="aspectFill"></image>
</view>
<view class="item">
<view class="title">{{it.title}}</view>
<view class="name">
<image :src="it.head"></image>
<text>{{it.name}}</text>
</view>
<view class="zan" @click="handleZan(it)">
<icon class="iconfont" :class="[it.iszan?'icon-icon3':'icon-icon_collect']"></icon>
<text>{{it.zan}}</text>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "list",
data() {
return {
footlist: []
};
},
props: {
title: {
type: String,
default: ''
}
},
mounted() {
let that = this
that.footlist = that.$json.footlist
},
methods: {
//
handleDetail() {
uni.navigateTo({
url: "/pageTwo/me/menudetail?title=" + this.title
})
},
}
}
</script>
<style scoped lang="scss">
</style>

104
components/search.vue Normal file
View File

@ -0,0 +1,104 @@
<template>
<!-- 搜索 -->
<view class="serachBox">
<view class="serach-box">
<view class="searchInput">
<input placeholder="请输入..." class="city-serach-input" v-model="name" />
<icon v-if="name" class="iconfont icon-error" @click="handlecolse"></icon>
</view>
<view class="searchBtn">
<view @click="handleSerach">搜索</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "search",
data() {
return {
name: ""
};
},
methods: {
//
handleSerach() {
this.$emit("handleSearch", this.name)
},
//
handlecolse() {
this.name = ""
this.$emit("handleSearch", "")
}
}
}
</script>
<style scoped lang="scss">
.serachBox {
height: 40px;
position: fixed;
top: 0;
left: 0;
right: 0;
padding: 0 15px 10px;
z-index: 9;
background-color: #efefef;
.serach-box {
height: 40px;
border-radius: 10px;
position: relative;
background-color: #fff;
}
.searchInput {
position: absolute;
left: 0;
right: 60px;
height: 40px;
icon {
position: absolute;
right: 10px;
top: 10px;
display: flex;
}
}
.searchBtn {
position: absolute;
width: 60px;
right: 0px;
height: 40px;
line-height: 40px;
background: $mainColor;
border-radius: 0 10px 10px 0;
text-align: center;
color: #fff;
}
input {
height: 40px;
padding: 0 5px;
text-align: center;
position: absolute;
left: 0px;
right: 0px;
border-radius: 10px;
}
.icon {
width: 50px;
height: 40px;
position: absolute;
right: 15px;
display: flex;
align-items: center;
justify-content: center;
}
}
</style>

90
components/tabbar.vue Normal file
View File

@ -0,0 +1,90 @@
<template>
<view class="tabbar">
<view class="list" v-for="(ite,ind) in list" :key="ind">
<image :src="ite.iconPath"></image>
<text>{{ite.text}}</text>
</view>
</view>
</template>
<script>
export default {
name: "tabbar",
data() {
return {
list: [{
"pagePath": "pages/index/index",
"iconPath": "../static/home.png",
"selectedIconPath": "../static/home01.png",
"text": "首页"
},
{
"pagePath": "pages/menu/menu",
"iconPath": "../static/cai.png",
"selectedIconPath": "../static/cai01.png",
"text": "菜谱"
},
{
"pagePath": "pages/add/add",
"iconPath": "../static/add.png",
"selectedIconPath": "../static/add.png",
"text": ""
},
{
"pagePath": "pages/count/count",
"iconPath": "../static/ji.png",
"selectedIconPath": "../static/ji01.png",
"text": "计食器"
},
{
"pagePath": "pages/me/me",
"iconPath": "../static/me.png",
"selectedIconPath": "../static/me01.png",
"text": "我的"
}
]
};
}
}
</script>
<style lang="scss" scoped>
.tabbar {
border-top: 1px solid #dfdfdf;
position: fixed;
left: 0;
right: 0;
height: 55px;
display: flex;
justify-content: space-between;
align-items: center;
bottom: 0;
.list {
display: flex;
flex-wrap: wrap;
justify-content: center;
image {
width: 25px;
height: 25px;
}
text {
display: inline-block;
width: 100%;
text-align: center;
}
}
:nth-child(3).list {
image {
width: 42px;
height: 42px;
}
}
}
</style>

21
config.js Normal file
View File

@ -0,0 +1,21 @@
const accountInfo = wx.getAccountInfoSync();
const appid = accountInfo.miniProgram.appId
uni.setStorageSync('appid', appid)
let configPro = {}
if (process.env.NODE_ENV === 'development') {
console.log("测试环境")
configPro = {
host: "https://ipet.pcxbc.com",
envVersion: "trial"
}
} else {
console.log("生产环境")
configPro = {
host: "https://ipet.pcxbc.com",
envVersion: "develop"
}
}
module.exports = {
appid,
configPro,
};

293
data.json Normal file
View File

@ -0,0 +1,293 @@
{
"fimages": [{
"image": "../../static/img.jpg",
"title": "减脂一定要吃的生菜鸡丝卷01",
"head": "../../static/dan.png",
"name": "季总蛋先生01",
"iszan": false
}, {
"image": "../../static/img2.jpg",
"title": "减脂一定要吃的生菜鸡丝卷02",
"head": "../../static/dan.png",
"name": "季总蛋先生02",
"iszan": false
}],
"footlist": [{
"height": 370,
"image": "../static/img.jpg",
"title": "鸡蛋芝士烤吐司",
"head": "../static/dan.png",
"name": "ayamama",
"zan": 2255,
"iszan": false
},
{
"height": 370,
"image": "../static/img2.jpg",
"title": "鸡蛋芝士烤吐司",
"head": "../static/dan.png",
"name": "ayamama",
"zan": 2255,
"iszan": false
},
{
"height": 370,
"image": "../static/img.jpg",
"title": "减脂一定要吃的生菜鸡丝卷03",
"head": "../static/dan.png",
"name": "季总蛋先生03",
"iszan": true,
"zan": 1699
},
{
"height": 370,
"image": "../static/img.jpg",
"title": "减脂一定要吃的生菜鸡丝卷03",
"head": "../static/dan.png",
"name": "季总蛋先生03",
"iszan": true,
"zan": 1699
},
{
"height": 370,
"image": "../static/img2.jpg",
"title": "减脂一定要吃的生菜鸡丝卷03",
"head": "../static/dan.png",
"name": "季总蛋先生03",
"iszan": true,
"zan": 1699
},
{
"height": 370,
"image": "../static/img2.jpg",
"title": "减脂一定要吃的生菜鸡丝卷03",
"head": "../static/dan.png",
"name": "季总蛋先生03",
"iszan": true,
"zan": 1699
}
],
"menu": [{
"name": "酒水饮料"
},
{
"name": "健康饮食"
},
{
"name": "家常菜谱"
},
{
"name": "轻食沙拉"
},
{
"name": "烘焙"
}
],
"menulist": [{
"name": "酒水",
"list": [{
"image": "../../static/img2.jpg",
"name": "莫吉托"
},
{
"image": "../../static/jiu.jpg",
"name": "威士忌"
},
{
"image": "../../static/img2.jpg",
"name": "白兰地"
},
{
"image": "../../static/jiu.jpg",
"name": "朗姆酒"
}
]
},
{
"name": "饮品",
"list": [{
"image": "../../static/jiu.jpg",
"name": "咖啡"
},
{
"image": "../../static/img2.jpg",
"name": "豆浆"
},
{
"image": "../../static/jiu.jpg",
"name": "果汁"
},
{
"image": "../../static/jiu.jpg",
"name": "奶茶"
}
]
}
],
"food": [{
"name": "蔬菜豆品"
},
{
"name": "水果鲜花"
},
{
"name": "酒水饮料"
},
{
"name": "乳品烘焙"
},
{
"name": "肉蛋水产"
},{
"name": "蔬菜豆品"
},
{
"name": "水果鲜花"
},
{
"name": "酒水饮料"
},
{
"name": "乳品烘焙"
},
{
"name": "肉蛋水产"
},{
"name": "蔬菜豆品"
},
{
"name": "水果鲜花"
},
{
"name": "酒水饮料"
},
{
"name": "乳品烘焙"
},
{
"name": "肉蛋水产"
}
],
"foodlist": [{
"name": "土豆/根茎类",
"list": [{
"id": 1,
"name": "土豆",
"unit": "g",
"weight": null
},
{
"id": 2,
"name": "紫薯",
"unit": "g",
"weight": null
},
{
"id": 3,
"name": "铁棍山药",
"unit": "g",
"weight": null
},
{
"id": 4,
"name": "胡萝卜",
"unit": "g",
"weight": null
}
]
},
{
"name": "叶菜类",
"list": [{
"id": 5,
"name": "上海青",
"unit": "g",
"weight": null
},
{
"id": 6,
"name": "本地生菜",
"unit": "g",
"weight": null
},
{
"id": 7,
"name": "球生菜",
"unit": "g",
"weight": null
},
{
"id": 8,
"name": "菠菜",
"unit": "g",
"weight": null
}
]
}
],
"recordList": [{
"time": "2323/03/25",
"kcal": "1235",
"status": 1
}, {
"time": "2323/03/25",
"kcal": "1236",
"status": 2
}, {
"time": "2323/03/25",
"kcal": "1237",
"status": 1
}, {
"time": "2323/03/25",
"kcal": "1238",
"status": 1
}, {
"time": "2323/03/25",
"kcal": "1239",
"status": -1
}, {
"time": "2323/03/25",
"kcal": "1240",
"status": -1
}, {
"time": "2323/03/25",
"kcal": "1241",
"status": 2
}],
"menudetail": {
"id": 1,
"FMimg": "../../static/1-2.jpg",
"content": "简单易操作,方便又美味",
"list": [{
"id": 1,
"name": "牛肉",
"unit": "g",
"weight": "10"
}, {
"id": 2,
"name": "芝麻",
"unit": "g",
"weight": "20"
}, {
"id": 3,
"name": "面粉",
"unit": "g",
"weight": "30"
}],
"user": {
"headimg": "../../static/dan.png",
"name": "季总蛋先生03",
"iszan": false,
"zan": 1699
},
"stepList": [{
"content": "去面粉500g,加水100ml搅拌均匀取葱1根切葱花热锅放油放面饼翻面放葱花芝麻",
"image": "../../static/img2.jpg"
}, {
"content": "去面粉500g,加水100ml搅拌均匀取葱1根切葱花热锅放油放面饼翻面放葱花芝麻",
"image": "../../static/img.jpg"
}],
"title": "葱油饼"
}
}

20
index.html Normal file
View File

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

42
main.js Normal file
View File

@ -0,0 +1,42 @@
import App from './App'
import './uni.scss';
import './assets/common.scss'
import './assets/iconfont.css'
import './assets/iconfont-weapp-icon.css'
import store from './store'
Vue.prototype.$store = store;
// js
import tools from '@/tools/tools.js'
Vue.prototype.$tools = tools;
//请求
import http from '@/tools/https.js'
Vue.prototype.$http = http;
//接口
import model from '@/tools/model.js'
Vue.prototype.$model = model;
//模拟数据
import json from '@/data.json'
Vue.prototype.$json = json;
// #ifndef VUE3
import Vue from 'vue'
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
// #endif
// #ifdef VUE3
import {
createSSRApp
} from 'vue'
export function createApp() {
const app = createSSRApp(App)
return {
app
}
}
// #endif

86
manifest.json Normal file
View File

@ -0,0 +1,86 @@
{
"name" : "kitchendDevice",
"appid" : "__UNI__2494015",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
/* 5+App */
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "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.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.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<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.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
/* ios */
"ios" : {},
/* SDK */
"sdkConfigs" : {}
}
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "wxd230a93791c03259",
"setting" : {
"urlCheck" : false,
"minified" : true,
"es6" : true,
"postcss" : true
},
"usingComponents" : true,
//
"optimization" : {
"Package8s" : true
},
"plugins" : {
"sdkPlugin" : {
// 线
"version" : "2.3.3", //
"provider" : "wx17e93aad47cdae1a" //appid
}
}
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "2"
}

View File

@ -0,0 +1,88 @@
<template>
<view class="content">
<view class="title">
自定义卡路里量
<text class="desc">可选范围是1000~4000千卡修改时请谨慎</text>
</view>
<view class="input">
<input type="digit" placeholder="请输入" v-model="kcal" />
<text>千卡</text>
</view>
<view class="btn" @click="handlesub">确认修改</view>
</view>
</template>
<script>
export default {
data() {
return {
kcal: ""
}
},
methods: {
handlesub() {
let that = this
if (that.kcal == '' || Number(that.kcal) <= 0) {
that.$tools.msg("请输入卡路里")
return
}
}
}
}
</script>
<style scoped lang="scss">
.content {
padding: 0 15px;
flex-wrap: wrap;
background-color: #fff;
}
.title {
width: 100%;
font-size: 16px;
margin: 15px 0;
font-weight: bold;
text {
font-size: 14px;
color: #999;
font-weight: 500;
width: 100%;
display: inline-block;
margin-top: 10px;
}
}
.input {
display: flex;
margin: 20px;
height: 35px;
line-height: 35px;
border-bottom: 1px solid #dfdfdf;
width: calc(100% - 40px);
position: relative;
/deep/input {
width: 100%;
height: 35px;
font-size: 18px;
line-height: 35px;
text-align: center;
font-weight: bold;
position: absolute;
}
text {
position: absolute;
right: 0;
}
}
.btn {
margin-top: 40px;
width: calc(100% - 30px);
color: #fff;
}
</style>

486
pageTwo/count/food.vue Normal file
View File

@ -0,0 +1,486 @@
<template>
<view class="content">
<!-- 搜索 -->
<search @handleSearch="handleSearch"></search>
<view class="box menu">
<!-- 左侧菜单栏 -->
<view class="left">
<view class="name" v-for="(ite,ind) in menu" :key="ind" :class="[index==ind?'active':'']"
@click="handleToggle(ind)">
{{ite.name}}
</view>
</view>
<!-- 右侧商品 -->
<view class="right">
<view class="right_list" v-for="(ite,ind) in menulist" :key="ind">
<view class="title">
<view>{{ite.name}}</view>
</view>
<view class="list">
<view class="item" v-for="(it,id) in ite.list" :key="id" @click="handleDetail(it)">
<text>{{it.name}}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 底部购物车 -->
<view class="groupbtn">
<view class="che" @click="isShop =! isShop">
<text v-if="ActiveList.length">{{ActiveList.length}}</text>
<!-- <image src="../../static/pan.png"></image> -->
<icon class="t-icon t-icon-canpan"></icon>
</view>
<view class="subbtn" @click="handlesubbtn"> 确定</view>
</view>
<!-- 购物车列表 -->
<view class="wrapper activeList" v-if="isShop">
<view class="bg" @click='isShop=false'>
<view class="box" @click.stop>
<view class="title">{{ActiveList.length}}条记录</view>
<view class="list" v-if="ActiveList.length">
<view class="item" v-for="(ite,ind) in ActiveList" :key="ind">
<view class="">
<text class="name">{{ite.name}}</text>
<text>{{ite.weight}}{{ite.unit}}</text>
</view>
<icon class="iconfont icon-ashbin" @click="handledelactive(ite)"></icon>
</view>
</view>
<view v-else class="nolist list">
<icon class="iconfont icon-wancan"></icon>
<text>还没有记录哦</text>
</view>
</view>
</view>
</view>
<!-- 称重区 -->
<view class="wrapper" v-if="IsWeight">
<view class="bg" @click='IsWeight=false'>
<view class="box" @click.stop>
<view class="title">
<view class="weight" @click="handleWeight()">
<icon class="iconfont icon-lianjie"></icon>
食物秤称重
</view>
<view class="cancel">
<icon class="iconfont icon-error" @click="Cancelword()"></icon>
</view>
</view>
<view class="name">{{activeType.name}}</view>
<view class="val">
<text>{{activeType.weight?activeType.weight:'100'}}</text>g
</view>
<view class="mybrankmask">
<view class="MymaskAll">
<view class="MymaskList">
<view class="maskListItem" @click="NumberCk(1)">1</view>
<view class="maskListItem" @click="NumberCk(2)">2</view>
<view class="maskListItem" @click="NumberCk(3)">3</view>
</view>
<view class="MymaskList">
<view class="maskListItem" @click="NumberCk(4)">4</view>
<view class="maskListItem" @click="NumberCk(5)">5</view>
<view class="maskListItem" @click="NumberCk(6)">6</view>
</view>
<view class="MymaskList">
<view class="maskListItem" @click="NumberCk(7)">7</view>
<view class="maskListItem" @click="NumberCk(8)">8</view>
<view class="maskListItem" @click="NumberCk(9)">9</view>
</view>
<view class="MymaskList">
<view class="maskListItem" @click="NumberCk('.')">.</view>
<view class="maskListItem" @click="NumberCk(0)">0</view>
<view class="maskListItem" @click="Cancelword()">
<image src="../../static/Clear.png"></image>
</view>
</view>
</view>
<view class="MymaskList MymaskList2">
<view class="maskListItem text" @click="Tuige()">
<image src="../../static/close.png" class="close"></image>
</view>
<view class="maskListItem text" @click="Clear()">清空</view>
<view class="maskListItem width48" @click="Next()">保存</view>
</view>
</view>
</view>
</view>
</view>
<!--蓝牙连接区 -->
<view class="wrapper" v-if="isBle">
<view class="bg" @click='isBle=false'>
<view class="box" @click.stop>
<view class="title">
<view class="name">{{activeType.name}}</view>
<icon class="iconfont icon-error" @click='isBle=false'></icon>
</view>
<blue-tooth @handleBle="handleBle" :weightType="'2'"></blue-tooth>
</view>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
let myTime
const plugin = requirePlugin("sdkPlugin").AiLink;
import search from "../../components/search.vue"
import blueTooth from "../../components/bluetooth.vue"
export default {
components: {
search,
blueTooth
},
data() {
return {
typename: "",
typeind: 0,
index: 0,
menu: [],
menulist: [],
myvalue: [],
ActiveList: [],
activeType: {},
IsWeight: false,
isShop: false,
isBle: false,
kcal: "",
weight: "",
stopblue: true,
isConnection: 0, //
};
},
computed: {
...mapState(["user", 'isConnected', "isBluetoothTyle"]),
},
onLoad(options) {
let that = this
that.typename = options.name
that.typeind = options.ind
that.menu = that.$json.food
that.menulist = that.$json.foodlist
},
methods: {
//
handleSearch(ite){
console.log("计食器搜索",ite)
},
//
handleToggle(index) {
let that = this
that.index = index
},
//
handleDetail(ite) {
var that = this;
that.myvalue = []
that.activeType = ite
that.activeType.weight = 100
that.IsWeight = true
that.isShop = false
console.log("选中的商品", ite)
},
//
handlesubbtn() {
let that = this
let pages = getCurrentPages()
let prevPage = pages[pages.length - 2]
let data = {
index: "",
title: "",
list: []
}
data.index = that.typeind
data.title = that.typename
data.list = that.ActiveList
prevPage.$vm.getAddFood(data)
uni.navigateBack({
delta: 1
})
},
//
handledelactive(ite) {
let that = this
that.ActiveList.splice(that.ActiveList.indexOf(ite), 1);
},
//
NumberCk(val) {
let that = this
that.myvalue = that.myvalue[0] == '.' ? [0, '.'].concat(val) : that.myvalue.concat(val)
if (that.myvalue.toString().indexOf('.') != -1) {
let ind = that.myvalue.indexOf(".")
that.myvalue = that.myvalue.slice(0, ind + 2)
}
if (that.myvalue.toString().indexOf('.') == -1 && that.myvalue.length > 3) {
that.myvalue = ["9", "9", "9"]
}
that.activeType.weight = that.myvalue.join("")
},
// 退
Tuige() {
let that = this
var txt = that.myvalue
if (txt.length >= 1) {
if (txt[txt.length - 2] != '.') {
that.myvalue = txt.slice(0, txt.length - 1)
} else {
that.myvalue = txt.slice(0, txt.length - 2)
}
}
that.activeType.weight = that.myvalue.join("")
// console.log("退1", txt, that.myvalue.join(""))
},
//
Cancelword() {
this.IsWeight = false
this.myvalue = []
this.activeType = {}
// console.log("")
},
//
Clear() {
this.myvalue = []
this.activeType.weight = null
// console.log("")
},
//
Next() {
let that = this
let ite = that.activeType
that.IsWeight = false
if (that.ActiveList.indexOf(ite) == -1) {
that.ActiveList.push(ite);
} else {
let index = that.ActiveList.indexOf(ite)
that.ActiveList[index].weight = that.activeType.weight;
that.ActiveList[index].unit = that.activeType.unit;
}
console.log("保存", that.ActiveList)
},
//
handleWeight() {
let that = this
that.isBle = true
that.IsWeight = false
},
//
handleBle(weight, unit, kcal) {
let that = this
that.isBle = false
that.activeType.weight = weight
that.activeType.unit = unit
that.Next()
console.log("返回", that.activeType, weight, unit, kcal)
}
}
}
</script>
<style lang="scss" scoped>
.right {
.item {
width: 30%;
border: 1px solid #f7f7f7;
display: flex;
align-items: center;
justify-content: space-around;
height: 28px;
border-radius: 8px;
margin-bottom: 10px;
text {
margin-bottom: 0 !important;
}
}
.icon-xuanzhong {
color: $mainColor;
}
.active0 {
border: 1px solid $mainColor;
}
}
.weightPages {
display: flex;
flex-wrap: wrap;
flex-direction: column;
position: absolute;
left: 0;
right: 0;
bottom: 20px;
top: 60px;
justify-content: space-around;
.weight {
background: #fff;
color: #666;
font-size: 16px;
flex-wrap: wrap;
text-align: center;
view {
width: 60%;
height: 50px;
display: flex;
margin-left: 25%;
align-items: flex-end;
margin-bottom: 15px;
text {
width: 80px;
display: inline-block;
border-bottom: 1px solid #dfdfdf;
margin: 0 10px;
font-size: 18px;
font-weight: bold;
color: #f0ae43;
}
}
}
.tips {
font-size: 12px;
text-align: center;
}
.btn {
color: #fff;
width: 80%;
margin-left: 10%;
}
.table {
width: 100%;
font-size: 16px;
font-weight: bold;
text-align: center;
margin: 15px 0;
}
.image {
width: 160px;
height: 160px;
margin: auto;
image {
width: 100%;
height: 100%;
}
}
.tips {
margin-bottom: 15px;
margin-left: 15px;
display: flex;
color: #999;
}
}
.groupbtn {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 10px;
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 55px;
z-index: 15;
background-color: #fff;
overflow: hidden;
box-shadow: 0px 1px 5px 2px #dfe2e1fc;
.subbtn {
color: #fff;
width: 40%;
text-align: center;
border-radius: 10px;
height: 31px;
line-height: 31px;
background-color: $mainColor;
}
.che {
width: 50px;
height: 40px;
position: relative;
text {
position: absolute;
height: 15px;
background: red;
width: 15px;
border-radius: 50%;
display: inline-block;
color: #fff;
line-height: 15px;
text-align: center;
font-size: 12px;
right: 0;
top: 5px;
}
image,
.t-icon {
width: 50px;
height: 50px;
margin-top: -3px;
border-radius: 50%;
}
}
}
.menu {
.left {
bottom: 55px;
height: calc(100vh - 120px);
}
.right {
bottom: 55px;
height: calc(100vh - 120px);
}
}
.activeList {
z-index: 12;
bottom: 50px;
.title {
font-weight: bold;
margin: 5px 0;
}
.list {
padding-bottom: 55px;
.name {
margin-right: 5px;
}
}
}
.icon-error {
font-size: 45px;
margin-top: -30px;
background: #fff;
border-radius: 50%;
width: 45px;
height: 45px;
}
</style>

202
pageTwo/count/setting.vue Normal file
View File

@ -0,0 +1,202 @@
<template>
<view class="content">
<!-- -->
<view class="info" @click="handleEditUser">
<view class="left">
<image :src="user.headimg"></image>
<view class="name overflow">{{user.name}}</view>
<view>{{user.sex==1?'男':user.sex==2?'女':'未知'}}</view>
<view>{{user.age}}</view>
</view>
<icon class="iconfont icon-bianji"></icon>
</view>
<!-- -->
<view class="kcal" @click="handleEditKcal()">
<view class="text">
建议摄入卡路里
<text>修改></text>
</view>
<view class="num">
<text>1227</text>千卡
</view>
<view class="desc">
基础代谢指人体在清醒而又极端安静的状态下不受肌肉活动环境温度食物及精神紧张等影响时的能量代谢率
</view>
</view>
<!-- -->
<view class="kcal">
<view class="text">
建议三大营养比列
</view>
<view class="num">
<view class="item">
<icon class="iconfont icon-tanshuihuahewu"></icon>
<text>碳水化合物</text>
<text>53%</text>
<view class="val">172g</view>
</view>
<view class="item">
<icon class="iconfont icon-Sm-danbaizhi"></icon>
<text>蛋白质</text>
<text>17%</text>
<view class="val">45g</view>
</view>
<view class="item">
<icon class="iconfont icon-w_fat_normal"></icon>
<text>脂肪</text>
<text>30%</text>
<view class="val">43g</view>
</view>
</view>
<view class="desc">
根据您的预算热量和饮食方案为您计算推荐摄入量请注意此处的推荐摄入是不涉及运动产生的额外可摄入热量
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
export default {
data() {
return {
}
},
computed: {
...mapState(["user"])
},
methods: {
handleEditUser() {
uni.navigateTo({
url: "/pageTwo/me/userEdit?familayData=" +JSON.stringify(this.user)
})
},
handleEditKcal() {
uni.navigateTo({
url: "/pageTwo/count/KcalEdit"
})
}
}
}
</script>
<style scoped lang="scss">
.content {
padding: 0 10px;
}
.info {
width: calc(100% - 20px);
background: #fff;
border-radius: 10px;
padding: 10px;
display: flex;
align-items: center;
margin-bottom: 15px;
justify-content: space-between;
.left {
display: flex;
align-items: center;
.name {
max-width: 50%;
font-weight: bold;
}
view {
margin-right: 15px;
}
image {
width: 50px;
height: 50px;
border-radius: 50%;
margin-right: 10px;
border: 1px solid #dfdfdf;
}
}
icon {
font-size: 20px;
}
}
.kcal {
width: 100%;
background: #fff;
border-radius: 10px;
padding: 10px 0;
margin-bottom: 15px;
.text {
padding: 5px 10px;
display: flex;
justify-content: space-between;
}
.num {
width: 100%;
text-align: center;
margin: 15px 0;
display: flex;
justify-content: center;
align-items: baseline;
text {
font-size: 25px;
font-weight: bold;
margin-right: 5px;
color: $mainColor;
border-bottom: 1px solid;
}
.item {
display: flex;
flex-wrap: wrap;
width: 33.3%;
justify-content: center;
icon {
font-size: 40px;
color: $uni-color-warning;
border-radius: 30%;
padding: 5px;
margin-bottom: 8px;
}
text {
font-size: 14px;
font-weight: 500;
color: #666;
display: inline-block;
width: 100%;
text-align: center;
line-height: 20px;
border-bottom: none;
}
.val {
width: 100px;
background: #f7f7f7;
border-radius: 10px;
margin: auto;
margin-top: 8px;
font-weight: bold;
padding: 2px 0;
}
}
}
.desc {
margin: 0 10px;
font-size: 12px;
color: #999;
line-height: 20px;
}
}
</style>

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

@ -0,0 +1,300 @@
<template>
<view class="content">
<view class="top">
<image :src="configBox.logo"></image>
<text>{{configBox.title}}</text>
</view>
<view class="edit">
<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">
<text>其他登录方式</text>
<button open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
<icon class="t-icon t-icon-weixin"></icon>
</button>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
export default {
data() {
return {
phone: "",
code: "",
disabled: false,
second: 60,
value: 1,
}
},
computed: {
...mapState(["configBox", "themeColor"]),
},
onLoad(options) {
//
let that = this
if (!uni.getStorageSync('sessionid')) {
// that.$store.dispatch('getsessionId')
}
},
methods: {
//
handleTelLogin() {
let that = this
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.getvisitordelogin({
phone: that.phone,
code: that.code,
isvrcode: true,
sessionId: uni.getStorageSync('sessionid'),
}).then(res => {
if (res.code != 0) {
that.$tools.msg(res.message)
return
}
uni.setStorageSync('token', res.data.token)
uni.setStorageSync('refreshtoken', res.data.refreshtoken)
uni.setStorageSync('sessionid', res.data.sessionid)
that.$store.commit('changeVisitorInfo', res.data)
uni.reLaunch({
url: "/pages/index/index"
})
}).catch(err => {})
},
//
handleCode() {
let that = this
that.code = ""
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) {
let that = this
if (res.detail.errMsg == 'getPhoneNumber:ok') {
this.$model.getregister({
sessionId: uni.getStorageSync('sessionid'),
encryptedData: res.detail.encryptedData,
iv: res.detail.iv,
}).then(res => {
if (res.code != 0) 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)
uni.reLaunch({
url: "/pages/index/index"
})
})
}
},
}
}
</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;
font-size: 14px;
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-bottom: #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%;
}
}
.yanzhengma {
input {
height: 35px;
line-height: 35px;
position: absolute;
left: 10px;
right: 120px;
width: auto;
}
}
.code {
width: 110px;
background: #dfdfdf;
font-size: 12px;
margin: 0;
border-radius: 10px;
text-align: center;
position: absolute;
right: 2.5px;
top: 2.5px;
}
.btnlogin {
width: 100%;
margin: 20px 0;
height: 38px;
line-height: 38px;
background: $mainColor;
font-weight: 700;
border-radius: 10px;
text-align: center;
color: #fff !important;
}
}
.btnGroup {
width: 100%;
display: flex;
justify-content: center;
flex-wrap: wrap;
background-color: inherit;
line-height: inherit;
position: absolute;
bottom: 100rpx;
.wxbtn {
width: 100%;
icon {
width: 35px;
height: 35px;
}
text {
width: 100%;
font-size: 14px;
color: #999;
display: block;
text-align: center;
margin-bottom: 10px;
}
button {
line-height: initial;
background: #fff;
display: flex;
flex-wrap: wrap;
padding: 0;
justify-content: center;
}
button::after {
display: none;
}
}
}
</style>

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

@ -0,0 +1,100 @@
<template>
<view class="content">
<view class="formbox">
<view class="input">
<input type="text" v-model="formdata.phone" placeholder="在此输入您的联系方式" />
</view>
<view class="input textarea">
<textarea v-model="formdata.content" name="content" placeholder="有什么想说的,尽管来吧..." />
</view>
<view class="btn " type="button" @click="submit">提交</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
export default {
data() {
return {
formdata: {
phone: "",
content: ""
},
}
},
computed: {
...mapState([])
},
onLoad() {},
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>
.formbox {
padding: 15px;
width: calc(100% - 30px);
}
.input {
margin: 0;
display: flex;
border-radius: 10px;
padding: 10px;
margin-bottom: 1rem;
background: #fff;
input {
width: 100%;
height: 1.5rem;
line-height: 1.5rem;
background: none;
border: none;
font-size: 14px;
}
/deep/textarea {
width: 100%;
height: 6rem;
line-height: 20px;
background: none;
border: none;
font-size: 14px;
}
}
.btn {
color: #fff;
margin: 15px 0;
}
</style>

203
pageTwo/me/foodlist.vue Normal file
View File

@ -0,0 +1,203 @@
<template>
<view class="content">
<!-- 搜索 -->
<search @handleSearch="handleSearch"></search>
<view class="box menu">
<!-- 左侧菜单栏 -->
<view class="left" :class="[ActiveList.length?'maxheight':'']">
<view class="name" v-for="(ite,ind) in menu" :key="ind" :class="[index==ind?'active':'']"
@click="handleToggle(ind)">
{{ite.name}}
</view>
</view>
<!-- 右侧商品 -->
<view class="right" :class="[ActiveList.length?'C':'']">
<view class="right_list" v-for="(ite,ind) in menulist" :key="ind">
<view class="title">
<view>{{ite.name}}</view>
</view>
<view class="list">
<view class="item" v-for="(it,id) in ite.list" :key="id" @click="handleDetail(it)"
:class="[ActiveList.indexOf(it)!=-1?'active0':'']">
<text>{{it.name}}</text>
<icon class="iconfont" :class="[ActiveList.indexOf(it)!=-1?'icon-xuanzhong':'icon-add']">
</icon>
</view>
</view>
</view>
</view>
</view>
<!-- 选中区 -->
<view class="activeList" v-if="ActiveList.length">
<view class="list">
<view class="item" v-for="(ite,ind) in ActiveList" :key="ind">
<text>{{ite.name}}</text>
<icon class="iconfont icon-quxiao" @click="handleDetail(ite)"></icon>
</view>
</view>
<view class="groupbtn">
<view @click="handledelete">清空</view>
<view class="subbtn" @click="handlesubbtn"> 确定</view>
</view>
</view>
</view>
</template>
<script>
import search from "../../components/search.vue"
export default {
components: {
search
},
data() {
return {
text: "",
index: 0,
menu: [],
menulist: [],
ActiveList: [],
type: "",
};
},
onLoad() {
let that = this
that.menu = that.$json.food
that.menulist = that.$json.foodlist
},
methods: {
//
handleToggle(index) {
let that = this
that.index = index
},
//
handledelete() {
this.ActiveList = []
},
//
handleDetail(ite) {
var that = this;
if (that.ActiveList.indexOf(ite) == -1) {
that.ActiveList.push(ite);
} else {
that.ActiveList.splice(that.ActiveList.indexOf(ite), 1);
}
},
//
handlesubbtn() {
let that = this
let pages = getCurrentPages()
let prevPage = pages[pages.length - 2]
prevPage.$vm.getAddFood(that.ActiveList)
uni.navigateBack({
delta: 1
})
},
//
handleSearch(ite) {
console.log("食材库搜索", ite)
},
}
}
</script>
<style lang="scss" scoped>
.right {
.item {
width: 30%;
border: 1px solid #f7f7f7;
display: flex;
align-items: center;
justify-content: space-around;
height: 28px;
border-radius: 8px;
margin-bottom: 10px;
text {
margin-bottom: 0 !important;
}
}
.icon-xuanzhong {
color: $mainColor;
}
.active0 {
border: 1px solid $mainColor;
}
}
.activeList {
position: fixed;
bottom: 0px;
left: 0;
right: 0;
z-index: 999;
background: #fff;
padding: 10px 10px 0 0;
border-radius: 10px 10px 0 0;
box-shadow: 0px 1px 5px 2px #dfe2e1fc;
.list {
height: 340rpx;
overflow: scroll;
padding-bottom: 55px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-content: end;
.item {
width: 46%;
border: 1px solid $mainColor;
display: flex;
justify-content: space-around;
height: 28px;
border-radius: 5px;
align-items: center;
margin-bottom: 10px;
margin-left: 1%;
float: left;
icon {
color: $mainColor;
font-size: 16px;
}
}
}
.groupbtn {
display: flex;
justify-content: space-between;
position: absolute;
left: 0px;
right: 0px;
bottom: 0px;
padding: 10px;
background: #fff;
border-top: 1px solid #f7f7f7;
view {
width: 40%;
text-align: center;
border: 1px solid #dfdfdf;
border-radius: 10px;
height: 31px;
line-height: 31px;
}
.subbtn {
color: #fff;
border-color: $mainColor;
background-color: $mainColor;
}
}
}
.maxheight {
height: calc(100vh - 500rpx);
}
</style>

529
pageTwo/me/menudetail.vue Normal file
View File

@ -0,0 +1,529 @@
<template>
<view class="content addFood">
<!-- 封面 -->
<view class="topimg">
<image :src="info.FMimg" mode="aspectFill"></image>
</view>
<!-- 信息 -->
<view class="title">
<view class="table">{{info.title}}</view>
<view class="user">
<view class="left">
<image :src="info.user.headimg"></image>
<text>{{info.user.name}}</text>
</view>
<view class="right" v-if="type!='菜谱预览'">
<icon class="t-icon" :class="[info.user.iszan?'t-icon-icon3':'t-icon-icon_collect']"></icon>
<text>{{info.user.zan}}</text>
</view>
</view>
</view>
<!-- 食材 -->
<view class="food">
<view class="desc">
{{info.content}}
</view>
<view class="h4">
所需食材
<view class="close" @click="handleWeight" v-if="type!='菜谱预览'">
<image src="../../static/lianjie.png"></image>
连接称重
</view>
</view>
<view class="foodlist">
<view class="item" v-for="(ite,ind) in info.list" :key="ind" v-if="info.list&&info.list.length">
<view class="name">{{ite.name}}</view>
<view class="weight">
{{ite.weight}}{{ite.unit}}
</view>
</view>
</view>
</view>
<!-- 步骤 -->
<view class="step">
<view class="stepList" v-for="(ite,ind) in info.stepList" :key="ind"
v-if="info.stepList&&info.stepList.length">
<view class="top">
<text>步骤{{ind+1}}</text>
</view>
<view class="right">
<view class="desc">
{{ite.content}}
</view>
<view class="image">
<image :src="ite.image" mode="aspectFill"></image>
</view>
</view>
</view>
</view>
<!-- 底部操作 -->
<view class="foot" v-if="type!='菜谱预览'">
<view class="item" @click="handleCang()">
<icon class="t-icon" :class="[info.user.iszan?'t-icon-icon3':'t-icon-icon_collect']"></icon>
<text>收藏</text>
</view>
<view class="item" @click="handleshare()">
<icon class="iconfont icon-a-fenxiang2"></icon>
<text>分享</text>
</view>
<view class="item" v-if="type=='我的菜谱'" @click="handleEdit()">
<icon class="iconfont icon-bianji"></icon>
<text>编辑</text>
</view>
<view class="item" v-if="type=='我的菜谱'" @click="handledel()">
<icon class="iconfont icon-ashbin"></icon>
<text>删除</text>
</view>
</view>
<!--蓝牙连接区 -->
<view class="wrapper" v-if="isBle">
<view class="bg" @click="isBle = false">
<view class="box weightBox" @click.stop>
<view class="table">
<text>备料</text>
<icon class="iconfont icon-error" @click='isBle=false'></icon>
</view>
<view class="foodlist">
<view class="text">
<text>食材</text>
<text>建议</text>
<text>重量</text>
<text>热量</text>
<text>重秤</text>
</view>
<view class="item" v-for="(ite,ind) in info.list" :key="ind" v-if="info.list&&info.list.length">
<view class="name">{{ite.name}}</view>
<view class="num">
{{ite.weight}}{{ite.unit}}
</view>
<view class="num" v-if="ite.newweight">
{{ite.newweight}}{{ite.newunit}}
</view>
<view class="num" v-if="ite.newkcal">
{{ite.newkcal}}
</view>
<view class="edit" @click="handlechongzhi(ite,ind)" v-if="ite.newweight">
<icon class="iconfont icon-reset"></icon>
</view>
<view class="kcal" v-if="activeType.id ==ite.id&&!ite.newweight">
正在称重...
</view>
</view>
</view>
<view class="groupbtn" v-if="isWeightType&&iSWeightSub">
<view @click="handleWeightType(1)">累计称重</view>
<view @click="handleWeightType(0)">分类称重</view>
</view>
<view class="title" v-if="!isWeightType&&iSWeightSub">
<view class="name">{{activeType.name}}</view>
<blue-tooth @handleDetailNext="handleDetailNext" @handleDetailSub="handleDetailSub"
:weightType="weightType" :isLast="isLast" />
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
import blueTooth from "../../components/bluetooth.vue"
export default {
data() {
return {
type: "",
info: {},
weightType: 2,
activeType: {},
isBle: false,
isWeightType: true,
iSWeightSub: true,
listInd: 0,
isLast: false,
}
},
components: {
blueTooth
},
onLoad(options) {
let that = this
let info = {}
if (options && options.info) {
info = JSON.parse(options.info)
that.type = info.pageName
that.info = info
} else {
that.type = options.title
that.info = that.$json.menudetail
}
console.log("type", options, that.type)
},
methods: {
//
handleWeight() {
let that = this
that.isBle = true
that.isLast = false
that.activeType = {}
that.iSWeightSub = true
that.isWeightType = true
},
//
handleDetailNext(weight, dw, kcal) {
let that = this
console.log("下一位id", that.activeType.id)
let ind = that.info.list.findIndex(ite => ite.id == that.activeType.id)
that.info.list[ind].newweight = weight
that.info.list[ind].newunit = dw
that.info.list[ind].newkcal = kcal
that.listInd = that.listInd + 1
that.activeType = that.info.list[ind + 1]
if (that.listInd == that.info.list.length - 1 || that.listInd == that.info.list.length) {
that.isLast = true
}
console.log("下一位序号", that.listInd)
},
//
handleDetailSub(weight, dw, kcal) {
let that = this
let ind = that.info.list.findIndex(ite => ite.id == that.activeType.id)
that.info.list[ind].newweight = weight
that.info.list[ind].newunit = dw
that.info.list[ind].newkcal = kcal
that.iSWeightSub = false
console.log("称重完成", weight, dw, kcal)
},
//
handlechongzhi(ite, ind) {
let that = this
that.listInd = ind
that.isLast = false
that.activeType = ite
that.iSWeightSub = true
that.isWeightType = false
that.info.list[ind].newweight = ""
that.info.list[ind].newunit = ""
that.info.list[ind].newkcal = ""
if (that.listInd == that.info.list.length - 1 || that.listInd == that.info.list.length) {
that.isLast = true
}
console.log("重置", ind, that.info.list.length)
},
//
handleWeightType(ind) {
this.weightType = ind
this.isLast = false
this.isWeightType = false
this.activeType = this.info.list[0]
},
handleCang() {
this.$tools.msg("收藏")
},
handleshare() {
this.$tools.msg("分享")
},
handleEdit() {
this.$tools.msg("编辑")
},
handledel() {
this.$tools.msg("删除")
}
}
}
</script>
<style lang="scss" scoped>
.content {
padding: 0 15px;
}
.topimg {
width: 100%;
height: 320px;
background: #fff;
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
flex-direction: column;
margin-bottom: 10px;
overflow: hidden;
position: relative;
.iconfont {
font-size: 30px;
color: $mainColor;
}
text {
display: inline-block;
width: 100%;
text-align: center;
font-size: 12px;
color: #999;
}
.text {
font-size: 16px;
color: #666;
margin-bottom: 3px;
}
image {
width: 100%;
height: inherit;
}
}
.step {
.image {
height: 320px;
margin: auto;
background: #f7f7f7;
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
flex-direction: column;
overflow: hidden;
image {
width: 100%;
height: inherit;
display: inline-table;
}
icon {
font-size: 30px;
color: #ff4c4f;
margin-bottom: 5px;
}
}
}
.title {
padding: 10px;
.table {
font-size: 16px;
font-weight: bold;
}
.user {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 15px;
.left {
display: flex;
align-items: center;
image {
width: 22px;
height: 22px;
margin-right: 5px;
}
}
.right {
display: flex;
}
}
}
.desc {
width: 100%;
line-height: 25px;
margin-bottom: 10px;
}
.h4 {
margin: 10px 0;
padding-top: 10px;
border-top: 1px solid #f7f7f7;
.close {
color: #fff;
width: 100px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
background-color: $mainColor;
image {
width: 25px;
height: 25px;
}
}
}
.step {
margin-bottom: 60px;
}
.foodlist {
border-radius: 10px;
background: #fff;
.item {
margin-top: 0 !important;
border-radius: 0px !important;
border-bottom: 1px solid #f7f7f7;
}
.name {
border-right: none !important;
}
}
.foot {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #fff;
display: flex;
justify-content: space-between;
padding: 5px 0px;
border-radius: 10px 10px 0 0;
box-shadow: 0px 1px 5px 2px #dfe2e1fc;
.item {
width: 25%;
display: flex;
flex-wrap: wrap;
justify-content: center;
icon {
font-size: 21px;
}
text {
display: inline-block;
text-align: center;
width: 100%;
}
}
}
//
.weightBox {
top: 32px;
height: auto;
border-radius: 0;
.table {
width: 100%;
display: flex;
justify-content: center;
font-size: 18px;
font-weight: bold;
border-bottom: 1px solid #fff;
icon {
font-size: 45px;
margin-top: -30px;
background: #fff;
border-radius: 50%;
width: 45px;
height: 45px;
position: absolute;
right: 16px;
}
}
.foodlist {
border-radius: 0;
height: 40%;
overflow: scroll;
margin-top: 15px;
.text {
width: 100%;
font-weight: bold;
font-size: 14px;
display: flex;
height: 40px;
line-height: 40px;
text {
width: 20%;
}
:nth-child(1) {
width: 25%;
}
:nth-child(5) {
width: 15%;
text-align: right;
}
}
.item {
display: flex;
// justify-content: space-between;
align-items: center;
height: 40px;
line-height: 40px;
font-size: 16px;
view {
width: 20%;
text-align: left;
}
:nth-child(5) {
width: 15%;
text-align: right;
}
}
.kcal {
width: 60% !important;
text-align: center !important;
}
.name {
width: auto;
float: left;
font-size: 14px;
font-weight: 500;
width: 25% !important;
}
}
.title {
width: 100%;
padding: 0;
margin-top: 10px;
overflow: hidden;
position: absolute;
bottom: 10px;
top: 50%;
left: 0;
right: 0;
/deep/.weightPages {
top: 15px;
display: block;
}
}
.groupbtn {
position: absolute;
left: 15px;
right: 15px;
width: auto;
bottom: 50px;
}
}
</style>

51
pageTwo/me/mymenu.vue Normal file
View File

@ -0,0 +1,51 @@
<template>
<view class="content">
<!-- 搜索 -->
<search @handleSearch="handleSearch"></search>
<!-- 食谱 -->
<view class="itemTag footbox">
<view class="tab_list">
<view class="tabbar" v-for="(ite,ind) in list" :key="ind" @click="handleToggle(ind)">
<view :class="[index ==ind?'active':'']">{{ite.name}}</view>
</view>
</view>
<foodList :title="type"></foodList>
</view>
</view>
</template>
<script>
import search from "../../components/search.vue"
import foodList from "../../components/list.vue"
export default {
data() {
return {
type: ""
}
},
components: {
search,
foodList
},
onLoad(option) {
let that = this
console.log("列表", option)
that.type = option.pageName
uni.setNavigationBarTitle({
title: that.type
});
},
methods: {
//
handleZan() {},
//
handleSearch(ite) {
console.log("我的菜谱搜索", ite)
}
}
}
</script>
<style lang="scss" scoped>
</style>

152
pageTwo/me/record.vue Normal file
View File

@ -0,0 +1,152 @@
<template>
<view class="content">
<!-- 日期搜索 -->
<view class="calendar">
<ren-calendar ref='ren' :markDays='markDays' @maskClick="maskClick" @onMonthClickPre='onMonthClickPre'
@onMonthClickNext="onMonthClickNext">
</ren-calendar>
</view>
<!-- 列表 -->
<view class="box">
<view class="list" v-for="(item,ind) in list" :key="ind" @click="handleDetail(item)">
<view class="time">{{item.time}}</view>
<view class="kcal">
<view>摄入卡路里<text>{{item.kcal}}</text>kcal</view>
<view class="status">
<text class="quan" :class="[item.status==1?'quan1':item.status==2?'quan2':'']"></text>
{{item.status==1?'达标':item.status==2?'未达标':'超标'}}
</view>
<icon class="iconfont icon-arrow-right"></icon>
</view>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
import RenCalendar from '@/uni_modules/ren-calendar/ren-calendar.vue';
export default {
data() {
return {
single: "",
list: [],
markDays: {
warning: ['2023-07-04'],
success: ["2023-07-03"],
error: ["2023-07-02"],
}
}
},
components: {
RenCalendar,
},
computed: {
...mapState(["user"]),
end() {
return this.$tools.getTime()
},
},
onLoad() {
let that = this
that.list = that.$json.recordList
},
methods: {
//
maskClick(e) {
console.log('maskClick事件:', e);
},
onMonthClickPre(data) {
console.log("上月", data)
},
onMonthClickNext(data) {
console.log("下月", data)
},
handleDetail(item) {
let that = this
uni.setStorageSync("startDay", "2023-07-02")
uni.switchTab({
url: '/pages/count/count',
});
}
}
}
</script>
<style scoped="scoped" lang="scss">
.content {
padding: 0 15px;
}
.calendar {
text-align: center;
background: #fff;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 20;
height: 40px;
line-height: 40px;
box-shadow: 0px 1px 5px 2px #dfe2e1fc;
}
.box {
margin-top: 55px;
width: 100%;
}
.list {
color: #999;
width: calc(100% - 30px);
background: #fff;
margin-bottom: 15px;
border-radius: 15px;
padding: 10px 15px;
.time {
width: 100%;
height: 30px;
line-height: 30px;
}
.kcal {
display: flex;
justify-content: space-between;
align-items: center;
text {
font-size: 16px;
font-weight: bold;
margin: 0 3px;
color: #000;
}
.status {
width: 85px;
}
.quan {
width: 12px;
height: 12px;
background: $uni-color-warning;
display: inline-block;
border-radius: 50%;
margin-right: 5px;
}
.quan1 {
background: $uni-color-success;
}
.quan2 {
background: $mainColor;
}
}
}
</style>

280
pageTwo/me/userEdit.vue Normal file
View File

@ -0,0 +1,280 @@
<template>
<view class="content">
<view class="lanBox">
<view class="headbox">
<view class="touxiang">
<uni-file-picker :imageStyles="imageStyles" @select="handleimg" file-mediatype="image"
disable-preview limit="1" :del-icon="false">
<image v-if="memInfo.headimg" :src="memInfo.headimg" class="headimage" />
<icon v-else class="headimage t-icon t-icon-nvtouxiang"></icon>
</uni-file-picker>
</view>
</view>
<view class="lan border-bottom">
<view class="left">昵称</view>
<view class="right">
<input name="name" type="text" v-model="memInfo.name" placeholder="请输入昵称" class="name" />
<icon class="iconfont icon-bianji" v-if="!memInfo.name"></icon>
<icon class="iconfont icon-error" v-else @click="memInfo.name=''"></icon>
</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">
<picker mode="selector" :range="ageArr" @change="onageArr">
<view class="uni-input">{{!memInfo.age?'请选择年龄':memInfo.age+'岁'}}</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" v-model="memInfo.height" placeholder="请输入身高" />
<text>cm</text>
</view>
</view>
<view class="lan border-bottom">
<view class="left">体重</view>
<view class="right">
<input type="digit" v-model="memInfo.weight" placeholder="请输入体重" />
<text>kg</text>
</view>
</view>
</view>
<view class="btn" @click="confirmInfo">提交</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
export default {
data() {
return {
imageStyles: {
width: 65,
height: 65,
border: {
radius: '50%'
},
},
ageArr: [],
sexItem: [
"男",
"女"
],
isEdit: false,
memInfo: {
age: "",
height: "",
weight: "",
sex: "",
name: "",
headimg: ""
},
};
},
computed: {
...mapState(["user", "appTheme"]),
},
methods: {
//
confirmInfo() {
let that = this
if (!this.memInfo.name) {
this.$tools.msg("请输入昵称")
return;
}
if (!this.memInfo.sex) {
this.$tools.msg("请选择性别")
return;
}
if (!this.memInfo.age) {
this.$tools.msg("请选择年龄")
return;
}
if (!this.memInfo.height) {
this.$tools.msg("请输入身高")
return;
}
if (!this.memInfo.weight) {
this.$tools.msg("请输入体重")
return;
}
// console.log("", this.memInfo)
that.subInfo(this.memInfo)
},
subInfo(data) {
let that = this
that.$model.getsubmit(data).then(res => {
if (res.code == 0) {
that.$tools.msg("提交成功");
uni.navigateBack({
delta: 1
});
} else {
that.$tools.msg(res.message);
}
});
},
//
onsexArr(e) {
this.memInfo.sex = this.sexItem[e.target.value] == "男" ? 1 : 2
},
//
onageArr(e) {
this.memInfo.age = this.ageArr[e.target.value]
},
//
handleimg(e) {
let that = this
that.memInfo.headimg = e.tempFilePaths[0]
}
},
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 = {
age: "",
height: "",
weight: "",
sex: "",
name: "",
headimg: ""
}
}
},
};
</script>
<style scoped="scoped" lang="scss">
.content {
padding: 0 15px;
}
.lanBox {
margin-top: 15px;
padding: 15px 15px 0;
width: calc(100% - 30px);
background: #fff;
border-radius: 10px;
.headbox {
text-align: center;
position: relative;
display: flex;
justify-content: center;
height: 65px;
margin-bottom: 15px;
.headimage {
display: block;
width: 65px;
height: 65px;
font-size: 65px;
border-radius: 50%;
}
}
}
.lan {
display: flex;
align-items: center;
font-size: 14px;
height: 50px;
line-height: 50px;
border-bottom: 1px solid #f7f7f7;
.left {
width: 24%;
text-align: left;
}
.right {
display: flex;
align-items: center;
justify-content: flex-end;
width: 76%;
height: 50px;
position: relative;
text-align: right;
/deep/input {
height: 50px;
line-height: 50px;
border: none;
background: inherit;
width: 100%;
}
.name {
padding-right: 25px;
}
picker {
width: 100%;
text-align: right;
border: none;
margin-right: 8px;
view {
padding-right: 18px;
color: #828282;
font-size: 14px;
}
}
text {
display: inline-block;
width: 30px;
text-align: right;
color: #828282;
}
.iconfont {
color: #828282;
position: absolute;
right: 0px;
top: 0;
width: 30px;
justify-content: flex-end;
}
}
}
.btn {
color: #fff;
width: 100%;
}
</style>

155
pages.json Normal file
View File

@ -0,0 +1,155 @@
{
"pages": [ //pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页"
}
}, {
"path": "pages/menu/menu",
"style": {
"navigationBarTitleText": "菜谱",
"enablePullDownRefresh": false
}
},
{
"path": "pages/add/add",
"style": {
"navigationBarTitleText": "添加食谱",
"enablePullDownRefresh": false
}
}, {
"path": "pages/count/count",
"style": {
"navigationBarTitleText": "计食器",
"enablePullDownRefresh": false
}
}, {
"path": "pages/me/me",
"style": {
"navigationBarTitleText": "个人中心",
"enablePullDownRefresh": false
}
}
],
"subPackages": [{
"root": "pageTwo",
"pages": [{
"path": "login/login",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}, {
"path": "me/feedBack",
"style": {
"navigationBarTitleText": "意见反馈",
"navigationBarBackgroundColor": "#F9FAFC"
}
}, {
"path": "me/userEdit",
"style": {
"navigationBarTitleText": "个人资料",
"navigationBarBackgroundColor": "#F9FAFC"
}
}, {
"path": "me/record",
"style": {
"navigationBarTitleText": "饮食记录",
"enablePullDownRefresh": false
}
}, {
"path": "me/mymenu",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}, {
"path": "me/menudetail",
"style": {
"navigationBarTitleText": "详情",
"enablePullDownRefresh": false
}
}, {
"path": "me/foodlist",
"style": {
"navigationBarTitleText": "食材库",
"enablePullDownRefresh": false
}
}, {
"path": "count/setting",
"style": {
"navigationBarTitleText": "设置",
"enablePullDownRefresh": false
}
}, {
"path": "count/KcalEdit",
"style": {
"navigationBarTitleText": "自定义卡路里",
"enablePullDownRefresh": false
}
},{
"path": "count/food",
"style": {
"navigationBarTitleText": "食材库",
"enablePullDownRefresh": false
}
}]
}],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#efefef",
"backgroundColor": "#efefef"
}, //
"tabBar": {
"color": "#333",
"selectedColor": "#ff4c4f",
"backgroundColor": "#fff",
"list": [{
"pagePath": "pages/index/index",
"iconPath": "static/home.png",
"selectedIconPath": "static/home01.png",
"text": "首页"
},
{
"pagePath": "pages/menu/menu",
"iconPath": "static/cai.png",
"selectedIconPath": "static/cai01.png",
"text": "菜谱"
},
{
"pagePath": "pages/add/add",
"iconPath": "static/add.png",
"selectedIconPath": "static/add.png",
"text": ""
},
{
"pagePath": "pages/count/count",
"iconPath": "static/ji.png",
"selectedIconPath": "static/ji01.png",
"text": "计食器"
},
{
"pagePath": "pages/me/me",
"iconPath": "static/me.png",
"selectedIconPath": "static/me01.png",
"text": "我的"
}
]
},
"uniIdRouter": {}
}

334
pages/add/add.vue Normal file
View File

@ -0,0 +1,334 @@
<template>
<view class="content addFood">
<!-- 菜谱介绍 -->
<view class="topimg">
<uni-file-picker :imageStyles="imageStyles" @select="handleFMimg" file-mediatype="image" disable-preview
limit="1">
<icon class="iconfont icon-add"></icon>
<text class="text">上传封面</text>
<text>(单张图片)</text>
</uni-file-picker>
</view>
<view class="title">
<input type="text" v-model="info.title" placeholder="输入菜谱标题" />
</view>
<view class="textarea">
<textarea v-model="info.content" name="content" placeholder="输入菜谱简介" maxlength="100" />
</view>
<!-- 添加食材 -->
<view class="food" v-if="isFood">
<view class="h4">
添加食材
<text class="close" @click="handleClose" v-if="info.list.length">清空</text>
</view>
<view class="foodlist" v-for="(ite,ind) in info.list" :key="ind" v-if="info.list.length">
<view class="item">
<view class="name">{{ite.name}}</view>
<view class="input">
<input class="text" placeholder="请输入用量" v-model="ite.weight" type="digit" />{{ite.unit}}
</view>
<view class="edit">
<icon class="iconfont icon-ashbin" @click="handledel(ind,'food')"></icon>
<image src="../../static/xia.png" @click="handleMove(ind,0,'food')" class="xia"></image>
<image src="../../static/xia.png" @click="handleMove(ind,1,'food')" class="shang xia"></image>
</view>
</view>
</view>
<view class="add" @click="handleAddfood">+添加食材</view>
</view>
<!-- 添加步骤 -->
<view class="step">
<view class="h4">添加步骤</view>
<view class="stepList" v-for="(ite,ind) in info.stepList" :key="ind" v-if="info.stepList.length">
<view class="top">
<text>步骤{{ind+1}}</text>
<view class="edit">
<icon class="iconfont icon-ashbin" @click="handledel(ind,'step')"></icon>
<image src="../../static/xia.png" @click="handleMove(ind,0,'step')" class="xia"></image>
<image src="../../static/xia.png" @click="handleMove(ind,1,'step')" class="shang xia"></image>
</view>
</view>
<view class="right">
<view class="image">
<uni-file-picker :imageStyles="imageStyles" file-mediatype="image" :index="ind"
@select="handleBZimage" limit="1">
<icon class="iconfont icon-add"></icon>
<text class="text">上传图片</text>
</uni-file-picker>
</view>
<view class="textarea">
<textarea v-model="ite.content" name="content" placeholder="输入步骤说明" maxlength="100" />
</view>
</view>
</view>
<view class="add" @click="handleAddstep">+添加步骤</view>
</view>
<!-- 保存 -->
<view class="groupbtn">
<view @click="handleLook"> 预览</view>
<view class="subbtn"> 保存</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
export default {
data() {
return {
isFood: true,
info: {
FMimg: "",
title: "",
content: "",
list: [],
stepList: []
},
imageStyles: {
width: '100%',
height: 331,
},
}
},
computed: {
...mapState(["user"])
},
onLoad() {},
methods: {
//
getAddFood(list) {
let that = this
list.forEach(ite => {
ite.weight = null
})
that.info.list = list
console.log("list", list)
},
//
handleClose() {
let that = this
that.info.list = []
},
//
handleAddfood() {
let that = this
uni.navigateTo({
url: "/pageTwo/me/foodlist"
})
},
// /
handledel(id, type) {
let that = this
let name = type == 'step' ? '步骤' : '食材'
let list = type == 'step' ? that.info.stepList : that.info.list
uni.showModal({
title: '友情提示',
content: '是否删除当前' + name,
success: function(res) {
if (res.confirm) {
list.splice(list.findIndex((ite, ind) => ind === id), 1)
} else if (res.cancel) {
that.$tools.msg("您已取消操作!");
}
},
})
},
//
handleMove(ind, dir, type) {
let that = this
let list = type == 'step' ? that.info.stepList : that.info.list
let moveComm = (curIndex, nextIndex) => {
let arr = type == 'step' ? that.info.stepList : that.info.list
arr[curIndex] = arr.splice(nextIndex, 1, arr[curIndex])[0]
return arr
}
list.some((val, index) => {
if (index === ind) {
if (dir === 1 && index === 0) {
this.$tools.msg('已在顶部!')
} else if (dir === 0 && index === list.length - 1) {
this.$tools.msg('已在底部!')
} else {
let nextIndex = dir === 1 ? index - 1 : index + 1
list = moveComm(index, nextIndex)
}
return true
}
return false
})
},
//
handleAddstep() {
let that = this
that.info.stepList.push({
image: null,
content: null,
})
},
//
handleFMimg(e) {
let that = this
that.info.FMimg = e.tempFilePaths[0]
console.log('选择文件:', e.tempFilePaths[0])
},
//
handleBZimage(e) {
let that = this
that.info.stepList[e.index].image = e.tempFilePaths[0]
console.log('选择文件:', e, that.info.stepList)
},
handleLook() {
let that = this
if (!that.info.FMimg) {
that.$tools.msg("请上传封面图!")
return
}
if (!that.info.title) {
that.$tools.msg("请输入菜谱标题!")
return
}
if (!that.info.content) {
that.$tools.msg("请输入菜谱简介!")
return
}
if (!that.info.list.length) {
that.$tools.msg("请添加食材!")
return
}
let array = []
that.info.list.forEach(ite => {
if (ite.weight != null || ite.weight > 0) {
array.push(ite.weight)
}
})
if (array.length != that.info.list.length) {
that.$tools.msg("请输入食材重量!")
return
}
if (!that.info.stepList.length) {
that.$tools.msg("请添加步骤!")
return
}
if (that.info.stepList.length) {
let array = []
that.info.stepList.forEach(ite => {
if (ite.image != null && ite.content != null) {
array.push(ite.image)
return
}
})
if (array.length != that.info.stepList.length) {
that.$tools.msg("请完善步骤!")
return
}
}
that.info.pageName = "菜谱预览"
that.info.user = that.user
console.log("预览info", that.info)
uni.navigateTo({
url: "/pageTwo/me/menudetail?info=" + JSON.stringify(that.info)
})
}
}
}
</script>
<style scoped lang="scss">
.content {
padding: 0 15px;
}
.topimg {
width: 100%;
height: 320px;
background: #fff;
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
flex-direction: column;
margin-bottom: 10px;
overflow: hidden;
position: relative;
.iconfont {
font-size: 30px;
color: $mainColor;
}
text {
display: inline-block;
width: 100%;
text-align: center;
font-size: 12px;
color: #999;
}
.text {
font-size: 16px;
color: #666;
margin-bottom: 3px;
}
image {
width: 100%;
height: inherit;
}
}
.step {
.image {
height: 320px;
margin: auto;
background: #f7f7f7;
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
flex-direction: column;
overflow: hidden;
image {
width: 100%;
height: inherit;
display: inline-table;
}
icon {
font-size: 30px;
color: #ff4c4f;
margin-bottom: 5px;
}
}
}
/deep/.is-add {
flex-wrap: wrap;
flex-direction: column;
}
.title,
.textarea {
/deep/input {
height: 40px;
line-height: 40px;
}
/deep/textarea {
width: 100%;
height: 6rem;
line-height: 20px;
background: none;
border: none;
font-size: 14px;
padding-top: 10px;
}
}
</style>

530
pages/count/count.vue Normal file
View File

@ -0,0 +1,530 @@
<template>
<view class="content">
<view class="box" v-if="userinfo&&userinfo.weight">
<!-- 日期搜索 -->
<view class="calendar">
<ren-calendar ref='ren' :startDay="startDay" :markDays='markDays' @maskClick="maskClick"
@onMonthClickPre='onMonthClickPre' @onMonthClickNext="onMonthClickNext">
</ren-calendar>
</view>
<view class="kcal">
<view class="set" @click="handleSet">
<icon class="iconfont icon-shezhi1"></icon>
</view>
<view class="top">
<!-- 进度 -->
<view class="left ">
<qiun-data-charts type="arcbar" :chartData="chartData" :canvas2d="true" canvasId="chartsId" />
<view class="center">
还能吃
<text>1256</text>
</view>
</view>
<view class="right">
<text>建议摄入</text>
<text class="num">1294</text>
</view>
</view>
<view class="weight">
<view class="item">
<text>碳水化合物</text>
<view class="bold">
<view class="val" :style="{ width: percent + '%'}"></view>
<text>12/125</text>
</view>
</view>
<view class="item">
<text>蛋白质</text>
<view class="bold">
<view class="val" :style="{ width: percent + '%'}"></view>
<text>12/125</text>
</view>
</view>
<view class="item">
<text>脂肪</text>
<view class="bold">
<view class="val" :style="{ width: percent + '%'}"></view>
<text>12/125</text>
</view>
</view>
</view>
</view>
<!-- -->
<view class="tabbar">
<view class="type" @click="handleAddFood(0,'早餐')">
<icon class="t-icon t-icon-yingyangzaocan"></icon>
<view class="text">
<icon class="iconfont icon-add"></icon>早餐
</view>
</view>
<view class="type" @click="handleAddFood(1,'午餐')">
<icon class="t-icon t-icon-jiucan"></icon>
<view class="text">
<icon class="iconfont icon-add"></icon>午餐
</view>
</view>
<view class="type" @click="handleAddFood(2,'晚餐')">
<icon class="t-icon t-icon-wancan1"></icon>
<view class="text">
<icon class="iconfont icon-add"></icon>晚餐
</view>
</view>
<view class="type" @click="isShow = true">
<icon class="t-icon t-icon-jiacan"></icon>
<view class="text">
<icon class="iconfont icon-add"></icon>加餐
</view>
</view>
</view>
<!-- -->
<view class="list" v-if="list.length">
<view class="listbox" v-for="(ite,ind) in list" :key="ind">
<view class="left">
<view class="title">{{ite.title}}</view>
<view class="kcalval">
<text>1250</text>kcal
</view>
</view>
<view class="right">
<view class="item" v-for="(it,id) in ite.list" :key="id">
<text>{{it.name}}</text>
<text>{{it.weight}}{{it.unit}}</text>
<text>{{it.kcal?it.kcal:'125'}}kcal</text>
</view>
</view>
</view>
</view>
<view v-else class="nolist list">
<icon class="iconfont icon-zanwushuju"></icon>
<text>还没有记录点击上方按钮添加</text>
</view>
</view>
<view v-else class="nolist list2" @click="handleEditUser()">
<view>
<icon class="iconfont icon-zanwushuju"></icon>
<text>完善资料后记录更准确哦</text>
</view>
<view class="btn">完善资料</view>
</view>
<!-- 加餐 -->
<view class="wrapper activeList" v-if="isShow">
<view class="bg" @click='isShow=false'>
<view class="addfood" @click.stop>
<icon class="iconfont icon-error" @click='isShow=false'></icon>
<view class="list">
<view class="item" v-for="(ite,ind) in addfoodList" :key="ind"
@click="handleAddFood(ite.id,ite.name)">
<text class="name">{{ite.name}}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
let next = 0
import RenCalendar from '@/uni_modules/ren-calendar/ren-calendar.vue';
import qiunDataCharts from '@/uni_modules/qiun-data-charts/components/qiun-data-charts.vue';
export default {
data() {
return {
list: [],
start: "",
percent: 55,
status: true,
userinfo: {},
isShow: false,
chartData: {
"series": [{
"data": 0.8,
"color": "#ff4c4f"
}]
},
addfoodList: [{
name: "早加餐",
id: 3,
},
{
name: "午加餐",
id: 4,
}, {
name: "晚加餐",
id: 5,
}
],
markDays: {
warning: ['2023-07-04'],
success: ["2023-07-03"],
error: ["2023-07-02"],
},
startDay: ""
}
},
components: {
RenCalendar,
qiunDataCharts
},
computed: {
...mapState(["user"]),
},
onLoad(options) {
let that = this
that.startDay = this.$tools.getDate("start")
that.userinfo = that.$store.state.user
},
onShow() {
let that = this
let start = uni.getStorageSync("startDay")
if (start) {
console.log(start);
that.startDay = start;
uni.removeStorageSync('startDay');
} else if (that.startDay != that.$tools.getDate("start")) {
that.startDay = this.$tools.getDate("start")
console.log("111")
}
},
methods: {
//
getstartDay(date) {
let that = this
that.startDay = date
console.log("选定日期", date)
},
//
getAddFood(list) {
let that = this
that.list.push(list)
console.log("list", that.list, that.list.sort())
},
//
maskClick(e) {
console.log('maskClick事件:', e);
},
onMonthClickPre(data) {
console.log("上月", data)
},
onMonthClickNext(data) {
console.log("下月", data)
},
//
handleSet() {
uni.navigateTo({
url: "/pageTwo/count/setting"
})
},
//
handleEditUser() {
uni.navigateTo({
url: "/pageTwo/me/userEdit?type=add"
})
},
//
handleAddFood(ind, name) {
this.isShow = false
uni.navigateTo({
url: "/pageTwo/count/food?name=" + name + '&ind=' + ind
})
}
}
}
</script>
<style scoped lang="scss">
.content {
padding: 0 15px;
}
.box {
width: 100%;
}
.calendar {
text-align: center;
background: #fff;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 20;
height: 40px;
line-height: 40px;
box-shadow: 0px 1px 5px 2px #dfe2e1fc;
}
.kcal {
width: calc(100% - 20px);
margin-bottom: 15px;
background: #fff;
border-radius: 5px;
padding: 10px;
position: relative;
margin-top: 60px;
.set {
position: absolute;
right: 15px;
width: 50px;
height: 50px;
display: flex;
align-items: flex-start;
justify-content: flex-end;
font-weight: bold;
z-index: 18;
icon {
font-size: 22px;
}
}
.top {
margin-left: 5px;
position: relative;
.left {
width: 300rpx;
height: 300rpx;
position: relative;
.center {
position: absolute;
top: 0;
text-align: center;
width: 300rpx;
height: 300rpx;
display: flex;
flex-wrap: wrap;
flex-direction: column;
align-items: center;
justify-content: center;
text {
display: inline-block;
font-size: 22px;
font-weight: bold;
}
}
}
.right {
position: absolute;
left: 65%;
height: 300rpx;
top: 0;
display: flex;
flex-wrap: wrap;
justify-content: center;
flex-direction: column;
.num {
font-size: 24px;
font-weight: bold;
width: 100%;
display: inline-block;
margin-top: 5px;
}
}
}
.weight {
width: 100%;
display: flex;
margin-top: 25px;
margin-bottom: 5px;
justify-content: space-between;
.item {
width: 30%;
.bold {
width: 100%;
background: #eaeaea;
border-radius: 6px;
margin-top: 5px;
text-align: right;
font-weight: 500;
font-size: 12px;
height: 15px;
line-height: 15px;
position: relative;
text {
position: absolute;
z-index: 6;
right: 8px;
}
}
.val {
position: absolute;
left: 0;
background: #f9ce27;
height: 15px;
border-radius: 10px;
z-index: 2;
}
}
}
}
.tabbar {
width: 100%;
background: #fff;
border-radius: 10px;
padding: 10px 0;
display: flex;
margin-bottom: 15px;
justify-content: space-between;
.type {
width: 20%;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
.t-icon {
width: 35px;
height: 35px;
font-size: 28px;
}
.text {
width: 100%;
text-align: center;
margin-top: 5px;
display: flex;
justify-content: center;
icon {
font-size: 14px;
}
}
}
}
.list {
width: 100%;
padding-bottom: 50px;
.listbox {
width: calc(100% - 20px);
padding: 10px;
border-radius: 10px;
background-color: #fff;
margin-top: 15px;
}
.left {
width: 100%;
margin-bottom: 10px;
display: flex;
align-items: center;
.title {
font-size: 16px;
font-weight: bold;
}
text {
font-weight: bold;
margin-right: 5px;
margin-left: 15px;
}
}
.right {
width: calc(100% - 20px);
margin: 0 10px;
.item {
height: 35px;
line-height: 35px;
border-bottom: 1px solid #f7f7f7;
display: flex;
justify-content: space-between;
:nth-child(1) {
width: 45%;
}
:nth-child(2) {
width: 25%;
}
}
}
}
.nolist {
font-size: 12px;
color: #999;
padding: 30px 10px;
text-align: center;
width: auto;
icon {
font-size: 50px;
color: #999;
display: flex;
justify-content: center;
margin-bottom: 10px;
}
}
.list2 {
margin-top: 45%;
.btn {
color: #fff;
height: 32px;
line-height: 32px;
}
}
.addfood {
background-color: #fff;
position: absolute;
left: 0;
right: 0;
bottom: 0;
padding: 10px 10px 0 10px;
border-radius: 10px 10px 0 0;
.iconfont {
position: absolute;
right: 7px;
top: -10px;
background: #f7f7f7;
border-radius: 50%;
font-size: 30px;
}
.list {
padding-bottom: 0px;
.item {
height: 40px;
line-height: 40px;
border-bottom: none;
}
.name {
width: 100%;
text-align: center;
}
:nth-child(2).item {
border-bottom: 1px solid #dfdfdf;
border-top: 1px solid #dfdfdf;
}
}
}
</style>

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

@ -0,0 +1,218 @@
<template>
<view class="content">
<!-- 搜索 -->
<search @handleSearch="handleSearch"></search>
<!-- 轮播 -->
<view class="f_banner footbox" v-if="fimages.length">
<swiper class="swiper" circular="true" previous-margin="15px" next-margin="15px">
<swiper-item v-for="(ite, ind) in fimages" :key="ind" @click="handleDetail(ite)">
<image :src="ite.image" mode="aspectFill">
<view class="item">
<view class="title">{{ite.title}}</view>
<view class="name">
<image :src="ite.head"></image>
<text>{{ite.name}}</text>
</view>
<view class="zan" @click="handleZan(ite)">
<icon class="iconfont" :class="[ite.iszan?'icon-icon3':'icon-icon_collect']"></icon>
</view>
</view>
</image>
</swiper-item>
</swiper>
</view>
<!-- 功能 -->
<view class="tools footbox">
<view class="list" v-for="(ite,ind) in tools" :key="ind" @tap="navTo(ite.path)">
<!-- <image :src="ite.image"></image> -->
<view>
<icon :class="ite.icon"></icon>
</view>
<text>{{ite.text}}</text>
</view>
</view>
<!-- 食谱 -->
<view class="itemTag footbox">
<view class="tab_list">
<view class="tabbar" v-for="(ite,ind) in list" :key="ind" @click="handleToggle(ind)">
<view :class="[index ==ind?'active':'']">{{ite.name}}</view>
</view>
</view>
<foodList></foodList>
</view>
</view>
</template>
<script>
import search from "../../components/search.vue"
import foodList from "../../components/list.vue"
export default {
data() {
return {
index: 0,
fimages: [],
list: [{
"name": "早餐"
},
{
"name": "午餐"
},
{
"name": "晚餐"
},
{
"name": "酒水"
}
],
tools: [{
path: "/pages/menu/menu",
text: "菜谱分类",
icon: "t-icon t-icon-shipinyinliao2-chengzi "
}, {
path: "/pageTwo/me/mymenu?pageName=我的收藏",
text: "我的收藏",
icon: "t-icon t-icon-shipinbeifen "
}, {
path: "/pages/count/count",
text: "热量计算",
icon: "t-icon t-icon-shiwureliang"
}, {
path: "pageTwo/me/record",
text: "饮食记录",
icon: "t-icon t-icon-shouyedaohangtubiao-jiankangshipin"
}],
}
},
components: {
search,
foodList
},
onShow(options) {
let that = this
that.fimages = that.$json.fimages
},
methods: {
//
handleToggle(index) {
let that = this
that.index = index
},
//
handleDetail() {
uni.navigateTo({
url: "/pageTwo/me/menudetail"
})
},
//
handleSearch(ite) {
console.log("首页搜索", ite)
},
//
handleZan() {},
//
navTo(url) {
// if (!uni.getStorageSync('token')) {
// return
// }
uni.navigateTo({
url
})
uni.switchTab({
url
})
},
}
}
</script>
<style lang="scss" scoped>
.f_banner {
width: 100% !important;
height: 450rpx;
margin-top: 50px;
/deep/swiper {
height: 450rpx;
}
image {
width: calc(100% - 10px);
height: 100%;
background-size: 100%;
margin: 0 5px;
border-radius: 10px;
}
}
.tools {
width: calc(100% - 30px);
background: #fff;
display: flex;
border-radius: 5px;
margin-top: 35px !important;
justify-content: space-between;
.list {
display: flex;
flex-wrap: wrap;
padding-bottom: 10px;
justify-content: center;
image,
icon {
width: 55px;
height: 55px;
}
view {
width: 55px;
height: 55px;
background-color: #fff;
margin-top: -20px;
border-radius: 50%;
text-align: center;
margin-bottom: 5px;
}
icon {
margin-top: 10px;
width: 35px;
height: 35px;
}
text {
display: block;
width: 100%;
text-align: center;
}
}
}
.tab_list {
display: flex;
justify-content: left;
.tabbar {
padding: 0 10px;
font-size: 16px;
font-weight: bold;
}
.active {
color: $mainColor;
border-bottom: 2px solid $mainColor;
}
}
.itemTag {
margin-top: 20px !important;
}
.t-icon-shipinyinliao2-chengzi {
width: 40px !important;
height: 33px !important;
}
</style>

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

@ -0,0 +1,125 @@
<template>
<view class="content">
<view class="head">
<icon class="t-icon t-icon-nvtouxiang"></icon>
<text>栗子</text>
</view>
<view class="list">
<view class="item" @tap="navTo('/pageTwo/me/mymenu?pageName=我的菜谱')">
<text>我的菜谱</text>
<icon class="iconfont icon-arrow-right"></icon>
</view>
<view class="item" @tap="navTo('/pageTwo/me/mymenu?pageName=我的收藏')">
<text>我的收藏</text>
<icon class="iconfont icon-arrow-right"></icon>
</view>
<view class="item" @tap="navTo('/pageTwo/me/userEdit')">
<text>个人资料</text>
<icon class="iconfont icon-arrow-right"></icon>
</view>
<view class="item" @tap="navTo('/pageTwo/me/record')">
<text>饮食记录</text>
<icon class="iconfont icon-arrow-right"></icon>
</view>
<view class="item" @tap="navTo('/pageTwo/me/feedBack')">
<text>联系客服</text>
<icon class="iconfont icon-arrow-right"></icon>
</view>
</view>
<view class="btn " v-if="!token" @click="handleOutLogin">退出登录</view>
</view>
</template>
<script>
export default {
data() {
return {
token: null
}
},
onLoad() {
let that = this
that.token = uni.getStorageSync('token')
},
methods: {
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
uni.setStorageSync('sessionid', null)
uni.setStorageSync('token', null)
that.$store.commit("changeLogout", false);
that.handleLogin()
})
} else if (res.cancel) {
that.$tools.msg("您已取消操作!");
}
},
})
},
navTo(url) {
// if (!uni.getStorageSync('token')) {
// this.$tools.msg("")
// return
// }
uni.navigateTo({
url
})
},
}
}
</script>
<style scoped lang="scss">
.content {
padding: 0 15px;
min-height: 100vh;
}
.head {
width: 100%;
height: 6rem;
background: #fff;
display: flex;
align-items: center;
border-radius: 10px;
font-size: 16px;
font-weight: bold;
icon {
width: 50px;
height: 50px;
margin: 0 15px;
}
}
.list {
width: 100%;
background: #fff;
margin: 15px;
border-radius: 10px;
line-height: 50px;
.item {
display: flex;
justify-content: space-between;
margin: 0 15px;
border-bottom: 1px solid #f7f7f7;
}
}
.btn {
width: 100%;
color: #fff;
}
</style>

83
pages/menu/menu.vue Normal file
View File

@ -0,0 +1,83 @@
<template>
<view class="content">
<!-- 搜索 -->
<search @handleSearch="handleSearch"></search>
<view class="box menu">
<!-- 左侧菜单栏 -->
<view class="left">
<view class="name" v-for="(ite,ind) in menu" :key="ind" :class="[index==ind?'active':'']"
@click="handleToggle(ind)">
{{ite.name}}
</view>
</view>
<!-- 右侧商品 -->
<view class="right">
<view class="right_list" v-for="(ite,ind) in menulist" :key="ind">
<view class="title" @click="handleList(ite)">
<view>{{ite.name}}</view>
<icon class="iconfont icon-arrow-right"></icon>
</view>
<view class="list" @click="handleDetail(ite)">
<view class="item" v-for="(it,id) in ite.list" :key="id">
<image :src="it.image" mode="aspectFill"></image>
<text>{{it.name}}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import search from "../../components/search.vue"
export default {
components: {
search
},
data() {
return {
text: "",
index: 0,
menu: [],
menulist: []
};
},
onLoad() {
let that = this
that.menu = that.$json.menu
that.text = that.menu[0].name
that.menulist = that.$json.menulist
},
methods: {
//
handleToggle(index) {
let that = this
that.index = index
that.text = that.menu[index].name
// console.log("111", that.menu[index].name)
},
//
handleList() {
uni.navigateTo({
url: "/pageTwo/me/mymenu?type=" + this.text
})
},
//
handleDetail() {
uni.navigateTo({
url: "/pageTwo/me/menudetail"
})
},
//
handleSearch(ite) {
console.log("菜谱搜索", ite)
},
}
}
</script>
<style lang="scss" scoped>
</style>

BIN
static/1-2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

BIN
static/1-3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

BIN
static/1-4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

BIN
static/Clear.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
static/add.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
static/bannar-1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

BIN
static/banner-2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 KiB

BIN
static/banner-3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

BIN
static/cai.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
static/cai01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
static/cheng.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
static/close.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
static/dan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
static/home.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
static/home01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
static/img.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
static/img2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 KiB

BIN
static/ji.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
static/ji01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
static/jiu.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
static/lianjie.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
static/me.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
static/me01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
static/pan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
static/xia.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

119
store/actions.js Normal file
View File

@ -0,0 +1,119 @@
import model from "../tools/model.js"
import tools from '@/tools/tools.js'
import config from '@/config.js'
// Action 包含异步操作请求API方法、回调函数提交mutaions更改state数据状态使之可以异步
export default {
//sessionId
getsessionId({
commit
}) {
return uni.login({
success(res) {
if (res.code) {
if (res.errMsg = "login:ok") {
model.onlogin({
code: res.code
}).then(ress => {
uni.setStorageSync('sessionid', ress.data.sessionid)
return ress
})
}
}
}
})
},
// 用户信息
getPetInfo({
commit
},
account) {
return model.getPetInfo(account).then(res => {
if (res.code != 0) false
uni.setStorageSync('petid', res.data.id);
commit('changePetInfo', res.data)
commit('changeInfoConf', res.data.conf)
});
},
// 获取历史记录
gethistoryList({
commit
}, account) {
return model.getList(account).then((res) => {
if (res.data && res.data.items) {
commit('changehistoryList', res.data.items)
} else {
commit('changehistoryList', null)
}
return res
})
},
// 宠物列表
getPetList({
commit
}) {
return model.getPetList({
pagenum: 20,
pagesize: 1
}).then((res) => {
if (res.data) {
commit("changePetList", res.data)
} else {
commit("changePetList", null)
}
return res
})
},
//养护提醒
getAlertList({
commit
}, account) {
return model.getAlertList(account).then(res => {
if (res.data && res.data.rows) {
commit('changeAlertList', res.data.rows)
} else {
commit('changeAlertList', null)
}
return res
})
},
//通知提醒
getNoticelist({
commit
}) {
return model.getnoticelist({}).then(res => {
if (res.data) {
commit('changeNoticelist', res.data)
} else {
commit('changeNoticelist', null)
}
return res
})
},
// 配置详情
getConfig({
commit
}) {
return model.getConfig({
appid: config.appid
}).then((res) => {
if (res.code == 0) {
commit("changeConfig", res.data)
}
})
},
// 枚举
getnumdata({
commit
}) {
return model.getnumdata({
appid: config.appid
}).then((res) => {
if (res.code == 0) {
commit("changenumdata", res.data)
}
})
},
}

66
store/index.js Normal file
View File

@ -0,0 +1,66 @@
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: "../../static/dan.png",
name: "季总蛋先生",
weight: 68,
age: 26,
height: 178,
sex: 1,
id: "",
mage: "",
iszan: false,
zan: 0
},
isedit: false,
isLogout: true,
isConnected: false,
isBluetoothTyle: false,
},
// mutations: Store中更改state数据状态的唯一方法(必须是同步函数)
mutations: {
/* 用户信息 */
changePetInfo(state, newData) {
state.user = newData
},
// 手动添加
changeEdit(state, newData) {
state.isedit = newData
},
//蓝牙状态
changeBluetooth(state, newData) {
state.isBluetoothTyle = newData
},
// 蓝牙连接状态
changeConnected(state, newData) {
state.isConnected = newData
},
// 退出登录
changeLogout(state, newData) {
if (newData == false) {
state.user = {
headimg: null,
name: "",
weight: 0,
birthday: "",
height: 0,
sex: 0,
id: "",
mage: "",
iszan: false,
zan: 0
}
}
state.isLogout = newData
},
},
// 模块化vuex
modules: {},
actions
})

60
tools/https.js Normal file
View File

@ -0,0 +1,60 @@
import tools from '@/tools/tools.js'
import store from '../store'
import config from '@/config.js'
let baseUrl = config.configPro.host
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) {
uni.request(httpDefaultOpts).then(
(res) => {
uni.hideLoading()
if (res[1].data.code == 401) {
uni.clearStorageSync()
store.commit("changeLogout", false);
store.commit("changePetInfo", null);
uni.setStorageSync('token', null)
uni.setStorageSync('sessionid', null)
uni.setStorageSync('refreshtoken', null)
uni.setStorageSync('petid', null)
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 = config.appid
return httpRequest(url, 'get', data)
}
const post = (url, data) => {
data.appid = config.appid
return httpRequest(url, 'post', data)
}
export default {
baseUrl,
get,
post
}

282
tools/model.js Normal file
View File

@ -0,0 +1,282 @@
import http from './https.js'
import tools from './tools.js'
import store from '@/store'
let options = [{
text: '删除',
style: {
backgroundColor: '#dd524d'
}
}]
export default {
onlogin(param) { // 登录
return http.post("/api/app/wxopen/onlogin", param).then(res => {
return res
})
},
getSendCode(param) { // 验证码
return http.post("/api/app/wxopen/sendcode", param).then(res => {
return res
})
},
getDeregister(param) { //手机号注册
return http.post("/api/app/wxopen/deregister", param).then(res => {
return res
})
},
getRegister(param) { // 微信授权登录
return http.post('/api/app/wxopen/register', param).then(res => {
return res
})
},
getConfig(param) { // 小程序配置
return http.post("/api/app/wxopen/config", param).then(res => {
return res
})
},
getoutlogin(param) { // 退出登录
return http.post("/api/app/wxopen/logout", param).then(res => {
return res
})
},
uploadimg(param) { // 图片上传
return http.post("/api/app/wxopen/uploadimg", param).then(res => {
return res
})
},
submitadvice(param) { // 意见反馈
return http.post("/api/app/wxopen/submitadvice", param).then(res => {
return res
})
},
getnumdata(param) { // 枚举数据
return http.get("/api/app/wxopen/getenumdata", param).then(res => {
return res
})
},
getinfo(param) { // 获取账户资料
return http.post("/api/app/wxopen/info", param).then(res => {
return res
})
},
// 记录管理
getAddinsect(param) { //添加驱虫记录
return http.post("/api/app/result/addinsect", param).then(res => {
return res
})
},
getAddvaccion(param) { //添加疫苗记录
return http.post("/api/app/result/addvaccion", param).then(res => {
return res
})
},
getAddweight(param) { //添加重量/身长记录
return http.post("/api/app/result/addweight", param).then(res => {
return res
})
},
getdelete(param) { //删除记录
return http.post("/api/app/result/delete", param).then(res => {
return res
})
},
getList(param) { //记录列表
return http.post("/api/app/result/list", param).then(res => {
let cidata = {
weight: {
categories: [],
series: [{
name: "体重",
color: "#5ba7ff",
data: [],
}]
},
height: {
categories: [],
series: [{
color: "#3fcba7",
name: "身长",
data: [],
}]
}
}
if (res.data && res.data.rows.length) {
let list = res.data.rows
list.forEach(item => {
item.options = options
cidata.weight.categories.push(item.recordtime);
cidata.height.categories.push(item.recordtime);
cidata.weight.series.forEach(ite => {
ite.data.push(item.weight)
})
cidata.height.series.forEach(ite => {
ite.data.push(item.height)
})
})
res.data.rows.cidata = cidata
}
return res
})
},
gettrandlist(param) { //身长/体重趋势列表
return http.post("/api/app/result/trendlist", param).then(res => {
if (res.code == 0) {
let list = res.data
let cidata = {
weight: {
categories: [],
series: [{
name: "体重",
color: "#5ba7ff",
data: [],
}]
},
height: {
categories: [],
series: [{
color: "#3fcba7",
name: "身长",
data: [],
}]
}
}
for (var i = 0; i < list.length; i++) {
cidata.weight.categories.push(list[i].recordtime);
cidata.height.categories.push(list[i].recordtime);
cidata.weight.series.forEach(item => {
item.data.push(list[i].weight)
})
cidata.height.series.forEach(item => {
item.data.push(list[i].height)
})
}
res.data.cidata = cidata
}
return res
})
},
// 宠物管理
getPetList(param) { //宠物列表
return http.post("/api/app/pet/list", param).then(res => {
let options = [{
text: '编辑',
style: {
backgroundColor: '#ccc'
}
}, {
text: '删除',
style: {
backgroundColor: '#dd524d'
}
}]
if (res.code == 0 && res.data && res.data.length) {
res.data.forEach(item => {
item.options = options
item.birthday = item.birthday.substring(0, 10)
})
}
return res
})
},
getPetDelete(param) { //宠物删除
return http.post("/api/app/pet/delete", param).then(res => {
return res
})
},
getPetInfo(param) { //宠物资料
return http.post("/api/app/pet/info", param).then(res => {
if (res.data.conf.alertlist.length) {
let alertlist = res.data.conf.alertlist //提醒类型
let insectlist = res.data.conf.insectlist //驱虫类型
let vaccionlist = res.data.conf.vaccionlist //疫苗类型
let petalerttype = store.state.enumdata.petalerttype
let petinsecttype = store.state.enumdata.petinsecttype
let vacciontype = store.state.enumdata.vacciontype
res.data.conf.alertlist = tools.jsonList(alertlist, petalerttype)
res.data.conf.insectlist = tools.jsonList(insectlist, petinsecttype)
res.data.conf.vaccionlist = tools.jsonList(vaccionlist, vacciontype)
}
return res
})
},
getPetSubmit(param) { //宠物信息提交
return http.post("/api/app/pet/submit", param).then(res => {
return res
})
},
getPetType(param) { //宠物类型列表
return http.post("/api/app/pet/typelist", param).then(res => {
return res
})
},
// ji记事本
getNotepadList(param) { //记事列表
return http.post("/api/app/notepad/list", param).then(res => {
if (res.data && res.data.rows.length) {
res.data.rows.forEach(item => {
item.options = options
})
}
return res
})
},
getNotepadDelete(param) { //记事删除
return http.post("/api/app/notepad/delete", param).then(res => {
return res
})
},
getNotepadSubmit(param) { //增加记事
return http.post("/api/app/notepad/submit", param).then(res => {
return res
})
},
// 提醒
getAlertList(param) { //提醒列表
return http.post("/api/app/alert/list", param).then(res => {
let options2 = [{
text: '忽略',
style: {
backgroundColor: '#dfdfdf'
}
}, {
text: '删除',
style: {
backgroundColor: '#dd524d'
}
}]
if (res.data && res.data.rows.length) {
res.data.rows.forEach(item => {
if (item.status == 1) {
item.options = options2
} else {
item.options = options
}
})
}
return res
})
},
getAlertDelete(param) { //提醒删除
return http.post("/api/app/alert/delete", param).then(res => {
return res
})
},
getAlertStatus(param) { //提醒状态修改
return http.post("/api/app/alert/setstatus", param).then(res => {
return res
})
},
getAlertSubmit(param) { //提醒信息提交
return http.post("/api/app/alert/submit", param).then(res => {
return res
})
},
getnoticelist(param) { //通知列表
return http.post("/api/app/alert/noticelist", param).then(res => {
return res
})
}
}

97
tools/tools.js Normal file
View File

@ -0,0 +1,97 @@
import $store from '@/store'
export default {
msg,
ab2hex,
getTime,
getDate,
getMonth,
GetDateStr,
}
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 msg(str) {
uni.showToast({
title: str,
icon: 'none'
})
}
//获取AddDayCount天后的日期
function GetDateStr(AddDayCount) {
var dd = new Date();
dd.setDate(dd.getDate() + 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 m + "月" + d + '日';
}
// 获取当前年、月、日、时、分、秒
function getTime() {
var date = new Date()
var y = date.getFullYear();
var m = (date.getMonth() + 1) < 10 ? "0" + (date.getMonth() + 1) : (date.getMonth() + 1); //获取当前月份的日期不足10补0
var d = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
let H = date.getHours() > 9 ? date.getHours() : '0' + date.getHours()
let Min = date.getMinutes() > 9 ? date.getMinutes() : '0' + date.getMinutes()
return y + '/' + m + '/' + d + " " + H + ':' + Min
}
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 === 'start') {
year = year;
return `${year}-${month}-${day}`;
}
if (type === 'month') {
return month + '月' + day + '日'
}
}
// 月初到月底
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";
};
};

80
uni.scss Normal file
View File

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

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": "#ff4c4f",
"title": {
"name": "",
"fontSize": 25,
"color": "#00FF00"
},
"subtitle": {
"name": "",
"fontSize": 15,
"color": "#666666"
},
"extra": {
"arcbar": {
"type": "circle",
"width": 15,
"backgroundColor": "#E9E9E9",
"startAngle":1.5,
"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

View File

@ -0,0 +1,541 @@
<template>
<view class="calendar_all">
<view class="date" @click="handleisCalen">
{{startDay?startDay:startdate}}
</view>
<view class="wrapper Calen" v-if="isCalen">
<view class="bg" @click='isCalen=false'>
<view class="addfood" @click.stop>
<!-- -->
<view class="calendar-wrapper">
<view class="header">
<view class="pre" @click="changeMonth('pre')">
<uni-icons type="back" size="20"></uni-icons>
</view>
<view>{{y+'年'+formatNum(m)+'月'}}</view>
<view class="next" @click="changeMonth('next')">
<uni-icons type="forward" size="20"></uni-icons>
</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 error"
v-if="isMarkDay(item.year, item.month, item.date,'error')&&item.isCurM">
</view>
<view class="markDay success"
v-if="isMarkDay(item.year, item.month, item.date,'success')&&item.isCurM">
</view>
<view class="markDay warning"
v-if="isMarkDay(item.year, item.month, item.date,'warning')&&item.isCurM">
</view>
</view>
</view>
</view>
<view class="level">
<view><text></text>超标</view>
<view><text></text>达标</view>
<view><text></text>未达标</view>
</view>
</view>
<!-- -->
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'ren-calendar',
props: {
// (0)
weekstart: {
type: Number,
default: 0
},
//
markDays: {
type: Object,
default: () => {
return {};
}
},
//
headerBar: {
type: Boolean,
default: true
},
//
open: {
type: Boolean,
default: true
},
//
collapsible: {
type: Boolean,
default: true
},
//
disabledAfter: {
type: Boolean,
default: true
},
//
startDay: {
type: String,
default: ""
}
},
data() {
return {
weektext: ['日', '一', '二', '三', '四', '五', '六'],
y: new Date().getFullYear(), //
m: new Date().getMonth() + 1, //
dates: [], //
positionTop: 0,
monthOpen: true,
choose: '',
month: null,
isCalen: false,
};
},
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.getMonth(this.$tools.getTime(), 0)
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';
},
startdate() {
return this.$tools.getDate("start")
}
},
methods: {
handleisCalen() {
console.log("店家")
this.isCalen = !this.isCalen
},
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, type) {
let flag = false;
let markDays = this.markDays[type]
for (let i = 0; i < markDays.length; i++) {
let dy = `${y}-${m}-${d}`;
if (markDays[i] == dy) {
flag = true;
break;
}
}
// console.log("isMarkDay", this.markDays, type, markDays)
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('maskClick', response);
}
} else {
this.choose = date;
this.$emit('maskClick', response);
}
this.start = response.date
this.isCalen = false
},
//
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>
.date {
font-size: 16px;
font-weight: bold;
}
.Calen {
top: 50px;
.bg {
top: 50px;
}
.addfood {
top: 0;
bottom: auto;
border-radius: 0;
}
}
.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: $mainColor;
font-size: 28rpx;
}
}
.week {
display: flex;
align-items: center;
height: 70rpx;
line-height: 70rpx;
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: 70rpx;
line-height: 70rpx;
width: calc(100% / 7);
.day {
font-style: normal;
display: inline-block;
vertical-align: middle;
width: 50rpx;
height: 50rpx;
line-height: 50rpx;
overflow: hidden;
border-radius: 60rpx;
&.choose {
background-color: $mainColor;
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;
}
.error {
background-color: $uni-color-error;
}
.warning {
background-color: $uni-color-warning;
}
.success {
background-color: $uni-color-success;
}
}
}
}
.hide {
height: 70rpx !important;
}
.weektoggle {
width: 85rpx;
height: 32rpx;
position: relative;
bottom: -42rpx;
&.down {
transform: rotate(180deg);
bottom: 0;
}
}
}
//
.level {
display: flex;
font-size: 12px;
margin-left: 10px;
margin-top: -20px;
view {
width: 25%;
text-align: left;
height: 28px;
line-height: 28px;
text {
width: 10px;
height: 10px;
background: red;
display: inline-block;
border-radius: 50%;
margin-right: 5px;
}
}
:nth-child(2) text {
background: $uni-color-success
}
:nth-child(3) text {
background: $uni-color-warning
}
}
</style>

View File

@ -0,0 +1,67 @@
## 1.0.42023-03-29
- 修复 手动上传删除一个文件后不能再上传的bug
## 1.0.32022-12-19
- 新增 sourceType 属性, 可以自定义图片和视频选择的来源
## 1.0.22022-07-04
- 修复 在uni-forms下样式不生效的bug
## 1.0.12021-11-23
- 修复 参数为对象的情况下url在某些情况显示错误的bug
## 1.0.02021-11-19
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-file-picker](https://uniapp.dcloud.io/component/uniui/uni-file-picker)
## 0.2.162021-11-08
- 修复 传入空对象 显示错误的Bug
## 0.2.152021-08-30
- 修复 return-type="object" 时且存在v-model时无法删除文件的Bug
## 0.2.142021-08-23
- 新增 参数中返回 fileID 字段
## 0.2.132021-08-23
- 修复 腾讯云传入fileID 不能回显的bug
- 修复 选择图片后,不能放大的问题
## 0.2.122021-08-17
- 修复 由于 0.2.11 版本引起的不能回显图片的Bug
## 0.2.112021-08-16
- 新增 clearFiles(index) 方法,可以手动删除指定文件
- 修复 v-model 值设为 null 报错的Bug
## 0.2.102021-08-13
- 修复 return-type="object" 时无法删除文件的Bug
## 0.2.92021-08-03
- 修复 auto-upload 属性失效的Bug
## 0.2.82021-07-31
- 修复 fileExtname属性不指定值报错的Bug
## 0.2.72021-07-31
- 修复 在某种场景下图片不回显的Bug
## 0.2.62021-07-30
- 修复 return-type为object下返回值不正确的Bug
## 0.2.52021-07-30
- 修复(重要) H5 平台下如果和uni-forms组件一同使用导致页面卡死的问题
## 0.2.32021-07-28
- 优化 调整示例代码
## 0.2.22021-07-27
- 修复 vue3 下赋值错误的Bug
- 优化 h5平台下上传文件导致页面卡死的问题
## 0.2.02021-07-13
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 0.1.12021-07-02
- 修复 sourceType 缺少默认值导致 ios 无法选择文件
## 0.1.02021-06-30
- 优化 解耦与uniCloud的强绑定关系 如不绑定服务空间默认autoUpload为false且不可更改
## 0.0.112021-06-30
- 修复 由 0.0.10 版本引发的 returnType 属性失效的问题
## 0.0.102021-06-29
- 优化 文件上传后进度条消失时机
## 0.0.92021-06-29
- 修复 在uni-forms 中,删除文件 获取的值不对的Bug
## 0.0.82021-06-15
- 修复 删除文件时无法触发 v-model 的Bug
## 0.0.72021-05-12
- 新增 组件示例地址
## 0.0.62021-04-09
- 修复 选择的文件非 file-extname 字段指定的扩展名报错的Bug
## 0.0.52021-04-09
- 优化 更新组件示例
## 0.0.42021-04-09
- 优化 file-extname 字段支持字符串写法,多个扩展名需要用逗号分隔
## 0.0.32021-02-05
- 调整为uni_modules目录规范
- 修复 微信小程序不指定 fileExtname 属性选择失败的Bug

View File

@ -0,0 +1,224 @@
'use strict';
const ERR_MSG_OK = 'chooseAndUploadFile:ok';
const ERR_MSG_FAIL = 'chooseAndUploadFile:fail';
function chooseImage(opts) {
const {
count,
sizeType = ['original', 'compressed'],
sourceType,
extension
} = opts
return new Promise((resolve, reject) => {
uni.chooseImage({
count,
sizeType,
sourceType,
extension,
success(res) {
resolve(normalizeChooseAndUploadFileRes(res, 'image'));
},
fail(res) {
reject({
errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL),
});
},
});
});
}
function chooseVideo(opts) {
const {
camera,
compressed,
maxDuration,
sourceType,
extension
} = opts;
return new Promise((resolve, reject) => {
uni.chooseVideo({
camera,
compressed,
maxDuration,
sourceType,
extension,
success(res) {
const {
tempFilePath,
duration,
size,
height,
width
} = res;
resolve(normalizeChooseAndUploadFileRes({
errMsg: 'chooseVideo:ok',
tempFilePaths: [tempFilePath],
tempFiles: [
{
name: (res.tempFile && res.tempFile.name) || '',
path: tempFilePath,
size,
type: (res.tempFile && res.tempFile.type) || '',
width,
height,
duration,
fileType: 'video',
cloudPath: '',
}, ],
}, 'video'));
},
fail(res) {
reject({
errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL),
});
},
});
});
}
function chooseAll(opts) {
const {
count,
extension
} = opts;
return new Promise((resolve, reject) => {
let chooseFile = uni.chooseFile;
if (typeof wx !== 'undefined' &&
typeof wx.chooseMessageFile === 'function') {
chooseFile = wx.chooseMessageFile;
}
if (typeof chooseFile !== 'function') {
return reject({
errMsg: ERR_MSG_FAIL + ' 请指定 type 类型,该平台仅支持选择 image 或 video。',
});
}
chooseFile({
type: 'all',
count,
extension,
success(res) {
resolve(normalizeChooseAndUploadFileRes(res));
},
fail(res) {
reject({
errMsg: res.errMsg.replace('chooseFile:fail', ERR_MSG_FAIL),
});
},
});
});
}
function normalizeChooseAndUploadFileRes(res, fileType) {
res.tempFiles.forEach((item, index) => {
if (!item.name) {
item.name = item.path.substring(item.path.lastIndexOf('/') + 1);
}
if (fileType) {
item.fileType = fileType;
}
item.cloudPath =
Date.now() + '_' + index + item.name.substring(item.name.lastIndexOf('.'));
});
if (!res.tempFilePaths) {
res.tempFilePaths = res.tempFiles.map((file) => file.path);
}
return res;
}
function uploadCloudFiles(files, max = 5, onUploadProgress) {
files = JSON.parse(JSON.stringify(files))
const len = files.length
let count = 0
let self = this
return new Promise(resolve => {
while (count < max) {
next()
}
function next() {
let cur = count++
if (cur >= len) {
!files.find(item => !item.url && !item.errMsg) && resolve(files)
return
}
const fileItem = files[cur]
const index = self.files.findIndex(v => v.uuid === fileItem.uuid)
fileItem.url = ''
delete fileItem.errMsg
uniCloud
.uploadFile({
filePath: fileItem.path,
cloudPath: fileItem.cloudPath,
fileType: fileItem.fileType,
onUploadProgress: res => {
res.index = index
onUploadProgress && onUploadProgress(res)
}
})
.then(res => {
fileItem.url = res.fileID
fileItem.index = index
if (cur < len) {
next()
}
})
.catch(res => {
fileItem.errMsg = res.errMsg || res.message
fileItem.index = index
if (cur < len) {
next()
}
})
}
})
}
function uploadFiles(choosePromise, {
onChooseFile,
onUploadProgress
}) {
return choosePromise
.then((res) => {
if (onChooseFile) {
const customChooseRes = onChooseFile(res);
if (typeof customChooseRes !== 'undefined') {
return Promise.resolve(customChooseRes).then((chooseRes) => typeof chooseRes === 'undefined' ?
res : chooseRes);
}
}
return res;
})
.then((res) => {
if (res === false) {
return {
errMsg: ERR_MSG_OK,
tempFilePaths: [],
tempFiles: [],
};
}
return res
})
}
function chooseAndUploadFile(opts = {
type: 'all'
}) {
if (opts.type === 'image') {
return uploadFiles(chooseImage(opts), opts);
}
else if (opts.type === 'video') {
return uploadFiles(chooseVideo(opts), opts);
}
return uploadFiles(chooseAll(opts), opts);
}
export {
chooseAndUploadFile,
uploadCloudFiles
};

View File

@ -0,0 +1,673 @@
<template>
<view class="uni-file-picker">
<view v-if="title" class="uni-file-picker__header">
<text class="file-title">{{ title }}</text>
<text class="file-count">{{ filesList.length }}/{{ limitLength }}</text>
</view>
<upload-image v-if="fileMediatype === 'image' && showType === 'grid'" :readonly="readonly"
:image-styles="imageStyles" :files-list="filesList" :limit="limitLength" :disablePreview="disablePreview"
:delIcon="delIcon" @uploadFiles="uploadFiles" @choose="choose" @delFile="delFile">
<slot>
<view class="is-add">
<view class="icon-add"></view>
<view class="icon-add rotate"></view>
</view>
</slot>
</upload-image>
<upload-file v-if="fileMediatype !== 'image' || showType !== 'grid'" :readonly="readonly"
:list-styles="listStyles" :files-list="filesList" :showType="showType" :delIcon="delIcon"
@uploadFiles="uploadFiles" @choose="choose" @delFile="delFile">
<slot><button type="primary" size="mini">选择文件</button></slot>
</upload-file>
</view>
</template>
<script>
import {
chooseAndUploadFile,
uploadCloudFiles
} from './choose-and-upload-file.js'
import {
get_file_ext,
get_extname,
get_files_and_is_max,
get_file_info,
get_file_data
} from './utils.js'
import uploadImage from './upload-image.vue'
import uploadFile from './upload-file.vue'
let fileInput = null
/**
* FilePicker 文件选择上传
* @description 文件选择上传组件可以选择图片视频等任意文件并上传到当前绑定的服务空间
* @tutorial https://ext.dcloud.net.cn/plugin?id=4079
* @property {Object|Array} value 组件数据通常用来回显 ,类型由return-type属性决定
* @property {Boolean} disabled = [true|false] 组件禁用
* @value true 禁用
* @value false 取消禁用
* @property {Boolean} readonly = [true|false] 组件只读不可选择不显示进度不显示删除按钮
* @value true 只读
* @value false 取消只读
* @property {String} return-type = [array|object] 限制 value 格式当为 object 组件只能单选且会覆盖
* @value array 规定 value 属性的类型为数组
* @value object 规定 value 属性的类型为对象
* @property {Boolean} disable-preview = [true|false] 禁用图片预览 mode:grid 时生效
* @value true 禁用图片预览
* @value false 取消禁用图片预览
* @property {Boolean} del-icon = [true|false] 是否显示删除按钮
* @value true 显示删除按钮
* @value false 不显示删除按钮
* @property {Boolean} auto-upload = [true|false] 是否自动上传值为true则只触发@select,可自行上传
* @value true 自动上传
* @value false 取消自动上传
* @property {Number|String} limit 最大选择个数 h5 会自动忽略多选的部分
* @property {String} title 组件标题右侧显示上传计数
* @property {String} mode = [list|grid] 选择文件后的文件列表样式
* @value list 列表显示
* @value grid 宫格显示
* @property {String} file-mediatype = [image|video|all] 选择文件类型
* @value image 只选择图片
* @value video 只选择视频
* @value all 选择所有文件
* @property {Array} file-extname 选择文件后缀根据 file-mediatype 属性而不同
* @property {Object} list-style mode:list 时的样式
* @property {Object} image-styles 选择文件后缀根据 file-mediatype 属性而不同
* @event {Function} select 选择文件后触发
* @event {Function} progress 文件上传时触发
* @event {Function} success 上传成功触发
* @event {Function} fail 上传失败触发
* @event {Function} delete 文件从列表移除时触发
*/
export default {
name: 'uniFilePicker',
components: {
uploadImage,
uploadFile
},
options: {
virtualHost: true
},
emits: ['select', 'success', 'fail', 'progress', 'delete', 'update:modelValue', 'input'],
props: {
// #ifdef VUE3
modelValue: {
type: [Array, Object],
default () {
return []
}
},
// #endif
// #ifndef VUE3
value: {
type: [Array, Object],
default () {
return []
}
},
// #endif
disabled: {
type: Boolean,
default: false
},
disablePreview: {
type: Boolean,
default: false
},
delIcon: {
type: Boolean,
default: true
},
//
autoUpload: {
type: Boolean,
default: true
},
//
index: {
type: Number,
default: 0
},
// h5
limit: {
type: [Number, String],
default: 9
},
// grid | list | list-card
mode: {
type: String,
default: 'grid'
},
// image/video/all
fileMediatype: {
type: String,
default: 'image'
},
//
fileExtname: {
type: [Array, String],
default () {
return []
}
},
title: {
type: String,
default: ''
},
listStyles: {
type: Object,
default () {
return {
//
border: false,
// 线
dividline: false,
// 线
borderStyle: {}
}
}
},
imageStyles: {
type: Object,
default () {
return {
width: 'auto',
height: 'auto'
}
}
},
readonly: {
type: Boolean,
default: false
},
returnType: {
type: String,
default: 'array'
},
sizeType: {
type: Array,
default () {
return ['original', 'compressed']
}
},
sourceType: {
type: Array,
default () {
return ['album', 'camera']
}
}
},
data() {
return {
files: [],
localValue: []
}
},
watch: {
// #ifndef VUE3
value: {
handler(newVal, oldVal) {
this.setValue(newVal, oldVal)
},
immediate: true
},
// #endif
// #ifdef VUE3
modelValue: {
handler(newVal, oldVal) {
this.setValue(newVal, oldVal)
},
immediate: true
},
// #endif
},
computed: {
filesList() {
let files = []
this.files.forEach(v => {
files.push(v)
})
return files
},
showType() {
if (this.fileMediatype === 'image') {
return this.mode
}
return 'list'
},
limitLength() {
if (this.returnType === 'object') {
return 1
}
if (!this.limit) {
return 1
}
if (this.limit >= 9) {
return 9
}
return this.limit
}
},
created() {
// TODO
if (!(uniCloud.config && uniCloud.config.provider)) {
this.noSpace = true
uniCloud.chooseAndUploadFile = chooseAndUploadFile
}
this.form = this.getForm('uniForms')
this.formItem = this.getForm('uniFormsItem')
if (this.form && this.formItem) {
if (this.formItem.name) {
this.rename = this.formItem.name
this.form.inputChildrens.push(this)
}
}
},
methods: {
/**
* 公开用户使用清空文件
* @param {Object} index
*/
clearFiles(index) {
if (index !== 0 && !index) {
this.files = []
this.$nextTick(() => {
this.setEmit()
})
} else {
this.files.splice(index, 1)
}
this.$nextTick(() => {
this.setEmit()
})
},
/**
* 公开用户使用继续上传
*/
upload() {
let files = []
this.files.forEach((v, index) => {
if (v.status === 'ready' || v.status === 'error') {
files.push(Object.assign({}, v))
}
})
return this.uploadFiles(files)
},
async setValue(newVal, oldVal) {
const newData = async (v) => {
const reg = /cloud:\/\/([\w.]+\/?)\S*/
let url = ''
if (v.fileID) {
url = v.fileID
} else {
url = v.url
}
if (reg.test(url)) {
v.fileID = url
v.url = await this.getTempFileURL(url)
}
if (v.url) v.path = v.url
return v
}
if (this.returnType === 'object') {
if (newVal) {
await newData(newVal)
} else {
newVal = {}
}
} else {
if (!newVal) newVal = []
for (let i = 0; i < newVal.length; i++) {
let v = newVal[i]
await newData(v)
}
}
this.localValue = newVal
if (this.form && this.formItem && !this.is_reset) {
this.is_reset = false
this.formItem.setValue(this.localValue)
}
let filesData = Object.keys(newVal).length > 0 ? newVal : [];
this.files = [].concat(filesData)
},
/**
* 选择文件
*/
choose() {
if (this.disabled) return
if (this.files.length >= Number(this.limitLength) && this.showType !== 'grid' && this.returnType ===
'array') {
uni.showToast({
title: `您最多选择 ${this.limitLength} 个文件`,
icon: 'none'
})
return
}
this.chooseFiles()
},
/**
* 选择文件并上传
*/
chooseFiles() {
const _extname = get_extname(this.fileExtname)
//
uniCloud
.chooseAndUploadFile({
type: this.fileMediatype,
compressed: false,
sizeType: this.sizeType,
sourceType: this.sourceType,
// TODO video
extension: _extname.length > 0 ? _extname : undefined,
count: this.limitLength - this.files.length, //9
onChooseFile: this.chooseFileCallback,
onUploadProgress: progressEvent => {
this.setProgress(progressEvent, progressEvent.index)
}
})
.then(result => {
this.setSuccessAndError(result.tempFiles)
})
.catch(err => {
console.log('选择失败', err)
})
},
/**
* 选择文件回调
* @param {Object} res
*/
async chooseFileCallback(res) {
const _extname = get_extname(this.fileExtname)
const is_one = (Number(this.limitLength) === 1 &&
this.disablePreview &&
!this.disabled) ||
this.returnType === 'object'
//
if (is_one) {
this.files = []
}
let {
filePaths,
files
} = get_files_and_is_max(res, _extname)
if (!(_extname && _extname.length > 0)) {
filePaths = res.tempFilePaths
files = res.tempFiles
}
let currentData = []
for (let i = 0; i < files.length; i++) {
if (this.limitLength - this.files.length <= 0) break
files[i].uuid = Date.now()
let filedata = await get_file_data(files[i], this.fileMediatype)
filedata.progress = 0
filedata.status = 'ready'
this.files.push(filedata)
currentData.push({
...filedata,
file: files[i]
})
}
this.$emit('select', {
tempFiles: currentData,
tempFilePaths: filePaths,
index: this.index
})
res.tempFiles = files
//
if (!this.autoUpload || this.noSpace) {
res.tempFiles = []
}
},
/**
* 批传
* @param {Object} e
*/
uploadFiles(files) {
files = [].concat(files)
return uploadCloudFiles.call(this, files, 5, res => {
this.setProgress(res, res.index, true)
})
.then(result => {
this.setSuccessAndError(result)
return result;
})
.catch(err => {
console.log(err)
})
},
/**
* 成功或失败
*/
async setSuccessAndError(res, fn) {
let successData = []
let errorData = []
let tempFilePath = []
let errorTempFilePath = []
for (let i = 0; i < res.length; i++) {
const item = res[i]
const index = item.uuid ? this.files.findIndex(p => p.uuid === item.uuid) : item.index
if (index === -1 || !this.files) break
if (item.errMsg === 'request:fail') {
this.files[index].url = item.path
this.files[index].status = 'error'
this.files[index].errMsg = item.errMsg
// this.files[index].progress = -1
errorData.push(this.files[index])
errorTempFilePath.push(this.files[index].url)
} else {
this.files[index].errMsg = ''
this.files[index].fileID = item.url
const reg = /cloud:\/\/([\w.]+\/?)\S*/
if (reg.test(item.url)) {
this.files[index].url = await this.getTempFileURL(item.url)
} else {
this.files[index].url = item.url
}
this.files[index].status = 'success'
this.files[index].progress += 1
successData.push(this.files[index])
tempFilePath.push(this.files[index].fileID)
}
}
if (successData.length > 0) {
this.setEmit()
//
this.$emit('success', {
tempFiles: this.backObject(successData),
tempFilePaths: tempFilePath
})
}
if (errorData.length > 0) {
this.$emit('fail', {
tempFiles: this.backObject(errorData),
tempFilePaths: errorTempFilePath
})
}
},
/**
* 获取进度
* @param {Object} progressEvent
* @param {Object} index
* @param {Object} type
*/
setProgress(progressEvent, index, type) {
const fileLenth = this.files.length
const percentNum = (index / fileLenth) * 100
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total)
let idx = index
if (!type) {
idx = this.files.findIndex(p => p.uuid === progressEvent.tempFile.uuid)
}
if (idx === -1 || !this.files[idx]) return
// fix by mehaotian 100 -1
this.files[idx].progress = percentCompleted - 1
//
this.$emit('progress', {
index: idx,
progress: parseInt(percentCompleted),
tempFile: this.files[idx]
})
},
/**
* 删除文件
* @param {Object} index
*/
delFile(index) {
this.$emit('delete', {
tempFile: this.files[index],
tempFilePath: this.files[index].url
})
this.files.splice(index, 1)
this.$nextTick(() => {
this.setEmit()
})
},
/**
* 获取文件名和后缀
* @param {Object} name
*/
getFileExt(name) {
const last_len = name.lastIndexOf('.')
const len = name.length
return {
name: name.substring(0, last_len),
ext: name.substring(last_len + 1, len)
}
},
/**
* 处理返回事件
*/
setEmit() {
let data = []
if (this.returnType === 'object') {
data = this.backObject(this.files)[0]
this.localValue = data ? data : null
} else {
data = this.backObject(this.files)
if (!this.localValue) {
this.localValue = []
}
this.localValue = [...data]
}
// #ifdef VUE3
this.$emit('update:modelValue', this.localValue)
// #endif
// #ifndef VUE3
this.$emit('input', this.localValue)
// #endif
},
/**
* 处理返回参数
* @param {Object} files
*/
backObject(files) {
let newFilesData = []
files.forEach(v => {
newFilesData.push({
extname: v.extname,
fileType: v.fileType,
image: v.image,
name: v.name,
path: v.path,
size: v.size,
fileID: v.fileID,
url: v.url,
// bug, #694
uuid: v.uuid,
status: v.status,
cloudPath: v.cloudPath
})
})
return newFilesData
},
async getTempFileURL(fileList) {
fileList = {
fileList: [].concat(fileList)
}
const urls = await uniCloud.getTempFileURL(fileList)
return urls.fileList[0].tempFileURL || ''
},
/**
* 获取父元素实例
*/
getForm(name = 'uniForms') {
let parent = this.$parent;
let parentName = parent.$options.name;
while (parentName !== name) {
parent = parent.$parent;
if (!parent) return false;
parentName = parent.$options.name;
}
return parent;
}
}
}
</script>
<style>
.uni-file-picker {
/* #ifndef APP-NVUE */
box-sizing: border-box;
overflow: hidden;
width: 100%;
/* #endif */
flex: 1;
}
.uni-file-picker__header {
padding-top: 5px;
padding-bottom: 10px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: space-between;
}
.file-title {
font-size: 14px;
color: #333;
}
.file-count {
font-size: 14px;
color: #999;
}
.is-add {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
justify-content: center;
}
.icon-add {
width: 50px;
height: 5px;
background-color: #f1f1f1;
border-radius: 2px;
}
.rotate {
position: absolute;
transform: rotate(90deg);
}
</style>

View File

@ -0,0 +1,326 @@
<template>
<view class="uni-file-picker__files">
<view v-if="!readonly" class="files-button" @click="choose">
<slot></slot>
</view>
<!-- :class="{'is-text-box':showType === 'list'}" -->
<view v-if="list.length > 0" class="uni-file-picker__lists is-text-box" :style="borderStyle">
<!-- ,'is-list-card':showType === 'list-card' -->
<view class="uni-file-picker__lists-box" v-for="(item ,index) in list" :key="index" :class="{
'files-border':index !== 0 && styles.dividline}"
:style="index !== 0 && styles.dividline &&borderLineStyle">
<view class="uni-file-picker__item">
<!-- :class="{'is-text-image':showType === 'list'}" -->
<!-- <view class="files__image is-text-image">
<image class="header-image" :src="item.logo" mode="aspectFit"></image>
</view> -->
<view class="files__name">{{item.name}}</view>
<view v-if="delIcon&&!readonly" class="icon-del-box icon-files" @click="delFile(index)">
<view class="icon-del icon-files"></view>
<view class="icon-del rotate"></view>
</view>
</view>
<view v-if="(item.progress && item.progress !== 100) ||item.progress===0 " class="file-picker__progress">
<progress class="file-picker__progress-item" :percent="item.progress === -1?0:item.progress" stroke-width="4"
:backgroundColor="item.errMsg?'#ff5a5f':'#EBEBEB'" />
</view>
<view v-if="item.status === 'error'" class="file-picker__mask" @click.stop="uploadFiles(item,index)">
点击重试
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "uploadFile",
emits:['uploadFiles','choose','delFile'],
props: {
filesList: {
type: Array,
default () {
return []
}
},
delIcon: {
type: Boolean,
default: true
},
limit: {
type: [Number, String],
default: 9
},
showType: {
type: String,
default: ''
},
listStyles: {
type: Object,
default () {
return {
//
border: true,
// 线
dividline: true,
// 线
borderStyle: {}
}
}
},
readonly:{
type:Boolean,
default:false
}
},
computed: {
list() {
let files = []
this.filesList.forEach(v => {
files.push(v)
})
return files
},
styles() {
let styles = {
border: true,
dividline: true,
'border-style': {}
}
return Object.assign(styles, this.listStyles)
},
borderStyle() {
let {
borderStyle,
border
} = this.styles
let obj = {}
if (!border) {
obj.border = 'none'
} else {
let width = (borderStyle && borderStyle.width) || 1
width = this.value2px(width)
let radius = (borderStyle && borderStyle.radius) || 5
radius = this.value2px(radius)
obj = {
'border-width': width,
'border-style': (borderStyle && borderStyle.style) || 'solid',
'border-color': (borderStyle && borderStyle.color) || '#eee',
'border-radius': radius
}
}
let classles = ''
for (let i in obj) {
classles += `${i}:${obj[i]};`
}
return classles
},
borderLineStyle() {
let obj = {}
let {
borderStyle
} = this.styles
if (borderStyle && borderStyle.color) {
obj['border-color'] = borderStyle.color
}
if (borderStyle && borderStyle.width) {
let width = borderStyle && borderStyle.width || 1
let style = borderStyle && borderStyle.style || 0
if (typeof width === 'number') {
width += 'px'
} else {
width = width.indexOf('px') ? width : width + 'px'
}
obj['border-width'] = width
if (typeof style === 'number') {
style += 'px'
} else {
style = style.indexOf('px') ? style : style + 'px'
}
obj['border-top-style'] = style
}
let classles = ''
for (let i in obj) {
classles += `${i}:${obj[i]};`
}
return classles
}
},
methods: {
uploadFiles(item, index) {
console.log("1111", item, index)
this.$emit("uploadFiles", {
item,
index
})
},
choose() {
this.$emit("choose")
},
delFile(index) {
this.$emit('delFile', index)
},
value2px(value) {
if (typeof value === 'number') {
value += 'px'
} else {
value = value.indexOf('px') !== -1 ? value : value + 'px'
}
return value
}
}
}
</script>
<style lang="scss">
.uni-file-picker__files {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: flex-start;
}
.files-button {
// border: 1px red solid;
}
.uni-file-picker__lists {
position: relative;
margin-top: 5px;
overflow: hidden;
}
.file-picker__mask {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
position: absolute;
right: 0;
top: 0;
bottom: 0;
left: 0;
color: #fff;
font-size: 14px;
background-color: rgba(0, 0, 0, 0.4);
}
.uni-file-picker__lists-box {
position: relative;
}
.uni-file-picker__item {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
padding: 8px 10px;
padding-right: 5px;
padding-left: 10px;
}
.files-border {
border-top: 1px #eee solid;
}
.files__name {
flex: 1;
font-size: 14px;
color: #666;
margin-right: 25px;
/* #ifndef APP-NVUE */
word-break: break-all;
word-wrap: break-word;
/* #endif */
}
.icon-files {
/* #ifndef APP-NVUE */
position: static;
background-color: initial;
/* #endif */
}
// .icon-files .icon-del {
// background-color: #333;
// width: 12px;
// height: 1px;
// }
.is-list-card {
border: 1px #eee solid;
margin-bottom: 5px;
border-radius: 5px;
box-shadow: 0 0 2px 0px rgba(0, 0, 0, 0.1);
padding: 5px;
}
.files__image {
width: 40px;
height: 40px;
margin-right: 10px;
}
.header-image {
width: 100%;
height: 100%;
}
.is-text-box {
border: 1px #eee solid;
border-radius: 5px;
}
.is-text-image {
width: 25px;
height: 25px;
margin-left: 5px;
}
.rotate {
position: absolute;
transform: rotate(90deg);
}
.icon-del-box {
/* #ifndef APP-NVUE */
display: flex;
margin: auto 0;
/* #endif */
align-items: center;
justify-content: center;
position: absolute;
top: 0px;
bottom: 0;
right: 5px;
height: 26px;
width: 26px;
// border-radius: 50%;
// background-color: rgba(0, 0, 0, 0.5);
z-index: 2;
transform: rotate(-45deg);
}
.icon-del {
width: 15px;
height: 1px;
background-color: #333;
// border-radius: 1px;
}
/* #ifdef H5 */
@media all and (min-width: 768px) {
.uni-file-picker__files {
max-width: 375px;
}
}
/* #endif */
</style>

View File

@ -0,0 +1,292 @@
<template>
<view class="uni-file-picker__container">
<view class="file-picker__box" v-for="(item,index) in filesList" :key="index" :style="boxStyle">
<view class="file-picker__box-content" :style="borderStyle">
<image class="file-image" :src="item.url" mode="aspectFill" @click.stop="prviewImage(item,index)"></image>
<view v-if="delIcon && !readonly" class="icon-del-box" @click.stop="delFile(index)">
<view class="icon-del"></view>
<view class="icon-del rotate"></view>
</view>
<!-- <view v-if="(item.progress && item.progress !== 100) ||item.progress===0 " class="file-picker__progress">
<progress class="file-picker__progress-item" :percent="item.progress === -1?0:item.progress" stroke-width="4"
:backgroundColor="item.errMsg?'#ff5a5f':'#EBEBEB'" />
</view> -->
<view v-if="item.errMsg" class="file-picker__mask" @click.stop="uploadFiles(item,index)">
点击重试
</view>
</view>
</view>
<view v-if="filesList.length < limit && !readonly" class="file-picker__box" :style="boxStyle">
<view class="file-picker__box-content is-add" :style="borderStyle" @click="choose">
<slot>
<view class="icon-add"></view>
<view class="icon-add rotate"></view>
</slot>
</view>
</view>
</view>
</template>
<script>
export default {
name: "uploadImage",
emits:['uploadFiles','choose','delFile'],
props: {
filesList: {
type: Array,
default () {
return []
}
},
disabled:{
type: Boolean,
default: false
},
disablePreview: {
type: Boolean,
default: false
},
limit: {
type: [Number, String],
default: 9
},
imageStyles: {
type: Object,
default () {
return {
width: 'auto',
height: 'auto',
border: {}
}
}
},
delIcon: {
type: Boolean,
default: true
},
readonly:{
type:Boolean,
default:false
}
},
computed: {
styles() {
let styles = {
width: 'auto',
height: 'auto',
border: {}
}
return Object.assign(styles, this.imageStyles)
},
boxStyle() {
const {
width = 'auto',
height = 'auto'
} = this.styles
let obj = {}
if (height === 'auto') {
if (width !== 'auto') {
obj.height = this.value2px(width)
obj['padding-top'] = 0
} else {
obj.height = 0
}
} else {
obj.height = this.value2px(height)
obj['padding-top'] = 0
}
if (width === 'auto') {
if (height !== 'auto') {
obj.width = this.value2px(height)
} else {
obj.width = '33.3%'
}
} else {
obj.width = this.value2px(width)
}
let classles = ''
for(let i in obj){
classles+= `${i}:${obj[i]};`
}
return classles
},
borderStyle() {
let {
border
} = this.styles
let obj = {}
const widthDefaultValue = 1
const radiusDefaultValue = 3
if (typeof border === 'boolean') {
obj.border = border ? '1px #eee solid' : 'none'
} else {
let width = (border && border.width) || widthDefaultValue
width = this.value2px(width)
let radius = (border && border.radius) || radiusDefaultValue
radius = this.value2px(radius)
obj = {
'border-width': width,
// 'border-style': (border && border.style) || 'solid',
// 'border-color': (border && border.color) || '#eee',
'border-radius': radius
}
}
let classles = ''
for(let i in obj){
classles+= `${i}:${obj[i]};`
}
return classles
}
},
methods: {
uploadFiles(item, index) {
this.$emit("uploadFiles", item)
},
choose() {
this.$emit("choose")
},
delFile(index) {
this.$emit('delFile', index)
},
prviewImage(img, index) {
let urls = []
if(Number(this.limit) === 1&&this.disablePreview&&!this.disabled){
this.$emit("choose")
}
if(this.disablePreview) return
this.filesList.forEach(i => {
urls.push(i.url)
})
uni.previewImage({
urls: urls,
current: index
});
},
value2px(value) {
if (typeof value === 'number') {
value += 'px'
} else {
if (value.indexOf('%') === -1) {
value = value.indexOf('px') !== -1 ? value : value + 'px'
}
}
return value
}
}
}
</script>
<style lang="scss">
.uni-file-picker__container {
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
/* #endif */
flex-wrap: wrap;
// margin: -5px;
}
.file-picker__box {
position: relative;
// flex: 0 0 33.3%;
width: 33.3%;
height: 0;
padding-top: 33.33%;
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
}
.file-picker__box-content {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
// margin: 5px;
// border: 1px #eee solid;
border-radius: 10px;
overflow: hidden;
}
.file-picker__progress {
position: absolute;
bottom: 0;
left: 0;
right: 0;
/* border: 1px red solid; */
z-index: 2;
}
.file-picker__progress-item {
width: 100%;
}
.file-picker__mask {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
position: absolute;
right: 0;
top: 0;
bottom: 0;
left: 0;
color: #fff;
font-size: 12px;
background-color: rgba(0, 0, 0, 0.4);
}
.file-image {
width: 100%;
height: 100%;
}
.is-add {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
justify-content: center;
}
.icon-add {
width: 50px;
height: 5px;
background-color: #f1f1f1;
border-radius: 2px;
}
.rotate {
position: absolute;
transform: rotate(90deg);
}
.icon-del-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
justify-content: center;
position: absolute;
top: 3px;
right: 3px;
height: 26px;
width: 26px;
border-radius: 50%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 2;
transform: rotate(-45deg);
}
.icon-del {
width: 15px;
height: 2px;
background-color: #fff;
border-radius: 2px;
}
</style>

View File

@ -0,0 +1,109 @@
/**
* 获取文件名和后缀
* @param {String} name
*/
export const get_file_ext = (name) => {
const last_len = name.lastIndexOf('.')
const len = name.length
return {
name: name.substring(0, last_len),
ext: name.substring(last_len + 1, len)
}
}
/**
* 获取扩展名
* @param {Array} fileExtname
*/
export const get_extname = (fileExtname) => {
if (!Array.isArray(fileExtname)) {
let extname = fileExtname.replace(/(\[|\])/g, '')
return extname.split(',')
} else {
return fileExtname
}
return []
}
/**
* 获取文件和检测是否可选
*/
export const get_files_and_is_max = (res, _extname) => {
let filePaths = []
let files = []
if(!_extname || _extname.length === 0){
return {
filePaths,
files
}
}
res.tempFiles.forEach(v => {
let fileFullName = get_file_ext(v.name)
const extname = fileFullName.ext.toLowerCase()
if (_extname.indexOf(extname) !== -1) {
files.push(v)
filePaths.push(v.path)
}
})
if (files.length !== res.tempFiles.length) {
uni.showToast({
title: `当前选择了${res.tempFiles.length}个文件 ${res.tempFiles.length - files.length} 个文件格式不正确`,
icon: 'none',
duration: 5000
})
}
return {
filePaths,
files
}
}
/**
* 获取图片信息
* @param {Object} filepath
*/
export const get_file_info = (filepath) => {
return new Promise((resolve, reject) => {
uni.getImageInfo({
src: filepath,
success(res) {
resolve(res)
},
fail(err) {
reject(err)
}
})
})
}
/**
* 获取封装数据
*/
export const get_file_data = async (files, type = 'image') => {
// 最终需要上传数据库的数据
let fileFullName = get_file_ext(files.name)
const extname = fileFullName.ext.toLowerCase()
let filedata = {
name: files.name,
uuid: files.uuid,
extname: extname || '',
cloudPath: files.cloudPath,
fileType: files.fileType,
url: files.path || files.path,
size: files.size, //单位是字节
image: {},
path: files.path,
video: {}
}
if (type === 'image') {
const imageinfo = await get_file_info(files.path)
delete filedata.video
filedata.image.width = imageinfo.width
filedata.image.height = imageinfo.height
filedata.image.location = imageinfo.path
} else {
delete filedata.image
}
return filedata
}

View File

@ -0,0 +1,83 @@
{
"id": "uni-file-picker",
"displayName": "uni-file-picker 文件选择上传",
"version": "1.0.4",
"description": "文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间",
"keywords": [
"uni-ui",
"uniui",
"图片上传",
"文件上传"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": ["uni-scss"],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "n"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@ -0,0 +1,11 @@
## FilePicker 文件选择上传
> **组件名uni-file-picker**
> 代码块: `uFilePicker`
文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-file-picker)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

View File

@ -0,0 +1,22 @@
## 1.3.52022-01-24
- 优化 size 属性可以传入不带单位的字符串数值
## 1.3.42022-01-24
- 优化 size 支持其他单位
## 1.3.32022-01-17
- 修复 nvue 有些图标不显示的bug兼容老版本图标
## 1.3.22021-12-01
- 优化 示例可复制图标名称
## 1.3.12021-11-23
- 优化 兼容旧组件 type 值
## 1.3.02021-11-19
- 新增 更多图标
- 优化 自定义图标使用方式
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-icons](https://uniapp.dcloud.io/component/uniui/uni-icons)
## 1.1.72021-11-08
## 1.2.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.52021-05-12
- 新增 组件示例地址
## 1.1.42021-02-05
- 调整为uni_modules目录规范

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,96 @@
<template>
<!-- #ifdef APP-NVUE -->
<text :style="{ color: color, 'font-size': iconSize }" class="uni-icons" @click="_onClick">{{unicode}}</text>
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<text :style="{ color: color, 'font-size': iconSize }" class="uni-icons" :class="['uniui-'+type,customPrefix,customPrefix?type:'']" @click="_onClick"></text>
<!-- #endif -->
</template>
<script>
import icons from './icons.js';
const getVal = (val) => {
const reg = /^[0-9]*$/g
return (typeof val === 'number' || reg.test(val) )? val + 'px' : val;
}
// #ifdef APP-NVUE
var domModule = weex.requireModule('dom');
import iconUrl from './uniicons.ttf'
domModule.addRule('fontFace', {
'fontFamily': "uniicons",
'src': "url('"+iconUrl+"')"
});
// #endif
/**
* Icons 图标
* @description 用于展示 icons 图标
* @tutorial https://ext.dcloud.net.cn/plugin?id=28
* @property {Number} size 图标大小
* @property {String} type 图标图案参考示例
* @property {String} color 图标颜色
* @property {String} customPrefix 自定义图标
* @event {Function} click 点击 Icon 触发事件
*/
export default {
name: 'UniIcons',
emits:['click'],
props: {
type: {
type: String,
default: ''
},
color: {
type: String,
default: '#333333'
},
size: {
type: [Number, String],
default: 16
},
customPrefix:{
type: String,
default: ''
}
},
data() {
return {
icons: icons.glyphs
}
},
computed:{
unicode(){
let code = this.icons.find(v=>v.font_class === this.type)
if(code){
return unescape(`%u${code.unicode}`)
}
return ''
},
iconSize(){
return getVal(this.size)
}
},
methods: {
_onClick() {
this.$emit('click')
}
}
}
</script>
<style lang="scss">
/* #ifndef APP-NVUE */
@import './uniicons.css';
@font-face {
font-family: uniicons;
src: url('./uniicons.ttf') format('truetype');
}
/* #endif */
.uni-icons {
font-family: uniicons;
text-decoration: none;
text-align: center;
}
</style>

View File

@ -0,0 +1,663 @@
.uniui-color:before {
content: "\e6cf";
}
.uniui-wallet:before {
content: "\e6b1";
}
.uniui-settings-filled:before {
content: "\e6ce";
}
.uniui-auth-filled:before {
content: "\e6cc";
}
.uniui-shop-filled:before {
content: "\e6cd";
}
.uniui-staff-filled:before {
content: "\e6cb";
}
.uniui-vip-filled:before {
content: "\e6c6";
}
.uniui-plus-filled:before {
content: "\e6c7";
}
.uniui-folder-add-filled:before {
content: "\e6c8";
}
.uniui-color-filled:before {
content: "\e6c9";
}
.uniui-tune-filled:before {
content: "\e6ca";
}
.uniui-calendar-filled:before {
content: "\e6c0";
}
.uniui-notification-filled:before {
content: "\e6c1";
}
.uniui-wallet-filled:before {
content: "\e6c2";
}
.uniui-medal-filled:before {
content: "\e6c3";
}
.uniui-gift-filled:before {
content: "\e6c4";
}
.uniui-fire-filled:before {
content: "\e6c5";
}
.uniui-refreshempty:before {
content: "\e6bf";
}
.uniui-location-filled:before {
content: "\e6af";
}
.uniui-person-filled:before {
content: "\e69d";
}
.uniui-personadd-filled:before {
content: "\e698";
}
.uniui-back:before {
content: "\e6b9";
}
.uniui-forward:before {
content: "\e6ba";
}
.uniui-arrow-right:before {
content: "\e6bb";
}
.uniui-arrowthinright:before {
content: "\e6bb";
}
.uniui-arrow-left:before {
content: "\e6bc";
}
.uniui-arrowthinleft:before {
content: "\e6bc";
}
.uniui-arrow-up:before {
content: "\e6bd";
}
.uniui-arrowthinup:before {
content: "\e6bd";
}
.uniui-arrow-down:before {
content: "\e6be";
}
.uniui-arrowthindown:before {
content: "\e6be";
}
.uniui-bottom:before {
content: "\e6b8";
}
.uniui-arrowdown:before {
content: "\e6b8";
}
.uniui-right:before {
content: "\e6b5";
}
.uniui-arrowright:before {
content: "\e6b5";
}
.uniui-top:before {
content: "\e6b6";
}
.uniui-arrowup:before {
content: "\e6b6";
}
.uniui-left:before {
content: "\e6b7";
}
.uniui-arrowleft:before {
content: "\e6b7";
}
.uniui-eye:before {
content: "\e651";
}
.uniui-eye-filled:before {
content: "\e66a";
}
.uniui-eye-slash:before {
content: "\e6b3";
}
.uniui-eye-slash-filled:before {
content: "\e6b4";
}
.uniui-info-filled:before {
content: "\e649";
}
.uniui-reload:before {
content: "\e6b2";
}
.uniui-micoff-filled:before {
content: "\e6b0";
}
.uniui-map-pin-ellipse:before {
content: "\e6ac";
}
.uniui-map-pin:before {
content: "\e6ad";
}
.uniui-location:before {
content: "\e6ae";
}
.uniui-starhalf:before {
content: "\e683";
}
.uniui-star:before {
content: "\e688";
}
.uniui-star-filled:before {
content: "\e68f";
}
.uniui-calendar:before {
content: "\e6a0";
}
.uniui-fire:before {
content: "\e6a1";
}
.uniui-medal:before {
content: "\e6a2";
}
.uniui-font:before {
content: "\e6a3";
}
.uniui-gift:before {
content: "\e6a4";
}
.uniui-link:before {
content: "\e6a5";
}
.uniui-notification:before {
content: "\e6a6";
}
.uniui-staff:before {
content: "\e6a7";
}
.uniui-vip:before {
content: "\e6a8";
}
.uniui-folder-add:before {
content: "\e6a9";
}
.uniui-tune:before {
content: "\e6aa";
}
.uniui-auth:before {
content: "\e6ab";
}
.uniui-person:before {
content: "\e699";
}
.uniui-email-filled:before {
content: "\e69a";
}
.uniui-phone-filled:before {
content: "\e69b";
}
.uniui-phone:before {
content: "\e69c";
}
.uniui-email:before {
content: "\e69e";
}
.uniui-personadd:before {
content: "\e69f";
}
.uniui-chatboxes-filled:before {
content: "\e692";
}
.uniui-contact:before {
content: "\e693";
}
.uniui-chatbubble-filled:before {
content: "\e694";
}
.uniui-contact-filled:before {
content: "\e695";
}
.uniui-chatboxes:before {
content: "\e696";
}
.uniui-chatbubble:before {
content: "\e697";
}
.uniui-upload-filled:before {
content: "\e68e";
}
.uniui-upload:before {
content: "\e690";
}
.uniui-weixin:before {
content: "\e691";
}
.uniui-compose:before {
content: "\e67f";
}
.uniui-qq:before {
content: "\e680";
}
.uniui-download-filled:before {
content: "\e681";
}
.uniui-pyq:before {
content: "\e682";
}
.uniui-sound:before {
content: "\e684";
}
.uniui-trash-filled:before {
content: "\e685";
}
.uniui-sound-filled:before {
content: "\e686";
}
.uniui-trash:before {
content: "\e687";
}
.uniui-videocam-filled:before {
content: "\e689";
}
.uniui-spinner-cycle:before {
content: "\e68a";
}
.uniui-weibo:before {
content: "\e68b";
}
.uniui-videocam:before {
content: "\e68c";
}
.uniui-download:before {
content: "\e68d";
}
.uniui-help:before {
content: "\e679";
}
.uniui-navigate-filled:before {
content: "\e67a";
}
.uniui-plusempty:before {
content: "\e67b";
}
.uniui-smallcircle:before {
content: "\e67c";
}
.uniui-minus-filled:before {
content: "\e67d";
}
.uniui-micoff:before {
content: "\e67e";
}
.uniui-closeempty:before {
content: "\e66c";
}
.uniui-clear:before {
content: "\e66d";
}
.uniui-navigate:before {
content: "\e66e";
}
.uniui-minus:before {
content: "\e66f";
}
.uniui-image:before {
content: "\e670";
}
.uniui-mic:before {
content: "\e671";
}
.uniui-paperplane:before {
content: "\e672";
}
.uniui-close:before {
content: "\e673";
}
.uniui-help-filled:before {
content: "\e674";
}
.uniui-paperplane-filled:before {
content: "\e675";
}
.uniui-plus:before {
content: "\e676";
}
.uniui-mic-filled:before {
content: "\e677";
}
.uniui-image-filled:before {
content: "\e678";
}
.uniui-locked-filled:before {
content: "\e668";
}
.uniui-info:before {
content: "\e669";
}
.uniui-locked:before {
content: "\e66b";
}
.uniui-camera-filled:before {
content: "\e658";
}
.uniui-chat-filled:before {
content: "\e659";
}
.uniui-camera:before {
content: "\e65a";
}
.uniui-circle:before {
content: "\e65b";
}
.uniui-checkmarkempty:before {
content: "\e65c";
}
.uniui-chat:before {
content: "\e65d";
}
.uniui-circle-filled:before {
content: "\e65e";
}
.uniui-flag:before {
content: "\e65f";
}
.uniui-flag-filled:before {
content: "\e660";
}
.uniui-gear-filled:before {
content: "\e661";
}
.uniui-home:before {
content: "\e662";
}
.uniui-home-filled:before {
content: "\e663";
}
.uniui-gear:before {
content: "\e664";
}
.uniui-smallcircle-filled:before {
content: "\e665";
}
.uniui-map-filled:before {
content: "\e666";
}
.uniui-map:before {
content: "\e667";
}
.uniui-refresh-filled:before {
content: "\e656";
}
.uniui-refresh:before {
content: "\e657";
}
.uniui-cloud-upload:before {
content: "\e645";
}
.uniui-cloud-download-filled:before {
content: "\e646";
}
.uniui-cloud-download:before {
content: "\e647";
}
.uniui-cloud-upload-filled:before {
content: "\e648";
}
.uniui-redo:before {
content: "\e64a";
}
.uniui-images-filled:before {
content: "\e64b";
}
.uniui-undo-filled:before {
content: "\e64c";
}
.uniui-more:before {
content: "\e64d";
}
.uniui-more-filled:before {
content: "\e64e";
}
.uniui-undo:before {
content: "\e64f";
}
.uniui-images:before {
content: "\e650";
}
.uniui-paperclip:before {
content: "\e652";
}
.uniui-settings:before {
content: "\e653";
}
.uniui-search:before {
content: "\e654";
}
.uniui-redo-filled:before {
content: "\e655";
}
.uniui-list:before {
content: "\e644";
}
.uniui-mail-open-filled:before {
content: "\e63a";
}
.uniui-hand-down-filled:before {
content: "\e63c";
}
.uniui-hand-down:before {
content: "\e63d";
}
.uniui-hand-up-filled:before {
content: "\e63e";
}
.uniui-hand-up:before {
content: "\e63f";
}
.uniui-heart-filled:before {
content: "\e641";
}
.uniui-mail-open:before {
content: "\e643";
}
.uniui-heart:before {
content: "\e639";
}
.uniui-loop:before {
content: "\e633";
}
.uniui-pulldown:before {
content: "\e632";
}
.uniui-scan:before {
content: "\e62a";
}
.uniui-bars:before {
content: "\e627";
}
.uniui-cart-filled:before {
content: "\e629";
}
.uniui-checkbox:before {
content: "\e62b";
}
.uniui-checkbox-filled:before {
content: "\e62c";
}
.uniui-shop:before {
content: "\e62f";
}
.uniui-headphones:before {
content: "\e630";
}
.uniui-cart:before {
content: "\e631";
}

View File

@ -0,0 +1,86 @@
{
"id": "uni-icons",
"displayName": "uni-icons 图标",
"version": "1.3.5",
"description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。",
"keywords": [
"uni-ui",
"uniui",
"icon",
"图标"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": "^3.2.14"
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": ["uni-scss"],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@ -0,0 +1,8 @@
## Icons 图标
> **组件名uni-icons**
> 代码块: `uIcons`
用于展示 icons 图标 。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-icons)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

View File

@ -0,0 +1,8 @@
## 1.0.32022-01-21
- 优化 组件示例
## 1.0.22021-11-22
- 修复 / 符号在 vue 不同版本兼容问题引起的报错问题
## 1.0.12021-11-22
- 修复 vue3中scss语法兼容问题
## 1.0.02021-11-18
- init

View File

@ -0,0 +1 @@
@import './styles/index.scss';

View File

@ -0,0 +1,82 @@
{
"id": "uni-scss",
"displayName": "uni-scss 辅助样式",
"version": "1.0.3",
"description": "uni-sass是uni-ui提供的一套全局样式 通过一些简单的类名和sass变量实现简单的页面布局操作比如颜色、边距、圆角等。",
"keywords": [
"uni-scss",
"uni-ui",
"辅助样式"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"category": [
"JS SDK",
"通用 SDK"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "u"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "n",
"联盟": "n"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@ -0,0 +1,4 @@
`uni-sass``uni-ui`提供的一套全局样式 ,通过一些简单的类名和`sass`变量,实现简单的页面布局操作,比如颜色、边距、圆角等。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-sass)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

View File

@ -0,0 +1,7 @@
@import './setting/_variables.scss';
@import './setting/_border.scss';
@import './setting/_color.scss';
@import './setting/_space.scss';
@import './setting/_radius.scss';
@import './setting/_text.scss';
@import './setting/_styles.scss';

View File

@ -0,0 +1,3 @@
.uni-border {
border: 1px $uni-border-1 solid;
}

View File

@ -0,0 +1,66 @@
// TODO 暂时不需要 class 需要用户使用变量实现 如果使用类名其实并不推荐
// @mixin get-styles($k,$c) {
// @if $k == size or $k == weight{
// font-#{$k}:#{$c}
// }@else{
// #{$k}:#{$c}
// }
// }
$uni-ui-color:(
// 主色
primary: $uni-primary,
primary-disable: $uni-primary-disable,
primary-light: $uni-primary-light,
// 辅助色
success: $uni-success,
success-disable: $uni-success-disable,
success-light: $uni-success-light,
warning: $uni-warning,
warning-disable: $uni-warning-disable,
warning-light: $uni-warning-light,
error: $uni-error,
error-disable: $uni-error-disable,
error-light: $uni-error-light,
info: $uni-info,
info-disable: $uni-info-disable,
info-light: $uni-info-light,
// 中性色
main-color: $uni-main-color,
base-color: $uni-base-color,
secondary-color: $uni-secondary-color,
extra-color: $uni-extra-color,
// 背景色
bg-color: $uni-bg-color,
// 边框颜色
border-1: $uni-border-1,
border-2: $uni-border-2,
border-3: $uni-border-3,
border-4: $uni-border-4,
// 黑色
black:$uni-black,
// 白色
white:$uni-white,
// 透明
transparent:$uni-transparent
) !default;
@each $key, $child in $uni-ui-color {
.uni-#{"" + $key} {
color: $child;
}
.uni-#{"" + $key}-bg {
background-color: $child;
}
}
.uni-shadow-sm {
box-shadow: $uni-shadow-sm;
}
.uni-shadow-base {
box-shadow: $uni-shadow-base;
}
.uni-shadow-lg {
box-shadow: $uni-shadow-lg;
}
.uni-mask {
background-color:$uni-mask;
}

View File

@ -0,0 +1,55 @@
@mixin radius($r,$d:null ,$important: false){
$radius-value:map-get($uni-radius, $r) if($important, !important, null);
// Key exists within the $uni-radius variable
@if (map-has-key($uni-radius, $r) and $d){
@if $d == t {
border-top-left-radius:$radius-value;
border-top-right-radius:$radius-value;
}@else if $d == r {
border-top-right-radius:$radius-value;
border-bottom-right-radius:$radius-value;
}@else if $d == b {
border-bottom-left-radius:$radius-value;
border-bottom-right-radius:$radius-value;
}@else if $d == l {
border-top-left-radius:$radius-value;
border-bottom-left-radius:$radius-value;
}@else if $d == tl {
border-top-left-radius:$radius-value;
}@else if $d == tr {
border-top-right-radius:$radius-value;
}@else if $d == br {
border-bottom-right-radius:$radius-value;
}@else if $d == bl {
border-bottom-left-radius:$radius-value;
}
}@else{
border-radius:$radius-value;
}
}
@each $key, $child in $uni-radius {
@if($key){
.uni-radius-#{"" + $key} {
@include radius($key)
}
}@else{
.uni-radius {
@include radius($key)
}
}
}
@each $direction in t, r, b, l,tl, tr, br, bl {
@each $key, $child in $uni-radius {
@if($key){
.uni-radius-#{"" + $direction}-#{"" + $key} {
@include radius($key,$direction,false)
}
}@else{
.uni-radius-#{$direction} {
@include radius($key,$direction,false)
}
}
}
}

View File

@ -0,0 +1,56 @@
@mixin fn($space,$direction,$size,$n) {
@if $n {
#{$space}-#{$direction}: #{$size*$uni-space-root}px
} @else {
#{$space}-#{$direction}: #{-$size*$uni-space-root}px
}
}
@mixin get-styles($direction,$i,$space,$n){
@if $direction == t {
@include fn($space, top,$i,$n);
}
@if $direction == r {
@include fn($space, right,$i,$n);
}
@if $direction == b {
@include fn($space, bottom,$i,$n);
}
@if $direction == l {
@include fn($space, left,$i,$n);
}
@if $direction == x {
@include fn($space, left,$i,$n);
@include fn($space, right,$i,$n);
}
@if $direction == y {
@include fn($space, top,$i,$n);
@include fn($space, bottom,$i,$n);
}
@if $direction == a {
@if $n {
#{$space}:#{$i*$uni-space-root}px;
} @else {
#{$space}:#{-$i*$uni-space-root}px;
}
}
}
@each $orientation in m,p {
$space: margin;
@if $orientation == m {
$space: margin;
} @else {
$space: padding;
}
@for $i from 0 through 16 {
@each $direction in t, r, b, l, x, y, a {
.uni-#{$orientation}#{$direction}-#{$i} {
@include get-styles($direction,$i,$space,true);
}
.uni-#{$orientation}#{$direction}-n#{$i} {
@include get-styles($direction,$i,$space,false);
}
}
}
}

View File

@ -0,0 +1,167 @@
/* #ifndef APP-NVUE */
$-color-white:#fff;
$-color-black:#000;
@mixin base-style($color) {
color: #fff;
background-color: $color;
border-color: mix($-color-black, $color, 8%);
&:not([hover-class]):active {
background: mix($-color-black, $color, 10%);
border-color: mix($-color-black, $color, 20%);
color: $-color-white;
outline: none;
}
}
@mixin is-color($color) {
@include base-style($color);
&[loading] {
@include base-style($color);
&::before {
margin-right:5px;
}
}
&[disabled] {
&,
&[loading],
&:not([hover-class]):active {
color: $-color-white;
border-color: mix(darken($color,10%), $-color-white);
background-color: mix($color, $-color-white);
}
}
}
@mixin base-plain-style($color) {
color:$color;
background-color: mix($-color-white, $color, 90%);
border-color: mix($-color-white, $color, 70%);
&:not([hover-class]):active {
background: mix($-color-white, $color, 80%);
color: $color;
outline: none;
border-color: mix($-color-white, $color, 50%);
}
}
@mixin is-plain($color){
&[plain] {
@include base-plain-style($color);
&[loading] {
@include base-plain-style($color);
&::before {
margin-right:5px;
}
}
&[disabled] {
&,
&:active {
color: mix($-color-white, $color, 40%);
background-color: mix($-color-white, $color, 90%);
border-color: mix($-color-white, $color, 80%);
}
}
}
}
.uni-btn {
margin: 5px;
color: #393939;
border:1px solid #ccc;
font-size: 16px;
font-weight: 200;
background-color: #F9F9F9;
// TODO 暂时处理边框隐藏一边的问题
overflow: visible;
&::after{
border: none;
}
&:not([type]),&[type=default] {
color: #999;
&[loading] {
background: none;
&::before {
margin-right:5px;
}
}
&[disabled]{
color: mix($-color-white, #999, 60%);
&,
&[loading],
&:active {
color: mix($-color-white, #999, 60%);
background-color: mix($-color-white,$-color-black , 98%);
border-color: mix($-color-white, #999, 85%);
}
}
&[plain] {
color: #999;
background: none;
border-color: $uni-border-1;
&:not([hover-class]):active {
background: none;
color: mix($-color-white, $-color-black, 80%);
border-color: mix($-color-white, $-color-black, 90%);
outline: none;
}
&[disabled]{
&,
&[loading],
&:active {
background: none;
color: mix($-color-white, #999, 60%);
border-color: mix($-color-white, #999, 85%);
}
}
}
}
&:not([hover-class]):active {
color: mix($-color-white, $-color-black, 50%);
}
&[size=mini] {
font-size: 16px;
font-weight: 200;
border-radius: 8px;
}
&.uni-btn-small {
font-size: 14px;
}
&.uni-btn-mini {
font-size: 12px;
}
&.uni-btn-radius {
border-radius: 999px;
}
&[type=primary] {
@include is-color($uni-primary);
@include is-plain($uni-primary)
}
&[type=success] {
@include is-color($uni-success);
@include is-plain($uni-success)
}
&[type=error] {
@include is-color($uni-error);
@include is-plain($uni-error)
}
&[type=warning] {
@include is-color($uni-warning);
@include is-plain($uni-warning)
}
&[type=info] {
@include is-color($uni-info);
@include is-plain($uni-info)
}
}
/* #endif */

View File

@ -0,0 +1,24 @@
@mixin get-styles($k,$c) {
@if $k == size or $k == weight{
font-#{$k}:#{$c}
}@else{
#{$k}:#{$c}
}
}
@each $key, $child in $uni-headings {
/* #ifndef APP-NVUE */
.uni-#{$key} {
@each $k, $c in $child {
@include get-styles($k,$c)
}
}
/* #endif */
/* #ifdef APP-NVUE */
.container .uni-#{$key} {
@each $k, $c in $child {
@include get-styles($k,$c)
}
}
/* #endif */
}

View File

@ -0,0 +1,146 @@
// @use "sass:math";
@import '../tools/functions.scss';
// 间距基础倍数
$uni-space-root: 2 !default;
// 边框半径默认值
$uni-radius-root:5px !default;
$uni-radius: () !default;
// 边框半径断点
$uni-radius: map-deep-merge(
(
0: 0,
// TODO 当前版本暂时不支持 sm 属性
// 'sm': math.div($uni-radius-root, 2),
null: $uni-radius-root,
'lg': $uni-radius-root * 2,
'xl': $uni-radius-root * 6,
'pill': 9999px,
'circle': 50%
),
$uni-radius
);
// 字体家族
$body-font-family: 'Roboto', sans-serif !default;
// 文本
$heading-font-family: $body-font-family !default;
$uni-headings: () !default;
$letterSpacing: -0.01562em;
$uni-headings: map-deep-merge(
(
'h1': (
size: 32px,
weight: 300,
line-height: 50px,
// letter-spacing:-0.01562em
),
'h2': (
size: 28px,
weight: 300,
line-height: 40px,
// letter-spacing: -0.00833em
),
'h3': (
size: 24px,
weight: 400,
line-height: 32px,
// letter-spacing: normal
),
'h4': (
size: 20px,
weight: 400,
line-height: 30px,
// letter-spacing: 0.00735em
),
'h5': (
size: 16px,
weight: 400,
line-height: 24px,
// letter-spacing: normal
),
'h6': (
size: 14px,
weight: 500,
line-height: 18px,
// letter-spacing: 0.0125em
),
'subtitle': (
size: 12px,
weight: 400,
line-height: 20px,
// letter-spacing: 0.00937em
),
'body': (
font-size: 14px,
font-weight: 400,
line-height: 22px,
// letter-spacing: 0.03125em
),
'caption': (
'size': 12px,
'weight': 400,
'line-height': 20px,
// 'letter-spacing': 0.03333em,
// 'text-transform': false
)
),
$uni-headings
);
// 主色
$uni-primary: #2979ff !default;
$uni-primary-disable:lighten($uni-primary,20%) !default;
$uni-primary-light: lighten($uni-primary,25%) !default;
// 辅助色
// 除了主色外的场景色需要在不同的场景中使用例如危险色表示危险的操作
$uni-success: #18bc37 !default;
$uni-success-disable:lighten($uni-success,20%) !default;
$uni-success-light: lighten($uni-success,25%) !default;
$uni-warning: #f3a73f !default;
$uni-warning-disable:lighten($uni-warning,20%) !default;
$uni-warning-light: lighten($uni-warning,25%) !default;
$uni-error: #e43d33 !default;
$uni-error-disable:lighten($uni-error,20%) !default;
$uni-error-light: lighten($uni-error,25%) !default;
$uni-info: #8f939c !default;
$uni-info-disable:lighten($uni-info,20%) !default;
$uni-info-light: lighten($uni-info,25%) !default;
// 中性色
// 中性色用于文本背景和边框颜色通过运用不同的中性色来表现层次结构
$uni-main-color: #3a3a3a !default; // 主要文字
$uni-base-color: #6a6a6a !default; // 常规文字
$uni-secondary-color: #909399 !default; // 次要文字
$uni-extra-color: #c7c7c7 !default; // 辅助说明
// 边框颜色
$uni-border-1: #F0F0F0 !default;
$uni-border-2: #EDEDED !default;
$uni-border-3: #DCDCDC !default;
$uni-border-4: #B9B9B9 !default;
// 常规色
$uni-black: #000000 !default;
$uni-white: #ffffff !default;
$uni-transparent: rgba($color: #000000, $alpha: 0) !default;
// 背景色
$uni-bg-color: #f7f7f7 !default;
/* 水平间距 */
$uni-spacing-sm: 8px !default;
$uni-spacing-base: 15px !default;
$uni-spacing-lg: 30px !default;
// 阴影
$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5) !default;
$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2) !default;
$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5) !default;
// 蒙版
$uni-mask: rgba($color: #000000, $alpha: 0.4) !default;

View File

@ -0,0 +1,19 @@
// 合并 map
@function map-deep-merge($parent-map, $child-map){
$result: $parent-map;
@each $key, $child in $child-map {
$parent-has-key: map-has-key($result, $key);
$parent-value: map-get($result, $key);
$parent-type: type-of($parent-value);
$child-type: type-of($child);
$parent-is-map: $parent-type == map;
$child-is-map: $child-type == map;
@if (not $parent-has-key) or ($parent-type != $child-type) or (not ($parent-is-map and $child-is-map)){
$result: map-merge($result, ( $key: $child ));
}@else {
$result: map-merge($result, ( $key: map-deep-merge($parent-value, $child) ));
}
}
@return $result;
};

View File

@ -0,0 +1,31 @@
// 间距基础倍数
$uni-space-root: 2;
// 边框半径默认值
$uni-radius-root:5px;
// 主色
$uni-primary: #2979ff;
// 辅助色
$uni-success: #4cd964;
// 警告色
$uni-warning: #f0ad4e;
// 错误色
$uni-error: #dd524d;
// 描述色
$uni-info: #909399;
// 中性色
$uni-main-color: #303133;
$uni-base-color: #606266;
$uni-secondary-color: #909399;
$uni-extra-color: #C0C4CC;
// 背景色
$uni-bg-color: #f5f5f5;
// 边框颜色
$uni-border-1: #DCDFE6;
$uni-border-2: #E4E7ED;
$uni-border-3: #EBEEF5;
$uni-border-4: #F2F6FC;
// 常规色
$uni-black: #000000;
$uni-white: #ffffff;
$uni-transparent: rgba($color: #000000, $alpha: 0);

View File

@ -0,0 +1,62 @@
@import './styles/setting/_variables.scss';
// 间距基础倍数
$uni-space-root: 2;
// 边框半径默认值
$uni-radius-root:5px;
// 主色
$uni-primary: #2979ff;
$uni-primary-disable:mix(#fff,$uni-primary,50%);
$uni-primary-light: mix(#fff,$uni-primary,80%);
// 辅助色
// 除了主色外的场景色需要在不同的场景中使用例如危险色表示危险的操作
$uni-success: #18bc37;
$uni-success-disable:mix(#fff,$uni-success,50%);
$uni-success-light: mix(#fff,$uni-success,80%);
$uni-warning: #f3a73f;
$uni-warning-disable:mix(#fff,$uni-warning,50%);
$uni-warning-light: mix(#fff,$uni-warning,80%);
$uni-error: #e43d33;
$uni-error-disable:mix(#fff,$uni-error,50%);
$uni-error-light: mix(#fff,$uni-error,80%);
$uni-info: #8f939c;
$uni-info-disable:mix(#fff,$uni-info,50%);
$uni-info-light: mix(#fff,$uni-info,80%);
// 中性色
// 中性色用于文本背景和边框颜色通过运用不同的中性色来表现层次结构
$uni-main-color: #3a3a3a; // 主要文字
$uni-base-color: #6a6a6a; // 常规文字
$uni-secondary-color: #909399; // 次要文字
$uni-extra-color: #c7c7c7; // 辅助说明
// 边框颜色
$uni-border-1: #F0F0F0;
$uni-border-2: #EDEDED;
$uni-border-3: #DCDCDC;
$uni-border-4: #B9B9B9;
// 常规色
$uni-black: #000000;
$uni-white: #ffffff;
$uni-transparent: rgba($color: #000000, $alpha: 0);
// 背景色
$uni-bg-color: #f7f7f7;
/* 水平间距 */
$uni-spacing-sm: 8px;
$uni-spacing-base: 15px;
$uni-spacing-lg: 30px;
// 阴影
$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5);
$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2);
$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5);
// 蒙版
$uni-mask: rgba($color: #000000, $alpha: 0.4);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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