| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535 |
- <template>
- <div
- ref="wrapper"
- v-loading="!loaded && loading"
- element-loading-background="transparent"
- >
- <warning
- v-if="!loaded && !loading"
- @click="getBoundThirdPartyDevices"
- />
- <div
- v-if="loaded"
- class="c-link-state l-flex--row"
- :class="className"
- >
- <div
- class="c-link-state__main"
- :style="styles"
- >
- <div
- v-for="item in items"
- :key="item.key"
- class="o-link-item"
- :class="item.className"
- @click="onClick(item)"
- >
- <div class="o-link-item__name">{{ item.label }}</div>
- <device-player
- v-if="item.key === 'led'"
- :device="device"
- autoplay
- retry
- />
- <svg-icon
- v-else
- class="o-link-item__img"
- :icon-class="item.icon"
- />
- </div>
- <div
- v-for="line in lines"
- :key="line.key"
- class="o-line"
- :class="line.className"
- />
- </div>
- </div>
- <slot />
- </div>
- </template>
- <script>
- import { getBoundThirdPartyDevices } from '@/api/external'
- import { ThirdPartyDevice } from '@/constant'
- const LinkItems = Object.freeze([
- {
- key: 'msr',
- label: '浪潮屏媒安播云平台'
- },
- {
- key: 'device',
- label: '浪潮超高清媒体播控器'
- },
- {
- key: 'led',
- label: 'LED大屏'
- },
- {
- key: ThirdPartyDevice.GATEWAY,
- alias: 'gateway',
- label: '浪潮物联网关',
- iconKey: 'gateway',
- canClick: true
- },
- {
- key: ThirdPartyDevice.TRAFFIC_CAMERA,
- alias: 'traffic_camera',
- label: '人流量监测摄像头',
- iconKey: 'camera',
- canClick: true
- },
- {
- key: ThirdPartyDevice.LED_CAMERA,
- alias: 'led_camera',
- label: 'LED屏监测摄像头',
- iconKey: 'camera',
- canClick: true
- },
- {
- key: ThirdPartyDevice.SENDING_CARD,
- alias: 'sending_card',
- label: '发送控制设备',
- iconKey: 'sending-card',
- canClick: true
- },
- {
- key: ThirdPartyDevice.RECEIVING_CARD,
- alias: 'receiving_card',
- label: '接收卡',
- iconKey: 'receiving-card',
- canClick: true
- }
- ])
- const LineFromeTo = {
- 1: ['msr', 'device'],
- 2: ['device', ThirdPartyDevice.SENDING_CARD],
- 3: [ThirdPartyDevice.SENDING_CARD, ThirdPartyDevice.RECEIVING_CARD],
- 4: [ThirdPartyDevice.RECEIVING_CARD, 'led'],
- 5: ['msr', ThirdPartyDevice.GATEWAY],
- 6: ['msr', ThirdPartyDevice.LED_CAMERA, ThirdPartyDevice.TRAFFIC_CAMERA],
- 7: ['msr', ThirdPartyDevice.LED_CAMERA],
- 8: ['msr', ThirdPartyDevice.LED_CAMERA],
- 9: ['msr', ThirdPartyDevice.TRAFFIC_CAMERA],
- 10: [ThirdPartyDevice.GATEWAY, 'led'],
- 11: ['msr', ThirdPartyDevice.GATEWAY, ThirdPartyDevice.LED_CAMERA, ThirdPartyDevice.TRAFFIC_CAMERA]
- }
- export default {
- name: 'FullLink',
- props: {
- device: {
- type: Object,
- required: true
- },
- theme: {
- type: String,
- default: 'dark'
- },
- square: {
- type: [Boolean, String],
- default: false
- }
- },
- data () {
- return {
- linkDeviceMap: null,
- scale: 1,
- loading: false,
- loaded: false
- }
- },
- computed: {
- online () {
- return this.device.onlineStatus === 1
- },
- targetId () {
- return this.device.id
- },
- className () {
- return [this.theme, this.square ? 'square' : ''].join(' ')
- },
- linkState () {
- const map = {
- msr: 1,
- device: this.online ? 1 : 0,
- led: this.online ? 1 : 0,
- [ThirdPartyDevice.GATEWAY]: -1,
- [ThirdPartyDevice.LED_CAMERA]: -1,
- [ThirdPartyDevice.TRAFFIC_CAMERA]: -1,
- [ThirdPartyDevice.SENDING_CARD]: -1,
- [ThirdPartyDevice.RECEIVING_CARD]: -1
- }
- if (this.linkDeviceMap) {
- for (const item of this.linkDeviceMap) {
- map[item.deviceType] = item.status
- }
- }
- return map
- },
- items () {
- const map = this.linkState
- return LinkItems.map(({ key, alias, label, iconKey, canClick }) => {
- const status = map[key]
- return {
- key, label, status, canClick,
- icon: status === -1
- ? 'link-unbound'
- : `link-${iconKey || key}-${status === 1 ? 'online' : 'offline'}`,
- className: [alias || key, canClick && ~status ? 'u-pointer' : ''].join(' ')
- }
- })
- },
- lines () {
- const state = this.linkState
- return Object.keys(LineFromeTo).map(key => {
- const from = LineFromeTo[key][0]
- const to = LineFromeTo[key].slice(1)
- return {
- key: `line${key}`,
- className: [`l${key}`, state[from] === 1 && to.some(key => state[key] === 1) ? 'linked' : ''].join(' ')
- }
- })
- },
- styles () {
- return {
- transform: `scale(${this.scale})`
- }
- }
- },
- created () {
- this.getBoundThirdPartyDevices()
- this.$timer = setInterval(this.getBoundThirdPartyDevices, 10000)
- },
- mounted () {
- this.checkScale()
- window.addEventListener('resize', this.checkScale)
- },
- beforeDestroy () {
- window.removeEventListener('resize', this.checkScale)
- clearInterval(this.$timer)
- },
- methods: {
- checkScale () {
- const elm = this.$refs.wrapper
- const width = elm.clientWidth
- const height = elm.clientHeight
- this.scale = this.square
- ? Math.min(width / 804, height / 640).toFixed(2)
- : Math.min(width / 966, height / 420).toFixed(2)
- },
- getBoundThirdPartyDevices () {
- if (this.loading) {
- return
- }
- this.loading = true
- getBoundThirdPartyDevices(this.targetId, true).then(({ data }) => {
- this.linkDeviceMap = data
- this.loaded = true
- }).finally(() => {
- this.loading = false
- })
- },
- onClick (item) {
- if (!item.canClick) {
- return
- }
- this.$emit('click', item)
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- @mixin getPosition($left, $top, $width, $height) {
- top: $top;
- left: $left;
- width: $width;
- height: $height;
- }
- .c-link-state {
- width: 100%;
- height: 100%;
- overflow: hidden;
- &__main {
- position: relative;
- width: 966px;
- height: 420px;
- transform-origin: left center;
- }
- &.dark {
- color: $black;
- }
- &.light {
- color: #fff;
- }
- &.square {
- .c-link-state__main {
- width: 804px;
- height: 640px;
- }
- .o-link-item {
- &.msr {
- top: 0;
- left: 0;
- }
- &.device {
- top: 75px;
- left: 286px;
- }
- &.sending_card {
- top: 75px;
- left: 472px;
- }
- &.receiving_card {
- top: 75px;
- left: 660px;
- }
- &.gateway {
- top: 432px;
- left: 52px;
- width: 138px;
- height: 138px;
- }
- &.traffic_camera {
- top: 280px;
- left: 460px;
- }
- &.led_camera {
- top: 400px;
- left: 290px;
- }
- &.led {
- top: 400px;
- left: 440px;
- }
- }
- .o-line {
- &.l1 {
- top: 166px;
- left: 232px;
- width: 60px;
- transform: none;
- }
- &.l2 {
- top: 166px;
- left: 418px;
- width: 60px;
- }
- &.l3 {
- top: 166px;
- left: 604px;
- width: 60px;
- }
- &.l4 {
- top: 202px;
- left: 728px;
- width: 198px;
- }
- &.l5 {
- top: 334px;
- left: 122px;
- width: 108px;
- transform: rotate(90deg);
- }
- &.l6 {
- top: 334px;
- left: 122px;
- width: 120px;
- }
- &.l7 {
- top: 334px;
- left: 240px;
- width: 120px;
- }
- &.l8 {
- top: 454px;
- left: 240px;
- }
- &.l9 {
- top: 334px;
- left: 240px;
- width: 234px;
- }
- &.l10 {
- top: 522px;
- left: 184px;
- width: 256px;
- }
- &.l11 {
- top: 230px;
- left: 122px;
- width: 104px;
- height: 2px;
- transform: rotate(90deg);
- transform-origin: left;
- }
- }
- }
- }
- @keyframes move {
- from {
- background-position: 0 0;
- }
- to {
- background-position: 3em 0;
- }
- }
- .o-link-item {
- position: absolute;
- z-index: 1;
- &__name {
- position: absolute;
- top: 100%;
- left: 50%;
- font-size: 14px;
- line-height: 1;
- white-space: nowrap;
- transform: translateX(-50%);
- }
- &__img {
- width: 100%;
- height: 100%;
- }
- &.msr {
- @include getPosition(0, 42px, 242px, 236px);
- }
- &.device {
- @include getPosition(270px, 0, 138px, 138px);
- }
- &.sending_card {
- @include getPosition(484px, 0, 138px, 138px);
- }
- &.receiving_card {
- @include getPosition(720px, 0, 138px, 138px);
- .o-link-item__name {
- transform: translateX(8px);
- }
- }
- &.gateway {
- @include getPosition(270px, 250px, 138px, 138px);
- }
- &.traffic_camera {
- @include getPosition(480px, 156px, 80px, 80px);
- }
- &.led_camera {
- @include getPosition(480px, 252px, 80px, 80px);
- }
- &.led {
- @include getPosition(604px, 208px, 352px, 198px);
- .o-link-item__name {
- top: -8px;
- left: auto;
- right: 0;
- bottom: auto;
- transform: translateY(-100%);
- }
- }
- }
- .o-line {
- position: absolute;
- background-color: $gray--light;
- &.linked {
- background-size: 3em 1em;
- background-image: linear-gradient(
- -90deg,
- transparent 0em,
- transparent 1em,
- #026af2 1em,
- #026af2 2em,
- transparent 3em
- );
- animation: move 0.6s linear infinite;
- }
- &.l1 {
- transform: skewY(-30deg);
- transform-origin: left;
- @include getPosition(180px, 178px, 122px, 2px);
- }
- &.l2 {
- @include getPosition(402px, 92px, 86px, 2px);
- }
- &.l3 {
- @include getPosition(618px, 92px, 106px, 2px);
- }
- &.l4 {
- transform: rotate(90deg);
- transform-origin: left;
- @include getPosition(788px, 129px, 80px, 2px);
- }
- &.l5 {
- transform: skewY(30deg);
- transform-origin: left;
- @include getPosition(170px, 244px, 122px, 2px);
- }
- &.l6 {
- @include getPosition(234px, 209px, 196px, 2px);
- }
- &.l7 {
- transform: rotate(90deg);
- transform-origin: left;
- @include getPosition(428px, 209px, 95px, 2px);
- }
- &.l8 {
- @include getPosition(428px, 304px, 66px, 2px);
- }
- &.l9 {
- @include getPosition(428px, 209px, 66px, 2px);
- }
- &.l10 {
- @include getPosition(376px, 356px, 228px, 2px);
- }
- }
- </style>
|