Browse Source

微信小程序-预约/活动

master
xuhuajiao 2 weeks ago
parent
commit
958e05b1fb
  1. 603
      src/views/weChatMiniProgram/activity.vue
  2. 156
      src/views/weChatMiniProgram/activityLog.vue
  3. 296
      src/views/weChatMiniProgram/reservation.vue
  4. 140
      src/views/weChatMiniProgram/reservationLog.vue

603
src/views/weChatMiniProgram/activity.vue

@ -0,0 +1,603 @@
<template>
<div class="app-container row-container" style="height: calc(100vh - 140px);">
<!--工具栏-->
<div class="head-container">
<crudOperation :permission="permission">
<template v-slot:middle>
<el-button slot="reference" size="mini" :loading="crud.delAllLoading" :disabled="crud.selections.length === 0" @click="toDelete(crud.selections)">
<i class="iconfont icon-shanchu" />
删除
</el-button>
</template>
</crudOperation>
</div>
<!--表单渲染-->
<el-dialog class="activity-form" append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title">
<!-- label-position="top" -->
<div class="setting-dialog">
<el-form ref="form" label-position="top" :inline="true" :model="form" :rules="rules" size="small" label-width="90px">
<div style="display: flex; justify-content: space-around; ">
<div style="width: 600px; margin: 0 10px; ">
<el-row>
<el-form-item label="活动标题" prop="title">
<el-input v-model="form.title" placeholder="请输入" style="width: 500px;" />
</el-form-item>
</el-row>
<el-row>
<el-form-item label="开始时间" prop="startTime">
<el-date-picker
v-model="form.startTime"
type="datetime"
placeholder="选择日期时间"
format="yyyy-MM-dd HH:mm:ss"
value-format="yyyy-MM-dd HH:mm:ss"
:picker-options="{
disabledDate: (time) =>{
return time.getTime() < Date.now() - 8.64e7
}
}"
/>
</el-form-item>
<el-form-item label="结束时间" prop="endTime">
<el-date-picker
v-model="form.endTime"
type="datetime"
placeholder="选择日期时间"
:picker-options="endPickerOptions"
format="yyyy-MM-dd HH:mm:ss"
value-format="yyyy-MM-dd HH:mm:ss"
default-time="['23:59:59']"
/>
</el-form-item>
</el-row>
<el-form-item class="activity-number" label="活动人数" prop="numberLimit">
<el-radio-group v-model="form.numberLimit" v-removeAriaHidden @change="handleNumberLimitChange">
<el-radio :label="1">不限制</el-radio>
<el-radio :label="2">限制</el-radio>
</el-radio-group>
<el-input v-if="form.numberLimit === 2" v-model="form.number" type="number" placeholder="请输入" @blur="validateNumber" />
</el-form-item>
<el-row>
<el-form-item label="活动地点" prop="address">
<el-input v-model="form.address" placeholder="请输入" style="width: 500px;" />
</el-form-item>
</el-row>
<el-row>
<el-form-item label="活动封面" prop="imgPath">
<div class="activity-upload">
<img v-if="form.imgPath" :src="`${baseApi}/api/fileRelevant/getImg?imgType=2&imgId=${form.imgPath}`" class="upload-preview">
<div v-else class="upload-preview-placeholder">
<img :src="require('@/assets/images/system/default-img.jpg')" class="placeholder-img">
</div>
<el-upload
class="upload-btn-box"
:action="baseApi + '/api/fileRelevant/uploadBookImg'"
:show-file-list="false"
:on-success="handleImgUploadSuccess"
:before-upload="beforeImgUpload"
:headers="uploadHeaders"
>
<div class="upload-btn-inner">
<i class="el-icon-plus" />
</div>
</el-upload>
</div>
</el-form-item>
</el-row>
</div>
<quill-editor
v-model="editorContent"
style="width: 800px;"
:editor-content="editorContent"
:editor-ref="editorRef"
@contentData="contentData"
/>
</div>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="text" @click="crud.cancelCU">取消</el-button>
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button>
</div>
</div>
</el-dialog>
<el-dialog
title="取消活动"
:visible.sync="cancelDialogVisible"
width="600px"
class="closed-dialog"
append-to-body
:close-on-click-modal="false"
>
<el-form ref="cancelForm" :inline="true" :rules="cancelRules" :model="cancelForm">
<el-form-item label="活动名称">
<span>{{ cancelForm.title }}</span>
</el-form-item>
<el-form-item label="取消原因" prop="reason">
<el-input
v-model="cancelForm.reason"
type="textarea"
:rows="5"
placeholder="请输入取消活动的原因"
style="width: 480px;"
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer" style="margin-top: 20px;">
<el-button @click="cancelDialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirmCancel">确认</el-button>
</div>
</el-dialog>
<!--表格渲染-->
<div class="container-wrap">
<span class="right-top-line" />
<span class="left-bottom-line" />
<el-table
ref="table"
v-loading="crud.loading"
class="archives-table"
height="calc(100vh - 330px)"
:data="crud.data"
@selection-change="crud.selectionChangeHandler"
@row-click="clickRowHandler"
>
<el-table-column type="selection" align="center" width="55" />
<el-table-column prop="icon" label="封面" align="center">
<template slot-scope="scope">
<img
style="height:80px;display:block;margin:0 auto;"
:src="scope.row.imgPath ? `${baseApi}/api/fileRelevant/getImg?imgType=2&imgId=${scope.row.imgPath}` : require('@/assets/images/system/default-img.jpg')"
alt="封面"
>
</template>
</el-table-column>
<!-- width="260" :show-overflow-tooltip="true" -->
<el-table-column label="标题" prop="title" />
<el-table-column prop="startTime" label="开始时间" />
<el-table-column prop="endTime" label="结束时间" />
<el-table-column prop="number" label="活动人数">
<template slot-scope="scope">
{{ scope.row.number || '不限制' }}
</template>
</el-table-column>
<el-table-column prop="gridName" label="实约人数">
<template slot-scope="scope">
{{ scope.row.gridName || '-' }}
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="100" align="center">
<template slot-scope="scope">
<!-- <span :class="getStatusClass(scope.row.status)">{{ getStatusText(scope.row.status) }}</span> -->
<!-- 未开始 -->
<span v-if="scope.row.status === 0" class="row-state row-physical state-active">{{ getStatusText(scope.row.status) }}</span>
<!-- 进行中 -->
<span v-if="scope.row.status === 1" class="row-state row-binding state-active">{{ getStatusText(scope.row.status) }}</span>
<!-- 已结束 -->
<span v-if="scope.row.status === 2" class="row-state">{{ getStatusText(scope.row.status) }}</span>
<!-- 手动取消 -->
<span v-if="scope.row.status === 3" class="row-state row-lending state-active">{{ getStatusText(scope.row.status) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="100" align="center">
<template slot-scope="scope">
<el-button
v-if="scope.row.status === 0 || scope.row.status === 1"
style="padding: 7px !important;"
icon="el-icon-circle-close"
@click="showCancelDialog(scope.row)"
>取消</el-button>
<el-button
v-else-if="scope.row.status === 3 && canRestore(scope.row)"
style="padding: 7px !important;"
type="success"
icon="el-icon-refresh"
@click="restoreActivity(scope.row)"
>恢复</el-button>
</template>
</el-table-column>
<el-table-column prop="create_time" label="创建日期" width="160">
<template slot-scope="scope">
<div>{{ scope.row.create_time | parseTime }}</div>
</template>
</el-table-column>
</el-table>
<!--分页组件-->
<pagination v-if="crud.data.length!==0" />
</div>
</div>
</template>
<script>
import crudWeChat from '@/api/digitalScreen/index'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import CRUD, { presenter, header, form, crud } from '@crud/crud'
import crudOperation from '@crud/CRUD.operation'
import pagination from '@crud/Pagination'
import { mapGetters } from 'vuex'
import QuillEditor from '@/components/quillEditor/index.vue'
import { getToken } from '@/utils/auth'
const defaultForm = { id: null, title: null, startTime: null, endTime: null, number: null, numberLimit: 1, address: null, imgPath: null }
export default {
name: 'Activity',
components: { crudOperation, pagination, QuillEditor },
cruds() {
return CRUD({ title: '活动', url: 'api/screenSetting/initScreenBookRecommend2', crudMethod: { ...crudWeChat },
optShow: {
add: true,
edit: true,
del: false,
download: false,
group: false,
reset: false
}
})
},
mixins: [presenter(), header(), form(defaultForm), crud()],
data() {
return {
permission: { add: [], edit: [], del: [] },
imageUrl: require('@/assets/images/system/default-img.jpg'),
editorRef: 'test',
editorContent: '',
cancelDialogVisible: false,
cancelForm: {
title: '',
reason: '',
row: null
},
rules: {
title: [
{ required: true, message: '请输入活动标题', trigger: 'blur' }
],
startTime: [
{ required: true, message: '请选择开始时间', trigger: 'change' }
],
endTime: [
{
required: true,
validator: (rule, value, callback) => {
if (!value) {
callback(new Error('请选择结束时间'))
} else if (this.form.startTime > value) {
callback(new Error('开始时间不得大于结束时间'))
} else {
callback()
}
},
trigger: 'change'
}
],
numberLimit: [
{
validator: (rule, value, callback) => {
if (value === 2 && (!this.form.number || this.form.number.toString().trim() === '')) {
callback(new Error('请输入活动人数'))
} else {
callback()
}
},
trigger: ['blur', 'change']
}
],
address: [
{ required: true, message: '请输入活动地点', trigger: 'blur' }
],
imgPath: [
{ required: true, message: '请上传活动封面', trigger: 'change' }
]
},
cancelRules: {
reason: [
{ required: true, message: '请输入取消原因', trigger: 'blur' }
]
},
endPickerOptions: {
disabledDate: (time) => {
const startTime = new Date(this.form.startTime).getTime()
if (startTime) {
return (time.getTime()) <= startTime - 8.64e7
} else {
return time.getTime() < Date.now() - 8.64e7
}
}
}
}
},
computed: {
...mapGetters([
'baseApi',
'user'
]),
uploadHeaders() {
return { Authorization: getToken() }
}
},
methods: {
[CRUD.HOOK.beforeRefresh]() {
this.crud.params.libcode = this.user.fonds.fondsNo
const mockData = [
{
id: 1,
imgPath: null,
title: '读书分享会',
startTime: '2026-01-15 14:00',
endTime: '2026-01-15 16:00',
number: null,
gridName: 45,
status: 1,
create_time: '2026-01-10 10:00:00'
},
{
id: 2,
imgPath: null,
title: '新书发布会',
startTime: '2026-01-20 10:00',
endTime: '2026-01-20 12:00',
number: 100,
gridName: 88,
status: 0,
create_time: '2026-01-12 14:30:00'
},
{
id: 3,
imgPath: null,
title: '作家见面会',
startTime: '2026-01-05 10:00',
endTime: '2026-01-05 12:00',
number: 80,
gridName: 75,
status: 2,
create_time: '2026-01-01 09:00:00'
},
{
id: 4,
imgPath: null,
title: '亲子阅读活动',
startTime: '2026-07-16 14:00',
endTime: '2026-07-30 16:00',
number: 60,
gridName: 30,
status: 3,
create_time: '2026-01-14 11:00:00'
}
]
this.crud.data = mockData
this.crud.loading = false
return false
},
//
[CRUD.HOOK.afterToCU](crud, form) {
},
//
[CRUD.HOOK.beforeToAdd]() {
},
//
[CRUD.HOOK.beforeToEdit](crud, form) {
console.log('crud', crud.form)
form.numberLimit = form.number === null ? 1 : 2
},
//
[CRUD.HOOK.afterValidateCU](crud) {
console.log(crud.form)
if (crud.form.numberLimit === 1) {
crud.form.number = null
}
delete crud.form.numberLimit
return false
},
validateNumber() {
this.$refs.form.validateField('numberLimit')
},
handleNumberLimitChange(val) {
if (val === 1) {
this.$refs.form.clearValidate('numberLimit')
}
},
handleImgUploadSuccess(res) {
if (res.code === 200) {
this.form.imgPath = res.data
this.$message({ message: '上传成功', type: 'success', offset: 8 })
} else {
this.$message({ message: res.message || '上传失败', type: 'error', offset: 8 })
}
},
beforeImgUpload(file) {
const isImage = file.type.startsWith('image/')
if (!isImage) {
this.$message({ message: '只可上传图片', type: 'error', offset: 8 })
}
const isLt2M = file.size / 1024 / 1024 < 2
if (!isLt2M) {
this.$message({ message: '图片大小不能超过2MB', type: 'error', offset: 8 })
}
return isImage && isLt2M
},
contentData(val) {
console.log('contentData', val)
this.editorContent = val
},
getStatusText(status) {
const statusMap = {
0: '未开始',
1: '进行中',
2: '已结束',
3: '已取消'
}
return statusMap[status] || '未知'
},
getStatusClass(status) {
const classMap = {
0: 'status-pending',
1: 'status-active',
2: 'status-ended',
3: 'status-canceled'
}
return classMap[status] || 'status-default'
},
canRestore(row) {
const now = new Date().getTime()
const startTime = new Date(row.startTime).getTime()
const endTime = new Date(row.endTime).getTime()
const threeDays = 3 * 24 * 60 * 60 * 1000
return (now < startTime) || (now >= startTime && now <= endTime && endTime - now >= threeDays)
},
restoreActivity(row) {
const now = new Date().getTime()
const startTime = new Date(row.startTime).getTime()
row.status = now < startTime ? 0 : 1
this.$message({ message: '活动已恢复', type: 'success', offset: 8 })
},
showCancelDialog(row) {
this.cancelForm.title = row.title
this.cancelForm.reason = ''
this.cancelForm.row = row
this.cancelDialogVisible = true
},
confirmCancel() {
// if (!this.cancelForm.reason.trim()) {
// this.$message({ message: '', type: 'error', offset: 8 })
// return
// }
//
this.$refs.cancelForm.validate((valid) => {
if (valid) {
this.cancelForm.row.status = 3
this.cancelDialogVisible = false
this.$message({ message: '活动已取消', type: 'success', offset: 8 })
} else {
console.log('校验失败')
}
})
},
toDelete(datas) {
this.$confirm('此操作将删除当前所选活动<span>你是否还要继续?</span>', '提示', {
confirmButtonText: '继续',
cancelButtonText: '取消',
type: 'warning',
dangerouslyUseHTMLString: true
}).then(() => {
this.crud.delAllLoading = true
const ids = []
datas.forEach(val => {
ids.push(val.id)
})
// crudCollBook.del(ids).then(() => {
// this.$message({ message: '', type: 'success', offset: 8 })
// this.crud.delAllLoading = false
// this.crud.refresh()
// }).catch(err => {
// this.crud.delAllLoading = false
// console.log(err)
// })
}).catch(() => {
})
},
clickRowHandler(row) {
this.$refs.table.clearSelection()
this.$refs.table.toggleRowSelection(row)
}
}
}
</script>
<style lang="scss" scoped>
.activity-form{
::v-deep .el-dialog{
width: 1300px;
.activity-number{
width: 380px;
margin-right: 0 !important;
.el-form-item__content{
display: flex;
justify-content: flex-start;
.el-radio-group{
display: flex;
justify-content: flex-start;
align-items: center;
margin-right: 20px;
}
.el-input__inner{
width: 140px;
}
}
}
.ql-container{
height: 480px !important;
}
.dialog-footer{
margin-top: 10px;
}
}
}
.activity-upload{
display: flex;
align-items: center;
width: 500px;
gap: 16px;
.upload-preview{
width: 300px;
height: 150px;
display: block;
object-fit: cover;
// border: 1px solid #e6e8ed;
border-radius: 4px;
}
.upload-preview-placeholder{
width: 300px;
height: 150px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
// background-color: #fafafa;
overflow: hidden;
.placeholder-img{
width: 100%;
height: 100%;
display: block;
object-fit: contain;
}
}
.upload-btn-box{
width: 100px;
height: 100px;
border: 2px dashed #d9d9d9;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: border-color 0.3s;
&:hover{
border-color: #409EFF;
}
::v-deep .el-upload{
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.upload-btn-inner{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
cursor: pointer;
i{
font-size: 28px;
color: #8c939d;
}
}
}
}
.closed-dialog{
::v-deep .el-dialog__footer{
padding: 0 0 20px 0;
}
}
</style>

156
src/views/weChatMiniProgram/activityLog.vue

@ -0,0 +1,156 @@
<template>
<div class="app-container row-container" style="height: calc(100vh - 140px);">
<!--工具栏-->
<div class="head-container">
<div class="head-search">
<!-- 搜索 -->
<el-select v-model="query.status" clearable size="small" placeholder="状态" class="filter-item" style="width: 100px" @change="crud.toQuery">
<i slot="prefix" class="iconfont icon-zhuangtai" />
<el-option v-for="item in statusOptions" :key="item.key" :label="item.display_name" :value="item.key" />
</el-select>
<el-input v-model="query.search" clearable size="small" placeholder="输入检索条件检索" prefix-icon="el-icon-search" style="width: 220px;" class="filter-item" @clear="crud.toQuery" @keyup.enter.native="crud.toQuery" />
<rrOperation />
</div>
<!-- <crudOperation :permission="permission" /> -->
</div>
<!--表格渲染-->
<div class="container-wrap">
<span class="right-top-line" />
<span class="left-bottom-line" />
<el-table
ref="table"
v-loading="crud.loading"
class="archives-table"
height="calc(100vh - 330px)"
:data="crud.data"
@selection-change="crud.selectionChangeHandler"
@row-click="clickRowHandler"
>
<el-table-column type="selection" align="center" width="55" />
<!-- <el-table-column prop="icon" label="封面" align="center">
<template slot-scope="scope">
<img
style="height:80px;display:block;margin:0 auto;"
:src="scope.row.imgPath ? `${baseApi}/api/fileRelevant/getImg?imgType=2&imgId=${scope.row.imgPath}` : require('@/assets/images/system/default-img.jpg')"
alt="封面"
>
</template>
</el-table-column> -->
<!-- width="260" :show-overflow-tooltip="true" -->
<el-table-column label="活动标题" prop="title" />
<el-table-column prop="readCardNo" label="读者证号" />
<el-table-column prop="readName" label="读者昵称" />
<el-table-column prop="name" label="姓名" />
<el-table-column prop="contact" label="联系方式" />
<el-table-column prop="number" label="参加人数">
<template slot-scope="scope">
{{ scope.row.number || '不限制' }}
</template>
</el-table-column>
<el-table-column prop="status" label="预约状态" width="100" align="center">
<template slot-scope="scope">
<span v-if="scope.row.status === 0" class="row-state row-lending state-active">已取消</span>
</template>
</el-table-column>
<el-table-column prop="create_time" label="预约日期" width="160">
<template slot-scope="scope">
<div>{{ scope.row.create_time | parseTime }}</div>
</template>
</el-table-column>
</el-table>
<!--分页组件-->
<pagination v-if="crud.data.length!==0" />
</div>
</div>
</template>
<script>
import crudWeChat from '@/api/digitalScreen/index'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import CRUD, { presenter, header, form, crud } from '@crud/crud'
// import crudOperation from '@crud/CRUD.operation'
import rrOperation from '@crud/RR.operation'
import pagination from '@crud/Pagination'
import { mapGetters } from 'vuex'
const defaultForm = { }
export default {
name: 'ActivityLog',
components: { rrOperation, pagination },
cruds() {
return CRUD({ title: '活动预约', url: 'api/screenSetting/initScreenBookRecommend2', crudMethod: { ...crudWeChat },
optShow: {
add: false,
edit: false,
del: false,
download: false,
group: false,
reset: true
}
})
},
mixins: [presenter(), header(), form(defaultForm), crud()],
data() {
return {
statusOptions: [
{ key: 1, display_name: '进行中' },
{ key: 0, display_name: '已取消' }
],
permission: { add: [], edit: [], del: [] }
}
},
computed: {
...mapGetters([
'baseApi',
'user'
])
},
methods: {
[CRUD.HOOK.beforeRefresh]() {
this.crud.params.libcode = this.user.fonds.fondsNo
const mockData = [
{
id: 1,
name: '张三',
contact: '13800000000',
title: '读书分享会',
number: 4,
status: 1,
create_time: '2026-01-10 10:00:00'
},
{
id: 2,
name: '李四',
contact: '13800000001',
title: '新书发布会',
number: 1,
status: 0,
create_time: '2026-01-12 14:30:00'
}
]
this.crud.data = mockData
this.crud.loading = false
},
//
[CRUD.HOOK.afterToCU](crud, form) {
},
//
[CRUD.HOOK.beforeToAdd]() {
},
//
[CRUD.HOOK.beforeToEdit](crud, form) {
console.log('crud', crud.form)
},
//
[CRUD.HOOK.afterValidateCU](crud) {
},
clickRowHandler(row) {
this.$refs.table.clearSelection()
this.$refs.table.toggleRowSelection(row)
}
}
}
</script>
<style lang="scss" scoped>
</style>

296
src/views/weChatMiniProgram/reservation.vue

@ -0,0 +1,296 @@
<template>
<div class="app-container">
<el-card class="reservation-card">
<div slot="header">
<span>预约设置</span>
</div>
<div class="reservation-form">
<div class="frequency-item">
<span class="label">预约时间设置频率</span>
<el-select v-model="frequency" placeholder="请选择频率">
<el-option label="7天" value="7" />
<el-option label="15天" value="15" />
<el-option label="30天" value="30" />
</el-select>
</div>
<div class="week-list">
<div v-for="day in weekDays" :key="day.id" class="week-item">
<label class="week-checkbox">
<el-checkbox v-model="day.checked" />
<span>{{ day.name }}</span>
</label>
<div class="time-container">
<div class="time-list">
<el-tag
v-for="(time, index) in day.times"
:key="index"
closable
@close="removeTime(day, index)"
>
{{ time }}
</el-tag>
</div>
<div class="time-picker-container">
<el-time-picker
v-if="day.showPicker"
v-model="day.newTime"
is-range
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
placeholder="选择时间范围"
value-format="HH:mm"
style="width: 220px;"
@change="selectTime(day)"
@blur="day.showPicker = false"
/>
<i
v-if="day.checked"
class="el-icon-circle-plus-outline add-time-icon"
@click="addTime(day)"
/>
</div>
</div>
</div>
</div>
</div>
</el-card>
<el-card class="reservation-card">
<div slot="header" style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
<span>临时闭馆设置</span>
<el-button size="mini" @click="closedDialogVisible = true">
<i class="iconfont icon-xinzeng" />
新增
</el-button>
</div>
<div style="padding: 20px;">
<el-table ref="table" v-loading="closedLoading" highlight-current-row style="width: 100%;" height="calc(100vh - 234px)" :data="closedTableData">
<el-table-column prop="closeTime" label="闭馆日期" width="160px">
<template slot-scope="scope">
<div>{{ scope.row.closeTime | parseTime }}</div>
</template>
</el-table-column>
<el-table-column prop="phone" label="闭馆公告" />
</el-table>
</div>
</el-card>
<el-dialog
title="新增临时闭馆"
class="closed-dialog"
:visible.sync="closedDialogVisible"
width="600px"
append-to-body
:close-on-click-modal="false"
:before-close="beforeClose"
>
<el-form ref="closedForm" :inline="true" :model="closedForm" :rules="rules">
<el-form-item label="闭馆日期" prop="closeTime">
<el-date-picker
v-model="closedForm.closeTime"
type="date"
placeholder="选择日期"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
/>
</el-form-item>
<el-form-item label="闭馆公告" prop="reason">
<el-input
v-model="closedForm.reason"
type="textarea"
:rows="5"
placeholder="请输入闭馆公告"
style="width: 480px;"
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer" style="margin-top: 20px;">
<el-button @click="beforeClose">取消</el-button>
<el-button type="primary" @click="confirmAdd">确认</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: 'Reservation',
components: { },
data() {
return {
frequency: '7',
weekDays: [
{ id: 1, name: '周一', checked: false, times: [], showPicker: false, newTime: '' },
{ id: 2, name: '周二', checked: false, times: [], showPicker: false, newTime: '' },
{ id: 3, name: '周三', checked: false, times: [], showPicker: false, newTime: '' },
{ id: 4, name: '周四', checked: false, times: [], showPicker: false, newTime: '' },
{ id: 5, name: '周五', checked: false, times: [], showPicker: false, newTime: '' },
{ id: 6, name: '周六', checked: false, times: [], showPicker: false, newTime: '' },
{ id: 7, name: '周日', checked: false, times: [], showPicker: false, newTime: '' }
],
closedTableData: [],
closedLoading: false,
closedDialogVisible: false,
closedForm: {
closeTime: '',
reason: ''
},
rules: {
closeTime: [{ required: true, message: '请选择闭馆日期', trigger: 'blur' }],
reason: [{ required: true, message: '请输入闭馆公告', trigger: 'blur' }]
}
}
},
computed: {
...mapGetters([
'baseApi',
'user'
])
},
methods: {
addTime(day) {
day.showPicker = true
},
selectTime(day) {
if (day.newTime && day.newTime.length === 2) {
const startStr = day.newTime[0]
const endStr = day.newTime[1]
day.times.push(`${startStr} - ${endStr}`)
day.newTime = ''
day.showPicker = false
}
},
removeTime(day, index) {
day.times.splice(index, 1)
},
confirmAdd() {
this.$refs.closedForm.validate((valid) => {
if (valid) {
console.log(this.closedForm)
// this.$refs.closedForm.resetFields()
this.closedDialogVisible = false
} else {
console.log('校验失败')
}
})
},
beforeClose() {
this.$refs.closedForm.resetFields()
this.closedDialogVisible = false
}
}
}
</script>
<style lang="scss" scoped>
.app-container{
display: flex;
justify-content: space-between;
height: calc(100vh - 140px);
}
.reservation-card{
width: 49%;
}
::v-deep .el-card__header {
display: flex;
justify-content: space-between;
align-items: center;
color: #0c0e1e;
border-bottom: 1px solid #edeff3;
background-color: #fff;
line-height: 40px;
padding: 6px 14px;
}
.reservation-form {
padding: 16px;
}
.frequency-item {
display: flex;
align-items: center;
margin-bottom: 16px;
.label {
margin-right: 16px;
}
.el-select {
width: 150px;
}
}
.week-list {
border: 1px solid #ebeef5;
border-radius: 4px;
}
.week-item {
display: flex;
align-items: center;
padding: 0 20px;
border-bottom: 1px solid #ebeef5;
&:last-child {
border-bottom: none;
}
}
.week-checkbox {
width: 80px;
display: flex;
align-items: center;
padding: 14px 0;
cursor: pointer;
.el-checkbox{
margin-right: 10px;
}
}
.time-container {
flex: 1;
display: flex;
flex-direction: column;
padding: 14px 16px;
border-left: 1px solid #ebeef5;
}
.time-list {
display: flex;
flex-wrap: wrap;
max-height: 64px;
overflow-y: scroll;
.el-tag{
margin: 0 8px 8px 0;
}
}
.time-picker-container{
display: flex;
justify-content: flex-start;
align-items: center;
::v-deep .el-date-editor{
margin-right: 8px;
.el-range-separator{
width: 13%;
}
}
}
.add-time-icon {
color: #409EFF;
font-size: 24px;
cursor: pointer;
}
.closed-dialog{
::v-deep .el-dialog__footer{
padding: 0 0 20px 0;
}
}
</style>

140
src/views/weChatMiniProgram/reservationLog.vue

@ -0,0 +1,140 @@
<template>
<div class="app-container row-container" style="height: calc(100vh - 140px);">
<!--工具栏-->
<div class="head-container">
<div class="head-search">
<!-- 搜索 -->
<el-select v-model="query.status" clearable size="small" placeholder="状态" class="filter-item" style="width: 100px" @change="crud.toQuery">
<i slot="prefix" class="iconfont icon-zhuangtai" />
<el-option v-for="item in statusOptions" :key="item.key" :label="item.display_name" :value="item.key" />
</el-select>
<el-input v-model="query.search" clearable size="small" placeholder="输入检索条件检索" prefix-icon="el-icon-search" style="width: 220px;" class="filter-item" @clear="crud.toQuery" @keyup.enter.native="crud.toQuery" />
<rrOperation />
</div>
<!-- <crudOperation :permission="permission" /> -->
</div>
<!--表格渲染-->
<div class="container-wrap">
<span class="right-top-line" />
<span class="left-bottom-line" />
<el-table
ref="table"
v-loading="crud.loading"
class="archives-table"
height="calc(100vh - 330px)"
:data="crud.data"
@selection-change="crud.selectionChangeHandler"
@row-click="clickRowHandler"
>
<el-table-column type="selection" align="center" width="55" />
<el-table-column prop="readCardNo" label="读者证号" />
<el-table-column prop="readName" label="读者昵称" />
<el-table-column prop="phone" label="联系方式" />
<!-- <el-table-column prop="contact" label="联系方式" /> -->
<el-table-column prop="create_time" label="预约日期">
<template slot-scope="scope">
<div>{{ scope.row.create_time | parseTime }}</div>
</template>
</el-table-column>
<el-table-column prop="status" label="预约状态" width="100" align="center">
<template slot-scope="scope">
<span v-if="scope.row.status === 0" class="row-state row-lending state-active">已取消</span>
</template>
</el-table-column>
</el-table>
<!--分页组件-->
<pagination v-if="crud.data.length!==0" />
</div>
</div>
</template>
<script>
import crudWeChat from '@/api/digitalScreen/index'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import CRUD, { presenter, header, form, crud } from '@crud/crud'
// import crudOperation from '@crud/CRUD.operation'
import rrOperation from '@crud/RR.operation'
import pagination from '@crud/Pagination'
import { mapGetters } from 'vuex'
const defaultForm = { }
export default {
name: 'ReservationLog',
components: { rrOperation, pagination },
cruds() {
return CRUD({ title: '预约入馆日志', url: 'api/screenSetting/initScreenBookRecommend2', crudMethod: { ...crudWeChat },
optShow: {
add: false,
edit: false,
del: false,
download: false,
group: false,
reset: true
}
})
},
mixins: [presenter(), header(), form(defaultForm), crud()],
data() {
return {
statusOptions: [
{ key: 1, display_name: '进行中' },
{ key: 0, display_name: '已取消' }
],
permission: { add: [], edit: [], del: [] }
}
},
computed: {
...mapGetters([
'baseApi',
'user'
])
},
methods: {
[CRUD.HOOK.beforeRefresh]() {
this.crud.params.libcode = this.user.fonds.fondsNo
const mockData = [
{
id: 1,
name: '张三',
contact: '13800000000',
title: '读书分享会',
number: 4,
status: 1,
create_time: '2026-01-10 10:00:00'
},
{
id: 2,
name: '李四',
contact: '13800000001',
title: '新书发布会',
number: 1,
status: 0,
create_time: '2026-01-12 14:30:00'
}
]
this.crud.data = mockData
this.crud.loading = false
},
//
[CRUD.HOOK.afterToCU](crud, form) {
},
//
[CRUD.HOOK.beforeToAdd]() {
},
//
[CRUD.HOOK.beforeToEdit](crud, form) {
console.log('crud', crud.form)
},
//
[CRUD.HOOK.afterValidateCU](crud) {
},
clickRowHandler(row) {
this.$refs.table.clearSelection()
this.$refs.table.toggleRowSelection(row)
}
}
}
</script>
<style lang="scss" scoped>
</style>
Loading…
Cancel
Save