徐景良 2025-12-22 08:58:32 +08:00
commit d6486eada2
23 changed files with 1125 additions and 127 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 936 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 990 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 844 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 953 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 703 B

View File

@ -0,0 +1,14 @@
import { defHttp } from '@/utils/http/axios';
enum Api {
LoadRcxjCaseinfo = '/api/DroneCaseInfoRcjg/LoadRcxjCaseinfo',
UpdateStatus = '/api/DroneCaseInfoRcjg/UpdateStatus',
}
export function LoadRcxjCaseinfo(params){
return defHttp.get({ url: Api.LoadRcxjCaseinfo, params });
}
export function UpdateStatus(id){
return defHttp.post({
url: `${Api.UpdateStatus}?id=${id}`,
});
}

View File

@ -416,6 +416,7 @@ const loadCaseInfoTuBanListUrlObj = {
"生态保护红线": '/api/DroneCaseInfoSTHX/LoadCaseInfoTuBanList',
"生态修复": '/api/DroneCaseInfoSTXF/LoadCaseInfoTuBanList',
"乱占耕地建房": '/api/DroneCaseInfoLzwjf/LoadCaseInfoTuBanList',
"设施农业监管": '/api/DroneCaseinfoSsnyjg/LoadCaseInfoTuBanList',
}
export function homePageLoadCaseInfoTuBanList(type,params) {
return defHttp.get({

View File

@ -43,7 +43,7 @@ enum Api {
// 获取用户访问机构权限
GetUserOrgs = '/api/Check/GetOrgs',
// 获取案件图片坐标、方位角信息
LoadCaseImgList = "/api/DroneCaseInfoLzwjf/LoadCaseImgList",
LoadCaseImgList = "/api/DroneCaseInfoSingle/LoadCaseImgList",
// 线索列表
LoadCaseInfoTuBanList = '/api/DroneCaseInfoLzwjf/LoadCaseInfoTuBanList',
CaseOffence = '/api/DroneCaseInfoLzwjf/CaseOffenceLzgdjf',

View File

@ -1778,6 +1778,12 @@
createMessage.error('请传入操作类型!');
}
};
const handlerShowPoint = (lng, lat) => {
new mapboxgl.Marker({
color: 'red' //
}).setLngLat([lng, lat]).addTo(map);
handlerLocation([lng,lat])
}
const currentGeoJson = ref({});
const editGeoJson = ref({})
@ -2359,6 +2365,7 @@
handlerCancleDraw,
handlerLoadPictureAzimuth,
handlerCurrentImageChange,
handlerShowPoint,
});
</script>

View File

@ -263,7 +263,7 @@
import MapboxMap from '@/components/MapboxMaps/MapComponent.vue';
import { getConfig } from '@/api/sys/layerManagement';
import { getGeom } from '@/api/sys/layerManagement';
import { getLoadCaseImgList } from '@/api/inspectionaudit';
import { getLoadCaseImgList } from '@/api/farmland';
import { useMessage } from '@/hooks/web/useMessage';
import axios from 'axios';
import Icon from '@/components/Icon/Icon.vue';
@ -300,7 +300,7 @@
async function getCaseImgList() {
imageList.value = await getLoadCaseImgList({
caseid: props.showInfoData.id,
category: '巡察审计',
category: '乱占耕地建房',
});
MapboxComponent.value.handlerLoadPictureAzimuth(imageList.value);

View File

@ -301,5 +301,9 @@ export const getZhuantiName = () => {
return '非法采矿'
case "100002":
return '非法采矿'
case "0000009":
return '乱占耕地建房'
case "0000010":
return '设施农业监管'
}
}

View File

@ -0,0 +1,395 @@
<template>
<div class="detail-container">
<div class="map-container" v-if="!props.hiddenInfoMap">
<MapboxMap
:caseno="props.showInfoData.case_no"
:countyname="props.showInfoData.countyname"
:imageList="imageList"
:geomsList="geomsList"
:mapConfig="mapConfig"
@handlerDrawComplete="handlerDrawComplete"
@mapOnLoad="onMapboxLoad"
ref="MapboxComponent"
/>
</div>
<div class="info-container" id="info-container">
<a-descriptions
:column="2"
bordered
:contentStyle="{
'text-align': 'center',
'min-width': '250px',
'word-break': 'break-all',
}"
>
<a-descriptions-item label="线索编号">
{{ props.showInfoData.case_no }}
</a-descriptions-item>
<a-descriptions-item label="区县">
{{ props.showInfoData.countyname }}
</a-descriptions-item>
<a-descriptions-item label="乡镇">
{{ props.showInfoData.streetname }}
</a-descriptions-item>
<a-descriptions-item label="社区/村">
{{ props.showInfoData.communityname }}
</a-descriptions-item>
<a-descriptions-item label="线索类型">
{{ getLabel('typename', props.showInfoData.typename) }}
</a-descriptions-item>
<a-descriptions-item label="线索来源">
{{ getLabel('tubanlaiyuan', props.showInfoData.tubanlaiyuan) }}
</a-descriptions-item>
<a-descriptions-item label="上报时间">
{{ props.showInfoData.createtime }}
</a-descriptions-item>
<a-descriptions-item label="经度">
{{ props.showInfoData.lng }}
</a-descriptions-item>
<a-descriptions-item label="纬度">
{{ props.showInfoData.lat }}
</a-descriptions-item>
<a-descriptions-item label="线索描述">
{{ props.showInfoData.case_description }}
</a-descriptions-item>
<a-descriptions-item label="线索状态">
{{ getLabel('biaozhu', props.showInfoData.biaozhu) }}
</a-descriptions-item>
<a-descriptions-item label="线索照片" :span="2">
<div class="image-div">
<a-image-preview-group
:preview="{
getContainer: getContainer,
onVisibleChange: handlerImageChange,
}"
>
<template v-for="(imageItem, imageIndex) in casepicList" :key="imageIndex">
<a-image
v-if="imageItem"
width="100px"
height="100px"
:src="`${VITE_GLOB_INFO_IMAGE_URL}/${imageItem}`"
@click="handlerPreviewImage(imageIndex, imageItem)"
:preview="{
getContainer,
}"
></a-image>
</template>
</a-image-preview-group>
</div>
</a-descriptions-item>
</a-descriptions>
<a-button style="width: 100px;" type="primary" @click="confirm"></a-button>
</div>
<!-- File Preview && Download Start -->
<a-modal
v-model:open="previewFileModalVisible"
style="width: 100vw"
title="文件预览"
wrap-class-name="full-modal"
>
<FilePreview v-if="previewFileModalVisible" :fileUrl="previewFileUrl"></FilePreview>
<template #footer>
<a-button key="cancel" @click="handleCancelPreviewFile"></a-button>
<a-button key="confirm" type="primary" @click="handlerDownloadFle"></a-button>
</template>
</a-modal>
<!--File Preview && Download End -->
</div>
</template>
<script setup lang="ts">
import { defineProps, defineEmits, ref, computed, onBeforeMount, watch, onMounted } from 'vue';
import MapboxMap from '@/components/MapboxMaps/MapComponent.vue';
import { getConfig } from '@/api/sys/layerManagement';
import { getGeom } from '@/api/sys/layerManagement';
import { getLoadCaseImgList } from '@/api/facilityfarm';
import { UpdateStatus } from '@/api/dailycheck';
import { useMessage } from '@/hooks/web/useMessage';
import axios from 'axios';
const { createMessage } = useMessage();
import Icon from '@/components/Icon/Icon.vue';
import { getAppEnvConfig } from '@/utils/env';
const { VITE_GLOB_INFO_IMAGE_URL } = getAppEnvConfig();
import dayjs from 'dayjs';
const MapboxComponent = ref();
const mapConfig = ref({});
const props = defineProps(['showInfoData','hiddenInfoMap', 'typenameOptions', 'tubanlaiyuanOptions']);
const emits = defineEmits(['reload']);
const activeKey = ref('1');
const geomsList = ref();
const imageList = ref([]);
console.log('props', props.showInfoData);
watch(
() => props.showInfoData,
() => {
getConfig({ code: 'mapsetting' }).then((res) => {
mapConfig.value = JSON.parse(res.codeValue);
});
changeTask();
},
);
async function getCaseImgList() {
imageList.value = await getLoadCaseImgList({
caseid: props.showInfoData.id,
category: '日常巡检',
});
MapboxComponent.value.handlerLoadPictureAzimuth(imageList.value);
//
// let zhengshiImageList = [];
// imageList.value?.forEach((item,index)=>{
// let obj = anjianzhaopianList.value?.find((it,idx)=>{
// return item.filePath == it;
// })
// if(obj){
// zhengshiImageList.push(imageList.value[index]);
// }
// })
}
function handlerDealFileName(path) {
const regex = /([^/\\]+)(?=\.[^/\\]*$|$)/;
const matchStr = path.match(regex);
if (matchStr?.length) {
return matchStr[0];
}
}
function handlerPreviewImage(index, url) {
const regex = /([^/\\]+)(?=\.[^/\\]*$|$)/;
const match = url.match(regex);
if (match) {
MapboxComponent.value.handlerCurrentImageChange(match[1]);
}
}
const isInitImageLisener = ref<Boolean>(false);
//
function handlerImageChange(e): void {
isInitImageLisener.value = false;
if (e && !isInitImageLisener.value) {
setTimeout(function () {
const targetNode = document.getElementsByClassName('ant-image-preview-img');
targetNode?.forEach((node, index) => {
let imageObserver = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
if (node.getAttribute(mutation.attributeName).match('http')) {
handlerPreviewImage(0, node.getAttribute(mutation.attributeName));
}
}
});
const config = { attributes: true };
imageObserver.observe(node, config);
isInitImageLisener.value = true;
});
}, 250);
}
}
onBeforeMount(() => {
getCaseImgList()
});
onMounted(() => {
if(props.showInfoData.lng && props.showInfoData.lat){
MapboxComponent.value.handlerShowPoint(props.showInfoData.lng, props.showInfoData.lat);
}
})
const casepicList = computed(() => {
return props.showInfoData.casepic ? props.showInfoData.casepic.split(',') : [];
});
function onMapboxLoad() {
changeTask();
}
const getLabel = (type, value) => {
let result: any[] = [];
let label = '';
switch (type) {
case 'typename':
result = props.typenameOptions;
break;
case 'tubanlaiyuan':
result = props.tubanlaiyuanOptions;
break;
case 'biaozhu':
result = [
{ label: '未确认', value: 0},
{ label: '已确认', value: 1},
];
break;
}
result.forEach((item) => {
if (item.value == value) {
label = item.label;
}
});
return label;
};
async function changeTask() {
let getGeomPrams = {
TableName: 'drone_shp_data ',
FieldName: 'gid',
FieldValue: props.showInfoData.geomid?.split(','),
page: 1,
limit: 999,
key: null,
};
if (props.showInfoData.geomid) {
getGeom(getGeomPrams).then((res) => {
let geoms = [];
if (res) {
if (res.items?.length > 0) {
res.items.forEach((item, index) => {
let geom = {
key: item.gid,
mapgeom: item.geometry,
};
geoms.push(geom);
geomsList.value = geoms;
});
}
// MapboxComponent.value.handlerDraw(status,mapgemoList.value, false);
MapboxComponent.value.handlerDraw('Details', geoms, false);
} else {
geomsList.value = null;
// createMessage.error('线');
}
});
} else {
// createMessage.error('线');
}
}
import FilePreview from '@/components/Upload/src/components/FilePreview.vue';
import { message } from 'ant-design-vue';
const previewFileModalVisible = ref(false);
const previewFileUrl = ref('');
const hanlderPreViewFile = (url) => {
previewFileUrl.value = `${VITE_GLOB_INFO_IMAGE_URL}/${url}`;
previewFileModalVisible.value = true;
};
const handlerDownloadFle = () => {
window.open(previewFileUrl.value, 'mozillaTab');
};
const handleCancelPreviewFile = () => {
previewFileModalVisible.value = false;
};
///////
const getContainer = () => {
return document.getElementById('info-container');
};
const dataProcessing = (value) => {
if (!value) {
return '0';
}
if (value.indexOf('.') == -1) {
return value;
} else {
if (value.split('.')[1].length <= 2) {
return value;
}
let resultString = value.replace('㎡', '');
return Number(resultString).toFixed(2);
}
};
const showImage = (url) => {
if (url.indexOf('.png') !== -1 || url.indexOf('.jpg') !== -1 || url.indexOf('.jpeg') !== -1) {
return true;
} else {
return false;
}
};
const confirm = () => {
UpdateStatus(props.showInfoData.id).then(res => {
message.success('确认成功')
emits('reload')
})
}
</script>
<style lang="scss" scoped>
.image-div {
min-width: 340px;
max-height: 220px;
overflow: auto;
}
.detail-container {
width: 100%;
height: calc(100vh - 120px);
display: flex;
padding: 0px 20px;
}
.detail-container::after {
content: '';
display: block;
clear: both;
height: 0;
visibility: none;
}
.map-container {
float: left;
width: 45vw;
height: calc(100vh - 100px);
margin-right: 20px;
}
:deep(.ant-image) {
margin-right: 10px;
margin-bottom: 10px;
}
:deep(.ant-image-preview-switch-left) {
position: absolute;
}
:deep(.ant-image-preview-switch-right) {
position: absolute;
}
.info-container {
// float: left;
position: relative;
flex: 1;
display: flex;
flex-flow: column;
justify-content: space-between;
:deep(.ant-image-preview-wrap) {
position: absolute;
}
:deep(.ant-image-preview-mask) {
position: absolute;
}
:deep(.ant-image-preview-operations-wrapper) {
height: 100%;
position: absolute;
.ant-image-preview-operations {
position: absolute;
top: 0;
width: 100%;
.ant-image-preview-operations-operation {
// flex:1;
}
}
.ant-image-preview-operations-operation:nth-last-child(1) {
display: none;
}
.ant-image-preview-operations-operation:nth-last-child(2) {
display: none;
}
}
}
::v-deep .ant-tabs .ant-tabs-content-holder {
overflow: auto;
height: 80vh;
overflow: auto;
padding-right: 10px;
}
</style>

View File

@ -0,0 +1,135 @@
<template>
<PageWrapper dense contentFullHeight fixedHeight contentClass="flex">
<BasicTable @register="registerTable">
<template #bodyCell="{ column, record, text }">
<template v-if="column.key === 'action'">
<TableAction
:actions="[
{
label: '详情',
onClick: () => {
handleInfo(record);
},
}
]"
/>
</template>
<template v-if="['typename','tubanlaiyuan','biaozhu'].includes(column.dataIndex)">
{{ getLabel(column.dataIndex, text) }}
</template>
</template>
</BasicTable>
<a-modal
style="width: 100vw; top: 0px; left: 0px; margin: 0px; padding: 0px"
wrap-class-name="full-modal"
v-model:open="showInfoOpen"
title="详情"
:footer="null"
:maskClosable="true"
:destroyOnClose="true"
@cancel="showInfoOpen = false"
>
<ShowInfoModal
:showInfoData="showInfoData"
:typenameOptions="typenameOptions"
:tubanlaiyuanOptions="tubanlaiyuanOptions"
@reload="reloadList"
/>
</a-modal>
</PageWrapper>
</template>
<script setup lang="ts">
import { ref } from "vue"
import { BasicTable, useTable, TableAction } from '@/components/Table';
import { columns, searchFormSchema, typenameOptions, tubanlaiyuanOptions } from './utils';
import { LoadRcxjCaseinfo } from '@/api/dailycheck/index'
import ShowInfoModal from '@/views/demo/dailycheck/ShowInfoModal/index.vue'
import dayjs from "dayjs";
const showInfoOpen = ref(false)
const showInfoData = ref();
const [registerTable, { getForm, reload }] = useTable({
title: '线索列表',
api: LoadRcxjCaseinfo,
columns,
rowKey: 'id',
useSearchForm: true,
showTableSetting: true,
bordered: true,
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
showAdvancedButton: false, // /
alwaysShowLines: 0,
},
actionColumn: {
width: 80,
title: '操作',
dataIndex: 'action',
fixed: 'right',
},
beforeFetch: (params) => {
let resultParams = {
...params
}
if(resultParams.synchronoustimebegin){
resultParams.synchronoustimebegin = dayjs(resultParams.synchronoustimebegin).startOf('day').format('YYYY-MM-DD HH:mm:ss');
}
if(resultParams.synchronoustimeend){
resultParams.synchronoustimeend = dayjs(resultParams.synchronoustimeend).endOf('day').format('YYYY-MM-DD HH:mm:ss');
}
return resultParams
},
});
function handleInfo(record) {
showInfoData.value = record
showInfoOpen.value = true
}
const getLabel = (type, value) => {
let result: any[] = [];
let label = '';
switch (type) {
case 'typename':
result = typenameOptions;
break;
case 'tubanlaiyuan':
result = tubanlaiyuanOptions;
break;
case 'biaozhu':
result = [
{ label: '未确认', value: 0},
{ label: '已确认', value: 1},
];
break;
}
result.forEach((item) => {
if (item.value == value) {
label = item.label;
}
});
return label;
};
const reloadList = () => {
reload()
}
</script>
<style lang="scss" scoped>
.full-modal {
.ant-modal {
min-width: 100vw;
top: 0px;
padding: 0px;
margin: 0px;
}
.ant-modal-content {
display: flex;
flex-direction: column;
}
.ant-modal-body {
flex: 1;
}
}
</style>

View File

@ -0,0 +1,158 @@
import { BasicColumn, FormSchema } from '@/components/Table';
import { getChildrenTree } from '@/api/demo/system';
import { getLoad } from '@/api/sys/sysDataItemDetail';
import { asyncGetOptions } from '@/utils/global'
import dayjs from 'dayjs';
export const typenameOptions = await asyncGetOptions('rcxjxslx');
export const tubanlaiyuanOptions = await asyncGetOptions('rcxjxsly');
export const columns: BasicColumn[] = [
{
title: '线索来源',
dataIndex: 'tubanlaiyuan',
},
{
title: '线索编号',
dataIndex: 'case_no',
width: 240
},
{
title: '县区',
dataIndex: 'countyname',
width: 100
},
{
title: '乡镇',
dataIndex: 'streetname',
width: 100
},
{
title: '社区/村',
dataIndex: 'communityname',
},
{
title: '线索类型',
dataIndex: 'typename',
},
{
title: '线索描述',
dataIndex: 'case_description',
},
{
title: '线索状态',
dataIndex: 'biaozhu',
},
{
title: '上报时间',
dataIndex: 'createtime',
},
{
title: '经度',
dataIndex: 'lng',
},
{
title: '纬度',
dataIndex: 'lat',
},
];
export const searchFormSchema: FormSchema[] = [
{
field: 'typename',
component: 'ApiSelect',
colProps: { span: 5 },
label: '线索类型',
componentProps: ({ formModel }) => {
return {
api: getLoad,
params: { code: 'rcxjxslx' },
resultField: 'result',
labelField: 'itemName',
valueField: 'itemValue',
};
},
},
{
field: 'tubanlaiyuan',
component: 'ApiSelect',
colProps: { span: 5 },
label: '线索来源',
componentProps: ({ formModel }) => {
return {
api: getLoad,
params: { code: 'rcxjxsly' },
resultField: 'result',
labelField: 'itemName',
valueField: 'itemValue',
};
},
},
{
field: 'countyid',
label: '区县',
component: 'ApiSelect',
colProps: { span: 5 },
componentProps: ({ formModel }) => {
return {
api: getChildrenTree,
params: { parentId: 371300 },
// 接口参数
resultField: 'result',
labelField: 'name',
valueField: 'id',
onChange: () => {
formModel.streetid = '';
},
};
},
},
{
field: 'streetid',
label: '乡镇',
component: 'ApiSelect',
colProps: { span: 5 },
componentProps: ({ formModel }) => {
return {
api: formModel.countyid && getChildrenTree,
params: { parentId: formModel.countyid },
// 接口参数
resultField: 'result',
labelField: 'name',
valueField: 'id',
placeholder: '请先选择区县',
};
},
},
{
field: 'biaozhu',
label: '线索状态',
component: 'Select',
colProps: { span: 4 },
componentProps: {
options: [
{ label: '未确认', value: 0},
{ label: '已确认', value: 1},
],
},
},
{
field: '[synchronoustimebegin, synchronoustimeend]',
label: '上报时间',
component: 'RangePicker',
colProps: { span: 5 },
componentProps: {
format: 'YYYY-MM-DD',
placeholder: ['开始日期', '结束日期'],
},
},
{
field: 'case_no',
label: '线索编号',
component: 'Input',
colProps: { span: 5 },
},
];

View File

@ -1,33 +1,6 @@
<template>
<div class="map-list-content">
<div class="screen-div">
<!-- <div class="screen-item" style="margin-right:15px;margin-bottom:15px;">
<div class="screen-item-label">年份</div>
<a-select
allowClear
style="width:122px;"
v-model:value="params.year"
:options="props.yearOptions"
/>
</div>
<div class="screen-item" style="margin-right:15px;margin-bottom:15px;">
<div class="screen-item-label">线索来源</div>
<a-select
allowClear
style="width:122px;"
v-model:value="params.tubanlaiyuan"
:options="stxftblyOptions"
/>
</div>
<div class="screen-item" style="margin-bottom:15px;">
<div class="screen-item-label">批次</div>
<a-select
allowClear
style="width:122px;"
v-model:value="params.picihao"
:options="stxfpcOptions"
/>
</div> -->
<div class="screen-item" style="margin-right:15px;margin-bottom:15px;">
<div class="screen-item-label">县区</div>
<a-select
@ -57,7 +30,7 @@
/>
</div>
<div class="screen-item" style="margin-right:10px;">
<a-input style="width:450px;" allowClear v-model:value="params.geomid" class="item-input" placeholder="请输入备案编号" @press-enter="query"/>
<a-input style="width:450px;" allowClear v-model:value="params.caseno" class="item-input" placeholder="请输入备案编号" @press-enter="query"/>
</div>
<div class="screen-item" style="display: flex; justify-content: end;margin-bottom: 0px;">
<a-button type="primary" class="item-button" :icon="h(SearchOutlined)" @click="query"></a-button>
@ -271,7 +244,7 @@
level: props.level,
countyid: null,
streetid: null,
geomid: null,
caseno: null,
year: props.year,
picihao: props.batch,
tubanlaiyuan: null,

View File

@ -24,7 +24,7 @@
'word-break': 'break-all',
}"
>
<a-descriptions-item label="线索编号">
<a-descriptions-item label="编号">
{{ props.showInfoData.case_no }}
</a-descriptions-item>
<a-descriptions-item label="项目名称">
@ -58,7 +58,7 @@
{{ props.showInfoData.linbao_area }}
</a-descriptions-item>
<a-descriptions-item label="备案时间">
{{ props.showInfoData.beianshijian }}
{{ props.showInfoData.beianshijian && dayjs(props.showInfoData.beianshijian).format('YYYY-MM-DD') }}
</a-descriptions-item>
<a-descriptions-item label="审核意见" :span="2">
{{ props.showInfoData.shijiyijian }}
@ -198,6 +198,7 @@
import Icon from '@/components/Icon/Icon.vue';
import { getAppEnvConfig } from '@/utils/env';
const { VITE_GLOB_INFO_IMAGE_URL } = getAppEnvConfig();
import dayjs from 'dayjs';
import {
mapTypeOptions,

View File

@ -1,36 +1,6 @@
<template>
<div class="map-list-content">
<div class="screen-div">
<!-- <div class="screen-item" style="margin-right:20px;margin-bottom:12px;">
<div class="screen-item-label">年份</div>
<a-select
allowClear
style="width:120px;"
v-model:value="props.infoScreenData.year"
:options="yearOptions"
@change="(value) => emits('mapListScreenChange',value,'year')"
/>
</div>
<div class="screen-item" style="margin-right:17px;margin-bottom:12px;">
<div class="screen-item-label" style="margin-right: 11px;">线索来源</div>
<a-select
allowClear
style="width:120px;"
v-model:value="props.infoScreenData.patchSource"
:options="stxftblyOptions"
@change="(value) => emits('mapListScreenChange',value,'patchSource')"
/>
</div>
<div class="screen-item" style="margin-bottom:12px;">
<div class="screen-item-label">批次</div>
<a-select
allowClear
style="width: 118px"
:options="stxfpcOptions"
v-model:value="props.infoScreenData.batch"
@change="(value) => emits('mapListScreenChange',value,'batch')"
/>
</div> -->
<div class="screen-item" style="margin-bottom:12px;">
<div class="screen-item-label">乡镇</div>
<a-select
@ -91,53 +61,6 @@
</div>
</div>
<div class="collect-div">
<a-popover placement="bottom">
<template #content>
<div style="display:flex;">
<div>当前状态</div>
<div>
<a-checkbox-group
v-model:value="props.infoScreenData.mapStatus"
@change="(value) => emits('mapListScreenChange',value,'mapStatus')"
style="width: 100%"
:options="stxftbztOptions"
/>
</div>
</div>
<div style="display:flex; align-items: center; margin-top: 4px;">
<div>线索面积</div>
<div style="display:flex;">
<a-input style="width:40%;"
v-model:value="props.infoScreenData.mapAreaFirst"
@change="(e) => emits('mapListScreenChange',e.target.value,'mapAreaFirst')"
/>
<span>---</span>
<a-input
style="width:40%;margin-right: 4px;"
v-model:value="props.infoScreenData.mapAreaLast"
@change="(e) => emits('mapListScreenChange',e.target.value,'mapAreaLast')"
/>
</div>
</div>
<div style="display:flex; margin-top: 4px;">
<div>耕地面积</div>
<div style="display:flex;align-items: center;">
<a-input style="width:40%;"
v-model:value="props.infoScreenData.arableAreaFirst"
@change="(e) => emits('mapListScreenChange',e.target.value,'arableAreaFirst')"
/>
<span>---</span>
<a-input style="width:40%;margin-right: 4px;"
v-model:value="props.infoScreenData.arableAreaLast"
@change="(e) => emits('mapListScreenChange',e.target.value,'arableAreaLast')"
/>
</div>
</div>
</template>
<img src="@/assets/images/tiankongdi/filt.png" class="img-box mr-r-20" />
</a-popover>
<img src="@/assets/images/tiankongdi/collect-active.png" class="img-box" @click="getCollectList" v-if="openCollect"/>
<img src="@/assets/images/tiankongdi/collect.png" class="img-box" @click="getCollectList" v-else/>
</div>

View File

@ -205,7 +205,7 @@ export const searchFormSchema: FormSchema[] = [
},
{
field: 'caseNo',
label: '线索编号',
label: '编号',
component: 'Input',
colProps: { span: 5 },
},

View File

@ -222,6 +222,19 @@ export const searchFormSchema: FormSchema[] = [
},
colProps: { span: 4 },
},
{
field: 'juzheng',
label: '举证情况',
component: 'Select',
componentProps: {
options: [
{ label: '全部', value: 0 },
{ label: '已举证', value: 1 },
{ label: '未举证', value: 2 },
],
},
colProps: { span: 4 },
},
{
field: 'case_name',
label: '项目名称',

View File

@ -39,6 +39,14 @@ export const flowCode = [
code: '0000008',
name: '生态修复',
},
{
code: '0000009',
name: '乱占耕地建房',
},
{
code: '0000010',
name: '设施农业监管',
},
];
export const flowCodeName = (code) => {
const item = flowCode.find((item) => item.code === code);

View File

@ -52,6 +52,11 @@
<div> {{ currentTime_week }} </div>
<div> {{ currentTime_year }} </div>
</div>
<!-- <div class="subject_top_currentTime_interval"></div>
<div class="subject_top_currentTime_monitor" @click="getHome(monitor)">
<div class="subject_top_currentTime_monitor_icon"></div>
<div class="subject_top_currentTime_monitor_span">监测中心</div>
</div> -->
</div>
<div
class="subject_top_adminAndLogout"
@ -63,9 +68,30 @@
>
<span class="loginUser"> {{ loginUser }} {{ t('sys.subject.header_admin') }}</span>
&nbsp;&nbsp;
<img src="/subject_lindidiaocha/setting.png" @click="getHome(setting)" />
&nbsp;&nbsp;
<span class="line" @click="getHome(setting)"> {{ setting.title }} &nbsp;&nbsp;</span>
<a-dropdown :placement="'bottomRight'" :arrow="{ pointAtCenter: true }" overlayClassName="subject-right-menu-list">
<div style="display: flex;align-items: center;">
<img src="/subject_lindidiaocha/setting.png" @click="getHome(setting)" />
&nbsp;&nbsp;
<span class="line" @click="getHome(setting)"> {{ setting.title }}</span>
<div class="dropdown-icon"></div>
</div>
<template #overlay>
<a-menu>
<a-menu-item>
<div class="button-item" @click="getHome(monitor)">
<div class="button-icon monitor-center-icon"></div>
监测中心
</div>
</a-menu-item>
<a-menu-item>
<div class="button-item" @click="getHome(data)">
<div class="button-icon data-center-icon"></div>
数据中心
</div>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
<span class="line"> | </span>
&nbsp;&nbsp;&nbsp;&nbsp;
<img src="/subject_lindidiaocha/logout.png" @click="handleLoginOut()" />
@ -279,22 +305,36 @@
const userStore = useUserStore();
const spanWrap = ref(1);
const setting = ref({});
const monitor = ref({})
const data = ref()
async function getData() {
const res: any = await getSpecialData();
let result:any = []
//
res?.forEach((item, index) => {
if (item.title == '系统管理') {
setting.value = item;
res.splice(index, 1);
} else {
res.isHover = false;
if (Math.ceil(item.title.length / 6) > spanWrap.value) {
spanWrap.value = Math.ceil(item.title.length / 6);
}
switch(item.title){
case '系统管理':
setting.value = item;
break
case '监测中心':
monitor.value = item
break
case '数据中心':
data.value = item
break
default:
let useItem = {
...item,
isHover: false,
}
result.push(useItem)
if (Math.ceil(item.title.length / 6) > spanWrap.value) {
spanWrap.value = Math.ceil(item.title.length / 6);
}
}
});
list.value = res;
list.value = result;
loginUser.value = localStorage.getItem('fireUserLoginName');
}
@ -454,11 +494,36 @@
color: #ffffff;
line-height: 12px;
display: block;
margin-right: 27px;
div {
margin-bottom: 2px;
}
}
&_interval{
width: 1px;
height: 100%;
background: linear-gradient(0deg, rgba(255,255,255,0.01), #FFFFFF, rgba(255,255,255,0));
margin-right: 24px;
}
&_monitor{
display: flex;
align-items: center;
cursor: pointer;
&_icon{
width: 20px;
height: 20px;
background-image: url('/public/subject/monitor_icon.png');
margin-right: 9px;
}
&_span{
font-family: Microsoft YaHei;
font-weight: 400;
font-size: 16px;
color: #FFFFFF;
line-height: 24px;
}
}
}
&_adminAndLogout {
@ -491,6 +556,14 @@
top: 0px;
font-size: 18px;
color: #ffffff;
margin-right: 8px;
}
.dropdown-icon{
width: 8px;
height: 8px;
background-image: url('/public/subject/dropdown_icon.png');
background-size: 100% 100%;
margin-right: 15px;
}
}
}
@ -602,3 +675,40 @@
}
}
</style>
<style lang="scss">
.subject-right-menu-list{
.button-item{
font-family: Microsoft YaHei;
font-weight: 400;
font-size: 16px;
color: #000000;
line-height: 24px;
display: flex;
.button-icon{
width: 20px;
height: 20px;
margin-right: 9px;
}
.monitor-center-icon{
background-image: url('/public/subject/monitor_center.png');
background-size: 100% 100%;
}
.data-center-icon{
background-image: url('/public/subject/data_center.png');
background-size: 100% 100%;
}
}
.ant-dropdown-menu-item:hover{
background-color: rgba(42, 144, 241, 0.1) !important;
.button-item{
color: #2A90F1;
.monitor-center-icon{
background-image: url('/public/subject/monitor_center_hover.png');
}
.data-center-icon{
background-image: url('/public/subject/data_center_hover.png');
}
}
}
}
</style>

View File

@ -6,6 +6,60 @@
@handlerFilter="handlerFilter"
:layerSettings="layerSettings"
></SearchComponent>
<div class="to-location-button" @click="LocationShow = !LocationShow">
<EnvironmentOutlined style="color: #fff;font-size: 20px;"/>
</div>
<div class="to-location-input" v-if="LocationShow">
<div class="location-operation">
<span style="font-size: 16px;">坐标定位</span>
<span style="float: right;margin-right: 10px;cursor: pointer;">
<CloseOutlined @click="handlerLocationClose" />
</span>
</div>
<div class="location-item-list-coantienr">
<a-table :dataSource="locationArrays" size="small" :pagination="false" >
<a-table-column-group>
<a-table-column key="lng" title="经度(Y)" data-index="lng">
<template #default="{ record }">
<a-input
v-model:value="record.lng"
@chagne="handlerLocationChange"
size="small"
/>
</template>
</a-table-column>
<a-table-column key="lat" title="纬度(X)" data-index="lat">
<template #default="{record}">
<a-input
v-model:value="record.lat"
@chagne="handlerLocationChange"
size="small"
/>
</template>
</a-table-column>
<a-table-column key="operation" title="操作" data-index="operation" width="100px">
<template #default="{record,index}">
<a-button type="default" size="small" @click="handlerLocationFlyTo(index)"
><EnvironmentOutlined
/></a-button>
&nbsp;
<a-button type="default" size="small" @click="handlerClearDate(index)"
><DeleteOutlined
/></a-button>
</template>
</a-table-column>
</a-table-column-group>
</a-table>
</div>
</div>
</div>
<div class="map-type-switch-container">
<div class="switch-button" v-if="mapAngle == '3D'" @click="handlerChangeMapAngle()">
@ -30,7 +84,7 @@
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, defineExpose, defineEmits, defineProps, watch } from 'vue';
import { ref, onMounted, defineExpose, defineEmits, defineProps, watch, reactive } from 'vue';
import { generateUUID } from '@/components/MapboxMaps/src/tool';
import { WktToGeojson } from '@/components/MapboxMaps/src/WktGeojsonTransform';
import mapboxgl, { Map, Popup } from 'mapbox-gl';
@ -46,7 +100,30 @@
const mapContainerName = ref<String>();
mapContainerName.value = 'mapContainer-' + generateUUID();
const { VITE_GLOB_YINGXIANG_SERVER, VITE_GLOB_YAOGANYINGXIANG_SERVER } = getAppEnvConfig();
import { CloseOutlined, MinusOutlined, ExpandAltOutlined, EnvironmentOutlined, DeleteOutlined, } from '@ant-design/icons-vue';
import proj4 from 'proj4'
interface LocationItem {
lng: string;
lat: string;
}
const LocationShow = ref<Boolean>(false);
const locationArrays = ref<LocationItem[]>([{ lng: '',lat: '', }]);
const locationDrawArrays = ref<LocationItem[]>();
const locationGeoJson = reactive({
point: {
type: 'FeatureCollection',
features: [],
},
polyline: {
type: 'FeatureCollection',
features: [],
},
polygon: {
type: 'FeatureCollection',
features: [],
},
});
const networkType = ref("WAN");
const showTodayType = ref<null | number>(null)
const handlerLoadPolygonAttr = ref({
@ -554,7 +631,7 @@
}
//
function handlerLocation(lngLat, zoom) {
function handlerLocation(lngLat, zoom=17) {
map.flyTo({
center: lngLat,
zoom: zoom,
@ -1176,8 +1253,146 @@
const { code, filter, type, level } = handlerLoadPolygonAttr.value;
handlerLoadPolygon(code, filter, type, level);
}
const handlerLocationClose = () => {
LocationShow.value = false;
};
const handlerLocationChange = (e) => {};
//
const handlerLocationFlyTo = (clickIndex:number) => {
locationDrawArrays.value = [];
locationArrays.value?.forEach((location)=>{
let obj={...location}
//console.log(obj);
locationDrawArrays.value?.push(obj)
})
locationDrawArrays.value?.forEach((item,index)=>{
//
if(item.lng > 180){
let coor = GkToCGCS2000([parseFloat(item.lng),parseFloat(item.lat)]);
item.lng = coor[0];
item.lat = coor[1];
}
if (item.lng && item.lat) {
handlerLocationGeoJson();
}
})
//
handlerLocation([locationDrawArrays.value[clickIndex].lng, locationDrawArrays.value[clickIndex].lat]);
};
//
function GkToCGCS2000(lngLat){
try{ //
let from_system = "";
if(lngLat[0]>=37000000 && lngLat[0] < 38000000){
from_system = "+proj=tmerc +lat_0=0 +lon_0=111 +k=1 +x_0=37500000 +y_0=0 +ellps=GRS80 +units=m +no_defs +type=crs"
}if(lngLat[0]>=38000000 && lngLat[0] < 39000000){
from_system = "+proj=tmerc +lat_0=0 +lon_0=114 +k=1 +x_0=38500000 +y_0=0 +ellps=GRS80 +units=m +no_defs +type=crs"
}if(lngLat[0]>=39000000 && lngLat[0] < 40000000){ // CGCS2000 / 3-degree Gauss-Kruger zone 39
from_system = "+proj=tmerc +lat_0=0 +lon_0=117 +k=1 +x_0=39500000 +y_0=0 +ellps=GRS80 +units=m +no_defs +type=crs"
}else if(lngLat[0] >= 40000000){ // CGCS2000 / 3-degree Gauss-Kruger zone 40
from_system = "+proj=tmerc +lat_0=0 +lon_0=120 +k=1 +x_0=40500000 +y_0=0 +ellps=GRS80 +units=m +no_defs +type=crs"
}
// China Geodetic Coordinate System 2000
// let to_system = "+proj=longlat +ellps=GRS80 +no_defs +type=crs";
// WGS 84 -- WGS84 - World Geodetic System 1984,
let to_system = "+proj=longlat +datum=WGS84 +no_defs +type=crs";
// transform
let trasnformLnglat = proj4(from_system,to_system,lngLat);
return trasnformLnglat;
}catch(e){
return null;
}
}
const handlerLocationGeoJson = () => {
locationGeoJson.point.features = [];
locationGeoJson.polyline.features = [];
locationGeoJson.polygon.features = [];
locationDrawArrays.value?.forEach((item, index) => {
if (item.lng && item.lat) {
let feature = {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [parseFloat(item.lng), parseFloat(item.lat)],
},
};
locationGeoJson.point.features.push(feature);
}
});
handlerLocationLoadLayer();
//console.log('locationGeoJson', locationGeoJson);
};
// 线
const handlerLocationLoadLayer = () => {
//console.log("locationGeoJson123",locationGeoJson);
//
if (map.getSource('LocationPointSource')) {
map.getSource('LocationPointSource').setData(locationGeoJson.point);
} else {
map.addSource('LocationPointSource', {
type: 'geojson',
data: locationGeoJson.point,
});
map.addLayer({
id: 'LocationPointLayer',
type: 'circle',
source: 'LocationPointSource',
paint: {
'circle-radius': 5,
'circle-color': '#408eff', //
},
});
}
// 线
if (map.getSource('LocationPolylineSource')) {
map.getSource('LocationPolylineSource').setData(locationGeoJson.polyline);
} else {
map.addSource('LocationPolylineSource', {
type: 'geojson',
data: locationGeoJson.polyline,
});
map.addLayer({
id: 'LocationLineLayer',
type: 'line',
source: 'LocationPolylineSource',
paint: {
'line-color': '#408eff', // 线
'line-width': 2, // 线
},
});
}
//
if (map.getSource('LocationPolygonSource')) {
map.getSource('LocationPolygonSource').setData(locationGeoJson.polygon);
} else {
map.addSource('LocationPolygonSource', {
type: 'geojson',
data: locationGeoJson.polygon,
});
map.addLayer({
id: 'LocationPolygonLayer',
type: 'fill',
source: 'LocationPolygonSource',
paint: {
'fill-color': '#408eff', //
'fill-opacity': 0.5, //
},
});
}
};
const handlerClearDate = (index) => {
locationArrays.value[index].lat = ''
locationArrays.value[index].lng = ''
}
</script>
<style type="less" scoped>
<style type="scss" scoped>
.map-container {
width: 100%;
height: 100%;
@ -1233,4 +1448,45 @@
::v-deep .mapboxgl-ctrl-logo {
display: none !important;
}
.to-location-button{
position: absolute;
right: -165px;
top: 0px;
width: 36px;
height: 36px;
background-color: #0a62c6;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.to-location-input {
padding: 16px;
padding-right: 4px;
width: 418px;
min-height: 60px;
background: #fff;
position: absolute;
top: 48px;
right: -547px;
z-index: 999999;
border-radius: 5px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
.location-operation {
width: 100%;
height: 40px;
border-bottom: 1px solid #f1f1f1;
margin-bottom: 12px;
}
.location-item-list-coantienr {
width: 100%;
max-height: 400px;
overflow-y: auto;
.location-item {
line-height: 20px;
margin-bottom: 6px;
}
}
}
</style>