Browse Source

找回代码

yuhongzhe
王泽彦 11 months ago
parent
commit
c95c810357
  1. 9
      admin/components.d.ts
  2. 23
      admin/src/app/api/campus.ts
  3. 36
      admin/src/app/lang/zh-cn/campus.campus.json
  4. 324
      admin/src/app/views/campus/campus.vue
  5. 8
      admin/src/app/views/campus/components/campus-edit.vue
  6. 248
      admin/src/components/TencentMapPicker.vue
  7. 37
      niucloud/app/adminapi/route/campus.php
  8. 94
      niucloud/app/model/campus/Campus.php
  9. 100
      niucloud/app/service/admin/campus/CampusService.php
  10. 35
      niucloud/app/validate/campus/Campus.php

9
admin/components.d.ts

@ -38,6 +38,7 @@ declare module '@vue/runtime-core' {
ElMenu: typeof import('element-plus/es')['ElMenu'] ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption'] ElOption: typeof import('element-plus/es')['ElOption']
ElPageHeader: typeof import('element-plus/es')['ElPageHeader']
ElPagination: typeof import('element-plus/es')['ElPagination'] ElPagination: typeof import('element-plus/es')['ElPagination']
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']
@ -45,11 +46,18 @@ declare module '@vue/runtime-core' {
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']
ElStep: typeof import('element-plus/es')['ElStep']
ElSteps: typeof import('element-plus/es')['ElSteps']
ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
ElSwitch: typeof import('element-plus/es')['ElSwitch'] ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable'] ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag']
ElTooltip: typeof import('element-plus/es')['ElTooltip'] ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTree: typeof import('element-plus/es')['ElTree']
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
ElUpload: typeof import('element-plus/es')['ElUpload'] ElUpload: typeof import('element-plus/es')['ElUpload']
ExportSure: typeof import('./src/components/export-sure/index.vue')['default'] ExportSure: typeof import('./src/components/export-sure/index.vue')['default']
HeatMap: typeof import('./src/components/heat-map/index.vue')['default'] HeatMap: typeof import('./src/components/heat-map/index.vue')['default']
@ -60,6 +68,7 @@ declare module '@vue/runtime-core' {
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
SelectArea: typeof import('./src/components/select-area/index.vue')['default'] SelectArea: typeof import('./src/components/select-area/index.vue')['default']
SelectIcon: typeof import('./src/components/select-icon/index.vue')['default'] SelectIcon: typeof import('./src/components/select-icon/index.vue')['default']
TencentMapPicker: typeof import('./src/components/TencentMapPicker.vue')['default']
UploadAttachment: typeof import('./src/components/upload-attachment/index.vue')['default'] UploadAttachment: typeof import('./src/components/upload-attachment/index.vue')['default']
UploadFile: typeof import('./src/components/upload-file/index.vue')['default'] UploadFile: typeof import('./src/components/upload-file/index.vue')['default']
UploadImage: typeof import('./src/components/upload-image/index.vue')['default'] UploadImage: typeof import('./src/components/upload-image/index.vue')['default']

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

@ -1,5 +1,7 @@
import request from '@/utils/request' import request from '@/utils/request'
// USER_CODE_BEGIN -- campus // USER_CODE_BEGIN -- campus
/** /**
* *
@ -7,7 +9,7 @@ import request from '@/utils/request'
* @returns * @returns
*/ */
export function getCampusList(params: Record<string, any>) { export function getCampusList(params: Record<string, any>) {
return request.get(`campus/campus`, { params }) return request.get(`campus/campus`, {params})
} }
/** /**
@ -16,7 +18,7 @@ export function getCampusList(params: Record<string, any>) {
* @returns * @returns
*/ */
export function getCampusInfo(id: number) { export function getCampusInfo(id: number) {
return request.get(`campus/campus/${id}`) return request.get(`campus/campus/${id}`);
} }
/** /**
@ -25,10 +27,7 @@ export function getCampusInfo(id: number) {
* @returns * @returns
*/ */
export function addCampus(params: Record<string, any>) { export function addCampus(params: Record<string, any>) {
return request.post('campus/campus', params, { return request.post('campus/campus', params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -38,10 +37,7 @@ export function addCampus(params: Record<string, any>) {
* @returns * @returns
*/ */
export function editCampus(params: Record<string, any>) { export function editCampus(params: Record<string, any>) {
return request.put(`campus/campus/${params.id}`, params, { return request.put(`campus/campus/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
/** /**
@ -50,10 +46,9 @@ export function editCampus(params: Record<string, any>) {
* @returns * @returns
*/ */
export function deleteCampus(id: number) { export function deleteCampus(id: number) {
return request.delete(`campus/campus/${id}`, { return request.delete(`campus/campus/${id}`, { showErrorMessage: true, showSuccessMessage: true })
showErrorMessage: true,
showSuccessMessage: true,
})
} }
// USER_CODE_END -- campus // USER_CODE_END -- campus

36
admin/src/app/lang/zh-cn/campus.campus.json

@ -1,20 +1,20 @@
{ {
"campusName": "校区名称", "campusName":"校区名称",
"campusNamePlaceholder": "请输入校区名称", "campusNamePlaceholder":"请输入校区名称",
"campusAddress": "校区地址", "campusAddress":"校区地址",
"campusAddressPlaceholder": "请输入校区地址", "campusAddressPlaceholder":"请输入校区地址",
"campusPreviewImage": "校区预览图,存储图片路径", "campusPreviewImage":"校区banner",
"campusPreviewImagePlaceholder": "请输入校区预览图,存储图片路径", "campusPreviewImagePlaceholder":"请选择图片",
"campusCoordinates": "校区坐标,格式为经度,纬度", "campusCoordinates":"校区位置",
"campusCoordinatesPlaceholder": "请输入校区坐标,格式为经度,纬度", "campusCoordinatesPlaceholder":"请选择校区位置",
"campusIntroduction": "校区介绍", "campusIntroduction":"校区介绍",
"campusIntroductionPlaceholder": "请输入校区介绍", "campusIntroductionPlaceholder":"请输入校区介绍",
"campusStatus": "校区状态", "campusStatus":"校区状态",
"campusStatusPlaceholder": "请输入校区状态", "campusStatusPlaceholder":"请输入校区状态",
"createTime": "校区创建时间", "createTime":"校区创建时间",
"addCampus": "添加校区", "addCampus":"添加校区",
"updateCampus": "编辑校区", "updateCampus":"编辑校区",
"campusDeleteTips": "确定要删除该数据吗?", "campusDeleteTips":"确定要删除该数据吗?",
"startDate": "请选择开始时间", "startDate":"请选择开始时间",
"endDate": "请选择结束时间" "endDate":"请选择结束时间"
} }

324
admin/src/app/views/campus/campus.vue

@ -1,138 +1,79 @@
<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">
<span class="text-lg">{{ pageName }}</span> <div class="flex justify-between items-center">
<el-button type="primary" @click="addEvent"> <span class="text-lg">{{pageName}}</span>
{{ t('addCampus') }} <el-button type="primary" @click="addEvent">
</el-button> {{ t('addCampus') }}
</div> </el-button>
</div>
<el-card
class="box-card !border-none my-[10px] table-search-wrap" <el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never">
shadow="never" <el-form :inline="true" :model="campusTable.searchParam" ref="searchFormRef">
> <el-form-item :label="t('campusName')" prop="campus_name">
<el-form <el-input v-model="campusTable.searchParam.campus_name" :placeholder="t('campusNamePlaceholder')" />
:inline="true" </el-form-item>
:model="campusTable.searchParam" <el-form-item :label="t('campusAddress')" prop="campus_address">
ref="searchFormRef" <el-input v-model="campusTable.searchParam.campus_address" :placeholder="t('campusAddressPlaceholder')" />
> </el-form-item>
<el-form-item :label="t('campusName')" prop="campus_name">
<el-input <el-form-item :label="t('campusStatus')" prop="campus_status">
v-model="campusTable.searchParam.campus_name" <el-select class="w-[280px]" v-model="campusTable.searchParam.campus_status" clearable :placeholder="t('campusStatusPlaceholder')">
:placeholder="t('campusNamePlaceholder')" <el-option label="全部" value=""></el-option>
/> <el-option
</el-form-item> v-for="(item, index) in campus_statusList"
<el-form-item :label="t('campusAddress')" prop="campus_address"> :key="index"
<el-input :label="item.name"
v-model="campusTable.searchParam.campus_address" :value="item.value"
:placeholder="t('campusAddressPlaceholder')" />
/> </el-select>
</el-form-item> </el-form-item>
<el-form-item :label="t('campusStatus')" prop="campus_status"> <el-form-item>
<el-select <el-button type="primary" @click="loadCampusList()">{{ t('search') }}</el-button>
class="w-[280px]" <el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button>
v-model="campusTable.searchParam.campus_status" </el-form-item>
clearable </el-form>
:placeholder="t('campusStatusPlaceholder')" </el-card>
>
<el-option label="全部" value=""></el-option> <div class="mt-[10px]">
<el-option <el-table :data="campusTable.data" size="large" v-loading="campusTable.loading">
v-for="(item, index) in campus_statusList" <template #empty>
:key="index" <span>{{ !campusTable.loading ? t('emptyData') : '' }}</span>
:label="item.name" </template>
:value="item.value" <el-table-column prop="campus_name" :label="t('campusName')" min-width="120" :show-overflow-tooltip="true"/>
/>
</el-select> <el-table-column prop="campus_address" :label="t('campusAddress')" min-width="120" :show-overflow-tooltip="true"/>
</el-form-item>
<el-table-column :label="t('campusStatus')" min-width="180" align="center" :show-overflow-tooltip="true">
<el-form-item> <template #default="{ row }">
<el-button type="primary" @click="loadCampusList()">{{ <div v-for="(item, index) in campus_statusList">
t('search') <div v-if="item.value == row.campus_status">{{ item.name }}</div>
}}</el-button> </div>
<el-button @click="resetForm(searchFormRef)">{{ </template>
t('reset') </el-table-column>
}}</el-button>
</el-form-item> <el-table-column prop="create_time" :label="t('createTime')" min-width="120" :show-overflow-tooltip="true"/>
</el-form>
</el-card> <el-table-column :label="t('operation')" fixed="right" min-width="120">
<template #default="{ row }">
<div class="mt-[10px]"> <el-button type="primary" link @click="editEvent(row)">{{ t('edit') }}</el-button>
<el-table <el-button type="primary" link @click="deleteEvent(row.id)">{{ t('delete') }}</el-button>
:data="campusTable.data" </template>
size="large" </el-table-column>
v-loading="campusTable.loading"
> </el-table>
<template #empty> <div class="mt-[16px] flex justify-end">
<span>{{ !campusTable.loading ? t('emptyData') : '' }}</span> <el-pagination v-model:current-page="campusTable.page" v-model:page-size="campusTable.limit"
</template> layout="total, sizes, prev, pager, next, jumper" :total="campusTable.total"
<el-table-column @size-change="loadCampusList()" @current-change="loadCampusList" />
prop="campus_name"
:label="t('campusName')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
prop="campus_address"
:label="t('campusAddress')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
:label="t('campusStatus')"
min-width="180"
align="center"
:show-overflow-tooltip="true"
>
<template #default="{ row }">
<div v-for="(item, index) in campus_statusList">
<div v-if="item.value == row.campus_status">
{{ item.name }}
</div> </div>
</div> </div>
</template>
</el-table-column> <edit ref="editCampusDialog" @complete="loadCampusList" />
</el-card>
<el-table-column </div>
prop="create_time"
:label="t('createTime')"
min-width="120"
:show-overflow-tooltip="true"
/>
<el-table-column
:label="t('operation')"
fixed="right"
min-width="120"
>
<template #default="{ row }">
<el-button type="primary" link @click="editEvent(row)">{{
t('edit')
}}</el-button>
<el-button type="primary" link @click="deleteEvent(row.id)">{{
t('delete')
}}</el-button>
</template>
</el-table-column>
</el-table>
<div class="mt-[16px] flex justify-end">
<el-pagination
v-model:current-page="campusTable.page"
v-model:page-size="campusTable.limit"
layout="total, sizes, prev, pager, next, jumper"
:total="campusTable.total"
@size-change="loadCampusList()"
@current-change="loadCampusList"
/>
</div>
</div>
<edit ref="editCampusDialog" @complete="loadCampusList" />
</el-card>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -141,23 +82,23 @@ import { t } from '@/lang'
import { useDictionary } from '@/app/api/dict' import { useDictionary } from '@/app/api/dict'
import { getCampusList, deleteCampus } from '@/app/api/campus' import { getCampusList, deleteCampus } from '@/app/api/campus'
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/campus/components/campus-edit.vue' import Edit from '@/app/views/campus/components/campus-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 campusTable = reactive({ let campusTable = reactive({
page: 1, page: 1,
limit: 10, limit: 10,
total: 0, total: 0,
loading: true, loading: true,
data: [], data: [],
searchParam: { searchParam:{
campus_name: '', "campus_name":"",
campus_address: '', "campus_address":"",
campus_status: '', "campus_status":""
}, }
}) })
const searchFormRef = ref<FormInstance>() const searchFormRef = ref<FormInstance>()
@ -166,33 +107,29 @@ const searchFormRef = ref<FormInstance>()
const selectData = ref<any[]>([]) const selectData = ref<any[]>([])
// //
const campus_statusList = ref([] as any[]) const campus_statusList = ref([] as any[])
const campus_statusDictList = async () => { const campus_statusDictList = async () => {
campus_statusList.value = await ( campus_statusList.value = await (await useDictionary('campus_status')).data.dictionary
await useDictionary('campus_status') }
).data.dictionary campus_statusDictList();
}
campus_statusDictList()
/** /**
* 获取校区列表 * 获取校区列表
*/ */
const loadCampusList = (page: number = 1) => { const loadCampusList = (page: number = 1) => {
campusTable.loading = true campusTable.loading = true
campusTable.page = page campusTable.page = page
getCampusList({ getCampusList({
page: campusTable.page, page: campusTable.page,
limit: campusTable.limit, limit: campusTable.limit,
...campusTable.searchParam, ...campusTable.searchParam
}) }).then(res => {
.then((res) => { campusTable.loading = false
campusTable.loading = false campusTable.data = res.data.data
campusTable.data = res.data.data campusTable.total = res.data.total
campusTable.total = res.data.total }).catch(() => {
}) campusTable.loading = false
.catch(() => {
campusTable.loading = false
}) })
} }
loadCampusList() loadCampusList()
@ -203,8 +140,8 @@ const editCampusDialog: Record<string, any> | null = ref(null)
* 添加校区 * 添加校区
*/ */
const addEvent = () => { const addEvent = () => {
editCampusDialog.value.setFormData() editCampusDialog.value.setFormData()
editCampusDialog.value.showDialog = true editCampusDialog.value.showDialog = true
} }
/** /**
@ -212,42 +149,45 @@ const addEvent = () => {
* @param data * @param data
*/ */
const editEvent = (data: any) => { const editEvent = (data: any) => {
editCampusDialog.value.setFormData(data) editCampusDialog.value.setFormData(data)
editCampusDialog.value.showDialog = true editCampusDialog.value.showDialog = true
} }
/** /**
* 删除校区 * 删除校区
*/ */
const deleteEvent = (id: number) => { const deleteEvent = (id: number) => {
ElMessageBox.confirm(t('campusDeleteTips'), t('warning'), { ElMessageBox.confirm(t('campusDeleteTips'), t('warning'),
confirmButtonText: t('confirm'), {
cancelButtonText: t('cancel'), confirmButtonText: t('confirm'),
type: 'warning', cancelButtonText: t('cancel'),
}).then(() => { type: 'warning',
deleteCampus(id) }
.then(() => { ).then(() => {
loadCampusList() deleteCampus(id).then(() => {
}) loadCampusList()
.catch(() => {}) }).catch(() => {
}) })
})
} }
const resetForm = (formEl: FormInstance | undefined) => { const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.resetFields() formEl.resetFields()
loadCampusList() loadCampusList()
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
/* 多行超出隐藏 */ /* 多行超出隐藏 */
.multi-hidden { .multi-hidden {
word-break: break-all; word-break: break-all;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
} }
</style> </style>

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

@ -37,12 +37,7 @@
</el-form-item> </el-form-item>
<el-form-item :label="t('campusCoordinates')"> <el-form-item :label="t('campusCoordinates')">
<el-input <TencentMapPicker v-model="formData.campus_coordinates" />
v-model="formData.campus_coordinates"
clearable
:placeholder="t('campusCoordinatesPlaceholder')"
class="input-width"
/>
</el-form-item> </el-form-item>
<el-form-item :label="t('campusIntroduction')"> <el-form-item :label="t('campusIntroduction')">
@ -84,6 +79,7 @@ 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 { addCampus, editCampus, getCampusInfo } from '@/app/api/campus' import { addCampus, editCampus, getCampusInfo } from '@/app/api/campus'
import TencentMapPicker from '@/components/TencentMapPicker.vue'
let showDialog = ref(false) let showDialog = ref(false)
const loading = ref(false) const loading = ref(false)

248
admin/src/components/TencentMapPicker.vue

@ -0,0 +1,248 @@
<template>
<el-dialog
v-model="dialogVisible"
:title="t('mapPickerTitle')"
width="800px"
:before-close="handleClose"
>
<div class="map-container" id="container"></div>
<div class="address-search">
<el-select
v-model="province"
:placeholder="t('provincePlaceholder')"
@change="handleProvinceChange"
>
<el-option
v-for="item in provinceList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
<el-select
v-model="city"
:placeholder="t('cityPlaceholder')"
@change="handleCityChange"
:disabled="!province"
>
<el-option
v-for="item in cityList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
<el-select
v-model="district"
:placeholder="t('districtPlaceholder')"
@change="handleDistrictChange"
:disabled="!province || !city"
>
<el-option
v-for="item in districtList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
<el-input
v-model="detailAddress"
:placeholder="t('detailAddressPlaceholder')"
/>
<el-button type="primary" @click="handleAddressSearch">{{ t('search') }}</el-button>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">{{ t('cancel') }}</el-button>
<el-button type="primary" @click="handleConfirm">
{{ t('confirm') }}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, onMounted, watch } from 'vue'
import { getAreaListByPid, getAreaByCode } from '@/app/api/sys'
import { createMarker, latLngToAddress, addressToLatLng } from '@/utils/qqmap'
import { t } from '@/lang'
const props = defineProps({
modelValue: {
type: Object,
default: () => ({
lat: null,
lng: null,
address: '',
}),
},
})
const emit = defineEmits(['update:modelValue', 'confirm'])
const dialogVisible = ref(false)
const handleClose = (done: () => void) => {
done()
}
const handleConfirm = () => {
emit('confirm', {
lat: props.modelValue.lat,
lng: props.modelValue.lng,
address: detailAddress.value
})
dialogVisible.value = false
}
//
let map: any
let marker: any
const mapKey = ref('')
//
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(() => {
const mapScript = document.createElement('script')
mapKey.value = 'IZQBZ-3UHEU-WTCVD-2464U-I5N4V-ZFFU3'
mapScript.type = 'text/javascript'
mapScript.src =
'https://map.qq.com/api/gljs?libraries=tools,service&v=1.exp&key=IZQBZ-3UHEU-WTCVD-2464U-I5N4V-ZFFU3'
document.body.appendChild(mapScript)
mapScript.onload = () => {
setTimeout(() => {
initMap()
}, 500)
}
//
getAreaListByPid(0).then((res) => {
provinceList.value = res.data
})
})
const initMap = () => {
const TMap = (window as any).TMap
const center = new TMap.LatLng(39.90403, 116.407526)
map = new TMap.Map('container', {
center,
zoom: 12,
})
marker = createMarker(map)
map.on('click', (evt: any) => {
map.setCenter(evt.latLng)
marker.updateGeometries({
id: 'center',
position: evt.latLng,
})
emit('update:modelValue', {
lat: evt.latLng.lat,
lng: evt.latLng.lng,
address: detailAddress.value,
})
})
}
//
const handleProvinceChange = (val: string) => {
getAreaListByPid(val).then((res) => {
cityList.value = res.data
city.value = ''
district.value = ''
})
}
const handleCityChange = (val: string) => {
getAreaListByPid(val).then((res) => {
districtList.value = res.data
district.value = ''
})
}
const handleDistrictChange = (val: string) => {
// TODO:
}
//
const handleAddressSearch = () => {
const address = [
province.value
? provinceList.value.find((p) => p.id === province.value)?.name
: '',
city.value ? cityList.value.find((c) => c.id === city.value)?.name : '',
district.value
? districtList.value.find((d) => d.id === district.value)?.name
: '',
detailAddress.value,
].join('')
addressToLatLng({ mapKey: mapKey.value, address }).then(
({ message, result }) => {
if (message == 'Success' || message == 'query ok') {
const latLng = new (window as any).TMap.LatLng(
result.location.lat,
result.location.lng
)
map.setCenter(latLng)
marker.updateGeometries({
id: 'center',
position: latLng,
})
emit('update:modelValue', {
lat: result.location.lat,
lng: result.location.lng,
address: detailAddress.value,
})
}
}
)
}
//
watch(
() => props.modelValue,
(newVal) => {
if (newVal.lat && newVal.lng) {
const latLng = new (window as any).TMap.LatLng(newVal.lat, newVal.lng)
map?.setCenter(latLng)
marker?.updateGeometries({
id: 'center',
position: latLng,
})
}
},
{ immediate: true }
)
</script>
<style scoped>
.map-picker {
display: flex;
flex-direction: column;
gap: 16px;
}
.map-container {
width: 100%;
height: 400px;
border: 1px solid #dcdfe6;
border-radius: 4px;
}
.address-search {
display: flex;
gap: 8px;
}
</style>

37
niucloud/app/adminapi/route/campus.php

@ -0,0 +1,37 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
use think\facade\Route;
use app\adminapi\middleware\AdminCheckRole;
use app\adminapi\middleware\AdminCheckToken;
use app\adminapi\middleware\AdminLog;
// USER_CODE_BEGIN -- campus
Route::group('campus', function () {
//校区列表
Route::get('campus', 'campus.Campus/lists');
//校区详情
Route::get('campus/:id', 'campus.Campus/info');
//添加校区
Route::post('campus', 'campus.Campus/add');
//编辑校区
Route::put('campus/:id', 'campus.Campus/edit');
//删除校区
Route::delete('campus/:id', 'campus.Campus/del');
})->middleware([
AdminCheckToken::class,
AdminCheckRole::class,
AdminLog::class
]);
// USER_CODE_END -- campus

94
niucloud/app/model/campus/Campus.php

@ -0,0 +1,94 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\model\campus;
use core\base\BaseModel;
use think\model\concern\SoftDelete;
use think\model\relation\HasMany;
use think\model\relation\HasOne;
/**
* 校区模型
* Class Campus
* @package app\model\campus
*/
class Campus extends BaseModel
{
use SoftDelete;
/**
* 数据表主键
* @var string
*/
protected $pk = 'id';
/**
* 模型名称
* @var string
*/
protected $name = 'campus';
/**
* 定义软删除标记字段.
* @var string
*/
protected $deleteTime = 'delete_time';
/**
* 定义软删除字段的默认值.
* @var int
*/
protected $defaultSoftDelete = 0;
/**
* 搜索器:校区校区名称
* @param $value
* @param $data
*/
public function searchCampusNameAttr($query, $value, $data)
{
if ($value) {
$query->where("campus_name", "like", "%".$value."%");
}
}
/**
* 搜索器:校区校区地址
* @param $value
* @param $data
*/
public function searchCampusAddressAttr($query, $value, $data)
{
if ($value) {
$query->where("campus_address", $value);
}
}
/**
* 搜索器:校区校区状态
* @param $value
* @param $data
*/
public function searchCampusStatusAttr($query, $value, $data)
{
if ($value) {
$query->where("campus_status", $value);
}
}
}

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

@ -0,0 +1,100 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\service\admin\campus;
use app\model\campus\Campus;
use core\base\BaseAdminService;
/**
* 校区服务层
* Class CampusService
* @package app\service\admin\campus
*/
class CampusService extends BaseAdminService
{
public function __construct()
{
parent::__construct();
$this->model = new Campus();
}
/**
* 获取校区列表
* @param array $where
* @return array
*/
public function getPage(array $where = [])
{
$field = 'id,campus_name,campus_address,campus_preview_image,campus_coordinates,campus_introduction,campus_status,create_time,update_time,delete_time';
$order = '';
$search_model = $this->model->withSearch(["campus_name","campus_address","campus_status"], $where)->field($field)->order($order);
$list = $this->pageQuery($search_model);
return $list;
}
/**
* 获取校区信息
* @param int $id
* @return array
*/
public function getInfo(int $id)
{
$field = 'id,campus_name,campus_address,campus_preview_image,campus_coordinates,campus_introduction,campus_status,create_time,update_time,delete_time';
$info = $this->model->field($field)->where([['id', "=", $id]])->findOrEmpty()->toArray();
$info['campus_status'] = strval($info['campus_status']);
return $info;
}
/**
* 添加校区
* @param array $data
* @return mixed
*/
public function add(array $data)
{
$res = $this->model->create($data);
return $res->id;
}
/**
* 校区编辑
* @param int $id
* @param array $data
* @return bool
*/
public function edit(int $id, array $data)
{
$this->model->where([['id', '=', $id]])->update($data);
return true;
}
/**
* 删除校区
* @param int $id
* @return bool
*/
public function del(int $id)
{
$model = $this->model->where([['id', '=', $id]])->find();
$res = $model->delete();
return $res;
}
}

35
niucloud/app/validate/campus/Campus.php

@ -0,0 +1,35 @@
<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\validate\campus;
use core\base\BaseValidate;
/**
* 校区验证器
* Class Campus
* @package addon\app\validate\campus
*/
class Campus extends BaseValidate
{
protected $rule = [
'campus_name' => 'require',
];
protected $message = [
'campus_name.require' => ['common_validate.require', ['campus_name']],
];
protected $scene = [
"add" => ['campus_name', 'campus_address', 'campus_preview_image', 'campus_coordinates', 'campus_introduction', 'campus_status'],
"edit" => ['campus_name', 'campus_address', 'campus_preview_image', 'campus_coordinates', 'campus_introduction', 'campus_status']
];
}
Loading…
Cancel
Save