/* eslint-disable no-restricted-syntax */ import { Space, Table, Button, Popconfirm, notification, Spin, Input, Radio, message } from 'antd'; import React, { useState, useEffect } from 'react'; import styles from '../SchemeConfig.less'; import { GetVectorService, deleteVectorService, getSolutionList, updatePublishedMetaData, GettMaplayer, deleteConfig, GetFileContent, getAllMetaData, AddStyleConfigJson } from '@/services/webConfig/api'; import { LayerSetting } from '@/services/gis/gis'; import AddModal from './AddModal'; import PreviewModal from './VectorPreviewModal'; import MeteDataModal from './MeteDataModal'; import AddSlicedModal from './AddSlicedModal'; import { mapConfig , VectorUtils} from '@wisdom-map/gis-utils' import {parseUrlQueryParams , queryParamsToUrl} from '@/utils/utils' const VectorData = props => { const [treeLoading, setTreeLoading] = useState(false); // 弹窗显示 const [tileData, setTileData] = useState([]); // table表格数据 const [tileSlicedData, setTileSlicedData] = useState([]); const [visible, setVisible] = useState(false); // 弹窗 const [previewVisible, setPreviewVisible] = useState(false); // 预览弹窗 const [meteDataVisible, setMeteDataVisible] = useState(false); // 预览弹窗 const [flag, setFlag] = useState(0); // 更新list const [loading, setLoading] = useState([]); // 更新状态 const [allLoading, setAllLoading] = useState(false); // 更新状态 const [type, setType] = useState(''); // 弹窗类型 const [solutionNames, setSolutionNames] = useState(''); const [formObj, setFormObj] = useState({ user: 'admin', password: 'panda_server@2023' }); const [record, setRecord] = useState(); const [currentMetaData, setCurrentMetaData] = useState(null); const [searchValue, setSearchValue] = useState(''); const [radioType, setRadioType] = useState('1'); const [addVisible, setAddVisible] = useState(false); // 弹窗 const [treeTileLoading, setTreeTileLoading] = useState(false); const [name, setName] = useState([]); const { Search } = Input; const columns = [ { title: '服务名', dataIndex: 'ServiceName', key: 'ServiceName', align: 'center', }, { title: 'IP', dataIndex: 'GISServerIP', key: 'GISServerIP', align: 'center', }, { title: '端口', dataIndex: 'GISServerPort', key: 'GISServerPort', align: 'center', }, { title: '工程名', dataIndex: 'GISServerProjectName', key: 'GISServerProjectName', align: 'center', }, { title: '发布时间', dataIndex: 'PublishTime', key: 'PublishTime', align: 'center', }, { title: '编辑', align: 'center', width: 260, render: (text, record, index) => ( <Space> <Button type="primary" size="small" onClick={() => metadata(record)}> 元数据 </Button> <Button type="primary" size="small" onClick={() => previewMetaData(record, index)}> 预览 </Button> <Button type="primary" size="small" loading={loading[index] || allLoading} onClick={() => enterLoading(record, index)} > 更新 </Button> <div onClick={e => e.stopPropagation()}> <Popconfirm title="是否删除该矢量数据?" okText="确认" cancelText="取消" onConfirm={() => { delConfirm(record); }} > <Button size="small" danger> 删除 </Button> </Popconfirm> </div> </Space> ), }, ]; const columnsPart = [ { title: '服务名', dataIndex: 'servicename', key: 'servicename', align: 'center', }, { title: '标签', dataIndex: 'label', key: 'label', align: 'center', }, { title: '类型', dataIndex: 'type', key: 'type', align: 'center', }, { title: '编辑', align: 'center', render: (text, record) => ( <Space> <Button type="primary" size="small" onClick={() => { changebaseMap(record); }} > 编辑 </Button> <div onClick={e => e.stopPropagation()}> <Popconfirm title="是否删除该切片管网?" okText="确认" cancelText="取消" onConfirm={() => { delConfirmSliced(record); }} > <Button size="small" danger> 删除 </Button> </Popconfirm> </div> </Space> ), }, ]; // 更新 const enterLoading = (record, index) => { const newLoadings = [...loading]; newLoadings[index] = true; setLoading(newLoadings); let query = { serviceName: record.ServiceName, _version: 9999, solution: solutionNames, }; updatePublishedMetaData(query) .then(res => { const newLoadings = [...loading]; newLoadings[index] = false; setLoading(newLoadings); if (res.success) { updateVectorConfig({ mapServerName : record['ServiceName'] }) setFlag(flag + 1); notification.success({ message: '提示', duration: 3, description: '更新元数据成功', }); } else { notification.error({ message: '提示', duration: 3, description: '更新元数据失败', }); } }) .catch(err => { const newLoadings = [...loading]; newLoadings[index] = false; setLoading(newLoadings); notification.error({ message: '提示', duration: 3, description: '服务无法访问', }); }); }; const updateVectorConfig = async ({ mapServerName }) => { try { const schemes = await updateCurrentMapschemes({mapServerName, exportScheme : mapConfig.exportScheme.arcgis}) if(schemes.length == 0) return const vectorData = await getVectorConfigData({ schemes, mapServerName }) if(!vectorData) return const metaData = await getMetaData({mapServerName}) if(!metaData) return let isChange = handleDataLayer({ schemes, vectorData, metaData }) const isFilterField = getDataIsFilterField({ schemes, vectorData }) if(isFilterField) { const isUpdateFile = updateVectorFileds({ metaData, schemes, vectorData }) if(isUpdateFile) { isChange = true } } if(isChange) { const result = await AddStyleConfigJson({ fileName : "StyleConfig", preventCache : Date.now() }, vectorData) } } catch (error) { console.log(error) } } const updateCurrentMapschemes = async ({mapServerName, exportScheme}) => { const data = await LayerSetting({client : "sandbox"}) if(data.code == "0") { return data.data.filter(item => item.id == mapServerName && ( exportScheme ? item.exportScheme == mapConfig.exportScheme.arcgis : true ) ) } return [] } const getVectorConfigData = async () => { const data = await GetFileContent({ path : "StyleConfig/StyleConfig.json", preventCache : Date.now() }) if(data.code == "0" && data.data.data && data.data.hasOwnProperty("version")) { return data.data } return null } const handleDataLayer = ({ schemes, vectorData, metaData }) => { let isChange = false schemes.map(scheme => { const data = vectorData.data[`${scheme.schemename}-${scheme.id}`] data.map(item => { const {params, url} = parseUrlQueryParams({ url : item.style.sources.osm.tiles[0] }) const layerNameArr = params.layerNames.split(",") const outfields = params.outfields.split(";") if(layerNameArr.length != outfields.length) return const newLayerNameArr = [], deleteIndexArr = [] for(let i = 0; i < item.style.layers.length ; i++) { const layer = item.style.layers[i] const hasLayer = metaData.find(item => item.name == layer['source-layer']) if(hasLayer) { !newLayerNameArr.includes(hasLayer.name) && newLayerNameArr.push(hasLayer.name) } else { } } if(newLayerNameArr.length == layerNameArr.length) return isChange = true const newOutfields = newLayerNameArr.map(name => { const index = layerNameArr.findIndex(a => a == name) if(index == -1) { const outFiled = getLayerFilterOutFields({ item, name, metaLayer : metaData.find(item => item.name == name) }) return outFiled } return outfields[index] }) item.style.sources.osm.tiles[0] = queryParamsToUrl({ url, params : { ...params, layerNames : newLayerNameArr.join(","), outfields : newOutfields.join(";") } }) }) }) return isChange } const getLayerFilterOutFields = ({item, name, metaLayer}) => { const layers = item.style.layers.filter(a => a['source-layer'] == name) const outFileds = new Set() layers.map(layer => { const parseField = VectorUtils.filterFieldsHandle({ layerItem : layer, outfields : null, layerFields : [] }) if((parseField && parseField.sqlObj && parseField.sqlObj.length > 0)) { parseField.sqlObj.filter(item => { return metaLayer.fields.find(field => field.name == item.label) }).map(item => outFileds.add(item.label)) } extractBraceContentsRegex(layer?.layout?.['text-field'])?.filter(fieldName => { return (metaLayer.fields.find(item => item.name == fieldName)) })?.map(item => { outFileds.add(item) }) }) return Array.from(outFileds).join(",") } const getDataIsFilterField = ({ schemes, vectorData }) => { for(let i = 0 ; i < schemes.length ; i++) { const scheme = schemes[i] const data = vectorData.data[`${scheme.schemename}-${scheme.id}`] if(Array.isArray(data)) { const hasFilter = data.find(({style}) => style.layers.find(layer => !!layer.filter)) if(hasFilter) { return true } } } return false } const getMetaData = async ({mapServerName}) => { const data = await getAllMetaData({mapServerName}) return Array.isArray(data) ? data : null } const updateVectorFileds = ({metaData , schemes, vectorData}) => { let isUpdateFile = false schemes.map(scheme => { const data = vectorData.data[`${scheme.schemename}-${scheme.id}`] if(!data) return data.map(({style}) => { const setFilterCollection = new Map() const setLayerCollection = new Set() const {params} = parseUrlQueryParams({ url : style.sources.osm.tiles[0] }) style.layers.map(layer => { let isHandle = true const metaLayer = metaData.find(item => item.name == layer['source-layer']) if(!metaLayer) { if( params.layerNames.indexOf(layer['source-layer']) > -1) { setLayerCollection.add(layer['source-layer']) return } else { isHandle = false } } isHandle && handleFilterField({ layer, setFilterCollection, metaLayer }) isHandle && handleLayoutTextField({ layer, setFilterCollection, metaLayer }) }) if(updateStyleLayer({ style, setLayerCollection })) { isUpdateFile = true } if(updateTileUrlAndField({ style, setFilterCollection })) { isUpdateFile = true } }) updateStyle(data) }) return isUpdateFile } const handleFilterField = ({ layer, setFilterCollection, metaLayer }) => { if(!layer.filter) return const parseField = VectorUtils.filterFieldsHandle({ layerItem : layer, outfields : null, layerFields : [] }) if(!(parseField && parseField.sqlObj && parseField.sqlObj.length > 0)) return const hasCondition = parseField.sqlObj.every(item => { return !item.label || metaLayer.fields.find(field => field.name == item.label) }) if(!hasCondition) { const layerName = layer['source-layer'] layer.filter = "" if(!setFilterCollection.has(layerName)) { setFilterCollection.set(layerName, new Set()) } const setCollection = setFilterCollection.get(layerName) parseField.sqlObj.map(item => setCollection.add(item.label)) } } const extractBraceContentsRegex = str => { const regex = /\{([^}]+)\}/g; const contents = []; let match; while ((match = regex.exec(str))!== null) { contents.push(match[1]); } return contents; } const handleLayoutTextField = ({ layer, setFilterCollection, metaLayer }) => { const data = extractBraceContentsRegex(layer?.layout?.['text-field'])?.filter(fieldName => { return !(metaLayer.fields.find(item => item.name == fieldName)) }) if(data && data.length > 0) { layer['layout']['text-field'] = "" const layerName = layer['source-layer'] if(!setFilterCollection.has(layerName)) { setFilterCollection.set(layerName, new Set()) } const setCollection = setFilterCollection.get(layerName) data.map(item => { setCollection.add(item) }) } } const updateTileUrlAndField = ({ style, setFilterCollection }) => { const tileUrl = style?.sources?.osm?.tiles[0] if(!tileUrl || setFilterCollection.size < 1) return false const {params , url} = parseUrlQueryParams({ url : tileUrl }) const layerNameArr = params.layerNames.split(",") const outfields = params.outfields.split(";") if(layerNameArr.length != outfields.length ) return layerNameArr.map((layerName, index) => { if(!outfields[index]) return const layerNameCollection = setFilterCollection.get(layerName) if(!layerNameCollection) return const outFieldsArr = outfields[index].split(",") Array.from(layerNameCollection).map(field => { const indexCollections = [] outFieldsArr.map((outFiled, index) => { if(outFiled == field) { indexCollections.push(index) } }) indexCollections.sort((a,b) => a - b > 0 ? -1 : 1) indexCollections.map(index => { outFieldsArr.splice(index, 1) }) }) outfields[index] = outFieldsArr.join(",") }) style.sources.osm.tiles[0] = queryParamsToUrl({ url, params : { ...params, outfields : outfields.join(";") } }) return true } const updateStyleLayer = ({ style, setLayerCollection }) => { if(setLayerCollection.size == 0) { return false } let indexCollections = [] style.layers.map((layer , index) => { const layerName = layer['source-layer'] if(setLayerCollection.has(layerName)) { indexCollections.push(index) } }) indexCollections.sort((a,b) => a - b > 0 ? -1 : 1) indexCollections.map(index => { style.layers.splice(index , 1) }) const tileUrl = style?.sources?.osm?.tiles[0] const {params , url} = parseUrlQueryParams({ url : tileUrl }) const layerNameArr = params.layerNames.split(",") const outfields = params.outfields.split(";") indexCollections = [] layerNameArr.map((layerName, index) => { if(setLayerCollection.has(layerName)) { indexCollections.push(index) } }) indexCollections.sort((a,b) => a - b > 0 ? -1 : 1) indexCollections.map(index => { layerNameArr.splice(index , 1) outfields.splice(index , 1) }) style.sources.osm.tiles[0] = queryParamsToUrl({ url, params : { ...params, outfields : outfields.join(";"), layerNames : layerNameArr.join(";"), } }) return true } const updateStyle = (data) => { const indexCollections = [] data.map((item , index) => { if(!(item.style && item.style.layers && item.style.layers.length > 0)) { indexCollections.push(index) } }) indexCollections.sort((a,b) => a - b > 0 ? -1 : 1) indexCollections.map(index => { data.splice(index, 1) }) } const previewMetaData = record => { setCurrentMetaData(record); setPreviewVisible(true); }; const metadata = record => { setCurrentMetaData(record); setMeteDataVisible(true); }; const solutionName = () => { getSolutionList({ _version: 9999, }).then(res => { setSolutionNames(res.data.currentSolution); }); }; const onSubmit = prop => { setVisible(false); setFlag(flag + 1); setAddVisible(false); }; const delConfirm = record => { console.log(' record.ServiceName', record.ServiceName.split('.')); let query = { serviceName: record.ServiceName.split('.')[0], _version: 9999, solution: solutionNames, }; deleteVectorService(query).then(res => { if (res.success) { setFlag(flag + 1); //deleteVectorData(record) notification.success({ message: '提示', duration: 3, description: '删除元数据成功', }); } else { notification.error({ message: '提示', duration: 3, description: '删除元数据失败', }); } }); }; const deleteVectorData = async (record) => { try { const mapServerName = record?.ServiceName?.split('.')?.[0] if(!mapServerName) return const schemes = await updateCurrentMapschemes({mapServerName}) if(schemes.length == 0) return const vectorData = await getVectorConfigData({ schemes, mapServerName }) if(!vectorData) return schemes.map(scheme => { delete vectorData.data[`${scheme.schemename}-${scheme.id}`] }) await AddStyleConfigJson({ fileName : "StyleConfig", preventCache : Date.now() }, vectorData) } catch { } } const delConfirmSliced = record => { const { servicename = '' } = record; setTreeLoading(true); deleteConfig({ servicename, terminalType: 'base', isBaseMap: true, }) .then(res => { setFlag(flag + 1); if (res.code == '0') { // form.resetFields(); // callBackSubmit(); notification.success({ message: '提示', duration: 3, description: res.message || '删除成功', }); } else { notification.error({ message: '提示', duration: 3, description: res.message || '删除失败', }); } }) .catch(err => { setFlag(flag + 1); setTreeLoading(false); }); }; const handleAdd = () => { setType('add'); if (radioType == 1) { setVisible(true); } else { setAddVisible(true); } }; useEffect(() => { renderTile({ info: searchValue }); renderTileSliced(); }, [flag]); // 获取瓦片数据配置数据 const renderTile = (params = { info: '' }) => { setTreeLoading(true); solutionName(); GetVectorService(params) .then(res => { setTreeLoading(false); if (res.msg === 'Ok') { let arr = []; res.data.VectorList.map(item => { arr.push(false); }); setLoading(arr); setTileData(res.data.VectorList); } else { notification.error({ message: '获取失败', description: res.message, }); } }) .catch(err => { if (err.message.indexOf('timeout') !== -1) { notification.error({ message: '提示', duration: 3, description: '请求超时', }); } else { notification.error({ message: '提示', duration: 3, description: err.message, }); } setTreeLoading(false); }); }; const renderTileSliced = () => { setTreeTileLoading(true); GettMaplayer({ terminalType: 'base', isBaseMap: true, }) .then(res => { setTreeTileLoading(false); if (res.code == '0') { let newdata = res.data.general.baseMap.layers?.filter(i => i.isVector === 1); setTileSlicedData(newdata); let data = []; newdata.map(item => { data.push(item.servicename); }); setName(data); } else { notification.error({ message: '获取失败', description: res.message, }); } }) .catch(err => { setTreeTileLoading(false); if (err.message.indexOf('timeout') !== -1) { notification.error({ message: '提示', duration: 3, description: '请求超时', }); } else { notification.error({ message: '提示', duration: 3, description: err.message, }); } }); }; // 搜索 const handleSearch = text => { setFlag(flag + 1); }; // 搜索框改变时存储输入的值 const handleChange = e => { setSearchValue(e.target.value); }; const updateAll = async () => { let query = { version: 9999, solution: solutionNames, }; for (const [index, item] of tileData.entries()) { setAllLoading(true); query.serviceName = item.ServiceName; let res = null; res = await updatePublishedMetaData(query); if (res.success) { setAllLoading(false); notification.success({ message: '提示', duration: 1, // description: `${item.ServiceName}更新辣`, description: `更新元数据成功`, }); } else { setAllLoading(false); notification.error({ message: '提示', duration: 3, description: '更新元数据失败', }); } if (index === tileData.length - 1) { setFlag(flag + 1); } } }; const handleSelect = e => { setRadioType(e.target.value); }; const changebaseMap = e => { setType('edit'); setRecord(e); setAddVisible(true); }; return ( <> <div className={styles.pipeNetwork}> <div className={styles.tileBtnVe}> <div className={styles.tileBtnLeft}> <span>管网类型:</span> <Radio.Group defaultValue="1" value={radioType} onChange={e => handleSelect(e)}> <Radio.Button value="1" style={{ width: '90px', textAlign: 'center' }}> 管网 </Radio.Button> <Radio.Button value="2" style={{ width: '90px', textAlign: 'center' }}> 切片管网 </Radio.Button> </Radio.Group> </div> <div className={styles.tileBtnRight}> {radioType == 1 && ( <> <span style={{ marginLeft: '20px', marginRight: '5px' }}>快速检索</span> <Search allowClear placeholder="请输入服务名或工程名" onSearch={handleSearch} onChange={handleChange} value={searchValue} enterButton style={{ width: '300px', marginRight: '20px' }} /> <Button type="primary" onClick={() => { updateAll(); }} loading={allLoading} style={{ marginRight: '20px' }} > 批量更新 </Button> </> )} <Button type="primary" onClick={() => { handleAdd(); }} > 新增 </Button> </div> </div> <div style={{ height: 'calc(100% - 51px)', width: '100%' }}> <Table loading={radioType == 1 ? treeLoading : treeTileLoading} columns={radioType == 1 ? columns : columnsPart} dataSource={radioType == 1 ? tileData : tileSlicedData} bordered rowKey="CreateTime" scroll={{ y: 'calc(100% - 70px)' }} pagination={{ showTotal: (total, range) => `第${range[0]}-${range[1]} 条/共 ${total} 条`, }} /> </div> <AddModal visible={visible} onCancel={() => setVisible(false)} callBackSubmit={onSubmit} type={type} formObj={formObj} solutionNames={solutionNames} /> <PreviewModal visible={previewVisible} onCancel={() => setPreviewVisible(false)} metaData={currentMetaData} /> <MeteDataModal visible={meteDataVisible} onCancel={() => setMeteDataVisible(false)} metaData={currentMetaData} /> <AddSlicedModal visible={addVisible} onCancel={() => setAddVisible(false)} callBackSubmit={onSubmit} type={type} formObj={record} name={name} /> </div> </> ); }; export default VectorData;