kitchendDevice/pageTwo/count/search.vue

1234 lines
25 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="content">
<!-- 搜索 -->
<view class="serachBox">
<view class="type">
<picker mode="selector" @change="changeClickType" :range="foodItem" range-key="name">
<view>
{{foodName}}
<image src="/static/arrow-down.png"></image>
</view>
</picker>
</view>
<view class="serach-box">
<view class="searchInput">
<input placeholder="请输入..." class="city-serach-input" v-model="search_value" />
<icon v-if="search_value" class="iconfont icon-error" @click="handlecolse"></icon>
</view>
<view class="searchBtn">
<view @click="handleSerach">搜索</view>
</view>
</view>
</view>
<!-- 历史搜索 -->
<view class="content-box" v-if="!search_list.length">
<view v-if="history_food.length" class="search-history">
<view class="title">
<view class="quan mr-5"></view>历史搜索
</view>
<view class="button-container" @click="showAll =! showAll" v-if="history_food.length>10">
<image :src="showAll?'/static/arrow-up.png':'/static/arrow-down.png'"></image>
</view>
<view class="history-list">
<view class="history-list-item"
v-for="(item,index) in showAll?history_food:history_food.slice(0, 10)"
@click="handleSearchHistory(item.keyword)">
{{item.keyword}}
</view>
</view>
</view>
<view class="popular-container">
<view class="title">
<view class="quan mr-5"></view>猜你想搜
</view>
<view class="popular-food-item" v-for="(ite,index) in popular_food" :key="index">
<view class="food-title">{{ite.title}}</view>
<view class="popular-food-inner">
<text class="popular-food-subitem" v-for="(sub_item,sub_index) in ite.list"
@click="handleSearchHistory(sub_item.name)" :key="sub_index">{{sub_item.name}}
</text>
</view>
</view>
</view>
</view>
<!-- 搜索列表 -->
<view class="search_list" v-if="search_list.length">
<view class="search_list_item" v-for="(ite,ind) in search_list" @click="handleDetail(ite)">
<image :src="ite.pic_url"></image>
<view>
<text>{{ite.name}}</text>
<text>100g/{{ite.kcal}}kcal</text>
</view>
</view>
<view class="endtext" v-if="!lastPage || page >= lastPage">—— 到底了,看看别的吧 ——</view>
</view>
<!-- 购物车列表 -->
<view class="wrapper activeList" v-if="isShop">
<view class="bg" @click='isShop=false'>
<view class="box2" @click.stop>
<view class="left">
<view :class="[item.name == foodName?'active':'']" v-for="(item,index) in foodItem"
@click="handleToggle(item.name)">
{{item.name}}
</view>
</view>
<view class="list" v-if="ActiveList.length">
<view class="length">共{{ActiveList.filter(ite => ite.meals_type == foodName).length}}条记录</view>
<view class="item" v-for="(ite,ind) in ActiveList" :key="ind" v-if="ite.meals_type==foodName">
<view class="item-left">
<image :src="ite.pic_url"></image>
<view class="name">
<text>{{ite.name}}</text>
<text class="weight">{{ite.weight}}{{ite.unit}} / {{ite.kcal}}kcal</text>
</view>
</view>
<icon class="iconfont icon-ashbin" color="red" size="26" @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>
<icon class="iconfont icon-error" @click="IsWeight=false" size="30"></icon>
<scroll-view style="height: 100%;margin-top: 20rpx;" scroll-y="true">
<view class="box-info">
<view class="foodItem">
<view class="left">
<image :src="activeType.pic_url" mode="aspectFill"></image>
<view class="info">
<view class="name">{{activeType.name}}</view>
<view class="kcal">{{activeType.kcal}}千卡/100克</view>
</view>
</view>
</view>
<view class="foodInfo">
<view class="foodInfoItem" v-for="(item,index) in activeType.nutrients_four"
:key="index">
<view class="name">
<view class="color" :style="{'background-color':item.color}"
v-if="item.color != ''"></view>
<text>{{item.name}}({{unitConversion(item.unit)}})</text>
</view>
<view class="value">{{ Number(activeType.weight/100 * item.value).toFixed(1) }}
</view>
</view>
</view>
<!-- 蓝牙称重 -->
<view class="blue-tooth" v-if="isBle">
<blue-tooth @handleBle="handleBle" :weightType="'2'" :weightKcal="weightKcal"
@realTimeWeight="realTimeWeight" :btnType="'2'"></blue-tooth>
</view>
</view>
<!-- 营养分析 -->
<view class="foodDetail">
<view class="foodContent">
<view class="tips">
<text>营养素</text>
<text>{{Math.floor(activeType.weight)}}含量</text>
</view>
<view class="foodDetailList">
<view class="foodDetailItem" v-for="(item,index) in activeType.nutrients_list"
:key="index">
<view class="name">{{item.name_ch}}</view>
<view class="value">
{{Number(item.value*activeType.weight/100).toFixed(2)}}{{item.unit}}
</view>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
</view>
<!-- 底部购物车 -->
<view class="groupbtn">
<view @click="isShop =! isShop" class="left">
<view class="che">
<text>{{ActiveList.filter(ite => ite.meals_type == foodName).length||0}}</text>
<icon class="t-icon t-icon-canpan"></icon>
</view>
<view class="type">
{{foodName}}
<image src="/static/arrow-down.png"></image>
</view>
</view>
<view class="mic-icon" @touchstart="onVoiceTouchStart" @touchend="onVoiceTouchEnd">
<uni-icons type="mic-filled" size="20" :color="mic_touch ? '#777777' : '#fff'"></uni-icons>
语音搜索
</view>
<!-- <view class="subbtn" @click="handlesubbtn"> 完成</view> -->
</view>
</view>
</template>
<script>
import {
mapState
} from "vuex";
const plugin = requirePlugin("WechatSI")
import search from "../../components/search.vue"
import blueTooth from "../../components/bluetooth_food.vue"
import qiunDataCharts from '@/uni_modules/qiun-data-charts/components/qiun-data-charts.vue';
export default {
data() {
return {
opts: {
background: "transparent",
title: {
name: "",
},
},
chartData: {},
time: "",
page: 1,
foodName: "",
showAll: false,
IsWeight: false,
search_list: [],
isShop: false,
lastPage: "",
isBle: true,
weightKcal: "",
search_value: '',
ActiveList: [],
activeType: {},
mic_touch: false,
voiceManager: null,
autoSearchContent: "",
showAutoSearchDlg: false,
};
},
computed: {
...mapState(["configInfo", "user", 'bleValue', "countFoodInfo"]),
popular_food() {
return this.configInfo.search_guess.food_data
},
history_food() {
return this.configInfo.search_history.food
},
foodItem() {
return this.configInfo.meal_list
},
},
components: {
search,
blueTooth,
qiunDataCharts
},
onLoad(options) {
let that = this
that.time = options.time
that.foodName = options.name
},
watch: {
activeType: {
handler(newVal, oldVal) {
console.log("activeType", newVal)
},
deep: true
},
bleValue: {
handler(newVal, oldVal) {
console.log("实时bleValue", newVal)
this.realTimeWeight(newVal.countWeight, newVal.unit)
},
deep: true
}
},
mounted() {
let that = this
that.voiceManager = plugin.getRecordRecognitionManager()
that.voiceManager.onStop = function(res) {
that.search_value = res.result.replace('。', '')
that.handleSerach()
}
that.voiceManager.onError = function(res) {
console.error("error msg", res.retcode)
}
that.voiceManager.stop()
},
onReachBottom() {
let that = this
if (!this.lastPage || this.page >= this.lastPage) {
uni.showToast({
title: '没有更多数据!',
icon: 'none'
})
return
}
this.page++
this.handleSerach()
},
methods: {
onVoiceTouchStart() {
let that = this
that.mic_touch = true
that.voiceManager.start({
duration: 60000,
lang: "zh_CN"
})
},
onVoiceTouchEnd() {
let that = this
that.mic_touch = false
that.voiceManager.stop()
},
// 购物车早午晚餐切换
handleToggle(name) {
this.search_value = ""
this.search_list = []
this.foodName = name
},
//实时重量
realTimeWeight(weight, unit) {
this.activeType = Object.assign({}, this.activeType, {
weight: this.convertToGrams(weight, unit)
})
},
unitConversion(unit) {
if (unit == 'kcal') {
return '千卡'
} else if (unit == 'g') {
return '克'
}
return unit
},
convertToGrams(value, fromUnit) {
const conversionFactors = {
'lb': 453.59237, // 1磅 = 453.59237克
'oz': 28.349523125, // 1盎司 = 28.349523125克
'kg': 1000, // 1公斤 = 1000克
'g': 1
};
if (!conversionFactors.hasOwnProperty(fromUnit)) {
return ''
}
return value * conversionFactors[fromUnit];
},
// 食物选择
handleDetail(ite) {
let that = this
that.isBle = true
that.isShop = false
that.IsWeight = true
that.activeType = ite
that.activeType.weight = 100
that.weightKcal = that.activeType.kcal
let chart_data = []
that.opts.color = []
for (let i = 1; i < ite.nutrients_four.length; ++i) {
that.opts.color.push(ite.nutrients_four[i].color)
chart_data.push({
name: ite.nutrients_four[i].name,
value: Number(ite.nutrients_four[i].proportion),
})
}
that.opts.title.name = ite.kcal
that.chartData = JSON.parse(JSON.stringify({
series: [{
data: chart_data
}]
}));
},
//测量返回
handleBle(weight, unit, kcal) {
let that = this
let list = []
that.activeType.unit = unit
that.activeType.kcal = kcal
that.activeType.weight = weight
that.activeType.meals_type = that.foodName
list.push(that.activeType)
that.$model.getAddIntakeFood({
aud_id: that.user.aud_id,
food_list: list,
time: that.time
}).then(res => {
if (res.code != 0) return
if (that.time == that.user.food_count.date) {
that.$store.dispatch("getUserInfo")
} else {
that.$store.dispatch("getCountFoodInfo", {
aud_id: that.user.aud_id,
time: that.time
})
}
that.activeType.food_id = res.data.id
if (that.activeType.weight <= 0) {
that.$tools.msg("请输入重量")
return
}
that.isBle = false
that.IsWeight = false
if (that.ActiveList.indexOf(that.activeType) == -1) {
that.ActiveList.push(that.activeType);
} else {
let index = that.ActiveList.indexOf(that.activeType)
that.ActiveList[index].weight = that.activeType.weight;
that.ActiveList[index].unit = that.activeType.unit;
}
})
},
// 搜索
handleSerach() {
let that = this
if (that.search_value == "") {
that.$tools.msg("输入关键字后搜索")
return
}
that.search_list = []
that.$model.getFoodSearch({
page: that.page,
search_data: that.search_value
}).then(res => {
if (res.code != 0) {
uni.showToast({
title: res.msg,
icon: 'error'
})
return
}
that.search_list = that.search_list.concat(res.data.content_list)
})
},
// 取消搜索
handlecolse() {
this.search_value = ""
this.search_list = []
},
// 历史搜索
handleSearchHistory(text) {
let that = this
that.search_value = text
that.showAutoSearchDlg = false
that.handleSerach()
},
// 开始说话
onVoiceTouchStart() {
let that = this
that.mic_touch = true
that.voiceManager.start({
duration: 60000,
lang: "zh_CN"
})
},
// 语音结束
onVoiceTouchEnd() {
let that = this
that.mic_touch = false
that.voiceManager.stop()
},
// 早午晚餐筛选
changeClickType(e) {
this.search_value = ""
this.search_list = []
this.foodName = this.foodItem[e.target.value].name
},
//删除购物车食材
handledelactive(ite) {
let that = this
uni.showModal({
content: `是否删除[${ite.name}]`,
success: (res) => {
if (res.confirm) {
this.$model.delCEatAction({
aud_id: that.user.aud_id,
eat_log_id: ite.food_id
}).then(res => {
that.ActiveList.splice(that.ActiveList.indexOf(ite), 1);
if (that.time == that.user.food_count.date) {
that.$store.dispatch("getUserInfo")
} else {
that.$store.dispatch("getCountFoodInfo", {
aud_id: that.user.aud_id,
time: that.time
})
}
})
}
}
})
},
}
}
</script>
<style lang="scss" scoped>
.serachBox {
height: 130rpx;
position: fixed;
top: 0;
left: 0;
right: 0;
padding: 30rpx 20rpx;
z-index: 9;
background-color: #f7f7f7;
.type {
padding-bottom: 10px;
width: 100%;
text-align: center;
font-size: 30rpx;
font-weight: bold;
}
.serach-box {
height: 80rpx;
border-radius: 20rpx;
position: relative;
background-color: #fff;
}
.searchInput {
position: absolute;
left: 0;
right: 120rpx;
height: 80rpx;
icon {
position: absolute;
right: 20rpx;
top: 20rpx;
display: flex;
z-index: 9;
}
}
.searchBtn {
position: absolute;
width: 120rpx;
right: 0px;
height: 80rpx;
line-height: 80rpx;
background: $maincolor;
border-radius: 0 20rpx 20rpx 0;
text-align: center;
color: #fff;
}
input {
height: 80rpx;
padding: 0 5px;
text-align: center;
position: absolute;
left: 0px;
right: 0px;
border-radius: 20rpx;
}
.icon {
width: 100rpx;
height: 80rpx;
position: absolute;
right: 30rpx;
display: flex;
align-items: center;
justify-content: center;
}
image {
width: 15px;
height: 15px;
margin-left: 10px;
}
}
.content-box {
border-radius: 20rpx 20rpx 0 0;
position: relative;
z-index: 9;
width: 100%;
margin: 95px 0 270rpx;
background: #fff;
}
.search-history {
width: 100%;
height: auto;
overflow: hidden;
uni-icons {
color: #333333;
font-size: 60rpx;
position: absolute;
top: 13px;
right: 30rpx;
}
}
.history-list {
width: calc(100% - 40rpx);
margin: 20rpx 20rpx 0;
height: auto;
display: flex;
flex-wrap: wrap;
.history-list-item {
border: 1px solid #dfdfdf;
padding: 3px 24rpx;
border-radius: 20rpx;
margin-bottom: 20rpx;
margin-right: 20rpx;
}
}
.title {
width: 90%;
font-size: 30rpx;
font-weight: bold;
color: #000;
margin-top: 30rpx;
margin-left: 30rpx;
display: flex;
align-items: center;
}
.popular-container {
width: 100%;
margin-top: 30rpx;
.popular-food-item {
display: flex;
flex-direction: column;
align-items: center;
margin: 20rpx;
padding: 20rpx;
box-sizing: border-box;
border-radius: 20rpx;
background: linear-gradient(#EDFFF4, #ffffff 100%);
.food-title {
font-size: 34rpx;
font-weight: 700;
}
.popular-food-inner {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
width: 100%;
margin-top: 20rpx;
.popular-food-subitem {
display: flex;
align-items: center;
margin-bottom: 20rpx;
padding: 10rpx 20rpx;
background-color: #fff;
margin-right: 20rpx;
border-radius: 20rpx;
border: 1px solid #f7f7f7;
}
}
}
}
.search_list {
display: flex;
padding: 0 20rpx;
flex-wrap: wrap;
margin: 95px 20rpx 90px;
width: calc(100% - 80rpx);
justify-content: space-between;
background: #fff;
border-radius: 20rpx;
.search_list_item {
width: 100%;
display: flex;
align-items: center;
border-bottom: 1px solid #f7f7f7;
padding: 20rpx 0;
image {
width: 90rpx;
height: 90rpx;
margin-right: 20rpx;
border-radius: 50%;
border: 1px solid #f7f7f7;
}
text {
width: 100%;
display: inline-block;
}
:nth-child(2) text {
margin-top: 5px;
}
}
}
.activeList {
z-index: 12;
bottom: 100rpx;
.title {
font-weight: bold;
margin: 5px 0;
}
.list {
padding-bottom: 55px;
.name {
margin-right: 5px;
}
}
}
.auto-search-dialog {
display: flex;
justify-content: center;
align-items: center;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 999;
.auto-search-inner {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
position: relative;
width: 70%;
height: 350rpx;
padding: 80rpx 0;
background-color: #fff;
border-radius: 20rpx;
box-shadow: 0 0 20rpx #ccc;
.close {
position: absolute;
left: 0;
right: 0;
bottom: -140rpx;
width: 90rpx;
margin: 0 auto;
}
}
text {
font-size: 32rpx;
width: 80%;
}
.mic-icon {
display: flex;
justify-content: center;
align-items: center;
width: 150rpx;
height: 150rpx;
border-radius: 50%;
border: 8rpx solid #777777;
}
.btn-wrap {
display: flex;
justify-content: space-around;
width: 90%;
.retry,
.confirm {
width: 190rpx;
height: 60rpx;
line-height: 60rpx;
text-align: center;
font-size: 28rpx;
border: 2rpx solid #777;
border-radius: 15rpx;
}
}
}
.footBtn {
position: fixed;
width: 100%;
bottom: 0;
padding-top: 30rpx;
background: #fff;
display: flex;
justify-content: space-around;
view {
color: #fff;
width: auto;
padding: 5px 40rpx;
background: $maincolor;
margin-bottom: 30rpx;
display: flex;
align-items: center;
border-radius: 20rpx;
}
}
.groupbtn {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20rpx;
position: fixed;
bottom: 0rpx;
left: 0;
right: 0;
height: 60px;
padding-bottom: 15px;
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: 20rpx;
height: 35px;
line-height: 35px;
background-color: #f0ae43;
}
.left {
width: 110px;
display: flex;
align-items: center;
.che {
width: 80rpx;
height: 80rpx;
position: relative;
text {
position: absolute;
height: 30rpx;
background: red;
width: 30rpx;
border-radius: 50%;
display: inline-block;
color: #fff;
line-height: 30rpx;
text-align: center;
font-size: 24rpx;
right: 0;
top: 5px;
}
image,
.t-icon {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
.type {
image {
width: 15px;
height: 15px;
}
}
}
.mic-icon {
color: #fff;
width: calc(100% - 120px);
padding: 8px 0;
background: $maincolor;
display: flex;
align-items: center;
justify-content: center;
border-radius: 20rpx;
}
}
.wrapper {
.box {
top: 40px;
background-color: #dfdfdf;
}
.box-info {
border-radius: 20rpx;
padding: 20rpx;
background-color: #fff;
.val {
display: flex;
justify-content: center;
align-items: center;
width: 70%;
padding: 30rpx 0;
border-radius: 20rpx;
background-color: #F8F8F8;
margin: 30rpx auto;
input {
border-bottom: 1px soild #fff;
}
.unit {
width: auto;
display: inline-block;
padding: 10rpx;
margin-left: 30rpx;
font-size: 28rpx;
color: #fff;
border-radius: 8rpx;
background-color: #F0AE43;
}
}
}
.foodItem {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10rpx;
.more {
padding: 6rpx 10rpx;
border-radius: 12rpx;
color: #fff;
background-color: #f0ae43;
image {
width: 50rpx;
height: 50rpx;
}
}
.left {
width: 65%;
display: flex;
align-items: center;
image {
width: 90rpx;
height: 90rpx;
border-radius: 50%;
border: 1px solid #f7f7f7;
}
.info {
display: flex;
flex-direction: column;
justify-content: center;
margin-left: 30rpx;
.name {
font-size: 26rpx;
color: #333;
text-align: left;
margin-bottom: 10rpx;
}
.kcal {
font-size: 24rpx;
color: #666;
}
}
}
}
.foodInfo {
display: flex;
justify-content: space-around;
margin-top: 30rpx;
box-sizing: border-box;
.foodInfoItem {
display: flex;
flex-direction: column;
align-items: center;
.name {
display: flex;
align-items: center;
font-size: 24rpx;
color: #8F8F8F;
.color {
width: 6rpx;
height: 20rpx;
margin-right: 10rpx;
border-radius: 3rpx;
}
}
.value {
font-size: 28rpx;
margin-top: 10rpx;
}
}
}
.blue-tooth {
margin-top: 10rpx;
}
.foodDetail {
background: #fff;
border-radius: 20rpx;
margin-top: 20rpx;
}
.foodContent {
padding: 0 10rpx 30rpx;
margin-top: 0;
.title {
margin-left: 0;
}
.progress {
justify-content: space-between;
.info {
width: calc(100% - 280rpx);
.info-item {
display: flex;
align-items: center;
margin-top: 20rpx;
justify-content: space-between;
width: 100%;
.weight {
color: #f7f7f7;
background: none;
padding: 0;
text {
display: inline-block;
width: 30px;
margin: 0 10rpx;
color: #666;
}
}
.name {
text-align: left;
font-size: 28rpx;
font-weight: 500;
}
.color {
width: 6rpx;
height: 20rpx;
margin-right: 10rpx;
border-radius: 3rpx;
display: inline-block;
}
}
}
}
.tips {
display: flex;
justify-content: space-between;
border-bottom: 1px solid #f1f1f1;
padding: 16rpx 0;
font-size: 24rpx;
margin-top: 10rpx;
}
.foodDetailList {
margin-top: 10rpx;
.foodDetailItem {
display: flex;
justify-content: space-between;
padding: 20rpx 0;
box-sizing: border-box;
.name {
width: 70%;
font-size: 24rpx;
color: #777;
text-align: left;
}
.val {
width: 30%;
font-size: 24rpx;
font-weight: 700;
color: #333;
text-align: right;
}
}
}
}
.icon-error {
position: absolute;
right: 20rpx;
top: -34rpx;
background: #fff;
font-size: 60rpx;
width: 60rpx;
height: 60rpx;
border-radius: 50%;
}
.box2 {
left: 0;
right: 0;
height: 55%;
bottom: 0;
background-color: #fff;
overflow: scroll;
position: absolute;
padding: 20rpx;
.left {
width: 80px;
background: #dfdfdf;
position: absolute;
left: 0;
top: 0;
bottom: 75px;
display: flex;
flex-direction: column;
view {
height: 25%;
display: flex;
align-items: center;
justify-content: center;
}
.active {
background-color: #fff;
}
}
.list {
margin-bottom: 90px;
width: calc(100% - 80px);
margin-left: 80px;
.length {
width: 100%;
height: 30px;
line-height: 30px;
margin-top: -5px;
}
.item {
width: 100%;
height: 45px;
display: flex;
position: relative;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #f7f7f7;
.item-left {
width: 80%;
display: flex;
align-items: center;
image {
width: 90rpx;
height: 90rpx;
border-radius: 50%;
border: 1px solid #f7f7f7;
}
.name {
display: flex;
flex-direction: column;
margin-left: 10px;
height: 40px;
justify-content: space-between;
text {
width: 100%;
}
}
.weight {
font-size: 24rpx;
color: #999;
}
}
}
.icon-ashbin {
position: absolute;
right: 10px;
top: 15px;
color: red !important;
font-size: 18px !important;
}
}
}
}
.btn {
color: #fff;
width: 60%;
margin: auto;
background-color: #f0ae43;
}
.button-container {
position: absolute;
top: 20rpx;
right: 30rpx;
font-size: 40rpx;
image {
width: 50rpx;
height: 50rpx;
}
}
.footBtn {
position: fixed;
width: 100%;
bottom: 0px;
padding-bottom: 30rpx;
padding-top: 30rpx;
background: #fff;
display: flex;
z-index: 99;
justify-content: space-around;
view {
color: #fff;
width: 80%;
padding: 8px 40rpx;
background: $maincolor;
margin-bottom: 30rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 20rpx;
}
}
</style>