Browse Source

修改地区选择组件

yuhongzhe
王泽彦 11 months ago
parent
commit
1c394c15e5
  1. 4
      admin/components.d.ts
  2. 23
      admin/src/app/api/venue.ts
  3. 10
      admin/src/app/lang/zh-cn/venue.venue.json
  4. 23
      admin/src/app/views/campus/components/campus-edit.vue
  5. 217
      admin/src/app/views/venue/components/venue-edit.vue
  6. 258
      admin/src/app/views/venue/venue.vue
  7. 321
      admin/src/components/TencentMapPicker.vue
  8. 9
      niucloud/app/adminapi/controller/venue/Venue.php
  9. 3
      niucloud/app/adminapi/route/venue.php
  10. 86
      niucloud/app/model/venue/Venue.php
  11. 11
      niucloud/app/service/admin/campus/CampusService.php
  12. 2
      niucloud/app/service/admin/student_courses/StudentCoursesService.php
  13. 14
      niucloud/app/service/admin/venue/VenueService.php
  14. 3
      niucloud/app/validate/venue/Venue.php

4
admin/components.d.ts

@ -10,6 +10,7 @@ declare module '@vue/runtime-core' {
Attachment: typeof import('./src/components/upload-attachment/attachment.vue')['default'] Attachment: typeof import('./src/components/upload-attachment/attachment.vue')['default']
DiyLink: typeof import('./src/components/diy-link/index.vue')['default'] DiyLink: typeof import('./src/components/diy-link/index.vue')['default']
Editor: typeof import('./src/components/editor/index.vue')['default'] Editor: typeof import('./src/components/editor/index.vue')['default']
ElAlert: typeof import('element-plus/es')['ElAlert']
ElAside: typeof import('element-plus/es')['ElAside'] ElAside: typeof import('element-plus/es')['ElAside']
ElAvatar: typeof import('element-plus/es')['ElAvatar'] ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb'] ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
@ -44,6 +45,7 @@ declare module '@vue/runtime-core' {
ElPopover: typeof import('element-plus/es')['ElPopover'] ElPopover: typeof import('element-plus/es')['ElPopover']
ElRadio: typeof import('element-plus/es')['ElRadio'] ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElResult: typeof import('element-plus/es')['ElResult']
ElRow: typeof import('element-plus/es')['ElRow'] ElRow: typeof import('element-plus/es')['ElRow']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSelect: typeof import('element-plus/es')['ElSelect'] ElSelect: typeof import('element-plus/es')['ElSelect']
@ -56,6 +58,8 @@ declare module '@vue/runtime-core' {
ElTabPane: typeof import('element-plus/es')['ElTabPane'] ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs'] ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag'] ElTag: typeof import('element-plus/es')['ElTag']
ElTimeline: typeof import('element-plus/es')['ElTimeline']
ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
ElTooltip: typeof import('element-plus/es')['ElTooltip'] ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTree: typeof import('element-plus/es')['ElTree'] ElTree: typeof import('element-plus/es')['ElTree']
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect'] ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']

23
admin/src/app/api/venue.ts

@ -1,5 +1,7 @@
import request from '@/utils/request' import request from '@/utils/request'
// USER_CODE_BEGIN -- venue // USER_CODE_BEGIN -- venue
/** /**
* *
@ -16,7 +18,7 @@ export function getVenueList(params: Record<string, any>) {
* @returns * @returns
*/ */
export function getVenueInfo(id: number) { export function getVenueInfo(id: number) {
return request.get(`venue/venue/${id}`) return request.get(`venue/venue/${id}`);
} }
/** /**
@ -25,10 +27,7 @@ export function getVenueInfo(id: number) {
* @returns * @returns
*/ */
export function addVenue(params: Record<string, any>) { export function addVenue(params: Record<string, any>) {
return request.post('venue/venue', params, { return request.post('venue/venue', params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -38,10 +37,7 @@ export function addVenue(params: Record<string, any>) {
* @returns * @returns
*/ */
export function editVenue(params: Record<string, any>) { export function editVenue(params: Record<string, any>) {
return request.put(`venue/venue/${params.id}`, params, { return request.put(`venue/venue/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -50,10 +46,11 @@ export function editVenue(params: Record<string, any>) {
* @returns * @returns
*/ */
export function deleteVenue(id: number) { export function deleteVenue(id: number) {
return request.delete(`venue/venue/${id}`, { return request.delete(`venue/venue/${id}`, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true, }
showSuccessMessage: true,
}) export function getWithCampusList(params: Record<string,any>){
return request.get('venue/campus_all', {params})
} }
// USER_CODE_END -- venue // USER_CODE_END -- venue

10
admin/src/app/lang/zh-cn/venue.venue.json

@ -1,8 +1,6 @@
{ {
"id": "场地编号", "campusId":"校区",
"idPlaceholder": "请输入场地编号", "campusIdPlaceholder":"全部",
"campusId": "校区ID",
"campusIdPlaceholder": "请输入校区ID",
"venueName":"场地名称", "venueName":"场地名称",
"venueNamePlaceholder":"请输入场地名称", "venueNamePlaceholder":"请输入场地名称",
"capacity":"场地可容纳人数上限", "capacity":"场地可容纳人数上限",
@ -17,6 +15,10 @@
"timeRangeEndPlaceholder":"请输入范围类型的结束时间", "timeRangeEndPlaceholder":"请输入范围类型的结束时间",
"fixedTimeRanges":"固定时间范围类型的可用时间, 存储为JSON数组", "fixedTimeRanges":"固定时间范围类型的可用时间, 存储为JSON数组",
"fixedTimeRangesPlaceholder":"请输入固定时间范围类型的可用时间, 存储为JSON数组", "fixedTimeRangesPlaceholder":"请输入固定时间范围类型的可用时间, 存储为JSON数组",
"createdAt":"创建时间",
"createdAtPlaceholder":"请输入创建时间",
"updatedAt":"修改时间",
"updatedAtPlaceholder":"请输入修改时间",
"addVenue":"添加场地", "addVenue":"添加场地",
"updateVenue":"编辑场地", "updateVenue":"编辑场地",
"venueDeleteTips":"确定要删除该数据吗?", "venueDeleteTips":"确定要删除该数据吗?",

23
admin/src/app/views/campus/components/campus-edit.vue

@ -23,23 +23,26 @@
/> />
</el-form-item> </el-form-item>
<el-form-item :label="t('campusAddress')"> <!-- <el-form-item :label="t('campusAddress')">-->
<el-input <!-- <el-input-->
v-model="formData.campus_address" <!-- v-model="formData.campus_address"-->
clearable <!-- clearable-->
:placeholder="t('campusAddressPlaceholder')" <!-- :placeholder="t('campusAddressPlaceholder')"-->
class="input-width" <!-- class="input-width"-->
/> <!-- />-->
</el-form-item> <!-- </el-form-item>-->
<el-form-item :label="t('campusPreviewImage')"> <el-form-item :label="t('campusPreviewImage')">
<upload-image v-model="formData.campus_preview_image" /> <upload-image v-model="formData.campus_preview_image" />
</el-form-item> </el-form-item>
<el-form-item :label="t('campusCoordinates')"> <el-form-item :label="t('campusCoordinates')">
<el-button @click="showMapPicker">{{ <el-button @click="showMapPicker">
{{
formData.campus_coordinates?.address ||
t('campusCoordinatesPlaceholder') t('campusCoordinatesPlaceholder')
}}</el-button> }}</el-button
>
<TencentMapPicker <TencentMapPicker
ref="mapPickerRef" ref="mapPickerRef"
v-model="formData.campus_coordinates" v-model="formData.campus_coordinates"

217
admin/src/app/views/venue/components/venue-edit.vue

@ -1,101 +1,84 @@
<template> <template>
<el-dialog <el-dialog v-model="showDialog" :title="formData.id ? t('updateVenue') : t('addVenue')" width="50%" class="diy-dialog-wrap" :destroy-on-close="true">
v-model="showDialog" <el-form :model="formData" label-width="120px" ref="formRef" :rules="formRules" class="page-form" v-loading="loading">
:title="formData.id ? t('updateVenue') : t('addVenue')"
width="50%"
class="diy-dialog-wrap"
:destroy-on-close="true"
>
<el-form
:model="formData"
label-width="120px"
ref="formRef"
:rules="formRules"
class="page-form"
v-loading="loading"
>
<el-form-item :label="t('campusId')" prop="campus_id"> <el-form-item :label="t('campusId')" prop="campus_id">
<el-input <el-select class="input-width" v-model="formData.campus_id" clearable :placeholder="t('campusIdPlaceholder')">
v-model="formData.campus_id" <el-option label="请选择" value=""></el-option>
clearable <el-option
:placeholder="t('campusIdPlaceholder')" v-for="(item, index) in campusIdList"
class="input-width" :key="index"
:label="item['campus_name']"
:value="item['id']"
/> />
</el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('venueName')" prop="venue_name"> <el-form-item :label="t('venueName')" prop="venue_name">
<el-input <el-input v-model="formData.venue_name" clearable :placeholder="t('venueNamePlaceholder')" class="input-width" />
v-model="formData.venue_name"
clearable
:placeholder="t('venueNamePlaceholder')"
class="input-width"
/>
</el-form-item> </el-form-item>
<el-form-item :label="t('capacity')" prop="capacity"> <el-form-item :label="t('capacity')" prop="capacity">
<el-input <el-input-number v-model="formData.capacity" clearable :placeholder="t('capacityPlaceholder')" class="input-width" :min = "1" max = "500" />
v-model="formData.capacity"
clearable
:placeholder="t('capacityPlaceholder')"
class="input-width"
/>
</el-form-item> </el-form-item>
<el-form-item :label="t('availabilityStatus')" prop="availability_status"> <el-form-item :label="t('availabilityStatus')" prop="availability_status">
<el-input <el-radio-group v-model="formData.availability_status" :placeholder="t('availabilityStatusPlaceholder')">
v-model="formData.availability_status" <el-radio
clearable v-for="(item, index) in availability_statusList"
:placeholder="t('availabilityStatusPlaceholder')" :key="index" :label="item.value">
class="input-width" {{ item.name }}
/> </el-radio>
</el-radio-group>
</el-form-item> </el-form-item>
<el-form-item :label="t('timeRangeType')" prop="time_range_type"> <el-form-item :label="t('timeRangeType')" prop="time_range_type">
<el-input <el-radio-group v-model="formData.time_range_type" :placeholder="t('timeRangeTypePlaceholder')">
v-model="formData.time_range_type" <el-radio
clearable v-for="(item, index) in time_range_typeList"
:placeholder="t('timeRangeTypePlaceholder')" :key="index" :label="item.value">
class="input-width" {{ item.name }}
/> </el-radio>
</el-radio-group>
</el-form-item> </el-form-item>
<el-form-item :label="t('timeRangeStart')"> <el-form-item :label="t('timeRangeStart')" class="input-width">
<el-input <el-date-picker
class="flex-1 !flex"
v-model="formData.time_range_start" v-model="formData.time_range_start"
clearable clearable
:placeholder="t('timeRangeStartPlaceholder')" type="datetime"
class="input-width" value-format="YYYY-MM-DD HH:mm:ss"
/> :placeholder="t('timeRangeStartPlaceholder')">
</el-date-picker>
</el-form-item> </el-form-item>
<el-form-item :label="t('timeRangeEnd')" class="input-width">
<el-form-item :label="t('timeRangeEnd')"> <el-date-picker
<el-input class="flex-1 !flex"
v-model="formData.time_range_end" v-model="formData.time_range_end"
clearable clearable
:placeholder="t('timeRangeEndPlaceholder')" type="datetime"
class="input-width" value-format="YYYY-MM-DD HH:mm:ss"
/> :placeholder="t('timeRangeEndPlaceholder')">
</el-date-picker>
</el-form-item> </el-form-item>
<el-form-item :label="t('fixedTimeRanges')" class="input-width">
<el-form-item :label="t('fixedTimeRanges')"> <el-date-picker
<el-input class="flex-1 !flex"
v-model="formData.fixed_time_ranges" v-model="formData.fixed_time_ranges"
clearable clearable
:placeholder="t('fixedTimeRangesPlaceholder')" type="datetime"
class="input-width" value-format="YYYY-MM-DD HH:mm:ss"
/> :placeholder="t('fixedTimeRangesPlaceholder')">
</el-date-picker>
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="showDialog = false">{{ t('cancel') }}</el-button> <el-button @click="showDialog = false">{{ t('cancel') }}</el-button>
<el-button <el-button type="primary" :loading="loading" @click="confirm(formRef)">{{
type="primary" t('confirm')
:loading="loading" }}</el-button>
@click="confirm(formRef)"
>{{ t('confirm') }}</el-button
>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
@ -106,7 +89,7 @@ import { ref, reactive, computed, watch } from 'vue'
import { useDictionary } from '@/app/api/dict' import { useDictionary } from '@/app/api/dict'
import { t } from '@/lang' import { t } from '@/lang'
import type { FormInstance } from 'element-plus' import type { FormInstance } from 'element-plus'
import { addVenue, editVenue, getVenueInfo } from '@/app/api/venue' import { addVenue, editVenue, getVenueInfo, getWithCampusList } from '@/app/api/venue'
let showDialog = ref(false) let showDialog = ref(false)
const loading = ref(false) const loading = ref(false)
@ -134,48 +117,44 @@ const formRules = computed(() => {
return { return {
campus_id: [ campus_id: [
{ required: true, message: t('campusIdPlaceholder'), trigger: 'blur' }, { required: true, message: t('campusIdPlaceholder'), trigger: 'blur' },
],
]
,
venue_name: [ venue_name: [
{ required: true, message: t('venueNamePlaceholder'), trigger: 'blur' }, { required: true, message: t('venueNamePlaceholder'), trigger: 'blur' },
],
]
,
capacity: [ capacity: [
{ required: true, message: t('capacityPlaceholder'), trigger: 'blur' }, { required: true, message: t('capacityPlaceholder'), trigger: 'blur' },
], { validator: (rule: any, value: string, callback: any) => { if (value && !/^\d{1,500}$/.test(value)) { callback(new Error(t('generateBetween')))} else { callback() }}},
]
,
availability_status: [ availability_status: [
{ { required: true, message: t('availabilityStatusPlaceholder'), trigger: 'blur' },
required: true,
message: t('availabilityStatusPlaceholder'), ]
trigger: 'blur', ,
},
],
time_range_type: [ time_range_type: [
{ { required: true, message: t('timeRangeTypePlaceholder'), trigger: 'blur' },
required: true,
message: t('timeRangeTypePlaceholder'), ]
trigger: 'blur', ,
},
],
time_range_start: [ time_range_start: [
{ { required: true, message: t('timeRangeStartPlaceholder'), trigger: 'blur' },
required: true,
message: t('timeRangeStartPlaceholder'), ]
trigger: 'blur', ,
},
],
time_range_end: [ time_range_end: [
{ { required: true, message: t('timeRangeEndPlaceholder'), trigger: 'blur' },
required: true,
message: t('timeRangeEndPlaceholder'), ]
trigger: 'blur', ,
},
],
fixed_time_ranges: [ fixed_time_ranges: [
{ { required: true, message: t('fixedTimeRangesPlaceholder'), trigger: 'blur' },
required: true,
message: t('fixedTimeRangesPlaceholder'), ]
trigger: 'blur', ,
},
],
} }
}) })
@ -195,13 +174,11 @@ const confirm = async (formEl: FormInstance | undefined) => {
let data = formData let data = formData
save(data) save(data).then(res => {
.then((res) => {
loading.value = false loading.value = false
showDialog.value = false showDialog.value = false
emit('complete') emit('complete')
}) }).catch(err => {
.catch((err) => {
loading.value = false loading.value = false
}) })
} }
@ -209,14 +186,31 @@ const confirm = async (formEl: FormInstance | undefined) => {
} }
// //
let availability_statusList = ref([])
const availability_statusDictList = async () => {
availability_statusList.value = await (await useDictionary('SiteStatus')).data.dictionary
}
availability_statusDictList();
watch(() => availability_statusList.value, () => { formData.availability_status = availability_statusList.value[0].value })
let time_range_typeList = ref([])
const time_range_typeDictList = async () => {
time_range_typeList.value = await (await useDictionary('ALLOTTED_TIME')).data.dictionary
}
time_range_typeDictList();
watch(() => time_range_typeList.value, () => { formData.time_range_type = time_range_typeList.value[0].value })
const campusIdList = ref([] as any[])
const setCampusIdList = async () => {
campusIdList.value = await (await getWithCampusList({})).data
}
setCampusIdList()
const setFormData = async (row: any = null) => { const setFormData = async (row: any = null) => {
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
loading.value = true loading.value = true
if(row){ if(row){
const data = await (await getVenueInfo(row.id)).data const data = await (await getVenueInfo(row.id)).data
if (data) if (data) Object.keys(formData).forEach((key: string) => {
Object.keys(formData).forEach((key: string) => {
if (data[key] != undefined) formData[key] = data[key] if (data[key] != undefined) formData[key] = data[key]
}) })
} }
@ -234,12 +228,7 @@ const mobileVerify = (rule: any, value: any, callback: any) => {
// //
const idCardVerify = (rule: any, value: any, callback: any) => { const idCardVerify = (rule: any, value: any, callback: any) => {
if ( if (value && !/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)) {
value &&
!/^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(
value
)
) {
callback(new Error(t('generateIdCard'))) callback(new Error(t('generateIdCard')))
} else { } else {
callback() callback()
@ -266,7 +255,7 @@ const numberVerify = (rule: any, value: any, callback: any) => {
defineExpose({ defineExpose({
showDialog, showDialog,
setFormData, setFormData
}) })
</script> </script>

258
admin/src/app/views/venue/venue.vue

@ -1,6 +1,7 @@
<template> <template>
<div class="main-container"> <div class="main-container">
<el-card class="box-card !border-none" shadow="never"> <el-card class="box-card !border-none" shadow="never">
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<span class="text-lg">{{pageName}}</span> <span class="text-lg">{{pageName}}</span>
<el-button type="primary" @click="addEvent"> <el-button type="primary" @click="addEvent">
@ -8,167 +9,109 @@
</el-button> </el-button>
</div> </div>
<el-card <el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
class="box-card !border-none my-[10px] table-search-wrap" <el-form :inline="true" :model="venueTable.searchParam" ref="searchFormRef">
shadow="never"
>
<el-form
:inline="true"
:model="venueTable.searchParam"
ref="searchFormRef"
>
<el-form-item :label="t('campusId')" prop="campus_id"> <el-form-item :label="t('campusId')" prop="campus_id">
<el-input <el-select class="w-[280px]" v-model="venueTable.searchParam.campus_id" clearable :placeholder="t('campusIdPlaceholder')">
v-model="venueTable.searchParam.campus_id" <el-option
:placeholder="t('campusIdPlaceholder')" v-for="(item, index) in campusIdList"
/> :key="index"
:label="item['campus_name']"
:value="item['id']"
/>
</el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('venueName')" prop="venue_name"> <el-form-item :label="t('venueName')" prop="venue_name">
<el-input <el-input v-model="venueTable.searchParam.venue_name" :placeholder="t('venueNamePlaceholder')" />
v-model="venueTable.searchParam.venue_name"
:placeholder="t('venueNamePlaceholder')"
/>
</el-form-item>
<el-form-item :label="t('capacity')" prop="capacity">
<el-input
v-model="venueTable.searchParam.capacity"
:placeholder="t('capacityPlaceholder')"
/>
</el-form-item> </el-form-item>
<el-form-item
:label="t('availabilityStatus')" <el-form-item :label="t('availabilityStatus')" prop="availability_status">
prop="availability_status" <el-select class="w-[280px]" v-model="venueTable.searchParam.availability_status" clearable :placeholder="t('availabilityStatusPlaceholder')">
> <el-option label="全部" value=""></el-option>
<el-input <el-option
v-model="venueTable.searchParam.availability_status" v-for="(item, index) in availability_statusList"
:placeholder="t('availabilityStatusPlaceholder')" :key="index"
:label="item.name"
:value="item.value"
/> />
</el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('timeRangeType')" prop="time_range_type"> <el-form-item :label="t('timeRangeType')" prop="time_range_type">
<el-input <el-select class="w-[280px]" v-model="venueTable.searchParam.time_range_type" clearable :placeholder="t('timeRangeTypePlaceholder')">
v-model="venueTable.searchParam.time_range_type" <el-option label="全部" value=""></el-option>
:placeholder="t('timeRangeTypePlaceholder')" <el-option
/> v-for="(item, index) in time_range_typeList"
:key="index"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('timeRangeStart')" prop="time_range_start">
<el-input <el-form-item :label="t('createdAt')" prop="created_at">
v-model="venueTable.searchParam.time_range_start" <el-date-picker v-model="venueTable.searchParam.created_at" type="datetimerange" format="YYYY-MM-DD hh:mm:ss"
:placeholder="t('timeRangeStartPlaceholder')" :start-placeholder="t('startDate')" :end-placeholder="t('endDate')" />
/>
</el-form-item>
<el-form-item :label="t('timeRangeEnd')" prop="time_range_end">
<el-input
v-model="venueTable.searchParam.time_range_end"
:placeholder="t('timeRangeEndPlaceholder')"
/>
</el-form-item> </el-form-item>
<el-form-item :label="t('fixedTimeRanges')" prop="fixed_time_ranges">
<el-input <el-form-item :label="t('updatedAt')" prop="updated_at">
v-model="venueTable.searchParam.fixed_time_ranges" <el-date-picker v-model="venueTable.searchParam.updated_at" type="datetimerange" format="YYYY-MM-DD hh:mm:ss"
:placeholder="t('fixedTimeRangesPlaceholder')" :start-placeholder="t('startDate')" :end-placeholder="t('endDate')" />
/>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="loadVenueList()">{{ <el-button type="primary" @click="loadVenueList()">{{ t('search') }}</el-button>
t('search') <el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
}}</el-button>
<el-button @click="resetForm(searchFormRef)">{{
t('reset')
}}</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-card> </el-card>
<div class="mt-[10px]"> <div class="mt-[10px]">
<el-table <el-table :data="venueTable.data" size="large" v-loading="venueTable.loading">
:data="venueTable.data"
size="large"
v-loading="venueTable.loading"
>
<template #empty> <template #empty>
<span>{{ !venueTable.loading ? t('emptyData') : '' }}</span> <span>{{ !venueTable.loading ? t('emptyData') : '' }}</span>
</template> </template>
<el-table-column <el-table-column prop="campus_id_name" :label="t('campusId')" min-width="120" :show-overflow-tooltip="true"/>
prop="campus_id"
:label="t('campusId')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column <el-table-column prop="venue_name" :label="t('venueName')" min-width="120" :show-overflow-tooltip="true"/>
prop="venue_name"
:label="t('venueName')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column <el-table-column prop="capacity" :label="t('capacity')" min-width="120" :show-overflow-tooltip="true"/>
prop="capacity"
:label="t('capacity')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column <el-table-column :label="t('availabilityStatus')" min-width="180" align="center" :show-overflow-tooltip="true">
prop="availability_status" <template #default="{ row }">
:label="t('availabilityStatus')" <div v-for="(item, index) in availability_statusList">
min-width="120" <div v-if="item.value == row.availability_status">{{ item.name }}</div>
:show-overflow-tooltip="true" </div>
/> </template>
</el-table-column>
<el-table-column
prop="time_range_type"
:label="t('timeRangeType')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column <el-table-column :label="t('timeRangeType')" min-width="180" align="center" :show-overflow-tooltip="true">
prop="time_range_start" <template #default="{ row }">
:label="t('timeRangeStart')" <div v-for="(item, index) in time_range_typeList">
min-width="120" <div v-if="item.value == row.time_range_type">{{ item.name }}</div>
:show-overflow-tooltip="true" </div>
/> </template>
</el-table-column>
<el-table-column <el-table-column prop="created_at" :label="t('createdAt')" min-width="120" :show-overflow-tooltip="true"/>
prop="time_range_end"
:label="t('timeRangeEnd')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column <el-table-column prop="updated_at" :label="t('updatedAt')" min-width="120" :show-overflow-tooltip="true"/>
prop="fixed_time_ranges"
:label="t('fixedTimeRanges')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column <el-table-column :label="t('operation')" fixed="right" min-width="120">
:label="t('operation')"
fixed="right"
min-width="120"
>
<template #default="{ row }"> <template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{ <el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
t('edit') <el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{
t('delete')
}}</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<div class="mt-[16px] flex justify-end"> <div class="mt-[16px] flex justify-end">
<el-pagination <el-pagination v-model:current-page="venueTable.page" v-model:page-size="venueTable.limit"
v-model:current-page="venueTable.page" layout="total, sizes, prev, pager, next, jumper" :total="venueTable.total"
v-model:page-size="venueTable.limit" @size-change="loadVenueList()" @current-change="loadVenueList" />
layout="total, sizes, prev, pager, next, jumper"
:total="venueTable.total"
@size-change="loadVenueList()"
@current-change="loadVenueList"
/>
</div> </div>
</div> </div>
@ -181,13 +124,13 @@
import { reactive, ref, watch } from 'vue' import { reactive, ref, watch } from 'vue'
import { t } from '@/lang' import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict' import { useDictionary } from '@/app/api/dict'
import { getVenueList, deleteVenue } from '@/app/api/venue' import { getVenueList, deleteVenue, getWithCampusList } from '@/app/api/venue'
import { img } from '@/utils/common' import { img } from '@/utils/common'
import { ElMessageBox,FormInstance } from 'element-plus' import { ElMessageBox,FormInstance } from 'element-plus'
import Edit from '@/app/views/venue/components/venue-edit.vue' import Edit from '@/app/views/venue/components/venue-edit.vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const route = useRoute() const route = useRoute()
const pageName = route.meta.title const pageName = route.meta.title;
let venueTable = reactive({ let venueTable = reactive({
page: 1, page: 1,
@ -196,15 +139,14 @@ let venueTable = reactive({
loading: true, loading: true,
data: [], data: [],
searchParam:{ searchParam:{
campus_id: '', "campus_id":"",
venue_name: '', "venue_name":"",
capacity: '', "capacity":"",
availability_status: '', "availability_status":"",
time_range_type: '', "time_range_type":"",
time_range_start: '', "created_at":"",
time_range_end: '', "updated_at":""
fixed_time_ranges: '', }
},
}) })
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
@ -213,6 +155,16 @@ const searchFormRef = ref<FormInstance>()
const selectData = ref<any[]>([]) const selectData = ref<any[]>([])
// //
const availability_statusList = ref([] as any[])
const availability_statusDictList = async () => {
availability_statusList.value = await (await useDictionary('SiteStatus')).data.dictionary
}
availability_statusDictList();
const time_range_typeList = ref([] as any[])
const time_range_typeDictList = async () => {
time_range_typeList.value = await (await useDictionary('ALLOTTED_TIME')).data.dictionary
}
time_range_typeDictList();
/** /**
* 获取场地列表 * 获取场地列表
@ -224,14 +176,12 @@ const loadVenueList = (page: number = 1) => {
getVenueList({ getVenueList({
page: venueTable.page, page: venueTable.page,
limit: venueTable.limit, limit: venueTable.limit,
...venueTable.searchParam, ...venueTable.searchParam
}) }).then(res => {
.then((res) => {
venueTable.loading = false venueTable.loading = false
venueTable.data = res.data.data venueTable.data = res.data.data
venueTable.total = res.data.total venueTable.total = res.data.total
}) }).catch(() => {
.catch(() => {
venueTable.loading = false venueTable.loading = false
}) })
} }
@ -260,19 +210,27 @@ const editEvent = (data: any) => {
* 删除场地 * 删除场地
*/ */
const deleteEvent = (id: number) => { const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('venueDeleteTips'), t('warning'), { ElMessageBox.confirm(t('venueDeleteTips'), t('warning'),
{
confirmButtonText: t('confirm'), confirmButtonText: t('confirm'),
cancelButtonText: t('cancel'), cancelButtonText: t('cancel'),
type: 'warning', type: 'warning',
}).then(() => { }
deleteVenue(id) ).then(() => {
.then(() => { deleteVenue(id).then(() => {
loadVenueList() loadVenueList()
}).catch(() => {
}) })
.catch(() => {})
}) })
} }
const campusIdList = ref([])
const setCampusIdList = async () => {
campusIdList.value = await (await getWithCampusList({})).data
}
setCampusIdList()
const resetForm = (formEl: FormInstance | undefined) => { const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.resetFields() formEl.resetFields()

321
admin/src/components/TencentMapPicker.vue

@ -12,9 +12,7 @@
<div <div
v-if="!props.modelValue.lat || !props.modelValue.lng" v-if="!props.modelValue.lat || !props.modelValue.lng"
class="map-placeholder" class="map-placeholder"
> ></div>
{{ props.placeholder }}
</div>
</div> </div>
<div class="address-search"> <div class="address-search">
<el-select <el-select
@ -55,10 +53,7 @@
:value="item.id" :value="item.id"
/> />
</el-select> </el-select>
<el-input <el-input v-model="detailAddress" placeholder="输入地区" />
v-model="detailAddress"
:placeholder="t('detailAddressPlaceholder')"
/>
<el-button <el-button
type="primary" type="primary"
@click="handleAddressSearch" @click="handleAddressSearch"
@ -78,11 +73,13 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted, watch, computed } from 'vue' import { ref, onMounted, watch, computed, nextTick, onBeforeUnmount } from 'vue'
import { getAreaListByPid, getAreaByCode } from '@/app/api/sys' import { ElMessage } from 'element-plus'
import { createMarker, latLngToAddress, addressToLatLng } from '@/utils/qqmap' import { getAreaListByPid } from '@/app/api/sys'
import { createMarker, addressToLatLng } from '@/utils/qqmap'
import { t } from '@/lang' import { t } from '@/lang'
// ====================== Props ======================
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
type: Object, type: Object,
@ -104,6 +101,7 @@ const props = defineProps({
const emit = defineEmits(['update:visible', 'update:modelValue', 'confirm']) const emit = defineEmits(['update:visible', 'update:modelValue', 'confirm'])
// ====================== ======================
const dialogVisible = computed({ const dialogVisible = computed({
get() { get() {
return props.visible return props.visible
@ -113,10 +111,74 @@ const dialogVisible = computed({
}, },
}) })
watch(dialogVisible, (newVal) => { //
emit('update:modelValue', newVal) let map: any = null
let marker: any = null
const mapKey = ref('YOUR_API_KEY') // API Key
let mapScript: HTMLScriptElement | null = null
let resizeTimer: number | null = null
//
const province = ref('')
const city = ref('')
const district = ref('')
const detailAddress = ref('')
const provinceList = ref<any[]>([])
const cityList = ref<any[]>([])
const districtList = ref<any[]>([])
// ====================== ======================
onMounted(() => {
// SDK
const preloadScript = document.createElement('script')
preloadScript.src = `https://map.qq.com/api/gljs?key= ${mapKey.value}`
document.head.appendChild(preloadScript)
}) })
// ====================== ======================
watch(
dialogVisible,
async (newVal) => {
if (newVal) {
try {
//
cleanupMap()
// DOM
await nextTick()
//
const container = document.getElementById('container')
if (!container) throw new Error('地图容器未找到')
// SDK
await loadMapSDK()
//
initMap()
//
const res = await getAreaListByPid(0)
provinceList.value = res.data
//
if (props.modelValue.address) {
await parseAndSetAddress(props.modelValue.address)
}
// resize
bindResizeListener()
} catch (error) {
handleError(error)
}
} else {
cleanupMap()
}
},
{ immediate: true }
)
// ====================== ======================
const handleClose = (done: () => void) => { const handleClose = (done: () => void) => {
done() done()
} }
@ -126,80 +188,164 @@ const handleConfirm = () => {
ElMessage.warning(t('mapPickerWarning')) ElMessage.warning(t('mapPickerWarning'))
return return
} }
//
const provinceName = province.value
? provinceList.value.find((p) => p.id === province.value)?.name || ''
: ''
const cityName = city.value
? cityList.value.find((c) => c.id === city.value)?.name || ''
: ''
const districtName = district.value
? districtList.value.find((d) => d.id === district.value)?.name || ''
: ''
const fullAddress = `${provinceName}${cityName}${districtName}${detailAddress.value}`
emit('confirm', { emit('confirm', {
lat: props.modelValue.lat, lat: props.modelValue.lat,
lng: props.modelValue.lng, lng: props.modelValue.lng,
address: detailAddress.value, address: fullAddress,
}) })
dialogVisible.value = false dialogVisible.value = false
} }
// //
let map: any const parseAndSetAddress = async (address: string) => {
let marker: any //
const mapKey = ref('') const { provinceName, cityName, districtName, detail } = parseAddress(address)
detailAddress.value = detail
// // 1.
const province = ref('') if (provinceName) {
const city = ref('') const provinceItem = provinceList.value.find((p) =>
const district = ref('') p.name.includes(provinceName)
const detailAddress = ref('') )
const provinceList = ref<any[]>([]) if (provinceItem) {
const cityList = ref<any[]>([]) province.value = provinceItem.id
const districtList = ref<any[]>([])
// // 2.
const initMapScript = () => { const cityRes = await getAreaListByPid(province.value)
const container = document.getElementById('container') cityList.value = cityRes.data
if (!container) return
mapScript = document.createElement('script') if (cityName) {
mapKey.value = 'IZQBZ-3UHEU-WTCVD-2464U-I5N4V-ZFFU3' const cityItem = cityList.value.find((c) => c.name.includes(cityName))
mapScript.type = 'text/javascript' if (cityItem) {
mapScript.src = city.value = cityItem.id
'https://map.qq.com/api/gljs?libraries=tools,service&v=1.exp&key=IZQBZ-3UHEU-WTCVD-2464U-I5N4V-ZFFU3'
document.body.appendChild(mapScript) // 3.
mapScript.onload = () => { const districtRes = await getAreaListByPid(city.value)
setTimeout(() => { districtList.value = districtRes.data
initMap()
}, 500) if (districtName) {
const districtItem = districtList.value.find((d) =>
d.name.includes(districtName)
)
if (districtItem) {
district.value = districtItem.id
}
}
}
}
}
} }
mapScript.onerror = (error) => { //
console.error('地图脚本加载失败:', error) handleAddressSearch()
} }
//
const parseAddress = (address: string) => {
let provinceName = ''
let cityName = ''
let districtName = ''
let detail = address
// //
const provinceMatch = address.match(/^([^省市自治区]+[省市区]|[^市]+市)/)
if (provinceMatch) {
provinceName = provinceMatch[0]
detail = address.slice(provinceName.length)
} }
let mapScript: HTMLScriptElement | null = null //
const cityMatch = detail.match(/^([^市区]+市)/)
if (cityMatch) {
cityName = cityMatch[0]
detail = detail.slice(cityName.length)
}
watch( // /
dialogVisible, const districtMatch = detail.match(/^([^区县]+[区县])/)
(newVal) => { if (districtMatch) {
if (newVal) { districtName = districtMatch[0]
if (mapScript) { detail = detail.slice(districtName.length)
document.body.removeChild(mapScript)
mapScript = null
} }
initMapScript()
getAreaListByPid(0).then((res) => { return {
provinceList.value = res.data provinceName,
}) cityName,
} else { districtName,
detail: detail.trim() || '',
}
}
// ====================== ======================
const cleanupMap = () => {
if (mapScript) { if (mapScript) {
document.body.removeChild(mapScript) document.body.removeChild(mapScript)
mapScript = null mapScript = null
} }
if (map) {
map.destroy()
map = null map = null
}
marker = null marker = null
if (resizeTimer) {
clearTimeout(resizeTimer)
resizeTimer = null
}
window.removeEventListener('resize', handleResize)
}
const loadMapSDK = (): Promise<void> => {
return new Promise((resolve, reject) => {
mapKey.value = 'AKTBZ-OGICT-E5NXQ-LGEGK-H5AJ5-M2BOX'
mapScript = document.createElement('script')
mapScript.type = 'text/javascript'
mapScript.src = `https://map.qq.com/api/gljs?libraries=tools ,service&v=1.exp&key=${mapKey.value}`
mapScript.onload = () => {
if ((window as any).TMap) {
resolve()
} else {
reject(new Error('TMap未定义'))
}
}
mapScript.onerror = (error) => {
reject(error)
}
document.body.appendChild(mapScript)
})
} }
},
{ immediate: true }
)
const initMap = () => { const initMap = () => {
console.log('initMap') const container = document.getElementById('container')
if (!(window as any).TMap || !container) {
throw new Error('地图SDK未加载或容器不存在')
}
const TMap = (window as any).TMap const TMap = (window as any).TMap
const center = new TMap.LatLng(39.90403, 116.407526) const center = new TMap.LatLng(39.90403, 116.407526)
map = new TMap.Map('container', { map = new TMap.Map('container', {
center, center,
zoom: 12, zoom: 12,
@ -221,20 +367,37 @@ const initMap = () => {
}) })
} }
// const bindResizeListener = () => {
const handleProvinceChange = (val: string) => { window.addEventListener('resize', handleResize)
getAreaListByPid(val).then((res) => { }
const handleResize = () => {
if (resizeTimer) clearTimeout(resizeTimer)
resizeTimer = setTimeout(() => {
map?.setSize()
}, 300)
}
// ====================== ======================
const handleProvinceChange = async (val: string) => {
try {
const res = await getAreaListByPid(val)
cityList.value = res.data cityList.value = res.data
city.value = '' city.value = ''
district.value = '' district.value = ''
}) } catch (error) {
handleError(error)
}
} }
const handleCityChange = (val: string) => { const handleCityChange = async (val: string) => {
getAreaListByPid(val).then((res) => { try {
const res = await getAreaListByPid(val)
districtList.value = res.data districtList.value = res.data
district.value = '' district.value = ''
}) } catch (error) {
handleError(error)
}
} }
const handleDistrictChange = (val: string) => { const handleDistrictChange = (val: string) => {
@ -242,7 +405,8 @@ const handleDistrictChange = (val: string) => {
} }
// //
const handleAddressSearch = () => { const handleAddressSearch = async () => {
try {
const address = [ const address = [
province.value province.value
? provinceList.value.find((p) => p.id === province.value)?.name ? provinceList.value.find((p) => p.id === province.value)?.name
@ -254,8 +418,11 @@ const handleAddressSearch = () => {
detailAddress.value, detailAddress.value,
].join('') ].join('')
addressToLatLng({ mapKey: mapKey.value, address }).then( const { message, result } = await addressToLatLng({
({ message, result }) => { mapKey: mapKey.value,
address,
})
if (message == 'Success' || message == 'query ok') { if (message == 'Success' || message == 'query ok') {
const latLng = new (window as any).TMap.LatLng( const latLng = new (window as any).TMap.LatLng(
result.location.lat, result.location.lat,
@ -272,17 +439,25 @@ const handleAddressSearch = () => {
address: detailAddress.value, address: detailAddress.value,
}) })
} }
} catch (error) {
handleError(error)
} }
) }
// ====================== ======================
const handleError = (error: any) => {
console.error('地图组件错误:', error)
ElMessage.error(t('mapLoadFailed'))
dialogVisible.value = false
} }
// //
watch( watch(
() => props.modelValue, () => props.modelValue,
(newVal) => { (newVal) => {
if (newVal.lat && newVal.lng) { if (newVal.lat && newVal.lng && map) {
const latLng = new (window as any).TMap.LatLng(newVal.lat, newVal.lng) const latLng = new (window as any).TMap.LatLng(newVal.lat, newVal.lng)
map?.setCenter(latLng) map.setCenter(latLng)
marker?.updateGeometries({ marker?.updateGeometries({
id: 'center', id: 'center',
position: latLng, position: latLng,
@ -291,6 +466,10 @@ watch(
}, },
{ immediate: true } { immediate: true }
) )
onBeforeUnmount(() => {
cleanupMap()
})
</script> </script>
<style scoped> <style scoped>

9
niucloud/app/adminapi/controller/venue/Venue.php

@ -33,9 +33,8 @@ class Venue extends BaseAdminController
["capacity",""], ["capacity",""],
["availability_status",""], ["availability_status",""],
["time_range_type",""], ["time_range_type",""],
["time_range_start",""], ["created_at",""],
["time_range_end",""], ["updated_at",""]
["fixed_time_ranges",""]
]); ]);
return success((new VenueService())->getPage($data)); return success((new VenueService())->getPage($data));
} }
@ -103,4 +102,8 @@ class Venue extends BaseAdminController
} }
public function getCampusAll(){
return success(( new VenueService())->getCampusAll());
}
} }

3
niucloud/app/adminapi/route/venue.php

@ -14,6 +14,7 @@ use think\facade\Route;
use app\adminapi\middleware\AdminCheckRole; use app\adminapi\middleware\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken; use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog; use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- venue // USER_CODE_BEGIN -- venue
Route::group('venue', function () { Route::group('venue', function () {
@ -29,6 +30,8 @@ Route::group('venue', function () {
//删除场地 //删除场地
Route::delete('venue/:id', 'venue.Venue/del'); Route::delete('venue/:id', 'venue.Venue/del');
Route::get('campus_all','venue.Venue/getCampusAll');
})->middleware([ })->middleware([
AdminCheckToken::class, AdminCheckToken::class,
AdminCheckRole::class, AdminCheckRole::class,

86
niucloud/app/model/venue/Venue.php

@ -9,19 +9,21 @@
// | Author: Niucloud Team // | Author: Niucloud Team
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
namespace app\model\campus; namespace app\model\venue;
use core\base\BaseModel; use core\base\BaseModel;
use think\model\concern\SoftDelete; use think\model\concern\SoftDelete;
use think\model\relation\HasMany; use think\model\relation\HasMany;
use think\model\relation\HasOne; use think\model\relation\HasOne;
use app\model\campus\Campus;
/** /**
* 校区模型 * 场地模型
* Class Campus * Class Venue
* @package app\model\campus * @package app\model\venue
*/ */
class Campus extends BaseModel class Venue extends BaseModel
{ {
use SoftDelete; use SoftDelete;
@ -36,13 +38,13 @@ class Campus extends BaseModel
* 模型名称 * 模型名称
* @var string * @var string
*/ */
protected $name = 'campus'; protected $name = 'venue';
/** /**
* 定义软删除标记字段. * 定义软删除标记字段.
* @var string * @var string
*/ */
protected $deleteTime = 'delete_time'; protected $deleteTime = 'deleted_at';
/** /**
* 定义软删除字段的默认值. * 定义软删除字段的默认值.
@ -51,44 +53,96 @@ class Campus extends BaseModel
protected $defaultSoftDelete = 0; protected $defaultSoftDelete = 0;
/** /**
* 搜索器:校区校区名称 * 搜索器:场地校区
* @param $value * @param $value
* @param $data * @param $data
*/ */
public function searchCampusNameAttr($query, $value, $data) public function searchCampusIdAttr($query, $value, $data)
{ {
if ($value) { if ($value) {
$query->where("campus_name", "like", "%".$value."%"); $query->where("campus_id", $value);
} }
} }
/** /**
* 搜索器:校区校区地址 * 搜索器:场地场地名称
* @param $value * @param $value
* @param $data * @param $data
*/ */
public function searchCampusAddressAttr($query, $value, $data) public function searchVenueNameAttr($query, $value, $data)
{ {
if ($value) { if ($value) {
$query->where("campus_address", $value); $query->where("venue_name", $value);
} }
} }
/** /**
* 搜索器:校区校区状态 * 搜索器:场地场地可容纳人数上限
* @param $value * @param $value
* @param $data * @param $data
*/ */
public function searchCampusStatusAttr($query, $value, $data) public function searchCapacityAttr($query, $value, $data)
{ {
if ($value) { if ($value) {
$query->where("campus_status", $value); $query->where("capacity", $value);
} }
} }
/**
* 搜索器:场地场地可用状态
* @param $value
* @param $data
*/
public function searchAvailabilityStatusAttr($query, $value, $data)
{
if ($value) {
$query->where("availability_status", $value);
}
}
/**
* 搜索器:场地场地可用时间范围类型
* @param $value
* @param $data
*/
public function searchTimeRangeTypeAttr($query, $value, $data)
{
if ($value) {
$query->where("time_range_type", $value);
}
}
/**
* 搜索器:场地创建时间
* @param $value
* @param $data
*/
public function searchCreatedAtAttr($query, $value, $data)
{
if ($value) {
$query->where("created_at", $value);
}
}
/**
* 搜索器:场地修改时间
* @param $value
* @param $data
*/
public function searchUpdatedAtAttr($query, $value, $data)
{
if ($value) {
$query->where("updated_at", $value);
}
}
public function campus(){
return $this->hasOne(Campus::class, 'id', 'campus_id')->joinType('left')->withField('campus_name,id')->bind(['campus_id_name'=>'campus_name']);
}
} }

11
niucloud/app/service/admin/campus/CampusService.php

@ -55,6 +55,7 @@ class CampusService extends BaseAdminService
$info = $this->model->field($field)->where([['id', "=", $id]])->findOrEmpty()->toArray(); $info = $this->model->field($field)->where([['id', "=", $id]])->findOrEmpty()->toArray();
$info['campus_status'] = strval($info['campus_status']); $info['campus_status'] = strval($info['campus_status']);
$info['campus_coordinates'] = json_decode($info['campus_coordinates'], true);
return $info; return $info;
} }
@ -65,6 +66,10 @@ class CampusService extends BaseAdminService
*/ */
public function add(array $data) public function add(array $data)
{ {
if (is_array($data['campus_coordinates'])) {
$data['campus_address'] = $data['campus_coordinates']['address'];
$data['campus_coordinates'] = json_encode($data['campus_coordinates']);
}
$res = $this->model->create($data); $res = $this->model->create($data);
return $res->id; return $res->id;
@ -78,7 +83,10 @@ class CampusService extends BaseAdminService
*/ */
public function edit(int $id, array $data) public function edit(int $id, array $data)
{ {
if (is_array($data['campus_coordinates'])) {
$data['campus_address'] = $data['campus_coordinates']['address'];
$data['campus_coordinates'] = json_encode($data['campus_coordinates']);
}
$this->model->where([['id', '=', $id]])->update($data); $this->model->where([['id', '=', $id]])->update($data);
return true; return true;
} }
@ -96,5 +104,4 @@ class CampusService extends BaseAdminService
} }
} }

2
niucloud/app/service/admin/student_courses/StudentCoursesService.php

@ -21,7 +21,7 @@ use core\base\BaseAdminService;
* Class CampusService * Class CampusService
* @package app\service\admin\campus * @package app\service\admin\campus
*/ */
class CampusService extends BaseAdminService class StudentCoursesService extends BaseAdminService
{ {
public function __construct() public function __construct()
{ {

14
niucloud/app/service/admin/venue/VenueService.php

@ -12,6 +12,7 @@
namespace app\service\admin\venue; namespace app\service\admin\venue;
use app\model\venue\Venue; use app\model\venue\Venue;
use app\model\campus\Campus;
use core\base\BaseAdminService; use core\base\BaseAdminService;
@ -37,9 +38,9 @@ class VenueService extends BaseAdminService
public function getPage(array $where = []) public function getPage(array $where = [])
{ {
$field = 'id,campus_id,venue_name,capacity,availability_status,time_range_type,time_range_start,time_range_end,fixed_time_ranges,created_at,updated_at,deleted_at'; $field = 'id,campus_id,venue_name,capacity,availability_status,time_range_type,time_range_start,time_range_end,fixed_time_ranges,created_at,updated_at,deleted_at';
$order = 'id desc'; $order = 'updated_at desc';
$search_model = $this->model->withSearch(["id","campus_id","venue_name","capacity","availability_status","time_range_type","time_range_start","time_range_end","fixed_time_ranges"], $where)->field($field)->order($order); $search_model = $this->model->withSearch(["campus_id","venue_name","capacity","availability_status","time_range_type","created_at","updated_at"], $where)->with(['campus'])->field($field)->order($order);
$list = $this->pageQuery($search_model); $list = $this->pageQuery($search_model);
return $list; return $list;
} }
@ -53,7 +54,9 @@ class VenueService extends BaseAdminService
{ {
$field = 'id,campus_id,venue_name,capacity,availability_status,time_range_type,time_range_start,time_range_end,fixed_time_ranges,created_at,updated_at,deleted_at'; $field = 'id,campus_id,venue_name,capacity,availability_status,time_range_type,time_range_start,time_range_end,fixed_time_ranges,created_at,updated_at,deleted_at';
$info = $this->model->field($field)->where([['id', "=", $id]])->findOrEmpty()->toArray(); $info = $this->model->field($field)->where([['id', "=", $id]])->with(['campus'])->findOrEmpty()->toArray();
$info['availability_status'] = strval($info['availability_status']);
$info['time_range_type'] = strval($info['time_range_type']);
return $info; return $info;
} }
@ -95,5 +98,10 @@ class VenueService extends BaseAdminService
} }
public function getCampusAll(){
$campusModel = new Campus();
return $campusModel->select()->toArray();
}
} }

3
niucloud/app/validate/venue/Venue.php

@ -22,7 +22,7 @@ class Venue extends BaseValidate
protected $rule = [ protected $rule = [
'campus_id' => 'require', 'campus_id' => 'require',
'venue_name' => 'require', 'venue_name' => 'require',
'capacity' => 'require', 'capacity' => 'require|between:1,500',
'availability_status' => 'require', 'availability_status' => 'require',
'time_range_type' => 'require', 'time_range_type' => 'require',
]; ];
@ -31,6 +31,7 @@ class Venue extends BaseValidate
'campus_id.require' => ['common_validate.require', ['campus_id']], 'campus_id.require' => ['common_validate.require', ['campus_id']],
'venue_name.require' => ['common_validate.require', ['venue_name']], 'venue_name.require' => ['common_validate.require', ['venue_name']],
'capacity.require' => ['common_validate.require', ['capacity']], 'capacity.require' => ['common_validate.require', ['capacity']],
'capacity.between' => ['common_validate.between', ['capacity','1','500']],
'availability_status.require' => ['common_validate.require', ['availability_status']], 'availability_status.require' => ['common_validate.require', ['availability_status']],
'time_range_type.require' => ['common_validate.require', ['time_range_type']], 'time_range_type.require' => ['common_validate.require', ['time_range_type']],
]; ];

Loading…
Cancel
Save