10 changed files with 746 additions and 292 deletions
@ -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":"请选择结束时间" |
||||
} |
} |
||||
@ -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