From f58da404d459a3387f78d9bf6fe8933010f137bf Mon Sep 17 00:00:00 2001
From: coder77 <2293444075@qq.com>
Date: Thu, 10 Apr 2025 11:02:22 +0800
Subject: [PATCH] feat: 日期选择器增加快捷选择

---
 forms/datePicker/CDateRangeAction.vue  |  307 +++++++++++++++++++++++++++++++++++++++++--
 forms/datePicker/CDatePicker.vue       |   25 +-
 forms/datePicker/cDateRangeAction.scss |   33 ++++
 3 files changed, 333 insertions(+), 32 deletions(-)

diff --git a/forms/datePicker/CDatePicker.vue b/forms/datePicker/CDatePicker.vue
index dd2c173..824a791 100644
--- a/forms/datePicker/CDatePicker.vue
+++ b/forms/datePicker/CDatePicker.vue
@@ -1,21 +1,16 @@
 /**
  * CDatePicker - 选择日期范围操作
- * 日期选择组件,用于在表单中选择日期或日期范围
- * 支持三种选择模式:日期选择、日期时间选择和日期范围选择
- * 可限制日期选择范围,支持清除功能和只读模式
  * @author Tevin
  */
 
 <template>
-    <view
-        class="c-date-picker"
-        :class="readOnly?'read-only':''"
-    >
+    <view class="c-date-picker" :class="readOnly ? 'read-only' : ''">
         <CDateRangeAction
-            v-if="mode==='dateRange'"
+            v-if="mode === 'dateRange'"
             :value="itemRes.formData[itemRes.name]"
-            :onChange="evt=>handleChange(evt)"
+            :onChange="evt => handleChange(evt)"
             :placeholder="placeholder"
+            :rangeTypes="rangeTypes"
         >
             <AtInput
                 :name="itemRes.name"
@@ -37,9 +32,9 @@
             </AtInput>
         </CDateRangeAction>
         <CDateTimeAction
-            v-else-if="mode==='dateTime'"
+            v-else-if="mode === 'dateTime'"
             :value="itemRes.formData[itemRes.name]"
-            :onChange="evt=>handleChange(evt)"
+            :onChange="evt => handleChange(evt)"
             :placeholder="placeholder"
         >
             <AtInput
@@ -61,14 +56,14 @@
                 ></view>
             </AtInput>
         </CDateTimeAction>
-        <view v-else-if="mode==='date'">
+        <view v-else-if="mode === 'date'">
             <picker
                 mode="date"
                 :start="limitStart || pickerStart"
                 :end="limitEnd || pickerEnd"
                 :fields="fields"
                 :value="itemRes.formData[itemRes.name]"
-                @change="evt=>handleChange(evt.detail.value)"
+                @change="evt => handleChange(evt.detail.value)"
             >
                 <AtInput
                     :name="itemRes.name"
@@ -122,6 +117,10 @@
         limitStart: String,
         // 结束日期
         limitEnd: String,
+        // 选择器类型,选日期、选周、选月
+        picker: String, //date,week,month
+        // 预设类型
+        rangeTypes: Array,
         // 日期选择粒度 year、month、day
         fields: {
             type: String,
diff --git a/forms/datePicker/CDateRangeAction.vue b/forms/datePicker/CDateRangeAction.vue
index 5c86a3d..f383de6 100644
--- a/forms/datePicker/CDateRangeAction.vue
+++ b/forms/datePicker/CDateRangeAction.vue
@@ -5,16 +5,10 @@
 
 <template>
     <view class="c-date-range-action">
-        <view
-            class="c-date-range-slot"
-            @tap="evt => handleOpen()"
-        >
+        <view class="c-date-range-slot" @tap="evt => handleOpen()">
             <slot />
         </view>
-        <view
-            class="c-data-range-float"
-            ref="floadLayer"
-        >
+        <view class="c-data-range-float" ref="floadLayer">
             <CDrawer
                 class="c-data-range-drawer"
                 direction="top"
@@ -22,7 +16,7 @@
                 :onClose="evt => handleClose()"
             >
                 <view class="title">
-                    <view v-if="placeholder">{{placeholder}}</view>
+                    <view v-if="placeholder">{{ placeholder }}</view>
                     <view v-else>请选择日期</view>
                 </view>
                 <view class="date">
@@ -35,8 +29,8 @@
                     >
                         <view class="item">
                             <view class="label">开始日期</view>
-                            <view :class="startDate?'filled':'empty'">
-                                {{ startDate?startDate:'请选择开始日期' }}
+                            <view :class="startDate ? 'filled' : 'empty'">
+                                {{ startDate ? startDate : '请选择开始日期' }}
                             </view>
                             <view class="at-icon at-icon-chevron-right" />
                         </view>
@@ -50,12 +44,22 @@
                     >
                         <view class="item">
                             <view class="label">结束日期</view>
-                            <view :class="endDate?'filled':'empty'">
-                                {{ endDate?endDate:'请选择结束日期' }}
+                            <view :class="endDate ? 'filled' : 'empty'">
+                                {{ endDate ? endDate : '请选择结束日期' }}
                             </view>
                             <view class="at-icon at-icon-chevron-right" />
                         </view>
                     </picker>
+                </view>
+                <view class="quick-select">
+                    <view
+                        class="quick-select-item"
+                        v-for="(item, index) in quickSelect"
+                        :key="index"
+                        @tap="evt => handleQuickSelect(item)"
+                    >
+                        <view class="quick-select-item-label">{{ item.label }}</view>
+                    </view>
                 </view>
                 <AtButton
                     class="btn"
@@ -63,7 +67,8 @@
                     full
                     :circle="false"
                     :onClick="evt => handleFinish()"
-                >确定</AtButton>
+                    >确定</AtButton
+                >
             </CDrawer>
         </view>
     </view>
@@ -71,6 +76,7 @@
 
 <script>
 import Taro from '@tarojs/taro';
+import moment from 'moment';
 import { $ } from '@tarojs/extend';
 import { AtDrawer, AtButton } from 'taro-ui-vue';
 import { CDrawer } from '@components/layout/drawer';
@@ -90,6 +96,13 @@
         onChange: Function,
         // 占位提示
         placeholder: String,
+        // 选择器类型,选日期、选周、选月
+        picker: {
+            type: String,
+            default: 'date', // date, week, month
+        },
+        // 预设类型
+        rangeTypes: Array,
     },
     data() {
         const year = new Date().getFullYear();
@@ -99,10 +112,274 @@
             endDate: '',
             pickerStart: year - 30 + '-01-01',
             pickerEnd: year + 30 + '-12-31',
+            quickSelect: [],
         };
     },
     computed: {},
     methods: {
+        _createRanges(ranges) {
+            const result = [];
+
+            for (let typeName of ranges) {
+                switch (typeName) {
+                    case 'today':
+                        result.push({
+                            label: '今天',
+                            value: [
+                                moment().format('YYYY-MM-DD'),
+                                moment().format('YYYY-MM-DD'),
+                            ],
+                        });
+                        break;
+                    case 'yesterday':
+                        result.push({
+                            label: '昨天',
+                            value: [
+                                moment().subtract(1, 'day').format('YYYY-MM-DD'),
+                                moment().subtract(1, 'day').format('YYYY-MM-DD'),
+                            ],
+                        });
+                        break;
+                    case 'curWeek':
+                        if (this.limitDays && this.limitDays < 7) {
+                            break;
+                        }
+                        result.push({
+                            label: '本周',
+                            value: [
+                                moment().startOf('week').format('YYYY-MM-DD'),
+                                moment().endOf('week').format('YYYY-MM-DD'),
+                            ],
+                        });
+                        break;
+                    case 'lastWeek':
+                        if (this.limitDays && this.limitDays < 7) {
+                            break;
+                        }
+                        result.push({
+                            label: '上周',
+                            value: [
+                                moment()
+                                    .subtract(1, 'week')
+                                    .startOf('week')
+                                    .format('YYYY-MM-DD'),
+                                moment()
+                                    .subtract(1, 'week')
+                                    .endOf('week')
+                                    .format('YYYY-MM-DD'),
+                            ],
+                        });
+                        break;
+                    case 'curMonth':
+                        if (this.limitDays && this.limitDays < 30) {
+                            break;
+                        }
+                        result.push({
+                            label: '本月',
+                            value: [
+                                moment().startOf('month').format('YYYY-MM-DD'),
+                                moment().endOf('month').format('YYYY-MM-DD'),
+                            ],
+                        });
+                        break;
+                    case 'lastMonth':
+                        if (this.limitDays && this.limitDays < 30) {
+                            break;
+                        }
+                        result.push({
+                            label: '上月',
+                            value: [
+                                moment()
+                                    .subtract(1, 'months')
+                                    .startOf('month')
+                                    .format('YYYY-MM-DD'),
+                                moment()
+                                    .subtract(1, 'months')
+                                    .endOf('month')
+                                    .format('YYYY-MM-DD'),
+                            ],
+                        });
+                        break;
+                    case 'curQuarter':
+                        if (this.limitDays && this.limitDays < 90) {
+                            break;
+                        }
+                        result.push({
+                            label: '本季',
+                            value: [
+                                moment().startOf('quarter').format('YYYY-MM-DD'),
+                                moment().endOf('quarter').format('YYYY-MM-DD'),
+                            ],
+                        });
+                        break;
+                    case 'lastQuarter':
+                        if (this.limitDays && this.limitDays < 90) {
+                            break;
+                        }
+                        result.push({
+                            label: '上季',
+                            value: [
+                                moment()
+                                    .subtract(1, 'quarter')
+                                    .startOf('quarter')
+                                    .format('YYYY-MM-DD'),
+                                moment()
+                                    .subtract(1, 'quarter')
+                                    .endOf('quarter')
+                                    .format('YYYY-MM-DD'),
+                            ],
+                        });
+                        break;
+                    case 'nearly3':
+                        if (this.limitDays && this.limitDays < 3) {
+                            break;
+                        }
+                        result.push({
+                            label: '最近3天',
+                            value: [
+                                moment().subtract(2, 'days').format('YYYY-MM-DD'),
+                                moment().format('YYYY-MM-DD'),
+                            ],
+                        });
+                        break;
+                    case 'nearly7':
+                        if (this.limitDays && this.limitDays < 7) {
+                            break;
+                        }
+                        result.push({
+                            label: '最近7天',
+                            value: [
+                                moment().subtract(6, 'days').format('YYYY-MM-DD'),
+                                moment().format('YYYY-MM-DD'),
+                            ],
+                        });
+                        break;
+                    case 'nearly10':
+                        if (this.limitDays && this.limitDays < 10) {
+                            break;
+                        }
+                        result.push({
+                            label: '最近10天',
+                            value: [
+                                moment().subtract(9, 'days').format('YYYY-MM-DD'),
+                                moment().format('YYYY-MM-DD'),
+                            ],
+                        });
+                        break;
+                    case 'nearly15':
+                        if (this.limitDays && this.limitDays < 15) {
+                            break;
+                        }
+                        result.push({
+                            label: '最近15天',
+                            value: [
+                                moment().subtract(14, 'days').format('YYYY-MM-DD'),
+                                moment().format('YYYY-MM-DD'),
+                            ],
+                        });
+                        break;
+                    case 'nearly30':
+                        if (this.limitDays && this.limitDays < 30) {
+                            break;
+                        }
+                        result.push({
+                            label: '最近30天',
+                            value: [
+                                moment().subtract(29, 'days').format('YYYY-MM-DD'),
+                                moment().format('YYYY-MM-DD'),
+                            ],
+                        });
+                        break;
+                    case 'nearly60':
+                        if (this.limitDays && this.limitDays < 60) {
+                            break;
+                        }
+                        result.push({
+                            label: '最近60天',
+                            value: [
+                                moment().subtract(59, 'days').format('YYYY-MM-DD'),
+                                moment().format('YYYY-MM-DD'),
+                            ],
+                        });
+                        break;
+                    case 'nearly90':
+                        if (this.limitDays && this.limitDays < 90) {
+                            break;
+                        }
+                        result.push({
+                            label: '最近90天',
+                            value: [
+                                moment().subtract(89, 'days').format('YYYY-MM-DD'),
+                                moment().format('YYYY-MM-DD'),
+                            ],
+                        });
+                        break;
+                    case 'nearly4W':
+                        if (this.limitDays && this.limitDays < 28) {
+                            break;
+                        }
+                        result.push({
+                            label: '最近4周',
+                            value: [
+                                moment()
+                                    .subtract(3, 'week')
+                                    .startOf('week')
+                                    .format('YYYY-MM-DD'),
+                                moment().endOf('week').format('YYYY-MM-DD'),
+                            ],
+                        });
+                        break;
+                    case 'nearly12W':
+                        if (this.limitDays && this.limitDays < 84) {
+                            break;
+                        }
+                        result.push({
+                            label: '最近12周',
+                            value: [
+                                moment()
+                                    .subtract(11, 'week')
+                                    .startOf('week')
+                                    .format('YYYY-MM-DD'),
+                                moment().endOf('week').format('YYYY-MM-DD'),
+                            ],
+                        });
+                        break;
+                    case 'nearly3M':
+                        if (this.limitDays && this.limitDays < 90) {
+                            break;
+                        }
+                        result.push({
+                            label: '最近3个月',
+                            value: [
+                                moment()
+                                    .subtract(2, 'months')
+                                    .startOf('month')
+                                    .format('YYYY-MM-DD'),
+                                moment().endOf('month').format('YYYY-MM-DD'),
+                            ],
+                        });
+                        break;
+                    default:
+                        break;
+                }
+            }
+
+            return result;
+        },
+        _initQuickSelect() {
+            const defaultRangeTypes = {
+                date: ['today', 'curWeek', 'nearly3', 'nearly7'],
+                week: ['curWeek', 'lastWeek', 'nearly4W', 'nearly12W'],
+                month: ['curMonth', 'lastMonth', 'curQuarter', 'lastQuarter', 'nearly3M'],
+            };
+            this.quickSelect = this.rangeTypes
+                ? this._createRanges(this.rangeTypes)
+                : this._createRanges(defaultRangeTypes[this.picker]);
+        },
+        handleQuickSelect(item) {
+            this.startDate = item.value[0];
+            this.endDate = item.value[1];
+        },
         handleOpen() {
             this.drawerShow = true;
             const curDates = (this.value || ',').split(',');
@@ -158,6 +435,8 @@
         if ($cFilter.length > 0) {
             $cFilter.eq(0).after(this.$refs.floadLayer);
         }
+
+        this._initQuickSelect();
     },
 };
 </script>
\ No newline at end of file
diff --git a/forms/datePicker/cDateRangeAction.scss b/forms/datePicker/cDateRangeAction.scss
index 6326783..3c45ee1 100644
--- a/forms/datePicker/cDateRangeAction.scss
+++ b/forms/datePicker/cDateRangeAction.scss
@@ -3,7 +3,7 @@
  * @author Tevin
  */
 
-@import "../../common/sassMixin";
+@import '../../common/sassMixin';
 
 .c-data-range-float {
     @include position(fixed, 0 0, 9100);
@@ -12,8 +12,8 @@
             height: 100px;
             text-align: center;
             line-height: 100px;
-            border-top: 1PX solid #eee;
-            border-bottom: 1PX solid #d6e4ef;
+            border-top: 1px solid #eee;
+            border-bottom: 1px solid #d6e4ef;
             background-color: #f8f8f8;
         }
         .item {
@@ -22,7 +22,7 @@
             height: 96px;
             padding: 24px 0 24px 24px;
             white-space: nowrap;
-            border-bottom: 1PX solid #d6e4ef;
+            border-bottom: 1px solid #d6e4ef;
             box-sizing: border-box;
             background-color: #fff;
             .label {
@@ -47,9 +47,32 @@
             padding-bottom: 24px;
             background-color: #f8f8f8;
         }
+        .quick-select {
+            display: flex;
+            flex-wrap: wrap;
+            padding: 0 24px;
+            .quick-select-item {
+                height: 60px;
+                line-height: 60px;
+                padding: 0 18px;
+                margin-bottom: 24px;
+                text-align: center;
+                color: #1890ff;
+                background: #e6f7ff;
+                border: 1px solid #1890ff;
+                border-color: #91d5ff;
+                border-radius: 4px;
+                &:not(:last-child) {
+                    margin-right: 24px;
+                }
+                &:active {
+                    background-color: #e8e8e8;
+                }
+            }
+        }
         .btn {
             background-color: #36a0e7;
             border: none;
         }
     }
-}
\ No newline at end of file
+}

--
Gitblit v1.9.1