混凝土运输管理微信小程序、替班
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

320 lines
7.4 KiB

2 weeks ago
  1. <template>
  2. <view class="select-datetime-container">
  3. <picker
  4. mode="multiSelector"
  5. :range="pickerRange"
  6. :value="pickerValue"
  7. @change="onPickerChange"
  8. @columnchange="onColumnChange"
  9. >
  10. <slot>
  11. <view class="datetime-display">
  12. <text>{{ displayText }}</text>
  13. <uv-icon name="arrow-down" size="16" color="#999"></uv-icon>
  14. </view>
  15. </slot>
  16. </picker>
  17. </view>
  18. </template>
  19. <script>
  20. export default {
  21. name: 'SelectDatetime',
  22. props: {
  23. // 选择器类型: 'datetime', 'date', 'time'
  24. type: {
  25. type: String,
  26. default: 'datetime'
  27. },
  28. // 默认值
  29. value: {
  30. type: String,
  31. default: ''
  32. },
  33. // 占位文本
  34. placeholder: {
  35. type: String,
  36. default: '请选择时间'
  37. },
  38. // 最小年份
  39. minYear: {
  40. type: Number,
  41. default: 2020
  42. },
  43. // 最大年份
  44. maxYear: {
  45. type: Number,
  46. default: 2030
  47. }
  48. },
  49. data() {
  50. return {
  51. pickerValue: [0, 0, 0, 0, 0],
  52. pickerRange: [],
  53. currentDate: new Date(),
  54. selectedDateTime: ''
  55. }
  56. },
  57. computed: {
  58. displayText() {
  59. if (this.selectedDateTime) {
  60. return this.selectedDateTime;
  61. }
  62. return this.placeholder;
  63. },
  64. // 年份数组
  65. years() {
  66. const years = [];
  67. for (let i = this.minYear; i <= this.maxYear; i++) {
  68. years.push(i + '年');
  69. }
  70. return years;
  71. },
  72. // 月份数组
  73. months() {
  74. const months = [];
  75. for (let i = 1; i <= 12; i++) {
  76. months.push(i + '月');
  77. }
  78. return months;
  79. },
  80. // 日期数组
  81. days() {
  82. const year = this.minYear + this.pickerValue[0];
  83. const month = this.pickerValue[1] + 1;
  84. const daysInMonth = new Date(year, month, 0).getDate();
  85. const days = [];
  86. for (let i = 1; i <= daysInMonth; i++) {
  87. days.push(i + '日');
  88. }
  89. return days;
  90. },
  91. // 小时数组
  92. hours() {
  93. const hours = [];
  94. for (let i = 0; i < 24; i++) {
  95. hours.push(i.toString().padStart(2, '0') + '时');
  96. }
  97. return hours;
  98. },
  99. // 分钟数组
  100. minutes() {
  101. const minutes = [];
  102. for (let i = 0; i < 60; i += 5) { // 每5分钟一个选项
  103. minutes.push(i.toString().padStart(2, '0') + '分');
  104. }
  105. return minutes;
  106. }
  107. },
  108. mounted() {
  109. this.initPicker();
  110. if (this.value) {
  111. this.parseValue(this.value);
  112. }
  113. },
  114. watch: {
  115. value(newVal) {
  116. if (newVal) {
  117. this.parseValue(newVal);
  118. }
  119. },
  120. type() {
  121. this.initPicker();
  122. }
  123. },
  124. methods: {
  125. // 初始化选择器
  126. initPicker() {
  127. switch (this.type) {
  128. case 'datetime':
  129. this.pickerRange = [this.years, this.months, this.days, this.hours, this.minutes];
  130. this.pickerValue = [0, 0, 0, 0, 0];
  131. break;
  132. case 'date':
  133. this.pickerRange = [this.years, this.months, this.days];
  134. this.pickerValue = [0, 0, 0];
  135. break;
  136. case 'time':
  137. this.pickerRange = [this.hours, this.minutes];
  138. this.pickerValue = [0, 0];
  139. break;
  140. }
  141. this.setDefaultValue();
  142. },
  143. // 设置默认值为当前时间
  144. setDefaultValue() {
  145. const now = new Date();
  146. const year = now.getFullYear();
  147. const month = now.getMonth();
  148. const day = now.getDate() - 1;
  149. const hour = now.getHours();
  150. const minute = Math.floor(now.getMinutes() / 5);
  151. switch (this.type) {
  152. case 'datetime':
  153. this.pickerValue = [
  154. year - this.minYear,
  155. month,
  156. day,
  157. hour,
  158. minute
  159. ];
  160. break;
  161. case 'date':
  162. this.pickerValue = [
  163. year - this.minYear,
  164. month,
  165. day
  166. ];
  167. break;
  168. case 'time':
  169. this.pickerValue = [hour, minute];
  170. break;
  171. }
  172. this.updateDisplayText();
  173. },
  174. // 解析传入的值
  175. parseValue(value) {
  176. try {
  177. const date = new Date(value);
  178. if (isNaN(date.getTime())) {
  179. return;
  180. }
  181. const year = date.getFullYear();
  182. const month = date.getMonth();
  183. const day = date.getDate() - 1;
  184. const hour = date.getHours();
  185. const minute = Math.floor(date.getMinutes() / 5);
  186. switch (this.type) {
  187. case 'datetime':
  188. this.pickerValue = [
  189. year - this.minYear,
  190. month,
  191. day,
  192. hour,
  193. minute
  194. ];
  195. break;
  196. case 'date':
  197. this.pickerValue = [
  198. year - this.minYear,
  199. month,
  200. day
  201. ];
  202. break;
  203. case 'time':
  204. this.pickerValue = [hour, minute];
  205. break;
  206. }
  207. this.updateDisplayText();
  208. } catch (e) {
  209. console.error('解析时间值失败:', e);
  210. }
  211. },
  212. // 选择器值改变
  213. onPickerChange(e) {
  214. this.pickerValue = e.detail.value;
  215. this.updateDisplayText();
  216. this.emitChange();
  217. },
  218. // 列改变时更新日期选项
  219. onColumnChange(e) {
  220. const column = e.detail.column;
  221. const value = e.detail.value;
  222. // 如果改变的是年份或月份,需要更新日期选项
  223. if ((column === 0 || column === 1) && this.type !== 'time') {
  224. this.pickerValue[column] = value;
  225. this.$nextTick(() => {
  226. this.pickerRange[2] = this.days;
  227. // 如果当前选择的日期超出了新月份的天数,调整到最后一天
  228. if (this.pickerValue[2] >= this.days.length) {
  229. this.pickerValue[2] = this.days.length - 1;
  230. }
  231. });
  232. }
  233. },
  234. // 更新显示文本
  235. updateDisplayText() {
  236. switch (this.type) {
  237. case 'datetime':
  238. this.selectedDateTime = `${this.years[this.pickerValue[0]]} ${this.months[this.pickerValue[1]]} ${this.days[this.pickerValue[2]]} ${this.hours[this.pickerValue[3]]} ${this.minutes[this.pickerValue[4]]}`;
  239. break;
  240. case 'date':
  241. this.selectedDateTime = `${this.years[this.pickerValue[0]]} ${this.months[this.pickerValue[1]]} ${this.days[this.pickerValue[2]]}`;
  242. break;
  243. case 'time':
  244. this.selectedDateTime = `${this.hours[this.pickerValue[0]]} ${this.minutes[this.pickerValue[1]]}`;
  245. break;
  246. }
  247. },
  248. // 发送改变事件
  249. emitChange() {
  250. let dateValue = '';
  251. switch (this.type) {
  252. case 'datetime':
  253. const year = this.minYear + this.pickerValue[0];
  254. const month = (this.pickerValue[1] + 1).toString().padStart(2, '0');
  255. const day = (this.pickerValue[2] + 1).toString().padStart(2, '0');
  256. const hour = this.pickerValue[3].toString().padStart(2, '0');
  257. const minute = (this.pickerValue[4] * 5).toString().padStart(2, '0');
  258. dateValue = `${year}-${month}-${day} ${hour}:${minute}:00`;
  259. break;
  260. case 'date':
  261. const dateYear = this.minYear + this.pickerValue[0];
  262. const dateMonth = (this.pickerValue[1] + 1).toString().padStart(2, '0');
  263. const dateDay = (this.pickerValue[2] + 1).toString().padStart(2, '0');
  264. dateValue = `${dateYear}-${dateMonth}-${dateDay}`;
  265. break;
  266. case 'time':
  267. const timeHour = this.pickerValue[0].toString().padStart(2, '0');
  268. const timeMinute = (this.pickerValue[1] * 5).toString().padStart(2, '0');
  269. dateValue = `${timeHour}:${timeMinute}:00`;
  270. break;
  271. }
  272. this.$emit('change', {
  273. value: dateValue,
  274. displayText: this.selectedDateTime,
  275. pickerValue: this.pickerValue
  276. });
  277. }
  278. }
  279. }
  280. </script>
  281. <style scoped lang="scss">
  282. .select-datetime-container {
  283. width: 100%;
  284. }
  285. .datetime-display {
  286. display: flex;
  287. align-items: center;
  288. justify-content: space-between;
  289. padding: 20rpx;
  290. background-color: #fff;
  291. border: 1rpx solid #e0e0e0;
  292. border-radius: 8rpx;
  293. font-size: 28rpx;
  294. color: #333;
  295. text {
  296. flex: 1;
  297. }
  298. }
  299. </style>