This commit is contained in:
2026-04-01 18:53:08 +08:00
parent dc71dc22d8
commit d799d11f69
34 changed files with 5509 additions and 0 deletions
@@ -0,0 +1,531 @@
const apply = {
template: /*language=HTML*/ `
<div>
<el-row :gutter="20" class="mb10">
<el-col :span="24" style="text-align: center">
<div style="font-size: large;color: #303133">
您正在预约【<span style="color: #409EFF">{{ row.name }}</span>】活动场地
</div>
</el-col>
</el-row>
<el-form :model="formData" ref="formRef" :rules="formRules" label-position="left" label-width="110px">
<el-row :gutter="10">
<el-col :span="12">
<el-form-item label="预约人" prop="applyUserName">
<el-input readonly v-model="formData.applyUserName"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="工号" prop="applyLoginName">
<el-input readonly v-model="formData.applyLoginName"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属单位" prop="applyUnitName">
<el-input readonly v-model="formData.applyUnitName"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="预约类型" prop="reserveType">
<el-radio-group v-model="formData.reserveType" @change="reserveTypeChange">
<el-radio-button label="union">分工会预约</el-radio-button>
<el-radio-button label="club">协会预约</el-radio-button>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="分工会" prop="applyUnionName" v-if="formData.reserveType === 'union'">
<el-input readonly v-model="formData.applyUnionName"
placeholder="自动读取当前登录人的分工会"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="协会"
prop="clubId"
v-if="formData.reserveType === 'club'"
:rules="[{ required: true, message: '请选择您管理的协会', trigger: ['change', 'blur'] }]">
<el-select v-model="formData.clubId" placeholder="请选择您管理的协会" filterable clearable
style="width: 100%" @change="clubChange">
<el-option
v-for="item in clubOptions"
:key="item.id"
:label="item.clubName"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系电话" prop="applyMobile">
<el-input maxlength="11" placeholder="请输入联系电话" v-model="formData.applyMobile"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="预约开始时间" prop="reserveStartTime">
<el-date-picker
:key="'start-' + pickerRefreshKey"
v-model="formData.reserveStartTime"
type="datetime"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择预约开始时间"
:picker-options="startPickerOptions"
style="width: 100%"
@change="timeFieldChange('reserveStartTime')">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="预约结束时间" prop="reserveEndTime">
<el-date-picker
:key="'end-' + pickerRefreshKey"
v-model="formData.reserveEndTime"
type="datetime"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择预约结束时间"
:picker-options="endPickerOptions"
style="width: 100%"
@change="timeFieldChange('reserveEndTime')">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="批量预约">
<div style="display:flex;align-items:flex-start;column-gap:12px;flex-wrap:wrap;line-height:1.7;">
<el-checkbox v-model="yearlyReserve">预约本年后续每周同一时段</el-checkbox>
<span style="color:#909399;">
例如先选某个周一 09:00-11:00,勾选后会自动预约本年剩余所有周一的这个时段。
</span>
</div>
<div v-if="yearlyReserve && yearlyReserveSummary" style="margin-top:8px;color:#E6A23C;">
{{ yearlyReserveSummary }}
</div>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="预约事由" prop="applyCause">
<el-input maxlength="1000" placeholder="请输入预约事由" v-model="formData.applyCause"
type="textarea" :autosize="{ minRows: 4, maxRows: 6}"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-row class="mt10" justify="end" type="flex">
<el-button @click="$emit('refresh')">取消</el-button>
<el-button type="primary" @click="onSubmit">提交预约</el-button>
</el-row>
</div>
`,
store,
data() {
return {
row: {},
clubOptions: [],
yearlyReserve: false,
timeLimitConfig: {
filterHolidays: false,
holidayList: [],
notApplyTimeList: [],
},
pickerRefreshKey: 0,
formData: {
reserveType: 'union',
applyUnionId: '',
applyUnionName: '',
clubId: '',
clubName: '',
reserveStartTime: '',
reserveEndTime: '',
joinCount: 1,
applyCause: '',
},
formRules: {
applyUserName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
applySex: [{required: true, message: '必填', trigger: ['blur', 'change']}],
applyLoginName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
applyUnitName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
reserveType: [{required: true, message: '必填', trigger: ['blur', 'change']}],
applyMobile: [{required: true, message: '必填', trigger: ['blur', 'change']}],
reserveStartTime: [{required: true, message: '必填', trigger: ['blur', 'change']}],
reserveEndTime: [{required: true, message: '必填', trigger: ['blur', 'change']}],
joinCount: [{required: true, message: '必填', trigger: ['blur', 'change']}],
applyCause: [{required: true, message: '必填', trigger: ['blur', 'change']}],
clubId: [{ validator: (rule, value, callback) => {
if (this.formData.reserveType === 'club' && !value) {
callback(new Error('请选择您管理的协会'))
return
}
callback()
}, trigger: ['blur', 'change']}],
},
}
},
computed: {
startPickerOptions() {
return {
disabledDate: (time) => this.isDisabledDate(time),
selectableRange: this.buildSelectableRange(this.formData.reserveStartTime),
}
},
endPickerOptions() {
return {
disabledDate: (time) => this.isDisabledDate(time),
selectableRange: this.buildSelectableRange(this.formData.reserveEndTime),
}
},
yearlyReserveDates() {
if (!this.yearlyReserve || !this.formData.reserveStartTime || !this.formData.reserveEndTime) {
return []
}
const start = this.$moment(this.formData.reserveStartTime)
const end = this.$moment(this.formData.reserveEndTime)
if (!start.isValid() || !end.isValid() || !end.isAfter(start)) {
return []
}
const result = []
const current = start.clone().startOf('day')
const endOfYear = start.clone().endOf('year').startOf('day')
const targetWeekDay = start.day()
const startClock = start.format('HH:mm:ss')
const endClock = end.format('HH:mm:ss')
while (current.isSameOrBefore(endOfYear, 'day')) {
if (current.day() === targetWeekDay) {
const day = current.format('YYYY-MM-DD')
const startTime = day + ' ' + startClock
const endTime = day + ' ' + endClock
if (this.validateTimeLimit(false, startTime, endTime)) {
result.push(day)
}
}
current.add(1, 'day')
}
return result
},
yearlyReserveSummary() {
if (!this.yearlyReserve) {
return ''
}
if (!this.formData.reserveStartTime || !this.formData.reserveEndTime) {
return '请先选择开始和结束时间后,再批量预约本年同星期时段'
}
if (!this.yearlyReserveDates.length) {
return '当前时间段无法生成本年批量预约日期'
}
return '将从 ' + this.yearlyReserveDates[0] + ' 开始,自动预约到 ' + this.yearlyReserveDates[this.yearlyReserveDates.length - 1] + ',共 ' + this.yearlyReserveDates.length + ' 个时段'
},
},
methods: {
async onOpen(row) {
this.row = row
this.clubOptions = []
this.yearlyReserve = false
this.formData = {
siteId: row.id,
applyUserId: this.$store.state.user.id,
applyUserName: this.$store.state.user.username,
applySex: this.$store.state.user.sex,
applyLoginName: this.$store.state.user.loginname,
applyUnitId: this.$store.state.user?.unit?.id,
applyUnitName: this.$store.state.user?.unit?.name,
reserveType: 'union',
applyUnionId: this.$store.state.user?.union?.id,
applyUnionName: this.$store.state.user?.union?.name,
clubId: '',
clubName: '',
applyMobile: this.$store.state.user.mobile,
reserveStartTime: '',
reserveEndTime: '',
joinCount: 1,
applyCause: '',
}
await this.queryTimeLimitConfig()
},
async queryTimeLimitConfig() {
const fallback = {
filterHolidays: !!this.row.filterHolidays,
holidayList: [],
notApplyTimeList: Array.isArray(this.row.notApplyTimeList) ? this.row.notApplyTimeList : [],
}
try {
const res = await this.$axios.post('/platform/siteCug/apply/timeLimitConfig', {
siteId: this.row.id,
})
if (res.code === 0 && res.data) {
this.timeLimitConfig = {
filterHolidays: !!res.data.filterHolidays,
holidayList: Array.isArray(res.data.holidayList) ? res.data.holidayList : [],
notApplyTimeList: Array.isArray(res.data.notApplyTimeList) ? res.data.notApplyTimeList : [],
}
} else {
this.timeLimitConfig = fallback
}
} catch (e) {
this.timeLimitConfig = fallback
}
this.pickerRefreshKey += 1
},
async reserveTypeChange(value) {
if (value === 'union') {
this.formData.applyUnionId = this.$store.state.user?.union?.id || ''
this.formData.applyUnionName = this.$store.state.user?.union?.name || ''
this.formData.clubId = ''
this.formData.clubName = ''
}
if (value === 'club') {
this.formData.applyUnionId = ''
this.formData.applyUnionName = ''
this.formData.clubId = ''
this.formData.clubName = ''
await this.loadManagedClubs()
}
this.$nextTick(() => {
this.$refs.formRef?.clearValidate(['applyUnionName', 'clubId'])
})
},
async loadManagedClubs() {
try {
const res = await this.$axios.post('/platform/club/examine/apply/getClubsByRole')
this.clubOptions = Array.isArray(res.data) ? res.data : []
if (!this.clubOptions.length) {
this.$message.warning('您当前没有可预约的协会管理权限')
}
} catch (e) {
this.clubOptions = []
this.$message.warning('协会列表加载失败,请稍后重试')
}
},
clubChange(clubId) {
const club = this.clubOptions.find(item => item.id === clubId)
this.formData.clubName = club ? club.clubName : ''
},
async normalizeReserveTypeData() {
if (this.formData.reserveType === 'union') {
this.formData.applyUnionId = this.$store.state.user?.union?.id || ''
this.formData.applyUnionName = this.$store.state.user?.union?.name || ''
this.formData.clubId = ''
this.formData.clubName = ''
return true
}
if (this.formData.reserveType === 'club') {
if (!this.clubOptions.length) {
await this.loadManagedClubs()
}
const club = this.clubOptions.find(item => item.id === this.formData.clubId)
this.formData.clubName = club ? club.clubName : ''
this.formData.applyUnionId = ''
this.formData.applyUnionName = ''
return true
}
return false
},
isDisabledDate(time) {
const day = this.$moment(time).format('YYYY-MM-DD')
const today = this.$moment().startOf('day')
const currentDay = this.$moment(day)
if (currentDay.isBefore(today)) {
return true
}
if (currentDay.day() === 0 || currentDay.day() === 6) {
return true
}
return this.timeLimitConfig.filterHolidays && this.timeLimitConfig.holidayList.includes(day)
},
normalizeTime(timeStr) {
if (!timeStr) {
return '00:00:00'
}
return timeStr.length === 5 ? timeStr + ':00' : timeStr
},
getDisabledRangesByDay(dayStr) {
const list = Array.isArray(this.timeLimitConfig.notApplyTimeList) ? this.timeLimitConfig.notApplyTimeList : []
return list
.filter(item => item && item.date && this.$moment(item.date).format('YYYY-MM-DD') === dayStr)
.sort((a, b) => this.normalizeTime(a.startTime).localeCompare(this.normalizeTime(b.startTime)))
},
buildSelectableRange(dateTimeValue) {
if (!dateTimeValue) {
return ['00:00:00 - 23:59:59']
}
const dayStr = this.$moment(dateTimeValue).format('YYYY-MM-DD')
const disabledRanges = this.getDisabledRangesByDay(dayStr)
if (!disabledRanges.length) {
return ['00:00:00 - 23:59:59']
}
const result = []
let cursor = '00:00:00'
disabledRanges.forEach(item => {
const start = this.normalizeTime(item.startTime)
const end = this.normalizeTime(item.endTime)
if (cursor < start) {
result.push(cursor + ' - ' + start)
}
if (cursor < end) {
cursor = end
}
})
if (cursor < '23:59:59') {
result.push(cursor + ' - 23:59:59')
}
return result.length ? result : ['00:00:00 - 00:00:00']
},
isDateTimeBlocked(dateTimeStr) {
if (!dateTimeStr) {
return false
}
const target = this.$moment(dateTimeStr)
const dayStr = target.format('YYYY-MM-DD')
if (this.timeLimitConfig.filterHolidays && this.timeLimitConfig.holidayList.includes(dayStr)) {
return true
}
const disabledRanges = this.getDisabledRangesByDay(dayStr)
return disabledRanges.some(item => {
const start = this.$moment(dayStr + ' ' + this.normalizeTime(item.startTime))
const end = this.$moment(dayStr + ' ' + this.normalizeTime(item.endTime))
return target.isSameOrAfter(start) && target.isBefore(end)
})
},
hasHolidayInRange(start, end) {
const current = start.clone().startOf('day')
const endDay = end.clone().startOf('day')
while (current.isSameOrBefore(endDay)) {
if (current.day() === 0 || current.day() === 6) {
return true
}
if (this.timeLimitConfig.filterHolidays && this.timeLimitConfig.holidayList.includes(current.format('YYYY-MM-DD'))) {
return true
}
current.add(1, 'day')
}
return false
},
overlapsDisabledRange(start, end) {
const list = Array.isArray(this.timeLimitConfig.notApplyTimeList) ? this.timeLimitConfig.notApplyTimeList : []
return list.some(item => {
if (!item || !item.date || !item.startTime || !item.endTime) {
return false
}
const rangeStart = this.$moment(this.$moment(item.date).format('YYYY-MM-DD') + ' ' + this.normalizeTime(item.startTime))
const rangeEnd = this.$moment(this.$moment(item.date).format('YYYY-MM-DD') + ' ' + this.normalizeTime(item.endTime))
return start.isBefore(rangeEnd) && end.isAfter(rangeStart)
})
},
validateTimeLimit(showMessage = true, startTime = this.formData.reserveStartTime, endTime = this.formData.reserveEndTime) {
if (!startTime || !endTime) {
return true
}
const start = this.$moment(startTime)
const end = this.$moment(endTime)
if (this.isDateTimeBlocked(startTime) || this.isDateTimeBlocked(endTime)) {
if (showMessage) {
this.$message.warning('预约时间不能选择周末、节假日或禁用时间')
}
return false
}
if (this.hasHolidayInRange(start, end)) {
if (showMessage) {
this.$message.warning('预约时间范围内包含周末或节假日,请重新选择')
}
return false
}
if (this.overlapsDisabledRange(start, end)) {
if (showMessage) {
this.$message.warning('预约时间范围与禁用时间冲突,请重新选择')
}
return false
}
return true
},
timeFieldChange(field) {
const value = this.formData[field]
if (!value) {
return
}
if (this.isDateTimeBlocked(value)) {
this.$message.warning('该时间点不可预约,请重新选择')
this.$set(this.formData, field, '')
return
}
if (this.formData.reserveStartTime && this.formData.reserveEndTime && !this.validateTimeLimit()) {
this.$set(this.formData, field, '')
}
},
validateYearlyReserve() {
if (!this.yearlyReserve) {
return true
}
if (!this.yearlyReserveDates.length) {
this.$message.warning('?????????????????????')
return false
}
return true
},
buildSubmitApi() {
return this.yearlyReserve ? '/platform/siteCug/apply/submitYearly' : '/platform/siteCug/apply/submit'
},
buildSubmitConfirmMessage() {
if (!this.yearlyReserve) {
return '您确定要提交吗?'
}
return '将一次性预约本年后续 ' + this.yearlyReserveDates.length + ' 个同星期时段,确认提交吗?'
},
onSubmit() {
this.$refs.formRef.validate(async (valid) => {
if (!valid) return
if (!this.formData.reserveType) {
this.$message.warning('请选择预约类型')
return
}
await this.normalizeReserveTypeData()
if (this.formData.reserveType === 'union' && !this.formData.applyUnionId) {
this.$message.warning('当前用户未关联分工会,不能发起分工会预约')
return
}
if (this.formData.reserveType === 'club' && !this.formData.clubId) {
this.$message.warning('请选择您管理的协会')
return
}
if (!this.formData.reserveStartTime || !this.formData.reserveEndTime) {
this.$message.warning('请选择预约开始和结束时间')
return
}
const start = this.$moment(this.formData.reserveStartTime)
const end = this.$moment(this.formData.reserveEndTime)
if (!start.isAfter(this.$moment())) {
this.$message.warning('预约开始时间必须晚于当前时间')
return
}
if (!end.isAfter(start)) {
this.$message.warning('预约结束时间必须晚于开始时间')
return
}
if (!this.validateTimeLimit()) {
return
}
if (!this.validateYearlyReserve()) {
return
}
this.$confirm(this.buildSubmitConfirmMessage(), '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$axios.post(this.buildSubmitApi(), {
data: JSON.stringify(this.formData),
}).then((resp) => {
if (resp.code === 0) {
this.$message.success(resp.msg || '提交成功')
this.$emit('refresh')
} else {
this.$message.warning(resp.msg || '提交失败')
}
}).catch((err) => {
this.$message.warning((err && err.msg) || '提交失败')
})
}).catch(() => {})
})
},
},
};
@@ -0,0 +1,125 @@
<!--#
layout("/layouts/platform.html"){
#-->
<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">
</el-input>
</search-item>
<search-item label="场地类型">
<el-select v-model="pageForm.type" clearable filterable placeholder="请选择场地类型" @change="doSearch">
<el-option
v-for="item in typeOptions"
:label="item.name"
:value="item.id"
:key="item.id"
></el-option>
</el-select>
</search-item>
</search>
</el-card>
<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>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<site-apply ref="applyRef" @refresh="refresh"></site-apply>
</template>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../manage/info.js'){}#-->
<!--#include('apply.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"info": siteInfo,
"site-apply": apply,
},
data() {
return {
typeOptions: [],
tableColumns: [
{prop: 'name', label: '场地名称'},
{prop: 'address', label: '场地地址'},
{prop: 'contactName', label: '联系人'},
{prop: 'contactPhone', label: '联系电话'},
{prop: 'maxNum', label: '容纳人数'},
{prop: 'typeName', label: '场地类型'},
],
}
},
methods: {
refresh() {
this.doSearch()
this.$refs.guava.index()
},
onApply(row) {
this.$refs.guava.edit(() => {
this.$refs.applyRef.onOpen(row)
})
},
onViewSite(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
querySiteType() {
this.$axios.post('/platform/siteCug/function/type/queryFunctionType').then((res) => {
this.typeOptions = res.data
})
},
pageData() {
this.$axios.post(loc() + '/pageData', this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
},
},
async created() {
this.querySiteType()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,80 @@
const siteCugApplyInfo = {
template: /*language=HTML*/ `
<div>
<div class="process-title">
申请信息
<el-link type="primary" @click="openChart">点击查看流程图</el-link>
</div>
<el-descriptions :column="2" border>
<el-descriptions-item label="预约场地">{{ viewData.siteName }}</el-descriptions-item>
<el-descriptions-item label="预约人">{{ viewData.applyUserName }}</el-descriptions-item>
<el-descriptions-item label="预约人工号">{{ viewData.applyLoginName }}</el-descriptions-item>
<el-descriptions-item label="所属单位">{{ viewData.applyUnitName }}</el-descriptions-item>
<el-descriptions-item label="预约类型">{{ reserveTypeLabel }}</el-descriptions-item>
<el-descriptions-item label="预约主体">{{ reserveTargetName }}</el-descriptions-item>
<el-descriptions-item label="开始时间">{{ viewData.reserveStartTime }}</el-descriptions-item>
<el-descriptions-item label="结束时间">{{ viewData.reserveEndTime }}</el-descriptions-item>
<el-descriptions-item label="联系电话">{{ viewData.applyMobile }}</el-descriptions-item>
<el-descriptions-item label="预约人数">{{ viewData.joinCount }}</el-descriptions-item>
<el-descriptions-item label="预约事由" :span="2">{{ viewData.applyCause }}</el-descriptions-item>
</el-descriptions>
<template v-for="task in doneTasks">
<div class="mt10">
<div class="process-title">{{ task.displayName }}</div>
<el-descriptions border class="flow-task-form" :column="3" :key="task.id" v-if="task.ext.isFirstTaskNode">
<el-descriptions-item label="申请用户">{{ task.ext.initiatorName }}({{task.ext.initiatorAccount}})</el-descriptions-item>
<el-descriptions-item label="申请时间">{{ task.finishTime }}</el-descriptions-item>
<el-descriptions-item label="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE" :value="task.ext.submitType"></dict-tag>
</el-descriptions-item>
</el-descriptions>
<el-descriptions border class="flow-task-form" :column="3" :key="task.id" v-else>
<el-descriptions-item label="办理用户">{{ task.taskFormData.userName }}({{task.taskFormData.loginName}})</el-descriptions-item>
<el-descriptions-item label="办理时间">{{ task.finishTime }}</el-descriptions-item>
<el-descriptions-item label="办理结果">
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE" :value="task.ext.submitType"></dict-tag>
</el-descriptions-item>
<el-descriptions-item label="办理意见">{{ task.taskFormData.opinion }}</el-descriptions-item>
</el-descriptions>
</div>
</template>
<slot></slot>
<snaker-chart ref="snakerChartRef"></snaker-chart>
</div>
`,
store,
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
viewData: {},
doneTasks: [],
row: null
}
},
computed: {
reserveTypeLabel() {
return this.viewData.reserveType === 'club' ? '协会预约' : '分工会预约'
},
reserveTargetName() {
return this.viewData.reserveType === 'club' ? (this.viewData.clubName || '-') : (this.viewData.applyUnionName || '-')
},
},
methods: {
onOpen(row) {
this.row = row
this.viewData = row
this.getDoneTasks()
},
getDoneTasks() {
this.$axios.post('/flow/common/doneTasks', {bizId: this.row.id}).then((res) => {
if (res.code === 0) {
this.doneTasks = res.data
}
})
},
openChart() {
this.$refs.snakerChartRef.onOpenFull(this.row.instanceProcessDefineId, this.row.instanceId)
}
},
}
@@ -0,0 +1,341 @@
const basicForm = {
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-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="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>
</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>
</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-form-item label="场地介绍" prop="introduce">
<text-editor v-model="formData.introduce"></text-editor>
</el-form-item>
</el-form>
<el-row class="mt10" justify="end" type="flex">
<el-button @click="$emit('refresh')">取消</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="设置时间">
<div class="left-span-label">选择日期</div>
<el-date-picker
@change="setUpDateChange"
placeholder="请选择一个或多个日期"
style="width: 100%"
type="dates"
v-model="formData.setUpDate"
value-format="yyyy-MM-dd">
</el-date-picker>
<div class="left-span-label mt20">设置禁用时间</div>
<el-row>
<el-time-select
:picker-options="{
start: '00:00',
step: '00:05',
end: '23:55'
}"
placeholder="开始时间"
v-model="timeOneKeySet.startTime">
</el-time-select>
<el-time-select
:picker-options="{
start: '00:00',
step: '00:05',
end: '23:55'
}"
placeholder="结束时间"
v-model="timeOneKeySet.endTime">
</el-time-select>
<el-button @click="oneKeySetStartEndTime" type="primary">一键设置开始/结束时间</el-button>
</el-row>
<el-table :data="formData.notApplyTimeList" class="mt10" max-height="520px" size="mini" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="日期" width="200">
<template v-slot="{row}">
<i class="el-icon-time"></i>
{{$moment(row.date).format('YYYY-MM-DD')}}
</template>
</el-table-column>
<el-table-column label="开始时间">
<template v-slot="{row}">
<el-time-select
size="mini"
:picker-options="{
start: '00:00',
step: '00:05',
end: '23:55'
}"
v-model="row.startTime">
</el-time-select>
</template>
</el-table-column>
<el-table-column label="结束时间">
<template v-slot="{row}">
<el-time-select
size="mini"
:picker-options="{
start: '00:00',
step: '00:05',
end: '23:55'
}"
v-model="row.endTime">
</el-time-select>
</template>
</el-table-column>
<el-table-column label="操作" width="200">
<template v-slot="{row, $index}">
<el-button
size="mini"
@click="formData.notApplyTimeList.splice($index,0,{date:row.date,startTime:'',endTime:''})"
type="primary">
新增同天时段
</el-button>
<el-button size="mini" @click="removeSetUpTableRow(row,$index)" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-row class="mt20" justify="end" type="flex">
<el-button @click="setUpTimeDialog = false">取消</el-button>
<el-button @click="doConfirmSetUpCourse" type="primary">确定</el-button>
</el-row>
</el-dialog>
</div>
`,
props: {
typeList: {
type: Array,
required: false,
default: [],
}
},
store,
data() {
return {
formData: {
state: true,
sexLimit: 0,
filterHolidays: false,
notApplyTimeList: [],
createUserName: this.$store.state.user.username,
createUserId: this.$store.state.user.id,
},
formRules: {
createUserName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
sortNum: [{required: true, message: '必填', trigger: ['blur', 'change']}],
name: [{required: true, message: '必填', trigger: ['blur', 'change']}],
address: [{required: true, message: '必填', trigger: ['blur', 'change']}],
contactName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
contactPhone: [{required: true, message: '必填', trigger: ['blur', 'change']}],
maxNum: [{required: true, message: '必填', trigger: ['blur', 'change']}],
typeId: [{required: true, message: '必填', trigger: ['blur', 'change']}],
sexLimit: [{required: true, message: '必填', trigger: ['blur', 'change']}],
filterHolidays: [{required: true, message: '必填', trigger: ['blur', 'change']}],
state: [{required: true, message: '必填', trigger: ['blur', 'change']}],
},
setUpTimeDialog: false,
timeOneKeySet: {
startTime: "",
endTime: ""
},
multipleSelection: [],
}
},
methods: {
doConfirmSetUpCourse() {
const timeList = this.formData.notApplyTimeList
if (timeList && timeList.length > 0) {
const valid = timeList.every(v => v.date && v.startTime && v.endTime && (v.startTime < v.endTime))
if (!valid) {
this.$message.warning("时间不完整或者有误")
return
}
}
this.setUpTimeDialog = false
},
removeSetUpTableRow(row, index) {
this.formData.notApplyTimeList.splice(index, 1)
const dateArray = this.formData.notApplyTimeList.map(v => this.$moment(v.date).format("YYYY-MM-DD"))
const setUpDate = this.formData.setUpDate || []
this.formData.setUpDate = setUpDate.filter(v => {
return dateArray.includes(this.$moment(v).format("YYYY-MM-DD"))
})
},
handleSelectionChange(val) {
this.multipleSelection = val
},
oneKeySetStartEndTime() {
if (this.multipleSelection.length === 0) {
this.$message.warning('请在下面表格多选框中选择需要一键设置的时间')
return
}
const { startTime, endTime } = this.timeOneKeySet
this.formData.notApplyTimeList.forEach(v => {
const selected = this.multipleSelection.find(o => o.date === v.date && o.startTime === v.startTime && o.endTime === v.endTime)
if (selected) {
this.$set(v, "startTime", startTime)
this.$set(v, "endTime", endTime)
}
})
this.$forceUpdate()
},
setUpDateChange(val) {
if (!val) {
this.formData.notApplyTimeList = []
return
}
if (this.formData.notApplyTimeList === undefined) {
this.$set(this.formData, "notApplyTimeList", [])
}
const dateSet = new Set(this.formData.notApplyTimeList.map(v => this.$moment(v.date).format("YYYY-MM-DD")))
val.forEach(v => {
if (!dateSet.has(v)) {
this.formData.notApplyTimeList.push({
date: v, startTime: "", endTime: ""
})
}
})
this.formData.notApplyTimeList = this.formData.notApplyTimeList.filter(v => {
return val.includes(this.$moment(v.date).format("YYYY-MM-DD"))
})
this.formData.notApplyTimeList.sort((a, b) => {
return Date.parse(a.date) - Date.parse(b.date)
})
},
openSetUpTime() {
if (this.formData.notApplyTimeList) {
this.$set(this.formData, 'setUpDate', this.formData.notApplyTimeList.map(o => o.date))
}
this.setUpTimeDialog = true
},
onOpen(row) {
if (row && row.id) {
this.formData = clone(row)
if (!Array.isArray(this.formData.notApplyTimeList)) {
this.$set(this.formData, 'notApplyTimeList', [])
}
} else {
this.formData = {
state: true,
sexLimit: 0,
filterHolidays: false,
notApplyTimeList: [],
createUserName: this.$store.state.user.username,
createUserId: this.$store.state.user.id,
}
}
},
onSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).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)
}
})
}
})
},
},
style: /*language=CSS*/ `
`
};
@@ -0,0 +1,180 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
</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">
</el-input>
</search-item>
<search-item label="场地类型">
<el-select v-model="pageForm.type" clearable filterable placeholder="请选择场地类型" @change="doSearch">
<el-option
v-for="item in typeOptions"
:label="item.name"
:value="item.id"
:key="item.id"
></el-option>
</el-select>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="场地列表">
<el-button type="primary" size="small" @click="onAdd">
<i class="ti-plus"></i>
新增场地
</el-button>
</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"
>
<template v-slot="{ row }" v-if="column.prop === 'state'">
<el-switch
@change="switchChange(row)"
v-model="row.state"
active-color="#13ce66"
inactive-color="#ff4949">
</el-switch>
</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>
<span v-else-if="row.sexLimit === 2">女</span>
<span v-else>--</span>
</template>
</el-table-column>
<el-table-column label="操作" width="230">
<template v-slot="{ row }">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
<el-button @click="onDelete(row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<basic-form :type-list="typeOptions" ref="basicFormRef" @refresh="refresh"></basic-form>
</template>
<template #view>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('basicForm.js'){}#-->
<!--#include('info.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"basic-form": basicForm,
"info": siteInfo,
},
data() {
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: 'typeName', label: '场地类型'},
{prop: 'sexLimit', label: '性别限制'},
{prop: 'state', label: '开启状态'},
],
}
},
methods: {
refresh() {
this.doSearch()
this.$refs.guava.index()
},
onAdd() {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen()
})
},
onEdit(row) {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen(row)
})
},
onView(row) {
this.$refs.guava.view(() => {
this.$refs.infoRef.onOpen(row)
})
},
onDelete(row) {
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$axios.post("/platform/siteCug/manage/delete", { id: row.id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
.catch(() => {})
},
switchChange(row) {
this.$axios.post("/platform/siteCug/manage/submit", row).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
},
querySiteType() {
this.$axios.post("/platform/siteCug/function/type/queryFunctionType").then((res) => {
this.typeOptions = res.data
})
},
pageData() {
this.$axios.post(loc() + "/pageData", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
},
},
async created() {
this.querySiteType()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,59 @@
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>
</div>
`,
data() {
return {
viewData: {},
}
},
methods: {
onOpen(row) {
this.viewData = row
},
},
style: /*language=CSS*/ `
.el-descriptions-item__label {
width: 200px;
min-width: 200px;
max-width: 200px;
}
`
};
@@ -0,0 +1,140 @@
<!--#
layout("/layouts/platform.html"){
#-->
<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">
</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>
</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>
</el-card>
<el-card shadow="never">
<table-tool label="申请列表"></table-tool>
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column type="index" width="50" label="序号" :index="indexMethod"></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"
>
<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>
</template>
<template v-slot="{ row }" v-else-if="column.prop === 'reserveTargetName'">
<span>{{ row.reserveType === 'club' ? (row.clubName || '-') : (row.applyUnionName || '-') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="180">
<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>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../common/applyInfo.js'){}#-->
new Vue({
el: '#app',
store,
mixins: [initTableMixins],
components: {
'info': siteCugApplyInfo,
},
data() {
return {
typeOptions: [],
siteOptions: [],
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: '流程状态'},
],
}
},
methods: {
onView(row) {
this.$refs.guava.edit(() => {
this.$refs.infoRef.onOpen(row)
})
},
onDelete(row) {
const message = row.yearlyBatch
? ('该记录属于“预约本年”批量预约,确认后将一并删除同批次的 ' + (row.batchDeleteCount || 0) + ' 条预约记录,是否继续?')
: '您确定要删除吗?'
this.$confirm(message, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$axios.post('/platform/siteCug/mine/delete', { id: row.id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
},
querySiteType() {
this.$axios.post('/platform/siteCug/function/type/queryFunctionType').then((res) => {
this.typeOptions = res.data
})
},
querySites() {
this.$axios.post('/platform/siteCug/manage/querySites').then((res) => {
this.siteOptions = res.data
})
},
},
async created() {
this.querySiteType()
this.querySites()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,187 @@
<!--#
layout("/layouts/platform.html"){
#-->
<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">
</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>
</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>
</search-item>
<search-item label="预约单位">
<el-input placeholder="请输入分工会或协会名称" clearable v-model="pageForm.reserveTargetKeyword"
@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>
</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>
</search-item>
</search>
</el-card>
<el-card shadow="never">
<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-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">
<template v-slot="{ row }" v-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>
</el-table-column>
<el-table-column label="操作" fixed="right" width="180">
<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>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<info ref="infoRef"></info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../common/applyInfo.js'){}#-->
new Vue({
el: '#app',
store,
mixins: [initTableMixins],
components: {
'info': siteCugApplyInfo,
},
data() {
return {
pageForm: {
audit: false,
siteType: '',
siteId: '',
reserveType: '',
reserveTargetKeyword: '',
reserveTimeStart: '',
reserveTimeEnd: '',
},
typeOptions: [],
siteOptions: [],
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: '联系方式'},
],
}
},
methods: {
onView(row) {
this.$refs.guava.edit(() => {
this.$refs.infoRef.onOpen(row)
})
},
onDelete(id) {
this.$confirm('您确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$axios.post('/platform/siteCug/record/delete', { id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
},
// 导出内容和列表当前筛选条件保持一致,实现所见即所得
doExport() {
this.$downLoad('/platform/siteCug/record/doExport', this.pageForm)
},
querySiteType() {
this.$axios.post('/platform/siteCug/function/type/queryFunctionType').then((res) => {
this.typeOptions = res.data
})
},
querySites() {
this.$axios.post('/platform/siteCug/manage/querySites').then((res) => {
this.siteOptions = res.data
})
},
},
created() {
// 查询字段在 data 中一次性声明完整,避免 Vue 2 对后加属性渲染不稳定
this.querySiteType()
this.querySites()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,237 @@
<!--#
layout("/layouts/platform.html"){
#-->
<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">
</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>
</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>
</el-card>
<el-card shadow="never">
<table-tool label="申请列表">
<el-radio-group v-model="pageForm.approval" size="small" @change="doSearch">
<el-radio-button :label="true">已审核</el-radio-button>
<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-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"
>
<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>
</template>
<template v-slot="{ row }" v-else-if="column.prop === 'reserveTargetName'">
<span>{{ row.reserveType === 'club' ? (row.clubName || '-') : (row.applyUnionName || '-') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="300px">
<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>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #edit>
<info ref="infoRef">
<div v-if="showApprovalForm">
<div class="process-title">
{{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']}]">
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
<el-button @click="handleTaskAction(6)" :loading="auditLoading" :disabled="auditLoading" size="small" type="info">退回到发起人</el-button>
<el-button @click="handleTaskAction(2)" :loading="auditLoading" :disabled="auditLoading" size="small" type="danger">拒绝申请</el-button>
<el-button @click="handleTaskAction(1)" :loading="auditLoading" :disabled="auditLoading" size="small" type="primary">同意申请</el-button>
</el-row>
</div>
</info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('../common/applyInfo.js'){}#-->
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
components: {
"info": siteCugApplyInfo,
},
data() {
return {
pageForm: {
approval: false
},
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: '流程状态'},
],
typeOptions: [],
siteOptions: [],
formData: {},
formRules: {},
showApprovalForm: false,
auditLoading: false,
revokeLoading: false,
}
},
methods: {
canRevoke(row) {
return Number(row.instanceState) === 20
},
onView(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = false
this.$refs.infoRef.onOpen(row)
})
},
onAudit(row) {
this.$refs.guava.edit(() => {
this.showApprovalForm = true
this.formData = {
processTaskId: row.taskId,
applyId: row.id,
taskName: row.curTaskName,
tf_opinion: '',
yearlyBatch: row.yearlyBatch,
batchAuditCount: row.batchAuditCount,
}
this.$refs.infoRef.onOpen(row)
})
},
handleTaskAction(val) {
if (this.auditLoading) {
return
}
const message = this.formData.yearlyBatch
? ('该记录属于“预约本年”批量预约,提交后将一并审核同批次的 ' + (this.formData.batchAuditCount || 0) + ' 条预约记录,是否继续?')
: '您确定要提交吗?'
this.$confirm(message, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.auditLoading = true
this.$axios.post('/platform/siteCug/schoolUnionAudit/executeTask', {
data: JSON.stringify({
...this.formData,
submitType: val
})
}).then((res) => {
if (res.code === 0) {
this.$refs.guava.index()
this.$message.success(res.msg)
this.doSearch()
}
}).finally(() => {
this.auditLoading = false
})
}).catch(() => {})
},
onRevoke(row) {
if (!this.canRevoke(row) || this.revokeLoading) {
return
}
const message = row.yearlyBatch
? ('该记录属于“预约本年”批量预约,撤回后将一并撤回同批次的 ' + (row.batchAuditCount || 0) + ' 条审核任务,是否继续?')
: '您确定要撤回吗?'
this.$confirm(message, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'info'
}).then(() => {
this.revokeLoading = true
this.$axios.post('/platform/siteCug/schoolUnionAudit/revokeTask', { taskId: row.taskId, applyId: row.id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.doSearch()
}
}).finally(() => {
this.revokeLoading = false
})
}).catch(() => {})
},
querySiteType() {
this.$axios.post('/platform/siteCug/function/type/queryFunctionType').then((res) => {
this.typeOptions = res.data
})
},
querySites() {
this.$axios.post('/platform/siteCug/manage/querySites').then((res) => {
this.siteOptions = res.data
})
},
},
async created() {
this.querySiteType()
this.querySites()
this.pageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,68 @@
const basicForm = {
template: /*language=HTML*/ `
<div>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left">
<el-form-item label="类型编码" prop="code">
<el-input type="text" v-model="formData.code" maxlength="50"
placeholder="请输入类型编码"></el-input>
</el-form-item>
<el-form-item label="类型名称" prop="name">
<el-input type="text" v-model="formData.name" maxlength="50"
placeholder="请输入类型名称"></el-input>
</el-form-item>
<el-form-item label="是否启用" prop="enable">
<el-switch
v-model="formData.enable"
active-color="#13ce66"
inactive-color="#ff4949">
</el-switch>
</el-form-item>
</el-form>
<el-row class="mt10" justify="end" type="flex">
<el-button @click="$emit('refresh')">取消</el-button>
<el-button @click="onSubmit" type="primary">提交</el-button>
</el-row>
</div>
`,
data() {
return {
formData: {
enable: true
},
formRules: {
name: [{required: true, message: '必填', trigger: ['blur', 'change']}],
code: [{required: true, message: '必填', trigger: ['blur', 'change']}],
enable: [{required: true, message: '必填', trigger: ['blur', 'change']}],
},
}
},
methods: {
onOpen(row) {
if (row && row.id) {
this.formData = clone(row)
}
},
onSubmit() {
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post("/platform/siteCug/function/type/submit", this.formData)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$emit('refresh')
} else {
this.$message.warning(resp.msg)
}
})
}
})
},
},
style: /*language=CSS*/ `
`
}
@@ -0,0 +1,139 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
</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">
</el-input>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt20">
<table-tool label="功能类型列表">
<el-button type="primary" size="small" @click="onAdd">
<i class="ti-plus"></i>
新增类型
</el-button>
</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"
>
<template v-slot="{ row }" v-if="column.prop === 'enable'">
<el-switch
@change="switchChange(row)"
v-model="row.enable"
active-color="#13ce66"
inactive-color="#ff4949">
</el-switch>
</template>
</el-table-column>
<el-table-column label="操作" width="230">
<template v-slot="{ row }">
<el-button @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
<el-button @click="onDelete(row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #edit>
<basic-form ref="basicFormRef" @refresh="refresh"></basic-form>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
<!--#include('basicForm.js'){}#-->
const vue = new Vue({
el: "#app",
mixins: [initTableMixins],
components: {
"basic-form": basicForm,
},
data() {
return {
tableColumns: [
{prop: 'code', label: '类型编码'},
{prop: 'name', label: '类型名称'},
{prop: 'enable', label: '是否启用'},
],
}
},
methods: {
refresh() {
this.doSearch()
this.$refs.guava.index()
},
onAdd() {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen()
})
},
onEdit(row) {
this.$refs.guava.edit(() => {
this.$refs.basicFormRef.onOpen(row)
})
},
onDelete(row) {
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$axios.post("/platform/siteCug/function/type/delete", { id: row.id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
.catch(() => {})
},
switchChange(row) {
this.$axios.post("/platform/siteCug/function/type/submit", row).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
},
pageData() {
this.$axios.post(loc() + "/pageData", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
},
},
async created() {
this.pageData()
}
})
</script>
<!--#
}
#-->