|
|
@@ -0,0 +1,286 @@
|
|
|
+<template>
|
|
|
+ <div class="l-flex__auto l-flex--col">
|
|
|
+ <div class="l-flex__none l-flex--row c-step has-padding">
|
|
|
+ <button
|
|
|
+ class="l-flex__none c-sibling-item o-button"
|
|
|
+ :class="{ hidden: active === 0 }"
|
|
|
+ @click="onPresent"
|
|
|
+ >
|
|
|
+ 上一步
|
|
|
+ </button>
|
|
|
+ <el-steps
|
|
|
+ :active="active"
|
|
|
+ class="l-flex__fill"
|
|
|
+ finish-status="success"
|
|
|
+ align-center
|
|
|
+ >
|
|
|
+ <el-step title="选择模板" />
|
|
|
+ <el-step title="选择设备" />
|
|
|
+ <el-step title="信息确认" />
|
|
|
+ </el-steps>
|
|
|
+ <button
|
|
|
+ class="l-flex__none c-sibling-item o-button"
|
|
|
+ :class="{ hidden: hideNext }"
|
|
|
+ @click="onNext"
|
|
|
+ >
|
|
|
+ {{ btnMsg }}
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ <div class="l-flex__auto l-flex--col has-padding">
|
|
|
+ <div
|
|
|
+ v-show="active === 0"
|
|
|
+ class="c-grid-form u-align-self--center"
|
|
|
+ >
|
|
|
+ <span class="c-grid-form__label required">位置</span>
|
|
|
+ <el-select v-model="position">
|
|
|
+ <el-option
|
|
|
+ v-for="option in positionOptions"
|
|
|
+ :key="option.value"
|
|
|
+ :label="option.label"
|
|
|
+ :value="option.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ <span class="c-grid-form__label required">模板</span>
|
|
|
+ <schema-select
|
|
|
+ v-model="templateId"
|
|
|
+ :schema="templateSelectSchema"
|
|
|
+ placeholder="请选择"
|
|
|
+ @change="onTemplateChange"
|
|
|
+ />
|
|
|
+ <div
|
|
|
+ v-if="templateId && !templateContent"
|
|
|
+ class="c-grid-form__row u-text-center"
|
|
|
+ >
|
|
|
+ <i class="el-icon-loading" />
|
|
|
+ </div>
|
|
|
+ <template v-if="templateContent">
|
|
|
+ <span class="c-grid-form__label">失效时间</span>
|
|
|
+ <el-date-picker
|
|
|
+ v-model="endDateTime"
|
|
|
+ type="datetime"
|
|
|
+ placeholder="请选择失效时间"
|
|
|
+ value-format="yyyy-MM-dd HH:mm:ss"
|
|
|
+ :picker-options="endDatePickerOptions"
|
|
|
+ @change="onEndDateTimeChange"
|
|
|
+ />
|
|
|
+ <span class="c-grid-form__label">内容</span>
|
|
|
+ <div class="l-flex--row c-grid-form__option c-grid-form__text">{{ templateContent }}</div>
|
|
|
+ <div
|
|
|
+ v-for="(value, key) in keywordMap"
|
|
|
+ :key="key"
|
|
|
+ class="c-grid-form__row"
|
|
|
+ >
|
|
|
+ <span class="c-grid-form__label required c-grid-form__text">{{ value.keywordName }}</span>
|
|
|
+ <el-input
|
|
|
+ v-model.trim="value.content"
|
|
|
+ placeholder="最多50个字符"
|
|
|
+ maxlength="50"
|
|
|
+ clearable
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ <device-group-tree
|
|
|
+ v-show="active === 1"
|
|
|
+ ref="tree"
|
|
|
+ class="l-flex__fill has-padding"
|
|
|
+ @change="onChange"
|
|
|
+ />
|
|
|
+ <div
|
|
|
+ v-if="active === 2"
|
|
|
+ class="c-grid-form u-align-self--center"
|
|
|
+ >
|
|
|
+ <span class="c-grid-form__label">位置:</span>
|
|
|
+ <div class="l-flex--row c-grid-form__option c-grid-form__text">{{ positionDesc }}</div>
|
|
|
+ <span class="c-grid-form__label">内容:</span>
|
|
|
+ <div class="l-flex--row c-grid-form__option c-grid-form__text">{{ targetContent }}</div>
|
|
|
+ <span class="c-grid-form__label">目标设备:</span>
|
|
|
+ <div class="l-flex--row c-grid-form__option c-grid-form__text">{{ selectedDeviceName }}</div>
|
|
|
+ <span class="c-grid-form__label">失效时间:</span>
|
|
|
+ <div class="l-flex--row c-grid-form__option c-grid-form__text">{{ endDateTime || '不限定' }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { parseTime } from '@/utils'
|
|
|
+import {
|
|
|
+ getBroadcastTemplates,
|
|
|
+ getBroadcastTemplate,
|
|
|
+ publishBroadcast
|
|
|
+} from '@/api/broadcast'
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'BrodcastDeployPanel',
|
|
|
+ props: {
|
|
|
+ tenant: {
|
|
|
+ type: String,
|
|
|
+ default: ''
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data () {
|
|
|
+ return {
|
|
|
+ active: 0,
|
|
|
+ position: 1,
|
|
|
+ positionOptions: [
|
|
|
+ { label: '屏幕顶部', value: 0 },
|
|
|
+ { label: '屏幕底部', value: 1 }
|
|
|
+ ],
|
|
|
+ templateSelectSchema: {
|
|
|
+ remote: getBroadcastTemplates,
|
|
|
+ pagination: true,
|
|
|
+ value: 'templateId',
|
|
|
+ label: 'templateName'
|
|
|
+ },
|
|
|
+ templateId: '',
|
|
|
+ templateContent: '',
|
|
|
+ targetContent: '',
|
|
|
+ endDateTime: '',
|
|
|
+ keywordMap: [],
|
|
|
+ selectedDevices: []
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ minDate () {
|
|
|
+ const now = new Date()
|
|
|
+ return new Date(now.getFullYear(), now.getMonth(), now.getDate())
|
|
|
+ },
|
|
|
+ endDatePickerOptions () {
|
|
|
+ return {
|
|
|
+ disabledDate: this.isDisableDate
|
|
|
+ }
|
|
|
+ },
|
|
|
+ hideNext () {
|
|
|
+ switch (this.active) {
|
|
|
+ case 0:
|
|
|
+ return !this.templateContent || this.keywordMap.some(({ content }) => !content)
|
|
|
+ case 1:
|
|
|
+ return this.selectedDevices.length === 0
|
|
|
+ default:
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ btnMsg () {
|
|
|
+ return this.active < 2 ? '下一步' : '发布'
|
|
|
+ },
|
|
|
+ positionDesc () {
|
|
|
+ return this.positionOptions[this.position].label
|
|
|
+ },
|
|
|
+ selectedDeviceName () {
|
|
|
+ return this.selectedDevices.map(device => device.name).join(', ')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ onEndDateTimeChange () {
|
|
|
+ if (this.endDateTime && new Date(this.endDateTime).getTime() < Date.now()) {
|
|
|
+ this.endDateTime = parseTime(Date.now(), '{y}-{m}-{d} {h}:{i}:{s}')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ isDisableDate (date) {
|
|
|
+ return date < this.minDate
|
|
|
+ },
|
|
|
+ onTemplateChange (templateId) {
|
|
|
+ this.templateContent = ''
|
|
|
+ this.keywordMap = []
|
|
|
+ getBroadcastTemplate(templateId).then(({ data }) => {
|
|
|
+ const { templateName, templateContent, keywordMap, optionalNumbers } = data
|
|
|
+ const arr = []
|
|
|
+ let content = templateContent
|
|
|
+ for (let i = 0; i < optionalNumbers; i++) {
|
|
|
+ content = content.replace(new RegExp(`\\{${i}\\}`, 'g'), `{${keywordMap[i].keywordName}}`)
|
|
|
+ arr.push({
|
|
|
+ ...keywordMap[i],
|
|
|
+ content: ''
|
|
|
+ })
|
|
|
+ }
|
|
|
+ this.templateContent = content
|
|
|
+ this.$templateData = {
|
|
|
+ templateName,
|
|
|
+ templateContent,
|
|
|
+ optionalNumbers
|
|
|
+ }
|
|
|
+ this.keywordMap = arr
|
|
|
+ })
|
|
|
+ },
|
|
|
+ onPresent () {
|
|
|
+ if (this.active > 0) {
|
|
|
+ this.active -= 1
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onNext () {
|
|
|
+ switch (this.active) {
|
|
|
+ case 0:
|
|
|
+ this.active += 1
|
|
|
+ break
|
|
|
+ case 1:
|
|
|
+ this.collectInfo()
|
|
|
+ this.active += 1
|
|
|
+ break
|
|
|
+ case 2:
|
|
|
+ this.publish().then(() => {
|
|
|
+ this.active = 0
|
|
|
+ this.position = 1
|
|
|
+ this.templateId = ''
|
|
|
+ this.templateContent = ''
|
|
|
+ this.keywordMap = []
|
|
|
+ this.endDateTime = ''
|
|
|
+ this.$refs.tree.reset()
|
|
|
+ })
|
|
|
+ break
|
|
|
+ default:
|
|
|
+ break
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onChange (devices) {
|
|
|
+ this.selectedDevices = devices
|
|
|
+ },
|
|
|
+ collectInfo () {
|
|
|
+ const { templateContent, optionalNumbers } = this.$templateData
|
|
|
+ let content = templateContent
|
|
|
+ for (let i = 0; i < optionalNumbers; i++) {
|
|
|
+ content = content.replace(new RegExp(`\\{${i}\\}`, 'g'), this.keywordMap[i].content)
|
|
|
+ }
|
|
|
+ this.targetContent = content
|
|
|
+ },
|
|
|
+ publish () {
|
|
|
+ if (this.endDateTime && new Date(this.endDateTime).getTime() < Date.now()) {
|
|
|
+ this.$message({
|
|
|
+ type: 'warning',
|
|
|
+ message: '失效时间已过期'
|
|
|
+ })
|
|
|
+ return Promise.reject()
|
|
|
+ }
|
|
|
+ return this.$confirm(
|
|
|
+ `立即发布?`,
|
|
|
+ { type: 'warning' }
|
|
|
+ ).then(() => {
|
|
|
+ const keywordMap = {}
|
|
|
+ this.keywordMap.forEach(({ content }, key) => {
|
|
|
+ keywordMap[key] = { content }
|
|
|
+ })
|
|
|
+ return publishBroadcast({
|
|
|
+ tenant: this.tenant,
|
|
|
+ position: this.position,
|
|
|
+ name: this.$templateData.templateName,
|
|
|
+ templateId: this.templateId,
|
|
|
+ keywordMap,
|
|
|
+ startTime: parseTime(Date.now(), '{y}-{m}-{d} {h}:{i}:{s}'),
|
|
|
+ endTime: this.endDateTime,
|
|
|
+ deviceIds: this.selectedDevices.map(device => device.id)
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.c-step {
|
|
|
+ border-bottom: 1px solid $gray--light;
|
|
|
+
|
|
|
+ .hidden {
|
|
|
+ visibility: hidden;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|