diff --git a/package.json b/package.json index 7272612..497e69a 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,8 @@ "dependencies": { "@ant-design-vue/pro-layout": "^1.0.11", "@antv/data-set": "^0.10.2", + "@wangeditor/editor": "^5.1.23", + "@wangeditor/editor-for-vue": "^1.0.2", "ant-design-vue": "^1.7.8", "axios": "^0.26.1", "cesium": "1.101.0", diff --git a/src/App.vue b/src/App.vue index 4412a74..05e1652 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,7 +1,7 @@ @@ -11,53 +11,115 @@ import { domTitle, setDocumentTitle } from '@/utils/domUtil' import { i18nRender } from '@/locales' export default { - data () { - return { - } + data() { + return {} }, computed: { - locale () { + locale() { // 只是为了切换语言时,更新标题 const { title } = this.$route.meta - title && (setDocumentTitle(`${i18nRender(title)} - ${domTitle}`)) + title && setDocumentTitle(`${i18nRender(title)} - ${domTitle}`) return this.$i18n.getLocaleMessage(this.$store.getters.lang).antLocale - } - } + }, + }, } \ No newline at end of file +.ant-table td { + white-space: nowrap !important; +} +.ant-table th { + white-space: nowrap !important; +} +.ant-table-thead > tr > th, +.ant-table-tbody > tr > td { + padding: 8px 8px !important; + overflow-wrap: break-word; + font-size: 14px; +} +.flexRowStart { + display: flex; + flex-direction: row; + align-items: flex-start; +} +.flexRowCenter { + display: flex; + flex-direction: row; + align-items: center; +} +.flexCenterCenter { + display: flex; + justify-content: center; + align-items: center; +} +.flexColumnCenterCenter { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} +.shaixuan_float_left { + float: left; + margin-right: 20px; +} + +.flex { + display: flex; +} +.flex-rr { + display: flex; + flex-direction: row-reverse; +} +.flex-c { + display: flex; + flex-direction: column; +} +.flex-1 { + flex: 1; +} +.flex-cr { + display: flex; + flex-direction: column-reverse; +} +.ai-fs { + align-items: flex-start; +} +.ai-s { + align-items: stretch; +} +.ai-fe { + align-items: flex-end; +} +.ai-c { + align-items: center; +} +.ai-s { + align-items: stretch; +} +.jc-c { + justify-content: center; +} +.jc-sb { + justify-content: space-between; +} +.jc-sa { + justify-content: space-around; +} +.jc-fs { + justify-content: flex-start; +} +.jc-fe { + justify-content: flex-end; +} +.fr-w { + flex-wrap: wrap; +} +.fr-n { + flex-wrap: nowrap; +} +.fr-wr { + flex-wrap: wrap-reverse; +} + diff --git a/src/components/Common/Cesium/index.js b/src/components/Common/Cesium/index.js index 1fb54db..f0a5277 100644 --- a/src/components/Common/Cesium/index.js +++ b/src/components/Common/Cesium/index.js @@ -32,7 +32,7 @@ export default class MyCesium { // 未完成的在地图上移动类的操作 operations = [] - constructor(dom) { + constructor(dom, options = {}) { const imageryProvider = new Cesium.UrlTemplateImageryProvider({ url: window._CONFIG.ImageryProviderUrl || MyCesium.ImageryProviderUrl, tilingScheme: new Cesium.WebMercatorTilingScheme(), @@ -65,11 +65,13 @@ export default class MyCesium { }) this.viewer = viewer + const { center = MyCesium.center } = options + // viewer.scene.globe.depthTestAgainstTerrain = true viewer.imageryLayers.addImageryProvider(roadProvider) viewer.camera.setView({ - destination: Cesium.Cartesian3.fromDegrees(...MyCesium.center), + destination: Cesium.Cartesian3.fromDegrees(...center), }) // 不显示Cesium的Logo @@ -93,7 +95,7 @@ export default class MyCesium { // 创建指北针小部件并将其添加到地图 new CesiumNavigation(viewer, { // 用于在使用重置导航重置地图视图时设置默认视图控制。接受的值是Cesium.Cartographic 和Cesium.Rectangle. - defaultResetView: Cesium.Cartographic.fromDegrees(...MyCesium.center), + defaultResetView: Cesium.Cartographic.fromDegrees(...center), // 用于启用或禁用罗盘。true是启用罗盘,false是禁用罗盘。默认值为true。如果将选项设置为false,则罗盘将不会添加到地图中。 enableCompass: true, // 用于启用或禁用缩放控件。true是启用,false是禁用。默认值为true。如果将选项设置为false,则缩放控件 将不会添加到地图中。 @@ -275,4 +277,26 @@ export default class MyCesium { }, }) } + + setViewerByAllCorner(leftUp, rightUp, rightDown, leftDown) { + const [leftUpLon, leftUpLat] = leftUp + const [rightUpLon, rightUpLat] = rightUp + const [rightDownLon, rightDownLat] = rightDown + const [leftDownLon, leftDownLat] = leftDown + // 计算矩形区域的边界 + const west = Math.min(leftDownLon, leftUpLon, rightDownLon, rightUpLon) + const east = Math.max(leftDownLon, leftUpLon, rightDownLon, rightUpLon) + const south = Math.min(leftDownLat, leftUpLat, rightDownLat, rightUpLat) + const north = Math.max(leftDownLat, leftUpLat, rightDownLat, rightUpLat) + // 创建矩形范围 + const rectangle = Cesium.Rectangle.fromDegrees(west, south, east, north) + this.viewer.camera.setView({ + destination: rectangle, + orientation: { + heading: 0.0, + pitch: -Cesium.Math.PI_OVER_TWO, + roll: 0.0, + }, + }) + } } diff --git a/src/components/Common/Directives/Flex.js b/src/components/Common/Directives/Flex.js deleted file mode 100644 index ad3cafd..0000000 --- a/src/components/Common/Directives/Flex.js +++ /dev/null @@ -1,43 +0,0 @@ -const keyMaps = { - c: 'center', - fs: 'flex-start', - fe: 'flex-end', - sb: 'space-between', - sa: 'space-around', - n: 'nowrap', - w: 'wrap', - wr: 'wrap-reverse', -} - -export default { - bind(el, binding, vnode, oldVnode) { - // console.log('----bind----', el, binding, vnode, oldVnode) - el.style.display = 'flex' - if (binding.modifiers.v === true) { - el.style.flexDirection = 'column' - } - if (binding.value && binding.value instanceof Array) { - const [ai, jc, fw] = binding.value - if (ai) el.style.alignItems = keyMaps[ai] || ai - if (jc) el.style.justifyContent = keyMaps[jc] || jc - if (fw) el.style.flexWrap = keyMaps[fw] || fw - } - }, - inserted(el, binding, vnode, oldVnode) { - // console.log('----inserted----', el, binding, vnode, oldVnode) - }, - update(el, binding, vnode, oldVnode) { - // console.log('----update----', el, binding, vnode, oldVnode) - if (binding.value && binding.value instanceof Array) { - const [ai, jc] = binding.value - if (ai) el.style.alignItems = keyMaps[ai] || ai - if (jc) el.style.justifyContent = keyMaps[jc] || jc - } - }, - componentUpdated(el, binding, vnode, oldVnode) { - // console.log('----componentUpdated----', el, binding, vnode, oldVnode) - }, - unbind(el, binding, vnode, oldVnode) { - // console.log('----unbind----', el, binding, vnode, oldVnode) - }, -} diff --git a/src/components/Common/Directives/Loading.js b/src/components/Common/Directives/Loading.js index 5e360aa..05fd094 100644 --- a/src/components/Common/Directives/Loading.js +++ b/src/components/Common/Directives/Loading.js @@ -9,6 +9,7 @@ function initLoadingDom(el) { el.loadingDom.style.justifyContent = 'center' } function appendLoadingDom(el) { + if (document.body.contains(el.loadingDom)) return const { top, left, width, height } = el.getBoundingClientRect() el.loadingDom.style.top = `${top}px` el.loadingDom.style.left = `${left}px` @@ -18,7 +19,9 @@ function appendLoadingDom(el) { el.loadingDom.innerHTML = `` } function removeLoadingDom(el) { - document.body.removeChild(el.loadingDom) + if (document.body.contains(el.loadingDom)) { + document.body.removeChild(el.loadingDom) + } } export default { @@ -45,5 +48,6 @@ export default { }, unbind(el, binding, vnode, oldVnode) { // console.log('----unbind----', el, binding, vnode, oldVnode) + removeLoadingDom(el) }, } diff --git a/src/components/Common/Form/DurationPicker.vue b/src/components/Common/Form/DurationPicker.vue new file mode 100644 index 0000000..df56fc5 --- /dev/null +++ b/src/components/Common/Form/DurationPicker.vue @@ -0,0 +1,137 @@ + + + + + diff --git a/src/components/Common/WangEditor/Index.vue b/src/components/Common/WangEditor/Index.vue new file mode 100644 index 0000000..231b547 --- /dev/null +++ b/src/components/Common/WangEditor/Index.vue @@ -0,0 +1,152 @@ + + + + + diff --git a/src/components/Common/WangEditor/Readme.md b/src/components/Common/WangEditor/Readme.md new file mode 100644 index 0000000..3e33c12 --- /dev/null +++ b/src/components/Common/WangEditor/Readme.md @@ -0,0 +1,81 @@ +#### WangEditor + +基于wangeditor5二次封装的公用组件,添加上传音频的功能 + +#### 官方文档 +https://www.wangeditor.com/ + +#### 组件属性 + +1. value / v-model 内容 + +2. toolbarKeysEnable 可用工具栏,仅限初始化 +``` +布尔值 / 操作按钮key组成的数组 +false / true / [] +``` + +3. audio 是否启用上传音频的功能 +``` +false / true +``` + +#### 工具栏keys配置 + +1. 新增功能按钮 +``` +上传音频 uploadAudio +``` + +2. wangeditor5工具栏默认keys配置 +``` +[ + 'headerSelect', + 'blockquote', + '|', + 'bold', + 'underline', + 'italic', + { + key: 'group-more-style', + menuKeys: ['through', 'code', 'sup', 'sub', 'clearStyle'], + }, + 'color', + 'bgColor', + '|', + 'fontSize', + 'fontFamily', + 'lineHeight', + '|', + 'bulletedList', + 'numberedList', + 'todo', + { + key: 'group-justify', + menuKeys: ['justifyLeft', 'justifyRight', 'justifyCenter', 'justifyJustify'], + }, + { + key: 'group-indent', + menuKeys: ['indent', 'delIndent'], + }, + '|', + 'emotion', + 'insertLink', + { + key: 'group-image', + menuKeys: ['insertImage', 'uploadImage'], + }, + { + key: 'group-video', + menuKeys: ['insertVideo', 'uploadVideo'], + }, + 'insertTable', + 'codeBlock', + 'divider', + '|', + 'undo', + 'redo', + '|', + 'fullScreen', +] +``` diff --git a/src/components/Common/WangEditor/audioMenuRegister.js b/src/components/Common/WangEditor/audioMenuRegister.js new file mode 100644 index 0000000..7bbc09e --- /dev/null +++ b/src/components/Common/WangEditor/audioMenuRegister.js @@ -0,0 +1,65 @@ +import { Boot } from '@wangeditor/editor' + +class AudioMenu { + title = '' + iconSvg = '' + tag = '' + constructor () { + this.title = '上传音频' + this.iconSvg = + '' + this.tag = 'button' + } + getValue (editor) { + return '' + } + isActive (editor) { + return false + } + isDisabled () { + return false + } + exec (editor, value) { + if (this.isDisabled(editor)) return + const input = document.createElement('input') + input.type = 'file' + input.accept = 'audio/*' + input.style.cssText = `display: none;` + document.body.appendChild(input) + input.click() + input.addEventListener('change', (event) => { + editor.emit('selectFile', event.target.files) + }) + const wf = () => { + setTimeout(() => { + document.body.removeChild(input) + window.removeEventListener('focus', wf) + }, 100) + } + window.addEventListener('focus', wf) + } +} + +const MenusList = [{ key: 'uploadAudio', index: 24, Class: AudioMenu }] +const AudioMenuRegister = function (editor, toolbarConfig, callback = () => {}) { + const allRegisterMenu = editor.getAllMenuKeys() + const keys = [] + for (const item of MenusList) { + if (allRegisterMenu.indexOf(item.key) < 0) { + Boot.registerMenu({ + key: item.key, + factory () { + return new item.Class() + }, + }) + } + keys.push(item.key) + } + toolbarConfig.insertKeys = { + index: MenusList[0].index, + keys: keys, + } + editor.on('selectFile', callback) +} + +export default AudioMenuRegister diff --git a/src/components/Common/register.js b/src/components/Common/register.js index 344abd9..37c8c73 100644 --- a/src/components/Common/register.js +++ b/src/components/Common/register.js @@ -2,9 +2,11 @@ import ModuleWrapper from './Layout/ModuleWrapper.vue' import AntOriginSelect from './Form/AntOriginSelect.vue' import AntOriginTreeSelect from './Form/AntOriginTreeSelect.vue' +import DurationPicker from './Form/DurationPicker.vue' + +import WangEditor from './WangEditor/Index.vue' import GridBox from './Directives/GridBox' -import Flex from './Directives/Flex' import Loading from './Directives/Loading' import MyCesium from './Cesium/index' @@ -15,9 +17,11 @@ export default { Vue.component('AntOriginSelect', AntOriginSelect) Vue.component('AntOriginTreeSelect', AntOriginTreeSelect) + Vue.component('DurationPicker', DurationPicker) + + Vue.component('WangEditor', WangEditor) Vue.directive('grid-box', GridBox) - Vue.directive('flex', Flex) Vue.directive('loading', Loading) window.MyCesium = MyCesium diff --git a/src/layouts/BasicLayout.less b/src/layouts/BasicLayout.less index cf0ba68..8b04426 100644 --- a/src/layouts/BasicLayout.less +++ b/src/layouts/BasicLayout.less @@ -43,4 +43,8 @@ transition: all 0.3s; line-height: 64px; background: #001529; -} \ No newline at end of file +} + +.ant-layout-footer { + display: none; +} diff --git a/src/views/simulationScene/centralControl/index.vue b/src/views/simulationScene/centralControl/index.vue index d491a51..65b3b58 100644 --- a/src/views/simulationScene/centralControl/index.vue +++ b/src/views/simulationScene/centralControl/index.vue @@ -5,8 +5,7 @@
{{ block.moduleName }}
@@ -17,7 +16,7 @@
-
+
-
-
-
+
+
+
运行方式:
人在回路 人不在回路
-
+
开始 暂停 中止 @@ -64,27 +63,75 @@ 快进X1
-
+
想定时间 想定区域 想定说明 - 想定时间 - 想定区域 - - + + +
想定当前时间:
+
+ + +
+
+ +
想定开始时间:
+
+ + +
+
+ +
想定持续时间:
+
+ +
+
+ +
想定消耗时间:
+
+ +
+
+
+
+
+
经纬度坐标
+
左上
+ + +
右上
+ + +
右下
+ + +
左下
+ + +
+
+
+
+
+
+ +
想定名称:
{{ scenarioDetail.planName }}
- +
作者:
{{ scenarioDetail.author }}
想定说明:
- + +
@@ -95,7 +142,7 @@ -
+
{{ item.eventTime }} {{ item.eventDesc }} @@ -122,8 +169,9 @@ export default { }, runningMode: '1', - radioType: 'xdsm', + radioType: 'xdsj', scenarioDetail: {}, + cesium: null, visible: false, ioEventList: [ @@ -175,12 +223,30 @@ export default { url: `/baseData/scenario/${item.id}`, method: 'get', }) - this.scenarioDetail = JSON.parse(res.data.data.content) + this.scenarioDetail = JSON.parse(res.data.content) + console.log('----', this.scenarioDetail) this.loadedScenario = item.id + this.$nextTick(() => { + this.initCesium() + }) } catch (error) { console.log(error) } }, + initCesium() { + const { leftUpLat, rightUpLat, rightDownLat, leftDownLat, leftUpLon, rightUpLon, rightDownLon, leftDownLon } = + this.scenarioDetail + const centerLon = (leftUpLon + rightUpLon + rightDownLon + leftDownLon) / 4 + const centerLat = (leftUpLat + rightUpLat + rightDownLat + leftDownLat) / 4 + this.cesium = new window.MyCesium('jwd-cesium', { center: [centerLon, centerLat] }) + + this.cesium.setViewerByAllCorner( + [leftUpLon, leftUpLat], + [rightUpLon, rightUpLat], + [rightDownLon, rightDownLat], + [leftDownLon, leftDownLat] + ) + }, handleCloseSenario() { this.loadedScenario = '' }, @@ -238,8 +304,6 @@ export default { .scenario-item { position: relative; cursor: pointer; - width: 100%; - height: 100%; .scenario-image { width: 100%; height: 100%; @@ -298,15 +362,51 @@ export default { .xdsm-wrapper { background-color: #ffffff; color: #666666; - padding: 8px 10px; - p { - margin-bottom: 0; - } } } *::-webkit-scrollbar { display: none; } + ::v-deep { + .ant-calendar-picker-input, + .ant-time-picker-input { + background-color: #0b293a; + border: solid 1px #1d5777; + color: #ffffff; + } + } + .ant-calendar-picker { + color: #ffffff; + margin: 5px 0; + } + .ant-time-picker { + margin: 5px 0; + } + .ant-calendar-picker::v-deep { + .anticon { + color: #ffffff; + } + } + .ant-calendar-picker:hover::v-deep { + .anticon { + background-color: transparent; + } + } + .ant-time-picker::v-deep { + .anticon { + color: #ffffff; + } + } + .ant-time-picker:hover::v-deep { + .anticon { + background-color: transparent; + } + } + .ant-input { + background-color: #0b293a; + border: solid 1px #1d5777; + color: #ffffff; + } } .io-event-list { @@ -315,7 +415,6 @@ export default { background-color: #082532; padding: 20px; overflow-y: scroll; - display: block !important; .io-event-item { padding: 10px 0; font-size: 16px; diff --git a/src/views/simulationScene/index.vue b/src/views/simulationScene/index.vue index 38df00a..5a883c7 100644 --- a/src/views/simulationScene/index.vue +++ b/src/views/simulationScene/index.vue @@ -1,5 +1,5 @@