index.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. <template>
  2. <div class="date-range">
  3. <!--<year-range-panel />-->
  4. <el-select v-model="dateType" :size="size"
  5. style="max-width: 100px; min-width: 100px; margin-right: 10px;"
  6. v-if="!hideTypeOnlyOne || validTypeList.length > 1">
  7. <el-option v-for="type in validTypeList" :key="type.value" :value="type.value" :label="type.label" />
  8. </el-select>
  9. <el-date-picker style="flex-grow: 1;" v-model="currentDates"
  10. :size="size" :placeholder="placeholder" :type="innerDateType"
  11. :disabled="disabled" :format="innerDateFormat" :readonly="readonly" :editable="editable"
  12. :clearable="clearable" :start-placeholder="startPlaceholder" :end-placeholder="endPlaceholder"
  13. :align="align" :range-separator="rangeSeparator" :value-format="valueFormat"
  14. :prefix-icon="prefixIcon" :clear-icon="clearIcon" @change="onValueChange" />
  15. </div>
  16. </template>
  17. <script>
  18. import { formatDate, parseDate } from 'element-ui/src/utils/date-util';
  19. const allTypeList = [{
  20. value: 'day',
  21. label: '自然日'
  22. }, {
  23. value: 'month',
  24. label: '自然月'
  25. }, {
  26. value: 'year',
  27. label: '自然年'
  28. }];
  29. export default {
  30. name: 'DateRange',
  31. props: {
  32. /**
  33. * 绑定的数据
  34. */
  35. value: {
  36. type: [Array],
  37. default: () => {
  38. return []
  39. }
  40. },
  41. /**
  42. * 默认显示的数据选择方式,如果不存在与allowTypes中则显示allowTypes中的第一个
  43. */
  44. defaultDateType: {
  45. type: String,
  46. default: 'day'
  47. },
  48. /**
  49. * 组件大小(medium / small / mini)
  50. */
  51. size: {
  52. type: String
  53. },
  54. /**
  55. * 数据选择方式只有一个的时候是否隐藏数据选择方式下拉
  56. */
  57. hideTypeOnlyOne: {
  58. type: Boolean,
  59. default: true
  60. },
  61. /**
  62. * 允许的数据选择方式(day, month, year)
  63. * 默认值['day', 'month', 'year']
  64. */
  65. allowTypes: {
  66. type: Array,
  67. default: () => {
  68. return allTypeList.map((item) => {
  69. return item.value;
  70. });
  71. }
  72. },
  73. /**
  74. * 是否范围选择
  75. */
  76. isRange: {
  77. type: Boolean,
  78. default: true
  79. },
  80. /**
  81. * 输出字符串的format
  82. */
  83. outputFormat: {
  84. type: String,
  85. default: 'yyyy-MM-dd HH:mm:ss'
  86. },
  87. /**
  88. * 非范围选择时的占位内容
  89. */
  90. placeholder: String,
  91. /**
  92. * 范围选择时开始日期的占位内容
  93. */
  94. startPlaceholder: String,
  95. /**
  96. * 范围选择时结束日期的占位内容
  97. */
  98. endPlaceholder: String,
  99. /**
  100. * 完全只读
  101. */
  102. readonly: Boolean,
  103. /**
  104. * 禁用
  105. */
  106. disabled: Boolean,
  107. /**
  108. * 文本框可输入
  109. */
  110. editable: {
  111. type: Boolean,
  112. default: true
  113. },
  114. /**
  115. * 是否显示清除按钮
  116. */
  117. clearable: {
  118. type: Boolean,
  119. default: true
  120. },
  121. /**
  122. * 对齐方式(left, center, right)
  123. */
  124. align: {
  125. type: String,
  126. default: 'left'
  127. },
  128. /**
  129. * 选择范围时的分隔符
  130. */
  131. rangeSeparator: {
  132. type: String,
  133. default: '-'
  134. },
  135. /**
  136. * 可选,绑定值的格式。不指定则绑定值为 Date 对象
  137. */
  138. valueFormat: {
  139. type: String,
  140. default: 'yyyy-MM-dd'
  141. },
  142. /**
  143. * 自定义头部图标的类名
  144. */
  145. prefixIcon: {
  146. type: String,
  147. default: 'el-icon-date'
  148. },
  149. /**
  150. * 自定义清空图标的类名
  151. */
  152. clearIcon: {
  153. type: String,
  154. default: 'el-icon-circle-close'
  155. }
  156. },
  157. data () {
  158. return {
  159. dateType: this.defaultDateType,
  160. currentDates: undefined
  161. }
  162. },
  163. methods: {
  164. onValueChange (values) {
  165. this.$nextTick(() => {
  166. this.emitChange();
  167. });
  168. },
  169. emitChange () {
  170. let outputDate = [];
  171. if (this.currentDates != null) {
  172. if (!this.isRange) {
  173. outputDate[0] = new Date(this.currentDates);
  174. outputDate[1] = new Date(this.currentDates);
  175. } else {
  176. if (Array.isArray(this.currentDates) && this.currentDates.length === 2) {
  177. outputDate[0] = new Date(this.currentDates[0]);
  178. outputDate[1] = new Date(this.currentDates[1]);
  179. }
  180. }
  181. if (outputDate[0] != null && outputDate[1] != null) {
  182. outputDate[0].setHours(0, 0, 0, 0);
  183. outputDate[1].setHours(0, 0, 0, 0);
  184. switch (this.dateType) {
  185. case 'day':
  186. outputDate[1].setDate(outputDate[1].getDate() + 1);
  187. break;
  188. case 'month':
  189. outputDate[1].setDate(1);
  190. outputDate[0].setDate(1);
  191. outputDate[1].setMonth(outputDate[1].getMonth() + 1);
  192. break;
  193. case 'year':
  194. outputDate[1].setMonth(0);
  195. outputDate[1].setDate(1);
  196. outputDate[0].setMonth(0);
  197. outputDate[0].setDate(1);
  198. outputDate[1].setFullYear(outputDate[1].getFullYear() + 1);
  199. break;
  200. }
  201. outputDate[1] = new Date(outputDate[1].getTime() - 1);
  202. outputDate[0] = formatDate(outputDate[0], this.outputFormat);
  203. outputDate[1] = formatDate(outputDate[1], this.outputFormat);
  204. }
  205. }
  206. this.$emit('input', outputDate);
  207. this.$emit('change', outputDate);
  208. },
  209. getCurrentStatsDateType () {
  210. return this.dateType;
  211. }
  212. },
  213. computed: {
  214. validTypeList () {
  215. return allTypeList.filter((item) => {
  216. return this.allowTypes.indexOf(item.value) !== -1;
  217. });
  218. },
  219. /**
  220. * el-date-picker使用的type
  221. */
  222. innerDateType () {
  223. switch (this.dateType) {
  224. case 'day': return this.isRange ? 'daterange' : 'date';
  225. case 'month': return this.isRange ? 'monthrange' : 'month';
  226. case 'year': return this.isRange ? 'monthrange' : 'year';
  227. default: return this.isRange ? 'daterange' : 'date';
  228. }
  229. },
  230. /**
  231. * el-date-picker使用的format
  232. */
  233. innerDateFormat () {
  234. switch (this.dateType) {
  235. case 'day': return 'yyyy-MM-dd';
  236. case 'month': return 'yyyy-MM';
  237. case 'year': return 'yyyy';
  238. default: return 'yyyy-MM-dd';
  239. }
  240. }
  241. },
  242. watch: {
  243. value: {
  244. handler: function (newValue, oldValue) {
  245. if (newValue == null || newValue.length < 2) {
  246. this.currentDates = this.isRange ? [] : undefined;
  247. } else {
  248. if (this.currentDates == null) this.currentDates = [];
  249. if (this.isRange) {
  250. this.currentDates = [
  251. parseDate(newValue[0], this.valueFormat),
  252. parseDate(newValue[1], this.valueFormat)
  253. ];
  254. } else {
  255. this.currentDates = parseDate(newValue[0], this.valueFormat);
  256. }
  257. }
  258. },
  259. immediate: true,
  260. deep: true
  261. },
  262. dateType: {
  263. handler: function (newValue, oldValue) {
  264. if (this.allowTypes.indexOf(this.dateType) === -1) {
  265. this.dateType = this.allowTypes[0] || 'day';
  266. }
  267. this.emitChange();
  268. },
  269. immediate: true
  270. },
  271. defaultDateType: {
  272. handler: function (newValue, oldValue) {
  273. if (this.allowTypes.indexOf(newValue) !== -1) {
  274. this.dateType = newValue;
  275. } else {
  276. this.dateType = this.allowTypes[0];
  277. }
  278. }
  279. },
  280. isRange: {
  281. handler: function (newValue, oldValue) {
  282. let temp;
  283. if (newValue) {
  284. temp = [this.currentDates, this.currentDates];
  285. } else {
  286. temp = this.currentDates[0];
  287. }
  288. this.currentDates = temp;
  289. }
  290. }
  291. }
  292. }
  293. </script>
  294. <style scoped>
  295. .date-range {
  296. display: flex;
  297. }
  298. </style>