This commit is contained in:
曹辉 2023-02-17 09:36:17 +08:00
parent 349e0d1698
commit b4e080db92
24 changed files with 606 additions and 1185 deletions

View File

@ -286,37 +286,25 @@
{
"path": "pages/medicine/medicine",
"style": {
"navigationBarTitleText": "就医",
"navigationBarTitleText": "健康咨询",
"enablePullDownRefresh": false,
"navigationBarBackgroundColor": "#ffffff"
}
},
{
"path": "pages/Doctordetails/Doctordetails",
"style": {
"navigationBarTitleText": "医生信息",
"enablePullDownRefresh": false,
"navigationBarBackgroundColor": "#ffffff"
}
}, {
"path": "pages/Geriatricdisease/Geriatricdisease",
"style": {
"navigationBarTitleText": "老年病中心",
"enablePullDownRefresh": false,
"navigationBarBackgroundColor": "#ffffff"
}
}, {
"path": "pages/diseasemanagement/diseasemanagement",
"style": {
"navigationBarTitleText": "专病管理",
"enablePullDownRefresh": false,
"navigationBarBackgroundColor": "#ffffff"
}
}, {
"path": "pages/toptabbar/toptabbar",
},
{
"path": "pages/utabs/u-tabs",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
"enablePullDownRefresh": false,
"navigationBarBackgroundColor": "#ffffff"
}
},
{

View File

@ -1,120 +0,0 @@
<template>
<view class="app">
<view class="info">
<view class="image">
</view>
<view class="name">
某某某
</view>
<view class="position">
主任医师
</view>
<view class="border">
</view>
<view class="text">
熟悉呼吸系统疾病的诊治,尤其擅 长肺栓塞、肺动脉高压和慢性气道疾 病的研究。
</view>
</view>
<view class="price">
</view>
</view>
</template>
<script>
export default {
data() {
return {
};
},
//1.分享给朋友
onShareAppMessage(res) {
let pages = getCurrentPages();
let url = pages[pages.length - 1].$page.fullPath
return {
title: '泉医到家',
path: url,
}
},
//2.分享到朋友圈
onShareTimeline(res) {
let pages = getCurrentPages();
let url = pages[pages.length - 1].$page.fullPath
return {
title: '泉医到家',
path: url,
}
},
}
</script>
<style lang="scss">
.app {
padding-top: 20rpx;
.price {
width: 94%;
height: 105rpx;
background: #FFFFFF;
box-shadow: 0px 9rpx 31rpx 9rpx rgba(0, 0, 0, 0.03);
border-radius: 20rpx;
margin: 0 auto;
margin-top: 15rpx;
}
.info {
width: 94%;
height: 651rpx;
margin: 0 auto;
background: #FFFFFF;
box-shadow: 0px 9rpx 31rpx 9rpx rgba(0, 0, 0, 0.03);
border-radius: 20rpx;
position: relative;
font-size: 36rpx;
.text {
width: 90%;
line-height: 67rpx;
position: absolute;
left: 5%;
top: 263rpx;
text-indent: 1em;
}
.border {
width: 90%;
margin: 0 auto;
height: 1rpx;
background: #D8D4D4;
position: absolute;
left: 5%;
top: 209rpx;
}
.position {
font-size: 35rpx;
color: #969394;
position: absolute;
left: 264rpx;
top: 122rpx;
}
.name {
position: absolute;
left: 264rpx;
top: 68rpx;
}
.image {
width: 147rpx;
height: 150rpx;
background: #BFBFBF;
border-radius: 25rpx;
position: absolute;
left: 74rpx;
top: 32rpx;
}
}
}
</style>

View File

@ -1,95 +0,0 @@
<template>
<view class="app">
<view class="concent">
<view class="background">
<image src="/static/logo.png" mode=""></image>
<view>
<view class="detailed">
<view class="">
国家老年病中心山东分中心是依托于首都医科大学宣武医院的国家老年疾病临床医学研究中心(国家科技部、国家卫计委、中央军委后勤保障部、国家食品药品监督管理总局联合批准的国家级临床医学研究中心),老年慢性病全国网络化诊治体系及医疗大数据系统,医疗与健康一体化的新型服务体系和数据体系山东省建设单位。为提升山东省基层医院老年病学科水平,建设区域老年疾病预防、管理体系。利用国家中心在老年疾病临床诊疗的优势:在衰老、老年常见重大疾病(帕金森和老年痴呆等老年神经变性病、心脑及外周血管病、糖尿病)和老年综合征(衰弱、跌倒、便秘等)防治领域,围绕老年高龄外科围手术期管理、老年用药管理、老年共病、老年重症、以及老年常见疾病(帕金森病、痴呆、心脑外周血管病、糖尿病等)早期预警、干预及全程管理的综合评估、干预和管理新技术。
</view>
<view class="">
主要开展的科室有:帕金森,两腺科,妇科,心脑血管等精准治疗
</view>
<view class="">
开展项目有:慢病管理,血液净化(高血脂症)妇科筛查,老年病筛查、康复治疗等
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
};
},
//1.分享给朋友
onShareAppMessage(res) {
let pages = getCurrentPages();
let url = pages[pages.length - 1].$page.fullPath
return {
title: '泉医到家',
path: url,
}
},
//2.分享到朋友圈
onShareTimeline(res) {
let pages = getCurrentPages();
let url = pages[pages.length - 1].$page.fullPath
return {
title: '泉医到家',
path: url,
}
},
}
</script>
<style lang="scss">
.app {
padding-top: 10rpx;
.concent {
width: 701rpx;
height: 100%;
background: #4C7BC9;
box-shadow: 0px 9rpx 31rpx 9rpx rgba(0, 0, 0, 0.03);
border-radius: 20rpx;
margin: 5% auto 20px;
padding: 30rpx 0;
.background {
width: 657rpx;
height: 100%;
background: #FFFFFF;
border-radius: 25rpx;
background-color: white;
margin: 0 auto;
image {
width: 178rpx;
height: 84rpx;
background: #FFFFFF;
border-radius: 25px;
margin-left: 68%;
margin-top: 5%;
}
}
}
}
.detailed {
width: 657rpx;
height: 100%;
padding: 0 42rpx 20rpx;
line-height: 56rpx;
}
.detailed view {
text-indent: 2em;
}
</style>

View File

@ -8,7 +8,7 @@
</view>
</view>
<view class=" item" style="background-color: #E1AE3C ;" @tap='goorder'>
<!-- <image src="../../static/dingdan.png" mode=""></image> -->
<image src="../../static/dingdan.png" mode=""></image>
<view class="title">
我的订单
</view>

View File

@ -1,9 +1,11 @@
<template>
<view class="app">
<view class="" v-if='GoodsCategorychildrenlist.length>1'>
<top-tabbar :tabIndex="tabIndex" :tabBars="GoodsCategorychildrenlist" @toggleToptab="toggleTab"
selectedBottomColor="#D43953" selectedTextColor="#D43953" textColor="#000000" bgColor="#ffffff">
</top-tabbar>
<u-tabs :list="GoodsCategorychildrenlist" :current="tabIndex" @change="toggleTab"></u-tabs>
<view class="fenlei" @tap='toggleTab(1111111111111)'>
<image src="../../static/fenlei.png" mode=""></image>
<view class="">
分类
</view>
</view>
<view class="inputs">
<i class="icon"></i>
@ -41,11 +43,8 @@
getGoodsCategoryNameList
} from '@/api/ProductList/ProductList.js';
import baseurl from '@/api/baseurl.js'
import topTabbar from '../toptabbar/toptabbar.vue'
export default {
components: {
topTabbar
},
components: {},
data() {
return {
//将选中标签的索引绑定为tabIndex,以便后续的调用
@ -137,10 +136,11 @@
GoodsCategorychildren(value) {
getGoodsCategoryNameList(value).then(res => {
this.GoodsCategorychildrenlist = [{
goodsCategoryName: '全部',
name: '全部',
id: 99999999999999999,
}]
res.data.forEach(e => {
e.name = e.goodsCategoryName
this.GoodsCategorychildrenlist.push(e)
})
})
@ -216,9 +216,42 @@
</script>
<style lang="scss">
::v-deep .u-tabs {
width: 80%;
}
.app {
padding: 0;
.fenlei {
width: 20%;
display: inline-block;
background-color: #fff;
line-height: 86rpx;
font-weight: normal;
height: 86rpx;
text-align: center;
color: #000000;
position: absolute;
right: 0;
top: 0;
font-size: 32rpx;
view {
position: absolute;
right: 20%;
}
image {
width: 45rpx;
height: 45rpx;
position: absolute;
left: 10%;
top: 50%;
transform: translateY(-50%);
}
}
.noorder {
view {
text-align: center;

View File

@ -76,6 +76,7 @@
this.stationItemPriceId = options.stationItemPriceId
},
onShow() {
this.baseurl = baseurl
this.usershow = false
// 耗材包详情方法调用
this.getlist(this.stationId, this.stationItemId, this.stationItemPriceId)
@ -149,7 +150,7 @@
res.data.nurseItemContent = res.data.nurseItemContent.replace(/\<img/gi,
"<br/> <img class='richPic'")
}
if (res.data.poserInfoList) {
if (res.data.poserInfoList.length >= 1) {
res.data.poserInfoList.forEach(e => {
e.posterPictureUrl = baseurl + e.posterPictureUrl
var obj = {
@ -157,8 +158,12 @@
}
this.lbinfo.push(obj)
})
} else {
var obj = {
image: this.baseurl + res.data.itemPictureUrl
}
this.lbinfo.push(obj)
}
res.data.itemPictureUrl = baseurl + res.data.itemPictureUrl
this.list = res.data
})
},

View File

@ -40,7 +40,7 @@
<view class="contacts">·联系人:{{list.patientName}}</view>
<view class="contacts">·电话:{{list.patientPhone}}</view>
<view class="contacts">·地址:{{list.serviceAddress}}</view>
<view class="contacts">·时间:{{list.serviceDate}} {{list.serviceStartTime}}-{{list.serviceEndTime}}</view>
<view class="contacts">·时间:{{list.serviceDate}} {{list.serviceStartTime}}</view>
</view>
<view class="Package">套餐信息:
<span>¥{{list.nurseItemPrice}}</span>

View File

@ -98,31 +98,63 @@
border-radius: 20rpx;
line-height: 93rpx;
.selecttime {
height: 93rpx;
margin-left: 3%;
position: relative;
text {
font-size: 34rpx;
color: #878987;
}
image {
width: 18rpx;
height: 27rpx;
position: absolute;
right: 5%;
top: 50%;
transform: translateY(-50%);
}
.addition {
color: #666666;
line-height: 30rpx;
.timeyear{
.bottomtext{
width: 96%;
margin: 0 auto;
.items{
display: flex;
justify-content:flex-start;
flex-wrap: wrap;
text-align: center;
.timeitem{
width: 21%;
margin: 0 2% 20rpx;
height: 86rpx;
border-radius: 5rpx;
font-size: 28rpx;
line-height: 86rpx;
border: 2rpx solid #DADADA;
}
.timeitemtap{
width: 21%;
margin: 0 2% 20rpx;
height: 86rpx;
border: 2rpx solid #F44B2F;
border-radius: 5rpx;
font-size: 28rpx;
color: #F44B2F;
line-height: 86rpx;
}
}
}
.toptext{
padding-top: 10rpx;
display: flex;
justify-content:space-around;
height: 50rpx;
font-size: 30rpx;
color: #000000;
line-height: 27rpx;
margin-bottom: 30rpx;
text-align: center;
.Soonerorlater{
width: 200rpx;
height: 50rpx;
}
.Soonerorlaterclass{
color: #F44B2F;
width: 200rpx;
height: 50rpx;
}
view:nth-child(2){
width: 4rpx;
height: 27rpx;
background: #C5C3C3;
border-radius: 2rpx;
}
}
}
.item {
width: 97%;

View File

@ -14,24 +14,41 @@
<view class='addition'>{{personInfo.address}}</view>
</view>
<view class="item" style="border: 0;">
<span></span>
<span>上门时间:</span>
<span class='addition'>请您选择希望护理员到达的时间区间</span>
</view>
<view class="selecttime" @tap='yearshow=true'>
<span>日期:</span>
<text v-if="yeartime==''" class='addition'>请选择日期
<image src="../../static/jiantou.png"></image>
</text>
<text v-else class='addition'>{{yeartime}}</text>
<tabs :list="orderlist.appointmentTimeList" :is-scroll="false" :current="timecurrent" @change="timechange">
</tabs>
<view class="timeyear">
<view class="toptext">
<view :class="Soonerorlater=='morning'?'Soonerorlaterclass':'Soonerorlater'"
@tap="Soonerorlater='morning'">
上午
</view>
<view class="">
</view>
<view :class="Soonerorlater=='after'?'Soonerorlaterclass':'Soonerorlater'"
@tap="Soonerorlater='after'">
下午
</view>
</view>
<view class="bottomtext">
<view class="items" v-if="Soonerorlater=='morning'">
<view @tap='taptime(item,index)'
v-for="(item ,index) in orderlist.appointmentTimeList[timecurrent].morningList"
:class="timeindex==index?'timeitemtap':'timeitem'">
{{item}}
</view>
</view>
<view class="items" v-if="Soonerorlater=='after'">
<view @tap='taptime(item,index)'
v-for="(item ,index) in orderlist.appointmentTimeList[timecurrent].afternoonList"
:class="timeindex==index?'timeitemtap':'timeitem'">
{{item}}
</view>
</view>
</view>
</view>
<view class="selecttime" @tap='timeshow=true'>
<span>时间:</span>
<text v-if="usertime==''" class='addition'>请选择时间区间
<image src="../../static/jiantou.png"></image>
</text>
<text v-else class='addition'>{{usertime}}</text>
</view>
</view>
<view class="remarks">
服务时长:
@ -75,9 +92,6 @@
<view class="queren" @tap='updata'>确认预约</view>
</view>
<u-toast ref="uToast" />
<u-picker v-model="yearshow" mode="time" start-year='2022' :params="yearparams" @confirm='yeartimeconfirm'>
</u-picker>
<upicker v-model="timeshow" mode="time" :params="timeparams" @confirm='timeconfirm'></upicker>
<!-- //用户协议 -->
<u-mask :show="maskshow" class='mask' @click='maskshow=false'>
<view class="Agreement">
@ -105,37 +119,18 @@
appletAppointmentOrderPay
} from '@/api/appointmenttime/appointmenttime.js'
import baseurl from '@/api/baseurl.js'
import upicker from '../picker/picker.vue'
import appointmenttext from './text.vue'
import tabs from '../utabs/u-tabs.vue'
export default {
components: {
upicker,
appointmenttext
appointmenttext,
tabs
},
data() {
return {
Soonerorlater: 'morning',
timecurrent: 0, //时间下标
openid: '',
timeparams: { //picker组件所需
year: false,
month: false,
day: false,
hour: true,
endhour: true,
minute: true,
endminute: true,
},
timeshow: false, //时间开关
usertime: '', //页面展示时间
yearparams: { //picker组件所需
year: true,
month: true,
day: true,
hour: false,
minute: false,
second: false
},
yearshow: false, //时间开关
yeartime: '', //页面展示时间
maskshow: false, //用户协议开关
radio: 1, //用户协议
personInfo: {}, //用户信息
@ -150,7 +145,7 @@
stationItemPriceId: '',
serviceAddress: "",
serviceDate: "",
serviceStartTime: "",
serviceStartTime: null,
serviceEndTime: "",
nurseItemName: "",
nurseItemPrice: '',
@ -161,6 +156,7 @@
orderConsumableList: [],
orderChannel: '',
},
timeindex: 0,
}
},
onShow() {
@ -191,6 +187,11 @@
that.userinfo();
},
methods: {
//选择时间
taptime(item, index) {
this.orderlist.serviceStartTime = item
this.timeindex = index
},
userinfo() {
//取出patientId
var that = this
@ -208,9 +209,14 @@
}
} catch (e) {}
},
timechange(index) {
this.serviceDate = this.orderlist.appointmentTimeList[index].date
this.timecurrent = index
},
//获取耗材包详情
getPatientInfo(stationId, stationItemId, stationItemPriceId) {
getAppStationItemInfo(stationId, stationItemId, stationItemPriceId).then(res => {
console.log(res)
res.data.nurseItemContent = ''
if (res.code == 200) {
if (res.data.itemConsumableList) {
@ -218,7 +224,13 @@
e.radio = true
})
}
res.data.appointmentTimeList.forEach(e => {
e.dates = e.date.slice(5, 10)
e.name = e.week
})
this.orderlist = res.data
this.orderlist.serviceStartTime = res.data.appointmentTimeList[0].morningList[0]
this.orderlist.serviceDate = res.data.appointmentTimeList[0].date
this.consumableTotalPrice = res.data.consumableTotalPrice
}
})
@ -243,6 +255,10 @@
}
})
}
this.orderlist.afternoonOpenEndTime = this.orderlist.afternoonOpenEndTime.slice(0, 5)
this.orderlist.afternoonOpenStartTime = this.orderlist.afternoonOpenStartTime.slice(0, 5)
this.orderlist.morningOpenEndTime = this.orderlist.morningOpenEndTime.slice(0, 5)
this.orderlist.morningOpenStartTime = this.orderlist.morningOpenStartTime.slice(0, 5)
submitAppointment(this.orderlist).then(res => {
if (res.code == 500) {
that.$refs.uToast.show({
@ -376,18 +392,6 @@
},
// 选中任一checkbox时,由checkbox-group触发
checkboxGroupChange(e) {},
//获取时间
timeconfirm(e) {
this.orderlist.serviceStartTime = e.hour + ":" + e.minute
this.usertime = e.hour + ":" + e.minute + '--' + e.endhour + ":" + e.endminute
this.orderlist.serviceEndTime = e.endhour + ":" + e.endminute
this.orderlist.patientId = this.personInfo.patientId
this.orderlist.serviceAddress = this.personInfo.address
},
yeartimeconfirm(e) {
this.orderlist.serviceDate = e.year + '-' + e.month + '-' + e.day
this.yeartime = e.year + '年' + e.month + '月' + e.day + "日"
},
goaddress() {
uni.navigateTo({
url: `/pages/modifyAddress/modifyAddress?updata=${JSON.stringify(this.orderlist)}`

View File

@ -58,7 +58,7 @@
.background {
position: relative;
width: 657rpx;
height: 800rpx;
height: 850rpx;
background: #FFFFFF;
border-radius: 25rpx;
background-color: white;
@ -68,11 +68,11 @@
image {
width: 178rpx;
height: 84rpx;
height: 160rpx;
background: #FFFFFF;
border-radius: 25px;
margin-left: 68%;
margin-top: 5%;
margin-top: 0;
}
}
}

View File

@ -1,12 +1,6 @@
<template>
<view class="app">
<swiper class="swiper-block" :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000"
circular='true' previous-margin='70rpx' next-margin='70rpx' current='0' @change="swiperChange">
<swiper-item class="swiper-item" v-for="(item,index) in swiperImgUrls">
<image :src="item" :class="['slide-image', currentIndex === index?'active':'']">
</image>
</swiper-item>
</swiper>
<u-swiper :list="swiperImgUrls" effect3d='true' height='400' interval='5000' duration='2000'></u-swiper>
<view class="items">
<view class="item" @tap="gosite">
<image src="../../static/hlz.png" mode=""></image>
@ -14,7 +8,7 @@
护理站
</view>
</view>
<view class="item">
<view class="item" @tap="gomedicine">
<image src="../../static/jkzx.png" mode=""></image>
<view class="title">
健康咨询
@ -68,20 +62,25 @@
informationCategoryVOList: [], //咨询信息
};
},
onLoad() {
onShow() {
this.informationCategoryinfo()
},
methods: {
informationCategoryinfo() {
informationCategoryList().then(res => {
res.data.informationCategoryVOList.forEach(e => {
e.leadThumbnailUrl = baseurl + e.leadThumbnailUrl
})
this.informationCategoryVOList = res.data.informationCategoryVOList
res.data.poserInfoList.forEach(e => {
e.posterPictureUrl = baseurl + e.posterPictureUrl
this.swiperImgUrls.push(e.posterPictureUrl)
})
if (res.code == 200) {
res.data.informationCategoryVOList.forEach(e => {
e.leadThumbnailUrl = baseurl + e.leadThumbnailUrl
})
this.informationCategoryVOList = res.data.informationCategoryVOList
res.data.poserInfoList.forEach(e => {
e.posterPictureUrl = baseurl + e.posterPictureUrl
var obj = {
image: e.posterPictureUrl
}
this.swiperImgUrls.push(obj)
})
}
})
},
swiperChange(event) {
@ -93,6 +92,12 @@
url: '/pages/diseasemanagement/diseasemanagement'
})
},
//健康咨询
gomedicine() {
uni.navigateTo({
url: '/pages/medicine/medicine'
})
},
//跳转护理站页面
gosite() {
uni.navigateTo({
@ -123,7 +128,7 @@
<style lang="scss">
.app {
padding: 0;
padding: 100rpx 0 0 0;
.Healthknowledge {
width: 100%;
@ -227,36 +232,6 @@
}
}
.swiper-block {
padding-top: 120rpx;
background-color: #fff;
height: 400rpx;
width: 100%;
margin: 0 auto;
}
.swiper-item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
overflow: unset;
}
.slide-image {
height: 340rpx;
width: 96%;
margin: 0 auto;
border-radius: 30rpx;
z-index: 1;
}
.active {
transform: scale(1.14);
transition: all 0.2s ease-in 0s;
z-index: 20;
}
.items {
background-color: #fff;
padding: 30rpx 80rpx 20px;

View File

@ -84,11 +84,10 @@
image {
width: 178rpx;
height: 84rpx;
height: 160rpx;
background: #FFFFFF;
border-radius: 25px;
margin-left: 68%;
margin-top: 5%;
}
}
}

View File

@ -40,7 +40,7 @@
<view class="contacts">·联系人:{{list.patientName}}</view>
<view class="contacts">·电话:{{list.patientPhone}}</view>
<view class="contacts">·地址:{{list.serviceAddress}}</view>
<view class="contacts">·时间:{{list.serviceDate}} {{list.serviceStartTime}}-{{list.serviceEndTime}}</view>
<view class="contacts">·时间:{{list.serviceDate}} {{list.serviceStartTime}}</view>
</view>
<view class="Package">套餐信息:
<span>¥{{list.nurseItemPrice}}</span>

View File

@ -229,7 +229,7 @@
background-color: #ffffff;
border-radius: 20rpx;
margin: 10px auto;
padding-bottom: 20rpx;
padding-bottom: 30rpx;
.time{
font-size: 27rpx;
margin: 10rpx 0;
@ -257,55 +257,10 @@
text-overflow: ellipsis;
white-space: nowrap;
}
.call {
// display: flex;
.Navigation {
width: 103rpx;
height: 48rpx;
background: #00C176;
border-radius: 24px;
font-size: 21rpx;
color: #ffffff;
line-height: 48rpx;
margin-left: 5%;
text-align: center;
margin-top: 3%;
image {
width: 24rpx;
height: 24rpx;
}
}
.callme {
width: 150rpx;
height: 48rpx;
background: #D43953;
border-radius: 24px;
font-size: 21rpx;
color: #ffffff;
line-height: 48rpx;
margin-left: 35%;
margin-top: 3%;
text-align: center;
position: relative;
.icon{
position: absolute;
left:10%;
top:50%;
transform: translateY(-50%);
}
.text{
position: absolute;
top:50%;
right:10%;
transform: translateY(-50%);
}
}
}
.address {
font-size: 27rpx;
color: #666666;
margin:40rpx 0 10rpx 30rpx;
margin:40rpx 0 20rpx 30rpx;
word-break:break-all;
line-height: 40rpx;
// overflow: hidden;

View File

@ -1,6 +1,6 @@
<template>
<view class="app">
<u-swiper v-if="lbinfo" :list="lbinfo" height="400" style='background-size: 100%;' mode='none'></u-swiper>
<u-swiper v-if="lbinfo" :list="lbinfo" height="450" style='background-size: 100%;' mode='none'></u-swiper>
<view class="content">
<view class="righttext">
<view class="title" v-if="list.nurseStationName">
@ -130,6 +130,7 @@
export default {
data() {
return {
baseurl:'',
lbinfo: [], //轮播list
usershow: false, //完善信息开关
choicetab: false, //切换
@ -155,6 +156,7 @@
}
},
onShow() {
this.baseurl = baseurl
this.usershow = false
this.getInfo()
},
@ -235,6 +237,7 @@
res.data.afternoonOpenStartTime = res.data.afternoonOpenStartTime.slice(0, 5)
res.data.afternoonOpenEndTime = res.data.afternoonOpenEndTime.slice(0, 5)
res.data.stationIntroducePcitureUrl = baseurl + res.data.stationIntroducePcitureUrl
res.data.stationPictureUrl = baseurl + res.data.stationPictureUrl
if (res.data.agencyIntroduce) {
res.data.agencyIntroduce = res.data.agencyIntroduce.replace(/\<img/gi,
"<br/><img class='richPic'")
@ -248,13 +251,25 @@
}
this.tabList.push(obj)
this.list = res.data
res.data.poserInfoList.forEach(e => {
e.posterPictureUrl = baseurl + e.posterPictureUrl
if (res.data.poserInfoList.length >= 1) {
res.data.poserInfoList.forEach(e => {
e.posterPictureUrl = baseurl + e.posterPictureUrl
var obj = {
image: e.posterPictureUrl
}
this.lbinfo.push(obj)
})
} else {
var obj = {
image: e.posterPictureUrl
image: res.data.stationPictureUrl
}
this.lbinfo.push(obj)
})
var obj2 = {
image: res.data.stationIntroducePcitureUrl
}
this.lbinfo.push(obj2)
}
if (res.data.nurseStationLabelList) {
this.nurseStationLabelList = res.data.nurseStationLabelList
}

View File

@ -1,562 +0,0 @@
<template>
<u-popup :maskCloseAble="maskCloseAble" mode="bottom" :popup="false" v-model="value" length="auto"
:safeAreaInsetBottom="safeAreaInsetBottom" @close="close" :z-index="uZIndex">
<view class="u-datetime-picker">
<view class="u-picker-header" @touchmove.stop.prevent="">
<view class="u-btn-picker u-btn-picker--tips" :style="{ color: cancelColor }" hover-class="u-opacity"
:hover-stay-time="150" @tap="getResult('cancel')">{{cancelText}}</view>
<view class="u-picker__title">{{ title }}</view>
<view class="u-btn-picker u-btn-picker--primary" :style="{ color: moving ? cancelColor : confirmColor }"
hover-class="u-opacity" :hover-stay-time="150" @touchmove.stop="" @tap.stop="getResult('confirm')">
{{confirmText}}
</view>
</view>
<view class="u-picker-body">
<picker-view :value="valueArr" @change="change" class="u-picker-view" @pickstart="pickstart"
@pickend="pickend">
<picker-view-column v-if="!reset && params.year" style="flex:6">
<view class="u-column-item" v-for="(item, index) in years" :key="index">
{{ item }}
<text class="u-text" v-if="showTimeTag">年</text>
</view>
</picker-view-column>
<picker-view-column v-if="!reset && params.month" style="flex:5">
<view class="u-column-item" v-for="(item, index) in months" :key="index">
{{ formatNumber(item) }}
<text class="u-text" v-if="showTimeTag">月</text>
</view>
</picker-view-column>
<picker-view-column v-if="!reset && params.day" style="flex:5">
<view class="u-column-item" v-for="(item, index) in days" :key="index">
{{ formatNumber(item) }}
<text class="u-text" v-if="showTimeTag">日</text>
</view>
</picker-view-column>
<picker-view-column v-if="!reset && params.hour" style="flex:6">
<view class="u-column-item" v-for="(item, index) in hours" :key="index">
<view class="" style="font-size:38rpx">
{{ formatNumber(item) }}
</view>
<text class="u-text" v-if="showTimeTag">时</text>
</view>
</picker-view-column>
<picker-view-column v-if="!reset && params.minute" style="flex:6">
<view class="u-column-item" v-for="(item, index) in minutes" :key="index">
<view class="" style="font-size:38rpx">
{{ formatNumber(item) }}
</view>
<text class="u-text" v-if="showTimeTag">分</text>
</view>
</picker-view-column>
<picker-view-column style="flex:2">
<view class="u-column-item">
<text class="u-text">至</text>
</view>
</picker-view-column>
<picker-view-column v-if="!reset && params.endhour" style="flex:6">
<view class="u-column-item" v-for="(item, index) in endhours" :key="index">
<view class="" style="font-size:38rpx">
{{ formatNumber(item) }}
</view>
<text class="u-text" v-if="showTimeTag">时</text>
</view>
</picker-view-column>
<picker-view-column v-if="!reset && params.endminute" style="flex:6">
<view class="u-column-item" v-for="(item, index) in endminutes" :key="index">
<view class="" style="font-size:38rpx">
{{ formatNumber(item) }}
</view>
<text class="u-text" v-if="showTimeTag">分</text>
</view>
</picker-view-column>
</picker-view>
</view>
</view>
</u-popup>
</template>
<script>
/**
* picker picker弹出选择器
* @description 此选择器有两种弹出模式:一是时间模式,可以配置年,日,月,时,分,秒参数 二是地区模式,可以配置省,市,区参数
* @tutorial https://www.uviewui.com/components/picker.html
* @property {Object} params 需要显示的参数,见官网说明
* @property {String} mode 模式选择,region-地区类型,time-时间类型(默认time)
* @property {String Number} start-year 可选的开始年份,mode=time时有效(默认1950)
* @property {String Number} end-year 可选的结束年份,mode=time时有效(默认2050)
* @property {Boolean} safe-area-inset-bottom 是否开启底部安全区适配(默认false)
* @property {Boolean} show-time-tag 时间模式时,是否显示后面的年月日中文提示
* @property {String} cancel-color 取消按钮的颜色(默认#606266)
* @property {String} confirm-color 确认按钮的颜色(默认#2979ff)
* @property {String} default-time 默认选中的时间,mode=time时有效
* @property {String} confirm-text 确认按钮的文字
* @property {String} cancel-text 取消按钮的文字
* @property {String} default-region 默认选中的地区,中文形式,mode=region时有效
* @property {String} default-code 默认选中的地区,编号形式,mode=region时有效
* @property {Boolean} mask-close-able 是否允许通过点击遮罩关闭Picker(默认true)
* @property {String Number} z-index 弹出时的z-index值(默认1075)
* @property {Array} default-selector 数组形式,其中每一项表示选择了range对应项中的第几个
* @property {Array} range 自定义选择的数据,mode=selector或mode=multiSelector时有效
* @property {String} range-key 当range参数的元素为对象时,指定Object中的哪个key的值作为选择器显示内容
* @event {Function} confirm 点击确定按钮,返回当前选择的值
* @event {Function} cancel 点击取消按钮,返回当前选择的值
* @example <u-picker v-model="show" mode="time"></u-picker>
*/
export default {
name: 'u-picker',
props: {
// picker中需要显示的参数
params: {
type: Object,
default () {
return {
year: false,
month: true,
day: true,
hour: true,
endhour: true,
minute: true,
endminute: true,
second: false,
};
}
},
// 当mode=selector或者mode=multiSelector时,提供的数组
range: {
type: Array,
default () {
return [];
}
},
// 当mode=selector或者mode=multiSelector时,提供的默认选中的下标
defaultSelector: {
type: Array,
default () {
return [0];
}
},
// 当 range 是一个 Array<Object> 时,通过 range-key 来指定 Object 中 key 的值作为选择器显示内容
rangeKey: {
type: String,
default: ''
},
// 模式选择,region-地区类型,time-时间类型,selector-单列模式,multiSelector-多列模式
mode: {
type: String,
default: 'time'
},
// 年份开始时间
startYear: {
type: [String, Number],
default: 1950
},
// 年份结束时间
endYear: {
type: [String, Number],
default: 2050
},
// "取消"按钮的颜色
cancelColor: {
type: String,
default: '#606266'
},
// "确定"按钮的颜色
confirmColor: {
type: String,
default: '#2979ff'
},
// 默认显示的时间,2025-07-02 || 2025-07-02 13:01:00 || 2025/07/02
defaultTime: {
type: String,
default: ''
},
// 时间模式时,是否显示后面的年月日中文提示
showTimeTag: {
type: Boolean,
default: true
},
safeAreaInsetBottom: {
type: Boolean,
default: false
},
// 是否允许通过点击遮罩关闭Picker
maskCloseAble: {
type: Boolean,
default: true
},
// 通过双向绑定控制组件的弹出与收起
value: {
type: Boolean,
default: false
},
// 弹出的z-index值
zIndex: {
type: [String, Number],
default: 0
},
// 顶部标题
title: {
type: String,
default: '预约时间区间'
},
// 取消按钮的文字
cancelText: {
type: String,
default: '取消'
},
// 确认按钮的文字
confirmText: {
type: String,
default: '确认'
}
},
data() {
return {
years: [],
months: [],
days: [],
hours: [],
endhours: [],
minutes: [],
endminutes: [],
seconds: [],
year: 0,
month: 0,
day: 0,
hour: 0,
endhour: 0,
minute: 0,
endminute: 0,
second: 0,
reset: false,
startDate: '',
endDate: '',
valueArr: [],
moving: false // 列是否还在滑动中,微信小程序如果在滑动中就点确定,结果可能不准确
};
},
mounted() {
this.init();
},
computed: {
propsChange() {
// 引用这几个变量,是为了监听其变化
return `${this.mode}-${this.defaultTime}-${this.startYear}-${this.endYear}-${this.defaultRegion}-${this.areaCode}`;
},
regionChange() {
// 引用这几个变量,是为了监听其变化
return `${this.province}-${this.city}`;
},
yearAndMonth() {
return `${this.year}-${this.month}`;
},
uZIndex() {
// 如果用户有传递z-index值,优先使用
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
}
},
watch: {
propsChange() {
this.reset = true;
setTimeout(() => this.init(), 10);
},
// 如果地区发生变化,为了让picker联动起来,必须重置this.citys和this.areas
regionChange(val) {
this.citys = citys[this.province];
this.areas = areas[this.province][this.city];
},
// watch监听月份的变化,实时变更日的天数,因为不同月份,天数不一样
// 一个月可能有30,31天,甚至闰年2月的29天,平年2月28天
yearAndMonth(val) {
if (this.params.year) this.setDays();
},
// 微信和QQ小程序由于一些奇怪的原因(故同时对所有平台均初始化一遍),需要重新初始化才能显示正确的值
value(n) {
if (n) {
this.reset = true;
setTimeout(() => this.init(), 10);
}
}
},
methods: {
// 标识滑动开始,只有微信小程序才有这样的事件
pickstart() {
// #ifdef MP-WEIXIN
this.moving = true;
// #endif
},
// 标识滑动结束
pickend() {
// #ifdef MP-WEIXIN
this.moving = false;
// #endif
},
// 对单列和多列形式的判断是否有传入变量的情况
getItemValue(item, mode) {
// 目前(2020-05-25)uni-app对微信小程序编译有错误,导致v-if为false中的内容也执行,错误导致
// 单列模式或者多列模式中的getItemValue同时被执行,故在这里再加一层判断
if (this.mode == mode) {
return typeof item == 'object' ? item[this.rangeKey] : item;
}
},
// 小于10前面补0,用于月份,日期,时分秒等
formatNumber(num) {
return +num < 10 ? '0' + num : String(num);
},
// 生成递进的数组
generateArray: function(start, end) {
// 转为数值格式,否则用户给end-year等传递字符串值时,下面的end+1会导致字符串拼接,而不是相加
start = Number(start);
end = Number(end);
end = end > start ? end : start;
// 生成数组,获取其中的索引,并剪出来
return [...Array(end + 1).keys()].slice(start);
},
getIndex: function(arr, val) {
let index = arr.indexOf(val);
// 如果index为-1(即找不到index值),~(-1)=-(-1)-1=0,导致条件不成立
return ~index ? index : 0;
},
//日期时间处理
initTimeValue() {
// 格式化时间,在IE浏览器(uni不存在此情况),无法识别日期间的"-"间隔符号
let fdate = this.defaultTime.replace(/\-/g, '/');
fdate = fdate && fdate.indexOf('/') == -1 ? `2020/01/01 ${fdate}` : fdate;
let time = null;
if (fdate) time = new Date(fdate);
else time = new Date();
// 获取年日月时分秒
this.year = time.getFullYear();
this.month = Number(time.getMonth()) + 1;
this.day = time.getDate();
this.hour = time.getHours();
this.minute = time.getMinutes();
this.endhour = time.getHours();
this.endminute = time.getMinutes();
// this.second = time.getSeconds();
},
init() {
this.valueArr = [];
this.reset = false;
if (this.mode == 'time') {
this.initTimeValue();
if (this.params.year) {
this.valueArr.push(0);
this.setYears();
}
if (this.params.month) {
this.valueArr.push(0);
this.setMonths();
}
if (this.params.day) {
this.valueArr.push(0);
this.setDays();
}
if (this.params.hour) {
this.valueArr.push(0);
this.setHours();
}
if (this.params.minute) {
this.valueArr.push(0);
this.setMinutes();
}
if (this.params.endhour) {
this.valueArr.push(0);
this.setendHours();
}
if (this.params.endminute) {
this.valueArr.push(0);
this.setendMinutes();
}
// if (this.params.second) {
// this.valueArr.push(0);
// this.setSeconds();
// }
}
this.$forceUpdate();
},
// 设置picker的某一列值
setYears() {
// 获取年份集合
this.years = this.generateArray(this.startYear, this.endYear);
// 设置this.valueArr某一项的值,是为了让picker预选中某一个值
this.valueArr.splice(this.valueArr.length - 1, 1, this.getIndex(this.years, this.year));
},
setMonths() {
this.months = this.generateArray(1, 12);
this.valueArr.splice(this.valueArr.length - 1, 1, this.getIndex(this.months, this.month));
},
setDays() {
let totalDays = new Date(this.year, this.month, 0).getDate();
this.days = this.generateArray(1, totalDays);
let index = 0;
// 这里不能使用类似setMonths()中的this.valueArr.splice(this.valueArr.length - 1, xxx)做法
// 因为this.month和this.year变化时,会触发watch中的this.setDays(),导致this.valueArr.length计算有误
if (this.params.year && this.params.month) index = 2;
else if (this.params.month) index = 1;
else if (this.params.year) index = 1;
else index = 0;
// 当月份变化时,会导致日期的天数也会变化,如果原来选的天数大于变化后的天数,则重置为变化后的最大值
// 比如原来选中3月31日,调整为2月后,日期变为最大29,这时如果day值继续为31显然不合理,于是将其置为29(picker-column从1开始)
if (this.day > this.days.length) this.day = this.days.length;
this.valueArr.splice(index, 1, this.getIndex(this.days, this.day));
},
setHours() {
this.hours = this.generateArray(0, 23);
this.valueArr.splice(this.valueArr.length - 1, 1, this.getIndex(this.hours, this.hour));
},
setMinutes() {
this.minutes = this.generateArray(0, 59);
this.valueArr.splice(this.valueArr.length - 1, 1, this.getIndex(this.minutes, this.minute));
},
setendHours() {
this.endhours = this.generateArray(0, 23);
this.valueArr.splice(this.valueArr.length - 1, 1, this.getIndex(this.endhours, this.endhour));
},
setendMinutes() {
this.endminutes = this.generateArray(0, 59);
this.valueArr.splice(this.valueArr.length - 1, 1, this.getIndex(this.endminutes, this.endminute));
},
// setSeconds() {
// this.seconds = this.generateArray(0, 59);
// this.valueArr.splice(this.valueArr.length - 1, 1, this.getIndex(this.seconds, this.second));
// },
close() {
this.$emit('input', false);
},
// 用户更改picker的列选项
change(e) {
this.valueArr = e.detail.value;
let i = 0;
if (this.mode == 'time') {
// 这里使用i++,是因为this.valueArr数组的长度是不确定长度的,它根据this.params的值来配置长度
// 进入if规则,i会加1,保证了能获取准确的值
if (this.params.year) this.year = this.years[this.valueArr[i++]];
if (this.params.month) this.month = this.months[this.valueArr[i++]];
if (this.params.day) this.day = this.days[this.valueArr[i++]];
if (this.params.hour) this.hour = this.hours[this.valueArr[i++]];
if (this.params.minute) this.minute = this.minutes[this.valueArr[i++]];
if (this.params.endhour) this.endhour = this.hours[this.valueArr[3]]
if (this.params.endminute) this.endminute = this.endminutes[this.valueArr[4]];
// if (this.params.second) this.second = this.seconds[this.valueArr[i++]];
}
},
// 用户点击确定按钮
getResult(event = null) {
// #ifdef MP-WEIXIN
if (this.moving) return;
// #endif
let result = {};
// 只返回用户在this.params中配置了为true的字段
if (this.mode == 'time') {
if (this.params.year) result.year = this.formatNumber(this.year || 0);
if (this.params.month) result.month = this.formatNumber(this.month || 0);
if (this.params.day) result.day = this.formatNumber(this.day || 0);
if (this.params.hour) result.hour = this.formatNumber(this.hour || 0);
if (this.params.minute) result.minute = this.formatNumber(this.minute || 0);
if (this.params.endhour) result.endhour = this.formatNumber(this.endhour || 0);
if (this.params.endminute) result.endminute = this.formatNumber(this.endminute || 0);
// if (this.params.second) result.second = this.formatNumber(this.second || 0);
// if (this.params.timestamp) result.timestamp = this.getTimestamp();
}
if (event) this.$emit(event, result);
this.close();
},
// 获取时间戳
getTimestamp() {
// yyyy-mm-dd为安卓写法,不支持iOS,需要使用"/"分隔,才能二者兼容
let time = this.year + '/' + this.month + '/' + this.day + ' ' + this.hour + ':' + this.minute + ':' + this
.second;
return new Date(time).getTime() / 1000;
}
}
};
</script>
<style lang="scss" scoped>
// 定义混入指令,用于在非nvue环境下的flex定义,因为nvue没有display属性,会报错
@mixin vue-flex($direction: row) {
/* #ifndef APP-NVUE */
display: flex;
flex-direction: $direction;
/* #endif */
}
.u-datetime-picker {
position: relative;
z-index: 999;
}
.u-picker-view {
height: 100%;
box-sizing: border-box;
}
.u-picker-header {
width: 100%;
height: 90rpx;
padding: 0 40rpx;
@include vue-flex;
justify-content: space-between;
align-items: center;
box-sizing: border-box;
font-size: 30rpx;
background: #fff;
position: relative;
}
.u-picker-header::after {
content: '';
position: absolute;
border-bottom: 1rpx solid #eaeef1;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
bottom: 0;
right: 0;
left: 0;
}
.u-picker__title {
color: $u-content-color;
}
.u-picker-body {
width: 100%;
height: 500rpx;
overflow: hidden;
background-color: #fff;
}
.u-column-item {
@include vue-flex;
align-items: center;
justify-content: center;
font-size: 30rpx;
color: $u-main-color;
padding: 0 8rpx;
}
.u-text {
font-size: 24rpx;
padding-left: 8rpx;
}
.u-btn-picker {
padding: 16rpx;
box-sizing: border-box;
text-align: center;
text-decoration: none;
}
.u-opacity {
opacity: 0.5;
}
.u-btn-picker--primary {
color: $u-type-primary;
}
.u-btn-picker--tips {
color: $u-tips-color;
}
</style>

View File

@ -7,24 +7,6 @@
background-color: #F4F5F7 !important;
padding-bottom: 20rpx;
}
.swiper-block {
height: 200rpx;
width: 94%;
padding: 30rpx 3% 10rpx;
background-color: #F4F5F7;
}
.swiper-item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
}
.slide-image {
height: 200rpx;
width: 100%;
margin: 0 auto;
border-radius: 20rpx;
}
.Classificationlist{
margin: 30rpx 0 0;
width: 100%;

View File

@ -19,13 +19,7 @@
</view>
</view>
</view>
<swiper class="swiper-block" :indicator-dots="true" :autoplay="true" :interval="5000" :duration="3000"
circular='true' current='0'>
<swiper-item class="swiper-item" v-for="(item,index) in lbinfo">
<image :src="item.image" class="slide-image">
</image>
</swiper-item>
</swiper>
<u-swiper :list="lbinfo" height='200' interval='3000' duration='1500'></u-swiper>
<view class="conNew">
<view class="title">
周边医养机构

View File

@ -52,7 +52,7 @@
image {
width: 50%;
height: 200rpx;
height: 400rpx;
position: absolute;
left: 25%;
top: 28%;

View File

@ -1,168 +0,0 @@
<template>
<view style="position: relative;">
<!--顶部导航栏-->
<view class="uni-top-tabbar">
<scroll-view scroll-x="true" class="uni-swiper-tab" :style="{backgroundColor:bgColor}">
<view v-for="(tabBar,index) in tabBars" :key="index" class="swiper-tab-list"
:class="{'active': tabIndex==index}" :style="{color:tabIndex==index?selectedTextColor:textColor}"
@tap="toggleTab(index)">
<view class="title">
{{tabBar.goodsCategoryName}}
</view>
<view class="swiper-tab-line"
:style="{backgroundColor:tabIndex==index?selectedBottomColor:bgColor}"></view>
</view>
</scroll-view>
<view class="fenlei" @tap='toggleTab(1111111111111)'>
<image src="../../static/fenlei.png" mode=""></image>
<view class="">
分类
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "topTabbar",
props: {
//选中标签栏的索引
tabIndex: {
type: Number,
default: 0
},
//导航栏标签内容
tabBars: {
type: Array,
default: [{
goodsCategoryName: '标签1',
id: 1
},
{
goodsCategoryName: '标签2',
id: 2
},
{
goodsCategoryName: '标签3',
id: 3
},
{
goodsCategoryName: '标签4',
id: 4
},
{
goodsCategoryName: '标签5',
id: 5
},
{
goodsCategoryName: '标签6',
id: 6
}
]
},
//选中时底部横条颜色
selectedBottomColor: {
type: String,
default: '#D43953'
},
//导航区背景颜色
bgColor: {
type: String,
default: '#ffffff'
},
//选中时文字颜色
selectedTextColor: {
type: String,
default: '#D43953'
},
//默认文本颜色
textColor: {
type: String,
default: '#000000'
}
},
data() {
return {}
},
methods: {
//点击导航栏标签触发
toggleTab(index) {
this.$emit("toggleToptab", index)
}
}
}
</script>
<style lang="scss">
.fenlei {
width: 25%;
display: inline-block;
background-color: #fff;
line-height: 70rpx;
font-weight: normal;
height: 75rpx;
text-align: center;
color: #000000;
position: absolute;
right: 0;
top: 0;
font-size: 32rpx;
view {
position: absolute;
right: 25%;
}
image {
width: 45rpx;
height: 45rpx;
position: absolute;
left: 18%;
top: 50%;
transform: translateY(-55%);
}
}
.title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 100%;
}
.uni-top-tabbar {
/* 以下3项设置用于开启底部阴影显示 */
/* position: relative;
z-index: 1;
overflow: visible; */
width: 75%;
.uni-swiper-tab {
height: 75rpx;
//设置底部阴影
//box-shadow: rgba(170, 170, 170, 0.5) 0 2rpx 8rpx 0;
white-space: nowrap;
.swiper-tab-list {
font-size: 32rpx;
font-weight: normal;
line-height: 70rpx;
padding: 0 15rpx;
//设置标签宽度
text-align: center;
display: inline-block;
}
.active {
.swiper-tab-line {
height: 4rpx;
width: 100%;
margin: auto;
}
}
}
}
</style>

384
pages/utabs/u-tabs.vue Normal file
View File

@ -0,0 +1,384 @@
<template>
<view class="u-tabs" :style="{
background: bgColor
}">
<!-- $u.getRect()对组件根节点无效,因为写了.in(this),故这里获取内层接点尺寸 -->
<view :id="id">
<scroll-view scroll-x class="u-scroll-view" :scroll-left="scrollLeft" scroll-with-animation>
<view class="u-scroll-box" :class="{'u-tabs-scorll-flex': !isScroll}">
<view class="u-tab-item u-line-1" :id="'u-tab-item-' + index" v-for="(item, index) in list"
:key="index" @tap="clickTab(index)" :style="[tabItemStyle(index)]">
<view class="">
{{item.dates}}
</view>
<u-badge :count="item[count] || item['count'] || 0" :offset="offset" size="mini"></u-badge>
{{ item[name] || item['name']}}
</view>
<view v-if="showBar" class="u-tab-bar" :style="[tabBarStyle]"></view>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
/**
* tabs 标签
* @description 该组件,是一个tabs标签组件,在标签多的时候,可以配置为左右滑动,标签少的时候,可以禁止滑动。 该组件的一个特点是配置为滚动模式时,激活的tab会自动移动到组件的中间位置。
* @tutorial https://www.uviewui.com/components/tabs.html
* @property {Boolean} is-scroll tabs是否可以左右拖动(默认true)
* @property {Array} list 标签数组,元素为对象,如[{name: '推荐'}]
* @property {String Number} current 指定哪个tab为激活状态(默认0)
* @property {String Number} height 导航栏的高度,单位rpx(默认80)
* @property {String Number} font-size tab文字大小,单位rpx(默认30)
* @property {String Number} duration 滑块移动一次所需的时间,单位秒(默认0.5)
* @property {String} active-color 滑块和激活tab文字的颜色(默认#2979ff)
* @property {String} inactive-color tabs文字颜色(默认#303133)
* @property {String Number} bar-width 滑块宽度,单位rpx(默认40)
* @property {Object} active-item-style 活动tabs item的样式,对象形式
* @property {Object} bar-style 底部滑块的样式,对象形式
* @property {Boolean} show-bar 是否显示底部的滑块(默认true)
* @property {String Number} bar-height 滑块高度,单位rpx(默认6)
* @property {String Number} item-width 标签的宽度(默认auto)
* @property {String Number} gutter 单个tab标签的左右内边距之和,单位rpx(默认40)
* @property {String} bg-color tabs导航栏的背景颜色(默认#ffffff)
* @property {String} name 组件内部读取的list参数中的属性名(tab名称),见官网说明(默认name)
* @property {String} count 组件内部读取的list参数中的属性名(badge徽标数),同name属性的使用,见官网说明(默认count)
* @property {Array} offset 设置badge徽标数的位置偏移,格式为 [x, y],也即设置的为top和right的值,单位rpx(默认[5, 20])
* @property {Boolean} bold 激活选项的字体是否加粗(默认true)
* @event {Function} change 点击标签时触发
* @example <u-tabs ref="tabs" :list="list" :is-scroll="false"></u-tabs>
*/
export default {
name: "u-tabs",
props: {
// 导航菜单是否需要滚动,如只有2或者3个的时候,就不需要滚动了,此时使用flex平分tab的宽度
isScroll: {
type: Boolean,
default: true
},
//需循环的标签列表
list: {
type: Array,
default () {
return [];
}
},
// 当前活动tab的索引
current: {
type: [Number, String],
default: 0
},
// 导航栏的高度和行高
height: {
type: [String, Number],
default: 80
},
// 字体大小
fontSize: {
type: [String, Number],
default: 24
},
// 过渡动画时长, 单位ms
duration: {
type: [String, Number],
default: 0.5
},
// 选中项的主题颜色
activeColor: {
type: String,
default: '#F44B2F;'
},
// 未选中项的颜色
inactiveColor: {
type: String,
default: '#303133'
},
// 菜单底部移动的bar的宽度,单位rpx
barWidth: {
type: [String, Number],
default: 40
},
// 移动bar的高度
barHeight: {
type: [String, Number],
default: 6
},
// 单个tab的左或有内边距(左右相同)
gutter: {
type: [String, Number],
default: 30
},
// 导航栏的背景颜色
bgColor: {
type: String,
default: '#ffffff'
},
// 读取传入的数组对象的属性(tab名称)
name: {
type: String,
default: 'name'
},
// 读取传入的数组对象的属性(徽标数)
count: {
type: String,
default: 'count'
},
// 徽标数位置偏移
offset: {
type: Array,
default: () => {
return [5, 20]
}
},
// 活动tab字体是否加粗
bold: {
type: Boolean,
default: true
},
// 当前活动tab item的样式
activeItemStyle: {
type: Object,
default () {
return {}
}
},
// 是否显示底部的滑块
showBar: {
type: Boolean,
default: true
},
// 底部滑块的自定义样式
barStyle: {
type: Object,
default () {
return {}
}
},
// 标签的宽度
itemWidth: {
type: [Number, String],
default: 'auto'
}
},
data() {
return {
scrollLeft: 0, // 滚动scroll-view的左边滚动距离
tabQueryInfo: [], // 存放对tab菜单查询后的节点信息
componentWidth: 0, // 屏幕宽度,单位为px
scrollBarLeft: 0, // 移动bar需要通过translateX()移动的距离
parentLeft: 0, // 父元素(tabs组件)到屏幕左边的距离
id: this.$u.guid(), // id值
currentIndex: this.current,
barFirstTimeMove: true, // 滑块第一次移动时(页面刚生成时),无需动画,否则给人怪异的感觉
};
},
watch: {
// 监听tab的变化,重新计算tab菜单的布局信息,因为实际使用中菜单可能是通过
// 后台获取的(如新闻app顶部的菜单),获取返回需要一定时间,所以list变化时,重新获取布局信息
list(n, o) {
// list变动时,重制内部索引,否则可能导致超出数组边界的情况
if (n.length !== o.length) this.currentIndex = 0;
// 用$nextTick等待视图更新完毕后再计算tab的局部信息,否则可能因为tab还没生成就获取,就会有问题
this.$nextTick(() => {
this.init();
});
},
current: {
immediate: true,
handler(nVal, oVal) {
// 视图更新后再执行移动操作
this.$nextTick(() => {
this.currentIndex = nVal;
this.scrollByIndex();
});
}
},
},
computed: {
// 移动bar的样式
tabBarStyle() {
let style = {
width: this.barWidth + 'rpx',
transform: `translate(${this.scrollBarLeft}px, -100%)`,
// 滑块在页面渲染后第一次滑动时,无需动画效果
'transition-duration': `${this.barFirstTimeMove ? 0 : this.duration }s`,
'background-color': this.activeColor,
height: this.barHeight + 'rpx',
opacity: this.barFirstTimeMove ? 0 : 1,
// 设置一个很大的值,它会自动取能用的最大值,不用高度的一半,是因为高度可能是单数,会有小数出现
'border-radius': `${this.barHeight / 2}px`
};
Object.assign(style, this.barStyle);
return style;
},
// tab的样式
tabItemStyle() {
return (index) => {
let style = {
height: this.height + 'rpx',
'line-height': '28rpx',
'font-size': this.fontSize + 'rpx',
'transition-duration': `${this.duration}s`,
padding: this.isScroll ? `0 ${this.gutter}rpx` : '',
flex: this.isScroll ? 'auto' : '1',
width: this.$u.addUnit(this.itemWidth)
};
// 字体加粗
if (index == this.currentIndex && this.bold) style.fontWeight = 'bold';
if (index == this.currentIndex) {
style.color = this.activeColor;
// 给选中的tab item添加外部自定义的样式
style = Object.assign(style, this.activeItemStyle);
} else {
style.color = this.inactiveColor;
}
return style;
}
}
},
methods: {
// 设置一个init方法,方便多处调用
async init() {
// 获取tabs组件的尺寸信息
let tabRect = await this.$uGetRect('#' + this.id);
// tabs组件距离屏幕左边的宽度
this.parentLeft = tabRect.left;
// tabs组件的宽度
this.componentWidth = tabRect.width;
this.getTabRect();
},
// 点击某一个tab菜单
clickTab(index) {
// 点击当前活动tab,不触发事件
if (index == this.currentIndex) return;
// 发送事件给父组件
this.$emit('change', index);
},
// 查询tab的布局信息
getTabRect() {
// 创建节点查询
let query = uni.createSelectorQuery().in(this);
// 历遍所有tab,这里是执行了查询,最终使用exec()会一次性返回查询的数组结果
for (let i = 0; i < this.list.length; i++) {
// 只要size和rect两个参数
query.select(`#u-tab-item-${i}`).fields({
size: true,
rect: true
});
}
// 执行查询,一次性获取多个结果
query.exec(
function(res) {
this.tabQueryInfo = res;
// 初始化滚动条和移动bar的位置
this.scrollByIndex();
}.bind(this)
);
},
// 滚动scroll-view,让活动的tab处于屏幕的中间位置
scrollByIndex() {
// 当前活动tab的布局信息,有tab菜单的width和left(为元素左边界到父元素左边界的距离)等信息
let tabInfo = this.tabQueryInfo[this.currentIndex];
if (!tabInfo) return;
// 活动tab的宽度
let tabWidth = tabInfo.width;
// 活动item的左边到tabs组件左边的距离,用item的left减去tabs的left
let offsetLeft = tabInfo.left - this.parentLeft;
// 将活动的tabs-item移动到屏幕正中间,实际上是对scroll-view的移动
let scrollLeft = offsetLeft - (this.componentWidth - tabWidth) / 2;
this.scrollLeft = scrollLeft < 0 ? 0 : scrollLeft;
// 当前活动item的中点点到左边的距离减去滑块宽度的一半,即可得到滑块所需的移动距离
let left = tabInfo.left + tabInfo.width / 2 - this.parentLeft;
// 计算当前活跃item到组件左边的距离
this.scrollBarLeft = left - uni.upx2px(this.barWidth) / 2;
// 第一次移动滑块的时候,barFirstTimeMove为true,放到延时中将其设置false
// 延时是因为scrollBarLeft作用于computed计算时,需要一个过程需,否则导致出错
if (this.barFirstTimeMove == true) {
setTimeout(() => {
this.barFirstTimeMove = false;
}, 100)
}
}
},
mounted() {
this.init();
}
};
</script>
<style lang="scss" scoped>
// 定义混入指令,用于在非nvue环境下的flex定义,因为nvue没有display属性,会报错
@mixin vue-flex($direction: row) {
/* #ifndef APP-NVUE */
display: flex;
flex-direction: $direction;
/* #endif */
}
.u-tabs {
padding: 20rpx 0;
}
view,
scroll-view {
box-sizing: border-box;
}
/* #ifndef APP-NVUE */
::-webkit-scrollbar,
::-webkit-scrollbar,
::-webkit-scrollbar {
display: none;
width: 0 !important;
height: 0 !important;
-webkit-appearance: none;
background: transparent;
}
/* #endif */
.u-scroll-box {
position: relative;
/* #ifdef MP-TOUTIAO */
white-space: nowrap;
/* #endif */
}
/* #ifdef H5 */
// 通过样式穿透,隐藏H5下,scroll-view下的滚动条
scroll-view ::v-deep ::-webkit-scrollbar {
display: none;
width: 0 !important;
height: 0 !important;
-webkit-appearance: none;
background: transparent;
}
/* #endif */
.u-scroll-view {
width: 100%;
white-space: nowrap;
position: relative;
}
.u-tab-item {
position: relative;
/* #ifndef APP-NVUE */
display: inline-block;
/* #endif */
text-align: center;
transition-property: background-color, color;
}
.u-tab-bar {
position: absolute;
bottom: 0;
}
.u-tabs-scorll-flex {
@include vue-flex;
justify-content: space-between;
}
</style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

BIN
static/dingdan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB