WebApp【公共组件库】@前端(For Git Submodule)
coder77
2025-04-10 f58da404d459a3387f78d9bf6fe8933010f137bf
feat: 日期选择器增加快捷选择
3 files modified
365 ■■■■■ changed files
forms/datePicker/CDatePicker.vue 25 ●●●● patch | view | raw | blame | history
forms/datePicker/CDateRangeAction.vue 307 ●●●●● patch | view | raw | blame | history
forms/datePicker/cDateRangeAction.scss 33 ●●●● patch | view | raw | blame | history
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,
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>
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;
        }
    }
}
}