[mini-wechat] [picker] 时间选择时范围限制

本文介绍了一种在日期选择器中实现时间范围限制的方法,确保开始时间不会晚于结束时间,反之亦然。通过在picker组件上设置特定参数,可以有效地控制用户的选择范围,避免逻辑错误。

范围限制:开始时间的结束 只能是 结束时间的开始, 结束时间的开始 是 开始时间的结束

代码相当简单

  1. 在开始的picker上添加end="{{params.endDate}}", 结束的picker上添加start="{{params.startDate}}",用参数自身做边界值 😃
    在这里插入图片描述

举个栗子:

例如今天2019-11-7
在这里插入图片描述
点击了开始时间,只能选11-7当日或以前的11-7以后的都不能选包括2019年以后
同理结束的只能选11-7当日和11-7以后且不能小于2019年
在这里插入图片描述

// pages/my/my.js const STORAGE_KEY = 'wechatAccounts'; const TASK_ID_PREFIX = 'task_'; let taskIdCounter = 0; // 用于生成唯一任务ID Page({ data: { showTaskModal: false, searchKeyword: '', sortOptions: [ { name: '编号顺序', key: 'tagId' }, { name: '微信名', key: 'wechatName' }, { name: '业务员', key: 'salesman' } ], sortIndex: 0, rawList: [], displayList: [], activeTasks: [], // 当前激活的任务表 }, onAddTask() { this.loadWechatData(); this.setData({ showTaskModal: true }); }, loadWechatData() { try { const wechats = wx.getStorageSync(STORAGE_KEY) || []; this.setData({ rawList: wechats, displayList: wechats }, () => { this.filterAndSort(); }); } catch (e) { console.error('读取微信账号失败', e); this.setData({ rawList: [], displayList: [] }); } }, onSearchInput(e) { this.setData({ searchKeyword: e.detail.value.trim() }, () => { this.filterAndSort(); }); }, clearSearch() { this.setData({ searchKeyword: '' }, () => { this.filterAndSort(); }); }, onSortChange(e) { const index = parseInt(e.detail.value); this.setData({ sortIndex: index }, () => { this.filterAndSort(); }); }, filterAndSort() { const { rawList, searchKeyword, sortIndex, sortOptions } = this.data; const kw = searchKeyword.toLowerCase(); const sortKey = sortOptions[sortIndex].key; let result = [...rawList]; if (kw) { result = result.filter(item => [item.tagId, item.wechatName, item.salesman] .some(field => field && field.toString().toLowerCase().includes(kw)) ); } result.sort((a, b) => { const valA = (a[sortKey] || '').toString().toLowerCase(); const valB = (b[sortKey] || '').toString().toLowerCase(); return valA.localeCompare(valB, 'zh'); }); this.setData({ displayList: result }); }, // 选择某个账号并创建任务 selectAccount(e) { const account = e.currentTarget.dataset.account; const newTask = { id: TASK_ID_PREFIX + (taskIdCounter++), tagId: account.tagId, salesman: account.salesman || '—', invitedCount: 0, acceptedCount: 0, isExpanded: true, tempRemark: '', invitations: [] }; this.setData({ activeTasks: [...this.data.activeTasks, newTask], showTaskModal: false, searchKeyword: '' }); }, // 切换展开/收起 toggleTaskExpand(e) { const id = e.currentTarget.dataset.id; const tasks = this.data.activeTasks.map(t => { if (t.id === id) { return { ...t, isExpanded: !t.isExpanded }; } return t; }); this.setData({ activeTasks: tasks }); }, // 输入客户备注 onRemarkInput(e) { const value = e.detail.value; const id = e.currentTarget.dataset.id; const tasks = this.data.activeTasks.map(t => { if (t.id === id) { return { ...t, tempRemark: value }; } return t; }); this.setData({ activeTasks: tasks }); }, // 添加邀请 addInvite(e) { const id = e.currentTarget.dataset.id; const now = new Date(); const month = (now.getMonth() + 1).toString().padStart(2, '0'); const day = now.getDate().toString().padStart(2, '0'); const hour = now.getHours().toString().padStart(2, '0'); const minute = now.getMinutes().toString().padStart(2, '0'); const timeStr = `${month}-${day} ${hour}:${minute}`; // 格式:04-05 13:22 const tasks = this.data.activeTasks.map(t => { if (t.id === id && t.tempRemark.trim()) { const remark = t.tempRemark.trim(); const newInvite = { id: Date.now() + Math.random(), // 唯一ID remark, accepted: false, time: timeStr // 添加时间 }; t.invitations.push(newInvite); t.tempRemark = ''; t.invitedCount += 1; // 正常增加邀请数 } return t; }); this.setData({ activeTasks: tasks }); }, // 标记为已通过 acceptInvite(e) { const taskId = e.currentTarget.dataset.taskid; const index = parseInt(e.currentTarget.dataset.index); const tasks = this.data.activeTasks.map(t => { if (t.id === taskId && !t.invitations[index].accepted) { t.invitations[index].accepted = true; t.acceptedCount += 1; } return t; }); this.setData({ activeTasks: tasks }); }, // 删除邀请 deleteInvite(e) { const taskId = e.currentTarget.dataset.taskid; const index = parseInt(e.currentTarget.dataset.index); const tasks = this.data.activeTasks.map(t => { if (t.id === taskId && t.invitations[index]) { const invite = t.invitations[index]; // 如果是已通过的,才减少 acceptedCount if (invite.accepted) { t.acceptedCount -= 1; } // 任何情况删除,都要减少 invitedCount t.invitedCount -= 1; // 删除数组项 t.invitations.splice(index, 1); } return t; }); this.setData({ activeTasks: tasks }); }, // 清空所有任务 clearAllTasks() { this.setData({ activeTasks: [] }); }, noop() {} }); <!-- pages/my/my.wxml --> <view class="container"> <!-- 已添加的任务--> <view wx:if="{{activeTasks.length > 0}}" class="task-header"> <button class="add-task-btn mini" bindtap="onAddTask">添加任务</button> <button class="clear-task-btn mini" bindtap="clearAllTasks">清空任务</button> </view> <!-- 多个任务卡片 --> <block wx:for="{{activeTasks}}" wx:key="id"> <view class="task-card"> <!-- 卡片头部:编号 + 业务员 + 展开箭头 --> <view class="card-header" catchtap="toggleTaskExpand" data-id="{{item.id}}"> <text class="card-id">{{item.tagId}}</text> <text class="card-salesman">业务员: {{item.salesman}}</text> <text class="expand-arrow">{{item.isExpanded ? '▼' : '▶'}}</text> </view> <!-- 下方统计行 --> <view class="card-stats"> <text class="stat-text">已邀请: {{item.invitedCount}}</text> <text class="stat-text">已添加: {{item.acceptedCount}}</text> </view> <!-- 展开区域 --> <view wx:if="{{item.isExpanded}}" class="card-body"> <!-- 输入区 --> <view class="input-row"> <input type="text" placeholder="客户备注" value="{{item.tempRemark}}" bindinput="onRemarkInput" data-id="{{item.id}}" class="remark-input" /> <button class="add-invite-btn" bindtap="addInvite" data-id="{{item.id}}">添加邀请</button> </view> <!-- 邀请--> <view wx:for="{{item.invitations}}" wx:key="id" wx:for-item="invite" wx:for-index="idx" class="invite-item"> <block wx:if="{{!invite.accepted}}"> <!-- 显示:客户备注 + 时间 --> <text class="invite-text">{{invite.remark}} {{invite.time}}</text> <button class="accept-btn mini-btn" bindtap="acceptInvite" data-taskid="{{item.id}}" data-index="{{idx}}">已通过</button> <button class="delete-btn mini-btn" bindtap="deleteInvite" data-taskid="{{item.id}}" data-index="{{idx}}">删除</button> </block> <block wx:else> <text class="accepted-line">{{invite.remark}} 已通过</text> </block> </view> </view> </view> </block> <!-- 主添加按钮(当没有任务显示) --> <button wx:if="{{activeTasks.length === 0}}" class="add-task-btn" bindtap="onAddTask">添加任务</button> <!-- 弹窗遮罩层 --> <view class="modal-overlay" wx:if="{{showTaskModal}}" catchtouchmove="noop"> <view class="task-modal"> <!-- 搜索栏 --> <view class="search-bar"> <input type="text" placeholder="编号/微信名/业务员" value="{{searchKeyword}}" bindinput="onSearchInput" class="search-input" /> <text class="search-icon">🔍</text> <text class="clear-icon" wx:if="{{searchKeyword}}" catchtap="clearSearch">✕</text> </view> <!-- 排序选择 + 表头 --> <view class="header-row"> <picker mode="selector" range="{{sortOptions}}" range-key="name" value="{{sortIndex}}" bindchange="onSortChange"> <view class="sort-trigger"> {{sortOptions[sortIndex].name}} <text class="arrow-down">▼</text> </view> </picker> <text class="today-header">今日添加数</text> </view> <!-- 数据--> <scroll-view scroll-y class="data-list-container"> <block wx:for="{{displayList}}" wx:key="id"> <view class="data-item" catchtap="selectAccount" data-account="{{item}}"> <view class="col-id">{{item.tagId}}</view> <view class="col-tag orange-tag">{{item.wechatName || '—'}}</view> <view class="col-tag cyan-tag">{{item.salesman || '—'}}</view> <view class="col-count">0</view> </view> </block> <!-- 空数据提示 --> <view wx:if="{{displayList.length === 0}}" class="empty-tip">暂无匹配数据</view> </scroll-view> </view> </view> </view>/* pages/my/my.wxss */ .container { padding: 20rpx; position: relative; } /* 主按钮 */ .add-task-btn { width: 100%; background-color: #07c160; color: white; margin-bottom: 20rpx; font-size: 32rpx; } .mini { display: inline-block; width: auto; padding: 10rpx 20rpx; margin: 0 10rpx; font-size: 28rpx; } .clear-task-btn { background-color: #fa5151; color: white; float: right; } .task-header { display: flex; align-items: center; margin-bottom: 20rpx; } .add-task-btn.mini { background-color: #07c160; color: white; font-size: 28rpx; padding: 10rpx 30rpx; border-radius: 8rpx; margin-right: auto; /* 左对齐并拉开右边距 */ } /* 任务卡片 */ .task-card { background: #f9f9f9; border: 1px solid #ddd; border-radius: 12rpx; padding: 20rpx; margin-bottom: 20rpx; } .card-header { display: flex; justify-content: space-between; align-items: center; font-weight: bold; color: #333; } .card-id { color: #000; font-size: 32rpx; } .card-salesman { /* 绿色背景 + 白色文字 + 内边距 + 圆角 */ background-color: #07c160; color: white; padding: 6rpx 16rpx; border-radius: 6rpx; font-size: 24rpx; font-weight: normal; } .expand-arrow { font-size: 24rpx; color: #888; } .card-stats { margin-top: 10rpx; font-size: 24rpx; color: #888; } .stat-text { margin-right: 20rpx; } /* 输入行 */ .input-row { display: flex; margin-top: 20rpx; align-items: center; } .remark-input { flex: 1; height: 60rpx; border: 1px solid #ccc; border-radius: 8rpx; padding: 0 10rpx; font-size: 28rpx; margin-right: 10rpx; } .add-invite-btn { background-color: #1890ff; color: white; font-size: 28rpx; height: 60rpx; /* 和输入框同高 */ line-height: 60rpx; /* 垂直居中 */ padding: 0 20rpx; /* 控制宽度不要太宽 */ min-width: 100rpx; border-radius: 8rpx; } /* 邀请项 */ .invite-item { display: flex; justify-content: space-between; align-items: center; padding: 10rpx 0; border-bottom: 1px dashed #eee; font-size: 28rpx; } /* 客户名+时间 合并为一段文本,左对齐 */ .invite-text { flex: 1; color: #333; font-size: 28rpx; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; /* 禁止换行 */ } .accept-btn, .delete-btn { font-size: 24rpx; padding: 0 15rpx; height: 50rpx; line-height: 50rpx; } .accept-btn { background-color: #1890ff; color: white; height: 50rpx; } .delete-btn { background-color: #fa5151; color: white; } .accepted-text { color: #aaa; font-size: 24rpx; } /* 弹窗相关样式保持不变 */ .modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.5); display: flex; justify-content: center; align-items: center; z-index: 999; } .task-modal { width: 90%; max-height: 70%; background: white; border-radius: 16rpx; overflow: hidden; } .search-bar { display: flex; align-items: center; padding: 20rpx; position: relative; } .search-input { flex: 1; height: 60rpx; border: 1px solid #ddd; border-radius: 8rpx; padding: 0 60rpx; } .search-icon { position: absolute; left: 30rpx; color: #999; } .mini-btn { min-width: 60rpx !important; padding: 0 16rpx !important; height: 50rpx; line-height: 50rpx; font-size: 24rpx; margin: 0 0 0 10rpx; } .accepted-line { color: #aaa; font-size: 28rpx; flex: 1; } .clear-icon { position: absolute; right: 80rpx; color: #999; font-weight: bold; cursor: pointer; } .header-row { display: flex; justify-content: space-between; padding: 0 20rpx 20rpx; align-items: center; } .sort-trigger { display: flex; align-items: center; background: #f0f0f0; padding: 10rpx 20rpx; border-radius: 8rpx; font-size: 28rpx; } .arrow-down { margin-left: 10rpx; font-size: 20rpx; } .today-header { font-size: 24rpx; color: #666; } .data-list-container { max-height: 400rpx; height: 400rpx; } .data-item { display: flex; padding: 20rpx; border-bottom: 1px solid #eee; font-size: 28rpx; } .col-id { width: 15%; } .col-tag { padding: 6rpx 12rpx; border-radius: 6rpx; margin-right: 10rpx; } .orange-tag { background: #fff7e6; color: #faad14; } .cyan-tag { background: #e6fffb; color: #13c2c2; } .col-count { width: 20%; text-align: right; color: #999; } .empty-tip { text-align: center; color: #999; padding: 40rpx; } 同上 我现在看不到客户名字和时间 那个已通过和删除实在是太宽太长了
最新发布
01-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值