Changes
This commit is contained in:
@@ -27,27 +27,71 @@ layout("/layouts/platform.html"){
|
||||
|
||||
<el-card shadow="never" class="mt20">
|
||||
<table-tool label="场地列表"></table-tool>
|
||||
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
|
||||
<el-table-column
|
||||
:label="column.label"
|
||||
:prop="column.prop"
|
||||
:key="column.prop"
|
||||
:width="column.width"
|
||||
:sortable="column.sortable"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
v-for="column in tableColumns"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="180">
|
||||
<template v-slot="{ row }">
|
||||
<el-button @click="onViewSite(row)" size="mini" type="primary">查看场地</el-button>
|
||||
<el-button @click="onApply(row)" size="mini" type="primary">预约</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div v-if="tableData.length > 0" class="site-card-grid">
|
||||
<div v-for="row in tableData" :key="row.id" class="site-card">
|
||||
<div class="site-card__media">
|
||||
<el-image
|
||||
v-if="row.sitePhoto"
|
||||
:preview-src-list="[row.sitePhoto]"
|
||||
:src="row.sitePhoto"
|
||||
fit="cover"
|
||||
class="site-card__image">
|
||||
</el-image>
|
||||
<div v-else class="site-card__image site-card__image--placeholder">
|
||||
<i class="el-icon-picture-outline"></i>
|
||||
<span>暂无场地照片</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="site-card__content">
|
||||
<div class="site-card__header">
|
||||
<div class="site-card__title-wrap">
|
||||
<div class="site-card__title" :title="row.name">{{ row.name || '--' }}</div>
|
||||
<div class="site-card__meta">
|
||||
<i class="el-icon-location-outline"></i>
|
||||
<span :title="row.address">{{ row.address || '暂无场地地址' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="site-card__actions">
|
||||
<el-tag size="mini" effect="dark" type="success">{{ row.reserveTimeTypeName || '分段预约' }}</el-tag>
|
||||
<el-button size="mini" plain @click="onViewSite(row)">场地详情</el-button>
|
||||
<el-button size="mini" type="primary" @click="onApply(row)">预约</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="site-card__summary">
|
||||
<span>场地类型:{{ row.typeName || '--' }}</span>
|
||||
<span>容纳人数:{{ row.maxNum || 0 }}人</span>
|
||||
<span>联系人:{{ row.contactName || '--' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="site-card__timeline">
|
||||
<div class="site-card__timeline-title">今日预约情况</div>
|
||||
<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="hour in hourMarks" :key="row.id + '-hour-' + hour">{{ hour }}</span>
|
||||
</div>
|
||||
<div class="timeline-legend">
|
||||
<span class="timeline-legend__item">
|
||||
<i class="timeline-legend__dot timeline-legend__dot--available"></i>未预约
|
||||
</span>
|
||||
<span class="timeline-legend__item">
|
||||
<i class="timeline-legend__dot timeline-legend__dot--reserved"></i>已预约
|
||||
</span>
|
||||
<span class="timeline-legend__item">
|
||||
<i class="timeline-legend__dot timeline-legend__dot--closed"></i>未开放
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-else description="暂无可预约场地"></el-empty>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
</template>
|
||||
@@ -63,7 +107,7 @@ layout("/layouts/platform.html"){
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include('../manage/info.js'){}#-->
|
||||
<!--#include('apply.js'){}#-->
|
||||
<!--#include('apply_v2.js'){}#-->
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
@@ -74,14 +118,7 @@ layout("/layouts/platform.html"){
|
||||
data() {
|
||||
return {
|
||||
typeOptions: [],
|
||||
tableColumns: [
|
||||
{prop: 'name', label: '场地名称'},
|
||||
{prop: 'address', label: '场地地址'},
|
||||
{prop: 'contactName', label: '联系人'},
|
||||
{prop: 'contactPhone', label: '联系电话'},
|
||||
{prop: 'maxNum', label: '容纳人数'},
|
||||
{prop: 'typeName', label: '场地类型'},
|
||||
],
|
||||
hourMarks: ['0', '2', '4', '6', '8', '10', '12', '14', '16', '18', '20', '22']
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -120,6 +157,374 @@ layout("/layouts/platform.html"){
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.site-card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.site-card {
|
||||
display: flex;
|
||||
min-height: 240px;
|
||||
padding: 18px;
|
||||
border: 1px solid #e8edf5;
|
||||
border-radius: 16px;
|
||||
background: linear-gradient(180deg, #ffffff 0%, #f8fbff 100%);
|
||||
box-shadow: 0 10px 30px rgba(21, 66, 120, 0.06);
|
||||
}
|
||||
|
||||
.site-card__media {
|
||||
flex: 0 0 180px;
|
||||
margin-right: 18px;
|
||||
}
|
||||
|
||||
.site-card__image {
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
border-radius: 14px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.site-card__image--placeholder {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #8c9bb1;
|
||||
background: linear-gradient(135deg, #eef4fb 0%, #dde8f6 100%);
|
||||
font-size: 14px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.site-card__image--placeholder i {
|
||||
font-size: 34px;
|
||||
}
|
||||
|
||||
.site-card__content {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.site-card__header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.site-card__title-wrap {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.site-card__title {
|
||||
overflow: hidden;
|
||||
color: #1f2d3d;
|
||||
font-size: 22px;
|
||||
font-weight: 700;
|
||||
line-height: 1.3;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.site-card__meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 10px;
|
||||
color: #7f8ea3;
|
||||
font-size: 14px;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.site-card__meta span {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.site-card__actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.site-card__summary {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 16px;
|
||||
color: #4f6277;
|
||||
font-size: 13px;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.site-card__timeline {
|
||||
margin-top: auto;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.site-card__timeline-title {
|
||||
margin-bottom: 10px;
|
||||
color: #25364d;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.timeline-bar {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(48, minmax(0, 1fr));
|
||||
gap: 2px;
|
||||
align-items: center;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.timeline-bar__segment {
|
||||
height: 8px;
|
||||
border-radius: 999px;
|
||||
background: #e5ebf3;
|
||||
}
|
||||
|
||||
.timeline-bar__segment--available {
|
||||
background: #32b56c;
|
||||
}
|
||||
|
||||
.timeline-bar__segment--reserved {
|
||||
background: #9aa6b2;
|
||||
}
|
||||
|
||||
.timeline-bar__segment--closed {
|
||||
background: #e9edf3;
|
||||
}
|
||||
|
||||
.timeline-scale {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(12, minmax(0, 1fr));
|
||||
margin-top: 10px;
|
||||
color: #607389;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.timeline-scale span {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.timeline-scale span:last-child {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.timeline-legend {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 12px;
|
||||
color: #607389;
|
||||
font-size: 13px;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.timeline-legend__item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.timeline-legend__dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.timeline-legend__dot--available {
|
||||
background: #32b56c;
|
||||
}
|
||||
|
||||
.timeline-legend__dot--reserved {
|
||||
background: #9aa6b2;
|
||||
}
|
||||
|
||||
.timeline-legend__dot--closed {
|
||||
background: #e9edf3;
|
||||
border: 1px solid #d6dde8;
|
||||
}
|
||||
|
||||
.apply-visual-panel {
|
||||
margin-bottom: 18px;
|
||||
padding: 18px;
|
||||
border: 1px solid #e8edf5;
|
||||
border-radius: 14px;
|
||||
background: linear-gradient(180deg, #ffffff 0%, #f6faff 100%);
|
||||
}
|
||||
|
||||
.apply-visual-panel__toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.apply-visual-panel__title {
|
||||
color: #1f2d3d;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.apply-visual-panel__subtitle {
|
||||
margin-top: 6px;
|
||||
color: #708399;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.apply-visual-panel__actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.apply-visual-panel__legend {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 14px;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.apply-legend__item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: #607389;
|
||||
font-size: 13px;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.apply-legend__dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.apply-legend__dot--available {
|
||||
background: #32b56c;
|
||||
}
|
||||
|
||||
.apply-legend__dot--reserved {
|
||||
background: #9aa6b2;
|
||||
}
|
||||
|
||||
.apply-legend__dot--selected {
|
||||
background: #2f7df6;
|
||||
}
|
||||
|
||||
.apply-legend__dot--closed {
|
||||
background: #e9edf3;
|
||||
border: 1px solid #d6dde8;
|
||||
}
|
||||
|
||||
.apply-block-group {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.apply-block-group__title {
|
||||
margin-bottom: 10px;
|
||||
color: #1f2d3d;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.apply-block-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.apply-block {
|
||||
min-height: 40px;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 10px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.apply-block--available {
|
||||
color: #0f5132;
|
||||
background: #d9f6e5;
|
||||
border-color: #87d7a7;
|
||||
}
|
||||
|
||||
.apply-block--reserved {
|
||||
color: #4b5663;
|
||||
background: #e1e6ec;
|
||||
border-color: #c5ced8;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.apply-block--closed {
|
||||
color: #8b97a6;
|
||||
background: #f3f5f8;
|
||||
border-color: #e2e8f0;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.apply-block--selected {
|
||||
color: #ffffff;
|
||||
background: #2f7df6;
|
||||
border-color: #2f7df6;
|
||||
box-shadow: 0 6px 16px rgba(47, 125, 246, 0.22);
|
||||
}
|
||||
|
||||
.apply-block:not(.apply-block--reserved):not(.apply-block--closed):hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 8px 16px rgba(30, 72, 124, 0.12);
|
||||
}
|
||||
|
||||
.apply-visual-panel__summary {
|
||||
margin-top: 16px;
|
||||
padding: 12px 14px;
|
||||
color: #1f4e8c;
|
||||
font-size: 13px;
|
||||
background: #eef5ff;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1400px) {
|
||||
.site-card-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.site-card {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.site-card__media {
|
||||
flex: none;
|
||||
margin-right: 0;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.site-card__image {
|
||||
width: 100%;
|
||||
height: 220px;
|
||||
}
|
||||
|
||||
.site-card__header {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.site-card__actions {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.apply-visual-panel__toolbar {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
|
||||
+501
-102
@@ -2,109 +2,226 @@
|
||||
template: /*language=HTML*/ `
|
||||
<div>
|
||||
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left">
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="创建人" prop="createUserName">
|
||||
<el-input disabled type="text" v-model="formData.createUserName" maxlength="20" placeholder="请输入创建人"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="sortNum" label="排序编号">
|
||||
<el-input v-model="formData.sortNum" placeholder="请输入排序编号" type="number"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-tabs v-model="activeTab">
|
||||
<el-tab-pane label="场地基本信息" name="basicInfo">
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="创建人" prop="createUserName">
|
||||
<el-input disabled type="text" v-model="formData.createUserName" maxlength="20" placeholder="请输入创建人"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="sortNum" label="排序编号">
|
||||
<el-input v-model="formData.sortNum" placeholder="请输入排序编号" type="number"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="场地名称" prop="name">
|
||||
<el-input type="text" v-model="formData.name" maxlength="50" placeholder="请输入场地名称"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="场地地址" prop="address">
|
||||
<el-input type="text" v-model="formData.address" maxlength="100" placeholder="请输入场地地址"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="场地名称" prop="name">
|
||||
<el-input type="text" v-model="formData.name" maxlength="50" placeholder="请输入场地名称"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="场地地址" prop="address">
|
||||
<el-input type="text" v-model="formData.address" maxlength="100" placeholder="请输入场地地址"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系人" prop="contactName">
|
||||
<el-input type="text" v-model="formData.contactName" maxlength="20" placeholder="请输入联系人"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系电话" prop="contactPhone">
|
||||
<el-input type="text" v-model="formData.contactPhone" maxlength="20" placeholder="请输入联系电话"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系人" prop="contactName">
|
||||
<el-input type="text" v-model="formData.contactName" maxlength="20" placeholder="请输入联系人"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系电话" prop="contactPhone">
|
||||
<el-input type="text" v-model="formData.contactPhone" maxlength="20" placeholder="请输入联系电话"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="容纳人数" prop="maxNum">
|
||||
<el-input v-model="formData.maxNum" placeholder="请输入容纳人数" type="number"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="场地类型" prop="typeId">
|
||||
<el-select v-model="formData.typeId" clearable filterable placeholder="请选择场地类型" style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in typeList"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
:key="item.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="容纳人数" prop="maxNum">
|
||||
<el-input v-model="formData.maxNum" placeholder="请输入容纳人数" type="number"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="场地类型" prop="typeId">
|
||||
<el-select v-model="formData.typeId" clearable filterable placeholder="请选择场地类型" style="width: 100%">
|
||||
<el-option
|
||||
v-for="item in typeList"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
:key="item.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="sexLimit" label="性别限制">
|
||||
<el-radio-group v-model="formData.sexLimit" size="medium">
|
||||
<el-radio-button :label="0">不限制</el-radio-button>
|
||||
<el-radio-button :label="1">男</el-radio-button>
|
||||
<el-radio-button :label="2">女</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-form-item label="场地介绍" prop="introduce">
|
||||
<text-editor v-model="formData.introduce"></text-editor>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="state" label="开启状态">
|
||||
<el-radio-group v-model="formData.state" size="medium">
|
||||
<el-radio-button :label="true">开启</el-radio-button>
|
||||
<el-radio-button :label="false">禁用</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="filterHolidays" label="排除节假日">
|
||||
<el-radio-group v-model="formData.filterHolidays" size="medium">
|
||||
<el-radio-button :label="true">是</el-radio-button>
|
||||
<el-radio-button :label="false">否</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-form-item label="场地照片" prop="sitePhoto">
|
||||
<file-upload
|
||||
:value.sync="formData.sitePhoto"
|
||||
:upload_number="1"
|
||||
:upload_size="1024 * 1024 * 10"
|
||||
accept=".jpg,.jpeg,.png"
|
||||
upload_result_category="interval"
|
||||
complete_result>
|
||||
</file-upload>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="禁用时间">
|
||||
<el-button type="primary" @click="openSetUpTime" size="small">点击设置禁用时间</el-button>
|
||||
<span style="color: #c64120">您已设置{{ formData.notApplyTimeList ? formData.notApplyTimeList.length : 0 }}个禁用时间</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-form-item label="场地介绍" prop="introduce">
|
||||
<text-editor v-model="formData.introduce"></text-editor>
|
||||
</el-form-item>
|
||||
<el-tab-pane label="设置场地" name="siteSetting">
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="state" label="开启状态">
|
||||
<el-radio-group v-model="formData.state" size="medium">
|
||||
<el-radio-button :label="true">开启</el-radio-button>
|
||||
<el-radio-button :label="false">禁用</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="sexLimit" label="性别限制">
|
||||
<el-radio-group v-model="formData.sexLimit" size="medium">
|
||||
<el-radio-button :label="0">不限制</el-radio-button>
|
||||
<el-radio-button :label="1">男</el-radio-button>
|
||||
<el-radio-button :label="2">女</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="reserveTimeType" label="预约时间段类型">
|
||||
<el-radio-group v-model="formData.reserveTimeType" @change="handleReserveTimeTypeChange" size="medium">
|
||||
<el-radio-button :label="1">分段预约</el-radio-button>
|
||||
<el-radio-button :label="2">全天候预约</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="filterHolidays" label="排除节假日">
|
||||
<el-radio-group v-model="formData.filterHolidays" size="medium">
|
||||
<el-radio-button :label="true">是</el-radio-button>
|
||||
<el-radio-button :label="false">否</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="禁用时间">
|
||||
<el-button type="primary" @click="openSetUpTime" size="small">点击设置禁用时间</el-button>
|
||||
<span style="color: #c64120">您已设置{{ formData.notApplyTimeList ? formData.notApplyTimeList.length : 0 }}个禁用时间</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-divider content-position="left">场次信息</el-divider>
|
||||
|
||||
<div v-if="formData.reserveTimeType === 1">
|
||||
<div class="left-span-label">分段预约:可设置一个或多个场次,预约人按拆分后的场次进行预约。</div>
|
||||
<el-table :data="formData.openHours" border size="mini">
|
||||
<el-table-column type="index" label="序号" align="center" header-align="center" width="80"></el-table-column>
|
||||
<el-table-column prop="startTime" label="开始时间" align="center" header-align="center">
|
||||
<template v-slot="{ row }">
|
||||
<el-time-select
|
||||
style="width: 100%"
|
||||
placeholder="开始时间"
|
||||
v-model="row.startTime"
|
||||
@change="checkSegmentedOpenHoursOverlap"
|
||||
:picker-options="{ start: '00:00', step: '00:30', end: '23:59' }">
|
||||
</el-time-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="endTime" label="结束时间" align="center" header-align="center">
|
||||
<template v-slot="{ row }">
|
||||
<el-time-select
|
||||
style="width: 100%"
|
||||
placeholder="结束时间"
|
||||
v-model="row.endTime"
|
||||
@change="checkSegmentedOpenHoursOverlap"
|
||||
:picker-options="{ start: '00:00', step: '00:30', end: '23:59' }">
|
||||
</el-time-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="timeUnit" label="预约时间单位(分钟)" align="center" header-align="center">
|
||||
<template v-slot="{ row }">
|
||||
<el-input-number style="width: 100%" v-model="row.timeUnit" :min="1" :step="1" :precision="0" placeholder="请输入预约时间单位"></el-input-number>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" header-align="center" width="130">
|
||||
<template slot="header">
|
||||
<el-button size="mini" type="primary" icon="el-icon-plus" @click="addOpenHour">添加场次</el-button>
|
||||
</template>
|
||||
<template v-slot="scope">
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
:disabled="formData.openHours.length <= 1"
|
||||
@click="formData.openHours.splice(scope.$index, 1)">
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<div class="left-span-label">全天候预约:设置可预约的开始时间、结束时间和预约时间单位(分钟),预约人按设定单位选择连续时段。</div>
|
||||
<el-row :gutter="20" type="flex">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="开始时间">
|
||||
<el-time-select
|
||||
style="width: 100%"
|
||||
placeholder="开始时间"
|
||||
v-model="fullDayOpenHour.startTime"
|
||||
:picker-options="{ start: '00:00', step: '00:30', end: '23:59' }">
|
||||
</el-time-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="结束时间">
|
||||
<el-time-select
|
||||
style="width: 100%"
|
||||
placeholder="结束时间"
|
||||
v-model="fullDayOpenHour.endTime"
|
||||
:picker-options="{ start: '00:00', step: '00:30', end: '23:59' }">
|
||||
</el-time-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="预约时间单位(分钟)">
|
||||
<el-input-number
|
||||
style="width: 100%"
|
||||
v-model="fullDayOpenHour.timeUnit"
|
||||
:min="1"
|
||||
:step="1"
|
||||
:precision="0"
|
||||
placeholder="请输入预约时间单位">
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-form>
|
||||
<div class="mt10" style="color: #909399; font-size: 13px;">
|
||||
暂存:保存当前填写内容并留在本页继续编辑。正式提交:保存后返回列表页。
|
||||
</div>
|
||||
<el-row class="mt10" justify="end" type="flex">
|
||||
<el-button @click="$emit('refresh')">取消</el-button>
|
||||
<el-button @click="onSubmit" type="primary">提交</el-button>
|
||||
<el-button @click="onTempSave" plain type="warning">暂存并继续编辑</el-button>
|
||||
<el-button @click="onSubmit" type="primary">正式提交</el-button>
|
||||
</el-row>
|
||||
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :visible.sync="setUpTimeDialog" title="设置时间">
|
||||
@@ -202,10 +319,17 @@
|
||||
store,
|
||||
data() {
|
||||
return {
|
||||
activeTab: 'basicInfo',
|
||||
segmentedOpenHoursCache: [{ startTime: '', endTime: '', timeUnit: 30 }],
|
||||
fullDayOpenHourCache: { startTime: '', endTime: '', timeUnit: 30 },
|
||||
formData: {
|
||||
state: true,
|
||||
sexLimit: 0,
|
||||
filterHolidays: false,
|
||||
reserveTimeType: 1,
|
||||
openHours: [{ startTime: '', endTime: '', timeUnit: 30 }],
|
||||
segmentedOpenHours: [{ startTime: '', endTime: '', timeUnit: 30 }],
|
||||
fullDayOpenHour: { startTime: '', endTime: '', timeUnit: 30 },
|
||||
notApplyTimeList: [],
|
||||
createUserName: this.$store.state.user.username,
|
||||
createUserId: this.$store.state.user.id,
|
||||
@@ -222,6 +346,7 @@
|
||||
sexLimit: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
filterHolidays: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
state: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
reserveTimeType: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||
},
|
||||
setUpTimeDialog: false,
|
||||
timeOneKeySet: {
|
||||
@@ -231,7 +356,218 @@
|
||||
multipleSelection: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fullDayOpenHour() {
|
||||
if (!Array.isArray(this.formData.openHours)) {
|
||||
this.$set(this.formData, 'openHours', [])
|
||||
}
|
||||
if (this.formData.openHours.length === 0) {
|
||||
this.formData.openHours.push({ startTime: '', endTime: '', timeUnit: 30 })
|
||||
}
|
||||
if (!this.formData.openHours[0].timeUnit || this.formData.openHours[0].timeUnit <= 0) {
|
||||
this.$set(this.formData.openHours[0], 'timeUnit', 30)
|
||||
}
|
||||
return this.formData.openHours[0]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
normalizeTimeUnit(value, defaultValue = 30) {
|
||||
const num = Number(value)
|
||||
if (!Number.isFinite(num) || num <= 0) {
|
||||
return defaultValue
|
||||
}
|
||||
return Math.round(num)
|
||||
},
|
||||
syncOpenHoursCache() {
|
||||
if (this.formData.reserveTimeType === 1) {
|
||||
this.segmentedOpenHoursCache = Array.isArray(this.formData.openHours) && this.formData.openHours.length > 0
|
||||
? clone(this.formData.openHours).map(item => ({
|
||||
startTime: item.startTime || '',
|
||||
endTime: item.endTime || '',
|
||||
timeUnit: this.normalizeTimeUnit(item.timeUnit),
|
||||
}))
|
||||
: [{ startTime: '', endTime: '', timeUnit: 30 }]
|
||||
this.formData.segmentedOpenHours = clone(this.segmentedOpenHoursCache)
|
||||
} else {
|
||||
const first = (this.formData.openHours && this.formData.openHours[0]) || {}
|
||||
this.fullDayOpenHourCache = {
|
||||
startTime: first.startTime || '',
|
||||
endTime: first.endTime || '',
|
||||
timeUnit: this.normalizeTimeUnit(first.timeUnit),
|
||||
}
|
||||
this.formData.fullDayOpenHour = clone(this.fullDayOpenHourCache)
|
||||
}
|
||||
},
|
||||
buildSubmitFormData() {
|
||||
this.syncOpenHoursCache()
|
||||
const submitData = clone(this.formData)
|
||||
submitData.segmentedOpenHours = clone(this.segmentedOpenHoursCache || [])
|
||||
submitData.fullDayOpenHour = clone(this.fullDayOpenHourCache || { startTime: '', endTime: '', timeUnit: 30 })
|
||||
if (submitData.reserveTimeType === 1) {
|
||||
submitData.openHours = clone(this.segmentedOpenHoursCache || [])
|
||||
} else {
|
||||
submitData.openHours = [clone(this.fullDayOpenHourCache || { startTime: '', endTime: '', timeUnit: 60 })]
|
||||
}
|
||||
return submitData
|
||||
},
|
||||
initOpenHoursCache() {
|
||||
const segmentedOpenHours = Array.isArray(this.formData.segmentedOpenHours) && this.formData.segmentedOpenHours.length > 0
|
||||
? clone(this.formData.segmentedOpenHours)
|
||||
: (Array.isArray(this.formData.openHours) ? clone(this.formData.openHours) : [])
|
||||
const fullDayOpenHour = this.formData.fullDayOpenHour && Object.keys(this.formData.fullDayOpenHour).length > 0
|
||||
? clone(this.formData.fullDayOpenHour)
|
||||
: ((Array.isArray(this.formData.openHours) && this.formData.openHours.length > 0) ? clone(this.formData.openHours[0]) : {})
|
||||
if (this.formData.reserveTimeType === 2) {
|
||||
this.fullDayOpenHourCache = {
|
||||
startTime: fullDayOpenHour.startTime || '',
|
||||
endTime: fullDayOpenHour.endTime || '',
|
||||
timeUnit: this.normalizeTimeUnit(fullDayOpenHour.timeUnit),
|
||||
}
|
||||
this.segmentedOpenHoursCache = segmentedOpenHours && segmentedOpenHours.length > 0
|
||||
? segmentedOpenHours.map(item => ({
|
||||
startTime: item.startTime || '',
|
||||
endTime: item.endTime || '',
|
||||
timeUnit: this.normalizeTimeUnit(item.timeUnit),
|
||||
}))
|
||||
: [{ startTime: '', endTime: '', timeUnit: 30 }]
|
||||
this.formData.openHours = [clone(this.fullDayOpenHourCache)]
|
||||
} else {
|
||||
this.segmentedOpenHoursCache = segmentedOpenHours.length > 0
|
||||
? segmentedOpenHours.map(item => ({
|
||||
startTime: item.startTime || '',
|
||||
endTime: item.endTime || '',
|
||||
timeUnit: this.normalizeTimeUnit(item.timeUnit),
|
||||
}))
|
||||
: [{ startTime: '', endTime: '', timeUnit: 30 }]
|
||||
const first = this.segmentedOpenHoursCache[0] || {}
|
||||
this.fullDayOpenHourCache = {
|
||||
startTime: fullDayOpenHour.startTime || first.startTime || '',
|
||||
endTime: fullDayOpenHour.endTime || first.endTime || '',
|
||||
timeUnit: this.normalizeTimeUnit(fullDayOpenHour.timeUnit || first.timeUnit),
|
||||
}
|
||||
this.formData.openHours = clone(this.segmentedOpenHoursCache)
|
||||
}
|
||||
this.formData.segmentedOpenHours = clone(this.segmentedOpenHoursCache)
|
||||
this.formData.fullDayOpenHour = clone(this.fullDayOpenHourCache)
|
||||
},
|
||||
addOpenHour() {
|
||||
if (!Array.isArray(this.formData.openHours)) {
|
||||
this.$set(this.formData, 'openHours', [])
|
||||
}
|
||||
this.formData.openHours.push({ startTime: '', endTime: '', timeUnit: 30 })
|
||||
this.segmentedOpenHoursCache = clone(this.formData.openHours)
|
||||
},
|
||||
hasSegmentedOpenHoursOverlap(openHours) {
|
||||
const validHours = (openHours || [])
|
||||
.map((item, index) => ({ ...item, index }))
|
||||
.filter(item => item.startTime && item.endTime && item.startTime < item.endTime)
|
||||
.sort((a, b) => a.startTime.localeCompare(b.startTime))
|
||||
for (let i = 1; i < validHours.length; i++) {
|
||||
const prev = validHours[i - 1]
|
||||
const current = validHours[i]
|
||||
if (current.startTime < prev.endTime) {
|
||||
return {
|
||||
overlap: true,
|
||||
prevIndex: prev.index,
|
||||
currentIndex: current.index,
|
||||
}
|
||||
}
|
||||
}
|
||||
return { overlap: false }
|
||||
},
|
||||
checkSegmentedOpenHoursOverlap() {
|
||||
if (this.formData.reserveTimeType !== 1) {
|
||||
return false
|
||||
}
|
||||
const result = this.hasSegmentedOpenHoursOverlap(this.formData.openHours)
|
||||
if (result.overlap) {
|
||||
this.$message.warning('第' + (result.prevIndex + 1) + '条和第' + (result.currentIndex + 1) + '条场次时间有重叠,请调整后再保存')
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
handleReserveTimeTypeChange(val) {
|
||||
if (!Array.isArray(this.formData.openHours)) {
|
||||
this.$set(this.formData, 'openHours', [])
|
||||
}
|
||||
if (val === 1) {
|
||||
const currentFullDay = this.formData.openHours[0] || this.fullDayOpenHourCache || {}
|
||||
this.fullDayOpenHourCache = {
|
||||
startTime: currentFullDay.startTime || '',
|
||||
endTime: currentFullDay.endTime || '',
|
||||
timeUnit: this.normalizeTimeUnit(currentFullDay.timeUnit),
|
||||
}
|
||||
if (!Array.isArray(this.segmentedOpenHoursCache) || this.segmentedOpenHoursCache.length === 0) {
|
||||
this.segmentedOpenHoursCache = [{
|
||||
startTime: this.fullDayOpenHourCache.startTime || '',
|
||||
endTime: this.fullDayOpenHourCache.endTime || '',
|
||||
timeUnit: this.normalizeTimeUnit(this.fullDayOpenHourCache.timeUnit),
|
||||
}]
|
||||
}
|
||||
this.formData.openHours = clone(this.segmentedOpenHoursCache)
|
||||
} else if (val === 2) {
|
||||
this.segmentedOpenHoursCache = Array.isArray(this.formData.openHours) && this.formData.openHours.length > 0
|
||||
? clone(this.formData.openHours)
|
||||
: this.segmentedOpenHoursCache
|
||||
const first = this.fullDayOpenHourCache && (this.fullDayOpenHourCache.startTime || this.fullDayOpenHourCache.endTime)
|
||||
? this.fullDayOpenHourCache
|
||||
: (this.segmentedOpenHoursCache[0] || {})
|
||||
this.fullDayOpenHourCache = {
|
||||
startTime: first.startTime || '',
|
||||
endTime: first.endTime || '',
|
||||
timeUnit: this.normalizeTimeUnit(first.timeUnit || this.fullDayOpenHourCache.timeUnit),
|
||||
}
|
||||
this.formData.openHours = [clone(this.fullDayOpenHourCache)]
|
||||
}
|
||||
},
|
||||
validateOpenHours() {
|
||||
const openHours = this.formData.openHours || []
|
||||
if (this.formData.reserveTimeType === 1) {
|
||||
if (openHours.length === 0) {
|
||||
this.$message.warning('请至少添加一条场次信息')
|
||||
return false
|
||||
}
|
||||
for (let i = 0; i < openHours.length; i++) {
|
||||
const item = openHours[i] || {}
|
||||
if (!item.startTime) {
|
||||
this.$message.warning('第' + (i + 1) + '条场次信息中,开始时间必填')
|
||||
return false
|
||||
}
|
||||
if (!item.endTime) {
|
||||
this.$message.warning('第' + (i + 1) + '条场次信息中,结束时间必填')
|
||||
return false
|
||||
}
|
||||
if (item.startTime >= item.endTime) {
|
||||
this.$message.warning('第' + (i + 1) + '条场次信息中,开始时间必须早于结束时间')
|
||||
return false
|
||||
}
|
||||
if (!item.timeUnit || item.timeUnit <= 0) {
|
||||
this.$message.warning('第' + (i + 1) + '条场次信息中,预约时间单位必须大于0分钟')
|
||||
return false
|
||||
}
|
||||
}
|
||||
const overlapResult = this.hasSegmentedOpenHoursOverlap(openHours)
|
||||
if (overlapResult.overlap) {
|
||||
this.$message.warning('第' + (overlapResult.prevIndex + 1) + '条和第' + (overlapResult.currentIndex + 1) + '条场次时间有重叠,请调整后再保存')
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
const item = openHours[0] || {}
|
||||
if (!item.startTime || !item.endTime) {
|
||||
this.$message.warning('请设置全天候预约的开始时间和结束时间')
|
||||
return false
|
||||
}
|
||||
if (item.startTime >= item.endTime) {
|
||||
this.$message.warning('全天候预约的开始时间必须早于结束时间')
|
||||
return false
|
||||
}
|
||||
if (!item.timeUnit || item.timeUnit <= 0) {
|
||||
this.$message.warning('全天候预约的预约时间单位必须大于0分钟')
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
},
|
||||
doConfirmSetUpCourse() {
|
||||
const timeList = this.formData.notApplyTimeList
|
||||
if (timeList && timeList.length > 0) {
|
||||
@@ -296,40 +632,103 @@
|
||||
if (this.formData.notApplyTimeList) {
|
||||
this.$set(this.formData, 'setUpDate', this.formData.notApplyTimeList.map(o => o.date))
|
||||
}
|
||||
this.activeTab = 'siteSetting'
|
||||
this.setUpTimeDialog = true
|
||||
},
|
||||
onOpen(row) {
|
||||
this.activeTab = 'basicInfo'
|
||||
if (row && row.id) {
|
||||
this.formData = clone(row)
|
||||
if (!Array.isArray(this.formData.notApplyTimeList)) {
|
||||
this.$set(this.formData, 'notApplyTimeList', [])
|
||||
}
|
||||
if (!this.formData.reserveTimeType) {
|
||||
this.$set(this.formData, 'reserveTimeType', 1)
|
||||
}
|
||||
if (!Array.isArray(this.formData.openHours) || this.formData.openHours.length === 0) {
|
||||
this.$set(this.formData, 'openHours', this.formData.reserveTimeType === 2 ? [{ startTime: '', endTime: '', timeUnit: 30 }] : [{ startTime: '', endTime: '', timeUnit: 30 }])
|
||||
}
|
||||
if (!Array.isArray(this.formData.segmentedOpenHours) || this.formData.segmentedOpenHours.length === 0) {
|
||||
this.$set(this.formData, 'segmentedOpenHours', [{ startTime: '', endTime: '', timeUnit: 30 }])
|
||||
}
|
||||
if (!this.formData.fullDayOpenHour) {
|
||||
this.$set(this.formData, 'fullDayOpenHour', { startTime: '', endTime: '', timeUnit: 30 })
|
||||
}
|
||||
this.initOpenHoursCache()
|
||||
} else {
|
||||
this.formData = {
|
||||
state: true,
|
||||
sexLimit: 0,
|
||||
filterHolidays: false,
|
||||
reserveTimeType: 1,
|
||||
openHours: [{ startTime: '', endTime: '', timeUnit: 30 }],
|
||||
segmentedOpenHours: [{ startTime: '', endTime: '', timeUnit: 30 }],
|
||||
fullDayOpenHour: { startTime: '', endTime: '', timeUnit: 30 },
|
||||
notApplyTimeList: [],
|
||||
createUserName: this.$store.state.user.username,
|
||||
createUserId: this.$store.state.user.id,
|
||||
}
|
||||
this.segmentedOpenHoursCache = [{ startTime: '', endTime: '', timeUnit: 30 }]
|
||||
this.fullDayOpenHourCache = { startTime: '', endTime: '', timeUnit: 30 }
|
||||
}
|
||||
},
|
||||
async doSave(stayOnPage) {
|
||||
if (!this.validateOpenHours()) {
|
||||
this.activeTab = 'siteSetting'
|
||||
return
|
||||
}
|
||||
const submitData = this.buildSubmitFormData()
|
||||
const resp = await this.$axios.post("/platform/siteCug/manage/submit", {data: JSON.stringify(submitData)})
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(stayOnPage ? '暂存成功,您可以继续编辑当前内容' : '正式提交成功,已返回列表页')
|
||||
if (resp.data) {
|
||||
this.formData = clone(resp.data)
|
||||
if (!Array.isArray(this.formData.notApplyTimeList)) {
|
||||
this.$set(this.formData, 'notApplyTimeList', [])
|
||||
}
|
||||
if (!this.formData.reserveTimeType) {
|
||||
this.$set(this.formData, 'reserveTimeType', 1)
|
||||
}
|
||||
if (!Array.isArray(this.formData.openHours) || this.formData.openHours.length === 0) {
|
||||
this.$set(this.formData, 'openHours', this.formData.reserveTimeType === 2 ? [{ startTime: '', endTime: '', timeUnit: 30 }] : [{ startTime: '', endTime: '', timeUnit: 30 }])
|
||||
}
|
||||
if (!Array.isArray(this.formData.segmentedOpenHours) || this.formData.segmentedOpenHours.length === 0) {
|
||||
this.$set(this.formData, 'segmentedOpenHours', [{ startTime: '', endTime: '', timeUnit: 30 }])
|
||||
}
|
||||
if (!this.formData.fullDayOpenHour) {
|
||||
this.$set(this.formData, 'fullDayOpenHour', { startTime: '', endTime: '', timeUnit: 30 })
|
||||
}
|
||||
this.initOpenHoursCache()
|
||||
}
|
||||
if (!stayOnPage) {
|
||||
this.$emit('refresh')
|
||||
}
|
||||
} else {
|
||||
this.$message.warning(resp.msg)
|
||||
}
|
||||
},
|
||||
onTempSave() {
|
||||
this.$refs.formRef.validate(async (valid) => {
|
||||
if (valid) {
|
||||
this.$confirm("确认暂存当前内容,并继续留在本页编辑吗?", "暂存确认", {
|
||||
confirmButtonText: "确认暂存",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(async () => {
|
||||
await this.doSave(true)
|
||||
}).catch(() => {})
|
||||
}
|
||||
})
|
||||
},
|
||||
onSubmit() {
|
||||
this.$refs.formRef.validate((valid) => {
|
||||
if (valid) {
|
||||
this.$confirm("您确定要提交吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
this.$confirm("确认正式提交当前内容吗?提交成功后将返回列表页。", "正式提交确认", {
|
||||
confirmButtonText: "确认提交",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
type: "primary"
|
||||
}).then(async () => {
|
||||
const resp = await this.$axios.post("/platform/siteCug/manage/submit", {data: JSON.stringify(this.formData)})
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.$emit('refresh')
|
||||
} else {
|
||||
this.$message.warning(resp.msg)
|
||||
}
|
||||
await this.doSave(false)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -39,15 +39,15 @@ layout("/layouts/platform.html"){
|
||||
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
|
||||
<el-table-column
|
||||
v-for="column in tableColumns"
|
||||
:key="column.prop"
|
||||
:label="column.label"
|
||||
:prop="column.prop"
|
||||
:key="column.prop"
|
||||
:width="column.width"
|
||||
:sortable="column.sortable"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
v-for="column in tableColumns"
|
||||
>
|
||||
<template v-slot="{ row }" v-if="column.prop === 'state'">
|
||||
<el-switch
|
||||
@@ -57,6 +57,10 @@ layout("/layouts/platform.html"){
|
||||
inactive-color="#ff4949">
|
||||
</el-switch>
|
||||
</template>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'reserveTimeType'">
|
||||
<span v-if="row.reserveTimeType === 2">全天候预约</span>
|
||||
<span v-else>分段预约</span>
|
||||
</template>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'sexLimit'">
|
||||
<span v-if="row.sexLimit === 0">不限制</span>
|
||||
<span v-else-if="row.sexLimit === 1">男</span>
|
||||
@@ -98,16 +102,16 @@ layout("/layouts/platform.html"){
|
||||
return {
|
||||
typeOptions: [],
|
||||
tableColumns: [
|
||||
{prop: 'createUserName', label: '创建人'},
|
||||
{prop: 'sortNum', label: '排序编号'},
|
||||
{prop: 'name', label: '场地名称'},
|
||||
{prop: 'address', label: '场地地址'},
|
||||
{prop: 'contactName', label: '联系人'},
|
||||
{prop: 'contactPhone', label: '联系电话'},
|
||||
{prop: 'maxNum', label: '容纳人数'},
|
||||
{prop: 'createUserName', label: '创建人', sortable: 'custom'},
|
||||
{prop: 'name', label: '场地名称', sortable: 'custom'},
|
||||
{prop: 'address', label: '场地地址', sortable: 'custom'},
|
||||
{prop: 'contactName', label: '联系人', sortable: 'custom'},
|
||||
{prop: 'contactPhone', label: '联系电话', sortable: 'custom'},
|
||||
{prop: 'maxNum', label: '容纳人数', sortable: 'custom'},
|
||||
{prop: 'typeName', label: '场地类型'},
|
||||
{prop: 'sexLimit', label: '性别限制'},
|
||||
{prop: 'state', label: '开启状态'},
|
||||
{prop: 'reserveTimeType', label: '预约时间段类型', sortable: 'custom'},
|
||||
{prop: 'sexLimit', label: '性别限制', sortable: 'custom'},
|
||||
{prop: 'state', label: '开启状态', sortable: 'custom'},
|
||||
],
|
||||
}
|
||||
},
|
||||
@@ -132,7 +136,7 @@ layout("/layouts/platform.html"){
|
||||
})
|
||||
},
|
||||
onDelete(row) {
|
||||
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
|
||||
this.$confirm("您确定要删除吗? 是否继续?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
@@ -177,4 +181,4 @@ layout("/layouts/platform.html"){
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
#-->
|
||||
|
||||
@@ -1,51 +1,99 @@
|
||||
const siteInfo = {
|
||||
template: /*language=HTML*/ `
|
||||
<div>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="创建人">{{ viewData.createUserName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="排序编号">{{ viewData.sortNum }}</el-descriptions-item>
|
||||
<el-descriptions-item label="场地名称">{{ viewData.name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="场地地址">{{ viewData.address }}</el-descriptions-item>
|
||||
<el-descriptions-item label="联系人">{{ viewData.contactName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="联系电话">{{ viewData.contactPhone }}</el-descriptions-item>
|
||||
<el-descriptions-item label="容纳人数">{{ viewData.maxNum }}</el-descriptions-item>
|
||||
<el-descriptions-item label="场地类型">{{ viewData.typeName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="排除节假日">
|
||||
<span v-if="viewData.filterHolidays">是</span>
|
||||
<span v-else>否</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="禁用时间" :span="2">
|
||||
<el-table v-if="viewData.notApplyTimeList && viewData.notApplyTimeList.length > 0"
|
||||
:data="viewData.notApplyTimeList" max-height="300" size="mini">
|
||||
<el-table-column prop="date" label="日期"></el-table-column>
|
||||
<el-table-column prop="startTime" label="开始时间"></el-table-column>
|
||||
<el-table-column prop="endTime" label="结束时间"></el-table-column>
|
||||
</el-table>
|
||||
<span v-else>暂无禁用时间</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="性别限制">
|
||||
<span v-if="viewData.sexLimit === 0">不限制</span>
|
||||
<span v-if="viewData.sexLimit === 1">男</span>
|
||||
<span v-if="viewData.sexLimit === 2">女</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="开启状态">
|
||||
<span v-if="viewData.state">开启</span>
|
||||
<span v-else>禁用</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="场地介绍" :span="2">
|
||||
<div v-if="viewData.introduce" v-html="viewData.introduce"></div>
|
||||
<div v-else>暂无场地介绍</div>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-tabs v-model="activeTab">
|
||||
<el-tab-pane label="场地基本信息" name="basicInfo">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="创建人">{{ viewData.createUserName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="排序编号">{{ viewData.sortNum }}</el-descriptions-item>
|
||||
<el-descriptions-item label="场地名称">{{ viewData.name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="场地地址">{{ viewData.address }}</el-descriptions-item>
|
||||
<el-descriptions-item label="联系人">{{ viewData.contactName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="联系电话">{{ viewData.contactPhone }}</el-descriptions-item>
|
||||
<el-descriptions-item label="容纳人数">{{ viewData.maxNum }}</el-descriptions-item>
|
||||
<el-descriptions-item label="场地类型">{{ viewData.typeName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="场地介绍" :span="2">
|
||||
<div v-if="viewData.introduce" v-html="viewData.introduce"></div>
|
||||
<div v-else>暂无场地介绍</div>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="场地照片" :span="2">
|
||||
<el-image
|
||||
v-if="viewData.sitePhoto"
|
||||
:preview-src-list="[viewData.sitePhoto]"
|
||||
:src="viewData.sitePhoto"
|
||||
fit="cover"
|
||||
style="width: 160px; height: 160px; border-radius: 4px;">
|
||||
</el-image>
|
||||
<div v-else>暂无场地照片</div>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="设置场地" name="siteSetting">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="开启状态">
|
||||
<span v-if="viewData.state">开启</span>
|
||||
<span v-else>禁用</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="性别限制">
|
||||
<span v-if="viewData.sexLimit === 0">不限制</span>
|
||||
<span v-else-if="viewData.sexLimit === 1">男</span>
|
||||
<span v-else-if="viewData.sexLimit === 2">女</span>
|
||||
<span v-else>--</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="排除节假日">
|
||||
<span v-if="viewData.filterHolidays">是</span>
|
||||
<span v-else>否</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="预约时间段类型">
|
||||
<span v-if="viewData.reserveTimeType === 1">分段预约</span>
|
||||
<span v-else-if="viewData.reserveTimeType === 2">全天候预约</span>
|
||||
<span v-else>--</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="禁用时间" :span="2">
|
||||
<el-table v-if="viewData.notApplyTimeList && viewData.notApplyTimeList.length > 0"
|
||||
:data="viewData.notApplyTimeList" max-height="300" size="mini">
|
||||
<el-table-column prop="date" label="日期"></el-table-column>
|
||||
<el-table-column prop="startTime" label="开始时间"></el-table-column>
|
||||
<el-table-column prop="endTime" label="结束时间"></el-table-column>
|
||||
</el-table>
|
||||
<span v-else>暂无禁用时间</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="场次信息" :span="2">
|
||||
<div v-if="viewData.reserveTimeType === 1">
|
||||
<el-table v-if="viewData.openHours && viewData.openHours.length > 0"
|
||||
:data="viewData.openHours" max-height="300" size="mini">
|
||||
<el-table-column type="index" label="序号" width="80"></el-table-column>
|
||||
<el-table-column prop="startTime" label="开始时间"></el-table-column>
|
||||
<el-table-column prop="endTime" label="结束时间"></el-table-column>
|
||||
<el-table-column prop="timeUnit" label="预约时间单位(分钟)"></el-table-column>
|
||||
</el-table>
|
||||
<span v-else>暂无场次信息</span>
|
||||
</div>
|
||||
<div v-else-if="viewData.reserveTimeType === 2">
|
||||
<div v-if="viewData.openHours && viewData.openHours.length > 0">
|
||||
<div><span>开始时间:</span><span>{{ viewData.openHours[0].startTime || '--' }}</span></div>
|
||||
<div><span>结束时间:</span><span>{{ viewData.openHours[0].endTime || '--' }}</span></div>
|
||||
<div><span>预约时间单位(分钟):</span><span>{{ viewData.openHours[0].timeUnit || '--' }}</span></div>
|
||||
</div>
|
||||
<span v-else>暂无场次信息</span>
|
||||
</div>
|
||||
<span v-else>暂无场次信息</span>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
activeTab: 'basicInfo',
|
||||
viewData: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onOpen(row) {
|
||||
this.activeTab = 'basicInfo'
|
||||
this.viewData = row
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,23 +1,55 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
<style>
|
||||
.mine-batch-toggle {
|
||||
padding: 0;
|
||||
color: #409EFF;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.mine-batch-empty {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.mine-batch-child-row {
|
||||
background: #fafcff;
|
||||
}
|
||||
|
||||
.mine-batch-child-label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #7a8a9a;
|
||||
}
|
||||
|
||||
.mine-batch-child-label::before {
|
||||
content: "";
|
||||
width: 16px;
|
||||
height: 1px;
|
||||
background: #c8d3df;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<guava ref="guava">
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="姓名/工号/场地">
|
||||
<el-input placeholder="请输入姓名/工号/场地" clearable v-model="pageForm.searchKeyword"
|
||||
<search-item label="姓名/工号">
|
||||
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"
|
||||
@keyup.enter.native="doSearch">
|
||||
</el-input>
|
||||
</search-item>
|
||||
<search-item label="活动场地">
|
||||
<el-select v-model="pageForm.siteId" @change="doSearch" style="width: 100%" placeholder="请选择活动场地" filterable clearable>
|
||||
<el-select v-model="pageForm.siteId" @change="doSearch" style="width: 100%;" placeholder="请选择活动场地" filterable clearable>
|
||||
<el-option v-for="item in siteOptions" :value="item.id" :key="item.id" :label="item.name"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="场地类型">
|
||||
<el-select v-model="pageForm.siteType" @change="doSearch" style="width: 100%" placeholder="请选择场地类型" filterable clearable>
|
||||
<el-select v-model="pageForm.siteType" @change="doSearch" style="width: 100%;" placeholder="请选择场地类型" filterable clearable>
|
||||
<el-option v-for="item in typeOptions" :value="item.id" :key="item.id" :label="item.name"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
@@ -26,33 +58,46 @@ layout("/layouts/platform.html"){
|
||||
|
||||
<el-card shadow="never">
|
||||
<table-tool label="申请列表"></table-tool>
|
||||
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
|
||||
<el-table :data="tableData" @sort-change="pageOrder" :row-class-name="tableRowClassName" style="width: 100%;">
|
||||
<el-table-column label="" width="54" align="center" header-align="center">
|
||||
<template v-slot="{ row }">
|
||||
<el-button
|
||||
v-if="row._hasFoldChildren"
|
||||
class="mine-batch-toggle"
|
||||
type="text"
|
||||
@click="toggleBatchGroup(row)">
|
||||
<i :class="row._expanded ? 'el-icon-caret-bottom' : 'el-icon-caret-right'"></i>
|
||||
</el-button>
|
||||
<span v-else class="mine-batch-empty"></span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column type="index" width="50" label="序号" :index="indexMethod"></el-table-column>
|
||||
<el-table-column
|
||||
v-for="column in tableColumns"
|
||||
:key="column.prop"
|
||||
:label="column.label"
|
||||
:prop="column.prop"
|
||||
:key="column.prop"
|
||||
:width="column.width"
|
||||
:sortable="column.sortable"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
v-for="column in tableColumns"
|
||||
>
|
||||
<template v-slot="{ row }" v-if="column.prop === 'instanceState'">
|
||||
<template v-slot="{ row }" v-if="column.prop === 'siteName'">
|
||||
<span v-if="row._isBatchChild" class="mine-batch-child-label">{{ row.siteName }}</span>
|
||||
<span v-else>{{ row.siteName }}</span>
|
||||
</template>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'instanceState'">
|
||||
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message" size="small"></enum-tag>
|
||||
</template>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'reserveType'">
|
||||
<span>{{ row.reserveType === 'club' ? '协会预约' : '分工会预约' }}</span>
|
||||
</template>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'reserveTargetName'">
|
||||
<span>{{ row.reserveType === 'club' ? (row.clubName || '-') : (row.applyUnionName || '-') }}</span>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'yearlyBatch'">
|
||||
<span>{{ normalizeBatchFlag(row) ? '是' : '否' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="180">
|
||||
<template v-slot="{row}">
|
||||
<template v-slot="{ row }">
|
||||
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
|
||||
<el-button v-if="row.canCancel" @click="onDelete(row)" size="mini" type="danger">删除</el-button>
|
||||
<el-button v-if="row.canCancel && !row._isBatchChild" @click="onDelete(row)" size="mini" type="danger">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -79,29 +124,85 @@ layout("/layouts/platform.html"){
|
||||
return {
|
||||
typeOptions: [],
|
||||
siteOptions: [],
|
||||
rawTableData: [],
|
||||
expandedBatchKeys: {},
|
||||
tableColumns: [
|
||||
{prop: 'siteName', label: '场地名称'},
|
||||
{prop: 'applyUserName', label: '预约人'},
|
||||
{prop: 'reserveType', label: '预约类型'},
|
||||
{prop: 'reserveTargetName', label: '预约单位'},
|
||||
{prop: 'applyUnitName', label: '所属单位'},
|
||||
{prop: 'reserveStartTime', label: '开始时间'},
|
||||
{prop: 'reserveEndTime', label: '结束时间'},
|
||||
{prop: 'applyMobile', label: '联系方式'},
|
||||
{prop: 'taskName', label: '当前节点'},
|
||||
{prop: 'instanceState', label: '流程状态'},
|
||||
{prop: 'siteName', label: '场地名称', sortable: 'custom'},
|
||||
{prop: 'applyUserName', label: '预约人', sortable: 'custom'},
|
||||
{prop: 'applyLoginName', label: '工号', sortable: 'custom'},
|
||||
{prop: 'yearlyBatch', label: '是否批量预约', sortable: 'custom', width: 130},
|
||||
{prop: 'reserveTargetName', label: '预约单位', sortable: 'custom'},
|
||||
{prop: 'reserveStartTime', label: '开始时间', sortable: 'custom'},
|
||||
{prop: 'reserveEndTime', label: '结束时间', sortable: 'custom'},
|
||||
{prop: 'applyMobile', label: '联系方式', sortable: 'custom'},
|
||||
{prop: 'taskName', label: '当前节点', sortable: 'custom'},
|
||||
{prop: 'instanceState', label: '流程状态', sortable: 'custom', width: 120},
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
normalizeBatchFlag(row) {
|
||||
return row && (row.yearlyBatch === 1 || row.yearlyBatch === '1' || row.yearlyBatch === true)
|
||||
},
|
||||
getBatchGroupKey(row) {
|
||||
if (!this.normalizeBatchFlag(row)) {
|
||||
return 'single_' + row.id
|
||||
}
|
||||
const batchNo = row.backOption || row.id
|
||||
return 'batch_' + batchNo + '_' + (row.applyUserName || '') + '_' + (row.siteName || '')
|
||||
},
|
||||
buildTableData(rows) {
|
||||
const groups = new Map()
|
||||
;(rows || []).forEach(row => {
|
||||
const key = this.getBatchGroupKey(row)
|
||||
if (!groups.has(key)) {
|
||||
groups.set(key, [])
|
||||
}
|
||||
groups.get(key).push({...row})
|
||||
})
|
||||
const displayRows = []
|
||||
groups.forEach((groupRows, key) => {
|
||||
const sortedRows = groupRows.slice().sort((a, b) => {
|
||||
return (b.reserveStartTime || '').localeCompare(a.reserveStartTime || '')
|
||||
})
|
||||
const parent = {...sortedRows[0]}
|
||||
const children = sortedRows.slice(1).map(item => ({
|
||||
...item,
|
||||
_isBatchChild: true,
|
||||
_groupKey: key,
|
||||
_hasFoldChildren: false,
|
||||
}))
|
||||
parent._groupKey = key
|
||||
parent._isBatchChild = false
|
||||
parent._hasFoldChildren = children.length > 0
|
||||
parent._expanded = !!this.expandedBatchKeys[key]
|
||||
parent._batchCount = sortedRows.length
|
||||
parent._foldedRecords = children
|
||||
displayRows.push(parent)
|
||||
if (parent._expanded) {
|
||||
displayRows.push(...children)
|
||||
}
|
||||
})
|
||||
return displayRows
|
||||
},
|
||||
tableRowClassName({ row }) {
|
||||
return row && row._isBatchChild ? 'mine-batch-child-row' : ''
|
||||
},
|
||||
toggleBatchGroup(row) {
|
||||
if (!row || !row._groupKey || !row._hasFoldChildren) {
|
||||
return
|
||||
}
|
||||
this.$set(this.expandedBatchKeys, row._groupKey, !this.expandedBatchKeys[row._groupKey])
|
||||
this.tableData = this.buildTableData(this.rawTableData)
|
||||
},
|
||||
onView(row) {
|
||||
this.$refs.guava.edit(() => {
|
||||
this.$refs.infoRef.onOpen(row)
|
||||
})
|
||||
},
|
||||
onDelete(row) {
|
||||
const message = row.yearlyBatch
|
||||
? ('该记录属于“预约本年”批量预约,确认后将一并删除同批次的 ' + (row.batchDeleteCount || 0) + ' 条预约记录,是否继续?')
|
||||
const message = this.normalizeBatchFlag(row)
|
||||
? ('该记录属于“预约本年”批量预约,确认后将一并删除同批次的 ' + (row.batchDeleteCount || row._batchCount || 0) + ' 条预约记录,是否继续?')
|
||||
: '您确定要删除吗?'
|
||||
this.$confirm(message, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
@@ -126,6 +227,15 @@ layout("/layouts/platform.html"){
|
||||
this.siteOptions = res.data
|
||||
})
|
||||
},
|
||||
pageData() {
|
||||
this.$axios.post(loc() + '/pageData', this.pageForm).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.rawTableData = Array.isArray(res.data.list) ? res.data.list : []
|
||||
this.tableData = this.buildTableData(this.rawTableData)
|
||||
this.pageForm.totalCount = res.data.totalCount
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
this.querySiteType()
|
||||
|
||||
@@ -1,64 +1,111 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
<style>
|
||||
.record-batch-toggle {
|
||||
padding: 0;
|
||||
color: #409EFF;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.record-batch-empty {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.record-batch-child-row {
|
||||
background: #fafcff;
|
||||
}
|
||||
|
||||
.record-batch-child-label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #7a8a9a;
|
||||
}
|
||||
|
||||
.record-batch-child-label::before {
|
||||
content: "";
|
||||
width: 16px;
|
||||
height: 1px;
|
||||
background: #c8d3df;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<guava ref="guava">
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="姓名/工号/场地">
|
||||
<el-input placeholder="请输入姓名/工号/场地" clearable v-model="pageForm.searchKeyword"
|
||||
@keyup.enter.native="doSearch">
|
||||
<search-item label="姓名/工号">
|
||||
<el-input
|
||||
v-model="pageForm.searchKeyword"
|
||||
placeholder="请输入姓名或工号"
|
||||
clearable
|
||||
@keyup.enter.native="doSearch">
|
||||
</el-input>
|
||||
</search-item>
|
||||
<search-item label="活动场地">
|
||||
<el-select v-model="pageForm.siteId" @change="doSearch" style="width: 100%"
|
||||
placeholder="请选择活动场地" filterable clearable>
|
||||
<el-option v-for="item in siteOptions"
|
||||
:value="item.id"
|
||||
:key="item.id"
|
||||
:label="item.name"></el-option>
|
||||
<el-select
|
||||
v-model="pageForm.siteId"
|
||||
@change="doSearch"
|
||||
style="width: 100%"
|
||||
placeholder="请选择活动场地"
|
||||
filterable
|
||||
clearable>
|
||||
<el-option
|
||||
v-for="item in siteOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="场地类型">
|
||||
<el-select v-model="pageForm.siteType" @change="doSearch" style="width: 100%"
|
||||
placeholder="请选择场地类型" filterable clearable>
|
||||
<el-option v-for="item in typeOptions"
|
||||
:value="item.id"
|
||||
:key="item.id"
|
||||
:label="item.name"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="预约类型">
|
||||
<el-select v-model="pageForm.reserveType" @change="doSearch" style="width: 100%"
|
||||
placeholder="请选择预约类型" clearable>
|
||||
<el-option label="分工会预约" value="union"></el-option>
|
||||
<el-option label="协会预约" value="club"></el-option>
|
||||
<el-select
|
||||
v-model="pageForm.siteType"
|
||||
@change="doSearch"
|
||||
style="width: 100%"
|
||||
placeholder="请选择场地类型"
|
||||
filterable
|
||||
clearable>
|
||||
<el-option
|
||||
v-for="item in typeOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="预约单位">
|
||||
<el-input placeholder="请输入分工会或协会名称" clearable v-model="pageForm.reserveTargetKeyword"
|
||||
@keyup.enter.native="doSearch">
|
||||
<el-input
|
||||
v-model="pageForm.reserveTargetKeyword"
|
||||
placeholder="请输入分工会或协会名称"
|
||||
clearable
|
||||
@keyup.enter.native="doSearch">
|
||||
</el-input>
|
||||
</search-item>
|
||||
<search-item label="预约开始时间">
|
||||
<el-date-picker v-model="pageForm.reserveTimeStart"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="请选择预约开始时间"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
@change="doSearch">
|
||||
<el-date-picker
|
||||
v-model="pageForm.reserveTimeStart"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="请选择预约开始时间"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
@change="doSearch">
|
||||
</el-date-picker>
|
||||
</search-item>
|
||||
<search-item label="预约结束时间">
|
||||
<el-date-picker v-model="pageForm.reserveTimeEnd"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="请选择预约结束时间"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
@change="doSearch">
|
||||
<el-date-picker
|
||||
v-model="pageForm.reserveTimeEnd"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="请选择预约结束时间"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
@change="doSearch">
|
||||
</el-date-picker>
|
||||
</search-item>
|
||||
</search>
|
||||
@@ -68,27 +115,47 @@ layout("/layouts/platform.html"){
|
||||
<table-tool label="申请列表">
|
||||
<el-button type="primary" size="small" @click="doExport">导出表格</el-button>
|
||||
</table-tool>
|
||||
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
|
||||
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"></el-table-column>
|
||||
<el-table
|
||||
:data="tableData"
|
||||
:row-class-name="tableRowClassName"
|
||||
@sort-change="pageOrder"
|
||||
style="width: 100%">
|
||||
<el-table-column label="" width="54" align="center" header-align="center">
|
||||
<template v-slot="{ row }">
|
||||
<el-button
|
||||
v-if="row._hasFoldChildren"
|
||||
class="record-batch-toggle"
|
||||
type="text"
|
||||
@click="toggleBatchGroup(row)">
|
||||
<i :class="row._expanded ? 'el-icon-caret-bottom' : 'el-icon-caret-right'"></i>
|
||||
</el-button>
|
||||
<span v-else class="record-batch-empty"></span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column type="index" width="50" label="序号" :index="indexMethod"></el-table-column>
|
||||
<el-table-column
|
||||
v-for="column in tableColumns"
|
||||
:key="column.prop"
|
||||
:label="column.label"
|
||||
:prop="column.prop"
|
||||
:key="column.prop"
|
||||
:width="column.width"
|
||||
:sortable="column.sortable"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
v-for="column in tableColumns">
|
||||
<template v-slot="{ row }" v-if="column.prop === 'reserveType'">
|
||||
<span>{{ row.reserveType === 'club' ? '协会预约' : '分工会预约' }}</span>
|
||||
show-overflow-tooltip>
|
||||
<template v-slot="{ row }" v-if="column.prop === 'siteName'">
|
||||
<span v-if="row._isBatchChild" class="record-batch-child-label">{{ row.siteName }}</span>
|
||||
<span v-else>{{ row.siteName }}</span>
|
||||
</template>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'reserveTargetName'">
|
||||
<span>{{ row.reserveType === 'club' ? (row.clubName || '-') : (row.applyUnionName || '-') }}</span>
|
||||
</template>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'yearlyBatch'">
|
||||
<span>{{ normalizeBatchFlag(row) ? '是' : '否' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="180">
|
||||
<template v-slot="{row}">
|
||||
<template v-slot="{ row }">
|
||||
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
|
||||
<el-button @click="onDelete(row.id)" size="mini" type="danger">删除</el-button>
|
||||
</template>
|
||||
@@ -111,7 +178,7 @@ layout("/layouts/platform.html"){
|
||||
store,
|
||||
mixins: [initTableMixins],
|
||||
components: {
|
||||
'info': siteCugApplyInfo,
|
||||
info: siteCugApplyInfo,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -126,19 +193,75 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
typeOptions: [],
|
||||
siteOptions: [],
|
||||
rawTableData: [],
|
||||
expandedBatchKeys: {},
|
||||
tableColumns: [
|
||||
{prop: 'siteName', label: '场地名称'},
|
||||
{prop: 'applyUserName', label: '预约人'},
|
||||
{prop: 'reserveType', label: '预约类型'},
|
||||
{prop: 'reserveTargetName', label: '预约单位'},
|
||||
{prop: 'applyUnitName', label: '所属单位'},
|
||||
{prop: 'reserveStartTime', label: '开始时间'},
|
||||
{prop: 'reserveEndTime', label: '结束时间'},
|
||||
{prop: 'applyMobile', label: '联系方式'},
|
||||
{ prop: 'siteName', label: '场地名称', sortable: 'custom' },
|
||||
{ prop: 'applyUserName', label: '预约人', sortable: 'custom' },
|
||||
{ prop: 'applyLoginName', label: '工号', sortable: 'custom' },
|
||||
{ prop: 'yearlyBatch', label: '是否批量预约', sortable: 'custom', width: 130 },
|
||||
{ prop: 'reserveTargetName', label: '预约单位', sortable: 'custom' },
|
||||
{ prop: 'reserveStartTime', label: '开始时间', sortable: 'custom' },
|
||||
{ prop: 'reserveEndTime', label: '结束时间', sortable: 'custom' },
|
||||
{ prop: 'applyMobile', label: '联系方式', sortable: 'custom' },
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
normalizeBatchFlag(row) {
|
||||
return row && (row.yearlyBatch === 1 || row.yearlyBatch === '1' || row.yearlyBatch === true)
|
||||
},
|
||||
getBatchGroupKey(row) {
|
||||
if (!this.normalizeBatchFlag(row)) {
|
||||
return 'single_' + row.id
|
||||
}
|
||||
const batchNo = row.backOption || row.id
|
||||
return 'batch_' + batchNo + '_' + (row.applyUserName || '') + '_' + (row.siteName || '')
|
||||
},
|
||||
buildTableData(rows) {
|
||||
const groups = new Map()
|
||||
;(rows || []).forEach(row => {
|
||||
const key = this.getBatchGroupKey(row)
|
||||
if (!groups.has(key)) {
|
||||
groups.set(key, [])
|
||||
}
|
||||
groups.get(key).push({ ...row })
|
||||
})
|
||||
const displayRows = []
|
||||
groups.forEach((groupRows, key) => {
|
||||
const sortedRows = groupRows.slice().sort((a, b) => {
|
||||
return (b.reserveStartTime || '').localeCompare(a.reserveStartTime || '')
|
||||
})
|
||||
const parent = { ...sortedRows[0] }
|
||||
const children = sortedRows.slice(1).map(item => ({
|
||||
...item,
|
||||
_isBatchChild: true,
|
||||
_groupKey: key,
|
||||
_hasFoldChildren: false,
|
||||
}))
|
||||
parent._groupKey = key
|
||||
parent._isBatchChild = false
|
||||
parent._hasFoldChildren = children.length > 0
|
||||
parent._expanded = !!this.expandedBatchKeys[key]
|
||||
parent._batchCount = sortedRows.length
|
||||
parent._foldedRecords = children
|
||||
displayRows.push(parent)
|
||||
if (parent._expanded) {
|
||||
displayRows.push(...children)
|
||||
}
|
||||
})
|
||||
return displayRows
|
||||
},
|
||||
tableRowClassName({ row }) {
|
||||
return row && row._isBatchChild ? 'record-batch-child-row' : ''
|
||||
},
|
||||
toggleBatchGroup(row) {
|
||||
if (!row || !row._groupKey || !row._hasFoldChildren) {
|
||||
return
|
||||
}
|
||||
this.$set(this.expandedBatchKeys, row._groupKey, !this.expandedBatchKeys[row._groupKey])
|
||||
this.tableData = this.buildTableData(this.rawTableData)
|
||||
},
|
||||
onView(row) {
|
||||
this.$refs.guava.edit(() => {
|
||||
this.$refs.infoRef.onOpen(row)
|
||||
@@ -148,7 +271,7 @@ layout("/layouts/platform.html"){
|
||||
this.$confirm('您确定要删除吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
this.$axios.post('/platform/siteCug/record/delete', { id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
@@ -158,7 +281,6 @@ layout("/layouts/platform.html"){
|
||||
})
|
||||
})
|
||||
},
|
||||
// 导出内容和列表当前筛选条件保持一致,实现所见即所得
|
||||
doExport() {
|
||||
this.$downLoad('/platform/siteCug/record/doExport', this.pageForm)
|
||||
},
|
||||
@@ -172,13 +294,21 @@ layout("/layouts/platform.html"){
|
||||
this.siteOptions = res.data
|
||||
})
|
||||
},
|
||||
pageData() {
|
||||
this.$axios.post(loc() + '/pageData', this.pageForm).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.rawTableData = Array.isArray(res.data.list) ? res.data.list : []
|
||||
this.tableData = this.buildTableData(this.rawTableData)
|
||||
this.pageForm.totalCount = res.data.totalCount
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// 查询字段在 data 中一次性声明完整,避免 Vue 2 对后加属性渲染不稳定
|
||||
this.querySiteType()
|
||||
this.querySites()
|
||||
this.pageData()
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
+190
-59
@@ -1,35 +1,81 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
<style>
|
||||
.audit-batch-toggle {
|
||||
padding: 0;
|
||||
color: #409EFF;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.audit-batch-empty {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.audit-batch-child-row {
|
||||
background: #fafcff;
|
||||
}
|
||||
|
||||
.audit-batch-child-label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #7a8a9a;
|
||||
}
|
||||
|
||||
.audit-batch-child-label::before {
|
||||
content: "";
|
||||
width: 16px;
|
||||
height: 1px;
|
||||
background: #c8d3df;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app">
|
||||
<guava ref="guava">
|
||||
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="姓名/工号/场地">
|
||||
<el-input placeholder="请输入姓名/工号/场地" clearable v-model="pageForm.searchKeyword"
|
||||
@keyup.enter.native="doSearch">
|
||||
<search-item label="姓名/工号">
|
||||
<el-input
|
||||
v-model="pageForm.searchKeyword"
|
||||
placeholder="请输入姓名或工号"
|
||||
clearable
|
||||
@keyup.enter.native="doSearch">
|
||||
</el-input>
|
||||
</search-item>
|
||||
<search-item label="活动场地">
|
||||
<el-select v-model="pageForm.siteId" @change="doSearch" style="width: 100%"
|
||||
placeholder="请选择活动场地" filterable clearable>
|
||||
<el-option v-for="item in siteOptions"
|
||||
:value="item.id"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
></el-option>
|
||||
<el-select
|
||||
v-model="pageForm.siteId"
|
||||
@change="doSearch"
|
||||
style="width: 100%"
|
||||
placeholder="请选择活动场地"
|
||||
filterable
|
||||
clearable>
|
||||
<el-option
|
||||
v-for="item in siteOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="场地类型">
|
||||
<el-select v-model="pageForm.siteType" @change="doSearch" style="width: 100%"
|
||||
placeholder="请选择场地类型" filterable clearable>
|
||||
<el-option v-for="item in typeOptions"
|
||||
:value="item.id"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
></el-option>
|
||||
<el-select
|
||||
v-model="pageForm.siteType"
|
||||
@change="doSearch"
|
||||
style="width: 100%"
|
||||
placeholder="请选择场地类型"
|
||||
filterable
|
||||
clearable>
|
||||
<el-option
|
||||
v-for="item in typeOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
</search>
|
||||
@@ -42,34 +88,53 @@ layout("/layouts/platform.html"){
|
||||
<el-radio-button :label="false">未审核</el-radio-button>
|
||||
</el-radio-group>
|
||||
</table-tool>
|
||||
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
|
||||
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"></el-table-column>
|
||||
<el-table
|
||||
:data="tableData"
|
||||
:row-class-name="tableRowClassName"
|
||||
@sort-change="pageOrder"
|
||||
style="width: 100%">
|
||||
<el-table-column label="" width="54" align="center" header-align="center">
|
||||
<template v-slot="{ row }">
|
||||
<el-button
|
||||
v-if="row._hasFoldChildren"
|
||||
class="audit-batch-toggle"
|
||||
type="text"
|
||||
@click="toggleBatchGroup(row)">
|
||||
<i :class="row._expanded ? 'el-icon-caret-bottom' : 'el-icon-caret-right'"></i>
|
||||
</el-button>
|
||||
<span v-else class="audit-batch-empty"></span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column type="index" width="50" label="序号" :index="indexMethod"></el-table-column>
|
||||
<el-table-column
|
||||
v-for="column in tableColumns"
|
||||
:key="column.prop"
|
||||
:label="column.label"
|
||||
:prop="column.prop"
|
||||
:key="column.prop"
|
||||
:width="column.width"
|
||||
:sortable="column.sortable"
|
||||
align="center"
|
||||
header-align="center"
|
||||
show-overflow-tooltip
|
||||
v-for="column in tableColumns"
|
||||
>
|
||||
<template v-slot="{ row }" v-if="column.prop === 'instanceState'">
|
||||
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message" size="small"></enum-tag>
|
||||
</template>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'reserveType'">
|
||||
<span>{{ row.reserveType === 'club' ? '协会预约' : '分工会预约' }}</span>
|
||||
show-overflow-tooltip>
|
||||
<template v-slot="{ row }" v-if="column.prop === 'siteName'">
|
||||
<span v-if="row._isBatchChild" class="audit-batch-child-label">{{ row.siteName }}</span>
|
||||
<span v-else>{{ row.siteName }}</span>
|
||||
</template>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'reserveTargetName'">
|
||||
<span>{{ row.reserveType === 'club' ? (row.clubName || '-') : (row.applyUnionName || '-') }}</span>
|
||||
</template>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'yearlyBatch'">
|
||||
<span>{{ normalizeBatchFlag(row) ? '是' : '否' }}</span>
|
||||
</template>
|
||||
<template v-slot="{ row }" v-else-if="column.prop === 'instanceState'">
|
||||
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message" size="small"></enum-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" fixed="right" width="300px">
|
||||
<template v-slot="{row}">
|
||||
<el-table-column label="操作" fixed="right" width="220">
|
||||
<template v-slot="{ row }">
|
||||
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
|
||||
<el-button v-if="row.taskState === 10" @click="onAudit(row)" size="mini" type="primary">审核</el-button>
|
||||
<el-button v-if="canRevoke(row)" :loading="revokeLoading" :disabled="revokeLoading" @click="onRevoke(row)" size="mini" type="danger">撤回</el-button>
|
||||
<el-button v-if="!row._isBatchChild && row.taskState === 10" @click="onAudit(row)" size="mini" type="primary">审核</el-button>
|
||||
<el-button v-if="!row._isBatchChild && canRevoke(row)" :loading="revokeLoading" :disabled="revokeLoading" @click="onRevoke(row)" size="mini" type="danger">撤回</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -80,12 +145,13 @@ layout("/layouts/platform.html"){
|
||||
<info ref="infoRef">
|
||||
<div v-if="showApprovalForm">
|
||||
<div class="process-title">
|
||||
{{formData.taskName}}
|
||||
{{ formData.taskName }}
|
||||
</div>
|
||||
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":"
|
||||
class="flow-task-form">
|
||||
<el-form-item label="审批意见" prop="tf_opinion"
|
||||
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
||||
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" class="flow-task-form">
|
||||
<el-form-item
|
||||
label="审批意见"
|
||||
prop="tf_opinion"
|
||||
:rules="[{ required: true, message: '必填', trigger: ['change', 'blur'] }]">
|
||||
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -105,28 +171,30 @@ layout("/layouts/platform.html"){
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include('../common/applyInfo.js'){}#-->
|
||||
new Vue({
|
||||
el: "#app",
|
||||
el: '#app',
|
||||
store,
|
||||
mixins: [initTableMixins],
|
||||
components: {
|
||||
"info": siteCugApplyInfo,
|
||||
info: siteCugApplyInfo,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
approval: false
|
||||
approval: false,
|
||||
},
|
||||
rawTableData: [],
|
||||
expandedBatchKeys: {},
|
||||
tableColumns: [
|
||||
{prop: 'siteName', label: '场地名称'},
|
||||
{prop: 'applyUserName', label: '预约人'},
|
||||
{prop: 'reserveType', label: '预约类型'},
|
||||
{prop: 'reserveTargetName', label: '预约单位'},
|
||||
{prop: 'applyUnitName', label: '所属单位'},
|
||||
{prop: 'reserveStartTime', label: '开始时间'},
|
||||
{prop: 'reserveEndTime', label: '结束时间'},
|
||||
{prop: 'applyMobile', label: '联系方式'},
|
||||
{prop: 'curTaskName', label: '当前节点'},
|
||||
{prop: 'instanceState', label: '流程状态'},
|
||||
{ prop: 'siteName', label: '场地名称', sortable: 'custom' },
|
||||
{ prop: 'applyUserName', label: '预约人', sortable: 'custom' },
|
||||
{ prop: 'applyLoginName', label: '工号', sortable: 'custom' },
|
||||
{ prop: 'yearlyBatch', label: '是否批量预约', sortable: 'custom', width: 130 },
|
||||
{ prop: 'reserveTargetName', label: '预约单位', sortable: 'custom' },
|
||||
{ prop: 'reserveStartTime', label: '开始时间', sortable: 'custom' },
|
||||
{ prop: 'reserveEndTime', label: '结束时间', sortable: 'custom' },
|
||||
{ prop: 'applyMobile', label: '联系方式', sortable: 'custom' },
|
||||
{ prop: 'curTaskName', label: '当前节点', sortable: 'custom' },
|
||||
{ prop: 'instanceState', label: '流程状态', sortable: 'custom', width: 120 },
|
||||
],
|
||||
typeOptions: [],
|
||||
siteOptions: [],
|
||||
@@ -138,6 +206,60 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
normalizeBatchFlag(row) {
|
||||
return row && (row.yearlyBatch === 1 || row.yearlyBatch === '1' || row.yearlyBatch === true)
|
||||
},
|
||||
getBatchGroupKey(row) {
|
||||
if (!this.normalizeBatchFlag(row)) {
|
||||
return 'single_' + row.id
|
||||
}
|
||||
const batchNo = row.backOption || row.id
|
||||
return 'batch_' + batchNo + '_' + (row.applyUserName || '') + '_' + (row.siteName || '')
|
||||
},
|
||||
buildTableData(rows) {
|
||||
const groups = new Map()
|
||||
;(rows || []).forEach(row => {
|
||||
const key = this.getBatchGroupKey(row)
|
||||
if (!groups.has(key)) {
|
||||
groups.set(key, [])
|
||||
}
|
||||
groups.get(key).push({ ...row })
|
||||
})
|
||||
const displayRows = []
|
||||
groups.forEach((groupRows, key) => {
|
||||
const sortedRows = groupRows.slice().sort((a, b) => {
|
||||
return (b.reserveStartTime || '').localeCompare(a.reserveStartTime || '')
|
||||
})
|
||||
const parent = { ...sortedRows[0] }
|
||||
const children = sortedRows.slice(1).map(item => ({
|
||||
...item,
|
||||
_isBatchChild: true,
|
||||
_groupKey: key,
|
||||
_hasFoldChildren: false,
|
||||
}))
|
||||
parent._groupKey = key
|
||||
parent._isBatchChild = false
|
||||
parent._hasFoldChildren = children.length > 0
|
||||
parent._expanded = !!this.expandedBatchKeys[key]
|
||||
parent._batchCount = sortedRows.length
|
||||
parent._foldedRecords = children
|
||||
displayRows.push(parent)
|
||||
if (parent._expanded) {
|
||||
displayRows.push(...children)
|
||||
}
|
||||
})
|
||||
return displayRows
|
||||
},
|
||||
tableRowClassName({ row }) {
|
||||
return row && row._isBatchChild ? 'audit-batch-child-row' : ''
|
||||
},
|
||||
toggleBatchGroup(row) {
|
||||
if (!row || !row._groupKey || !row._hasFoldChildren) {
|
||||
return
|
||||
}
|
||||
this.$set(this.expandedBatchKeys, row._groupKey, !this.expandedBatchKeys[row._groupKey])
|
||||
this.tableData = this.buildTableData(this.rawTableData)
|
||||
},
|
||||
canRevoke(row) {
|
||||
return Number(row.instanceState) === 20
|
||||
},
|
||||
@@ -156,7 +278,7 @@ layout("/layouts/platform.html"){
|
||||
taskName: row.curTaskName,
|
||||
tf_opinion: '',
|
||||
yearlyBatch: row.yearlyBatch,
|
||||
batchAuditCount: row.batchAuditCount,
|
||||
batchAuditCount: row.batchAuditCount || row._batchCount,
|
||||
}
|
||||
this.$refs.infoRef.onOpen(row)
|
||||
})
|
||||
@@ -171,14 +293,14 @@ layout("/layouts/platform.html"){
|
||||
this.$confirm(message, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
type: 'warning',
|
||||
}).then(() => {
|
||||
this.auditLoading = true
|
||||
this.$axios.post('/platform/siteCug/schoolUnionAudit/executeTask', {
|
||||
data: JSON.stringify({
|
||||
...this.formData,
|
||||
submitType: val
|
||||
})
|
||||
submitType: val,
|
||||
}),
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$refs.guava.index()
|
||||
@@ -194,13 +316,13 @@ layout("/layouts/platform.html"){
|
||||
if (!this.canRevoke(row) || this.revokeLoading) {
|
||||
return
|
||||
}
|
||||
const message = row.yearlyBatch
|
||||
? ('该记录属于“预约本年”批量预约,撤回后将一并撤回同批次的 ' + (row.batchAuditCount || 0) + ' 条审核任务,是否继续?')
|
||||
const message = this.normalizeBatchFlag(row)
|
||||
? ('该记录属于“预约本年”批量预约,撤回后将一并撤回同批次的 ' + (row.batchAuditCount || row._batchCount || 0) + ' 条审核任务,是否继续?')
|
||||
: '您确定要撤回吗?'
|
||||
this.$confirm(message, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'info'
|
||||
type: 'info',
|
||||
}).then(() => {
|
||||
this.revokeLoading = true
|
||||
this.$axios.post('/platform/siteCug/schoolUnionAudit/revokeTask', { taskId: row.taskId, applyId: row.id }).then((res) => {
|
||||
@@ -223,12 +345,21 @@ layout("/layouts/platform.html"){
|
||||
this.siteOptions = res.data
|
||||
})
|
||||
},
|
||||
pageData() {
|
||||
this.$axios.post(loc() + '/pageData', this.pageForm).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.rawTableData = Array.isArray(res.data.list) ? res.data.list : []
|
||||
this.tableData = this.buildTableData(this.rawTableData)
|
||||
this.pageForm.totalCount = res.data.totalCount
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
created() {
|
||||
this.querySiteType()
|
||||
this.querySites()
|
||||
this.pageData()
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
+671
-579
File diff suppressed because it is too large
Load Diff
+490
-74
@@ -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"){
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
#-->
|
||||
Reference in New Issue
Block a user