flex,editor
This commit is contained in:
parent
3e39f6c34e
commit
1ad29f234e
|
|
@ -16,6 +16,8 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design-vue/pro-layout": "^1.0.11",
|
"@ant-design-vue/pro-layout": "^1.0.11",
|
||||||
"@antv/data-set": "^0.10.2",
|
"@antv/data-set": "^0.10.2",
|
||||||
|
"@wangeditor/editor": "^5.1.23",
|
||||||
|
"@wangeditor/editor-for-vue": "^1.0.2",
|
||||||
"ant-design-vue": "^1.7.8",
|
"ant-design-vue": "^1.7.8",
|
||||||
"axios": "^0.26.1",
|
"axios": "^0.26.1",
|
||||||
"cesium": "1.101.0",
|
"cesium": "1.101.0",
|
||||||
|
|
|
||||||
144
src/App.vue
144
src/App.vue
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<a-config-provider :locale="locale" :autoInsertSpaceInButton="false">
|
<a-config-provider :locale="locale" :autoInsertSpaceInButton="false">
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<router-view/>
|
<router-view />
|
||||||
</div>
|
</div>
|
||||||
</a-config-provider>
|
</a-config-provider>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -11,53 +11,115 @@ import { domTitle, setDocumentTitle } from '@/utils/domUtil'
|
||||||
import { i18nRender } from '@/locales'
|
import { i18nRender } from '@/locales'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data () {
|
data() {
|
||||||
return {
|
return {}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
locale () {
|
locale() {
|
||||||
// 只是为了切换语言时,更新标题
|
// 只是为了切换语言时,更新标题
|
||||||
const { title } = this.$route.meta
|
const { title } = this.$route.meta
|
||||||
title && (setDocumentTitle(`${i18nRender(title)} - ${domTitle}`))
|
title && setDocumentTitle(`${i18nRender(title)} - ${domTitle}`)
|
||||||
|
|
||||||
return this.$i18n.getLocaleMessage(this.$store.getters.lang).antLocale
|
return this.$i18n.getLocaleMessage(this.$store.getters.lang).antLocale
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.ant-table td { white-space: nowrap !important; }
|
.ant-table td {
|
||||||
.ant-table th { white-space: nowrap !important; }
|
white-space: nowrap !important;
|
||||||
.ant-table-thead > tr > th, .ant-table-tbody > tr > td {
|
}
|
||||||
padding: 8px 8px !important;
|
.ant-table th {
|
||||||
overflow-wrap: break-word;
|
white-space: nowrap !important;
|
||||||
font-size: 14px;
|
}
|
||||||
}
|
.ant-table-thead > tr > th,
|
||||||
.flexRowStart {
|
.ant-table-tbody > tr > td {
|
||||||
display: flex;
|
padding: 8px 8px !important;
|
||||||
flex-direction: row;
|
overflow-wrap: break-word;
|
||||||
align-items: flex-start;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
.flexRowCenter {
|
.flexRowStart {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
.flexCenterCenter {
|
.flexRowCenter {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
.flexColumnCenterCenter{
|
.flexCenterCenter {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
justify-content: center;
|
||||||
justify-content: center;
|
align-items: center;
|
||||||
align-items: center;
|
}
|
||||||
}
|
.flexColumnCenterCenter {
|
||||||
.shaixuan_float_left{
|
display: flex;
|
||||||
float: left;
|
flex-direction: column;
|
||||||
margin-right: 20px;
|
justify-content: center;
|
||||||
}
|
align-items: center;
|
||||||
</style>
|
}
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ export default class MyCesium {
|
||||||
// 未完成的在地图上移动类的操作
|
// 未完成的在地图上移动类的操作
|
||||||
operations = []
|
operations = []
|
||||||
|
|
||||||
constructor(dom) {
|
constructor(dom, options = {}) {
|
||||||
const imageryProvider = new Cesium.UrlTemplateImageryProvider({
|
const imageryProvider = new Cesium.UrlTemplateImageryProvider({
|
||||||
url: window._CONFIG.ImageryProviderUrl || MyCesium.ImageryProviderUrl,
|
url: window._CONFIG.ImageryProviderUrl || MyCesium.ImageryProviderUrl,
|
||||||
tilingScheme: new Cesium.WebMercatorTilingScheme(),
|
tilingScheme: new Cesium.WebMercatorTilingScheme(),
|
||||||
|
|
@ -65,11 +65,13 @@ export default class MyCesium {
|
||||||
})
|
})
|
||||||
this.viewer = viewer
|
this.viewer = viewer
|
||||||
|
|
||||||
|
const { center = MyCesium.center } = options
|
||||||
|
|
||||||
// viewer.scene.globe.depthTestAgainstTerrain = true
|
// viewer.scene.globe.depthTestAgainstTerrain = true
|
||||||
|
|
||||||
viewer.imageryLayers.addImageryProvider(roadProvider)
|
viewer.imageryLayers.addImageryProvider(roadProvider)
|
||||||
viewer.camera.setView({
|
viewer.camera.setView({
|
||||||
destination: Cesium.Cartesian3.fromDegrees(...MyCesium.center),
|
destination: Cesium.Cartesian3.fromDegrees(...center),
|
||||||
})
|
})
|
||||||
|
|
||||||
// 不显示Cesium的Logo
|
// 不显示Cesium的Logo
|
||||||
|
|
@ -93,7 +95,7 @@ export default class MyCesium {
|
||||||
// 创建指北针小部件并将其添加到地图
|
// 创建指北针小部件并将其添加到地图
|
||||||
new CesiumNavigation(viewer, {
|
new CesiumNavigation(viewer, {
|
||||||
// 用于在使用重置导航重置地图视图时设置默认视图控制。接受的值是Cesium.Cartographic 和Cesium.Rectangle.
|
// 用于在使用重置导航重置地图视图时设置默认视图控制。接受的值是Cesium.Cartographic 和Cesium.Rectangle.
|
||||||
defaultResetView: Cesium.Cartographic.fromDegrees(...MyCesium.center),
|
defaultResetView: Cesium.Cartographic.fromDegrees(...center),
|
||||||
// 用于启用或禁用罗盘。true是启用罗盘,false是禁用罗盘。默认值为true。如果将选项设置为false,则罗盘将不会添加到地图中。
|
// 用于启用或禁用罗盘。true是启用罗盘,false是禁用罗盘。默认值为true。如果将选项设置为false,则罗盘将不会添加到地图中。
|
||||||
enableCompass: true,
|
enableCompass: true,
|
||||||
// 用于启用或禁用缩放控件。true是启用,false是禁用。默认值为true。如果将选项设置为false,则缩放控件 将不会添加到地图中。
|
// 用于启用或禁用缩放控件。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,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
@ -9,6 +9,7 @@ function initLoadingDom(el) {
|
||||||
el.loadingDom.style.justifyContent = 'center'
|
el.loadingDom.style.justifyContent = 'center'
|
||||||
}
|
}
|
||||||
function appendLoadingDom(el) {
|
function appendLoadingDom(el) {
|
||||||
|
if (document.body.contains(el.loadingDom)) return
|
||||||
const { top, left, width, height } = el.getBoundingClientRect()
|
const { top, left, width, height } = el.getBoundingClientRect()
|
||||||
el.loadingDom.style.top = `${top}px`
|
el.loadingDom.style.top = `${top}px`
|
||||||
el.loadingDom.style.left = `${left}px`
|
el.loadingDom.style.left = `${left}px`
|
||||||
|
|
@ -18,7 +19,9 @@ function appendLoadingDom(el) {
|
||||||
el.loadingDom.innerHTML = `<i aria-label="图标: loading" class="anticon anticon-loading"><svg viewBox="0 0 1024 1024" data-icon="loading" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class="anticon-spin"><path d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 0 0-94.3-139.9 437.71 437.71 0 0 0-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"></path></svg></i>`
|
el.loadingDom.innerHTML = `<i aria-label="图标: loading" class="anticon anticon-loading"><svg viewBox="0 0 1024 1024" data-icon="loading" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class="anticon-spin"><path d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 0 0-94.3-139.9 437.71 437.71 0 0 0-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"></path></svg></i>`
|
||||||
}
|
}
|
||||||
function removeLoadingDom(el) {
|
function removeLoadingDom(el) {
|
||||||
document.body.removeChild(el.loadingDom)
|
if (document.body.contains(el.loadingDom)) {
|
||||||
|
document.body.removeChild(el.loadingDom)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -45,5 +48,6 @@ export default {
|
||||||
},
|
},
|
||||||
unbind(el, binding, vnode, oldVnode) {
|
unbind(el, binding, vnode, oldVnode) {
|
||||||
// console.log('----unbind----', el, binding, vnode, oldVnode)
|
// console.log('----unbind----', el, binding, vnode, oldVnode)
|
||||||
|
removeLoadingDom(el)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
137
src/components/Common/Form/DurationPicker.vue
Normal file
137
src/components/Common/Form/DurationPicker.vue
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
<template>
|
||||||
|
<div class="duration-picker">
|
||||||
|
<template v-if="_showDay">
|
||||||
|
<a-input-number v-model="day" :min="0" :step="1" />
|
||||||
|
<span>天</span>
|
||||||
|
</template>
|
||||||
|
<template v-if="_showHour">
|
||||||
|
<a-input-number v-model="hour" :min="minHour" :step="1" />
|
||||||
|
<span>小时</span>
|
||||||
|
</template>
|
||||||
|
<template v-if="_showMinute">
|
||||||
|
<a-input-number v-model="minute" :min="minMinute" :step="1" />
|
||||||
|
<span>分钟</span>
|
||||||
|
</template>
|
||||||
|
<template v-if="_showSecond">
|
||||||
|
<a-input-number v-model="second" :min="minSecond" :step="1" />
|
||||||
|
<span>秒</span>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
value: { type: Number, required: true },
|
||||||
|
countFormat: { validator: (v) => ['D', 'H', 'm', 's'].includes(v), default: 'm' },
|
||||||
|
showDay: { type: Boolean, default: true },
|
||||||
|
showHour: { type: Boolean, default: true },
|
||||||
|
showMinute: { type: Boolean, default: true },
|
||||||
|
showSecond: { type: Boolean, default: true },
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
rateMap: {
|
||||||
|
D: 1 * 60 * 60 * 24,
|
||||||
|
H: 1 * 60 * 60,
|
||||||
|
m: 1 * 60,
|
||||||
|
s: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
baseRate() {
|
||||||
|
return this.rateMap[this.countFormat]
|
||||||
|
},
|
||||||
|
day: {
|
||||||
|
get() {
|
||||||
|
return Math.floor((this.value * this.baseRate) / this.rateMap['D'])
|
||||||
|
},
|
||||||
|
set(v) {
|
||||||
|
this.$emit('input', this.value + ((v - this.day) * this.rateMap['D']) / this.baseRate)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
hour: {
|
||||||
|
get() {
|
||||||
|
return Math.floor(((this.value * this.baseRate) % this.rateMap['D']) / this.rateMap['H'])
|
||||||
|
},
|
||||||
|
set(v) {
|
||||||
|
this.$emit('input', this.value + ((v - this.hour) * this.rateMap['H']) / this.baseRate)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
minute: {
|
||||||
|
get() {
|
||||||
|
return Math.floor(((this.value * this.baseRate) % this.rateMap['H']) / this.rateMap['m'])
|
||||||
|
},
|
||||||
|
set(v) {
|
||||||
|
this.$emit('input', this.value + ((v - this.minute) * this.rateMap['m']) / this.baseRate)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
second: {
|
||||||
|
get() {
|
||||||
|
return Math.floor(((this.value * this.baseRate) % this.rateMap['m']) / this.rateMap['s'])
|
||||||
|
},
|
||||||
|
set(v) {
|
||||||
|
this.$emit('input', this.value + ((v - this.second) * this.rateMap['s']) / this.baseRate)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
_showDay() {
|
||||||
|
return this.showDay && ['D', 'H', 'm', 's'].includes(this.countFormat)
|
||||||
|
},
|
||||||
|
_showHour() {
|
||||||
|
return this.showHour && ['H', 'm', 's'].includes(this.countFormat)
|
||||||
|
},
|
||||||
|
_showMinute() {
|
||||||
|
return this.showMinute && ['m', 's'].includes(this.countFormat)
|
||||||
|
},
|
||||||
|
_showSecond() {
|
||||||
|
return this.showSecond && ['s'].includes(this.countFormat)
|
||||||
|
},
|
||||||
|
minHour() {
|
||||||
|
return this.day > 0 ? -1 : 0
|
||||||
|
},
|
||||||
|
minMinute() {
|
||||||
|
return this.day > 0 || this.hour > 0 ? -1 : 0
|
||||||
|
},
|
||||||
|
minSecond() {
|
||||||
|
return this.day > 0 || this.hour > 0 || this.minute > 0 ? -1 : 0
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
::v-deep {
|
||||||
|
.ant-input-number {
|
||||||
|
background-color: #0b293a;
|
||||||
|
border: solid 1px #1d5777;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
.has-error .ant-input-number:hover {
|
||||||
|
background-color: #0b293a;
|
||||||
|
}
|
||||||
|
.has-error .ant-input-number-affix-wrapper .ant-input-number,
|
||||||
|
.has-error .ant-input-number-affix-wrapper .ant-input-number:hover {
|
||||||
|
background-color: #0b293a;
|
||||||
|
}
|
||||||
|
.ant-input-number-handler-wrap {
|
||||||
|
background-color: #aaaaaa;
|
||||||
|
border-left: solid 1px #1d5777;
|
||||||
|
}
|
||||||
|
.ant-input-number-handler {
|
||||||
|
.anticon {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-input-number-handler:hover {
|
||||||
|
.anticon {
|
||||||
|
color: #40a9ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-input-number-handler-up {
|
||||||
|
}
|
||||||
|
.ant-input-number-handler-down {
|
||||||
|
border-top: solid 1px #1d5777;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
152
src/components/Common/WangEditor/Index.vue
Normal file
152
src/components/Common/WangEditor/Index.vue
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
<template>
|
||||||
|
<div class="wang-editor">
|
||||||
|
<Toolbar class="wang-editor-toolbar" :editor="editor" :defaultConfig="toolbarConfig" :mode="mode" />
|
||||||
|
<Editor
|
||||||
|
class="wang-editor-textarea"
|
||||||
|
:style="{ height }"
|
||||||
|
v-model="_value"
|
||||||
|
:defaultConfig="editorConfig"
|
||||||
|
:mode="mode"
|
||||||
|
@onCreated="onCreated"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { Toolbar, Editor } from '@wangeditor/editor-for-vue'
|
||||||
|
import '@wangeditor/editor/dist/css/style.css'
|
||||||
|
import audioMenuRegister from './audioMenuRegister'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { Toolbar, Editor },
|
||||||
|
props: {
|
||||||
|
value: { validator: () => true, default: '' }, // v-model
|
||||||
|
height: { type: String, default: '300px' }, // 编辑区域高度,应至少300px
|
||||||
|
audio: { type: Boolean, default: false }, // 是否上传音频
|
||||||
|
toolbarKeysEnable: { type: [Array, Boolean], default: true },
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
editor: null,
|
||||||
|
toolbarConfig: {},
|
||||||
|
editorConfig: {
|
||||||
|
placeholder: '请输入内容...',
|
||||||
|
MENU_CONF: {
|
||||||
|
uploadImage: { customUpload: this.customUpload },
|
||||||
|
uploadVideo: { customUpload: this.customUpload },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mode: 'default',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
_value: {
|
||||||
|
get() {
|
||||||
|
return this.value
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
this.$emit(
|
||||||
|
'input',
|
||||||
|
val.replace(/<video ([^>]*)>/g, (matchText, $1) => {
|
||||||
|
if ($1.includes('autoplay')) {
|
||||||
|
return matchText
|
||||||
|
} else {
|
||||||
|
return matchText.replace($1, 'autoplay="true" $&')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
hasAudio() {
|
||||||
|
if (typeof this.toolbarKeysEnable === 'boolean') {
|
||||||
|
return this.toolbarKeysEnable
|
||||||
|
}
|
||||||
|
return this.toolbarKeysEnable.includes('uploadAudio')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
if (this.editor == null) return
|
||||||
|
this.editor.destroy()
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.initToolbarKeys()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initToolbarKeys() {
|
||||||
|
if (this.toolbarKeysEnable === true) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.toolbarKeysEnable === false) {
|
||||||
|
this.$set(this.toolbarConfig, 'toolbarKeys', [])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$set(this.toolbarConfig, 'toolbarKeys', this.toolbarKeysEnable)
|
||||||
|
},
|
||||||
|
onCreated(editor) {
|
||||||
|
if (this.hasAudio && this.audio) {
|
||||||
|
audioMenuRegister(editor, this.toolbarConfig, async ([file]) => {
|
||||||
|
this.customUpload(file, (filePath) => {
|
||||||
|
editor.insertNode({
|
||||||
|
type: 'video',
|
||||||
|
src: filePath,
|
||||||
|
autoplay: true,
|
||||||
|
controls: true,
|
||||||
|
width: '300px',
|
||||||
|
height: '50px',
|
||||||
|
children: [{ text: '' }],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.editor = Object.seal(editor)
|
||||||
|
},
|
||||||
|
/** 自定义上传
|
||||||
|
* @params [file] 上传的文件
|
||||||
|
* @return Promise 最终生成的文件绝对路径
|
||||||
|
*/
|
||||||
|
async customUpload(file, insertFn) {
|
||||||
|
const formdata = new FormData()
|
||||||
|
formdata.append('file', file)
|
||||||
|
const res = await this.$http({
|
||||||
|
url: '/file/upload',
|
||||||
|
method: 'post',
|
||||||
|
data: formdata,
|
||||||
|
headers: { 'Content-Type': 'multipart/form-data' },
|
||||||
|
})
|
||||||
|
const filePath = res.data
|
||||||
|
insertFn(filePath)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.wang-editor {
|
||||||
|
border: 1px solid #d9d9d9;
|
||||||
|
border-radius: 5px;
|
||||||
|
::v-deep .button-container {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.wang-editor.w-e-full-screen-container {
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
.wang-editor:not(.w-e-full-screen-container) {
|
||||||
|
::v-deep .w-e-toolbar {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
::v-deep .w-e-text-container {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
::v-deep .w-e-textarea-video-container > video {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 60px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.wang-editor-toolbar {
|
||||||
|
border-bottom: 1px solid #d9d9d9;
|
||||||
|
}
|
||||||
|
.wang-editor-textarea {
|
||||||
|
min-height: 300px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
81
src/components/Common/WangEditor/Readme.md
Normal file
81
src/components/Common/WangEditor/Readme.md
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
#### WangEditor
|
||||||
|
|
||||||
|
基于wangeditor5二次封装的公用组件,添加上传音频的功能
|
||||||
|
|
||||||
|
#### 官方文档
|
||||||
|
https://www.wangeditor.com/
|
||||||
|
|
||||||
|
#### 组件属性
|
||||||
|
|
||||||
|
1. value / v-model 内容
|
||||||
|
|
||||||
|
2. toolbarKeysEnable 可用工具栏,仅限初始化
|
||||||
|
```
|
||||||
|
布尔值 / 操作按钮key组成的数组
|
||||||
|
false / true / []<key>
|
||||||
|
```
|
||||||
|
|
||||||
|
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',
|
||||||
|
]
|
||||||
|
```
|
||||||
65
src/components/Common/WangEditor/audioMenuRegister.js
Normal file
65
src/components/Common/WangEditor/audioMenuRegister.js
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
import { Boot } from '@wangeditor/editor'
|
||||||
|
|
||||||
|
class AudioMenu {
|
||||||
|
title = ''
|
||||||
|
iconSvg = ''
|
||||||
|
tag = ''
|
||||||
|
constructor () {
|
||||||
|
this.title = '上传音频'
|
||||||
|
this.iconSvg =
|
||||||
|
'<svg t="1637634971457" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7981" width="16" height="16"><path d="M983.792981 0H40.211115A40.5504 40.5504 0 0 0 0.002048 40.96v942.08c0 22.664533 17.954133 40.96 40.209067 40.96h943.581866a40.5504 40.5504 0 0 0 40.209067-40.96V40.96c0-22.664533-17.954133-40.96-40.209067-40.96z m-235.383466 207.530667v118.784H581.702315v326.8608c0 81.92-62.190933 148.548267-138.8544 148.548266-76.663467 0-138.8544-63.351467-138.8544-141.448533 0-78.097067 62.122667-141.448533 138.8544-141.448533 31.607467 0 60.074667-2.730667 83.3536 16.110933v-327.68l222.208 0.273067z" fill="#999999" p-id="7982"></path></svg>'
|
||||||
|
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
|
||||||
|
|
@ -2,9 +2,11 @@ import ModuleWrapper from './Layout/ModuleWrapper.vue'
|
||||||
|
|
||||||
import AntOriginSelect from './Form/AntOriginSelect.vue'
|
import AntOriginSelect from './Form/AntOriginSelect.vue'
|
||||||
import AntOriginTreeSelect from './Form/AntOriginTreeSelect.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 GridBox from './Directives/GridBox'
|
||||||
import Flex from './Directives/Flex'
|
|
||||||
import Loading from './Directives/Loading'
|
import Loading from './Directives/Loading'
|
||||||
|
|
||||||
import MyCesium from './Cesium/index'
|
import MyCesium from './Cesium/index'
|
||||||
|
|
@ -15,9 +17,11 @@ export default {
|
||||||
|
|
||||||
Vue.component('AntOriginSelect', AntOriginSelect)
|
Vue.component('AntOriginSelect', AntOriginSelect)
|
||||||
Vue.component('AntOriginTreeSelect', AntOriginTreeSelect)
|
Vue.component('AntOriginTreeSelect', AntOriginTreeSelect)
|
||||||
|
Vue.component('DurationPicker', DurationPicker)
|
||||||
|
|
||||||
|
Vue.component('WangEditor', WangEditor)
|
||||||
|
|
||||||
Vue.directive('grid-box', GridBox)
|
Vue.directive('grid-box', GridBox)
|
||||||
Vue.directive('flex', Flex)
|
|
||||||
Vue.directive('loading', Loading)
|
Vue.directive('loading', Loading)
|
||||||
|
|
||||||
window.MyCesium = MyCesium
|
window.MyCesium = MyCesium
|
||||||
|
|
|
||||||
|
|
@ -43,4 +43,8 @@
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
line-height: 64px;
|
line-height: 64px;
|
||||||
background: #001529;
|
background: #001529;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-layout-footer {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,7 @@
|
||||||
<div
|
<div
|
||||||
v-for="block in systemModules"
|
v-for="block in systemModules"
|
||||||
:key="block.moduleCode"
|
:key="block.moduleCode"
|
||||||
:class="['system-block', `system-${block.moduleStatus}`]"
|
:class="['system-block', 'flex-c', 'ai-c', 'jc-sb', `system-${block.moduleStatus}`]"
|
||||||
v-flex.v="['c', 'sb']"
|
|
||||||
>
|
>
|
||||||
<img class="icon" :src="systemIconMap[block.moduleCode]" alt="" />
|
<img class="icon" :src="systemIconMap[block.moduleCode]" alt="" />
|
||||||
<div class="title">{{ block.moduleName }}</div>
|
<div class="title">{{ block.moduleName }}</div>
|
||||||
|
|
@ -17,7 +16,7 @@
|
||||||
</div>
|
</div>
|
||||||
</ModuleWrapper>
|
</ModuleWrapper>
|
||||||
<ModuleWrapper v-if="!loadedScenario" title="全部想定" style="grid-column: 1 / 3">
|
<ModuleWrapper v-if="!loadedScenario" title="全部想定" style="grid-column: 1 / 3">
|
||||||
<div class="normal" v-flex.v="['c']" v-loading="loading">
|
<div class="normal flex-c ai-c" v-loading="loading">
|
||||||
<div class="scenario-wrapper" v-grid-box="{ columns: [1, 1, 1, 1, 1], rows: [1, 1] }">
|
<div class="scenario-wrapper" v-grid-box="{ columns: [1, 1, 1, 1, 1], rows: [1, 1] }">
|
||||||
<div v-for="item in scenarioList" :key="item.id" class="scenario-item">
|
<div v-for="item in scenarioList" :key="item.id" class="scenario-item">
|
||||||
<img
|
<img
|
||||||
|
|
@ -47,16 +46,16 @@
|
||||||
<template #extra>
|
<template #extra>
|
||||||
<a-button type="primary" shape="circle" icon="close" @click="handleCloseSenario()" />
|
<a-button type="primary" shape="circle" icon="close" @click="handleCloseSenario()" />
|
||||||
</template>
|
</template>
|
||||||
<div class="normal" v-flex.v>
|
<div class="normal flex-c">
|
||||||
<div v-flex="['c', 'sb']" style="margin-bottom: 10px">
|
<div class="flex ai-c jc-sb" style="margin-bottom: 10px">
|
||||||
<div v-flex="['c']">
|
<div class="flex ai-c">
|
||||||
<div style="color: #92bacb">运行方式:</div>
|
<div style="color: #92bacb">运行方式:</div>
|
||||||
<a-select style="width: 240px" v-model="runningMode">
|
<a-select style="width: 240px" v-model="runningMode">
|
||||||
<a-select-option value="1">人在回路</a-select-option>
|
<a-select-option value="1">人在回路</a-select-option>
|
||||||
<a-select-option value="2">人不在回路</a-select-option>
|
<a-select-option value="2">人不在回路</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</div>
|
</div>
|
||||||
<div v-flex="['c']">
|
<div class="flex ai-c">
|
||||||
<a-button type="primary" icon="caret-right">开始</a-button>
|
<a-button type="primary" icon="caret-right">开始</a-button>
|
||||||
<a-button type="primary" icon="pause">暂停</a-button>
|
<a-button type="primary" icon="pause">暂停</a-button>
|
||||||
<a-button type="primary" icon="stop">中止</a-button>
|
<a-button type="primary" icon="stop">中止</a-button>
|
||||||
|
|
@ -64,27 +63,75 @@
|
||||||
<a-button type="primary" icon="step-forward">快进X1</a-button>
|
<a-button type="primary" icon="step-forward">快进X1</a-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="scenario-info-wrapper" v-flex.v>
|
<div class="scenario-info-wrapper flex-c">
|
||||||
<a-radio-group v-model="radioType" button-style="solid">
|
<a-radio-group v-model="radioType" button-style="solid">
|
||||||
<a-radio-button value="xdsj">想定时间</a-radio-button>
|
<a-radio-button value="xdsj">想定时间</a-radio-button>
|
||||||
<a-radio-button value="xdqy">想定区域</a-radio-button>
|
<a-radio-button value="xdqy">想定区域</a-radio-button>
|
||||||
<a-radio-button value="xdsm">想定说明</a-radio-button>
|
<a-radio-button value="xdsm">想定说明</a-radio-button>
|
||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
<a-row v-if="radioType === 'xdsj'">想定时间</a-row>
|
<a-row v-show="radioType === 'xdsj'">
|
||||||
<a-row v-if="radioType === 'xdqy'">想定区域</a-row>
|
<a-col :span="24">
|
||||||
<a-row v-if="radioType === 'xdsm'" style="flex: 1; padding: 10px 16px; overflow-y: auto">
|
<div>想定当前时间:</div>
|
||||||
<a-col :span="12" v-flex="['c']">
|
<div>
|
||||||
|
<a-date-picker :value="scenarioDetail.planDate" valueFormat="YYYY-MM-DD" style="width: 100%" />
|
||||||
|
<a-time-picker :value="scenarioDetail.planTime" valueFormat="HH:mm:ss" style="width: 100%" />
|
||||||
|
</div>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="24">
|
||||||
|
<div>想定开始时间:</div>
|
||||||
|
<div>
|
||||||
|
<a-date-picker :value="scenarioDetail.startDate" valueFormat="YYYY-MM-DD" style="width: 100%" />
|
||||||
|
<a-time-picker :value="scenarioDetail.startTime" valueFormat="HH:mm:ss" style="width: 100%" />
|
||||||
|
</div>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="24">
|
||||||
|
<div>想定持续时间:</div>
|
||||||
|
<div>
|
||||||
|
<DurationPicker v-model="scenarioDetail.continueTime" />
|
||||||
|
</div>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="24">
|
||||||
|
<div>想定消耗时间:</div>
|
||||||
|
<div>
|
||||||
|
<DurationPicker v-model="scenarioDetail.wasterTime" />
|
||||||
|
</div>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
<div v-show="radioType === 'xdqy'" class="flex-1 flex">
|
||||||
|
<div style="width: 150px">
|
||||||
|
<div>经纬度坐标</div>
|
||||||
|
<div>左上</div>
|
||||||
|
<a-input v-model="scenarioDetail.leftUpLon" style="width: 100%" />
|
||||||
|
<a-input v-model="scenarioDetail.leftUpLat" style="width: 100%" />
|
||||||
|
<div>右上</div>
|
||||||
|
<a-input v-model="scenarioDetail.rightUpLon" style="width: 100%" />
|
||||||
|
<a-input v-model="scenarioDetail.rightUpLat" style="width: 100%" />
|
||||||
|
<div>右下</div>
|
||||||
|
<a-input v-model="scenarioDetail.rightDownLon" style="width: 100%" />
|
||||||
|
<a-input v-model="scenarioDetail.rightDownLat" style="width: 100%" />
|
||||||
|
<div>左下</div>
|
||||||
|
<a-input v-model="scenarioDetail.leftDownLon" style="width: 100%" />
|
||||||
|
<a-input v-model="scenarioDetail.leftDownLat" style="width: 100%" />
|
||||||
|
</div>
|
||||||
|
<div class="flex-1" style="position: relative">
|
||||||
|
<div id="jwd-cesium" style="width: 100%; height: 100%"></div>
|
||||||
|
<div style="position: absolute; left: 0; top: 0; width: 100%; height: 100%"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a-row v-show="radioType === 'xdsm'" style="flex: 1; padding: 10px 16px; overflow-y: auto">
|
||||||
|
<a-col :span="12" class="flex ai-c">
|
||||||
<div>想定名称:</div>
|
<div>想定名称:</div>
|
||||||
<div>{{ scenarioDetail.planName }}</div>
|
<div>{{ scenarioDetail.planName }}</div>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="12" v-flex="['c']">
|
<a-col :span="12" class="flex ai-c">
|
||||||
<div>作者:</div>
|
<div>作者:</div>
|
||||||
<div>{{ scenarioDetail.author }}</div>
|
<div>{{ scenarioDetail.author }}</div>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="24">
|
<a-col :span="24">
|
||||||
<div>想定说明:</div>
|
<div>想定说明:</div>
|
||||||
<div class="xdsm-wrapper">
|
<div class="xdsm-wrapper">
|
||||||
<iframe v-html="scenarioDetail.planDesc" frameborder="0"></iframe>
|
<WangEditor v-model="scenarioDetail.planDesc" />
|
||||||
|
<!-- <iframe v-html="scenarioDetail.planDesc" frameborder="0"></iframe> -->
|
||||||
</div>
|
</div>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
|
|
@ -95,7 +142,7 @@
|
||||||
<template #extra>
|
<template #extra>
|
||||||
<a-checkbox v-model="visible">显示</a-checkbox>
|
<a-checkbox v-model="visible">显示</a-checkbox>
|
||||||
</template>
|
</template>
|
||||||
<div class="io-event-list" test="1" style="display: block">
|
<div class="io-event-list">
|
||||||
<div v-for="item in ioEventList" :key="item.id" class="io-event-item">
|
<div v-for="item in ioEventList" :key="item.id" class="io-event-item">
|
||||||
<span style="margin-right: 20px">{{ item.eventTime }}</span>
|
<span style="margin-right: 20px">{{ item.eventTime }}</span>
|
||||||
<span>{{ item.eventDesc }}</span>
|
<span>{{ item.eventDesc }}</span>
|
||||||
|
|
@ -122,8 +169,9 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
runningMode: '1',
|
runningMode: '1',
|
||||||
radioType: 'xdsm',
|
radioType: 'xdsj',
|
||||||
scenarioDetail: {},
|
scenarioDetail: {},
|
||||||
|
cesium: null,
|
||||||
|
|
||||||
visible: false,
|
visible: false,
|
||||||
ioEventList: [
|
ioEventList: [
|
||||||
|
|
@ -175,12 +223,30 @@ export default {
|
||||||
url: `/baseData/scenario/${item.id}`,
|
url: `/baseData/scenario/${item.id}`,
|
||||||
method: 'get',
|
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.loadedScenario = item.id
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.initCesium()
|
||||||
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(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() {
|
handleCloseSenario() {
|
||||||
this.loadedScenario = ''
|
this.loadedScenario = ''
|
||||||
},
|
},
|
||||||
|
|
@ -238,8 +304,6 @@ export default {
|
||||||
.scenario-item {
|
.scenario-item {
|
||||||
position: relative;
|
position: relative;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
.scenario-image {
|
.scenario-image {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
@ -298,15 +362,51 @@ export default {
|
||||||
.xdsm-wrapper {
|
.xdsm-wrapper {
|
||||||
background-color: #ffffff;
|
background-color: #ffffff;
|
||||||
color: #666666;
|
color: #666666;
|
||||||
padding: 8px 10px;
|
|
||||||
p {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*::-webkit-scrollbar {
|
*::-webkit-scrollbar {
|
||||||
display: none;
|
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 {
|
.io-event-list {
|
||||||
|
|
@ -315,7 +415,6 @@ export default {
|
||||||
background-color: #082532;
|
background-color: #082532;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
display: block !important;
|
|
||||||
.io-event-item {
|
.io-event-item {
|
||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="simulation-scene-page" v-flex.v>
|
<div class="simulation-scene-page flex-c">
|
||||||
<div v-if="title" class="simulation-scene-header">
|
<div v-if="title" class="simulation-scene-header">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,23 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="scene-editing-page" v-grid-box="{ columns: ['320px', 1, '320px'], rows: [45, 30, 25], gap: '0px' }">
|
<div class="scene-editing-page" v-grid-box="{ columns: ['320px', 1, '320px'], rows: [45, 30, 25], gap: '0px' }">
|
||||||
<ModuleWrapper title="作战/保障力量" style="grid-column: 1 / 2; grid-row: 1 / 2">
|
<ModuleWrapper title="作战/保障力量" style="grid-column: 1 / 2; grid-row: 1 / 2">
|
||||||
<div class="normal" style="padding: 5px">
|
<div class="normal" style="padding: 5px; overflow-y: auto">
|
||||||
<a-tree :treeData="zb.zbTreeData"></a-tree>
|
<a-tree
|
||||||
|
:treeData="zb.zbTreeData"
|
||||||
|
:selectedKeys.sync="zb.selectedKeys"
|
||||||
|
:replaceFields="{ children: 'children', title: 'name', key: 'id' }"
|
||||||
|
@select="handleSelectTree"
|
||||||
|
></a-tree>
|
||||||
</div>
|
</div>
|
||||||
</ModuleWrapper>
|
</ModuleWrapper>
|
||||||
<ModuleWrapper title="装备元素" style="grid-column: 1 / 2; grid-row: 2 / 4">
|
<ModuleWrapper title="装备元素" style="grid-column: 1 / 2; grid-row: 2 / 4">
|
||||||
<div class="normal" style="padding: 5px" v-flex.v>
|
<div class="normal flex-c" style="padding: 5px">
|
||||||
<a-input-search v-model="ys.keyword" placeholder="输入关键词搜索..." @search="onSearch" />
|
<a-input-search v-model="ys.keyword" placeholder="输入关键词搜索..." @search="onSearch" />
|
||||||
<div style="height: 0; flex: 1; overflow-y: auto">
|
<div style="height: 0; flex: 1; overflow-y: auto">
|
||||||
<a-row>
|
<a-row>
|
||||||
<template v-for="item in ys.ysList">
|
<template v-for="item in ys.ysList">
|
||||||
<a-col :key="item.id" :span="24">{{ item.title }}</a-col>
|
<a-col :key="item.id" :span="24">{{ item.title }}</a-col>
|
||||||
<a-col v-for="it in item.children" :key="it.id" :span="12" v-flex.v="['c']">
|
<a-col v-for="it in item.children" :key="it.id" :span="12" class="flex-c ai-c">
|
||||||
<img class="ys-image" :src="it.image" alt="" />
|
<img class="ys-image" :src="it.image" alt="" />
|
||||||
<span>{{ it.title }}</span>
|
<span>{{ it.title }}</span>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
|
@ -31,11 +36,11 @@
|
||||||
<div style="height: 100%; padding: 0 15px; overflow-y: auto">
|
<div style="height: 100%; padding: 0 15px; overflow-y: auto">
|
||||||
<img class="image" :src="zt.image" />
|
<img class="image" :src="zt.image" />
|
||||||
<div class="name">{{ zt.name }}</div>
|
<div class="name">{{ zt.name }}</div>
|
||||||
<div v-for="item in zt.ztList" :key="item.label" class="zt-item" v-flex="['c']">
|
<div v-for="item in zt.ztList" :key="item.label" class="zt-item flex ai-c">
|
||||||
<span>{{ item.label }}:</span>
|
<span>{{ item.label }}:</span>
|
||||||
<img :src="item.icon" alt="" />
|
<img :src="item.icon" alt="" />
|
||||||
<span>{{ item.text }}</span>
|
<span>{{ item.text }}</span>
|
||||||
<div v-if="'progress' in item" class="progress-bar" v-flex>
|
<div v-if="'progress' in item" class="progress-bar flex">
|
||||||
<div class="progress" :style="{ width: item.progress }"></div>
|
<div class="progress" :style="{ width: item.progress }"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -45,7 +50,7 @@
|
||||||
<ModuleWrapper title="作战单元武器" style="grid-column: 3 / 4; grid-row: 3 / 4">
|
<ModuleWrapper title="作战单元武器" style="grid-column: 3 / 4; grid-row: 3 / 4">
|
||||||
<div class="normal" style="padding: 15px 0">
|
<div class="normal" style="padding: 15px 0">
|
||||||
<div style="height: 100%; padding: 0 15px; overflow-y: auto">
|
<div style="height: 100%; padding: 0 15px; overflow-y: auto">
|
||||||
<div v-for="(item, index) in zzdywq.wqList" :key="index" class="wq-item" v-flex>
|
<div v-for="(item, index) in zzdywq.wqList" :key="index" class="wq-item flex">
|
||||||
<span>{{ item.title }}</span>
|
<span>{{ item.title }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -60,42 +65,8 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
cesium: null,
|
cesium: null,
|
||||||
zb: {
|
scenarioId: null,
|
||||||
zbTreeData: [
|
zb: { zbTreeData: [], selectedKeys: [] },
|
||||||
{
|
|
||||||
key: '1',
|
|
||||||
title: '红方',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
key: '1-1',
|
|
||||||
title: '作战力量',
|
|
||||||
children: [
|
|
||||||
{ key: '1-1-1', title: '左翼夺控群火力分队' },
|
|
||||||
{ key: '1-1-2', title: '左翼攻击分队' },
|
|
||||||
{ key: '1-1-3', title: '右翼攻击分队' },
|
|
||||||
{ key: '1-1-4', title: '右翼夺控群反装甲分队' },
|
|
||||||
{ key: '1-1-5', title: '防空火力队' },
|
|
||||||
{ key: '1-1-6', title: '左翼牵制群右翼攻击分队' },
|
|
||||||
{ key: '1-1-7', title: '电子对抗兵队超短波干扰分队' },
|
|
||||||
{ key: '1-1-8', title: '纵深夺控群火力分队' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '1-2',
|
|
||||||
title: '保障力量',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '2',
|
|
||||||
title: '蓝方',
|
|
||||||
children: [
|
|
||||||
{ key: '1-1', title: '作战力量' },
|
|
||||||
{ key: '1-2', title: '保障力量' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
ys: {
|
ys: {
|
||||||
keyword: '',
|
keyword: '',
|
||||||
ysList: [
|
ysList: [
|
||||||
|
|
@ -159,8 +130,46 @@ export default {
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.cesium = new window.MyCesium('cesium-container')
|
this.cesium = new window.MyCesium('cesium-container')
|
||||||
|
this.scenarioId = 2733
|
||||||
|
this.getZbTree()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
async getZbTree() {
|
||||||
|
try {
|
||||||
|
const res = await this.$http({
|
||||||
|
url: `/scenario/power/${this.scenarioId}`,
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
this.zb.zbTreeData = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
name: '红方',
|
||||||
|
selectable: false,
|
||||||
|
children: [
|
||||||
|
{ id: '1-1', name: '作战力量', selectable: false, children: res.data.red.fight },
|
||||||
|
{ id: '1-2', name: '保障力量', selectable: false, children: res.data.red.guarantee },
|
||||||
|
{ id: '1-3', name: '指挥力量', selectable: false, children: res.data.red.command },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
name: '蓝方',
|
||||||
|
selectable: false,
|
||||||
|
children: [
|
||||||
|
{ id: '2-1', name: '作战力量', selectable: false, children: res.data.red.fight },
|
||||||
|
{ id: '2-2', name: '保障力量', selectable: false, children: res.data.red.guarantee },
|
||||||
|
{ id: '2-3', name: '指挥力量', selectable: false, children: res.data.red.command },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleSelectTree(selectedKeys, { node }) {
|
||||||
|
console.log(...arguments)
|
||||||
|
// node.dataRef
|
||||||
|
},
|
||||||
onSearch(e) {
|
onSearch(e) {
|
||||||
console.log('----', e, e.target.value)
|
console.log('----', e, e.target.value)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
<ModuleWrapper title="资源" style="grid-column: 3 / 4; grid-row: 3 / 4">
|
<ModuleWrapper title="资源" style="grid-column: 3 / 4; grid-row: 3 / 4">
|
||||||
<div class="normal" style="padding: 15px 0">
|
<div class="normal" style="padding: 15px 0">
|
||||||
<div style="height: 100%; padding: 0 15px; overflow-y: auto">
|
<div style="height: 100%; padding: 0 15px; overflow-y: auto">
|
||||||
<div v-for="item in zy.zyList" :key="item.label" class="zy-item" v-flex>
|
<div v-for="item in zy.zyList" :key="item.label" class="zy-item flex">
|
||||||
<span>{{ item.label }}:</span>
|
<span>{{ item.label }}:</span>
|
||||||
<span style="flex: 1; white-space: nowrap; overflow: hidden" v-html="zy.placeholder"></span>
|
<span style="flex: 1; white-space: nowrap; overflow: hidden" v-html="zy.placeholder"></span>
|
||||||
<span>{{ item.text }}</span>
|
<span>{{ item.text }}</span>
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,8 @@
|
||||||
<div
|
<div
|
||||||
v-for="(block, index) in systemModules"
|
v-for="(block, index) in systemModules"
|
||||||
:key="block.moduleCode"
|
:key="block.moduleCode"
|
||||||
:class="['system-block', `system-${block.moduleStatus}`]"
|
:class="['system-block', 'flex-c', 'ai-c', 'jc-sb', `system-${block.moduleStatus}`]"
|
||||||
:style="blockStyleMap[index]"
|
:style="blockStyleMap[index]"
|
||||||
v-flex.v="['c', 'sb']"
|
|
||||||
@click="handleClick(block)"
|
@click="handleClick(block)"
|
||||||
>
|
>
|
||||||
<img class="icon" :src="systemIconMap[block.moduleCode]" alt="" />
|
<img class="icon" :src="systemIconMap[block.moduleCode]" alt="" />
|
||||||
|
|
|
||||||
|
|
@ -395,13 +395,13 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
::v-deep {
|
::v-deep {
|
||||||
.ant-input-lg {
|
.ant-input {
|
||||||
height: 52px;
|
height: 52px;
|
||||||
background-color: #0b293a;
|
background-color: #0b293a;
|
||||||
border: solid 1px #1d5777;
|
border: solid 1px #1d5777;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
.ant-input-lg:-webkit-autofill {
|
.ant-input:-webkit-autofill {
|
||||||
-webkit-text-fill-color: #fff !important;
|
-webkit-text-fill-color: #fff !important;
|
||||||
transition: background-color 5000s ease-in-out 0s;
|
transition: background-color 5000s ease-in-out 0s;
|
||||||
caret-color: #acfff2;
|
caret-color: #acfff2;
|
||||||
|
|
@ -415,11 +415,11 @@ export default {
|
||||||
.ant-input-suffix .anticon:hover {
|
.ant-input-suffix .anticon:hover {
|
||||||
color: #ffffffcc;
|
color: #ffffffcc;
|
||||||
}
|
}
|
||||||
.has-error .ant-input-lg:hover {
|
.has-error .ant-input:hover {
|
||||||
background-color: #0b293a;
|
background-color: #0b293a;
|
||||||
}
|
}
|
||||||
.has-error .ant-input-affix-wrapper .ant-input-lg,
|
.has-error .ant-input-affix-wrapper .ant-input,
|
||||||
.has-error .ant-input-affix-wrapper .ant-input-lg:hover {
|
.has-error .ant-input-affix-wrapper .ant-input:hover {
|
||||||
background-color: #0b293a;
|
background-color: #0b293a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user