10 changed files with 746 additions and 292 deletions
@ -1,20 +1,20 @@ |
|||
{ |
|||
"campusName": "校区名称", |
|||
"campusNamePlaceholder": "请输入校区名称", |
|||
"campusAddress": "校区地址", |
|||
"campusAddressPlaceholder": "请输入校区地址", |
|||
"campusPreviewImage": "校区预览图,存储图片路径", |
|||
"campusPreviewImagePlaceholder": "请输入校区预览图,存储图片路径", |
|||
"campusCoordinates": "校区坐标,格式为经度,纬度", |
|||
"campusCoordinatesPlaceholder": "请输入校区坐标,格式为经度,纬度", |
|||
"campusIntroduction": "校区介绍", |
|||
"campusIntroductionPlaceholder": "请输入校区介绍", |
|||
"campusStatus": "校区状态", |
|||
"campusStatusPlaceholder": "请输入校区状态", |
|||
"createTime": "校区创建时间", |
|||
"addCampus": "添加校区", |
|||
"updateCampus": "编辑校区", |
|||
"campusDeleteTips": "确定要删除该数据吗?", |
|||
"startDate": "请选择开始时间", |
|||
"endDate": "请选择结束时间" |
|||
} |
|||
"campusName":"校区名称", |
|||
"campusNamePlaceholder":"请输入校区名称", |
|||
"campusAddress":"校区地址", |
|||
"campusAddressPlaceholder":"请输入校区地址", |
|||
"campusPreviewImage":"校区banner", |
|||
"campusPreviewImagePlaceholder":"请选择图片", |
|||
"campusCoordinates":"校区位置", |
|||
"campusCoordinatesPlaceholder":"请选择校区位置", |
|||
"campusIntroduction":"校区介绍", |
|||
"campusIntroductionPlaceholder":"请输入校区介绍", |
|||
"campusStatus":"校区状态", |
|||
"campusStatusPlaceholder":"请输入校区状态", |
|||
"createTime":"校区创建时间", |
|||
"addCampus":"添加校区", |
|||
"updateCampus":"编辑校区", |
|||
"campusDeleteTips":"确定要删除该数据吗?", |
|||
"startDate":"请选择开始时间", |
|||
"endDate":"请选择结束时间" |
|||
} |
|||
@ -1,253 +1,193 @@ |
|||
<template> |
|||
<div class="main-container"> |
|||
<el-card class="box-card !border-none" shadow="never"> |
|||
<div class="flex justify-between items-center"> |
|||
<span class="text-lg">{{ pageName }}</span> |
|||
<el-button type="primary" @click="addEvent"> |
|||
{{ t('addCampus') }} |
|||
</el-button> |
|||
</div> |
|||
|
|||
<el-card |
|||
class="box-card !border-none my-[10px] table-search-wrap" |
|||
shadow="never" |
|||
> |
|||
<el-form |
|||
:inline="true" |
|||
:model="campusTable.searchParam" |
|||
ref="searchFormRef" |
|||
> |
|||
<el-form-item :label="t('campusName')" prop="campus_name"> |
|||
<el-input |
|||
v-model="campusTable.searchParam.campus_name" |
|||
:placeholder="t('campusNamePlaceholder')" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item :label="t('campusAddress')" prop="campus_address"> |
|||
<el-input |
|||
v-model="campusTable.searchParam.campus_address" |
|||
:placeholder="t('campusAddressPlaceholder')" |
|||
/> |
|||
</el-form-item> |
|||
|
|||
<el-form-item :label="t('campusStatus')" prop="campus_status"> |
|||
<el-select |
|||
class="w-[280px]" |
|||
v-model="campusTable.searchParam.campus_status" |
|||
clearable |
|||
:placeholder="t('campusStatusPlaceholder')" |
|||
> |
|||
<el-option label="全部" value=""></el-option> |
|||
<el-option |
|||
v-for="(item, index) in campus_statusList" |
|||
:key="index" |
|||
:label="item.name" |
|||
:value="item.value" |
|||
/> |
|||
</el-select> |
|||
</el-form-item> |
|||
|
|||
<el-form-item> |
|||
<el-button type="primary" @click="loadCampusList()">{{ |
|||
t('search') |
|||
}}</el-button> |
|||
<el-button @click="resetForm(searchFormRef)">{{ |
|||
t('reset') |
|||
}}</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</el-card> |
|||
|
|||
<div class="mt-[10px]"> |
|||
<el-table |
|||
:data="campusTable.data" |
|||
size="large" |
|||
v-loading="campusTable.loading" |
|||
> |
|||
<template #empty> |
|||
<span>{{ !campusTable.loading ? t('emptyData') : '' }}</span> |
|||
</template> |
|||
<el-table-column |
|||
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> |
|||
</template> |
|||
</el-table-column> |
|||
|
|||
<el-table-column |
|||
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> |
|||
|
|||
<script lang="ts" setup> |
|||
import { reactive, ref, watch } from 'vue' |
|||
import { t } from '@/lang' |
|||
import { useDictionary } from '@/app/api/dict' |
|||
import { getCampusList, deleteCampus } from '@/app/api/campus' |
|||
import { img } from '@/utils/common' |
|||
import { ElMessageBox, FormInstance } from 'element-plus' |
|||
import Edit from '@/app/views/campus/components/campus-edit.vue' |
|||
import { useRoute } from 'vue-router' |
|||
const route = useRoute() |
|||
const pageName = route.meta.title |
|||
|
|||
let campusTable = reactive({ |
|||
page: 1, |
|||
limit: 10, |
|||
total: 0, |
|||
loading: true, |
|||
data: [], |
|||
searchParam: { |
|||
campus_name: '', |
|||
campus_address: '', |
|||
campus_status: '', |
|||
}, |
|||
}) |
|||
|
|||
const searchFormRef = ref<FormInstance>() |
|||
|
|||
// 选中数据 |
|||
const selectData = ref<any[]>([]) |
|||
|
|||
// 字典数据 |
|||
const campus_statusList = ref([] as any[]) |
|||
const campus_statusDictList = async () => { |
|||
campus_statusList.value = await ( |
|||
await useDictionary('campus_status') |
|||
).data.dictionary |
|||
} |
|||
campus_statusDictList() |
|||
|
|||
/** |
|||
* 获取校区列表 |
|||
*/ |
|||
const loadCampusList = (page: number = 1) => { |
|||
campusTable.loading = true |
|||
campusTable.page = page |
|||
|
|||
getCampusList({ |
|||
page: campusTable.page, |
|||
limit: campusTable.limit, |
|||
...campusTable.searchParam, |
|||
}) |
|||
.then((res) => { |
|||
campusTable.loading = false |
|||
campusTable.data = res.data.data |
|||
campusTable.total = res.data.total |
|||
}) |
|||
.catch(() => { |
|||
campusTable.loading = false |
|||
}) |
|||
} |
|||
loadCampusList() |
|||
|
|||
const editCampusDialog: Record<string, any> | null = ref(null) |
|||
|
|||
/** |
|||
* 添加校区 |
|||
*/ |
|||
const addEvent = () => { |
|||
editCampusDialog.value.setFormData() |
|||
editCampusDialog.value.showDialog = true |
|||
} |
|||
|
|||
/** |
|||
* 编辑校区 |
|||
* @param data |
|||
*/ |
|||
const editEvent = (data: any) => { |
|||
editCampusDialog.value.setFormData(data) |
|||
editCampusDialog.value.showDialog = true |
|||
} |
|||
|
|||
/** |
|||
* 删除校区 |
|||
*/ |
|||
const deleteEvent = (id: number) => { |
|||
ElMessageBox.confirm(t('campusDeleteTips'), t('warning'), { |
|||
confirmButtonText: t('confirm'), |
|||
cancelButtonText: t('cancel'), |
|||
type: 'warning', |
|||
}).then(() => { |
|||
deleteCampus(id) |
|||
.then(() => { |
|||
loadCampusList() |
|||
}) |
|||
.catch(() => {}) |
|||
}) |
|||
} |
|||
|
|||
const resetForm = (formEl: FormInstance | undefined) => { |
|||
if (!formEl) return |
|||
formEl.resetFields() |
|||
loadCampusList() |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
/* 多行超出隐藏 */ |
|||
.multi-hidden { |
|||
word-break: break-all; |
|||
text-overflow: ellipsis; |
|||
overflow: hidden; |
|||
display: -webkit-box; |
|||
-webkit-line-clamp: 2; |
|||
-webkit-box-orient: vertical; |
|||
} |
|||
</style> |
|||
<template> |
|||
<div class="main-container"> |
|||
<el-card class="box-card !border-none" shadow="never"> |
|||
|
|||
<div class="flex justify-between items-center"> |
|||
<span class="text-lg">{{pageName}}</span> |
|||
<el-button type="primary" @click="addEvent"> |
|||
{{ t('addCampus') }} |
|||
</el-button> |
|||
</div> |
|||
|
|||
<el-card class="box-card !border-none my-[10px] table-search-wrap" shadow="never"> |
|||
<el-form :inline="true" :model="campusTable.searchParam" ref="searchFormRef"> |
|||
<el-form-item :label="t('campusName')" prop="campus_name"> |
|||
<el-input v-model="campusTable.searchParam.campus_name" :placeholder="t('campusNamePlaceholder')" /> |
|||
</el-form-item> |
|||
<el-form-item :label="t('campusAddress')" prop="campus_address"> |
|||
<el-input v-model="campusTable.searchParam.campus_address" :placeholder="t('campusAddressPlaceholder')" /> |
|||
</el-form-item> |
|||
|
|||
<el-form-item :label="t('campusStatus')" prop="campus_status"> |
|||
<el-select class="w-[280px]" v-model="campusTable.searchParam.campus_status" clearable :placeholder="t('campusStatusPlaceholder')"> |
|||
<el-option label="全部" value=""></el-option> |
|||
<el-option |
|||
v-for="(item, index) in campus_statusList" |
|||
:key="index" |
|||
:label="item.name" |
|||
:value="item.value" |
|||
/> |
|||
</el-select> |
|||
</el-form-item> |
|||
|
|||
<el-form-item> |
|||
<el-button type="primary" @click="loadCampusList()">{{ t('search') }}</el-button> |
|||
<el-button @click="resetForm(searchFormRef)">{{ t('reset') }}</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</el-card> |
|||
|
|||
<div class="mt-[10px]"> |
|||
<el-table :data="campusTable.data" size="large" v-loading="campusTable.loading"> |
|||
<template #empty> |
|||
<span>{{ !campusTable.loading ? t('emptyData') : '' }}</span> |
|||
</template> |
|||
<el-table-column 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> |
|||
</template> |
|||
</el-table-column> |
|||
|
|||
<el-table-column 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> |
|||
|
|||
<script lang="ts" setup> |
|||
import { reactive, ref, watch } from 'vue' |
|||
import { t } from '@/lang' |
|||
import { useDictionary } from '@/app/api/dict' |
|||
import { getCampusList, deleteCampus } from '@/app/api/campus' |
|||
import { img } from '@/utils/common' |
|||
import { ElMessageBox,FormInstance } from 'element-plus' |
|||
import Edit from '@/app/views/campus/components/campus-edit.vue' |
|||
import { useRoute } from 'vue-router' |
|||
const route = useRoute() |
|||
const pageName = route.meta.title; |
|||
|
|||
let campusTable = reactive({ |
|||
page: 1, |
|||
limit: 10, |
|||
total: 0, |
|||
loading: true, |
|||
data: [], |
|||
searchParam:{ |
|||
"campus_name":"", |
|||
"campus_address":"", |
|||
"campus_status":"" |
|||
} |
|||
}) |
|||
|
|||
const searchFormRef = ref<FormInstance>() |
|||
|
|||
// 选中数据 |
|||
const selectData = ref<any[]>([]) |
|||
|
|||
// 字典数据 |
|||
const campus_statusList = ref([] as any[]) |
|||
const campus_statusDictList = async () => { |
|||
campus_statusList.value = await (await useDictionary('campus_status')).data.dictionary |
|||
} |
|||
campus_statusDictList(); |
|||
|
|||
/** |
|||
* 获取校区列表 |
|||
*/ |
|||
const loadCampusList = (page: number = 1) => { |
|||
campusTable.loading = true |
|||
campusTable.page = page |
|||
|
|||
getCampusList({ |
|||
page: campusTable.page, |
|||
limit: campusTable.limit, |
|||
...campusTable.searchParam |
|||
}).then(res => { |
|||
campusTable.loading = false |
|||
campusTable.data = res.data.data |
|||
campusTable.total = res.data.total |
|||
}).catch(() => { |
|||
campusTable.loading = false |
|||
}) |
|||
} |
|||
loadCampusList() |
|||
|
|||
const editCampusDialog: Record<string, any> | null = ref(null) |
|||
|
|||
/** |
|||
* 添加校区 |
|||
*/ |
|||
const addEvent = () => { |
|||
editCampusDialog.value.setFormData() |
|||
editCampusDialog.value.showDialog = true |
|||
} |
|||
|
|||
/** |
|||
* 编辑校区 |
|||
* @param data |
|||
*/ |
|||
const editEvent = (data: any) => { |
|||
editCampusDialog.value.setFormData(data) |
|||
editCampusDialog.value.showDialog = true |
|||
} |
|||
|
|||
/** |
|||
* 删除校区 |
|||
*/ |
|||
const deleteEvent = (id: number) => { |
|||
ElMessageBox.confirm(t('campusDeleteTips'), t('warning'), |
|||
{ |
|||
confirmButtonText: t('confirm'), |
|||
cancelButtonText: t('cancel'), |
|||
type: 'warning', |
|||
} |
|||
).then(() => { |
|||
deleteCampus(id).then(() => { |
|||
loadCampusList() |
|||
}).catch(() => { |
|||
}) |
|||
}) |
|||
} |
|||
|
|||
|
|||
|
|||
const resetForm = (formEl: FormInstance | undefined) => { |
|||
if (!formEl) return |
|||
formEl.resetFields() |
|||
loadCampusList() |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
/* 多行超出隐藏 */ |
|||
.multi-hidden { |
|||
word-break: break-all; |
|||
text-overflow: ellipsis; |
|||
overflow: hidden; |
|||
display: -webkit-box; |
|||
-webkit-line-clamp: 2; |
|||
-webkit-box-orient: vertical; |
|||
} |
|||
</style> |
|||
|
|||
@ -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> |
|||
@ -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 |
|||
@ -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); |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
} |
|||
@ -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; |
|||
} |
|||
|
|||
|
|||
|
|||
} |
|||
@ -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…
Reference in new issue