index.vue 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. <template>
  2. <wrapper
  3. fill
  4. margin
  5. background
  6. >
  7. <div class="l-flex__none l-flex--row c-step has-padding">
  8. <button
  9. class="l-flex__none c-sibling-item o-button"
  10. :class="{ hidden: active === 0 }"
  11. @click="onPresent"
  12. >
  13. 上一步
  14. </button>
  15. <el-steps
  16. :active="active"
  17. class="l-flex__fill"
  18. finish-status="success"
  19. align-center
  20. >
  21. <el-step title="选择设备" />
  22. <el-step title="选择内容" />
  23. </el-steps>
  24. <button
  25. class="l-flex__none c-sibling-item o-button"
  26. :class="{ hidden: hideNext }"
  27. @click="onNext"
  28. >
  29. {{ btnMsg }}
  30. </button>
  31. </div>
  32. <div class="l-flex__fill l-flex">
  33. <device-group-tree
  34. v-show="active === 0"
  35. ref="tree"
  36. class="l-flex__fill has-padding"
  37. @change="onChange"
  38. />
  39. <div
  40. v-if="active > 0"
  41. class="c-list has-padding u-overflow-y--auto"
  42. >
  43. <div class="c-list__item u-bold">{{ resolutionRatio }}</div>
  44. <div
  45. v-for="device in selectedDevices"
  46. :key="device.id"
  47. class="c-list__item"
  48. >
  49. {{ device.name }}
  50. </div>
  51. </div>
  52. <div
  53. v-if="active === 1"
  54. class="c-list large has-padding u-overflow-y--auto"
  55. >
  56. <div class="c-list__item">
  57. <div class="o-type">发布类型</div>
  58. <el-select v-model="eventOptions.type">
  59. <el-option
  60. v-for="option in typeOptions"
  61. :key="option.value"
  62. :label="option.label"
  63. :value="option.value"
  64. />
  65. </el-select>
  66. </div>
  67. <event-picker
  68. v-if="isEvent"
  69. ref="picker"
  70. class="c-list__item"
  71. :priority="3"
  72. :ratio="resolutionRatio"
  73. vertical
  74. @choosen="onChoosenProgram"
  75. />
  76. <div
  77. v-else
  78. class="c-list__item c-grid-form medium col"
  79. >
  80. <div class="c-grid-form__label required">播放内容</div>
  81. <div class="o-schedule-button u-pointer">
  82. <div
  83. class="o-schedule-button__label has-padding--h"
  84. @click="onChooseSchedule"
  85. >
  86. <div class="u-ellipsis">{{ msg }}</div>
  87. </div>
  88. </div>
  89. </div>
  90. <table-dialog
  91. ref="scheduleDialog"
  92. title="排期选择"
  93. size="medium"
  94. :schema="scheduleSchema"
  95. @choosen="onChoosenSchedule"
  96. />
  97. </div>
  98. <div
  99. v-if="active > 0 && eventTarget"
  100. class="c-list fill has-padding u-overflow-y--auto"
  101. >
  102. <schedule
  103. v-if="scheduleId"
  104. :schedule="scheduleId"
  105. />
  106. <div
  107. v-if="programId"
  108. class="o-program u-pointer"
  109. @click="onViewProgram"
  110. >
  111. {{ eventTarget.name }}
  112. </div>
  113. </div>
  114. </div>
  115. </wrapper>
  116. </template>
  117. <script>
  118. import { getSchedules } from '@/api/calendar'
  119. import { publish } from '@/api/platform'
  120. import {
  121. State,
  122. ScheduleType,
  123. EventTarget,
  124. PublishType
  125. } from '@/constant'
  126. export default {
  127. name: 'ScheduleDeploy',
  128. data () {
  129. return {
  130. typeOptions: [
  131. { value: PublishType.CALENDAR, label: '排期' },
  132. { value: PublishType.EVENT, label: '插播' }
  133. ],
  134. active: 0,
  135. selectedDevices: [],
  136. eventOptions: null,
  137. scheduleSchema: {
  138. condition: { type: ScheduleType.COMPLEX, status: State.RESOLVED },
  139. list: getSchedules,
  140. cols: [{ prop: 'name', label: '名称', align: 'center' }]
  141. }
  142. }
  143. },
  144. computed: {
  145. hideNext () {
  146. switch (this.active) {
  147. case 0:
  148. return this.selectedDevices.length === 0
  149. case 1:
  150. return !this.eventTarget
  151. default:
  152. return false
  153. }
  154. },
  155. eventTarget () {
  156. if (this.isCalendar) {
  157. return this.eventOptions.schedule
  158. }
  159. return this.eventOptions.program
  160. },
  161. isCalendar () {
  162. return this.eventOptions?.type === PublishType.CALENDAR
  163. },
  164. isEvent () {
  165. return this.eventOptions?.type === PublishType.EVENT
  166. },
  167. btnMsg () {
  168. return this.active < 1 ? '下一步' : '发布'
  169. },
  170. resolutionRatio () {
  171. return this.selectedDevices[0]?.resolutionRatio
  172. },
  173. typeMsg () {
  174. return this.typeOptions[this.eventOptions?.type - 1]?.label
  175. },
  176. scheduleId () {
  177. return this.eventOptions?.type === PublishType.CALENDAR || this.eventTarget?.type === EventTarget.RECUR ? this.eventTarget.id : null
  178. },
  179. programId () {
  180. return this.eventTarget?.type === EventTarget.PROGRAM ? this.eventTarget.id : null
  181. },
  182. msg () {
  183. return this.eventTarget?.name ?? '点击选择内容'
  184. }
  185. },
  186. methods: {
  187. onPresent () {
  188. if (this.active > 0) {
  189. this.active -= 1
  190. }
  191. },
  192. onNext () {
  193. switch (this.active) {
  194. case 0:
  195. if (this.checkDevices()) {
  196. this.active += 1
  197. }
  198. break
  199. case 1:
  200. this.publish().then(() => {
  201. this.active = 0
  202. this.$refs.tree.reset()
  203. this.eventOptions = null
  204. })
  205. break
  206. default:
  207. break
  208. }
  209. },
  210. onError (message) {
  211. this.$message({
  212. type: 'warning',
  213. message
  214. })
  215. return false
  216. },
  217. onChange (devices) {
  218. this.selectedDevices = devices
  219. },
  220. checkDevices () {
  221. const devices = this.selectedDevices
  222. const length = devices.length
  223. if (!length) {
  224. return this.onError('请选择目标设备')
  225. }
  226. const resolutionRatio = this.resolutionRatio
  227. if (devices.some(device => device.resolutionRatio !== resolutionRatio)) {
  228. return this.onError('选择的设备分辨率不一致')
  229. }
  230. this.eventOptions = this.createEventOptions()
  231. return true
  232. },
  233. createEventOptions () {
  234. return {
  235. ratio: this.resolutionRatio,
  236. type: PublishType.CALENDAR,
  237. schedule: null,
  238. program: null
  239. }
  240. },
  241. onChoosenProgram (val) {
  242. this.eventOptions.program = val
  243. },
  244. onChooseSchedule () {
  245. this.$refs.scheduleDialog.show({ resolutionRatio: this.resolutionRatio })
  246. },
  247. onChoosenSchedule ({ value: { id, name }, done }) {
  248. done()
  249. this.eventOptions.schedule = { id, name }
  250. },
  251. onViewProgram () {
  252. window.open(this.$router.resolve({
  253. name: 'program',
  254. params: { id: this.programId }
  255. }).href, '_blank')
  256. },
  257. getPublishTarget () {
  258. if (this.eventOptions.type === PublishType.CALENDAR) {
  259. return Promise.resolve({
  260. type: PublishType.CALENDAR,
  261. detail: this.eventTarget.id
  262. })
  263. }
  264. const event = this.$refs.picker.getValue()
  265. if (event) {
  266. return Promise.resolve({
  267. type: PublishType.EVENT,
  268. detail: { ...event }
  269. })
  270. }
  271. return Promise.reject()
  272. },
  273. publish () {
  274. return this.getPublishTarget().then(eventTarget => {
  275. const devices = this.selectedDevices
  276. return this.$confirm(
  277. `对设备 ${devices.map(device => device.name)}`,
  278. `发布 ${this.typeMsg} ${this.eventTarget.name}`,
  279. { type: 'warning' }
  280. ).then(() => publish(
  281. devices.map(device => device.id),
  282. eventTarget,
  283. {
  284. programCalendarName: this.eventTarget.name,
  285. resolutionRatio: this.resolutionRatio
  286. }
  287. ))
  288. })
  289. }
  290. }
  291. }
  292. </script>
  293. <style lang="scss" scoped>
  294. .c-step {
  295. border-bottom: 1px solid $gray--light;
  296. .hidden {
  297. visibility: hidden;
  298. }
  299. }
  300. .c-list {
  301. flex: 0 0 200px;
  302. min-width: 200px;
  303. padding-right: $spacing;
  304. color: $black;
  305. & + & {
  306. border-left: 1px solid $gray--light;
  307. }
  308. &.large {
  309. min-width: 336px;
  310. max-width: 336px;
  311. }
  312. &.fill {
  313. flex: 1 0 200px;
  314. }
  315. &__item {
  316. line-height: 1;
  317. & + & {
  318. margin-top: 8px;
  319. }
  320. &:nth-child(2) {
  321. margin-top: 10px;
  322. }
  323. }
  324. }
  325. .o-type {
  326. margin-bottom: 8px;
  327. font-size: 14px;
  328. font-weight: bold;
  329. line-height: 1;
  330. }
  331. .o-schedule-button {
  332. position: relative;
  333. width: 217px;
  334. height: 40px;
  335. color: $blue;
  336. font-size: 14px;
  337. line-height: 1;
  338. border-radius: $radius--mini;
  339. border: 1px solid #dcdfe6;
  340. &:hover {
  341. border-color: #c0c4cc;
  342. }
  343. &__label {
  344. display: inline-flex;
  345. justify-content: center;
  346. align-items: center;
  347. position: absolute;
  348. width: 100%;
  349. height: 100%;
  350. }
  351. }
  352. .o-program {
  353. font-size: 24px;
  354. font-weight: bold;
  355. &:hover {
  356. color: #409eff;
  357. }
  358. }
  359. </style>