c4e25e5bc01047ff4139216bab2f7197cc4dd1641289dc7f7542d4c389f451f8c0a9ed1fa60a0da180e467029bf47080cba2624819bc527035855f0de8485b 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. <template>
  2. <transition name="el-zoom-in-top" @after-leave="$emit('dodestroy')">
  3. <div
  4. v-show="visible"
  5. class="el-picker-panel el-date-range-picker el-popper"
  6. :class="[{
  7. 'has-sidebar': $slots.sidebar || shortcuts
  8. }, popperClass]">
  9. <div class="el-picker-panel__body-wrapper">
  10. <slot name="sidebar" class="el-picker-panel__sidebar"></slot>
  11. <div class="el-picker-panel__sidebar" v-if="shortcuts">
  12. <button
  13. type="button"
  14. class="el-picker-panel__shortcut"
  15. v-for="(shortcut, key) in shortcuts"
  16. :key="key"
  17. @click="handleShortcutClick(shortcut)">{{shortcut.text}}</button>
  18. </div>
  19. <div class="el-picker-panel__body">
  20. <div class="el-picker-panel__content el-date-range-picker__content is-left">
  21. <div class="el-date-range-picker__header">
  22. <button
  23. type="button"
  24. @click="leftPrevYear"
  25. class="el-picker-panel__icon-btn el-icon-d-arrow-left"></button>
  26. <button
  27. type="button"
  28. v-if="unlinkPanels"
  29. @click="leftNextYear"
  30. :disabled="!enableYearArrow"
  31. :class="{ 'is-disabled': !enableYearArrow }"
  32. class="el-picker-panel__icon-btn el-icon-d-arrow-right"></button>
  33. <div>{{ leftLabel }}</div>
  34. </div>
  35. <month-table
  36. selection-mode="range"
  37. :date="leftDate"
  38. :default-value="defaultValue"
  39. :min-date="minDate"
  40. :max-date="maxDate"
  41. :range-state="rangeState"
  42. :disabled-date="disabledDate"
  43. @changerange="handleChangeRange"
  44. @pick="handleRangePick">
  45. </month-table>
  46. </div>
  47. <div class="el-picker-panel__content el-date-range-picker__content is-right">
  48. <div class="el-date-range-picker__header">
  49. <button
  50. type="button"
  51. v-if="unlinkPanels"
  52. @click="rightPrevYear"
  53. :disabled="!enableYearArrow"
  54. :class="{ 'is-disabled': !enableYearArrow }"
  55. class="el-picker-panel__icon-btn el-icon-d-arrow-left"></button>
  56. <button
  57. type="button"
  58. @click="rightNextYear"
  59. class="el-picker-panel__icon-btn el-icon-d-arrow-right"></button>
  60. <div>{{ rightLabel }}</div>
  61. </div>
  62. <month-table
  63. selection-mode="range"
  64. :date="rightDate"
  65. :default-value="defaultValue"
  66. :min-date="minDate"
  67. :max-date="maxDate"
  68. :range-state="rangeState"
  69. :disabled-date="disabledDate"
  70. @changerange="handleChangeRange"
  71. @pick="handleRangePick">
  72. </month-table>
  73. </div>
  74. </div>
  75. </div>
  76. </div>
  77. </transition>
  78. </template>
  79. <script type="text/babel">
  80. import {
  81. isDate,
  82. modifyWithTimeString,
  83. prevYear,
  84. nextYear,
  85. nextMonth
  86. } from 'element-ui/src/utils/date-util';
  87. import Clickoutside from 'element-ui/src/utils/clickoutside';
  88. import Locale from 'element-ui/src/mixins/locale';
  89. import MonthTable from '../basic/month-table';
  90. import ElInput from 'element-ui/packages/input';
  91. import ElButton from 'element-ui/packages/button';
  92. const calcDefaultValue = (defaultValue) => {
  93. if (Array.isArray(defaultValue)) {
  94. return [new Date(defaultValue[0]), new Date(defaultValue[1])];
  95. } else if (defaultValue) {
  96. return [new Date(defaultValue), nextMonth(new Date(defaultValue))];
  97. } else {
  98. return [new Date(), nextMonth(new Date())];
  99. }
  100. };
  101. export default {
  102. mixins: [Locale],
  103. directives: { Clickoutside },
  104. computed: {
  105. btnDisabled() {
  106. return !(this.minDate && this.maxDate && !this.selecting && this.isValidValue([this.minDate, this.maxDate]));
  107. },
  108. leftLabel() {
  109. return this.leftDate.getFullYear() + ' ' + this.t('el.datepicker.year');
  110. },
  111. rightLabel() {
  112. return this.rightDate.getFullYear() + ' ' + this.t('el.datepicker.year');
  113. },
  114. leftYear() {
  115. return this.leftDate.getFullYear();
  116. },
  117. rightYear() {
  118. return this.rightDate.getFullYear() === this.leftDate.getFullYear() ? this.leftDate.getFullYear() + 1 : this.rightDate.getFullYear();
  119. },
  120. enableYearArrow() {
  121. return this.unlinkPanels && this.rightYear > this.leftYear + 1;
  122. }
  123. },
  124. data() {
  125. return {
  126. popperClass: '',
  127. value: [],
  128. defaultValue: null,
  129. defaultTime: null,
  130. minDate: '',
  131. maxDate: '',
  132. leftDate: new Date(),
  133. rightDate: nextYear(new Date()),
  134. rangeState: {
  135. endDate: null,
  136. selecting: false,
  137. row: null,
  138. column: null
  139. },
  140. shortcuts: '',
  141. visible: '',
  142. disabledDate: '',
  143. format: '',
  144. arrowControl: false,
  145. unlinkPanels: false
  146. };
  147. },
  148. watch: {
  149. value(newVal) {
  150. if (!newVal) {
  151. this.minDate = null;
  152. this.maxDate = null;
  153. } else if (Array.isArray(newVal)) {
  154. this.minDate = isDate(newVal[0]) ? new Date(newVal[0]) : null;
  155. this.maxDate = isDate(newVal[1]) ? new Date(newVal[1]) : null;
  156. if (this.minDate) {
  157. this.leftDate = this.minDate;
  158. if (this.unlinkPanels && this.maxDate) {
  159. const minDateYear = this.minDate.getFullYear();
  160. const maxDateYear = this.maxDate.getFullYear();
  161. this.rightDate = minDateYear === maxDateYear
  162. ? nextYear(this.maxDate)
  163. : this.maxDate;
  164. } else {
  165. this.rightDate = nextYear(this.leftDate);
  166. }
  167. } else {
  168. this.leftDate = calcDefaultValue(this.defaultValue)[0];
  169. this.rightDate = nextYear(this.leftDate);
  170. }
  171. }
  172. },
  173. defaultValue(val) {
  174. if (!Array.isArray(this.value)) {
  175. const [left, right] = calcDefaultValue(val);
  176. this.leftDate = left;
  177. this.rightDate = val && val[1] && left.getFullYear() !== right.getFullYear() && this.unlinkPanels
  178. ? right
  179. : nextYear(this.leftDate);
  180. }
  181. }
  182. },
  183. methods: {
  184. handleClear() {
  185. this.minDate = null;
  186. this.maxDate = null;
  187. this.leftDate = calcDefaultValue(this.defaultValue)[0];
  188. this.rightDate = nextYear(this.leftDate);
  189. this.$emit('pick', null);
  190. },
  191. handleChangeRange(val) {
  192. this.minDate = val.minDate;
  193. this.maxDate = val.maxDate;
  194. this.rangeState = val.rangeState;
  195. },
  196. handleRangePick(val, close = true) {
  197. const defaultTime = this.defaultTime || [];
  198. const minDate = modifyWithTimeString(val.minDate, defaultTime[0]);
  199. const maxDate = modifyWithTimeString(val.maxDate, defaultTime[1]);
  200. if (this.maxDate === maxDate && this.minDate === minDate) {
  201. return;
  202. }
  203. this.onPick && this.onPick(val);
  204. this.maxDate = maxDate;
  205. this.minDate = minDate;
  206. // workaround for https://github.com/ElemeFE/element/issues/7539, should remove this block when we don't have to care about Chromium 55 - 57
  207. setTimeout(() => {
  208. this.maxDate = maxDate;
  209. this.minDate = minDate;
  210. }, 10);
  211. if (!close) return;
  212. this.handleConfirm();
  213. },
  214. handleShortcutClick(shortcut) {
  215. if (shortcut.onClick) {
  216. shortcut.onClick(this);
  217. }
  218. },
  219. // leftPrev*, rightNext* need to take care of `unlinkPanels`
  220. leftPrevYear() {
  221. this.leftDate = prevYear(this.leftDate);
  222. if (!this.unlinkPanels) {
  223. this.rightDate = prevYear(this.rightDate);
  224. }
  225. },
  226. rightNextYear() {
  227. if (!this.unlinkPanels) {
  228. this.leftDate = nextYear(this.leftDate);
  229. }
  230. this.rightDate = nextYear(this.rightDate);
  231. },
  232. // leftNext*, rightPrev* are called when `unlinkPanels` is true
  233. leftNextYear() {
  234. this.leftDate = nextYear(this.leftDate);
  235. },
  236. rightPrevYear() {
  237. this.rightDate = prevYear(this.rightDate);
  238. },
  239. handleConfirm(visible = false) {
  240. if (this.isValidValue([this.minDate, this.maxDate])) {
  241. this.$emit('pick', [this.minDate, this.maxDate], visible);
  242. }
  243. },
  244. isValidValue(value) {
  245. return Array.isArray(value) &&
  246. value && value[0] && value[1] &&
  247. isDate(value[0]) && isDate(value[1]) &&
  248. value[0].getTime() <= value[1].getTime() && (
  249. typeof this.disabledDate === 'function'
  250. ? !this.disabledDate(value[0]) && !this.disabledDate(value[1])
  251. : true
  252. );
  253. },
  254. resetView() {
  255. // NOTE: this is a hack to reset {min, max}Date on picker open.
  256. // TODO: correct way of doing so is to refactor {min, max}Date to be dependent on value and internal selection state
  257. // an alternative would be resetView whenever picker becomes visible, should also investigate date-panel's resetView
  258. this.minDate = this.value && isDate(this.value[0]) ? new Date(this.value[0]) : null;
  259. this.maxDate = this.value && isDate(this.value[0]) ? new Date(this.value[1]) : null;
  260. }
  261. },
  262. components: { MonthTable, ElInput, ElButton }
  263. };
  264. </script>