盗采点维护画面,停车场管理画面

main
zhufu 2026-02-05 08:51:01 +08:00
parent 2ad755401a
commit a31caad7d3
10 changed files with 972 additions and 1 deletions

View File

@ -0,0 +1,43 @@
import { defHttp } from '@/utils/http/axios';
enum Api {
// 分页
LoadAllPage = '/api/MiMinePoint/LoadAllPage',
// 实体
Get = '/api/MiMinePoint/Get',
// 添加
Add = '/api/MiMinePoint/Add',
// 修改
Update = '/api/MiMinePoint/Update',
// 删除
Delete = '/api/MiMinePoint/Delete',
}
export function LoadAllPage(params) {
return defHttp.get({
url: Api.LoadAllPage,
params,
});
}
export function Get(params) {
return defHttp.get({
url: Api.Get,
params,
});
}
export function Add(params) {
return defHttp.post({
url: Api.Add,
params,
});
}
export function Update(params) {
return defHttp.post({
url: Api.Update,
params,
});
}
export function Delete(params) {
return defHttp.post({
url: Api.Delete,
params,
});
}

View File

@ -0,0 +1,43 @@
import { defHttp } from '@/utils/http/axios';
enum Api {
// 分页
LoadAllPage = '/api/MiParking/LoadAllPage',
// 实体
Get = '/api/MiParking/Get',
// 添加
Add = '/api/MiParking/Add',
// 修改
Update = '/api/MiParking/Update',
// 删除
Delete = '/api/MiParking/Delete',
}
export function LoadAllPage(params) {
return defHttp.get({
url: Api.LoadAllPage,
params,
});
}
export function Get(params) {
return defHttp.get({
url: Api.Get,
params,
});
}
export function Add(params) {
return defHttp.post({
url: Api.Add,
params,
});
}
export function Update(params) {
return defHttp.post({
url: Api.Update,
params,
});
}
export function Delete(params) {
return defHttp.post({
url: Api.Delete,
params,
});
}

View File

@ -0,0 +1,304 @@
<template>
<div style="position: relative; height: 100%" ref="vChartRef" id="mars3d-container"></div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import * as mars3d from 'mars3d';
const emits = defineEmits(['getAddress'])
let map: mars3d.Map; //
const vChartRef = ref<HTMLElement>();
onMounted(() => {
let options = {
scene: {
center: {
lat: 35.362625,
lng: 118.033886,
alt: 8306.3,
heading: 360,
pitch: -45,
},
scene3DOnly: false,
shadows: false,
removeDblClick: true,
sceneMode: 3,
showSun: true,
showMoon: true,
showSkyBox: true,
showSkyAtmosphere: true,
fog: true,
fxaa: true,
requestRenderMode: true,
contextOptions: {
requestWebgl1: false,
webgl: {
preserveDrawingBuffer: true,
alpha: false,
stencil: true,
powerPreference: 'high-performance',
},
},
globe: {
depthTestAgainstTerrain: false,
baseColor: '#546a53',
showGroundAtmosphere: true,
enableLighting: false,
},
cameraController: {
zoomFactor: 3,
minimumZoomDistance: 1,
maximumZoomDistance: 50000000,
enableRotate: true,
enableTranslate: true,
enableTilt: true,
enableZoom: true,
enableCollisionDetection: true,
minimumCollisionTerrainHeight: 15000,
},
},
control: {
homeButton: false,
baseLayerPicker: false,
sceneModePicker: false,
vrButton: false,
fullscreenButton: false,
navigationHelpButton: false,
animation: false,
timeline: false,
infoBox: false,
geocoder: false,
selectionIndicator: false,
showRenderLoopErrors: true,
contextmenu: {
hasDefault: true,
},
mouseDownView: true,
zoom: {
insertIndex: 1,
},
},
method: {
templateValues: {
dataServer: '//data.mars3d.cn',
gltfServerUrl: '//data.mars3d.cn/gltf',
},
},
terrain: {
url: '//data.mars3d.cn/terrain',
show: true,
clip: true,
},
basemaps: [
{
id: 10,
name: '地图底图',
type: 'group',
opacity: 1,
},
{
id: 2021,
pid: 10,
name: '天地图影像',
icon: 'https://data.mars3d.cn/img/thumbnail/basemap/tdt_img.png',
type: 'group',
layers: [
{
name: '底图',
type: 'tdt',
layer: 'img_d',
eventParent: {
id: 2021,
pid: 10,
name: '天地图影像',
icon: 'https://data.mars3d.cn/img/thumbnail/basemap/tdt_img.png',
type: 'group',
layers: [
{
name: '底图',
type: 'tdt',
layer: 'img_d',
show: true,
},
{
name: '注记',
type: 'tdt',
layer: 'img_z',
show: true,
},
],
show: true,
},
private: false,
id: 'm-a57ecb7d-ba05-47a3-b1be-2e28411a5954',
opacity: 1,
pid: 2021,
parent: {
id: 2021,
pid: 10,
name: '天地图影像',
icon: 'https://data.mars3d.cn/img/thumbnail/basemap/tdt_img.png',
type: 'group',
layers: [
{
name: '底图',
type: 'tdt',
layer: 'img_d',
show: true,
},
{
name: '注记',
type: 'tdt',
layer: 'img_z',
show: true,
},
],
show: true,
},
zIndex: 1,
},
{
name: '注记',
type: 'tdt',
layer: 'img_z',
eventParent: {
id: 2021,
pid: 10,
name: '天地图影像',
icon: 'https://data.mars3d.cn/img/thumbnail/basemap/tdt_img.png',
type: 'group',
layers: [
{
name: '底图',
type: 'tdt',
layer: 'img_d',
show: true,
},
{
name: '注记',
type: 'tdt',
layer: 'img_z',
show: true,
},
],
show: true,
},
private: false,
id: 'm-671f9d42-dda7-45ec-9d0f-4259c915b2cb',
opacity: 1,
pid: 2021,
parent: {
id: 2021,
pid: 10,
name: '天地图影像',
icon: 'https://data.mars3d.cn/img/thumbnail/basemap/tdt_img.png',
type: 'group',
layers: [
{
name: '底图',
type: 'tdt',
layer: 'img_d',
show: true,
},
{
name: '注记',
type: 'tdt',
layer: 'img_z',
show: true,
},
],
show: true,
},
zIndex: 2,
},
],
show: true,
opacity: 1,
},
],
layers: [],
};
initMap(options);
});
const isFirstLoad = ref(true);
const idNum = ref(0);
let graphicLayer = null;
const pointGraphic = ref();
const pointData = ref();
const initMap = (newData: any) => {
//
if (isFirstLoad.value) {
map = new mars3d.Map(vChartRef.value, newData);
} else {
//
// map.setOptions(newData);
map.setSceneOptions(newData.scene);
}
isFirstLoad.value = false;
//
handlerInitEntityLayer();
//
const pointLayer = new mars3d.layer.GraphicLayer({
name: 'PointLayer',
hasEdit: false,
isAutoEditing: false,
});
map.addLayer(pointLayer);
map.on(mars3d.EventType.click, async (event) => {
const cartesian = map.camera.pickEllipsoid(
event.position,
map.scene.globe.ellipsoid
);
if (!cartesian) return;
const point = mars3d.LngLatPoint.fromCartesian(cartesian);
point.format();
const { lng, lat } = point;
const address = await getAddressByLngLat(lng, lat);
emits('getAddress', lng, lat, address)
pointData.value = {
lng,
lat,
address
}
if (pointGraphic.value) {
pointLayer.removeGraphic(pointGraphic.value);
}
pointGraphic.value = new mars3d.graphic.BillboardEntity({
position: [lng, lat, 10],
style: {
image: '/positioning.png',
scale: 0.6,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
verticalOrigin: mars3d.Cesium.VerticalOrigin.BOTTOM,
},
});
pointLayer.addGraphic(pointGraphic.value);
});
};
async function getAddressByLngLat(lng: number, lat: number) {
const GAODE_KEY = "6af6a87038f44c8c793aa70331f2b7ca";
const url = `https://restapi.amap.com/v3/geocode/regeo?key=${GAODE_KEY}&location=${lng},${lat}&radius=1000&extensions=base`;
const res = await fetch(url);
const data = await res.json();
if (data.status === '1') {
return data.regeocode.formatted_address;
}
return '未知位置';
}
//
const handlerInitEntityLayer = () => {
if (graphicLayer == null) {
graphicLayer = new mars3d.layer.GraphicLayer({ id: 999 });
}
};
const getPosition = () => {
return pointData.value;
};
defineExpose({
getPosition,
});
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,186 @@
<template>
<div class="modal-content">
<a-form class="content-form" ref="formRef" :model="props.modalData" :label-col="labelCol">
<a-form-item
label="名称"
name="name"
:rules="[{ required: true, message: '请输入名称' }]"
>
<a-input v-model:value="props.modalData.name" />
</a-form-item>
<a-form-item
label="区县"
name="countyId"
:rules="[{ required: true, message: '请选择区县' }]"
>
<a-select v-model:value="props.modalData.countyId" :options="countyOptions" @change="changeCountry"/>
</a-form-item>
<a-form-item
label="乡镇"
name="streetId"
:rules="[{ required: true, message: '请选择乡镇' }]"
>
<a-select v-model:value="props.modalData.streetId" :options="streetOptions" @change="changeStreet"/>
</a-form-item>
<a-form-item
label="社区/村"
name="communityId"
:rules="[{ required: true, message: '请选择社区' }]"
>
<a-select v-model:value="props.modalData.communityId" :options="communityOptions" @change="changeCommunity"/>
</a-form-item>
<a-form-item
label="经纬度"
>
<a-button style="margin-right: 10px;" @click="mapVisible = true">选择经纬度</a-button>
<span v-if="props.modalData.lng && props.modalData.lat">{{ `${props.modalData.lng}, ${props.modalData.lat}` }}</span>
</a-form-item>
</a-form>
<div class="button-div">
<a-button class="cancel-button" @click="cancel"></a-button>
<a-button class="save-button" type="primary" @click="submit"></a-button>
</div>
</div>
<a-modal
width="60%"
v-model:open="mapVisible"
title="选择位置"
@ok="handlePostionOk"
:destroyOnClose="true"
>
<Map ref="PostionRef" @getAddress="getAddress"/>
</a-modal>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue"
import { getChildrenTree } from '@/api/demo/system';
import Map from '@/components/illegalconstruction/Map.vue'
import { Add, Update } from '@/api/illegalconstruction/miningsitemanagement'
import { message } from "ant-design-vue";
const props = defineProps(['modalType', 'modalData'])
const emits = defineEmits(['closeAddOrUpdateModal'])
const formRef = ref()
const PostionRef = ref();
const mapVisible = ref(false);
const countyOptions = ref([])
const streetOptions = ref([])
const communityOptions = ref([])
const labelCol = { style: { width: '80px' } };
onMounted(() => {
getChildrenTree({parentId: 371300}).then(res => {
countyOptions.value = res.map(item => {
return {
label: item.name,
value: item.id.toString()
}
})
})
if(props.modalType == 'update'){
if(props.modalData.countyId){
getChildrenTree({parentId: props.modalData.countyId}).then(res => {
streetOptions.value = res.map(item => {
return {
label: item.name,
value: item.id.toString()
}
})
})
}
if(props.modalData.streetId){
getChildrenTree({parentId: props.modalData.streetId}).then(res => {
communityOptions.value = res.map(item => {
return {
label: item.name,
value: item.id.toString()
}
})
})
}
}
})
const changeCountry = (value, record) => {
props.modalData.countyName = record.label
props.modalData.streetId = ''
props.modalData.streetName = ''
props.modalData.communityId = ''
props.modalData.communityName = ''
getChildrenTree({parentId: value}).then(res => {
streetOptions.value = res.map(item => {
return {
label: item.name,
value: item.id.toString()
}
})
})
}
const changeStreet = (value, record) => {
props.modalData.streetName = record.label
props.modalData.communityId = ''
props.modalData.communityName = ''
getChildrenTree({parentId: value}).then(res => {
communityOptions.value = res.map(item => {
return {
label: item.name,
value: item.id.toString()
}
})
})
}
const changeCommunity = (value, record) => {
props.modalData.communityName = record.label
}
const handlePostionOk = () => {
const data = PostionRef.value.getPosition();
console.log(data);
if(data){
props.modalData.lng = data.lng
props.modalData.lat = data.lat
}
mapVisible.value = false;
};
const getAddress = (lng, lat, siteAddress) => {
console.log(lng,lat,siteAddress)
}
const submit = () => {
formRef.value.validate().then(() => {
console.log('values', props.modalData);
if(props.modalType == 'add'){
Add(props.modalData).then(res => {
message.success('盗采站点添加成功')
emits('closeAddOrUpdateModal',true)
})
}else{
Update(props.modalData).then(res => {
message.success('盗采站点编辑成功')
emits('closeAddOrUpdateModal',true)
})
}
})
.catch(error => {
console.log('error', error);
});
}
const cancel = () => {
emits('closeAddOrUpdateModal')
}
</script>
<style lang="scss" scoped>
.modal-content{
padding: 20px;
.content-form{
margin-bottom: 20px;
}
.button-div{
display: flex;
justify-content: end;
.cancel-button{
margin-right: 10px;
}
}
}
</style>

View File

@ -0,0 +1,101 @@
<template>
<div>
<BasicTable @register="registerTable">
<template #toolbar>
<PermissionBtn @btnEvent="buttonClick"></PermissionBtn>
</template>
<template #bodyCell="{ column, record, index }">
<template v-if="column.key == 'LngLat'">
{{ `${record.lng}, ${record.lat}` }}
</template>
</template>
</BasicTable>
<a-modal v-model:open="addOrUpdateModalOpen" :title="modalType == 'add'? '添加': '编辑'" :footer="null" :destroyOnClose="true" @cancel="modalClose">
<AddOrUpdateModal :modalType="modalType" :modalData="modalData" @closeAddOrUpdateModal="closeAddOrUpdateModal"/>
</a-modal>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, reactive, watch, createVNode, unref } from 'vue';
import { Modal, message } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import { BasicTable, useTable } from '@/components/Table';
import { PermissionBtn } from '@/components/PermissionBtn/index';
import { LoadAllPage, Delete } from '@/api/illegalconstruction/miningsitemanagement'
import { columns, searchFormSchema } from './util';
import AddOrUpdateModal from './AddOrUpdateModal/index.vue'
const addOrUpdateModalOpen = ref(false)
const modalType = ref()
const modalData = ref({})
//
const [registerTable, { reload, getSelectRows, getPaginationRef }] = useTable({
title: '盗采点列表',
api: LoadAllPage,
columns: columns,
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
},
showIndexColumn: false,
rowSelection: {
type: 'radio',
},
useSearchForm: true,
bordered: true,
showTableSetting: true,
handleSearchInfoFn(info) {
return info;
},
});
//
const buttonClick = async (type) => {
switch (type) {
case 'btnAdd':
modalType.value = 'add'
addOrUpdateModalOpen.value = true
break;
case 'btnEdit':
let select = getSelectRows()
if (select.length !== 1) {
message.warning('请选择一条数据');
return;
}
console.log('getSelectRows()',getSelectRows())
modalData.value = {...select[0]}
modalType.value = 'update'
addOrUpdateModalOpen.value = true
break;
case 'btnDelete':
if (getSelectRows().length !== 1) {
message.warning('请选择一条数据');
return;
}
Modal.confirm({
title: '是否确认删除?',
icon: createVNode(ExclamationCircleOutlined),
onCancel() {},
onOk() {
return Delete(getSelectRows()).then(res => {
message.success('删除成功')
reload()
})
},
});
break;
}
};
const closeAddOrUpdateModal = (isReload=false) => {
addOrUpdateModalOpen.value = false
modalData.value = {}
if(isReload){
reload()
}
}
const modalClose = () => {
modalData.value = {}
}
</script>

View File

@ -0,0 +1,33 @@
import { BasicColumn, FormSchema } from '@/components/Table';
export const columns: BasicColumn[] = [
{
title: '名称',
dataIndex: 'name',
},
{
title: '区县',
dataIndex: 'countyName',
},
{
title: '乡镇',
dataIndex: 'streetName',
},
{
title: '社区/村',
dataIndex: 'communityName',
},
{
title: '经纬度',
dataIndex: 'LngLat',
},
];
export const searchFormSchema: FormSchema[] = [
{
field: 'key',
label: '名称',
component: 'Input',
colProps: { span: 8 },
},
];

View File

@ -0,0 +1,124 @@
<template>
<div class="modal-content">
<a-form class="content-form" ref="formRef" :model="props.modalData" :label-col="labelCol">
<a-form-item
label="编号"
name="num"
:rules="[{ required: true, message: '请输入编号' }]"
>
<a-input v-model:value="props.modalData.num" />
</a-form-item>
<a-form-item
label="名称"
name="name"
:rules="[{ required: true, message: '请输入名称' }]"
>
<a-input v-model:value="props.modalData.name" />
</a-form-item>
<a-form-item
label="负责人"
name="manager"
:rules="[{ required: true, message: '请输入负责人' }]"
>
<a-input v-model:value="props.modalData.manager" />
</a-form-item>
<a-form-item
label="联系方式"
name="phone"
:rules="[{ required: true, message: '请输入联系方式' }]"
>
<a-input v-model:value="props.modalData.phone" />
</a-form-item>
<a-form-item
label="地址"
name="address"
:rules="[{ required: true, message: '请输入地址' }]"
>
<div style="display: flex;">
<a-input v-model:value="props.modalData.address" style="margin-right: 10px;"/>
<a-button style="margin-right: 10px;" @click="mapVisible = true">选择地址</a-button>
</div>
</a-form-item>
</a-form>
<div class="button-div">
<a-button class="cancel-button" @click="cancel"></a-button>
<a-button class="save-button" type="primary" @click="submit"></a-button>
</div>
</div>
<a-modal
width="60%"
v-model:open="mapVisible"
title="选择位置"
@ok="handlePostionOk"
:destroyOnClose="true"
>
<Map ref="PostionRef" @getAddress="getAddress"/>
</a-modal>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue"
import Map from '@/components/illegalconstruction/Map.vue'
import { Add, Update } from '@/api/illegalconstruction/parkinglot'
import { message } from "ant-design-vue";
const props = defineProps(['modalType', 'modalData'])
const emits = defineEmits(['closeAddOrUpdateModal'])
const formRef = ref()
const PostionRef = ref();
const mapVisible = ref(false);
const labelCol = { style: { width: '80px' } };
onMounted(() => {
})
const handlePostionOk = () => {
const data = PostionRef.value.getPosition();
console.log(data);
if(data){
props.modalData.address = data.address
}
mapVisible.value = false;
};
const getAddress = (lng, lat, siteAddress) => {
console.log(lng,lat,siteAddress)
}
const submit = () => {
formRef.value.validate().then(() => {
console.log('values', props.modalData);
if(props.modalType == 'add'){
Add(props.modalData).then(res => {
message.success('停车场添加成功')
emits('closeAddOrUpdateModal',true)
})
}else{
Update(props.modalData).then(res => {
message.success('停车场编辑成功')
emits('closeAddOrUpdateModal',true)
})
}
})
.catch(error => {
console.log('error', error);
});
}
const cancel = () => {
emits('closeAddOrUpdateModal')
}
</script>
<style lang="scss" scoped>
.modal-content{
padding: 20px;
.content-form{
margin-bottom: 20px;
}
.button-div{
display: flex;
justify-content: end;
.cancel-button{
margin-right: 10px;
}
}
}
</style>

View File

@ -0,0 +1,101 @@
<template>
<div>
<BasicTable @register="registerTable">
<template #toolbar>
<PermissionBtn @btnEvent="buttonClick"></PermissionBtn>
</template>
<template #bodyCell="{ column, record, index }">
<template v-if="column.key == 'LngLat'">
{{ `${record.lng}, ${record.lat}` }}
</template>
</template>
</BasicTable>
<a-modal v-model:open="addOrUpdateModalOpen" :title="modalType == 'add'? '添加': '编辑'" :footer="null" :destroyOnClose="true" @cancel="modalClose">
<AddOrUpdateModal :modalType="modalType" :modalData="modalData" @closeAddOrUpdateModal="closeAddOrUpdateModal"/>
</a-modal>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, reactive, watch, createVNode, unref } from 'vue';
import { Modal, message } from 'ant-design-vue';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import { BasicTable, useTable } from '@/components/Table';
import { PermissionBtn } from '@/components/PermissionBtn/index';
import { LoadAllPage, Delete } from '@/api/illegalconstruction/parkinglot'
import { columns, searchFormSchema } from './util';
import AddOrUpdateModal from './AddOrUpdateModal/index.vue'
const addOrUpdateModalOpen = ref(false)
const modalType = ref()
const modalData = ref({})
//
const [registerTable, { reload, getSelectRows, getPaginationRef }] = useTable({
title: '停车场列表',
api: LoadAllPage,
columns: columns,
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
},
showIndexColumn: false,
rowSelection: {
type: 'radio',
},
useSearchForm: true,
bordered: true,
showTableSetting: true,
handleSearchInfoFn(info) {
return info;
},
});
//
const buttonClick = async (type) => {
switch (type) {
case 'btnAdd':
modalType.value = 'add'
addOrUpdateModalOpen.value = true
break;
case 'btnEdit':
let select = getSelectRows()
if (select.length !== 1) {
message.warning('请选择一条数据');
return;
}
console.log('getSelectRows()',getSelectRows())
modalData.value = {...select[0]}
modalType.value = 'update'
addOrUpdateModalOpen.value = true
break;
case 'btnDelete':
if (getSelectRows().length !== 1) {
message.warning('请选择一条数据');
return;
}
Modal.confirm({
title: '是否确认删除?',
icon: createVNode(ExclamationCircleOutlined),
onCancel() {},
onOk() {
return Delete(getSelectRows()).then(res => {
message.success('停车场删除成功')
reload()
})
},
});
break;
}
};
const closeAddOrUpdateModal = (isReload=false) => {
addOrUpdateModalOpen.value = false
modalData.value = {}
if(isReload){
reload()
}
}
const modalClose = () => {
modalData.value = {}
}
</script>

View File

@ -0,0 +1,33 @@
import { BasicColumn, FormSchema } from '@/components/Table';
export const columns: BasicColumn[] = [
{
title: '编号',
dataIndex: 'num',
},
{
title: '名称',
dataIndex: 'name',
},
{
title: '负责人',
dataIndex: 'manager',
},
{
title: '联系方式',
dataIndex: 'phone',
},
{
title: '地址',
dataIndex: 'address',
},
];
export const searchFormSchema: FormSchema[] = [
{
field: 'key',
label: '名称',
component: 'Input',
colProps: { span: 8 },
},
];

View File

@ -1,4 +1,5 @@
import { defineApplicationConfig } from '@vben/vite-config';
import {mars3dPlugin} from 'vite-plugin-mars3d';
export default defineApplicationConfig({
overrides: {
@ -56,6 +57,8 @@ export default defineApplicationConfig({
},
},
},
plugins: [],
plugins: [
mars3dPlugin()
],
},
});