This commit is contained in:
zhouhefeng
2026-04-24 16:39:05 +08:00
parent c2f93eb4b3
commit 6e246854fb
21 changed files with 3931 additions and 1040 deletions
File diff suppressed because it is too large Load Diff
@@ -4,9 +4,304 @@ layout("/layouts/platform_h5.html"){
<style scoped>
.page-container {
padding-bottom: 84px;
background: #f7f8fa;
padding: 12px 12px 96px;
background: #f5f7fb;
min-height: calc(100vh - 46px);
box-sizing: border-box;
}
.panel-card {
margin-bottom: 12px;
overflow: hidden;
border-radius: 22px;
background: #ffffff;
box-shadow:
0 2px 6px rgba(15, 23, 42, 0.04),
0 12px 28px rgba(15, 23, 42, 0.08),
0 0 0 1px rgba(226, 232, 240, 0.95);
}
.notice-card__header {
width: 100%;
padding: 16px;
border: none;
background: #ffffff;
display: flex;
align-items: center;
justify-content: space-between;
color: #0f172a;
font-size: 16px;
font-weight: 700;
line-height: 1.4;
box-sizing: border-box;
}
.notice-card__icon {
color: #64748b;
font-size: 16px;
transition: transform 0.2s ease;
}
.notice-card__icon--expanded {
transform: rotate(180deg);
}
.notice-card__body {
padding: 0 16px 14px;
border-top: 1px solid #eef2f7;
}
.notice-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.notice-item {
padding: 10px 12px;
border-radius: 14px;
background: #f8fafc;
}
.notice-item__label {
color: #334155;
font-size: 13px;
font-weight: 600;
line-height: 1.5;
}
.notice-item__value {
margin-top: 4px;
color: #64748b;
font-size: 12px;
line-height: 1.7;
}
.disabled-time-list {
display: flex;
flex-direction: column;
gap: 6px;
}
.disabled-time-item {
padding: 8px 10px;
border-radius: 10px;
background: #ffffff;
color: #475569;
line-height: 1.7;
}
.form-container {
margin: 0;
}
.section-tip {
padding: 0 16px 14px;
color: #94a3b8;
font-size: 12px;
line-height: 1.6;
}
.selection-summary {
margin: 0 16px 14px;
padding: 10px 12px;
border-radius: 12px;
background: rgba(37, 99, 235, 0.08);
color: #2563eb;
font-size: 12px;
line-height: 1.7;
}
.batch-panel {
padding: 0 16px 14px;
}
.batch-summary {
margin-top: 10px;
padding: 10px 12px;
border-radius: 12px;
background: rgba(37, 99, 235, 0.08);
color: #2563eb;
font-size: 12px;
line-height: 1.7;
}
.availability-popup {
height: 82vh;
display: flex;
flex-direction: column;
background: #f8fafc;
}
.availability-popup__header {
display: flex;
align-items: flex-start;
justify-content: space-between;
padding: 16px;
background: #ffffff;
border-bottom: 1px solid #eef2f7;
}
.availability-popup__title {
color: #0f172a;
font-size: 17px;
font-weight: 700;
line-height: 1.4;
}
.availability-popup__subtitle {
margin-top: 4px;
color: #64748b;
font-size: 12px;
line-height: 1.6;
}
.availability-popup__close {
color: #94a3b8;
font-size: 18px;
line-height: 1;
}
.availability-popup__tabs {
display: flex;
gap: 8px;
padding: 12px 16px 0;
overflow-x: auto;
background: #f8fafc;
}
.availability-tab {
min-width: 72px;
height: 34px;
padding: 0 14px;
border: 1px solid #cbd5e1;
border-radius: 999px;
background: #ffffff;
color: #475569;
font-size: 13px;
font-weight: 500;
box-sizing: border-box;
}
.availability-tab--active {
border-color: #2563eb;
background: #2563eb;
color: #ffffff;
box-shadow: 0 8px 16px rgba(37, 99, 235, 0.22);
}
.availability-popup__legend {
display: flex;
flex-wrap: wrap;
gap: 12px;
padding: 12px 16px 0;
color: #64748b;
font-size: 12px;
line-height: 1.5;
}
.availability-legend__item {
display: inline-flex;
align-items: center;
gap: 6px;
}
.availability-legend__dot {
width: 10px;
height: 10px;
border-radius: 999px;
display: inline-block;
}
.availability-legend__dot--available {
background: #22c55e;
}
.availability-legend__dot--reserved {
background: #9ca3af;
}
.availability-legend__dot--selected {
background: #2563eb;
}
.availability-legend__dot--closed {
background: #e5e7eb;
}
.availability-popup__body {
flex: 1;
overflow-y: auto;
padding: 16px;
box-sizing: border-box;
}
.slot-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
}
.slot-block {
min-height: 48px;
padding: 0 12px;
border: 1px solid #dbe4ee;
border-radius: 14px;
background: #ffffff;
color: #475569;
display: inline-flex;
align-items: center;
justify-content: center;
text-align: center;
font-size: 13px;
font-weight: 500;
line-height: 1.4;
box-sizing: border-box;
}
.slot-block--available {
border-color: #86efac;
background: rgba(34, 197, 94, 0.1);
color: #15803d;
}
.slot-block--reserved {
background: #e5e7eb;
color: #6b7280;
}
.slot-block--closed {
background: #f8fafc;
color: #94a3b8;
}
.slot-block--selected {
border-color: #2563eb;
background: #2563eb;
color: #ffffff;
box-shadow: 0 10px 20px rgba(37, 99, 235, 0.24);
}
.availability-popup__footer {
padding: 12px 16px calc(env(safe-area-inset-bottom) + 12px);
background: #ffffff;
border-top: 1px solid #eef2f7;
}
.availability-popup__summary {
margin-bottom: 12px;
color: #475569;
font-size: 12px;
line-height: 1.7;
}
.availability-popup__actions {
display: flex;
gap: 10px;
}
.availability-popup__actions .van-button {
flex: 1;
}
.footer-actions {
@@ -17,17 +312,39 @@ layout("/layouts/platform_h5.html"){
display: flex;
gap: 12px;
padding: 10px 12px calc(env(safe-area-inset-bottom) + 10px);
background: #ffffff;
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.06);
background: rgba(255, 255, 255, 0.96);
backdrop-filter: blur(10px);
box-shadow: 0 -8px 24px rgba(15, 23, 42, 0.08);
}
.footer-actions .van-button {
flex: 1;
height: 44px;
}
.disabled-time-item {
line-height: 20px;
margin-bottom: 4px;
/deep/ .panel-card .van-cell-group {
background: transparent;
}
/deep/ .panel-card .van-cell-group__title {
padding: 16px 16px 8px;
margin: 0;
color: #0f172a;
font-size: 16px;
font-weight: 700;
line-height: 1.4;
background: #ffffff;
}
/deep/ .panel-card .van-cell {
padding-top: 12px;
padding-bottom: 12px;
}
/deep/ .panel-card .van-field__label,
/deep/ .panel-card .van-cell__title {
color: #334155;
font-weight: 600;
}
/deep/ .direction-column-cell .van-cell__value {
@@ -40,46 +357,43 @@ layout("/layouts/platform_h5.html"){
<van-nav-bar title="场馆申请" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
<div class="page-container" v-if="siteLoaded">
<van-cell-group title="场馆信息">
<van-cell title="场馆名称" :value="row.name || '-' "></van-cell>
<van-cell title="场地地址" class="direction-column-cell">
<template #default>
{{ row.address || '-' }}
</template>
</van-cell>
<van-cell title="联系人" :value="row.contactName || '-' "></van-cell>
<van-cell title="联系电话" :value="row.contactPhone || '-' "></van-cell>
<van-cell title="场地类型" :value="row.typeName || '-' "></van-cell>
</van-cell-group>
<van-cell-group title="预约须知">
<van-cell title="可预约日期" value="仅限工作日"></van-cell>
<van-cell title="节假日限制"
:value="timeLimitConfig.filterHolidays ? '节假日不可预约' : '不排除节假日'"></van-cell>
<van-cell title="禁用时段" class="direction-column-cell">
<template #default>
<div v-if="timeLimitConfig.notApplyTimeList.length">
<div
class="disabled-time-item"
v-for="(item, index) in timeLimitConfig.notApplyTimeList"
:key="item.date + item.startTime + item.endTime + index">
{{ item.date }} {{ item.startTime }} - {{ item.endTime }}
<div class="panel-card">
<button type="button" class="notice-card__header" @click="noticeCollapsed = !noticeCollapsed">
<span>预约须知</span>
<van-icon :class="['notice-card__icon', noticeCollapsed ? '' : 'notice-card__icon--expanded']" name="arrow-down"></van-icon>
</button>
<div v-if="!noticeCollapsed" class="notice-card__body">
<div class="notice-list">
<div class="notice-item">
<div class="notice-item__label">可预约日期</div>
<div class="notice-item__value">仅限工作日</div>
</div>
<div class="notice-item">
<div class="notice-item__label">节假日限制</div>
<div class="notice-item__value">{{ timeLimitConfig.filterHolidays ? '节假日不可预约' : '不排除节假日' }}</div>
</div>
<div class="notice-item">
<div class="notice-item__label">禁用时段</div>
<div class="notice-item__value">
<div v-if="timeLimitConfig.notApplyTimeList.length" class="disabled-time-list">
<div
class="disabled-time-item"
v-for="(item, index) in timeLimitConfig.notApplyTimeList"
:key="item.date + item.startTime + item.endTime + index">
{{ item.date }} {{ item.startTime }} - {{ item.endTime }}
</div>
</div>
<div v-else>暂无禁用时段</div>
</div>
</div>
<div v-else>暂无禁用时段</div>
</template>
</van-cell>
</van-cell-group>
</div>
</div>
</div>
<van-form ref="formRef" class="form-container" :show-error-message="false">
<van-cell-group title="申请信息">
<van-field v-model="formData.applyUserName" label="预约人" name="applyUserName" readonly
:rules="[{ required: true, message: '请确认预约人' }]"></van-field>
<van-field v-model="formData.applyLoginName" label="工号" name="applyLoginName" readonly
:rules="[{ required: true, message: '请确认工号' }]"></van-field>
<van-field v-model="formData.applyUnitName" label="所属单位" name="applyUnitName" readonly
:rules="[{ required: true, message: '请确认所属单位' }]"></van-field>
<van-field
<div class="panel-card">
<van-cell-group title="申请信息">
<van-field
:value="reserveTypeText"
label="预约类型"
name="reserveType"
@@ -88,18 +402,24 @@ layout("/layouts/platform_h5.html"){
is-link
required
placeholder="请选择预约类型"
@click="showReserveTypePicker = true"
@click="openReserveTypePicker"
:rules="[{ required: true, message: '请选择预约类型' }]">
</van-field>
<van-field
</van-field>
<van-field v-model="formData.applyUserName" label="预约人" name="applyUserName" readonly
:rules="[{ required: true, message: '请确认预约人' }]"></van-field>
<van-field v-model="formData.applyLoginName" label="工号" name="applyLoginName" readonly
:rules="[{ required: true, message: '请确认工号' }]"></van-field>
<van-field v-model="formData.applyUnitName" label="所属单位" name="applyUnitName" readonly
:rules="[{ required: true, message: '请确认所属单位' }]"></van-field>
<van-field
v-if="formData.reserveType === 'union'"
v-model="formData.applyUnionName"
label="分工会"
name="applyUnionName"
readonly
placeholder="自动读取当前登录人的分工会">
</van-field>
<van-field
</van-field>
<van-field
v-if="formData.reserveType === 'club'"
v-model="formData.clubName"
label="协会"
@@ -111,21 +431,58 @@ layout("/layouts/platform_h5.html"){
placeholder="请选择您管理的协会"
@click="openClubPicker"
:rules="[{ required: true, message: '请选择您管理的协会' }]">
</van-field>
<van-field v-model="formData.applyMobile" label="联系电话" name="applyMobile" type="tel" maxlength="11"
required placeholder="请输入联系电话"
:rules="[{ required: true, message: '请输入联系电话' }]"></van-field>
<van-field v-model="formData.reserveStartTime" label="开始时间" name="reserveStartTime" readonly
clickable is-link required placeholder="请选择预约开始时间"
@click="openTimePicker('reserveStartTime')"
:rules="[{ required: true, message: '请选择预约开始时间' }]"></van-field>
<van-field v-model="formData.reserveEndTime" label="结束时间" name="reserveEndTime" readonly clickable
is-link required placeholder="请选择预约结束时间" @click="openTimePicker('reserveEndTime')"
:rules="[{ required: true, message: '请选择预约结束时间' }]"></van-field>
<van-field v-model="formData.applyCause" label="预约事由" name="applyCause" required rows="4" autosize
type="textarea" maxlength="1000" show-word-limit placeholder="请输入预约事由"
:rules="[{ required: true, message: '请输入预约事由' }]"></van-field>
</van-cell-group>
</van-field>
<van-field v-model="formData.applyMobile" label="联系电话" name="applyMobile" type="tel" maxlength="11"
required placeholder="请输入联系电话"
:rules="[{ required: true, message: '请输入联系电话' }]"></van-field>
<van-field
:value="scheduleDate"
label="预约日期"
name="scheduleDate"
readonly
clickable
is-link
required
placeholder="请选择预约日期"
@click="openScheduleDatePicker">
</van-field>
<van-field
:value="selectionSummary || ''"
label="预约时段"
name="timeSelection"
readonly
clickable
is-link
required
:placeholder="scheduleDate ? '请选择预约时段' : '请先选择预约日期'"
@click="openAvailabilityPopup">
</van-field>
<div v-if="selectionSummary" class="selection-summary">当前已选:{{ selectionSummary }}</div>
<van-cell title="批量预约">
<template #default>
<van-switch v-model="yearlyReserve" size="22px"></van-switch>
</template>
</van-cell>
<div v-if="yearlyReserve" class="batch-panel">
<div class="section-tip">将自动预约截止日期内每周同一时段,默认到本月底。</div>
<van-field
:value="formData.yearlyReserveEndDate"
label="截至日期"
name="yearlyReserveEndDate"
readonly
clickable
is-link
required
placeholder="请选择批量预约截止日期"
@click="openYearlyEndDatePicker">
</van-field>
<div v-if="batchReserveSummary" class="batch-summary">{{ batchReserveSummary }}</div>
</div>
<van-field v-model="formData.applyCause" label="预约事由" name="applyCause" required rows="4" autosize
type="textarea" maxlength="1000" show-word-limit placeholder="请输入预约事由"
:rules="[{ required: true, message: '请输入预约事由' }]"></van-field>
</van-cell-group>
</div>
</van-form>
</div>
@@ -144,17 +501,76 @@ layout("/layouts/platform_h5.html"){
@cancel="showClubPicker = false"></van-picker>
</van-popup>
<van-popup v-model="showTimePicker" position="bottom" round>
<van-picker
ref="timePickerRef"
show-toolbar
value-key="text"
:title="timePickerTitle"
:columns="timePickerColumns"
@change="onTimePickerChange"
@confirm="onTimeConfirm"
@cancel="timePickerSyncing = false; showTimePicker = false">
</van-picker>
<van-popup v-model="showScheduleDatePicker" position="bottom" round>
<van-datetime-picker
v-model="schedulePickerDate"
type="date"
title="选择预约日期"
:min-date="scheduleMinDate"
:max-date="scheduleMaxDate"
@confirm="onScheduleDateConfirm"
@cancel="showScheduleDatePicker = false">
</van-datetime-picker>
</van-popup>
<van-popup v-model="showAvailabilityPopup" position="bottom" round class="availability-popup">
<div class="availability-popup__header">
<div>
<div class="availability-popup__title">选择预约时段</div>
<div class="availability-popup__subtitle">{{ scheduleDate || '请选择预约日期' }} {{ reserveModeText }}</div>
</div>
<van-icon class="availability-popup__close" name="cross" @click="showAvailabilityPopup = false"></van-icon>
</div>
<div v-if="timeGroupTabs.length" class="availability-popup__tabs">
<button
v-for="tab in timeGroupTabs"
:key="tab.key"
type="button"
:class="['availability-tab', activeTimeGroupKey === tab.key ? 'availability-tab--active' : '']"
@click="activeTimeGroupKey = tab.key">
{{ tab.label }}
</button>
</div>
<div class="availability-popup__legend">
<span class="availability-legend__item"><i class="availability-legend__dot availability-legend__dot--available"></i>可预约</span>
<span class="availability-legend__item"><i class="availability-legend__dot availability-legend__dot--reserved"></i>已预约</span>
<span class="availability-legend__item"><i class="availability-legend__dot availability-legend__dot--selected"></i>已选择</span>
<span class="availability-legend__item"><i class="availability-legend__dot availability-legend__dot--closed"></i>不可预约</span>
</div>
<div class="availability-popup__body">
<van-loading v-if="availabilityLoading" vertical>时段加载中</van-loading>
<van-empty v-else-if="!availabilityBlocks.length" description="当前日期暂无可选时段"></van-empty>
<van-empty v-else-if="!displayedAvailabilityBlocks.length" description="当前标签暂无可选时段"></van-empty>
<div v-else class="slot-grid">
<button
v-for="block in displayedAvailabilityBlocks"
:key="block.key"
type="button"
:class="getBlockClass(block)"
@click="onAvailabilityBlockClick(block)">
<span>{{ block.label }}</span>
</button>
</div>
</div>
<div class="availability-popup__footer">
<div class="availability-popup__summary">{{ selectionSummary || '请选择一个或多个连续时段,不可跨越间隔选择。' }}</div>
<div class="availability-popup__actions">
<van-button plain round type="default" @click="clearSelection(true)">清空</van-button>
<van-button round type="primary" color="#246fb4" @click="confirmAvailabilitySelection">确定</van-button>
</div>
</div>
</van-popup>
<van-popup v-model="showYearlyEndDatePicker" position="bottom" round>
<van-datetime-picker
v-model="yearlyReservePickerDate"
type="date"
title="选择批量预约截止日期"
:min-date="yearlyReserveMinDate"
:max-date="yearlyReserveMaxDate"
@confirm="onYearlyReserveEndDateConfirm"
@cancel="showYearlyEndDatePicker = false">
</van-datetime-picker>
</van-popup>
</div>
@@ -3,13 +3,311 @@ layout("/layouts/platform_h5.html"){
#-->
<style scoped>
.site-page {
background: #f5f7fb;
min-height: 100vh;
}
.toolbar-wrap {
padding: 10px 10px 8px;
background: #f5f7fb;
box-shadow: 0 8px 18px rgba(15, 23, 42, 0.04);
}
.search-toolbar {
display: flex;
align-items: center;
gap: 8px;
}
.search-panel {
flex: 1;
min-width: 0;
border-radius: 16px;
overflow: hidden;
background: #ffffff;
box-shadow: 0 4px 14px rgba(15, 23, 42, 0.06);
}
.search-panel /deep/ .van-search {
padding: 0;
background: transparent;
}
.search-panel /deep/ .van-search__content {
height: 42px;
background: #ffffff;
border-radius: 16px;
}
.toolbar-btn,
.toolbar-icon-btn {
height: 42px;
border: none;
border-radius: 14px;
background: #ffffff;
box-shadow: 0 4px 14px rgba(15, 23, 42, 0.08);
display: inline-flex;
align-items: center;
justify-content: center;
color: #2563eb;
box-sizing: border-box;
}
.toolbar-btn {
min-width: 62px;
padding: 0 14px;
font-size: 14px;
font-weight: 600;
}
.toolbar-icon-btn {
width: 42px;
font-size: 18px;
}
.selected-type-bar {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 8px;
padding: 8px 12px;
border-radius: 14px;
background: rgba(37, 99, 235, 0.08);
color: #2563eb;
font-size: 13px;
line-height: 1.4;
}
.selected-type-text {
min-width: 0;
flex: 1;
padding-right: 12px;
font-weight: 500;
}
.selected-type-clear {
border: none;
padding: 0;
background: transparent;
color: #2563eb;
font-size: 13px;
font-weight: 600;
}
.type-popup {
width: calc(100vw - 48px);
max-width: 320px;
padding: 16px 16px 14px;
box-sizing: border-box;
}
.type-popup__header {
color: #111827;
font-size: 16px;
font-weight: 700;
line-height: 1.4;
}
.type-popup__list {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 14px;
}
.type-popup__item {
min-width: calc(50% - 5px);
min-height: 38px;
padding: 0 12px;
border: 1px solid #dbe4f0;
border-radius: 12px;
background: #ffffff;
color: #475569;
display: inline-flex;
align-items: center;
justify-content: space-between;
gap: 8px;
font-size: 13px;
line-height: 1.2;
box-sizing: border-box;
}
.type-popup__item--active {
border-color: #2563eb;
background: rgba(37, 99, 235, 0.08);
color: #2563eb;
font-weight: 600;
}
.site-card-header {
display: flex;
gap: 12px;
align-items: flex-start;
margin-bottom: 10px;
}
.site-thumb {
width: 92px;
height: 92px;
flex-shrink: 0;
overflow: hidden;
border-radius: 14px;
background: linear-gradient(135deg, #e5eefb 0%, #f5f9ff 100%);
box-shadow: inset 0 0 0 1px rgba(37, 99, 235, 0.06);
}
.site-thumb img,
.site-thumb .van-image {
width: 100%;
height: 100%;
display: block;
}
.site-thumb-empty {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
color: #94a3b8;
font-size: 12px;
text-align: center;
line-height: 1.4;
padding: 8px;
box-sizing: border-box;
}
.site-head-main {
min-width: 0;
flex: 1;
padding-top: 2px;
}
.site-name {
color: #111827;
font-size: 18px;
font-weight: 700;
line-height: 1.35;
word-break: break-all;
}
.site-address {
display: flex;
align-items: center;
gap: 4px;
margin-top: 8px;
color: #6b7280;
font-size: 13px;
line-height: 1.4;
}
.site-address i {
color: #9ca3af;
font-size: 12px;
}
.site-tags {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 10px;
}
.site-tag {
display: inline-flex;
align-items: center;
justify-content: center;
min-height: 24px;
padding: 0 8px;
border-radius: 8px;
border: 1px solid #93c5fd;
color: #2563eb;
font-size: 12px;
line-height: 1;
background: #ffffff;
box-sizing: border-box;
}
.site-tag--solid {
border-color: #2563eb;
background: #2563eb;
color: #ffffff;
}
.site-tag--muted {
border-color: #cbd5e1;
color: #64748b;
}
.site-timeline {
margin-top: 4px;
}
.timeline-bar {
display: grid;
grid-template-columns: repeat(48, minmax(0, 1fr));
gap: 1px;
align-items: center;
padding: 0 2px;
}
.timeline-bar__segment {
height: 4px;
border-radius: 999px;
background: #e5e7eb;
}
.timeline-bar__segment--available {
background: #22c55e;
}
.timeline-bar__segment--reserved {
background: #9ca3af;
}
.timeline-scale {
display: flex;
justify-content: space-between;
margin-top: 8px;
padding: 0 2px;
color: #64748b;
font-size: 11px;
line-height: 1;
}
/deep/ .table-list-container {
margin-top: 8px;
padding: 0 8px 12px;
}
/deep/ .table-list-container .table-list-item {
margin-bottom: 12px;
padding: 14px;
border: none;
overflow: hidden;
border-radius: 22px;
background: #ffffff;
box-shadow:
0 2px 6px rgba(15, 23, 42, 0.05),
0 10px 24px rgba(15, 23, 42, 0.08),
0 0 0 1px rgba(226, 232, 240, 0.9);
}
/deep/ .table-list-container .table-list-item .item-actions {
margin-top: 12px;
padding-top: 10px;
border-top: 1px solid #eef2f7;
}
</style>
<div id="app">
<div id="app" class="site-page">
<van-nav-bar title="场馆预约" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
<van-sticky offset-top="46px">
<div class="toolbar-wrap">
<div class="search-toolbar">
<div class="search-panel">
<van-search
v-model="pageForm.searchKeyword"
:show-action="false"
@@ -17,18 +315,54 @@ layout("/layouts/platform_h5.html"){
input-align="left"
placeholder="请输入名称或地址搜索"
@search="doSearch"
></van-search>
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
<van-dropdown-item v-model="pageForm.type" :options="typeOptions" :multiple="false" @change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
></van-search>
</div>
<button type="button" class="toolbar-btn" @click="doSearch">搜索</button>
<button type="button" class="toolbar-icon-btn" @click="typePopupVisible = true">
<van-icon name="apps-o"></van-icon>
</button>
</div>
<div v-if="selectedTypeText" class="selected-type-bar">
<div class="selected-type-text">已选场地类型:{{ selectedTypeText }}</div>
<button type="button" class="selected-type-clear" @click="selectType(null)">清除</button>
</div>
</div>
</van-sticky>
<table-list api="/platform/siteCug/apply/pageData" :page_form.sync="pageForm" ref="tableListRef" title="name" @ready="onReady">
<table-list api="/platform/siteCug/apply/pageData" :page_form.sync="pageForm" ref="tableListRef" @ready="onReady">
<template #header="{ row }">
<div class="site-card-header">
<div class="site-thumb" @click="previewSitePhoto(row)">
<van-image v-if="row.sitePhoto" :src="row.sitePhoto" fit="cover"></van-image>
<div v-else class="site-thumb-empty">暂无场地照片</div>
</div>
<div class="site-head-main">
<div class="site-name">{{ row.name || '-' }}</div>
<div class="site-address">
<i class="fa fa-map-marker"></i>
<span>{{ row.address || '-' }}</span>
</div>
<div class="site-tags">
<span class="site-tag site-tag--solid">{{ row.typeName || '活动场地' }}</span>
<span class="site-tag">容{{ row.maxNum || '-' }}</span>
<span :class="['site-tag', row.state ? '' : 'site-tag--muted']">{{ row.state ? '已开启' : '未开启' }}</span>
</div>
</div>
</div>
</template>
<template v-slot="{ row }">
<table-column label="场地地址">{{ row.address }}</table-column>
<table-column label="联系人">{{ row.contactName }}</table-column>
<table-column label="联系方式">{{ row.contactPhone }}</table-column>
<table-column label="场地类型">{{ row.typeName }}</table-column>
<div class="site-timeline">
<div class="timeline-bar">
<span
v-for="(segment, index) in row.timelineSegments || []"
:key="row.id + '-segment-' + index"
:class="['timeline-bar__segment', 'timeline-bar__segment--' + (segment.status || 'closed')]">
</span>
</div>
<div class="timeline-scale">
<span v-for="mark in timeMarks" :key="row.id + '-mark-' + mark">{{ mark }}</span>
</div>
</div>
</template>
<template #actions="{ row }">
<div class="action-btn" @click="onView(row)">
@@ -42,6 +376,21 @@ layout("/layouts/platform_h5.html"){
</template>
</table-list>
<van-popup v-model="typePopupVisible" round class="type-popup">
<div class="type-popup__header">选择场地类型</div>
<div class="type-popup__list">
<button
v-for="item in typeFilterOptions"
:key="String(item.value)"
type="button"
:class="['type-popup__item', pageForm.type === item.value ? 'type-popup__item--active' : '']"
@click="selectType(item.value)">
<span>{{ item.text }}</span>
<van-icon v-if="pageForm.type === item.value" name="success"></van-icon>
</button>
</div>
</van-popup>
<info ref="infoRef"></info>
</div>
@@ -62,11 +411,25 @@ layout("/layouts/platform_h5.html"){
searchKeyword: '',
type: null,
},
typeOptions: [],
typeFilterOptions: [],
typePopupVisible: false,
timeMarks: ['0', '2', '4', '6', '8', '10', '12', '14', '16', '18', '20', '22'],
}
},
computed: {
selectedTypeText() {
const current = this.typeFilterOptions.find((item) => item.value === this.pageForm.type)
return current && current.value !== null ? current.text : ''
},
},
methods: {
historyBack,
previewSitePhoto(row) {
if (!row || !row.sitePhoto) {
return
}
this.vant.ImagePreview([row.sitePhoto])
},
onView(row) {
this.$refs.infoRef.onOpen(row)
},
@@ -75,14 +438,14 @@ layout("/layouts/platform_h5.html"){
},
async onReady() {
const typeList = await this.querySiteType()
this.typeOptions = [
this.typeFilterOptions = [
{
text: '全部类型',
value: null,
}
].concat(typeList.map((item) => ({ text: item.name, value: item.id })))
if (this.typeOptions.length > 0) {
this.pageForm.type = this.typeOptions[0].value
if (this.typeFilterOptions.length > 0) {
this.pageForm.type = this.typeFilterOptions[0].value
this.doSearch()
}
},
@@ -90,6 +453,11 @@ layout("/layouts/platform_h5.html"){
const res = await this.$axios.post('/platform/siteCug/function/type/queryFunctionType')
return Array.isArray(res.data) ? res.data : []
},
selectType(value) {
this.pageForm.type = value
this.typePopupVisible = false
this.doSearch()
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
@@ -18,14 +18,14 @@ const siteCugApplyInfoH5 = {
</van-cell-group>
<template v-for="task in doneTasks">
<van-cell-group :title="task.displayName" v-if="task.ext.isFirstTaskNode" :key="task.id + '-first'">
<van-cell title="申请用户">{{ task.ext.initiatorName }}({{task.ext.initiatorAccount}})</van-cell>
<van-cell title="申请人">{{ task.ext.initiatorName }}({{task.ext.initiatorAccount}})</van-cell>
<van-cell title="申请时间">{{ task.finishTime }}</van-cell>
<van-cell title="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE" :value="task.ext.submitType"></dict-tag>
</van-cell>
</van-cell-group>
<van-cell-group :title="task.displayName" v-else :key="task.id + '-done'">
<van-cell title="办理用户">{{ task.taskFormData.userName }}({{task.taskFormData.loginName}})</van-cell>
<van-cell title="办理人">{{ task.taskFormData.userName }}({{task.taskFormData.loginName}})</van-cell>
<van-cell title="办理时间">{{ task.finishTime }}</van-cell>
<van-cell title="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE" :value="task.ext.submitType"></dict-tag>
@@ -77,29 +77,66 @@ const siteInfo = {
},
},
style: /*language=CSS*/ `
/deep/ .van-action-sheet {
border-top-left-radius: 24px;
border-top-right-radius: 24px;
overflow: hidden;
background: #f8fafc;
}
/deep/ .van-action-sheet__header {
font-size: 17px;
font-weight: 700;
color: #0f172a;
background: #ffffff;
}
/deep/ .detail-container {
padding: 10px 12px 18px;
background: #f8fafc;
}
/deep/ .detail-container .van-cell-group {
margin-bottom: 12px;
overflow: hidden;
border-radius: 18px;
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.06);
}
/deep/ .detail-container .van-cell-group__title {
padding: 12px 16px 8px;
color: #334155;
font-size: 14px;
font-weight: 700;
}
/deep/ .detail-container .van-cell {
min-height: 52px;
}
/deep/ .direction-column-cell .van-cell__value {
white-space: normal;
text-align: left;
}
/deep/ .table-class {
width: 100%;
border-radius: 5px;
border-radius: 10px;
overflow: hidden;
line-height: 1.5rem;
line-height: 1.8rem;
font-size: 13px;
table-layout: fixed;
border-collapse: collapse;
background: #ffffff;
}
/deep/ .table-class th {
background-color: #f2f2f2;
border: 1px solid #dddddd;
padding: 10px 8px;
background-color: #f1f5f9;
border: 1px solid #dbe4ee;
color: #334155;
font-weight: 600;
}
/deep/ .table-class tr {
text-align: center;
border-bottom: 1px solid #dddddd;
border-bottom: 1px solid #dbe4ee;
}
/deep/ .table-class td {
border: 1px solid #dddddd;
padding: 10px 8px;
border: 1px solid #dbe4ee;
color: #475569;
}
`
}
@@ -18,10 +18,8 @@ layout("/layouts/platform_h5.html"){
<table-list api="/platform/siteCug/mine/pageData" :page_form.sync="pageForm" ref="tableListRef" title="siteName" @ready="onReady">
<template v-slot="{index,row}">
<table-column label="场地名称">{{row.siteName}}</table-column>
<table-column label="预约人">{{row.applyUserName || '-'}}</table-column>
<table-column label="预约类型">{{row.reserveType === 'club' ? '协会预约' : '分工会预约'}}</table-column>
<table-column label="预约主体">{{row.reserveType === 'club' ? (row.clubName || '-') : (row.applyUnionName || '-')}}</table-column>
<table-column label="所属单位">{{row.applyUnitName}}</table-column>
<table-column label="开始时间">{{row.reserveStartTime}}</table-column>
<table-column label="结束时间">{{row.reserveEndTime}}</table-column>
<table-column label="当前节点">{{row.taskName || '-'}}</table-column>
@@ -73,7 +71,6 @@ layout("/layouts/platform_h5.html"){
}
},
methods: {
historyBack,
async onReady() {
await this.querySiteType()
await this.querySites()
@@ -148,4 +145,4 @@ layout("/layouts/platform_h5.html"){
<!--#
}
#-->
#-->