Commit aa6e4c40 authored by weishengfei's avatar weishengfei

新增产检页面开发提交

parent e6d89561
<!-- components/DatePicker.vue -->
<template>
<!-- 底部弹窗遮罩层 -->
<view v-if="visible" class="picker-layer-mask" @click="close"></view>
<!-- 弹窗内容区 -->
<view v-if="visible" class="picker-layer-popup">
<view class="picker-layer-panel">
<!-- 可自定义头部 -->
<view class="picker-layer-header">
<text class="picker-layer-cancel" @click="close">取消</text>
<text class="picker-layer-confirm" @click="handleConfirm">确定</text>
</view>
<view class="picker-layer-view-mask-top"></view>
<view class="picker-layer-view-mask-bottom"></view>
<!-- picker-view 选择器核心 -->
<picker-view
class="picker-layer-view"
mask-style="background: rgb(246, 248, 250); z-index: 0;"
indicator-style="border-radius: 10px; height: 50px; background:#ffffff; z-index:0"
:value="timeValue"
:immediate-change="true"
@change="bindChange"
>
<picker-view-column>
<view class="picker-layer-item" v-for="(item,index) in years" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column>
<view class="picker-layer-item" v-for="(item,index) in months" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column>
<view class="picker-layer-item" v-for="(item,index) in days" :key="index">{{item}}</view>
</picker-view-column>
</picker-view>
</view>
</view>
</template>
<script setup>
import { ref, watch, onMounted } from 'vue'
const props = defineProps({
visible: {
type: Boolean,
default: false
},
defaultDate: {
type: String,
default: ''
}
})
const emit = defineEmits(['update:visible', 'confirm'])
// 日期选择器相关状态
const date = new Date()
const timeValue = ref([]) // 日期选择器当前值
// 年份数据 (2010-当前年份+2)
const years = ref([])
const currentYear = date.getFullYear()
for (let i = 2010; i <= currentYear + 2; i++) {
years.value.push(i)
}
// 月份数据
const months = ref([])
for (let i = 1; i <= 12; i++) {
months.value.push(i)
}
// 日期数据 (动态生成)
const days = ref([])
// 当前选中的年月日
const selectedYear = ref(currentYear)
const selectedMonth = ref(date.getMonth() + 1)
const selectedDay = ref(date.getDate())
// 获取某年某月的天数
function getDaysInMonth(year, month) {
return new Date(year, month, 0).getDate()
}
// 更新日期数据
const updateDays = () => {
const daysInMonth = getDaysInMonth(selectedYear.value, selectedMonth.value)
days.value = []
for (let i = 1; i <= daysInMonth; i++) {
days.value.push(i)
}
// 确保选中的日期不超过当月最大天数
if (selectedDay.value > days.value.length) {
selectedDay.value = days.value.length
}
// 更新选择器的索引值
updateValueIndices()
}
// 更新选择器的索引值
const updateValueIndices = () => {
const yearIndex = years.value.indexOf(selectedYear.value)
const monthIndex = months.value.indexOf(selectedMonth.value)
const dayIndex = days.value.indexOf(selectedDay.value)
if (yearIndex !== -1 && monthIndex !== -1 && dayIndex !== -1) {
timeValue.value = [yearIndex, monthIndex, dayIndex]
}
}
// 设置日期
const setDate = (indices) => {
if (!indices || indices.length !== 3) return
const year = years.value[indices[0]]
const month = months.value[indices[1]]
const day = days.value[indices[2]]
selectedYear.value = year
selectedMonth.value = month
selectedDay.value = day
}
// 时间选择变化时间
const bindChange = (e) => {
const values = e.detail.value
timeValue.value = values
selectedYear.value = years.value[values[0]]
selectedMonth.value = months.value[values[1]]
selectedDay.value = days.value[values[2]]
}
// 关闭弹窗
const close = () => {
emit('update:visible', false)
}
// 确认选择
const handleConfirm = () => {
const formattedDate = `${selectedYear.value}-${String(selectedMonth.value).padStart(2, '0')}-${String(selectedDay.value).padStart(2, '0')}`
emit('confirm', formattedDate)
close()
}
// 初始化日期数据
const initDate = () => {
// 如果有默认日期,解析日期并设置选中值
if (props.defaultDate) {
const dateParts = props.defaultDate.split('-')
const year = parseInt(dateParts[0])
const month = parseInt(dateParts[1])
const day = parseInt(dateParts[2])
// 更新选中值
selectedYear.value = year
selectedMonth.value = month
selectedDay.value = day
// 更新 timeValue 的索引
const yearIndex = years.value.indexOf(year)
const monthIndex = months.value.indexOf(month)
const dayIndex = days.value.indexOf(day)
timeValue.value = [yearIndex, monthIndex, dayIndex]
} else {
// 如果没有时间,设置为当前日期
const today = new Date()
const yearIndex = years.value.indexOf(today.getFullYear())
const monthIndex = months.value.indexOf(today.getMonth() + 1)
const dayIndex = days.value.indexOf(today.getDate())
timeValue.value = [yearIndex, monthIndex, dayIndex]
}
}
// 监听年份和月份变化,更新日期数据
watch([selectedYear, selectedMonth], () => {
updateDays()
})
// 监听选择器值变化,更新选中日期
watch(() => timeValue.value, (newVal) => {
setDate(newVal)
})
// 监听visible变化,初始化数据
watch(() => props.visible, (newVal) => {
if (newVal) {
initDate()
}
})
onMounted(() => {
updateDays()
})
</script>
<style lang="less" scoped>
.picker-layer-mask {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 3999;
}
/* 遮罩层样式 */
.picker-layer-popup {
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 4000;
display: flex;
flex-direction: column;
align-items: center;
animation: picker-layer-up 0.3s;
}
@keyframes picker-layer-up {
from {
transform: translateY(100%);
}
to {
transform: translateY(0);
}
}
/* 弹窗容器样式 */
.picker-layer-panel {
width: 100vw;
height: 50vh;
background: #f6f8fa;
border-top-left-radius: 24rpx;
border-top-right-radius: 24rpx;
overflow: hidden;
display: flex;
flex-direction: column;
position: relative;
}
.picker-layer-header {
display: flex;
justify-content: space-between;
align-items: center;
height: 140rpx;
box-sizing: border-box;
background: #f6f8fa;
padding: 0 32rpx;
.picker-layer-cancel {
color: #6f6d67;
font-size: 28rpx;
width: 136rpx;
height: 74rpx;
border-radius: 20rpx;
background: #ffffff;
display: flex;
align-items: center;
justify-content: center;
}
.picker-layer-confirm {
color: #ffffff;
font-size: 28rpx;
width: 136rpx;
height: 74rpx;
border-radius: 20rpx;
background: #d3a358;
display: flex;
align-items: center;
justify-content: center;
}
.picker-layer-title {
color: #222;
font-size: 32rpx;
font-weight: bold;
}
}
.picker-layer-view {
flex: 1;
width: 100%;
height: 100%;
}
.picker-layer-item {
height: 100rpx;
line-height: 100rpx;
text-align: center;
font-size: 32rpx;
color: #1d1e25;
}
.picker-layer-view-mask-top {
position: absolute;
top: 140rpx;
left: 0;
width: 100%;
height: calc(50% - 100rpx);
z-index: 1;
background: linear-gradient(to bottom,
rgb(246, 248, 250) 0%,
rgba(255, 255, 255, 0.5) 100%);
pointer-events: none;
}
.picker-layer-view-mask-bottom {
position: absolute;
bottom: 0rpx;
left: 0;
width: 100%;
height: calc(50% - 100rpx);
z-index: 1;
background: linear-gradient(to top,
rgb(246, 248, 250) 0%,
rgba(255, 255, 255, 0.5) 100%);
pointer-events: none;
}
</style>
\ No newline at end of file
......@@ -87,8 +87,16 @@
"enablePullDownRefresh" : false,
"navigationStyle": "custom"
}
},
{
"path" : "pages/addPostnatal/addPostnatal",
"style" :
{
"navigationBarTitleText" : "新增产检",
"navigationBarBackgroundColor":"#ffffff",
"enablePullDownRefresh" : false
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
......
<template>
<view class="add-postnatal">
<!-- 产检时间 -->
<view class="add-postnatal-time style1">
<view class="time-l">
<image src="/static/chanjianTool/icon7.png" />
产检时间
</view>
<view class="time-r" @click="onChangeTime">
{{time}}
<image src="/static/chanjianTool/icon13.png" />
</view>
</view>
<!-- 产检项目 -->
<view class="add-postnatal-project">
<view class="project-info style1">
<view class="time-l">
<image src="/static/chanjianTool/icon8.png" />
产检项目
</view>
<view class="project-r" @click="onAdd">
<image src="/static/chanjianTool/icon10.png" />
添加
</view>
</view>
<!-- 添加的产品项目 -->
<view class="project-list" v-if="listData.length > 0">
<view class="list-item" v-for="({name, id}, index) in listData" :key="index">
<view class="item-name">
{{name}}
</view>
<image @click="onDetele(id)" class="item-img" src="/static/chanjianTool/delete.png"></image>
</view>
</view>
</view>
<!-- 报告单 -->
<view class="add-postnatal-bgd">
<view class="style1">
<view class="time-l">
<image src="/static/chanjianTool/icon9.png" />
本次报告单
</view>
<view class="time-r">
查看全部
<image src="/static/chanjianTool/icon13.png" />
</view>
</view>
<view class="img-list" v-if="bgdImgList.length > 0">
<view class="img-list-item" v-for="( {url, id}, index) in bgdImgList" :key="index">
<view class="item-image">
<image class="img1" :src="url" mode="widthFix"></image>
</view>
<image @click="onImageDel(id)" class="img" src="/static/chanjianTool/icon14.png"></image>
</view>
</view>
</view>
<!-- 上传报告单 -->
<view class="upload" @click="onUpload">
<image src="/static/chanjianTool/icon11.png"></image>
</view>
<button class="form-btn" @click="onSave">
保存
</button>
<!-- 产检选择时间 -->
<!-- 使用封装后的日期选择器组件 -->
<DatePicker
v-model:visible="visible"
:default-date="time"
@confirm="handleDateConfirm"
/>
<!-- 产检项目底部弹窗 -->
<uni-popup ref="popup" type="bottom" :mask-click="false" background-color="#f6f8fa" border-radius="32rpx 32rpx 0 0">
<view class="popup container">
<view class="popup-close" @click="onPopupClose">
<image src="/static/chanjianTool/icon15.png"></image>
</view>
<!-- 项目列表 -->
<scroll-view scroll-y @touchmove.stop.prevent=""
class="airport-list">
<view v-for="group in list" :key="group.letter" class="letter-group">
<view class="letter-title">{{ group.letter }}</view>
<view class="box">
<view v-for="item in group.data" :key="item.id" class="airport-item">
<view class="airport-item-radio" @click="toggleSelect(item)">
<image class="image-1" v-if="isSelected(item.id)" src="/static/chanjianTool/icon17.png" mode=""></image>
<image class="image-2" v-else src="/static/chanjianTool/icon18.png"></image>
{{ item.name }}
</view>
<view class="airport-item-image" @click="onView(item)">
<image src="/static/chanjianTool/icon16.png"></image>
</view>
</view>
</view>
</view>
</scroll-view>
<!-- 底部操作栏 -->
<button class="action-bar" @click="saveSelection">确认</button>
</view>
</uni-popup>
<!-- 项目介绍 -->
<uni-popup ref="popupText" type="bottom" :mask-click="false" background-color="#FFFFFF" border-radius="32rpx 32rpx 0 0">
<view class="container2">
<view class="text-t">
<view class="t-1">
{{popupTextObj.name}}
</view>
<image @click="onPopupClose2" src="/static/chanjianTool/icon15.png" mode=""></image>
</view>
<view class="text-c">
{{popupTextObj.text}}
</view>
</view>
</uni-popup>
</view>
</template>
<script setup>
import {
ref
} from 'vue'
import {
dateFormatter,
throttleTap,
showLoading,
hideLoading
} from '@/utils/index.js';
import {
uploadImage
} from "../../api/common.js";
// 导入日期选择器组件
import DatePicker from '@/components/DatePicker.vue'
// 默认产检时间
const time = ref(dateFormatter(new Date(), 'yyyy-MM-dd'));
// 控制选择时间显示
const visible = ref(false)
// 产品项目底部弹窗
const popup = ref(null)
// 产品项目介绍底部弹窗
const popupText = ref(null)
// 存储查看项目介绍内容
const popupTextObj = ref({})
// 模拟项目列表
const list = ref([{
"letter": "A",
"data": [{
id: 'A001',
name: "阿克苏机场",
text:'NT可以帮助判断胎宝宝是否患有唐氏综合征等染色体异常,或存在畸形的风险,有助于早期发现胎儿异常风险问题。 NT检查通常在孕 1'
},
{
id: 'A002',
name: "阿拉山口机场",
text:'NT可以帮助判断胎宝宝是否患有唐氏综合征等染色体异常,或存在畸形的风险,有助于早期发现胎儿异常风险问题。 NT检查通常在孕 1'
}
]
}, {
"letter": "B",
"data": [{
id: 'B001',
name: "保山机场",
text:'NT可以帮助判断胎宝宝是否患有唐氏综合征等染色体异常,或存在畸形的风险,有助于早期发现胎儿异常风险问题。 NT检查通常在孕 1'
},
{
id: 'B002',
name: "包头机场",
text:'NT可以帮助判断胎宝宝是否患有唐氏综合征等染色体异常,或存在畸形的风险,有助于早期发现胎儿异常风险问题。 NT检查通常在孕 1NT可以帮助判断胎宝宝是否患有唐氏综合征等染色体异常,或存在畸形的风险,有助于早期发现胎儿异常风险问题。 NT检查通常在孕 1NT可以帮助判断胎宝宝是否患有唐氏综合征等染色体异常,或存在畸形的风险,有助于早期发现胎儿异常风险问题。 NT检查通常在孕 1NT可以帮助判断胎宝宝是否患有唐氏综合征等染色体异常,或存在畸形的风险,有助于早期发现胎儿异常风险问题。 NT检查通常在孕 1NT可以帮助判断胎宝宝是否患有唐氏综合征等染色体异常,或存在畸形的风险,有助于早期发现胎儿异常风险问题。 NT检查通常在孕 1NT可以帮助判断胎宝宝是否患有唐氏综合征等染色体异常,或存在畸形的风险,有助于早期发现胎儿异常风险问题。 NT检查通常在孕 1'
}
]
}]);
// 已选项目(存储ID和name)
const selectedAirports = ref([]);
// 添加的产品列表
const listData = ref([]);
// 报告单图片
const bgdImgList = ref([{
url: 'https://momclub-picture-1253290912.cos.ap-beijing.myqcloud.com/xmh-mini-program/user/image/2025/07/17/xmh-mini-program_1752739702325_167279.jpeg',
id: Date.now() + Math.floor(Math.random() * 1000)
},
{
url: 'https://momclub-picture-1253290912.cos.ap-beijing.myqcloud.com/xmh-mini-program/user/image/2025/07/17/xmh-mini-program_1752739702325_167279.jpeg',
id: Date.now() + Math.floor(Math.random() * 1000)
},
{
url: 'https://momclub-picture-1253290912.cos.ap-beijing.myqcloud.com/xmh-mini-program/user/image/2025/07/17/xmh-mini-program_1752739702325_167279.jpeg',
id: Date.now() + Math.floor(Math.random() * 1000)
},
{
url: 'https://momclub-picture-1253290912.cos.ap-beijing.myqcloud.com/xmh-mini-program/user/image/2025/07/17/xmh-mini-program_1752739702325_167279.jpeg',
id: Date.now() + Math.floor(Math.random() * 1000)
},
{
url: 'https://momclub-picture-1253290912.cos.ap-beijing.myqcloud.com/xmh-mini-program/user/image/2025/07/17/xmh-mini-program_1752739702325_167279.jpeg',
id: Date.now() + Math.floor(Math.random() * 1000)
}
])
// 查看项目介绍
const onView = (item) =>{
console.log(item)
popupTextObj.value = item
popupText.value.open()
}
// 关闭项目介绍弹窗
const onPopupClose2 = () => {
popupText.value.close()
}
// 修改时间
const onChangeTime = () => {
visible.value = true;
}
// 选择日期回调确认
const handleDateConfirm = (date) => {
console.log('选择的日期是:', date);
time.value = date;
}
// 添加项目
const onAdd = () => {
wx.setPageStyle({
style: {
overflow: 'hidden'
}
})
popup.value.open()
// 回显数据
if(listData.value.length > 0){
// 回显数据 - 将 listData 中的数据同步到 selectedAirports
selectedAirports.value = [...listData.value]
}
}
// 关闭项目弹窗
const onPopupClose = () => {
wx.setPageStyle({
style: {
overflow: 'auto'
}
})
selectedAirports.value = []
popup.value.close()
}
// 检查是否已选中
const isSelected = (id) => {
return selectedAirports.value.some(item => item.id === id);
};
// 切换选择状态
const toggleSelect = (airport) => {
const index = selectedAirports.value.findIndex(item => item.id === airport.id);
if (index === -1) {
selectedAirports.value.push({
id: airport.id,
name: airport.name
});
} else {
selectedAirports.value.splice(index, 1);
}
};
// 保存选择
const saveSelection = () => {
console.log('已选项目ID:', selectedAirports.value);
// 合并 selectedAirports.value 到 listData.value,并去重
const combined = [...listData.value, ...selectedAirports.value];
const uniqueMap = new Map();
combined.forEach(item => uniqueMap.set(item.id, item));
listData.value = Array.from(uniqueMap.values());
onPopupClose();
};
// 移除已选项目
const removeSelected = (airport) => {
const index = selectedAirports.value.findIndex(item => item.id === airport.id);
if (index !== -1) {
selectedAirports.value.splice(index, 1);
}
};
// 删除所选产品项目
const onDetele = (id) => {
listData.value.filter((item, index) => {
if (item.id === id) {
listData.value.splice(index, 1)
}
})
}
// 删除上传图片
const onImageDel = (id) => {
bgdImgList.value.filter((item, index) => {
if (item.id === id) {
bgdImgList.value.splice(index, 1)
}
})
}
// 上传图片
const onUpload = throttleTap(() => {
// 唤起图片选择器
uni.chooseImage({
count: 15,
sizeType: ["original", "compressed"],
sourceType: ["album", "camera"],
success: async (res) => {
showLoading();
const tempFilePath = res.tempFilePaths[0];
console.log(tempFilePath)
const fs = uni.getFileSystemManager();
console.log(fs)
const base64 =
"data:image/jpeg;base64," + fs.readFileSync(tempFilePath, "base64");
const uploadRes = await uploadImage(base64);
hideLoading();
if (uploadRes.success) {
console.log(uploadRes)
bgdImgList.value.push({
url: uploadRes.data.url,
id: Date.now() + Math.floor(Math.random() * 1000)
})
} else {
uni.showToast({
title: uploadRes.message,
icon: "none",
});
}
},
});
})
// 保存
const onSave = throttleTap(() => {
if(listData.value.length == 0){
uni.showToast({
title: '还没有添加产检项哦',
icon: 'none'
})
return
}
const param = {
time: time.value,
list: listData.value,
bgdImgList: bgdImgList.value
}
console.log(param, '参数')
showLoading();
// const {success, data} = await updateBabyInfo(data);
const { success, data, message } = {
success: true,
message: '',
data:{}
}
hideLoading();
if(success){
uni.showToast({
title: "保存成功",
icon: "success",
});
uni.navigateBack()
} else {
uni.showToast({
title: message,
icon: "none",
});
}
})
</script>
<style lang="less" scoped>
.add-postnatal {
height: 100vh;
background-color: #f7f8fa;
padding: 25rpx 35rpx;
.style1 {
width: 680rpx;
height: 115rpx;
background: #ffffff;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 30rpx;
padding: 0 27rpx;
box-sizing: border-box;
.time-l,
.time-r,
.project-r {
display: flex;
align-items: center;
}
.time-l {
color: #000000;
font-weight: 600;
image {
width: 30rpx;
height: 30rpx;
margin-right: 10rpx;
}
}
}
&-time {
margin-top: 22rpx;
border-radius: 16rpx;
.time-r {
color: #1d1e26;
image {
width: 8rpx;
height: 16rpx;
margin-left: 12rpx;
}
}
}
&-project {
width: 680rpx;
border-radius: 16rpx;
overflow: hidden;
margin-top: 22rpx;
background: #ffffff;
.project-r {
color: #b27c1e;
image {
width: 27rpx;
height: 27rpx;
margin-right: 5rpx;
}
}
}
&-bgd {
width: 680rpx;
border-radius: 16rpx;
margin-top: 22rpx;
background: #ffffff;
.time-r {
color: #1d1e26;
image {
width: 8rpx;
height: 16rpx;
margin-left: 12rpx;
}
}
.img-list {
display: flex;
flex-wrap: wrap;
padding: 0 27rpx;
box-sizing: border-box;
padding-bottom: 180rpx;
.img-list-item {
margin-right: 15rpx;
margin-bottom: 15rpx;
position: relative;
.item-image {
width: 191rpx;
height: 191rpx;
border-radius: 10rpx;
overflow: hidden;
.img1 {
width: 191rpx;
height: 191rpx;
}
}
.img {
position: absolute;
right: -12rpx;
top: -12rpx;
width: 25rpx;
height: 25rpx;
}
}
}
}
.project-list {
.list-item {
width: 680rpx;
height: 115rpx;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 30rpx;
padding: 0 27rpx;
border-top: 1rpx solid #e9e9e9;
box-sizing: border-box;
.item-name {
width: 500rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 30rpx;
color: #000000;
font-weight: 500;
}
.item-img {
width: 31rpx;
height: 31rpx;
}
}
}
.upload {
position: fixed;
right: 0;
bottom: 260rpx;
image {
width: 185rpx;
height: 61rpx;
}
}
.form-btn {
width: 686rpx;
height: 94rpx;
border-radius: 46rpx;
background-color: #d3a358;
color: #ffffff;
font-size: 32rpx;
display: flex;
align-items: center;
justify-content: center;
position: fixed;
bottom: 60rpx;
left: 50%;
transform: translateX(-50%);
z-index: 2;
}
// 索引栏
.container {
display: flex;
flex-direction: column;
height: 1200rpx;
padding: 20rpx 35rpx 30rpx 35rpx;
overflow: hidden;
background: #f6f8fa;
position: relative;
border-radius: 32rpx 32rpx 0 0;
}
.popup-close{
position: absolute;
right: 34rpx;
top: 45rpx;
z-index: 10;
image{
width: 28rpx;
height: 29rpx;
}
}
.airport-list {
flex: 1;
overflow: auto;
-webkit-overflow-scrolling: touch;
}
.letter-group {
margin-top: 30rpx;
margin-bottom: 30rpx;
}
.letter-title {
padding: 0 38rpx;
font-weight: bold;
// position: sticky;
// top: 0;
z-index: 10;
color: #000000;
font-weight: 600;
font-size: 34rpx;
margin-bottom: 30rpx;
}
.box{
width: 100%;
overflow: hidden;
border-radius: 16rpx;
padding: 0 36rpx;
box-sizing: border-box;
background: #fff;
}
.airport-item {
width: 100%;
height: 115rpx;
box-sizing: border-box;
background-color: #ffffff;
touch-action: none;
font-size: 30rpx;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1rpx solid #e2e2e2;
&:last-child{
border:none;
}
.airport-item-image{
image{
width: 11rpx;
height: 21rpx;
}
}
}
.airport-item-radio{
display: flex;
align-items: center;
image{
margin-right: 8rpx;
margin-top: 5rpx;
}
.image-1{
width: 29rpx;
height: 29rpx;
}
.image-2{
width: 29rpx;
height: 29rpx;
}
}
.action-bar {
width: 686rpx;
height: 94rpx;
border-radius: 46rpx;
background-color: #d3a358;
color: #ffffff;
font-size: 32rpx;
display: flex;
align-items: center;
justify-content: center;
position: sticky;
bottom: 0;
z-index: 10;
}
.selected-list {
margin-top: 20rpx;
padding: 20rpx;
background-color: #f9f9f9;
border-radius: 10rpx;
max-height: 200rpx;
overflow: auto;
-webkit-overflow-scrolling: touch;
}
.title {
font-weight: bold;
margin-bottom: 15rpx;
position: sticky;
top: 0;
background-color: #f9f9f9;
z-index: 10;
}
.selected-items {
display: flex;
flex-wrap: wrap;
}
.selected-item {
position: relative;
background-color: #e6f7ff;
color: #1890ff;
padding: 10rpx 20rpx;
margin: 0 15rpx 15rpx 0;
border-radius: 30rpx;
touch-action: none;
}
.remove {
margin-left: 10rpx;
color: #ff4d4f;
cursor: pointer;
}
.container2 {
height:595rpx;
padding: 50rpx 35rpx 30rpx 35rpx;
overflow: hidden;
background: #ffffff;
border-radius: 32rpx 32rpx 0 0;
color: #000000;
display: flex;
flex-direction: column;
.text-t{
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: space-between;
.t-1{
flex: 1;
font-size: 34rpx;
font-weight: 700;
}
image{
width: 28rpx;
height: 29rpx;
}
}
.text-c{
flex: 1;
overflow: auto;
margin-top: 22rpx;
font-weight: 500;
}
}
}
</style>
\ No newline at end of file
......@@ -68,7 +68,7 @@
</view>
</view>
<!-- 新增产检 -->
<view class="postnatal-add">
<view class="postnatal-add" @click="onAdd">
<image src="/static/chanjianTool/add.png"></image>
</view>
<!-- 选择提醒弹窗 -->
......@@ -375,6 +375,12 @@
// buttonName: buttonName,
// });
}
// 新增体检
const onAdd = ()=>{
uni.navigateTo({
url:'/pages/addPostnatal/addPostnatal'
})
}
// 按钮点击
const onBtn = (type) => {
console.log(type)
......
## 1.2.1(2021-11-22)
- 修复 vue3中某些scss变量无法找到的问题
## 1.2.0(2021-11-19)
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-indexed-list](https://uniapp.dcloud.io/component/uniui/uni-indexed-list)
## 1.1.0(2021-07-30)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.0.11(2021-05-12)
- 新增 组件示例地址
## 1.0.10(2021-04-21)
- 优化 添加依赖 uni-icons, 导入后自动下载依赖
## 1.0.9(2021-02-05)
- 优化 组件引用关系,通过uni_modules引用组件
## 1.0.8(2021-02-05)
- 调整为uni_modules目录规范
- 新增 支持 PC 端
<template>
<view>
<view v-if="loaded || list.itemIndex < 15" class="uni-indexed-list__title-wrapper">
<text v-if="list.items && list.items.length > 0" class="uni-indexed-list__title">{{ list.key }}</text>
</view>
<view v-if="(loaded || list.itemIndex < 15) && list.items && list.items.length > 0" class="uni-indexed-list__list">
<view v-for="(item, index) in list.items" :key="index" class="uni-indexed-list__item" hover-class="uni-indexed-list__item--hover">
<view class="uni-indexed-list__item-container" @click="onClick(idx, index)">
<view class="uni-indexed-list__item-border" :class="{'uni-indexed-list__item-border--last':index===list.items.length-1}">
<view v-if="showSelect" style="margin-right: 20rpx;">
<uni-icons :type="item.checked ? 'checkbox-filled' : 'circle'" :color="item.checked ? '#007aff' : '#C0C0C0'" size="24" />
</view>
<text class="uni-indexed-list__item-content">{{ item.name }}</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'UniIndexedList',
emits:['itemClick'],
props: {
loaded: {
type: Boolean,
default: false
},
idx: {
type: Number,
default: 0
},
list: {
type: Object,
default () {
return {}
}
},
showSelect: {
type: Boolean,
default: false
}
},
methods: {
onClick(idx, index) {
this.$emit("itemClick", {
idx,
index
})
}
}
}
</script>
<style lang="scss" scoped>
.uni-indexed-list__list {
background-color: $uni-bg-color;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
border-top-style: solid;
border-top-width: 1px;
border-top-color: #DEDEDE;
}
.uni-indexed-list__item {
font-size: 14px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.uni-indexed-list__item-container {
padding-left: 15px;
flex: 1;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
/* #endif */
flex-direction: row;
justify-content: space-between;
align-items: center;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
.uni-indexed-list__item-border {
flex: 1;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
/* #endif */
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 50px;
padding: 25px;
padding-left: 0;
border-bottom-style: solid;
border-bottom-width: 1px;
border-bottom-color: #DEDEDE;
}
.uni-indexed-list__item-border--last {
border-bottom-width: 0px;
}
.uni-indexed-list__item-content {
flex: 1;
font-size: 14px;
color: #191919;
}
.uni-indexed-list {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.uni-indexed-list__title-wrapper {
/* #ifndef APP-NVUE */
display: flex;
width: 100%;
/* #endif */
background-color: #f7f7f7;
}
.uni-indexed-list__title {
padding: 6px 12px;
line-height: 24px;
font-size: 16px;
font-weight: 500;
}
</style>
<template>
<view class="uni-indexed-list" ref="list" id="list">
<!-- #ifdef APP-NVUE -->
<list class="uni-indexed-list__scroll" scrollable="true" show-scrollbar="false">
<cell v-for="(list, idx) in lists" :key="idx" :ref="'uni-indexed-list-' + idx">
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<scroll-view :scroll-into-view="scrollViewId" class="uni-indexed-list__scroll" scroll-y>
<view v-for="(list, idx) in lists" :key="idx" :id="'uni-indexed-list-' + idx">
<!-- #endif -->
<indexed-list-item :list="list" :loaded="loaded" :idx="idx" :showSelect="showSelect"
@itemClick="onClick"></indexed-list-item>
<!-- #ifndef APP-NVUE -->
</view>
</scroll-view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
</cell>
</list>
<!-- #endif -->
<view class="uni-indexed-list__menu" @touchstart="touchStart" @touchmove.stop.prevent="touchMove"
@touchend="touchEnd" @mousedown.stop="mousedown" @mousemove.stop.prevent="mousemove"
@mouseleave.stop="mouseleave">
<view v-for="(list, key) in lists" :key="key" class="uni-indexed-list__menu-item"
:class="touchmoveIndex == key ? 'uni-indexed-list__menu--active' : ''">
<text class="uni-indexed-list__menu-text"
:class="touchmoveIndex == key ? 'uni-indexed-list__menu-text--active' : ''">{{ list.key }}</text>
</view>
</view>
<view v-if="touchmove" class="uni-indexed-list__alert-wrapper">
<text class="uni-indexed-list__alert">{{ lists[touchmoveIndex].key }}</text>
</view>
</view>
</template>
<script>
import indexedListItem from './uni-indexed-list-item.vue'
// #ifdef APP-NVUE
const dom = weex.requireModule('dom');
// #endif
// #ifdef APP-PLUS
function throttle(func, delay) {
var prev = Date.now();
return function() {
var context = this;
var args = arguments;
var now = Date.now();
if (now - prev >= delay) {
func.apply(context, args);
prev = Date.now();
}
}
}
function touchMove(e) {
let pageY = e.touches[0].pageY
let index = Math.floor((pageY - this.winOffsetY) / this.itemHeight)
if (this.touchmoveIndex === index) {
return false
}
let item = this.lists[index]
if (item) {
// #ifndef APP-NVUE
this.scrollViewId = 'uni-indexed-list-' + index
this.touchmoveIndex = index
// #endif
// #ifdef APP-NVUE
dom.scrollToElement(this.$refs['uni-indexed-list-' + index][0], {
animated: false
})
this.touchmoveIndex = index
// #endif
}
}
const throttleTouchMove = throttle(touchMove, 40)
// #endif
/**
* IndexedList 索引列表
* @description 用于展示索引列表
* @tutorial https://ext.dcloud.net.cn/plugin?id=375
* @property {Boolean} showSelect = [true|false] 展示模式
* @value true 展示模式
* @value false 选择模式
* @property {Object} options 索引列表需要的数据对象
* @event {Function} click 点击列表事件 ,返回当前选择项的事件对象
* @example <uni-indexed-list options="" showSelect="false" @click=""></uni-indexed-list>
*/
export default {
name: 'UniIndexedList',
components: {
indexedListItem
},
emits: ['click'],
props: {
options: {
type: Array,
default () {
return []
}
},
showSelect: {
type: Boolean,
default: false
}
},
data() {
return {
lists: [],
winHeight: 0,
itemHeight: 0,
winOffsetY: 0,
touchmove: false,
touchmoveIndex: -1,
scrollViewId: '',
touchmovable: true,
loaded: false,
isPC: false
}
},
watch: {
options: {
handler: function() {
this.setList()
},
deep: true
}
},
mounted() {
// #ifdef H5
this.isPC = this.IsPC()
// #endif
setTimeout(() => {
this.setList()
}, 50)
setTimeout(() => {
this.loaded = true
}, 300);
},
methods: {
setList() {
let index = 0;
this.lists = []
this.options.forEach((value, index) => {
if (value.data.length === 0) {
return
}
let indexBefore = index
let items = value.data.map(item => {
let obj = {}
obj['key'] = value.letter
obj['name'] = item
obj['itemIndex'] = index
index++
obj.checked = item.checked ? item.checked : false
return obj
})
this.lists.push({
title: value.letter,
key: value.letter,
items: items,
itemIndex: indexBefore
})
})
// #ifndef APP-NVUE
uni.createSelectorQuery()
.in(this)
.select('#list')
.boundingClientRect()
.exec(ret => {
this.winOffsetY = ret[0].top
this.winHeight = ret[0].height
this.itemHeight = this.winHeight / this.lists.length
})
// #endif
// #ifdef APP-NVUE
dom.getComponentRect(this.$refs['list'], (res) => {
this.winOffsetY = res.size.top
this.winHeight = res.size.height
this.itemHeight = this.winHeight / this.lists.length
})
// #endif
},
touchStart(e) {
this.touchmove = true
let pageY = this.isPC ? e.pageY : e.touches[0].pageY
let index = Math.floor((pageY - this.winOffsetY) / this.itemHeight)
let item = this.lists[index]
if (item) {
this.scrollViewId = 'uni-indexed-list-' + index
this.touchmoveIndex = index
// #ifdef APP-NVUE
dom.scrollToElement(this.$refs['uni-indexed-list-' + index][0], {
animated: false
})
// #endif
}
},
touchMove(e) {
// #ifndef APP-PLUS
let pageY = this.isPC ? e.pageY : e.touches[0].pageY
let index = Math.floor((pageY - this.winOffsetY) / this.itemHeight)
if (this.touchmoveIndex === index) {
return false
}
let item = this.lists[index]
if (item) {
this.scrollViewId = 'uni-indexed-list-' + index
this.touchmoveIndex = index
}
// #endif
// #ifdef APP-PLUS
throttleTouchMove.call(this, e)
// #endif
},
touchEnd() {
this.touchmove = false
// this.touchmoveIndex = -1
},
/**
* 兼容 PC @tian
*/
mousedown(e) {
if (!this.isPC) return
this.touchStart(e)
},
mousemove(e) {
if (!this.isPC) return
this.touchMove(e)
},
mouseleave(e) {
if (!this.isPC) return
this.touchEnd(e)
},
// #ifdef H5
IsPC() {
var userAgentInfo = navigator.userAgent;
var Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
var flag = true;
for (let v = 0; v < Agents.length - 1; v++) {
if (userAgentInfo.indexOf(Agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
},
// #endif
onClick(e) {
let {
idx,
index
} = e
let obj = {}
for (let key in this.lists[idx].items[index]) {
obj[key] = this.lists[idx].items[index][key]
}
let select = []
if (this.showSelect) {
this.lists[idx].items[index].checked = !this.lists[idx].items[index].checked
this.lists.forEach((value, idx) => {
value.items.forEach((item, index) => {
if (item.checked) {
let obj = {}
for (let key in this.lists[idx].items[index]) {
obj[key] = this.lists[idx].items[index][key]
}
select.push(obj)
}
})
})
}
this.$emit('click', {
item: obj,
select: select
})
}
}
}
</script>
<style lang="scss" scoped>
.uni-indexed-list {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.uni-indexed-list__scroll {
flex: 1;
}
.uni-indexed-list__menu {
width: 24px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
}
.uni-indexed-list__menu-item {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
align-items: center;
justify-content: center;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
.uni-indexed-list__menu-text {
font-size: 12px;
text-align: center;
color: #aaa;
}
.uni-indexed-list__menu--active {
// background-color: rgb(200, 200, 200);
}
.uni-indexed-list__menu--active {}
.uni-indexed-list__menu-text--active {
border-radius: 16px;
width: 16px;
height: 16px;
line-height: 16px;
background-color: #007aff;
color: #fff;
}
.uni-indexed-list__alert-wrapper {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
}
.uni-indexed-list__alert {
width: 80px;
height: 80px;
border-radius: 80px;
text-align: center;
line-height: 80px;
font-size: 35px;
color: #fff;
background-color: rgba(0, 0, 0, 0.5);
}
</style>
{
"id": "uni-indexed-list",
"displayName": "uni-indexed-list 索引列表",
"version": "1.2.1",
"description": "索引列表组件,右侧带索引的列表,方便快速定位到具体内容,通常用于城市/机场选择等场景",
"keywords": [
"uni-ui",
"索引列表",
"索引",
"列表"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"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",
"uni-icons"
],
"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"
}
}
}
}
}
## IndexedList 索引列表
> **组件名:uni-indexed-list**
> 代码块: `uIndexedList`
用于展示索引列表。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-indexed-list)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
......@@ -110,3 +110,45 @@ export function hideLoading() {
uni.hideLoading();
}
}
/**
* 日期格式化
* @param date 接收可以被new Date()方法转换的内容
* @param format 字符串,需要的格式例如:'yyyy/MM/dd hh:mm:ss'
* @returns {String}
*/
const dateFormatter = (date, format = "yyyy/MM/dd") => {
if (!date) return "-";
date = new Date(
typeof date === "string" && isNaN(date)
? date.replace(/-/g, "/")
: Number(date)
);
const o = {
"M+": date.getMonth() + 1,
"d+": date.getDate(),
"h+": date.getHours(),
"m+": date.getMinutes(),
"s+": date.getSeconds(),
"q+": Math.floor((date.getMonth() + 3) / 3),
S: date.getMilliseconds(),
};
if (/(y+)/.test(format)) {
format = format.replace(
RegExp.$1,
(date.getFullYear() + "").substr(4 - RegExp.$1.length)
);
}
for (const k in o) {
if (new RegExp("(" + k + ")").test(format)) {
format = format.replace(
RegExp.$1,
RegExp.$1.length === 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)
);
}
}
return format;
};
export {
dateFormatter
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment