Compare commits

20 Commits
Author SHA1 Message Date
gcw_IJ7DAiVL 2e606513f5 add 道路分析接口获取数据 2025-11-18 16:01:57 +08:00
gcw_IJ7DAiVL 1c76c7d23c add title 2025-11-17 09:28:04 +08:00
gcw_IJ7DAiVL 802df4d446 add title从ini取 2025-11-03 17:00:28 +08:00
gcw_IJ7DAiVL 46c6b952fc fix bug 2025-10-27 10:48:12 +08:00
gcw_IJ7DAiVL a562e2cea8 add 样式 2025-10-27 09:46:51 +08:00
gcw_IJ7DAiVL af252cd65e fix 2025-10-24 09:02:28 +08:00
gcw_IJ7DAiVL 444bded88f add 字体 2025-10-23 10:23:50 +08:00
gcw_IJ7DAiVL 964ce7cede fix bug修复 2025-10-16 16:02:23 +08:00
gcw_IJ7DAiVL ce70fd98ec add json编辑功能 2025-10-15 09:27:20 +08:00
gcw_IJ7DAiVL 7d22506f18 add json 编辑 2025-10-14 17:23:54 +08:00
gcw_IJ7DAiVL 328700ec89 fix 2025-10-10 18:31:44 +08:00
gcw_IJ7DAiVL 2ad6bc1b47 add 导出 2025-10-10 15:32:47 +08:00
gcw_IJ7DAiVL 41f9034f54 ## 机动路线规划 2025-10-10 11:38:34 +08:00
gcw_IJ7DAiVL ae2f9d94e1 fix 路线规划 隐蔽 2025-10-10 11:35:42 +08:00
gcw_IJ7DAiVL c1876d23bd add 隐蔽规划 2025-09-24 11:15:23 +08:00
yiqiuyang e2b73640df Merge branch 'main' of https://work.rangutech.cn:85/yiqiuyang/kxfx 2025-09-10 09:44:48 +08:00
yiqiuyang f084fc92e9 代码提交 2025-09-10 09:44:44 +08:00
gcw_IJ7DAiVL 3e7ccea682 fix 2025-09-10 09:34:52 +08:00
gcw_IJ7DAiVL 935846d7f2 fix 2025-09-10 09:13:58 +08:00
gcw_IJ7DAiVL cc774db444 fix 2025-09-10 08:55:33 +08:00
20 changed files with 7355 additions and 165 deletions
+1 -27
View File
@@ -1,29 +1,3 @@
# kxfx
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
## 机动路线规划
+8 -3
View File
@@ -9,12 +9,15 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "0.21.0",
"core-js": "^3.8.3",
"@babel/preset-env": "^7.28.3",
"axios": "^1.13.2",
"echarts": "^5.4.3",
"element-ui": "2.9.2",
"file-saver": "^2.0.5",
"gsap": "^3.13.0",
"ini-parser": "^0.0.2",
"js-cookie": "2.2.1",
"raw-loader": "^4.0.2",
"vue": "^2.6.14",
"vue-router": "^3.5.1",
"vuex": "^3.6.2",
@@ -22,13 +25,15 @@
"vxe-table": "~3.18.9"
},
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/core": "^7.28.4",
"@babel/eslint-parser": "^7.12.16",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-plugin-vuex": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"babel-loader": "^10.0.0",
"core-js": "^3.46.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
+6
View File
@@ -0,0 +1,6 @@
[http]
port=8381
address=192.168.3.35
[title]
msg=道路堪选分析
+4
View File
@@ -0,0 +1,4 @@
window.config = {
// baseUrl: 'http://192.168.3.35:8381',
baseUrl: '/api'
}
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -59,7 +59,7 @@
"id": "image-tdss",
"name": "影像图",
"type": "xyz",
"url": "http:/www.tdss.website:280/tiles/img_c/{z}/{x}/{y}",
"url": "http://www.tdss.website:280/tiles/img_c/{z}/{x}/{y}",
"crs": "EPSG:4490",
"show": true
}
+16 -8
View File
@@ -1,26 +1,34 @@
[
{
"id": 1,
"width": 30,
"load": 500,
"name": "车1",
"long": 10,
"width": 7,
"load": 3,
"minTurnRadius": 5
},
{
"id": 2,
"width": 10,
"load": 600,
"name": "车2",
"long": 10,
"width": 11,
"load": 1,
"minTurnRadius": 6
},
{
"id": 3,
"width": 40,
"load": 700,
"name": "车3",
"long": 10,
"width": 8,
"load": 7,
"minTurnRadius": 10
},
{
"id": 4,
"width": 20,
"load": 700,
"name": "车4",
"long": 10,
"width": 10,
"load": 5,
"minTurnRadius": 2
}
]
+5 -21
View File
@@ -1,38 +1,22 @@
{
"startPoint": "114.262694,27.786216",
"endPoint": "114.274729,27.777062",
"startPoint": "114.312888,27.796612",
"endPoint": "114.336525,27.767989",
"viaPoints": [
{
"time": "1694352000000",
"points": "114.263233,27.777047"
},
{
"time": "1694352001000",
"points": "114.265512,27.789935"
},
{
"time": "1694352002000",
"points": "114.256863,27.780437"
"points": "114.334239,27.779261"
}
],
"avoidPoints": [
{
"time": "1694352003000",
"points": "114.261166,27.800982"
},
{
"time": "1694352004000",
"points": "114.251312,27.786932"
"points": ""
}
],
"avoidAreas": [
{
"time": "1694352005000",
"points": "[[114.267217,27.777566,0],[114.276695,27.78048,0],[114.276001,27.772547,0],[114.276001,27.772486,0]]"
},
{
"time": "1694352006000",
"points": "[[114.272317,27.786501,0],[114.281341,27.79818,0],[114.290389,27.779594,0],[114.284888,27.773934,0]]"
"points": "[[114.272797,27.7935,0],[114.27268,27.794201,0],[114.27537,27.795838,0]]"
}
]
}
+1
View File
@@ -11,6 +11,7 @@
rel="stylesheet"
type="text/css"
/>
<script src="./config/config.js" type="text/javascript"></script>
<script src="./map/Cesium/Cesium.js" type="text/javascript"></script>
<link href="./map/mars3d/mars3d.css" rel="stylesheet" type="text/css" />
<script src="./map/mars3d/mars3d.js" type="text/javascript"></script>
Binary file not shown.
+65 -2
View File
@@ -1,11 +1,57 @@
@font-face {
font-family: 'Dengxian';
src: url('@/assets/scss/Dengxian.ttf') format('truetype');
font-weight: 400;
font-style: normal;
font-display: swap;
}
/* 全局强制继承 */
html, body, #app, .cesium-widget, .mars3d-container,
.mars3d-popup, .mars3d-tooltip, .mars3d-contextmenu,
.mars3d-measure-result, .cesium-credit-text,
.el-button, .el-input, .el-select, .el-table, .el-form, .el-dialog,
.el-message, .el-notification, .el-tooltip,
.el-menu, .el-breadcrumb, .el-pagination,
.el-radio, .el-checkbox, .el-tag, .el-badge,
.el-alert, .el-steps, .el-tabs, .el-calendar,
.el-date-picker, .el-cascader, .el-transfer,
.el-slider, .el-upload,
.el-empty, .el-result,
.el-loading-text,.el-table,
.el-table__body-wrapper span,
.el-table__footer-wrapper span,
.el-table__header-wrapper span,
.el-table__fixed span,
.el-table__fixed-right span,
.vxe-table--render-default .vxe-cell--title,
.vxe-table--render-default .vxe-cell--label,
.vxe-toolbar *,
.vxe-pager *,
.vxe-modal--wrapper *,
.vxe-tooltip--wrapper * {
font-family: 'DengXian', sans-serif !important;
}
/* 覆盖 mars3d 所有内部 UI */
.mars3d-draw-tooltip,
.mars3d-measure-tooltip,
.mars3d-contextmenu *,
.mars3d-popup *,
.mars3d-measure-result *,
.mars3d-control-btn {
font-family: 'DengXian', sans-serif !important;
}
.Dengxian {
font-family: 'Dengxian' !important;
}
body,
html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB,
Microsoft YaHei, Arial, sans-serif;
font-family: 'Dengxian' !important;
user-select: none;
scrollbar-width: none;
-ms-overflow-style: none;
@@ -33,3 +79,20 @@ html {
.flex-warp {
flex-wrap: wrap;
}
.el-form-item {
display: flex!important;
justify-content: space-between;
margin-bottom: 12px!important;
}
.el-form-item__label {
letter-spacing: -1px;
min-width: 130px!important;
padding: 0!important;
white-space: nowrap; /* 强制不换行 */
flex-shrink: 0;
font-size: 16px!important;
}
.el-input__inner {
height: 24px;
line-height: 24px;
}
+3
View File
@@ -10,6 +10,9 @@ import 'vxe-pc-ui/es/style.css'
import VxeUITable from 'vxe-table'
import 'vxe-table/es/style.css'
import axios from 'axios'
Vue.prototype.$http = axios
Vue.config.productionTip = false
+1 -1
View File
@@ -1,6 +1,6 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/home.vue'
import HomeView from '../views/home/home.vue'
import residentAnalysis from '@/views/residentAnalysis/index.vue'
Vue.use(VueRouter)
+162
View File
@@ -0,0 +1,162 @@
/**
* 极简 WKT -> GeoJSON
* 支持 POINT / LINESTRING / POLYGON
* @param {String} wkt
* @return {Object} GeoJSON
*/
function wktToGeoJSON (wkt) {
const trim = str => str.trim()
const split = (str, d) => str.split(d).map(trim)
// 1. 提取类型 + 坐标字符串
const [head, coords] = split(wkt, '(')
const type = trim(head).toUpperCase()
const coordStr = coords.replace(/\)$/, '')
// 2. 通用“数字对”解析
const parseRing = ring =>
split(ring, ',').map(p => {
const [x, y] = split(p, ' ').map(Number)
return [x, y] // GeoJSON 里经度在前
})
// 3. 按类型组装
switch (type) {
case 'POINT': {
const [x, y] = split(coordStr, ' ').map(Number)
return { type: 'Point', coordinates: [x, y] }
}
case 'LINESTRING':
return { type: 'LineString', coordinates: parseRing(coordStr) }
case 'POLYGON': {
// 可能带孔,先按“), (”切
const rings = coordStr.split(/\s*\),\s*\(/).map(parseRing)
return { type: 'Polygon', coordinates: rings }
}
default:
throw new Error('暂不支持该 WKT 类型:' + type)
}
}
/* 拿当前视野四至(容错版) */
function getBounds(map) {
let rect = map.camera.computeViewRectangle()
if (!rect) {
// 高空/2D 模式下 computeViewRectangle 会失效,用四个角点兜底
const canvas = map.scene.canvas
const ellipsoid = Cesium.Ellipsoid.WGS84
const cv = (x, y) => map.camera.pickEllipsoid(
new Cesium.Cartesian2(x, y), ellipsoid
)
const ptNW = cv(0, 0)
const ptSE = cv(canvas.clientWidth, canvas.clientHeight)
// 如果仍 pick 不到,就缩小范围再试(再不行就返回一个默认矩形)
if (!ptNW || !ptSE) {
rect = map.camera.computeViewRectangle(
ellipsoid,
Cesium.Math.toRadians(0.1) // 0.1° 容差
)
if (!rect) {
// 终极保底:以相机位置为中心 ±0.1°
const c = map.camera.positionCartographic
const d = 0.1
return {
west : Cesium.Math.toDegrees(c.longitude) - d,
east : Cesium.Math.toDegrees(c.longitude) + d,
south: Cesium.Math.toDegrees(c.latitude) - d,
north: Cesium.Math.toDegrees(c.latitude) + d
}
}
} else {
// pick 成功
const nw = Cesium.Cartographic.fromCartesian(ptNW)
const se = Cesium.Cartographic.fromCartesian(ptSE)
return {
west : Cesium.Math.toDegrees(nw.longitude),
north: Cesium.Math.toDegrees(nw.latitude),
east : Cesium.Math.toDegrees(se.longitude),
south: Cesium.Math.toDegrees(se.latitude)
}
}
}
// 正常能算到
return {
west : Cesium.Math.toDegrees(rect.west),
south: Cesium.Math.toDegrees(rect.south),
east : Cesium.Math.toDegrees(rect.east),
north: Cesium.Math.toDegrees(rect.north)
}
}
/* 计算当前地图层级(zoom) */
function getZoom(map) {
const height = map.camera.positionCartographic.height
// 经验公式:Cesium 高度 -> WebMercator zoom
return Math.floor(29.5 - Math.log(height) / Math.LN2)
}
/* 画布像素边界 */
function getViewportPxBounds(map) {
const cvs = map.scene.canvas
return { left: 0, top: 0, right: cvs.clientWidth, bottom: cvs.clientHeight }
}
/* 像素 -> 经纬度四至 */
function pxToLatLngBounds(px, map) {
const pick = (x, y) => {
const cart = map.camera.pickEllipsoid(
new Cesium.Cartesian2(x, y),
Cesium.Ellipsoid.WGS84
)
if (!cart) return null
const c = Cesium.Cartographic.fromCartesian(cart)
return { lng: Cesium.Math.toDegrees(c.longitude), lat: Cesium.Math.toDegrees(c.latitude) }
}
const nw = pick(px.left, px.top)
const se = pick(px.right, px.bottom)
// 兜底:高空 pick 不到就用相机矩形
if (!nw || !se) {
const rect = map.camera.computeViewRectangle() || {}
return {
west : Cesium.Math.toDegrees(rect.west || 0),
south: Cesium.Math.toDegrees(rect.south || 0),
east : Cesium.Math.toDegrees(rect.east || 0),
north: Cesium.Math.toDegrees(rect.north || 0)
}
}
return { west: nw.lng, north: nw.lat, east: se.lng, south: se.lat }
}
var GRID_SIZE_DEG = 0.05 // 0.05° ≈ 5 km 一格
var CACHE_MIN = 30 * 60 * 1000 // 30 min
/* 经纬度 → 格子 key */
function lonLatToGridKey (lon, lat) {
const x = Math.floor(lon / GRID_SIZE_DEG)
const y = Math.floor(lat / GRID_SIZE_DEG)
return `${x}_${y}`
}
/* 取格子中心点(方便防抖) */
function gridKeyToCenter (key) {
const [x, y] = key.split('_').map(Number)
return {
lon: (x + 0.5) * GRID_SIZE_DEG,
lat: (y + 0.5) * GRID_SIZE_DEG
}
}
export {
wktToGeoJSON,
getBounds,
getZoom,
getViewportPxBounds,
pxToLatLngBounds,
lonLatToGridKey,
gridKeyToCenter,
}
+18 -3
View File
@@ -16,18 +16,22 @@
<script>
import {setStorage, getStorage} from '@/utils/localStorage.js'
import iniParser from 'ini-parser'
export default {
name: '',
data() {
return {
tabList: [
{id: 1, label: '机动路线规划'},
{id: 2, label: '临时部署驻地分析'},
{id: 1, label: '道路通过性分析'},
// {id: 2, label: '临时部署驻地分析'},
],
activeIndex: 1,
}
},
created() {
this.getTitle()
},
mounted() {
this.activeIndex = getStorage('activeIndex') || 1
},
@@ -36,6 +40,17 @@ export default {
setStorage('activeIndex', 1)
},
methods: {
getTitle() {
fetch('./config.ini')
.then(response => response.text())
.then(text => {
const parsedData = iniParser.parse(text);
this.tabList[0].label = parsedData.title.msg || '道路通过性分析'
})
.catch(() => {
this.tabList[0].label = '道路通过性分析'
})
},
setActiveIndex(id) {
if (this.activeIndex !== id) {
this.activeIndex = id
@@ -64,7 +79,7 @@ $label_height: 50px;
line-height: $label_height;
padding: 0 30px;
margin-right: 20px;
font-family: 'HarmonyOS Sans';
// font-family: 'HarmonyOS Sans';
font-weight: 400;
font-size: 20px;
cursor: pointer;
+651 -63
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+55 -21
View File
@@ -74,19 +74,28 @@
</div>
<div class="center" id="cesiumContainer"></div>
<div class="right flex column j-s">
<div
class="right flex column"
v-loading="showLoading"
element-loading-text="数据加载中"
>
<!-- 路点 -->
<div class="table-title" v-if="roadPointList.length > 0">
道路附属点
</div>
<vxe-table
class="item"
:data="roadPointList"
v-if="roadPointList.length > 0"
>
<vxe-column type="seq" width="70"></vxe-column>
<vxe-column field="name" title="Name"></vxe-column>
<vxe-column field="sex" title="Sex"></vxe-column>
<vxe-column field="age" title="Age"></vxe-column>
<vxe-column field="编码" title="编码"></vxe-column>
<vxe-column field="名称" title="名称"></vxe-column>
<vxe-column field="A" title="A"></vxe-column>
</vxe-table>
<!-- 路线 -->
<div class="table-title" v-if="roadLineList.length > 0">道路附属线</div>
<vxe-table
class="item"
:data="roadLineList"
@@ -94,30 +103,38 @@
>
<vxe-column type="seq" width="70"></vxe-column>
<vxe-column field="编码" title="编码"></vxe-column>
<vxe-column field="A" title="名称"></vxe-column>
<vxe-column field="图形特" title="图形特"></vxe-column>
<vxe-column field="名称" title="名称"></vxe-column>
<vxe-column field="A" title="A"></vxe-column>
</vxe-table>
<!-- 水点 -->
<div class="table-title" v-if="waterPointList.length > 0">
水系附属点
</div>
<vxe-table
class="item"
:data="waterPointList"
v-if="waterPointList.length > 0"
>
<vxe-column type="seq" width="70"></vxe-column>
<vxe-column field="name" title="Name"></vxe-column>
<vxe-column field="sex" title="Sex"></vxe-column>
<vxe-column field="age" title="Age"></vxe-column>
<vxe-column field="编码" title="编码"></vxe-column>
<vxe-column field="名称" title="名称"></vxe-column>
<vxe-column field="A" title="A"></vxe-column>
</vxe-table>
<!-- 水线 -->
<div class="table-title" v-if="waterLineList.length > 0">
水系附属线
</div>
<vxe-table
class="item"
:data="waterLineList"
v-if="waterLineList.length > 0"
>
<vxe-column type="seq" width="70"></vxe-column>
<vxe-column field="name" title="Name"></vxe-column>
<vxe-column field="sex" title="Sex"></vxe-column>
<vxe-column field="age" title="Age"></vxe-column>
<vxe-column field="编码" title="编码"></vxe-column>
<vxe-column field="名称" title="名称"></vxe-column>
<vxe-column field="A" title="A"></vxe-column>
</vxe-table>
</div>
</div>
@@ -133,6 +150,7 @@ export default {
name: '',
data() {
return {
showLoading: false,
imagesList: [{id: 1, src: require('@/assets/image/crop.png')}],
roadPointList: [],
roadLineList: [],
@@ -682,6 +700,8 @@ export default {
// 清除之前的矩形
this.clearRectangles()
console.log('this.rectangles===>', this.rectangles)
// 获取分割参数
const xSplit = parseInt(this.form.xLength) || 3
const ySplit = parseInt(this.form.yLength) || 3
@@ -813,6 +833,7 @@ export default {
console.error('坡度分析失败', e)
this.$message.error('坡度分析失败,请检查地形数据')
} finally {
rectInfoMap.clear()
this.drawLabelAndRec()
}
},
@@ -1014,7 +1035,11 @@ export default {
// 选择矩形
selectRectangle(rect) {
console.log('rect===>', rect)
this.showLoading = true
setTimeout(() => {
this.showLoading = false
}, 500)
if (this.selectedRect?.id === rect.id) return
this.selectedRect = {
id: rect.id,
@@ -1092,17 +1117,17 @@ export default {
// 清除所有矩形
clearRectangles() {
if (this.rectangles.length > 0) {
this.rectangles.forEach((rect) => {
window.graphicLayer.removeGraphic(rect)
})
this.rectangles.forEach((item) => item.remove())
window.graphicLayer.removeGraphic(this.rectangles)
this.rectangles = []
this.rectCount = 0
this.validBlocks = []
}
if (this.labels.length > 0) {
this.labels.forEach((label) => {
window.graphicLayer.removeGraphic(label)
})
this.labels.forEach((item) => item.remove())
window.graphicLayer.removeGraphic(this.labels)
this.labels = []
}
this.rectangles = []
this.labels = []
},
},
}
@@ -1192,11 +1217,20 @@ export default {
height: 100%;
background-color: #d4e5db;
padding-left: 20px;
padding-right: 10px;
overflow: auto;
.item {
margin-bottom: 10px;
}
.table-title {
font-size: 16px;
font-family: 'Pingfang';
font-weight: bold;
letter-spacing: 0.1em;
margin-bottom: 10px;
}
}
}
</style>
+47 -15
View File
@@ -1,30 +1,62 @@
const {defineConfig} = require('@vue/cli-service')
const postcssPxToViewport = require('postcss-px-to-viewport')
const path = require('path') // 需要引入 path 模块
const path = require('path')
module.exports = defineConfig({
publicPath: './',
transpileDependencies: false,
transpileDependencies: false, // 我们自己管,不让 CLI 插手
lintOnSave: false,
devServer: {client: {overlay: false}},
configureWebpack(config) {
// 调试
config.devtool = 'source-map'
// 别名
config.resolve.alias['@'] = path.resolve(__dirname, 'src')
/* 1. 追加 ini 规则 */
config.module.rules.push({
test: /\.ini$/,
use: 'raw-loader',
})
/* 2. 追加 ES5 规则(只转 src,不转 node_modules */
// config.module.rules.push({
// test: /\.js$/,
// include: path.resolve(__dirname, 'src'),
// use: {
// loader: 'babel-loader',
// options: {
// presets: [
// [
// '@babel/preset-env',
// {
// targets: {ie: '11'}, // 强制 ES5
// corejs: 3,
// useBuiltIns: 'entry',
// },
// ],
// ],
// },
// },
// })
},
devServer: {
client: {
overlay: false,
client: { overlay: false },
proxy: {
'/api': {
target: 'http://192.168.3.35:8381',
changeOrigin: true,
pathRewrite: { '^/api': '' },
},
},
},
configureWebpack: (config) => {
//调试JS
config.devtool = 'source-map'
config.resolve = {
alias: {
'@': path.resolve(__dirname, 'src'),
},
}
},
css: {
/* 你的 px-to-viewport 配置不动 */
loaderOptions: {
postcss: {
postcssOptions: {
// 增加这一层 postcssOptions
plugins: [
postcssPxToViewport({
unitToConvert: 'px',
@@ -37,7 +69,7 @@ module.exports = defineConfig({
minPixelValue: 1,
mediaQuery: false,
replace: true,
exclude: /(\/|\\)(node_modules)(\/|\\)/,
exclude: /node_modules/,
include: [],
landscape: false,
}),