You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
516 lines
11 KiB
Vue
516 lines
11 KiB
Vue
<template>
|
|
<view class="page-container">
|
|
<view class="page-header">
|
|
<view class="header-bg"></view>
|
|
<view class="header-content">
|
|
<view class="back-btn" @click="goBack">
|
|
<uni-icons type="left" size="20" color="#FFFFFF"></uni-icons>
|
|
</view>
|
|
<view class="header-title">选择预约时段</view>
|
|
<view class="header-placeholder"></view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="info-card" v-if="MianInfo">
|
|
<view class="info-header">
|
|
<uni-icons type="medal" size="20" color="#2E7D32"></uni-icons>
|
|
<text class="info-title">{{ MianInfo.entrust }}</text>
|
|
</view>
|
|
<view class="info-body">
|
|
<view class="info-row">
|
|
<text class="info-label">登记号</text>
|
|
<text class="info-value">{{ MianInfo.reg_num }}</text>
|
|
</view>
|
|
<view class="info-row">
|
|
<text class="info-label">执行科室</text>
|
|
<text class="info-value">{{ MianInfo.implement_department || '-' }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="date-section">
|
|
<view class="date-picker-card">
|
|
<view class="date-label">选择日期</view>
|
|
<uni-datetime-picker
|
|
v-model="SearchInfo.date"
|
|
:clear-icon="false"
|
|
type="date"
|
|
@change="dateSelecteFunc"
|
|
/>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="time-section" v-if="List.length > 0">
|
|
<view class="section-header">
|
|
<text class="section-title">可预约时段</text>
|
|
<text class="section-tip">点击时段进行预约</text>
|
|
</view>
|
|
|
|
<view class="time-grid">
|
|
<view
|
|
class="time-card"
|
|
v-for="(item, index) in List"
|
|
:key="item.id"
|
|
@click="StartYuYue(item)"
|
|
>
|
|
<view class="time-main">
|
|
<view class="time-range">
|
|
<text class="time-start">{{ item.begin_time ? item.begin_time.substring(0, 5) : '' }}</text>
|
|
<text class="time-separator">-</text>
|
|
<text class="time-end">{{ item.end_time ? item.end_time.substring(0, 5) : '' }}</text>
|
|
</view>
|
|
<view class="time-progress">
|
|
<view class="progress-bar">
|
|
<view
|
|
class="progress-fill"
|
|
:style="{ width: getProgressWidth(item) + '%' }"
|
|
:class="{ 'progress-warning': getProgressWidth(item) >= 80 }"
|
|
></view>
|
|
</view>
|
|
<text class="progress-text" :class="{ 'text-warning': getProgressWidth(item) >= 80 }">
|
|
{{ item.used_count || 0 }}/{{ item.count || 0 }}
|
|
</text>
|
|
</view>
|
|
</view>
|
|
<view class="time-footer">
|
|
<view class="resource-name">
|
|
<uni-icons type="location" size="12" color="#999"></uni-icons>
|
|
<text>{{ item.department_resources_name }}</text>
|
|
</view>
|
|
<view class="book-btn">预约</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="empty-state" v-else-if="SearchInfo.date">
|
|
<view class="empty-icon">
|
|
<uni-icons type="calendar" size="80" color="#CCCCCC"></uni-icons>
|
|
</view>
|
|
<text class="empty-text">该日期暂无可约时段</text>
|
|
<text class="empty-desc">请尝试选择其他日期</text>
|
|
</view>
|
|
|
|
<view class="tips-section">
|
|
<view class="tips-title">
|
|
<uni-icons type="info" size="16" color="#FF9800"></uni-icons>
|
|
<text>温馨提示</text>
|
|
</view>
|
|
<view class="tips-list">
|
|
<text class="tips-item">1. 请按时到达,逾期可能需要重新预约</text>
|
|
<text class="tips-item">2. 如需取消或改约,请提前操作</text>
|
|
<text class="tips-item">3. 如有疑问请咨询导诊台</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed } from "vue"
|
|
import { GetEnablePlan, H5_YuYue } from "@/api"
|
|
import { onLoad, onShow } from "@dcloudio/uni-app"
|
|
|
|
let SearchInfo = ref({
|
|
date: '',
|
|
do_type: 1,
|
|
appointment_type: 2,
|
|
mainlistid: []
|
|
});
|
|
|
|
let List = ref([]);
|
|
let MianInfo = ref(null);
|
|
|
|
const getProgressWidth = (item) => {
|
|
if (!item.count || item.count == 0) return 0;
|
|
return Math.min(100, Math.round((item.used_count || 0) / item.count * 100));
|
|
};
|
|
|
|
const GetList = () => {
|
|
uni.showLoading({ title: '加载中' });
|
|
GetEnablePlan({ ...SearchInfo.value }).then(res => {
|
|
uni.hideLoading();
|
|
if (res.status) {
|
|
List.value = res.data.plan_list || [];
|
|
MianInfo.value = res.data.mainInfo;
|
|
if (MianInfo.value) {
|
|
SearchInfo.value.mainlistid = [MianInfo.value.id];
|
|
}
|
|
}
|
|
}).catch(() => {
|
|
uni.hideLoading();
|
|
});
|
|
};
|
|
|
|
const dateSelecteFunc = (e) => {
|
|
SearchInfo.value.date = e;
|
|
GetList();
|
|
};
|
|
|
|
const StartYuYue = (item) => {
|
|
if ((item.used_count || 0) >= (item.count || 0)) {
|
|
uni.showToast({
|
|
title: '该时段已约满',
|
|
icon: 'none'
|
|
});
|
|
return;
|
|
}
|
|
|
|
const timeStr = `${item.begin_time ? item.begin_time.substring(0, 5) : ''}-${item.end_time ? item.end_time.substring(0, 5) : ''}`;
|
|
|
|
uni.showModal({
|
|
cancelText: "取消",
|
|
confirmText: "确认预约",
|
|
title: '预约确认',
|
|
content: `确定预约 ${SearchInfo.value.date} ${timeStr} 时段吗?`,
|
|
confirmColor: '#2E7D32',
|
|
success: function(res) {
|
|
if (res.confirm) {
|
|
uni.showLoading({ title: '预约中' });
|
|
SearchInfo.value.planid = item.id;
|
|
H5_YuYue({ ...SearchInfo.value }).then(res => {
|
|
uni.hideLoading();
|
|
if (res.status) {
|
|
uni.showToast({
|
|
title: '预约成功',
|
|
icon: 'success'
|
|
});
|
|
setTimeout(() => {
|
|
uni.redirectTo({
|
|
url: '/pages/CheckItemMainList'
|
|
});
|
|
}, 1000);
|
|
}
|
|
}).catch(() => {
|
|
uni.hideLoading();
|
|
});
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
const goBack = () => {
|
|
uni.navigateBack();
|
|
};
|
|
|
|
const getTodayDate = () => {
|
|
const today = new Date();
|
|
const year = today.getFullYear();
|
|
const month = String(today.getMonth() + 1).padStart(2, '0');
|
|
const day = String(today.getDate()).padStart(2, '0');
|
|
return `${year}-${month}-${day}`;
|
|
};
|
|
|
|
onLoad((option) => {
|
|
if (option.data) {
|
|
const data = JSON.parse(decodeURIComponent(option.data));
|
|
SearchInfo.value = { ...SearchInfo.value, ...data };
|
|
}
|
|
SearchInfo.value.date = getTodayDate();
|
|
GetList();
|
|
});
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.page-container {
|
|
min-height: 100vh;
|
|
background: #F5F7FA;
|
|
padding-bottom: 40rpx;
|
|
}
|
|
|
|
.page-header {
|
|
position: relative;
|
|
|
|
.header-bg {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 180rpx;
|
|
background: linear-gradient(135deg, #2E7D32 0%, #4CAF50 100%);
|
|
border-radius: 0 0 48rpx 48rpx;
|
|
}
|
|
|
|
.header-content {
|
|
position: relative;
|
|
z-index: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 60rpx 32rpx 40rpx;
|
|
|
|
.back-btn {
|
|
width: 64rpx;
|
|
height: 64rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: rgba(255, 255, 255, 0.2);
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.header-title {
|
|
font-size: 36rpx;
|
|
font-weight: 600;
|
|
color: #FFFFFF;
|
|
}
|
|
|
|
.header-placeholder {
|
|
width: 64rpx;
|
|
}
|
|
}
|
|
}
|
|
|
|
.info-card {
|
|
margin: -40rpx 32rpx 24rpx;
|
|
background: #FFFFFF;
|
|
border-radius: 24rpx;
|
|
padding: 28rpx;
|
|
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
|
|
position: relative;
|
|
z-index: 2;
|
|
|
|
.info-header {
|
|
display: flex;
|
|
align-items: center;
|
|
padding-bottom: 20rpx;
|
|
border-bottom: 1rpx solid #F0F0F0;
|
|
|
|
.info-title {
|
|
font-size: 32rpx;
|
|
font-weight: 600;
|
|
color: #333333;
|
|
margin-left: 12rpx;
|
|
}
|
|
}
|
|
|
|
.info-body {
|
|
padding-top: 20rpx;
|
|
|
|
.info-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: 8rpx 0;
|
|
|
|
.info-label {
|
|
font-size: 28rpx;
|
|
color: #999999;
|
|
}
|
|
|
|
.info-value {
|
|
font-size: 28rpx;
|
|
color: #333333;
|
|
font-weight: 500;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.date-section {
|
|
padding: 0 32rpx;
|
|
margin-bottom: 24rpx;
|
|
|
|
.date-picker-card {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
background: #FFFFFF;
|
|
border-radius: 20rpx;
|
|
padding: 24rpx 28rpx;
|
|
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
|
|
|
|
.date-label {
|
|
font-size: 30rpx;
|
|
color: #333333;
|
|
font-weight: 500;
|
|
}
|
|
}
|
|
}
|
|
|
|
.time-section {
|
|
padding: 0 32rpx;
|
|
box-sizing: border-box;
|
|
|
|
.section-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 20rpx;
|
|
|
|
.section-title {
|
|
font-size: 32rpx;
|
|
font-weight: 600;
|
|
color: #333333;
|
|
}
|
|
|
|
.section-tip {
|
|
font-size: 24rpx;
|
|
color: #999999;
|
|
}
|
|
}
|
|
|
|
.time-grid {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 20rpx;
|
|
|
|
.time-card {
|
|
width: 100%;
|
|
background: #FFFFFF;
|
|
border-radius: 20rpx;
|
|
padding: 28rpx 32rpx;
|
|
box-sizing: border-box;
|
|
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
|
|
transition: all 0.3s ease;
|
|
|
|
&:active {
|
|
transform: scale(0.99);
|
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.time-main {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
|
|
.time-range {
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
.time-start, .time-end {
|
|
font-size: 44rpx;
|
|
font-weight: 600;
|
|
color: #2E7D32;
|
|
}
|
|
|
|
.time-separator {
|
|
margin: 0 12rpx;
|
|
color: #CCCCCC;
|
|
font-size: 36rpx;
|
|
}
|
|
}
|
|
|
|
.time-progress {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: flex-end;
|
|
|
|
.progress-bar {
|
|
width: 160rpx;
|
|
height: 12rpx;
|
|
background: #F0F0F0;
|
|
border-radius: 6rpx;
|
|
overflow: hidden;
|
|
margin-bottom: 8rpx;
|
|
|
|
.progress-fill {
|
|
height: 100%;
|
|
background: linear-gradient(90deg, #4CAF50 0%, #81C784 100%);
|
|
border-radius: 6rpx;
|
|
transition: width 0.3s ease;
|
|
|
|
&.progress-warning {
|
|
background: linear-gradient(90deg, #FF9800 0%, #FFB74D 100%);
|
|
}
|
|
}
|
|
}
|
|
|
|
.progress-text {
|
|
font-size: 26rpx;
|
|
color: #4CAF50;
|
|
font-weight: 500;
|
|
|
|
&.text-warning {
|
|
color: #FF9800;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.time-footer {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-top: 20rpx;
|
|
padding-top: 20rpx;
|
|
border-top: 1rpx solid #F5F5F5;
|
|
|
|
.resource-name {
|
|
display: flex;
|
|
align-items: center;
|
|
font-size: 26rpx;
|
|
color: #666666;
|
|
|
|
text {
|
|
margin-left: 8rpx;
|
|
}
|
|
}
|
|
|
|
.book-btn {
|
|
padding: 14rpx 48rpx;
|
|
background: linear-gradient(135deg, #2E7D32 0%, #4CAF50 100%);
|
|
border-radius: 32rpx;
|
|
font-size: 28rpx;
|
|
color: #FFFFFF;
|
|
font-weight: 500;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.empty-state {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 100rpx 40rpx;
|
|
background: #FFFFFF;
|
|
margin: 0 32rpx;
|
|
border-radius: 24rpx;
|
|
|
|
.empty-icon {
|
|
margin-bottom: 24rpx;
|
|
}
|
|
|
|
.empty-text {
|
|
font-size: 32rpx;
|
|
color: #CCCCCC;
|
|
margin-bottom: 12rpx;
|
|
}
|
|
|
|
.empty-desc {
|
|
font-size: 26rpx;
|
|
color: #DDDDDD;
|
|
}
|
|
}
|
|
|
|
.tips-section {
|
|
margin: 32rpx 32rpx 0;
|
|
background: rgba(255, 152, 0, 0.08);
|
|
border-radius: 20rpx;
|
|
padding: 24rpx 28rpx;
|
|
border-left: 6rpx solid #FF9800;
|
|
|
|
.tips-title {
|
|
display: flex;
|
|
align-items: center;
|
|
font-size: 28rpx;
|
|
font-weight: 600;
|
|
color: #FF9800;
|
|
margin-bottom: 16rpx;
|
|
|
|
text {
|
|
margin-left: 8rpx;
|
|
}
|
|
}
|
|
|
|
.tips-list {
|
|
.tips-item {
|
|
display: block;
|
|
font-size: 24rpx;
|
|
color: #666666;
|
|
line-height: 2;
|
|
}
|
|
}
|
|
}
|
|
</style> |