| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437 |
- <template>
- <div class="l-flex__fill l-flex">
- <div class="l-flex__none c-takeover-debug u-overflow-y--auto">
- <div
- v-for="message in messages"
- :key="message.id"
- >
- {{ message.info }}
- </div>
- </div>
- <div
- v-loading="loading"
- class="l-flex__fill l-flex--col"
- >
- <div
- v-if="!loading && !valid"
- class="l-flex--col center"
- >
- <button
- v-if="online"
- class="o-button"
- @click="createClient"
- >
- 连接设备
- </button>
- <div
- v-else
- class="u-color--info"
- >
- 设备未上线
- </div>
- </div>
- <template v-if="valid">
- <div class="l-flex--row c-sibling-item--v">
- <button
- class="c-sibling-item o-button"
- @click="onAddAsset"
- >
- <i class="o-button__icon el-icon-circle-plus-outline" />
- 缓存资源
- </button>
- <button
- class="c-sibling-item o-button"
- @click="onAddWeb"
- >
- <i class="o-button__icon el-icon-circle-plus-outline" />
- 缓存网页
- </button>
- </div>
- <el-tabs
- v-model="active"
- class="c-sibling-item--v c-tabs has-bottom-padding"
- >
- <el-tab-pane
- name="loaded"
- label="已下载"
- />
- <el-tab-pane
- label="下载中"
- name="loading"
- />
- <el-tab-pane
- label="异常"
- name="error"
- />
- </el-tabs>
- <div class="l-flex__fill l-grid--info mini u-overflow-y--auto">
- <asset-card
- v-for="asset in list"
- :key="asset.keyName"
- :asset="asset"
- @play="onPlay"
- @reload="onReload"
- @del="onDel"
- />
- </div>
- <confirm-dialog
- ref="assetsDialog"
- title="资源列表"
- size="lg fixed"
- append-to-body
- @confirm="onSaveAssets"
- >
- <div class="l-flex__fill l-flex">
- <directory-tree
- class="c-sibling-item c-sidebar u-width--md"
- @change="onAssetDirectoryChanged"
- />
- <grid-table
- ref="gridTable"
- :schema="assetSchema"
- >
- <grid-table-item v-slot="item">
- <media-card
- class="o-card"
- :asset="item"
- @click="onToggleGrid"
- >
- <el-checkbox
- v-model="item.selected"
- class="o-card__checkbox"
- />
- <i
- class="o-card__icon el-icon-video-play has-active"
- @click.stop="onView(item)"
- />
- </media-card>
- </grid-table-item>
- </grid-table>
- </div>
- </confirm-dialog>
- <confirm-dialog
- ref="webDialog"
- title="网页配置"
- @confirm="onSaveWeb"
- >
- <div class="c-grid-form sm u-align-self--center">
- <span class="c-grid-form__label u-required">名称:</span>
- <el-input
- v-model.trim="web.name"
- clearable
- />
- <span class="c-grid-form__label u-required">网址:</span>
- <el-input
- v-model.trim="web.keyName"
- clearable
- />
- </div>
- </confirm-dialog>
- <preview-dialog ref="previewDialog" />
- </template>
- </div>
- </div>
- </template>
- <script>
- import {
- State,
- AssetType,
- AssetTypeInfo,
- AssetTag,
- AssetTagInfo
- } from '@/constant'
- import { getAssetsByQuery } from '@/api/asset'
- import {
- Topic,
- MediaType,
- MediaStatus,
- takeOver
- } from './takeover'
- import AssetCard from './components/AssetCard'
- export default {
- name: 'DeviceTakeOver',
- components: {
- AssetCard
- },
- props: {
- device: {
- type: Object,
- required: true
- },
- online: {
- type: [Boolean, String],
- default: false
- }
- },
- data () {
- return {
- loading: true,
- valid: false,
- messages: [],
- active: 'loaded',
- assets: [],
- sources: [],
- assetSchema: {
- list: this.getAssetsByQuery,
- transform: this.transformAsset,
- condition: { pageSize: 16, status: State.AVAILABLE, tag: AssetTag.AD, type: AssetType.IMAGE },
- filters: [
- { key: 'tag', type: 'select', options: [
- { value: AssetTag.AD, label: AssetTagInfo[AssetTag.AD] },
- { value: AssetTag.PUBLICITY, label: AssetTagInfo[AssetTag.PUBLICITY] },
- { value: AssetTag.LOCAL_PUBLICITY, label: AssetTagInfo[AssetTag.LOCAL_PUBLICITY] },
- { value: AssetTag.SHIM, label: AssetTagInfo[AssetTag.SHIM] }
- ] },
- { key: 'type', type: 'select', options: [
- { value: AssetType.IMAGE, label: AssetTypeInfo[AssetType.IMAGE] },
- { value: AssetType.VIDEO, label: AssetTypeInfo[AssetType.VIDEO] }
- ] },
- { key: 'originalName', type: 'search', placeholder: '资源名称' }
- ]
- },
- web: {}
- }
- },
- computed: {
- list () {
- switch (this.active) {
- case 'loaded':
- return this.assets.filter(({ status }) => status === MediaStatus.LOADED)
- case 'loading':
- return this.assets.filter(({ status }) => status === MediaStatus.WAITING || status === MediaStatus.LOADING)
- case 'error':
- return this.assets.filter(({ status }) => status === MediaStatus.ERROR)
- default:
- return this.assets
- }
- }
- },
- watch: {
- online: {
- handler (val) {
- if (val) {
- this.createClient()
- } else {
- this.destroyClient()
- }
- },
- immediate: true
- }
- },
- beforeDestroy () {
- this.destroyClient()
- },
- methods: {
- onAssetDirectoryChanged (directory) {
- this.$directoryOption = directory
- this.$refs.table?.getTable.pageTo(1)
- },
- getAssetsByQuery (params) {
- if (!this.$directoryOption) {
- return Promise.resolve({ data: [] })
- }
- const { root, id, group: { path } } = this.$directoryOption
- return getAssetsByQuery({
- ...params,
- ...(root
- ? { org: path }
- : { treeId: id, queryRelation: '1' })
- })
- },
- destroyClient () {
- this.loading = false
- if (this.valid) {
- this.$clientProxy.close()
- } else {
- this.$client?.end(true)
- }
- },
- onMessage (topic, payload, requestPayload) {
- switch (topic) {
- case Topic.PRELOAD:
- this.onReloadReply(requestPayload.assets)
- break
- case Topic.DEL:
- this.onDelReply(requestPayload.assets)
- break
- case Topic.PULL:
- this.onRefresh(payload.assets)
- break
- case Topic.DOWNLOAD:
- this.onDownload(payload)
- break
- default:
- break
- }
- },
- onCreated (proxy) {
- this.valid = true
- this.$client = null
- this.$clientProxy = proxy
- this.$clientProxy.pull()
- },
- onClose () {
- this.valid = false
- this.loading = false
- this.$client = null
- this.$clientProxy = null
- },
- onDebug (message) {
- this.messages.unshift({
- id: `${Date.now()}_${Math.random().toString().slice(2)}`,
- info: message
- })
- },
- createClient () {
- this.loading = true
- this.$client = takeOver(this.device, {
- onMessage: this.onMessage,
- onCreated: this.onCreated,
- onClose: this.onClose,
- debug: this.onDebug
- })
- },
- onRefresh (assets) {
- this.loading = false
- this.assets = assets
- },
- onPlay ({ type, name, keyName }) {
- this.$clientProxy.play({ type, name, keyName })
- },
- transformAsset ({ type, originalName, keyName, file, size, md5 }) {
- return {
- selected: false,
- type,
- name: originalName,
- keyName,
- size,
- md5,
- file
- }
- },
- onAddAsset () {
- this.$refs.assetsDialog.show()
- },
- onToggleGrid (asset) {
- asset.selected = !asset.selected
- },
- onSaveAssets (done) {
- const assets = this.$refs.gridTable.getData().filter(({ selected }) => selected).map(({ type, name, keyName, size, md5, file }) => {
- return {
- type, name, keyName, size, md5,
- thumb: file.thumb
- }
- })
- if (assets.length) {
- this.sources = this.sources.concat(assets)
- this.$clientProxy.preload(assets)
- }
- done()
- },
- onView ({ type, keyName }) {
- this.$refs.previewDialog.show({ type, url: keyName })
- },
- onAddWeb () {
- this.web = {
- name: '',
- keyName: ''
- }
- this.$refs.webDialog.show()
- },
- onSaveWeb (done) {
- const { name, keyName } = this.web
- if (!name) {
- this.$message({
- type: 'warning',
- message: '名称不能为空'
- })
- return
- }
- if (!keyName) {
- this.$message({
- type: 'warning',
- message: '网址不能为空'
- })
- return
- }
- this.$clientProxy.preload([{ type: MediaType.WEB, name, keyName }])
- done()
- },
- onReload (asset) {
- const { status, ...data } = asset
- this.$clientProxy.preload([data])
- },
- onReloadReply (assets) {
- assets.forEach(asset => {
- const targetKeyName = asset.keyName
- const index = this.assets.findIndex(({ keyName }) => targetKeyName === keyName)
- if (~index) {
- this.assets[index].status = MediaStatus.WAITING
- } else {
- this.assets.push({
- status: asset.type === MediaType.WEB ? MediaStatus.LOADED : MediaStatus.WAITING,
- ...asset
- })
- }
- })
- },
- onDel ({ name, keyName }) {
- this.onDebug(`删除${name}`)
- this.$clientProxy.del([keyName])
- },
- onDelReply (assets) {
- assets.forEach(keyName => {
- const index = this.assets.findIndex(asset => asset.keyName === keyName)
- if (~index) {
- this.assets.splice(index, 1)
- }
- })
- },
- onDownload ({ success, asset: { keyName } }) {
- const index = this.assets.findIndex(asset => asset.keyName === keyName)
- if (~index) {
- this.assets[index].status = success ? MediaStatus.LOADED : MediaStatus.ERROR
- } else if (!this.loading) {
- this.loading = true
- this.$clientProxy.pull()
- }
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .c-takeover-debug {
- width: 200px;
- padding-right: $spacing;
- margin-right: $spacing;
- color: $black;
- font-size: 14px;
- line-height: 24px;
- word-break: break-word;
- border-right: 1px solid $border;
- }
- .o-card {
- &__checkbox {
- position: absolute;
- top: 10px;
- left: 10px;
- pointer-events: none;
- z-index: 9;
- }
- &__icon {
- position: absolute;
- top: 50%;
- left: 50%;
- padding: 2px;
- font-size: 24px;
- border-radius: 50%;
- background-color: rgba(#000, 0.4);
- transform: translate(-50%, -50%);
- }
- }
- </style>
|