EventPicker.vue 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. <template>
  2. <div class="l-flex c-step">
  3. <div class="l-flex__none c-step__column large">
  4. <div>
  5. <slot />
  6. <div class="c-sibling-item--v u-font-size--sm">上播方式</div>
  7. <el-select
  8. v-model="eventOptions.freq"
  9. class="c-sibling-item--v near"
  10. >
  11. <el-option
  12. v-for="option in freqOptions"
  13. :key="option.value"
  14. :label="option.label"
  15. :value="option.value"
  16. />
  17. </el-select>
  18. <template v-if="isOnce">
  19. <div class="c-sibling-item--v u-font-size--sm u-required">开始时间</div>
  20. <el-date-picker
  21. v-model="eventOptions.start"
  22. class="c-sibling-item--v near"
  23. type="datetime"
  24. placeholder="请选择开始时间"
  25. value-format="yyyy-MM-dd HH:mm:ss"
  26. :picker-options="pickerOptions"
  27. @change="onDateTimeChange('start')"
  28. />
  29. <div class="c-sibling-item--v u-font-size--sm u-required">结束时间</div>
  30. <el-date-picker
  31. v-model="eventOptions.until"
  32. class="c-sibling-item--v near"
  33. type="datetime"
  34. popper-class="is-hide-now"
  35. :disabled="!eventOptions.start"
  36. placeholder="请选择结束时间"
  37. :default-value="defaultEndDateTime"
  38. value-format="yyyy-MM-dd HH:mm:ss"
  39. :picker-options="endPickerOptions"
  40. @change="onDateTimeChange('until')"
  41. />
  42. </template>
  43. <template v-if="isWeekly">
  44. <div class="c-sibling-item--v u-font-size--sm u-required">每周</div>
  45. <el-checkbox-group
  46. v-model="eventOptions.byDay"
  47. class="l-flex--row c-sibling-item--v near"
  48. size="mini"
  49. fill="#1c5cb0"
  50. >
  51. <el-checkbox-button
  52. v-for="week in weeks"
  53. :key="week.value"
  54. :label="week.value"
  55. >
  56. {{ week.label }}
  57. </el-checkbox-button>
  58. </el-checkbox-group>
  59. <div class="c-sibling-item--v u-font-size--sm u-required">开始时间</div>
  60. <el-time-picker
  61. v-model="eventOptions.startTime"
  62. class="c-sibling-item--v near"
  63. placeholder="请选择开始时间"
  64. value-format="HH:mm:ss"
  65. :clearable="false"
  66. />
  67. <div class="c-sibling-item--v u-font-size--sm u-required">结束时间</div>
  68. <el-time-picker
  69. v-model="eventOptions.endTime"
  70. class="c-sibling-item--v near has-info"
  71. data-info="结束时间小于等于开始时间为跨天播放"
  72. placeholder="请选择结束时间"
  73. value-format="HH:mm:ss"
  74. :clearable="false"
  75. />
  76. <div class="c-sibling-item--v u-font-size--sm u-required">生效日期</div>
  77. <el-date-picker
  78. v-model="eventOptions.start"
  79. class="c-sibling-item--v near"
  80. type="date"
  81. placeholder="请选择生效日期"
  82. value-format="yyyy-MM-dd HH:mm:ss"
  83. :picker-options="pickerOptions"
  84. @change="onDateTimeChange('start')"
  85. />
  86. <div class="c-sibling-item--v u-font-size--sm u-required">失效日期</div>
  87. <el-date-picker
  88. v-model="eventOptions.until"
  89. class="c-sibling-item--v near has-info"
  90. data-info="失效日期当天不执行"
  91. type="date"
  92. :disabled="!eventOptions.start"
  93. placeholder="请选择失效日期"
  94. value-format="yyyy-MM-dd HH:mm:ss"
  95. :picker-options="endPickerOptions"
  96. @change="onDateTimeChange('until')"
  97. />
  98. </template>
  99. </div>
  100. </div>
  101. <event-target-picker
  102. ref="eventTargetPicker"
  103. :event-target="eventTarget"
  104. class="l-flex__fill c-step__column"
  105. v-bind="$attrs"
  106. />
  107. </div>
  108. </template>
  109. <script>
  110. import {
  111. ONE_DAY,
  112. EventPriority,
  113. EventFrequency
  114. } from '@/constant'
  115. import {
  116. isMoreThanOneWeek,
  117. getNearestHitDate,
  118. isOverDay,
  119. toDateStr
  120. } from '@/utils/event'
  121. export default {
  122. name: 'EventPicker',
  123. props: {
  124. event: {
  125. type: Object,
  126. default: null
  127. },
  128. priority: {
  129. type: Number,
  130. default: EventPriority.SCHEDULING
  131. }
  132. },
  133. data () {
  134. return {
  135. weeks: [
  136. { value: '0', label: '日' },
  137. { value: '1', label: '一' },
  138. { value: '2', label: '二' },
  139. { value: '3', label: '三' },
  140. { value: '4', label: '四' },
  141. { value: '5', label: '五' },
  142. { value: '6', label: '六' }
  143. ],
  144. freqOptions: [
  145. { value: EventFrequency.ONCE, label: '时段播放' },
  146. { value: EventFrequency.WEEKLY, label: '周期播放' }
  147. ],
  148. eventOptions: null
  149. }
  150. },
  151. computed: {
  152. isOnce () {
  153. return this.eventOptions.freq === EventFrequency.ONCE
  154. },
  155. isWeekly () {
  156. return this.eventOptions.freq === EventFrequency.WEEKLY
  157. },
  158. pickerOptions () {
  159. return {
  160. disabledDate: this.isDisableDate
  161. }
  162. },
  163. endPickerOptions () {
  164. return {
  165. disabledDate: this.isDisableEndDate
  166. }
  167. },
  168. defaultEndDateTime () {
  169. if (this.eventOptions.start) {
  170. const date = new Date(this.eventOptions.start)
  171. date.setDate(date.getDate() + 1)
  172. return `${toDateStr(date)} 00:00:00`
  173. }
  174. return null
  175. }
  176. },
  177. watch: {
  178. event: {
  179. handler () {
  180. this.init()
  181. },
  182. immediate: true
  183. }
  184. },
  185. methods: {
  186. isDisableDate (date) {
  187. return date <= Date.now() - ONE_DAY
  188. },
  189. isDisableEndDate (date) {
  190. if (date <= Date.now() - ONE_DAY) {
  191. return true
  192. }
  193. const startDate = this.eventOptions.start
  194. if (startDate) {
  195. if (this.isWeekly) {
  196. return date <= new Date(startDate)
  197. }
  198. return date < new Date(startDate.replace(/\d{2}:\d{2}:\d{2}$/, '00:00:00'))
  199. }
  200. return false
  201. },
  202. init () {
  203. const { freq, byDay, target, ...options } = {
  204. freq: EventFrequency.ONCE,
  205. start: null,
  206. until: null,
  207. startTime: '00:00:00',
  208. endTime: '00:00:00',
  209. ...this.event
  210. }
  211. this.eventOptions = {
  212. ...options,
  213. freq,
  214. byDay: byDay ? byDay.split(',') : []
  215. }
  216. this.eventTarget = target || {}
  217. },
  218. onDateTimeChange (type) {
  219. const { start, until } = this.eventOptions
  220. if (start && until && start > until) {
  221. if (type === 'start') {
  222. this.eventOptions.until = start
  223. } else {
  224. this.eventOptions.start = until
  225. }
  226. }
  227. },
  228. onError (message) {
  229. this.$message({
  230. type: 'warning',
  231. message
  232. })
  233. return null
  234. },
  235. createWeeklyEvent () {
  236. const { start, until, byDay, startTime, endTime } = this.eventOptions
  237. if (byDay.length === 7 && startTime === endTime) {
  238. return {
  239. priority: this.priority,
  240. freq: EventFrequency.ONCE,
  241. start: start.replace(/\d{2}:\d{2}:\d{2}$/, startTime),
  242. until: until.replace(/\d{2}:\d{2}:\d{2}$/, startTime)
  243. }
  244. }
  245. const byDayValue = byDay.join(',')
  246. const isOver = isOverDay({ startTime, endTime })
  247. const startWeek = new Date(start).getDay()
  248. const startDate = start.replace(/\d{2}:\d{2}:\d{2}$/, byDayValue.includes(startWeek) || isOver && byDayValue.includes((startWeek + 6) % 7) ? startTime : '00:00:00')
  249. const untilDate = until && until.replace(/\d{2}:\d{2}:\d{2}$/, isOver && byDayValue.includes((new Date(until).getDay() + 6) % 7) ? endTime : '00:00:00')
  250. const event = {
  251. priority: this.priority,
  252. freq: EventFrequency.WEEKLY,
  253. start: startDate,
  254. until: untilDate,
  255. byDay: byDayValue,
  256. startTime,
  257. endTime
  258. }
  259. if (untilDate && !isMoreThanOneWeek(new Date(untilDate) - new Date(startDate)) && !getNearestHitDate(event, startDate, untilDate)) {
  260. return this.onError('有效日期内无法触发')
  261. }
  262. return event
  263. },
  264. createOnceEvent () {
  265. const { start, until } = this.eventOptions
  266. return {
  267. priority: this.priority,
  268. freq: EventFrequency.ONCE,
  269. start, until
  270. }
  271. },
  272. createEvent () {
  273. if (this.isWeekly) {
  274. return this.createWeeklyEvent()
  275. }
  276. return this.createOnceEvent()
  277. },
  278. getValue () {
  279. const { start, until } = this.eventOptions
  280. if (this.isOnce) {
  281. if (!start) {
  282. return this.onError('请选择开始时间')
  283. }
  284. if (!until) {
  285. return this.onError('请选择结束时间')
  286. }
  287. if (start === until) {
  288. return this.onError('开始时间与结束时间不能一样')
  289. }
  290. }
  291. if (this.isWeekly) {
  292. const { byDay, startTime, endTime } = this.eventOptions
  293. if (!byDay.length) {
  294. return this.onError('请选择生效星期')
  295. }
  296. if (!startTime) {
  297. return this.onError('请选择开始时间')
  298. }
  299. if (!endTime) {
  300. return this.onError('请选择结束时间')
  301. }
  302. if (!start) {
  303. return this.onError('请选择生效日期')
  304. }
  305. if (!until) {
  306. return this.onError('请选择失效日期')
  307. }
  308. if (start.split(' ')[0] === until.split(' ')[0]) {
  309. return this.onError('生效日期与失效日期不能一样')
  310. }
  311. }
  312. if (until && new Date(until).getTime() <= Date.now()) {
  313. return this.onError('结束时间小于当前时间,请配置有效的生效时间')
  314. }
  315. const target = this.$refs.eventTargetPicker.getValue()
  316. if (!target) {
  317. return null
  318. }
  319. return {
  320. ...this.createEvent(),
  321. target
  322. }
  323. },
  324. getEventTargetPicker () {
  325. return this.$refs.eventTargetPicker
  326. }
  327. }
  328. }
  329. </script>