4 files added
5 files modified
| | |
| | | /** |
| | | * 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" |
| | |
| | | </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 |
| | |
| | | ></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" |
| | |
| | | limitStart: String, |
| | | // 结束日期 |
| | | limitEnd: String, |
| | | // 选择器类型,选日期、选周、选月 |
| | | picker: String, //date,week,month |
| | | // 预设类型 |
| | | rangeTypes: Array, |
| | | // 日期选择粒度 year、month、day |
| | | fields: { |
| | | type: String, |
| | |
| | | |
| | | <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" |
| | |
| | | :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"> |
| | |
| | | > |
| | | <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> |
| | |
| | | > |
| | | <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" |
| | |
| | | full |
| | | :circle="false" |
| | | :onClick="evt => handleFinish()" |
| | | >确定</AtButton> |
| | | >确定</AtButton |
| | | > |
| | | </CDrawer> |
| | | </view> |
| | | </view> |
| | |
| | | |
| | | <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'; |
| | |
| | | onChange: Function, |
| | | // 占位提示 |
| | | placeholder: String, |
| | | // 选择器类型,选日期、选周、选月 |
| | | picker: { |
| | | type: String, |
| | | default: 'date', // date, week, month |
| | | }, |
| | | // 预设类型 |
| | | rangeTypes: Array, |
| | | }, |
| | | data() { |
| | | const year = new Date().getFullYear(); |
| | |
| | | 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(','); |
| | |
| | | if ($cFilter.length > 0) { |
| | | $cFilter.eq(0).after(this.$refs.floadLayer); |
| | | } |
| | | |
| | | this._initQuickSelect(); |
| | | }, |
| | | }; |
| | | </script> |
| | |
| | | * @author Tevin |
| | | */ |
| | | |
| | | @import "../../common/sassMixin"; |
| | | @import '../../common/sassMixin'; |
| | | |
| | | .c-data-range-float { |
| | | @include position(fixed, 0 0, 9100); |
| | |
| | | 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 { |
| | |
| | | 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 { |
| | |
| | | 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; |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | type="primary" |
| | | size="small" |
| | | :onClick="evt => handleChooseLocation(evt)" |
| | | >选择位置</AtButton> |
| | | >选择地点</AtButton> |
| | | <AtButton |
| | | type="primary" |
| | | size="small" |
| | |
| | | size="small" |
| | | class="btn-info" |
| | | :onClick="evt => handleSaveLocation(evt)" |
| | | >保存</AtButton> |
| | | >确认</AtButton> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | |
| | | .map-controls-top { |
| | | display: flex; |
| | | width: 100%; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | height: 100px; |
| | | padding: 0 20px; |
| | | box-sizing: border-box; |
| | | .at-button { |
| | | width: 45%; |
| | | width: calc(50% - 6px); |
| | | height: 76px !important; |
| | | line-height: 72px; |
| | | font-size: 40px; |
| | | margin: 0; |
| | | } |
| | | } |
| | | .map-controls-bottom { |
| | | display: flex; |
| | | align-items: center; |
| | | height: 100px; |
| | | width: 100%; |
| | | height: 88px; |
| | | padding: 0 20px; |
| | | box-sizing: border-box; |
| | | .at-button { |
| | | width: 95%; |
| | | width: 100%; |
| | | height: 76px !important; |
| | | line-height: 72px; |
| | | font-size: 40px; |
| | | margin: 0; |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /** |
| | | * 微信小程序原生头像选择组件 |
| | | * 用于在小程序环境中调用原生的头像选择功能 |
| | | * @author Tevin |
| | | * @tutorial |
| | | * 第一步:注册为 Taro 元素组件 |
| | | * 打开 Taro 页面的 config.js 配置文件,在 usingComponents 中注册为元素组件 |
| | | * export default { |
| | | * usingComponents: { |
| | | * 'weapp-choose-avatar': '@components/weappNative/chooseAvatar/weappChooseAvatar', |
| | | * } |
| | | * } |
| | | * 第二步:在页面中使用元素组件(直接当元素使用) |
| | | * <weapp-choose-avatar @chooseAvatar="evt=>onChooseAvatar(evt)"> |
| | | * <button>选择头像</button> |
| | | * </weapp-choose-avatar> |
| | | * |
| | | * @notice |
| | | * 1. 样式完全由内容决定,组件内部所有样式已清空 |
| | | * 2. 绑定事件需要用“@”,返回参数为头像地址 |
| | | */ |
| | | Component({ |
| | | behaviors: [], |
| | | options: { |
| | | styleIsolation: 'apply-shared', |
| | | }, |
| | | // 相当于 props |
| | | properties: { |
| | | // 禁用状态 |
| | | disabled: { |
| | | type: Boolean, |
| | | value: false, |
| | | }, |
| | | // 按钮文本 |
| | | content: { |
| | | type: String, |
| | | value: '按钮', |
| | | }, |
| | | }, |
| | | data: {}, |
| | | methods: { |
| | | handleChooseAvatar(evt) { |
| | | this.triggerEvent('chooseAvatar', evt.detail); |
| | | }, |
| | | }, |
| | | }); |
New file |
| | |
| | | { |
| | | "component": true, |
| | | "usingComponents": {} |
| | | } |
New file |
| | |
| | | <button |
| | | class="c-choose-avatar" |
| | | type="default" |
| | | plain="true" |
| | | size="mini" |
| | | disabled="{{ disabled }}" |
| | | open-type="chooseAvatar" |
| | | bindchooseavatar="{{ 'handleChooseAvatar' }}" |
| | | > |
| | | <slot></slot> |
| | | </button> |
New file |
| | |
| | | .c-choose-avatar { |
| | | width: auto; |
| | | height: auto; |
| | | padding-left: 0rpx !important; |
| | | padding-right: 0rpx !important; |
| | | margin: 0; |
| | | border-width: 0 !important; |
| | | border-color: transparent !important; |
| | | -webkit-tap-highlight-color: transparent !important; |
| | | } |