@ -0,0 +1,31 @@ | |||
/* | |||
* Eslint config file | |||
* Documentation: https://eslint.org/docs/user-guide/configuring/ | |||
* Install the Eslint extension before using this feature. | |||
*/ | |||
module.exports = { | |||
env: { | |||
es6: true, | |||
browser: true, | |||
node: true, | |||
}, | |||
ecmaFeatures: { | |||
modules: true, | |||
}, | |||
parserOptions: { | |||
ecmaVersion: 2018, | |||
sourceType: 'module', | |||
}, | |||
globals: { | |||
wx: true, | |||
App: true, | |||
Page: true, | |||
getCurrentPages: true, | |||
getApp: true, | |||
Component: true, | |||
requirePlugin: true, | |||
requireMiniProgram: true, | |||
}, | |||
// extends: 'eslint:recommended', | |||
rules: {}, | |||
} |
@ -0,0 +1,25 @@ | |||
let api={} | |||
api.openLock = "v1/device/isp/openLock" //远程开锁 | |||
api.oauthKey = "oauth/key" //验证码 | |||
api.login = "oauth/token" //登录 | |||
api.sendCommand = "v1/device/send/command" //通用接口 | |||
api.getuserInfo = "v1/account/user/info" //获取账户信息 | |||
api.getcardlist = "v1/card/get/list" //获取人员(卡)列表 | |||
api.getDeviceOperateUserInfo = "v1/device/isp/operateUserInfo" // 下发凭证用户命令 | |||
api.addCertificates = "v1/device/add/certificate" //添加凭证 | |||
api.getIntegration = "v1/card/get/integration" //获取首页列表 | |||
api.getSiteList = "v1/site/get/list" //获取房间列表信息 | |||
// api.getuserInfo = "v1/account/user/info"//获取用户信息 | |||
api.getDeviceItems = "v1/device/get/items"//获取设备 | |||
api.getTree = "v1/site/get/tree" //获取所有房源 | |||
api.bindDeviceSite = "v1/device/bind/site" // 绑定房间 | |||
api.unbindDeviceSite = "v1/device/unbind/site" // 解除绑定房间 | |||
api.getOpenRecord = "v1/device/get/open/record"//获取开门数据 | |||
api.addOpenRecord = "v1/device/add/openRecord"//添加开门记录 | |||
api.getSiteTenant = "v1/site/get/tenant" //获取已入住人员信息 | |||
api.addCard = "v1/card/add" //创建人员(卡) | |||
api.bindCard = "v1/site/bind/card" //绑定房间 | |||
api.queryList = "v1/card/query/list"//获取卡号(IMEI) | |||
export { | |||
api | |||
} |
@ -0,0 +1,166 @@ | |||
// app.js | |||
const app=getApp() | |||
const EventEmitter2 = require("./components/eventemitter2/index.js").EventEmitter2; | |||
const emitter = new EventEmitter2(); | |||
const WXAPI = require('./utils/request') | |||
const plugin = requirePlugin("myPlugin") | |||
App({ | |||
onLaunch() { | |||
this.globalData.sysinfo = wx.getSystemInfoSync() | |||
plugin.init('wx20de9fe5943934a1', '458f9df0-3405-66a9-1cdb-49d5f4197e6a') | |||
.then(function(res){ | |||
console.log('res', res) | |||
if(res.code != 200){ | |||
wx.showToast({ | |||
title: res.data.msg, | |||
}) | |||
} | |||
}) | |||
wx.login({ | |||
success (res) { | |||
if (res.code) { | |||
let data={ | |||
code:res.code | |||
} | |||
WXAPI.getOpenId(data).then(res=>{ | |||
console.log(res) | |||
wx.setStorageSync('openid', res.openid) | |||
}) | |||
} else { | |||
console.log('登录失败!' + res.errMsg) | |||
} | |||
} | |||
}) | |||
// 展示本地存储能力 | |||
var logs = wx.getStorageSync('token') || '' | |||
var userRole = wx.getStorageSync('userRole') || '' | |||
var signature= wx.getStorageSync('signature') || '' | |||
// 登录 | |||
if(logs!=''&&userRole==0){ | |||
this.globalData.token=logs.access_token | |||
setTimeout(()=>{ | |||
wx.switchTab({ | |||
url: '/pages/index/index', | |||
}) | |||
},100) | |||
} | |||
if(signature&&userRole==1){ | |||
wx.navigateTo({ | |||
url: '/pages/indexUser/indexUser', | |||
}) | |||
} | |||
}, | |||
getDeviceByDevName(devName) { | |||
return this.globalData.foundBleDevs[devName] | |||
}, | |||
addDeviceWithDevName(devName, dev) { | |||
this.globalData.foundBleDevs[devName] = dev | |||
}, | |||
connectTo: function(options) { | |||
console.debug('connectTo', options) | |||
if (typeof options !== 'object') { | |||
var message = '请求传参应为 object 类型,但实际传了 ' + (typeof options) + ' 类型'; | |||
throw new RequestError('invalid params', message); | |||
} | |||
var success = options.success || noop; | |||
var fail = options.fail || noop; | |||
var complete = options.complete || noop; | |||
// 成功回调 | |||
var callSuccess = function() { | |||
success.apply(null, arguments); | |||
complete.apply(null, arguments); | |||
}; | |||
// 失败回调 | |||
var callFail = function(error) { | |||
fail.call(null, error); | |||
complete.call(null, error); | |||
}; | |||
var that = this | |||
if (options.devName == undefined) { | |||
throw new RequestError('invalid params', 'options.devName'); | |||
} | |||
var bleDev = that.globalData.foundBleDevs[options.devName] | |||
console.log('bleDev', bleDev) | |||
if(bleDev == undefined){ | |||
throw new RequestError('dev not found', options.devName); | |||
} | |||
wx.showLoading({ | |||
mask: true, | |||
title: '连接中...', | |||
}) | |||
wx.createBLEConnection({ | |||
deviceId: bleDev.deviceId, | |||
timeout: 8000, | |||
success: function(res) { | |||
console.log('createBLEConnection success', res) | |||
wx.getBLEDeviceServices({ | |||
deviceId: bleDev.deviceId, | |||
success: function(res) { | |||
wx.getBLEDeviceCharacteristics({ | |||
deviceId: bleDev.deviceId, | |||
serviceId: config.uuid.serviceUuid.toUpperCase(), | |||
success: function(res) { | |||
wx.notifyBLECharacteristicValueChange({ | |||
deviceId: bleDev.deviceId, | |||
serviceId: config.uuid.serviceUuid.toUpperCase(), | |||
characteristicId: config.uuid.notifyUuid.toUpperCase(), | |||
state: true, | |||
success: function(res) { | |||
callSuccess() | |||
}, | |||
fail: function(res) { | |||
callFail(res) | |||
} | |||
}) | |||
}, | |||
fail: function(res) { | |||
callFail(res) | |||
} | |||
}) | |||
}, | |||
fail: function(res) { | |||
callFail(res) | |||
} | |||
}) | |||
}, | |||
fail: function(res) { | |||
console.log('createBLEConnection fail', res) | |||
wx.hideLoading() | |||
if (res.errMsg.indexOf('already connect') > 0) { | |||
callSuccess() | |||
} else { | |||
callFail(res) | |||
} | |||
} | |||
}) | |||
}, | |||
globalData: { | |||
userInfo: null, | |||
token:'', | |||
baseurl:'https://schoolsafety.zhiweisz.cn/', | |||
emitter:emitter,//全局订阅函数 | |||
ble: "", //全局蓝牙实例 | |||
blueStatus: false, | |||
userInfo: null, | |||
fingerprintId: -1,//指纹ID | |||
backdata: -1,//返回状态 | |||
openlock:-1,//蓝牙开锁返回状态 | |||
stop29:false, | |||
zgBlueStatus:false, | |||
blueDeviceId:'', | |||
deviceNum:'', | |||
tenantIdEnter:wx.getStorageSync('tenantId') || '100', | |||
sysinfo: null, | |||
foundBleDevs: {}, | |||
isSearch:false, | |||
isConnected:false, | |||
isInitReady:false | |||
} | |||
}) |
@ -0,0 +1,107 @@ | |||
{ | |||
"pages": [ | |||
"pages/login/login", | |||
"pages/index/index", | |||
"pages/my/my", | |||
"pages/logs/logs", | |||
"pages/register/register", | |||
"pages/roomDetail/roomDetail", | |||
"pages/openLockLog/openLockLog", | |||
"pages/permissions/permissions", | |||
"pages/bindLock/bindLock", | |||
"pages/personManger/personManger", | |||
"pages/addperson/addperson", | |||
"pages/updateWord/updateWord", | |||
"pages/modelselection/modelselection", | |||
"pages/Bluetooth1/Bluetooth1", | |||
"pages/changeLock/changeLock", | |||
"pages/Bluetooth/Bluetooth", | |||
"pages/selectPersonnel/selectPersonnel", | |||
"pages/addBlueButton/addBlueButton", | |||
"pages/userbluetoothUnlock/userbluetoothUnlock", | |||
"pages/indexUser/indexUser", | |||
"pages/config/config", | |||
"pages/rentDetail/rentDetail", | |||
"pages/rentManagement/rentManagement", | |||
"pages/paymentInterface/paymentInterface" | |||
], | |||
"subPackages": [ | |||
{ | |||
"root": "pagesA", | |||
"pages": [ | |||
"forgetpasswoed/forgetpasswoed", | |||
"installLock/installLock", | |||
"passwordList/passwordList", | |||
"facepeople/facepeople", | |||
"faceinfo/faceinfo", | |||
"selectFace/selectFace", | |||
"newconstructionitem/newconstructionitem", | |||
"activatePayment/activatePayment" | |||
] | |||
} | |||
], | |||
"window": { | |||
"backgroundTextStyle": "light", | |||
"navigationBarBackgroundColor": "#02BFFF", | |||
"navigationBarTitleText": "智慧公寓管理系统", | |||
"navigationBarTextStyle": "white" | |||
}, | |||
"plugins": { | |||
"myPlugin": { | |||
"version": "1.7.0", | |||
"provider": "wx8c85a8eeaad80bbf" | |||
} | |||
}, | |||
"tabBar": { | |||
"color": "#333", | |||
"selectedColor": "#00C1D1", | |||
"list": [ | |||
{ | |||
"pagePath": "pages/index/index", | |||
"iconPath": "./static/home1.png", | |||
"selectedIconPath": "./static/home.png", | |||
"text": "首页" | |||
}, | |||
{ | |||
"pagePath": "pages/my/my", | |||
"iconPath": "./static/my1.png", | |||
"selectedIconPath": "./static/my.png", | |||
"text": "我的" | |||
} | |||
] | |||
}, | |||
"usingComponents": { | |||
"van-button": "./components/dist/button/index", | |||
"van-field": "./components/dist/field/index", | |||
"van-search": "./components/dist/search/index", | |||
"van-card": "./components/dist/card/index", | |||
"van-datetime-picker": "./components/dist/datetime-picker/index", | |||
"van-cell": "./components/dist/cell/index", | |||
"van-cell-group": "./components/dist/cell-group/index", | |||
"van-popup": "./components/dist/popup/index", | |||
"van-radio": "./components/dist/radio/index", | |||
"van-radio-group": "./components/dist/radio-group/index", | |||
"van-dialog": "./components/dist/dialog/index", | |||
"van-sidebar": "./components/dist/sidebar/index", | |||
"van-sidebar-item": "./components/dist/sidebar-item/index", | |||
"van-steps": "./components/dist/steps/index", | |||
"van-action-sheet": "./components/dist/action-sheet/index", | |||
"van-tree-select": "./components/dist/tree-select/index", | |||
"van-tab": "./components/dist/tab/index", | |||
"van-tabs": "./components/dist/tabs/index", | |||
"van-empty": "./components/dist/empty/index", | |||
"van-icon": "./components/dist/icon/index", | |||
"van-image": "./components/dist/image/index" | |||
}, | |||
"onReachBottomDistance": 100, | |||
"permission": { | |||
"scope.userLocation": { | |||
"desc": "你的位置信息将用于获取蓝牙连接" | |||
} | |||
}, | |||
"requiredPrivateInfos":[ | |||
"getLocation" | |||
], | |||
"lazyCodeLoading": "requiredComponents", | |||
"sitemapLocation": "sitemap.json" | |||
} |
@ -0,0 +1,160 @@ | |||
/**app.wxss**/ | |||
/* @import "./static/css/iconfont/iconfont.wxss"; */ | |||
@import "./static/css/iconfont/iconfont.wxss"; | |||
@import "./static//css/common.wxss"; | |||
.container { | |||
height: 100%; | |||
display: flex; | |||
flex-direction: column; | |||
align-items: center; | |||
justify-content: space-between; | |||
padding: 200rpx 0; | |||
box-sizing: border-box; | |||
} | |||
.box-sizing-border{ | |||
box-sizing: border-box; | |||
} | |||
.position-relative{ | |||
position: relative; | |||
} | |||
.position-absolute{ | |||
position: absolute; | |||
} | |||
.position-fixed{ | |||
position: fixed; | |||
top: 0; | |||
left: 0; | |||
width: 100%; | |||
z-index: 99; | |||
} | |||
.position-sticky{ | |||
position: sticky; | |||
} | |||
.d-flex{ | |||
display: flex; | |||
flex-wrap: wrap; | |||
} | |||
.d-line{ | |||
display: inline; | |||
} | |||
.d-inline-block{ | |||
display: inline-block; | |||
} | |||
.align-center{ | |||
align-items: center; | |||
} | |||
.justify-content-between{ | |||
justify-content: space-between; | |||
} | |||
.bg-fff{ | |||
background: #fff; | |||
} | |||
.bg-000{ | |||
background: #000; | |||
} | |||
.pb-2{ | |||
padding-bottom: 8px; | |||
} | |||
.pa-1{ | |||
padding: 4px; | |||
} | |||
.pa-2{ | |||
padding: 8px; | |||
} | |||
.px-2{ | |||
padding-left: 8px; | |||
padding-right: 8px; | |||
} | |||
.py-2{ | |||
padding-top: 8px; | |||
padding-bottom: 8px; | |||
} | |||
.py-3{ | |||
padding-top: 12px; | |||
padding-bottom: 12px; | |||
} | |||
.ma-2{ | |||
margin: 8px; | |||
} | |||
.ma-4{ | |||
margin: 15px; | |||
} | |||
.mt-43{ | |||
margin-top: 172px; | |||
} | |||
.mb-1{ | |||
margin-bottom: 4px; | |||
} | |||
.mb-4{ | |||
margin-bottom: 16px; | |||
} | |||
.ml-1{ | |||
margin-left: 4px; | |||
} | |||
.ml-2{ | |||
margin-left: 8px; | |||
} | |||
.border-all{ | |||
border: 1px solid #f2f3f5; | |||
} | |||
.b-line{ | |||
border-bottom: 2rpx solid #eee; | |||
} | |||
/* 文字不超过一行 */ | |||
.text-ellipsis{ | |||
overflow: hidden; | |||
width: 100%; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
} | |||
/* 百分比宽度 */ | |||
.w-50{ | |||
width: 50%; | |||
} | |||
.w-80{ | |||
width: 80%; | |||
} | |||
.w-100{ | |||
width: 100%; | |||
} | |||
.height-percentage-100{ | |||
height: 100%; | |||
} | |||
.width-percentage-100{ | |||
width: 100%; | |||
} | |||
/* 字体大小 */ | |||
.font-size-10{ | |||
font-size: 10px; | |||
} | |||
.font-size-12{ | |||
font-size: 24rpx; | |||
} | |||
.font-size-14{ | |||
font-size: 28rpx; | |||
} | |||
.font-size-16{ | |||
font-size: 32rpx; | |||
} | |||
.font-size-28{ | |||
font-size: 28px; | |||
} | |||
/* 字体颜色 */ | |||
.color-red{ | |||
color: red; | |||
} | |||
.color-orange{ | |||
color: #f37b1d; | |||
} | |||
.color-green{ | |||
color: green; | |||
} | |||
.color-fff{ | |||
color: #fff; | |||
} | |||
.color-333{ | |||
color: #333; | |||
} |
@ -0,0 +1,35 @@ | |||
// components/Uploader.js | |||
Component({ | |||
/** | |||
* 组件的属性列表 | |||
*/ | |||
properties: { | |||
fileList: { | |||
type: Array, | |||
value: [] | |||
}, | |||
info: { | |||
type: Object, | |||
value: {url:'',text:''} | |||
} | |||
}, | |||
/** | |||
* 组件的初始数据 | |||
*/ | |||
data: { | |||
}, | |||
/** | |||
* 组件的方法列表 | |||
*/ | |||
methods: { | |||
afterRead(e){ | |||
this.triggerEvent('afterRead',e) | |||
}, | |||
deleteImg(e){ | |||
this.triggerEvent('deleteImg',e) | |||
} | |||
} | |||
}) |
@ -0,0 +1,6 @@ | |||
{ | |||
"component": true, | |||
"usingComponents": { | |||
"van-uploader": "../dist/uploader/index" | |||
} | |||
} |
@ -0,0 +1,8 @@ | |||
<!--components/Uploader.wxml--> | |||
<van-uploader preview-image="{{ true }}" preview-full-image="{{true}}" max-count="1" capture file-list="{{ fileList }}" bind:after-read="afterRead" bind:delete="deleteImg"> | |||
<image src="{{info.url}}" mode="widthFix" alt="" wx:if="{{ fileList.length === 0 }}"></image> | |||
<view class="position-absolute idCard-absolute" wx:if="{{ fileList.length === 0 }}"> | |||
<van-icon name="photograph" color="#1989fa" size="20" /> | |||
<view class="font-size-12 font-weight-600">{{info.text}}</view> | |||
</view> | |||
</van-uploader> |
@ -0,0 +1,26 @@ | |||
/* components/Uploader.wxss */ | |||
.position-absolute{ | |||
position: absolute; | |||
} | |||
.font-size-14{ | |||
font-size: 14px; | |||
} | |||
.font-size-12{ | |||
font-size: 12px; | |||
} | |||
.font-weight-600{ | |||
font-weight: 600; | |||
} | |||
.idCard van-uploader{ | |||
display: inline-block; | |||
width: 100%; | |||
} | |||
.idCard van-uploader image{ | |||
width: 49vw; | |||
} | |||
.idCard-absolute{ | |||
left: 50%; | |||
top: 50%; | |||
width: 80%; | |||
transform: translateX(-50%) translateY(-50%); | |||
} |
@ -0,0 +1 @@ | |||
export {}; |
@ -0,0 +1,70 @@ | |||
import { VantComponent } from '../common/component'; | |||
import { button } from '../mixins/button'; | |||
VantComponent({ | |||
mixins: [button], | |||
props: { | |||
show: Boolean, | |||
title: String, | |||
cancelText: String, | |||
description: String, | |||
round: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
zIndex: { | |||
type: Number, | |||
value: 100, | |||
}, | |||
actions: { | |||
type: Array, | |||
value: [], | |||
}, | |||
overlay: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
closeOnClickOverlay: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
closeOnClickAction: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
safeAreaInsetBottom: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
}, | |||
methods: { | |||
onSelect(event) { | |||
const { index } = event.currentTarget.dataset; | |||
const { actions, closeOnClickAction, canIUseGetUserProfile } = this.data; | |||
const item = actions[index]; | |||
if (item) { | |||
this.$emit('select', item); | |||
if (closeOnClickAction) { | |||
this.onClose(); | |||
} | |||
if (item.openType === 'getUserInfo' && canIUseGetUserProfile) { | |||
wx.getUserProfile({ | |||
desc: item.getUserProfileDesc || ' ', | |||
complete: (userProfile) => { | |||
this.$emit('getuserinfo', userProfile); | |||
}, | |||
}); | |||
} | |||
} | |||
}, | |||
onCancel() { | |||
this.$emit('cancel'); | |||
}, | |||
onClose() { | |||
this.$emit('close'); | |||
}, | |||
onClickOverlay() { | |||
this.$emit('click-overlay'); | |||
this.onClose(); | |||
}, | |||
}, | |||
}); |
@ -0,0 +1,8 @@ | |||
{ | |||
"component": true, | |||
"usingComponents": { | |||
"van-icon": "../icon/index", | |||
"van-popup": "../popup/index", | |||
"van-loading": "../loading/index" | |||
} | |||
} |
@ -0,0 +1,69 @@ | |||
<wxs src="../wxs/utils.wxs" module="utils" /> | |||
<van-popup | |||
show="{{ show }}" | |||
position="bottom" | |||
round="{{ round }}" | |||
z-index="{{ zIndex }}" | |||
overlay="{{ overlay }}" | |||
custom-class="van-action-sheet" | |||
safe-area-inset-bottom="{{ safeAreaInsetBottom }}" | |||
close-on-click-overlay="{{ closeOnClickOverlay }}" | |||
bind:close="onClickOverlay" | |||
> | |||
<view wx:if="{{ title }}" class="van-action-sheet__header"> | |||
{{ title }} | |||
<van-icon | |||
name="cross" | |||
custom-class="van-action-sheet__close" | |||
bind:click="onClose" | |||
/> | |||
</view> | |||
<view wx:if="{{ description }}" class="van-action-sheet__description van-hairline--bottom"> | |||
{{ description }} | |||
</view> | |||
<view wx:if="{{ actions && actions.length }}"> | |||
<!-- button外包一层view,防止actions动态变化,导致渲染时button被打散 --> | |||
<button | |||
wx:for="{{ actions }}" | |||
wx:key="index" | |||
open-type="{{ item.disabled || item.loading || (canIUseGetUserProfile && item.openType === 'getUserInfo') ? '' : item.openType }}" | |||
style="{{ item.color ? 'color: ' + item.color : '' }}" | |||
class="{{ utils.bem('action-sheet__item', { disabled: item.disabled || item.loading }) }} {{ item.className || '' }}" | |||
hover-class="van-action-sheet__item--hover" | |||
data-index="{{ index }}" | |||
bindtap="{{ item.disabled || item.loading ? '' : 'onSelect' }}" | |||
bindgetuserinfo="onGetUserInfo" | |||
bindcontact="onContact" | |||
bindgetphonenumber="onGetPhoneNumber" | |||
binderror="onError" | |||
bindlaunchapp="onLaunchApp" | |||
bindopensetting="onOpenSetting" | |||
lang="{{ lang }}" | |||
session-from="{{ sessionFrom }}" | |||
send-message-title="{{ sendMessageTitle }}" | |||
send-message-path="{{ sendMessagePath }}" | |||
send-message-img="{{ sendMessageImg }}" | |||
show-message-card="{{ showMessageCard }}" | |||
app-parameter="{{ appParameter }}" | |||
> | |||
<block wx:if="{{ !item.loading }}"> | |||
{{ item.name }} | |||
<view wx:if="{{ item.subname }}" class="van-action-sheet__subname" >{{ item.subname }}</view> | |||
</block> | |||
<van-loading wx:else custom-class="van-action-sheet__loading" size="22px" /> | |||
</button> | |||
</view> | |||
<slot /> | |||
<block wx:if="{{ cancelText }}"> | |||
<view class="van-action-sheet__gap" /> | |||
<view | |||
class="van-action-sheet__cancel" | |||
hover-class="van-action-sheet__cancel--hover" | |||
hover-stay-time="70" | |||
bind:tap="onCancel" | |||
> | |||
{{ cancelText }} | |||
</view> | |||
</block> | |||
</van-popup> |
@ -0,0 +1 @@ | |||
@import '../common/index.wxss';.van-action-sheet{color:var(--action-sheet-item-text-color,#323233);max-height:var(--action-sheet-max-height,90%)!important}.van-action-sheet__cancel,.van-action-sheet__item{background-color:var(--action-sheet-item-background,#fff);font-size:var(--action-sheet-item-font-size,16px);line-height:var(--action-sheet-item-line-height,22px);padding:14px 16px;text-align:center}.van-action-sheet__cancel--hover,.van-action-sheet__item--hover{background-color:#f2f3f5}.van-action-sheet__cancel:after,.van-action-sheet__item:after{border-width:0}.van-action-sheet__cancel{color:var(--action-sheet-cancel-text-color,#646566)}.van-action-sheet__gap{background-color:var(--action-sheet-cancel-padding-color,#f7f8fa);display:block;height:var(--action-sheet-cancel-padding-top,8px)}.van-action-sheet__item--disabled{color:var(--action-sheet-item-disabled-text-color,#c8c9cc)}.van-action-sheet__item--disabled.van-action-sheet__item--hover{background-color:var(--action-sheet-item-background,#fff)}.van-action-sheet__subname{color:var(--action-sheet-subname-color,#969799);font-size:var(--action-sheet-subname-font-size,12px);line-height:var(--action-sheet-subname-line-height,20px);margin-top:var(--padding-xs,8px)}.van-action-sheet__header{font-size:var(--action-sheet-header-font-size,16px);font-weight:var(--font-weight-bold,500);line-height:var(--action-sheet-header-height,48px);text-align:center}.van-action-sheet__description{color:var(--action-sheet-description-color,#969799);font-size:var(--action-sheet-description-font-size,14px);line-height:var(--action-sheet-description-line-height,20px);padding:20px var(--padding-md,16px);text-align:center}.van-action-sheet__close{color:var(--action-sheet-close-icon-color,#c8c9cc);font-size:var(--action-sheet-close-icon-size,22px)!important;line-height:inherit!important;padding:var(--action-sheet-close-icon-padding,0 16px);position:absolute!important;right:0;top:0}.van-action-sheet__loading{display:flex!important} |
@ -0,0 +1 @@ | |||
export {}; |
@ -0,0 +1,217 @@ | |||
import { VantComponent } from '../common/component'; | |||
import { pickerProps } from '../picker/shared'; | |||
import { requestAnimationFrame } from '../common/utils'; | |||
const EMPTY_CODE = '000000'; | |||
VantComponent({ | |||
classes: ['active-class', 'toolbar-class', 'column-class'], | |||
props: Object.assign(Object.assign({}, pickerProps), { value: { | |||
type: String, | |||
observer(value) { | |||
this.code = value; | |||
this.setValues(); | |||
}, | |||
}, areaList: { | |||
type: Object, | |||
value: {}, | |||
observer: 'setValues', | |||
}, columnsNum: { | |||
type: null, | |||
value: 3, | |||
}, columnsPlaceholder: { | |||
type: Array, | |||
observer(val) { | |||
this.setData({ | |||
typeToColumnsPlaceholder: { | |||
province: val[0] || '', | |||
city: val[1] || '', | |||
county: val[2] || '', | |||
}, | |||
}); | |||
}, | |||
} }), | |||
data: { | |||
columns: [{ values: [] }, { values: [] }, { values: [] }], | |||
typeToColumnsPlaceholder: {}, | |||
}, | |||
mounted() { | |||
requestAnimationFrame(() => { | |||
this.setValues(); | |||
}); | |||
}, | |||
methods: { | |||
getPicker() { | |||
if (this.picker == null) { | |||
this.picker = this.selectComponent('.van-area__picker'); | |||
} | |||
return this.picker; | |||
}, | |||
onCancel(event) { | |||
this.emit('cancel', event.detail); | |||
}, | |||
onConfirm(event) { | |||
const { index } = event.detail; | |||
let { value } = event.detail; | |||
value = this.parseValues(value); | |||
this.emit('confirm', { value, index }); | |||
}, | |||
emit(type, detail) { | |||
detail.values = detail.value; | |||
delete detail.value; | |||
this.$emit(type, detail); | |||
}, | |||
parseValues(values) { | |||
const { columnsPlaceholder } = this.data; | |||
return values.map((value, index) => { | |||
if (value && | |||
(!value.code || value.name === columnsPlaceholder[index])) { | |||
return Object.assign(Object.assign({}, value), { code: '', name: '' }); | |||
} | |||
return value; | |||
}); | |||
}, | |||
onChange(event) { | |||
var _a; | |||
const { index, picker, value } = event.detail; | |||
this.code = value[index].code; | |||
(_a = this.setValues()) === null || _a === void 0 ? void 0 : _a.then(() => { | |||
this.$emit('change', { | |||
picker, | |||
values: this.parseValues(picker.getValues()), | |||
index, | |||
}); | |||
}); | |||
}, | |||
getConfig(type) { | |||
const { areaList } = this.data; | |||
return (areaList && areaList[`${type}_list`]) || {}; | |||
}, | |||
getList(type, code) { | |||
if (type !== 'province' && !code) { | |||
return []; | |||
} | |||
const { typeToColumnsPlaceholder } = this.data; | |||
const list = this.getConfig(type); | |||
let result = Object.keys(list).map((code) => ({ | |||
code, | |||
name: list[code], | |||
})); | |||
if (code != null) { | |||
// oversea code | |||
if (code[0] === '9' && type === 'city') { | |||
code = '9'; | |||
} | |||
result = result.filter((item) => item.code.indexOf(code) === 0); | |||
} | |||
if (typeToColumnsPlaceholder[type] && result.length) { | |||
// set columns placeholder | |||
const codeFill = type === 'province' | |||
? '' | |||
: type === 'city' | |||
? EMPTY_CODE.slice(2, 4) | |||
: EMPTY_CODE.slice(4, 6); | |||
result.unshift({ | |||
code: `${code}${codeFill}`, | |||
name: typeToColumnsPlaceholder[type], | |||
}); | |||
} | |||
return result; | |||
}, | |||
getIndex(type, code) { | |||
let compareNum = type === 'province' ? 2 : type === 'city' ? 4 : 6; | |||
const list = this.getList(type, code.slice(0, compareNum - 2)); | |||
// oversea code | |||
if (code[0] === '9' && type === 'province') { | |||
compareNum = 1; | |||
} | |||
code = code.slice(0, compareNum); | |||
for (let i = 0; i < list.length; i++) { | |||
if (list[i].code.slice(0, compareNum) === code) { | |||
return i; | |||
} | |||
} | |||
return 0; | |||
}, | |||
setValues() { | |||
const picker = this.getPicker(); | |||
if (!picker) { | |||
return; | |||
} | |||
let code = this.code || this.getDefaultCode(); | |||
const provinceList = this.getList('province'); | |||
const cityList = this.getList('city', code.slice(0, 2)); | |||
const stack = []; | |||
const indexes = []; | |||
const { columnsNum } = this.data; | |||
if (columnsNum >= 1) { | |||
stack.push(picker.setColumnValues(0, provinceList, false)); | |||
indexes.push(this.getIndex('province', code)); | |||
} | |||
if (columnsNum >= 2) { | |||
stack.push(picker.setColumnValues(1, cityList, false)); | |||
indexes.push(this.getIndex('city', code)); | |||
if (cityList.length && code.slice(2, 4) === '00') { | |||
[{ code }] = cityList; | |||
} | |||
} | |||
if (columnsNum === 3) { | |||
stack.push(picker.setColumnValues(2, this.getList('county', code.slice(0, 4)), false)); | |||
indexes.push(this.getIndex('county', code)); | |||
} | |||
return Promise.all(stack) | |||
.catch(() => { }) | |||
.then(() => picker.setIndexes(indexes)) | |||
.catch(() => { }); | |||
}, | |||
getDefaultCode() { | |||
const { columnsPlaceholder } = this.data; | |||
if (columnsPlaceholder.length) { | |||
return EMPTY_CODE; | |||
} | |||
const countyCodes = Object.keys(this.getConfig('county')); | |||
if (countyCodes[0]) { | |||
return countyCodes[0]; | |||
} | |||
const cityCodes = Object.keys(this.getConfig('city')); | |||
if (cityCodes[0]) { | |||
return cityCodes[0]; | |||
} | |||
return ''; | |||
}, | |||
getValues() { | |||
const picker = this.getPicker(); | |||
if (!picker) { | |||
return []; | |||
} | |||
return this.parseValues(picker.getValues().filter((value) => !!value)); | |||
}, | |||
getDetail() { | |||
const values = this.getValues(); | |||
const area = { | |||
code: '', | |||
country: '', | |||
province: '', | |||
city: '', | |||
county: '', | |||
}; | |||
if (!values.length) { | |||
return area; | |||
} | |||
const names = values.map((item) => item.name); | |||
area.code = values[values.length - 1].code; | |||
if (area.code[0] === '9') { | |||
area.country = names[1] || ''; | |||
area.province = names[2] || ''; | |||
} | |||
else { | |||
area.province = names[0] || ''; | |||
area.city = names[1] || ''; | |||
area.county = names[2] || ''; | |||
} | |||
return area; | |||
}, | |||
reset(code) { | |||
this.code = code || ''; | |||
return this.setValues(); | |||
}, | |||
}, | |||
}); |
@ -0,0 +1,6 @@ | |||
{ | |||
"component": true, | |||
"usingComponents": { | |||
"van-picker": "../picker/index" | |||
} | |||
} |
@ -0,0 +1,20 @@ | |||
<wxs src="./index.wxs" module="computed" /> | |||
<van-picker | |||
class="van-area__picker" | |||
active-class="active-class" | |||
toolbar-class="toolbar-class" | |||
column-class="column-class" | |||
show-toolbar | |||
value-key="name" | |||
title="{{ title }}" | |||
loading="{{ loading }}" | |||
columns="{{ computed.displayColumns(columns, columnsNum) }}" | |||
item-height="{{ itemHeight }}" | |||
visible-item-count="{{ visibleItemCount }}" | |||
cancel-button-text="{{ cancelButtonText }}" | |||
confirm-button-text="{{ confirmButtonText }}" | |||
bind:change="onChange" | |||
bind:confirm="onConfirm" | |||
bind:cancel="onCancel" | |||
/> |
@ -0,0 +1,8 @@ | |||
/* eslint-disable */ | |||
function displayColumns(columns, columnsNum) { | |||
return columns.slice(0, +columnsNum); | |||
} | |||
module.exports = { | |||
displayColumns: displayColumns, | |||
}; |
@ -0,0 +1 @@ | |||
@import '../common/index.wxss'; |
@ -0,0 +1 @@ | |||
export {}; |
@ -0,0 +1,64 @@ | |||
import { VantComponent } from '../common/component'; | |||
import { button } from '../mixins/button'; | |||
import { canIUseFormFieldButton } from '../common/version'; | |||
const mixins = [button]; | |||
if (canIUseFormFieldButton()) { | |||
mixins.push('wx://form-field-button'); | |||
} | |||
VantComponent({ | |||
mixins, | |||
classes: ['hover-class', 'loading-class'], | |||
data: { | |||
baseStyle: '', | |||
}, | |||
props: { | |||
formType: String, | |||
icon: String, | |||
classPrefix: { | |||
type: String, | |||
value: 'van-icon', | |||
}, | |||
plain: Boolean, | |||
block: Boolean, | |||
round: Boolean, | |||
square: Boolean, | |||
loading: Boolean, | |||
hairline: Boolean, | |||
disabled: Boolean, | |||
loadingText: String, | |||
customStyle: String, | |||
loadingType: { | |||
type: String, | |||
value: 'circular', | |||
}, | |||
type: { | |||
type: String, | |||
value: 'default', | |||
}, | |||
dataset: null, | |||
size: { | |||
type: String, | |||
value: 'normal', | |||
}, | |||
loadingSize: { | |||
type: String, | |||
value: '20px', | |||
}, | |||
color: String, | |||
}, | |||
methods: { | |||
onClick(event) { | |||
this.$emit('click', event); | |||
const { canIUseGetUserProfile, openType, getUserProfileDesc, lang, } = this.data; | |||
if (openType === 'getUserInfo' && canIUseGetUserProfile) { | |||
wx.getUserProfile({ | |||
desc: getUserProfileDesc || ' ', | |||
lang: lang || 'en', | |||
complete: (userProfile) => { | |||
this.$emit('getuserinfo', userProfile); | |||
}, | |||
}); | |||
} | |||
}, | |||
}, | |||
}); |
@ -0,0 +1,7 @@ | |||
{ | |||
"component": true, | |||
"usingComponents": { | |||
"van-icon": "../icon/index", | |||
"van-loading": "../loading/index" | |||
} | |||
} |
@ -0,0 +1,53 @@ | |||
<wxs src="../wxs/utils.wxs" module="utils" /> | |||
<wxs src="./index.wxs" module="computed" /> | |||
<button | |||
id="{{ id }}" | |||
data-detail="{{ dataset }}" | |||
class="custom-class {{ utils.bem('button', [type, size, { block, round, plain, square, loading, disabled, hairline, unclickable: disabled || loading }]) }} {{ hairline ? 'van-hairline--surround' : '' }}" | |||
hover-class="van-button--active hover-class" | |||
lang="{{ lang }}" | |||
form-type="{{ formType }}" | |||
style="{{ computed.rootStyle({ plain, color, customStyle }) }}" | |||
open-type="{{ disabled || loading || (canIUseGetUserProfile && openType === 'getUserInfo') ? '' : openType }}" | |||
business-id="{{ businessId }}" | |||
session-from="{{ sessionFrom }}" | |||
send-message-title="{{ sendMessageTitle }}" | |||
send-message-path="{{ sendMessagePath }}" | |||
send-message-img="{{ sendMessageImg }}" | |||
show-message-card="{{ showMessageCard }}" | |||
app-parameter="{{ appParameter }}" | |||
aria-label="{{ ariaLabel }}" | |||
bindtap="{{ disabled || loading ? '' : 'onClick' }}" | |||
bindgetuserinfo="onGetUserInfo" | |||
bindcontact="onContact" | |||
bindgetphonenumber="onGetPhoneNumber" | |||
binderror="onError" | |||
bindlaunchapp="onLaunchApp" | |||
bindopensetting="onOpenSetting" | |||
> | |||
<block wx:if="{{ loading }}"> | |||
<van-loading | |||
custom-class="loading-class" | |||
size="{{ loadingSize }}" | |||
type="{{ loadingType }}" | |||
color="{{ computed.loadingColor({ type, color, plain }) }}" | |||
/> | |||
<view wx:if="{{ loadingText }}" class="van-button__loading-text"> | |||
{{ loadingText }} | |||
</view> | |||
</block> | |||
<block wx:else> | |||
<van-icon | |||
wx:if="{{ icon }}" | |||
size="1.2em" | |||
name="{{ icon }}" | |||
class-prefix="{{ classPrefix }}" | |||
class="van-button__icon" | |||
custom-style="line-height: inherit;" | |||
/> | |||
<view class="van-button__text"> | |||
<slot /> | |||
</view> | |||
</block> | |||
</button> |
@ -0,0 +1,39 @@ | |||
/* eslint-disable */ | |||
var style = require('../wxs/style.wxs'); | |||
function rootStyle(data) { | |||
if (!data.color) { | |||
return data.customStyle; | |||
} | |||
var properties = { | |||
color: data.plain ? data.color : '#fff', | |||
background: data.plain ? null : data.color, | |||
}; | |||
// hide border when color is linear-gradient | |||
if (data.color.indexOf('gradient') !== -1) { | |||
properties.border = 0; | |||
} else { | |||
properties['border-color'] = data.color; | |||
} | |||
return style([properties, data.customStyle]); | |||
} | |||
function loadingColor(data) { | |||
if (data.plain) { | |||
return data.color ? data.color : '#c9c9c9'; | |||
} | |||
if (data.type === 'default') { | |||
return '#c9c9c9'; | |||
} | |||
return '#fff'; | |||
} | |||
module.exports = { | |||
rootStyle: rootStyle, | |||
loadingColor: loadingColor, | |||
}; |
@ -0,0 +1 @@ | |||
@import '../common/index.wxss';.van-button{-webkit-text-size-adjust:100%;align-items:center;-webkit-appearance:none;border-radius:var(--button-border-radius,2px);box-sizing:border-box;display:inline-flex;font-size:var(--button-default-font-size,16px);height:var(--button-default-height,44px);justify-content:center;line-height:var(--button-line-height,20px);padding:0;position:relative;text-align:center;transition:opacity .2s;vertical-align:middle}.van-button:before{background-color:#000;border:inherit;border-color:#000;border-radius:inherit;content:" ";height:100%;left:50%;opacity:0;position:absolute;top:50%;transform:translate(-50%,-50%);width:100%}.van-button:after{border-width:0}.van-button--active:before{opacity:.15}.van-button--unclickable:after{display:none}.van-button--default{background:var(--button-default-background-color,#fff);border:var(--button-border-width,1px) solid var(--button-default-border-color,#ebedf0);color:var(--button-default-color,#323233)}.van-button--primary{background:var(--button-primary-background-color,#07c160);border:var(--button-border-width,1px) solid var(--button-primary-border-color,#07c160);color:var(--button-primary-color,#fff)}.van-button--info{background:var(--button-info-background-color,#1989fa);border:var(--button-border-width,1px) solid var(--button-info-border-color,#1989fa);color:var(--button-info-color,#fff)}.van-button--danger{background:var(--button-danger-background-color,#ee0a24);border:var(--button-border-width,1px) solid var(--button-danger-border-color,#ee0a24);color:var(--button-danger-color,#fff)}.van-button--warning{background:var(--button-warning-background-color,#ff976a);border:var(--button-border-width,1px) solid var(--button-warning-border-color,#ff976a);color:var(--button-warning-color,#fff)}.van-button--plain{background:var(--button-plain-background-color,#fff)}.van-button--plain.van-button--primary{color:var(--button-primary-background-color,#07c160)}.van-button--plain.van-button--info{color:var(--button-info-background-color,#1989fa)}.van-button--plain.van-button--danger{color:var(--button-danger-background-color,#ee0a24)}.van-button--plain.van-button--warning{color:var(--button-warning-background-color,#ff976a)}.van-button--large{height:var(--button-large-height,50px);width:100%}.van-button--normal{font-size:var(--button-normal-font-size,14px);padding:0 15px}.van-button--small{font-size:var(--button-small-font-size,12px);height:var(--button-small-height,30px);min-width:var(--button-small-min-width,60px);padding:0 var(--padding-xs,8px)}.van-button--mini{display:inline-block;font-size:var(--button-mini-font-size,10px);height:var(--button-mini-height,22px);min-width:var(--button-mini-min-width,50px)}.van-button--mini+.van-button--mini{margin-left:5px}.van-button--block{display:flex;width:100%}.van-button--round{border-radius:var(--button-round-border-radius,999px)}.van-button--square{border-radius:0}.van-button--disabled{opacity:var(--button-disabled-opacity,.5)}.van-button__text{display:inline}.van-button__icon+.van-button__text:not(:empty),.van-button__loading-text{margin-left:4px}.van-button__icon{line-height:inherit!important;min-width:1em;vertical-align:top}.van-button--hairline{border-width:0;padding-top:1px}.van-button--hairline:after{border-color:inherit;border-radius:calc(var(--button-border-radius, 2px)*2);border-width:1px}.van-button--hairline.van-button--round:after{border-radius:var(--button-round-border-radius,999px)}.van-button--hairline.van-button--square:after{border-radius:0} |
@ -0,0 +1,68 @@ | |||
<view class="van-calendar"> | |||
<header | |||
title="{{ title }}" | |||
showTitle="{{ showTitle }}" | |||
subtitle="{{ subtitle }}" | |||
showSubtitle="{{ showSubtitle }}" | |||
firstDayOfWeek="{{ firstDayOfWeek }}" | |||
bind:click-subtitle="onClickSubtitle" | |||
> | |||
<slot name="title" slot="title"></slot> | |||
</header> | |||
<scroll-view | |||
class="van-calendar__body" | |||
scroll-y | |||
scroll-into-view="{{ scrollIntoView }}" | |||
> | |||
<month | |||
wx:for="{{ computed.getMonths(minDate, maxDate) }}" | |||
wx:key="index" | |||
id="month{{ index }}" | |||
class="month" | |||
data-date="{{ item }}" | |||
date="{{ item }}" | |||
type="{{ type }}" | |||
color="{{ color }}" | |||
minDate="{{ minDate }}" | |||
maxDate="{{ maxDate }}" | |||
showMark="{{ showMark }}" | |||
formatter="{{ formatter }}" | |||
rowHeight="{{ rowHeight }}" | |||
currentDate="{{ currentDate }}" | |||
showSubtitle="{{ showSubtitle }}" | |||
allowSameDay="{{ allowSameDay }}" | |||
showMonthTitle="{{ index !== 0 || !showSubtitle }}" | |||
firstDayOfWeek="{{ firstDayOfWeek }}" | |||
bind:click="onClickDay" | |||
/> | |||
</scroll-view> | |||
<view | |||
class="{{ utils.bem('calendar__footer', { safeAreaInsetBottom }) }}" | |||
> | |||
<slot name="footer"></slot> | |||
</view> | |||
<view | |||
class="{{ utils.bem('calendar__footer', { safeAreaInsetBottom }) }}" | |||
> | |||
<van-button | |||
wx:if="{{ showConfirm }}" | |||
round | |||
block | |||
type="danger" | |||
color="{{ color }}" | |||
custom-class="van-calendar__confirm" | |||
disabled="{{ computed.getButtonDisabled(type, currentDate) }}" | |||
nativeType="text" | |||
bind:click="onConfirm" | |||
> | |||
{{ | |||
computed.getButtonDisabled(type, currentDate) | |||
? confirmDisabledText | |||
: confirmText | |||
}} | |||
</van-button> | |||
</view> | |||
</view> |
@ -0,0 +1 @@ | |||
export {}; |
@ -0,0 +1,37 @@ | |||
import { VantComponent } from '../../../common/component'; | |||
VantComponent({ | |||
props: { | |||
title: { | |||
type: String, | |||
value: '日期选择', | |||
}, | |||
subtitle: String, | |||
showTitle: Boolean, | |||
showSubtitle: Boolean, | |||
firstDayOfWeek: { | |||
type: Number, | |||
observer: 'initWeekDay', | |||
}, | |||
}, | |||
data: { | |||
weekdays: [], | |||
}, | |||
created() { | |||
this.initWeekDay(); | |||
}, | |||
methods: { | |||
initWeekDay() { | |||
const defaultWeeks = ['日', '一', '二', '三', '四', '五', '六']; | |||
const firstDayOfWeek = this.data.firstDayOfWeek || 0; | |||
this.setData({ | |||
weekdays: [ | |||
...defaultWeeks.slice(firstDayOfWeek, 7), | |||
...defaultWeeks.slice(0, firstDayOfWeek), | |||
], | |||
}); | |||
}, | |||
onClickSubtitle(event) { | |||
this.$emit('click-subtitle', event); | |||
}, | |||
}, | |||
}); |
@ -0,0 +1,3 @@ | |||
{ | |||
"component": true | |||
} |
@ -0,0 +1,16 @@ | |||
<view class="van-calendar__header"> | |||
<block wx:if="{{ showTitle }}"> | |||
<view class="van-calendar__header-title"><slot name="title"></slot></view> | |||
<view class="van-calendar__header-title">{{ title }}</view> | |||
</block> | |||
<view wx:if="{{ showSubtitle }}" class="van-calendar__header-subtitle" bind:tap="onClickSubtitle"> | |||
{{ subtitle }} | |||
</view> | |||
<view class="van-calendar__weekdays"> | |||
<view wx:for="{{ weekdays }}" wx:key="index" class="van-calendar__weekday"> | |||
{{ item }} | |||
</view> | |||
</view> | |||
</view> |
@ -0,0 +1 @@ | |||
@import '../../../common/index.wxss';.van-calendar__header{box-shadow:var(--calendar-header-box-shadow,0 2px 10px hsla(220,1%,50%,.16));flex-shrink:0}.van-calendar__header-subtitle,.van-calendar__header-title{font-weight:var(--font-weight-bold,500);height:var(--calendar-header-title-height,44px);line-height:var(--calendar-header-title-height,44px);text-align:center}.van-calendar__header-title+.van-calendar__header-title,.van-calendar__header-title:empty{display:none}.van-calendar__header-title:empty+.van-calendar__header-title{display:block!important}.van-calendar__weekdays{display:flex}.van-calendar__weekday{flex:1;font-size:var(--calendar-weekdays-font-size,12px);line-height:var(--calendar-weekdays-height,30px);text-align:center} |
@ -0,0 +1,6 @@ | |||
export interface Day { | |||
date: Date; | |||
type: string; | |||
text: number; | |||
bottomInfo?: string; | |||
} |
@ -0,0 +1,154 @@ | |||
import { VantComponent } from '../../../common/component'; | |||
import { getMonthEndDay, compareDay, getPrevDay, getNextDay, } from '../../utils'; | |||
VantComponent({ | |||
props: { | |||
date: { | |||
type: null, | |||
observer: 'setDays', | |||
}, | |||
type: { | |||
type: String, | |||
observer: 'setDays', | |||
}, | |||
color: String, | |||
minDate: { | |||
type: null, | |||
observer: 'setDays', | |||
}, | |||
maxDate: { | |||
type: null, | |||
observer: 'setDays', | |||
}, | |||
showMark: Boolean, | |||
rowHeight: null, | |||
formatter: { | |||
type: null, | |||
observer: 'setDays', | |||
}, | |||
currentDate: { | |||
type: null, | |||
observer: 'setDays', | |||
}, | |||
firstDayOfWeek: { | |||
type: Number, | |||
observer: 'setDays', | |||
}, | |||
allowSameDay: Boolean, | |||
showSubtitle: Boolean, | |||
showMonthTitle: Boolean, | |||
}, | |||
data: { | |||
visible: true, | |||
days: [], | |||
}, | |||
methods: { | |||
onClick(event) { | |||
const { index } = event.currentTarget.dataset; | |||
const item = this.data.days[index]; | |||
if (item.type !== 'disabled') { | |||
this.$emit('click', item); | |||
} | |||
}, | |||
setDays() { | |||
const days = []; | |||
const startDate = new Date(this.data.date); | |||
const year = startDate.getFullYear(); | |||
const month = startDate.getMonth(); | |||
const totalDay = getMonthEndDay(startDate.getFullYear(), startDate.getMonth() + 1); | |||
for (let day = 1; day <= totalDay; day++) { | |||
const date = new Date(year, month, day); | |||
const type = this.getDayType(date); | |||
let config = { | |||
date, | |||
type, | |||
text: day, | |||
bottomInfo: this.getBottomInfo(type), | |||
}; | |||
if (this.data.formatter) { | |||
config = this.data.formatter(config); | |||
} | |||
days.push(config); | |||
} | |||
this.setData({ days }); | |||
}, | |||
getMultipleDayType(day) { | |||
const { currentDate } = this.data; | |||
if (!Array.isArray(currentDate)) { | |||
return ''; | |||
} | |||
const isSelected = (date) => currentDate.some((item) => compareDay(item, date) === 0); | |||
if (isSelected(day)) { | |||
const prevDay = getPrevDay(day); | |||
const nextDay = getNextDay(day); | |||
const prevSelected = isSelected(prevDay); | |||
const nextSelected = isSelected(nextDay); | |||
if (prevSelected && nextSelected) { | |||
return 'multiple-middle'; | |||
} | |||
if (prevSelected) { | |||
return 'end'; | |||
} | |||
return nextSelected ? 'start' : 'multiple-selected'; | |||
} | |||
return ''; | |||
}, | |||
getRangeDayType(day) { | |||
const { currentDate, allowSameDay } = this.data; | |||
if (!Array.isArray(currentDate)) { | |||
return ''; | |||
} | |||
const [startDay, endDay] = currentDate; | |||
if (!startDay) { | |||
return ''; | |||
} | |||
const compareToStart = compareDay(day, startDay); | |||
if (!endDay) { | |||
return compareToStart === 0 ? 'start' : ''; | |||
} | |||
const compareToEnd = compareDay(day, endDay); | |||
if (compareToStart === 0 && compareToEnd === 0 && allowSameDay) { | |||
return 'start-end'; | |||
} | |||
if (compareToStart === 0) { | |||
return 'start'; | |||
} | |||
if (compareToEnd === 0) { | |||
return 'end'; | |||
} | |||
if (compareToStart > 0 && compareToEnd < 0) { | |||
return 'middle'; | |||
} | |||
return ''; | |||
}, | |||
getDayType(day) { | |||
const { type, minDate, maxDate, currentDate } = this.data; | |||
if (compareDay(day, minDate) < 0 || compareDay(day, maxDate) > 0) { | |||
return 'disabled'; | |||
} | |||
if (type === 'single') { | |||
return compareDay(day, currentDate) === 0 ? 'selected' : ''; | |||
} | |||
if (type === 'multiple') { | |||
return this.getMultipleDayType(day); | |||
} | |||
/* istanbul ignore else */ | |||
if (type === 'range') { | |||
return this.getRangeDayType(day); | |||
} | |||
return ''; | |||
}, | |||
getBottomInfo(type) { | |||
if (this.data.type === 'range') { | |||
if (type === 'start') { | |||
return '开始'; | |||
} | |||
if (type === 'end') { | |||
return '结束'; | |||
} | |||
if (type === 'start-end') { | |||
return '开始/结束'; | |||
} | |||
} | |||
}, | |||
}, | |||
}); |
@ -0,0 +1,3 @@ | |||
{ | |||
"component": true | |||
} |
@ -0,0 +1,39 @@ | |||
<wxs src="./index.wxs" module="computed"></wxs> | |||
<wxs src="../../../wxs/utils.wxs" module="utils" /> | |||
<view class="van-calendar__month" style="{{ computed.getMonthStyle(visible, date, rowHeight) }}"> | |||
<view wx:if="{{ showMonthTitle }}" class="van-calendar__month-title"> | |||
{{ computed.formatMonthTitle(date) }} | |||
</view> | |||
<view wx:if="{{ visible }}" class="van-calendar__days"> | |||
<view wx:if="{{ showMark }}" class="van-calendar__month-mark"> | |||
{{ computed.getMark(date) }} | |||
</view> | |||
<view | |||
wx:for="{{ days }}" | |||
wx:key="index" | |||
style="{{ computed.getDayStyle(item.type, index, date, rowHeight, color, firstDayOfWeek) }}" | |||
class="{{ utils.bem('calendar__day', [item.type]) }} {{ item.className }}" | |||
data-index="{{ index }}" | |||
bindtap="onClick" | |||
> | |||
<view wx:if="{{ item.type === 'selected' }}" class="van-calendar__selected-day" style="background: {{ color }}"> | |||
<view wx:if="{{ item.topInfo }}" class="van-calendar__top-info">{{ item.topInfo }}</view> | |||
{{ item.text }} | |||
<view wx:if="{{ item.bottomInfo }}" class="van-calendar__bottom-info"> | |||
{{ item.bottomInfo }} | |||
</view> | |||
</view> | |||
<view wx:else> | |||
<view wx:if="{{ item.topInfo }}" class="van-calendar__top-info">{{ item.topInfo }}</view> | |||
{{ item.text }} | |||
<view wx:if="{{ item.bottomInfo }}" class="van-calendar__bottom-info"> | |||
{{ item.bottomInfo }} | |||
</view> | |||
</view> | |||
</view> | |||
</view> | |||
</view> |
@ -0,0 +1,71 @@ | |||
/* eslint-disable */ | |||
var utils = require('../../utils.wxs'); | |||
function getMark(date) { | |||
return getDate(date).getMonth() + 1; | |||
} | |||
var ROW_HEIGHT = 64; | |||
function getDayStyle(type, index, date, rowHeight, color, firstDayOfWeek) { | |||
var style = []; | |||
var current = getDate(date).getDay() || 7; | |||
var offset = current < firstDayOfWeek ? (7 - firstDayOfWeek + current) : | |||
current === 7 && firstDayOfWeek === 0 ? 0 : | |||
(current - firstDayOfWeek); | |||
if (index === 0) { | |||
style.push(['margin-left', (100 * offset) / 7 + '%']); | |||
} | |||
if (rowHeight !== ROW_HEIGHT) { | |||
style.push(['height', rowHeight + 'px']); | |||
} | |||
if (color) { | |||
if ( | |||
type === 'start' || | |||
type === 'end' || | |||
type === 'start-end' || | |||
type === 'multiple-selected' || | |||
type === 'multiple-middle' | |||
) { | |||
style.push(['background', color]); | |||
} else if (type === 'middle') { | |||
style.push(['color', color]); | |||
} | |||
} | |||
return style | |||
.map(function(item) { | |||
return item.join(':'); | |||
}) | |||
.join(';'); | |||
} | |||
function formatMonthTitle(date) { | |||
date = getDate(date); | |||
return date.getFullYear() + '年' + (date.getMonth() + 1) + '月'; | |||
} | |||
function getMonthStyle(visible, date, rowHeight) { | |||
if (!visible) { | |||
date = getDate(date); | |||
var totalDay = utils.getMonthEndDay( | |||
date.getFullYear(), | |||
date.getMonth() + 1 | |||
); | |||
var offset = getDate(date).getDay(); | |||
var padding = Math.ceil((totalDay + offset) / 7) * rowHeight; | |||
return 'padding-bottom:' + padding + 'px'; | |||
} | |||
} | |||
module.exports = { | |||
getMark: getMark, | |||
getDayStyle: getDayStyle, | |||
formatMonthTitle: formatMonthTitle, | |||
getMonthStyle: getMonthStyle | |||
}; |
@ -0,0 +1 @@ | |||
@import '../../../common/index.wxss';.van-calendar{background-color:var(--calendar-background-color,#fff);display:flex;flex-direction:column;height:100%}.van-calendar__month-title{font-size:var(--calendar-month-title-font-size,14px);font-weight:var(--font-weight-bold,500);height:var(--calendar-header-title-height,44px);line-height:var(--calendar-header-title-height,44px);text-align:center}.van-calendar__days{display:flex;flex-wrap:wrap;position:relative;-webkit-user-select:none;user-select:none}.van-calendar__month-mark{color:var(--calendar-month-mark-color,rgba(242,243,245,.8));font-size:var(--calendar-month-mark-font-size,160px);left:50%;pointer-events:none;position:absolute;top:50%;transform:translate(-50%,-50%);z-index:0}.van-calendar__day,.van-calendar__selected-day{align-items:center;display:flex;justify-content:center;text-align:center}.van-calendar__day{font-size:var(--calendar-day-font-size,16px);height:var(--calendar-day-height,64px);position:relative;width:14.285%}.van-calendar__day--end,.van-calendar__day--multiple-middle,.van-calendar__day--multiple-selected,.van-calendar__day--start,.van-calendar__day--start-end{background-color:var(--calendar-range-edge-background-color,#ee0a24);color:var(--calendar-range-edge-color,#fff)}.van-calendar__day--start{border-radius:4px 0 0 4px}.van-calendar__day--end{border-radius:0 4px 4px 0}.van-calendar__day--multiple-selected,.van-calendar__day--start-end{border-radius:4px}.van-calendar__day--middle{color:var(--calendar-range-middle-color,#ee0a24)}.van-calendar__day--middle:after{background-color:currentColor;bottom:0;content:"";left:0;opacity:var(--calendar-range-middle-background-opacity,.1);position:absolute;right:0;top:0}.van-calendar__day--disabled{color:var(--calendar-day-disabled-color,#c8c9cc);cursor:default}.van-calendar__bottom-info,.van-calendar__top-info{font-size:var(--calendar-info-font-size,10px);left:0;line-height:var(--calendar-info-line-height,14px);position:absolute;right:0}@media (max-width:350px){.van-calendar__bottom-info,.van-calendar__top-info{font-size:9px}}.van-calendar__top-info{top:6px}.van-calendar__bottom-info{bottom:6px}.van-calendar__selected-day{background-color:var(--calendar-selected-day-background-color,#ee0a24);border-radius:4px;color:var(--calendar-selected-day-color,#fff);height:var(--calendar-selected-day-size,54px);width:var(--calendar-selected-day-size,54px)} |
@ -0,0 +1 @@ | |||
export {}; |
@ -0,0 +1,337 @@ | |||
import { VantComponent } from '../common/component'; | |||
import { ROW_HEIGHT, getPrevDay, getNextDay, getToday, compareDay, copyDates, calcDateNum, formatMonthTitle, compareMonth, getMonths, getDayByOffset, } from './utils'; | |||
import Toast from '../toast/toast'; | |||
import { requestAnimationFrame } from '../common/utils'; | |||
const initialMinDate = getToday().getTime(); | |||
const initialMaxDate = (() => { | |||
const now = getToday(); | |||
return new Date(now.getFullYear(), now.getMonth() + 6, now.getDate()).getTime(); | |||
})(); | |||
const getTime = (date) => date instanceof Date ? date.getTime() : date; | |||
VantComponent({ | |||
props: { | |||
title: { | |||
type: String, | |||
value: '日期选择', | |||
}, | |||
color: String, | |||
show: { | |||
type: Boolean, | |||
observer(val) { | |||
if (val) { | |||
this.initRect(); | |||
this.scrollIntoView(); | |||
} | |||
}, | |||
}, | |||
formatter: null, | |||
confirmText: { | |||
type: String, | |||
value: '确定', | |||
}, | |||
confirmDisabledText: { | |||
type: String, | |||
value: '确定', | |||
}, | |||
rangePrompt: String, | |||
showRangePrompt: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
defaultDate: { | |||
type: null, | |||
observer(val) { | |||
this.setData({ currentDate: val }); | |||
this.scrollIntoView(); | |||
}, | |||
}, | |||
allowSameDay: Boolean, | |||
type: { | |||
type: String, | |||
value: 'single', | |||
observer: 'reset', | |||
}, | |||
minDate: { | |||
type: Number, | |||
value: initialMinDate, | |||
}, | |||
maxDate: { | |||
type: Number, | |||
value: initialMaxDate, | |||
}, | |||
position: { | |||
type: String, | |||
value: 'bottom', | |||
}, | |||
rowHeight: { | |||
type: null, | |||
value: ROW_HEIGHT, | |||
}, | |||
round: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
poppable: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
showMark: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
showTitle: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
showConfirm: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
showSubtitle: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
safeAreaInsetBottom: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
closeOnClickOverlay: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
maxRange: { | |||
type: null, | |||
value: null, | |||
}, | |||
firstDayOfWeek: { | |||
type: Number, | |||
value: 0, | |||
}, | |||
readonly: Boolean, | |||
}, | |||
data: { | |||
subtitle: '', | |||
currentDate: null, | |||
scrollIntoView: '', | |||
}, | |||
created() { | |||
this.setData({ | |||
currentDate: this.getInitialDate(this.data.defaultDate), | |||
}); | |||
}, | |||
mounted() { | |||
if (this.data.show || !this.data.poppable) { | |||
this.initRect(); | |||
this.scrollIntoView(); | |||
} | |||
}, | |||
methods: { | |||
reset() { | |||
this.setData({ currentDate: this.getInitialDate() }); | |||
this.scrollIntoView(); | |||
}, | |||
initRect() { | |||
if (this.contentObserver != null) { | |||
this.contentObserver.disconnect(); | |||
} | |||
const contentObserver = this.createIntersectionObserver({ | |||
thresholds: [0, 0.1, 0.9, 1], | |||
observeAll: true, | |||
}); | |||
this.contentObserver = contentObserver; | |||
contentObserver.relativeTo('.van-calendar__body'); | |||
contentObserver.observe('.month', (res) => { | |||
if (res.boundingClientRect.top <= res.relativeRect.top) { | |||
// @ts-ignore | |||
this.setData({ subtitle: formatMonthTitle(res.dataset.date) }); | |||
} | |||
}); | |||
}, | |||
limitDateRange(date, minDate = null, maxDate = null) { | |||
minDate = minDate || this.data.minDate; | |||
maxDate = maxDate || this.data.maxDate; | |||
if (compareDay(date, minDate) === -1) { | |||
return minDate; | |||
} | |||
if (compareDay(date, maxDate) === 1) { | |||
return maxDate; | |||
} | |||
return date; | |||
}, | |||
getInitialDate(defaultDate = null) { | |||
const { type, minDate, maxDate } = this.data; | |||
const now = getToday().getTime(); | |||
if (type === 'range') { | |||
if (!Array.isArray(defaultDate)) { | |||
defaultDate = []; | |||
} | |||
const [startDay, endDay] = defaultDate || []; | |||
const start = this.limitDateRange(startDay || now, minDate, getPrevDay(new Date(maxDate)).getTime()); | |||
const end = this.limitDateRange(endDay || now, getNextDay(new Date(minDate)).getTime()); | |||
return [start, end]; | |||
} | |||
if (type === 'multiple') { | |||
if (Array.isArray(defaultDate)) { | |||
return defaultDate.map((date) => this.limitDateRange(date)); | |||
} | |||
return [this.limitDateRange(now)]; | |||
} | |||
if (!defaultDate || Array.isArray(defaultDate)) { | |||
defaultDate = now; | |||
} | |||
return this.limitDateRange(defaultDate); | |||
}, | |||
scrollIntoView() { | |||
requestAnimationFrame(() => { | |||
const { currentDate, type, show, poppable, minDate, maxDate } = this.data; | |||
// @ts-ignore | |||
const targetDate = type === 'single' ? currentDate : currentDate[0]; | |||
const displayed = show || !poppable; | |||
if (!targetDate || !displayed) { | |||
return; | |||
} | |||
const months = getMonths(minDate, maxDate); | |||
months.some((month, index) => { | |||
if (compareMonth(month, targetDate) === 0) { | |||
this.setData({ scrollIntoView: `month${index}` }); | |||
return true; | |||
} | |||
return false; | |||
}); | |||
}); | |||
}, | |||
onOpen() { | |||
this.$emit('open'); | |||
}, | |||
onOpened() { | |||
this.$emit('opened'); | |||
}, | |||
onClose() { | |||
this.$emit('close'); | |||
}, | |||
onClosed() { | |||
this.$emit('closed'); | |||
}, | |||
onClickDay(event) { | |||
if (this.data.readonly) { | |||
return; | |||
} | |||
let { date } = event.detail; | |||
const { type, currentDate, allowSameDay } = this.data; | |||
if (type === 'range') { | |||
// @ts-ignore | |||
const [startDay, endDay] = currentDate; | |||
if (startDay && !endDay) { | |||
const compareToStart = compareDay(date, startDay); | |||
if (compareToStart === 1) { | |||
const { days } = this.selectComponent('.month').data; | |||
days.some((day, index) => { | |||
const isDisabled = day.type === 'disabled' && | |||
getTime(startDay) < getTime(day.date) && | |||
getTime(day.date) < getTime(date); | |||
if (isDisabled) { | |||
({ date } = days[index - 1]); | |||
} | |||
return isDisabled; | |||
}); | |||
this.select([startDay, date], true); | |||
} | |||
else if (compareToStart === -1) { | |||
this.select([date, null]); | |||
} | |||
else if (allowSameDay) { | |||
this.select([date, date]); | |||
} | |||
} | |||
else { | |||
this.select([date, null]); | |||
} | |||
} | |||
else if (type === 'multiple') { | |||
let selectedIndex; | |||
// @ts-ignore | |||
const selected = currentDate.some((dateItem, index) => { | |||
const equal = compareDay(dateItem, date) === 0; | |||
if (equal) { | |||
selectedIndex = index; | |||
} | |||
return equal; | |||
}); | |||
if (selected) { | |||
// @ts-ignore | |||
const cancelDate = currentDate.splice(selectedIndex, 1); | |||
this.setData({ currentDate }); | |||
this.unselect(cancelDate); | |||
} | |||
else { | |||
// @ts-ignore | |||
this.select([...currentDate, date]); | |||
} | |||
} | |||
else { | |||
this.select(date, true); | |||
} | |||
}, | |||
unselect(dateArray) { | |||
const date = dateArray[0]; | |||
if (date) { | |||
this.$emit('unselect', copyDates(date)); | |||
} | |||
}, | |||
select(date, complete) { | |||
if (complete && this.data.type === 'range') { | |||
const valid = this.checkRange(date); | |||
if (!valid) { | |||
// auto selected to max range if showConfirm | |||
if (this.data.showConfirm) { | |||
this.emit([ | |||
date[0], | |||
getDayByOffset(date[0], this.data.maxRange - 1), | |||
]); | |||
} | |||
else { | |||
this.emit(date); | |||
} | |||
return; | |||
} | |||
} | |||
this.emit(date); | |||
if (complete && !this.data.showConfirm) { | |||
this.onConfirm(); | |||
} | |||
}, | |||
emit(date) { | |||
this.setData({ | |||
currentDate: Array.isArray(date) ? date.map(getTime) : getTime(date), | |||
}); | |||
this.$emit('select', copyDates(date)); | |||
}, | |||
checkRange(date) { | |||
const { maxRange, rangePrompt, showRangePrompt } = this.data; | |||
if (maxRange && calcDateNum(date) > maxRange) { | |||
if (showRangePrompt) { | |||
Toast({ | |||
context: this, | |||
message: rangePrompt || `选择天数不能超过 ${maxRange} 天`, | |||
}); | |||
} | |||
this.$emit('over-range'); | |||
return false; | |||
} | |||
return true; | |||
}, | |||
onConfirm() { | |||
if (this.data.type === 'range' && | |||
!this.checkRange(this.data.currentDate)) { | |||
return; | |||
} | |||
wx.nextTick(() => { | |||
// @ts-ignore | |||
this.$emit('confirm', copyDates(this.data.currentDate)); | |||
}); | |||
}, | |||
onClickSubtitle(event) { | |||
this.$emit('click-subtitle', event); | |||
}, | |||
}, | |||
}); |
@ -0,0 +1,10 @@ | |||
{ | |||
"component": true, | |||
"usingComponents": { | |||
"header": "./components/header/index", | |||
"month": "./components/month/index", | |||
"van-button": "../button/index", | |||
"van-popup": "../popup/index", | |||
"van-toast": "../toast/index" | |||
} | |||
} |
@ -0,0 +1,25 @@ | |||
<wxs src="./index.wxs" module="computed" /> | |||
<wxs src="../wxs/utils.wxs" module="utils" /> | |||
<import src="./calendar.wxml" /> | |||
<van-popup | |||
wx:if="{{ poppable }}" | |||
custom-class="van-calendar__popup--{{ position }}" | |||
close-icon-class="van-calendar__close-icon" | |||
show="{{ show }}" | |||
round="{{ round }}" | |||
position="{{ position }}" | |||
closeable="{{ showTitle || showSubtitle }}" | |||
close-on-click-overlay="{{ closeOnClickOverlay }}" | |||
bind:enter="onOpen" | |||
bind:close="onClose" | |||
bind:after-enter="onOpened" | |||
bind:after-leave="onClosed" | |||
> | |||
<include src="./calendar.wxml" /> | |||
</van-popup> | |||
<include wx:else src="./calendar.wxml" /> | |||
<van-toast id="van-toast" /> |
@ -0,0 +1,37 @@ | |||
/* eslint-disable */ | |||
var utils = require('./utils.wxs'); | |||
function getMonths(minDate, maxDate) { | |||
var months = []; | |||
var cursor = getDate(minDate); | |||
cursor.setDate(1); | |||
do { | |||
months.push(cursor.getTime()); | |||
cursor.setMonth(cursor.getMonth() + 1); | |||
} while (utils.compareMonth(cursor, getDate(maxDate)) !== 1); | |||
return months; | |||
} | |||
function getButtonDisabled(type, currentDate) { | |||
if (currentDate == null) { | |||
return true; | |||
} | |||
if (type === 'range') { | |||
return !currentDate[0] || !currentDate[1]; | |||
} | |||
if (type === 'multiple') { | |||
return !currentDate.length; | |||
} | |||
return !currentDate; | |||
} | |||
module.exports = { | |||
getMonths: getMonths, | |||
getButtonDisabled: getButtonDisabled | |||
}; |
@ -0,0 +1 @@ | |||
@import '../common/index.wxss';.van-calendar{background-color:var(--calendar-background-color,#fff);display:flex;flex-direction:column;height:var(--calendar-height,100%)}.van-calendar__close-icon{top:11px}.van-calendar__popup--bottom,.van-calendar__popup--top{height:var(--calendar-popup-height,80%)}.van-calendar__popup--left,.van-calendar__popup--right{height:100%}.van-calendar__body{-webkit-overflow-scrolling:touch;flex:1;overflow:auto}.van-calendar__footer{flex-shrink:0;padding:0 var(--padding-md,16px)}.van-calendar__footer--safe-area-inset-bottom{padding-bottom:env(safe-area-inset-bottom)}.van-calendar__footer+.van-calendar__footer,.van-calendar__footer:empty{display:none}.van-calendar__footer:empty+.van-calendar__footer{display:block!important}.van-calendar__confirm{height:var(--calendar-confirm-button-height,36px)!important;line-height:var(--calendar-confirm-button-line-height,34px)!important;margin:var(--calendar-confirm-button-margin,7px 0)!important} |
@ -0,0 +1,12 @@ | |||
export declare const ROW_HEIGHT = 64; | |||
export declare function formatMonthTitle(date: Date): string; | |||
export declare function compareMonth(date1: Date | number, date2: Date | number): 1 | -1 | 0; | |||
export declare function compareDay(day1: Date | number, day2: Date | number): 1 | -1 | 0; | |||
export declare function getDayByOffset(date: Date, offset: number): Date; | |||
export declare function getPrevDay(date: Date): Date; | |||
export declare function getNextDay(date: Date): Date; | |||
export declare function getToday(): Date; | |||
export declare function calcDateNum(date: [Date, Date]): number; | |||
export declare function copyDates(dates: Date | Date[]): Date | Date[]; | |||
export declare function getMonthEndDay(year: number, month: number): number; | |||
export declare function getMonths(minDate: number, maxDate: number): number[]; |
@ -0,0 +1,83 @@ | |||
export const ROW_HEIGHT = 64; | |||
export function formatMonthTitle(date) { | |||
if (!(date instanceof Date)) { | |||
date = new Date(date); | |||
} | |||
return `${date.getFullYear()}年${date.getMonth() + 1}月`; | |||
} | |||
export function compareMonth(date1, date2) { | |||
if (!(date1 instanceof Date)) { | |||
date1 = new Date(date1); | |||
} | |||
if (!(date2 instanceof Date)) { | |||
date2 = new Date(date2); | |||
} | |||
const year1 = date1.getFullYear(); | |||
const year2 = date2.getFullYear(); | |||
const month1 = date1.getMonth(); | |||
const month2 = date2.getMonth(); | |||
if (year1 === year2) { | |||
return month1 === month2 ? 0 : month1 > month2 ? 1 : -1; | |||
} | |||
return year1 > year2 ? 1 : -1; | |||
} | |||
export function compareDay(day1, day2) { | |||
if (!(day1 instanceof Date)) { | |||
day1 = new Date(day1); | |||
} | |||
if (!(day2 instanceof Date)) { | |||
day2 = new Date(day2); | |||
} | |||
const compareMonthResult = compareMonth(day1, day2); | |||
if (compareMonthResult === 0) { | |||
const date1 = day1.getDate(); | |||
const date2 = day2.getDate(); | |||
return date1 === date2 ? 0 : date1 > date2 ? 1 : -1; | |||
} | |||
return compareMonthResult; | |||
} | |||
export function getDayByOffset(date, offset) { | |||
date = new Date(date); | |||
date.setDate(date.getDate() + offset); | |||
return date; | |||
} | |||
export function getPrevDay(date) { | |||
return getDayByOffset(date, -1); | |||
} | |||
export function getNextDay(date) { | |||
return getDayByOffset(date, 1); | |||
} | |||
export function getToday() { | |||
const today = new Date(); | |||
today.setHours(0, 0, 0, 0); | |||
return today; | |||
} | |||
export function calcDateNum(date) { | |||
const day1 = new Date(date[0]).getTime(); | |||
const day2 = new Date(date[1]).getTime(); | |||
return (day2 - day1) / (1000 * 60 * 60 * 24) + 1; | |||
} | |||
export function copyDates(dates) { | |||
if (Array.isArray(dates)) { | |||
return dates.map((date) => { | |||
if (date === null) { | |||
return date; | |||
} | |||
return new Date(date); | |||
}); | |||
} | |||
return new Date(dates); | |||
} | |||
export function getMonthEndDay(year, month) { | |||
return 32 - new Date(year, month - 1, 32).getDate(); | |||
} | |||
export function getMonths(minDate, maxDate) { | |||
const months = []; | |||
const cursor = new Date(minDate); | |||
cursor.setDate(1); | |||
do { | |||
months.push(cursor.getTime()); | |||
cursor.setMonth(cursor.getMonth() + 1); | |||
} while (compareMonth(cursor, maxDate) !== 1); | |||
return months; | |||
} |
@ -0,0 +1,25 @@ | |||
/* eslint-disable */ | |||
function getMonthEndDay(year, month) { | |||
return 32 - getDate(year, month - 1, 32).getDate(); | |||
} | |||
function compareMonth(date1, date2) { | |||
date1 = getDate(date1); | |||
date2 = getDate(date2); | |||
var year1 = date1.getFullYear(); | |||
var year2 = date2.getFullYear(); | |||
var month1 = date1.getMonth(); | |||
var month2 = date2.getMonth(); | |||
if (year1 === year2) { | |||
return month1 === month2 ? 0 : month1 > month2 ? 1 : -1; | |||
} | |||
return year1 > year2 ? 1 : -1; | |||
} | |||
module.exports = { | |||
getMonthEndDay: getMonthEndDay, | |||
compareMonth: compareMonth | |||
}; |
@ -0,0 +1 @@ | |||
export {}; |
@ -0,0 +1,49 @@ | |||
import { link } from '../mixins/link'; | |||
import { VantComponent } from '../common/component'; | |||
VantComponent({ | |||
classes: [ | |||
'num-class', | |||
'desc-class', | |||
'thumb-class', | |||
'title-class', | |||
'price-class', | |||
'origin-price-class', | |||
], | |||
mixins: [link], | |||
props: { | |||
tag: String, | |||
num: String, | |||
desc: String, | |||
thumb: String, | |||
title: String, | |||
price: { | |||
type: String, | |||
observer: 'updatePrice', | |||
}, | |||
centered: Boolean, | |||
lazyLoad: Boolean, | |||
thumbLink: String, | |||
originPrice: String, | |||
thumbMode: { | |||
type: String, | |||
value: 'aspectFit', | |||
}, | |||
currency: { | |||
type: String, | |||
value: '¥', | |||
}, | |||
}, | |||
methods: { | |||
updatePrice() { | |||
const { price } = this.data; | |||
const priceArr = price.toString().split('.'); | |||
this.setData({ | |||
integerStr: priceArr[0], | |||
decimalStr: priceArr[1] ? `.${priceArr[1]}` : '', | |||
}); | |||
}, | |||
onClickThumb() { | |||
this.jumpLink('thumbLink'); | |||
}, | |||
}, | |||
}); |
@ -0,0 +1,6 @@ | |||
{ | |||
"component": true, | |||
"usingComponents": { | |||
"van-tag": "../tag/index" | |||
} | |||
} |
@ -0,0 +1,56 @@ | |||
<wxs src="../wxs/utils.wxs" module="utils" /> | |||
<view class="custom-class van-card"> | |||
<view class="{{ utils.bem('card__header', { center: centered }) }}"> | |||
<view class="van-card__thumb" bind:tap="onClickThumb"> | |||
<image | |||
wx:if="{{ thumb }}" | |||
src="{{ thumb }}" | |||
mode="{{ thumbMode }}" | |||
lazy-load="{{ lazyLoad }}" | |||
class="van-card__img thumb-class" | |||
/> | |||
<slot wx:else name="thumb" /> | |||
<van-tag | |||
wx:if="{{ tag }}" | |||
mark | |||
type="danger" | |||
custom-class="van-card__tag" | |||
> | |||
{{ tag }} | |||
</van-tag> | |||
<slot wx:else name="tag" /> | |||
</view> | |||
<view class="van-card__content {{ utils.bem('card__content', { center: centered }) }}"> | |||
<view> | |||
<view wx:if="{{ title }}" class="van-card__title title-class">{{ title }}</view> | |||
<slot wx:else name="title" /> | |||
<view wx:if="{{ desc }}" class="van-card__desc desc-class">{{ desc }}</view> | |||
<slot wx:else name="desc" /> | |||
<slot name="tags" /> | |||
</view> | |||
<view class="van-card__bottom"> | |||
<slot name="price-top" /> | |||
<view wx:if="{{ price || price === 0 }}" class="van-card__price price-class"> | |||
<text>{{ currency }}</text> | |||
<text class="van-card__price-integer">{{ integerStr }}</text> | |||
<text class="van-card__price-decimal">{{ decimalStr }}</text> | |||
</view> | |||
<slot wx:else name="price" /> | |||
<view wx:if="{{ originPrice || originPrice === 0 }}" class="van-card__origin-price origin-price-class">{{ currency }} {{ originPrice }}</view> | |||
<slot wx:else name="origin-price" /> | |||
<view wx:if="{{ num }}" class="van-card__num num-class">x {{ num }}</view> | |||
<slot wx:else name="num" /> | |||
<slot name="bottom" /> | |||
</view> | |||
</view> | |||
</view> | |||
<view class="van-card__footer"> | |||
<slot name="footer" /> | |||
</view> | |||
</view> |
@ -0,0 +1 @@ | |||
@import '../common/index.wxss';.van-card{background-color:var(--card-background-color,#fafafa);box-sizing:border-box;color:var(--card-text-color,#323233);font-size:var(--card-font-size,12px);padding:var(--card-padding,8px 16px);position:relative}.van-card__header{display:flex}.van-card__header--center{align-items:center;justify-content:center}.van-card__thumb{flex:none;height:var(--card-thumb-size,88px);margin-right:var(--padding-xs,8px);position:relative;width:var(--card-thumb-size,88px)}.van-card__thumb:empty{display:none}.van-card__img{border-radius:8px;height:100%;width:100%}.van-card__content{display:flex;flex:1;flex-direction:column;justify-content:space-between;min-height:var(--card-thumb-size,88px);min-width:0;position:relative}.van-card__content--center{justify-content:center}.van-card__desc,.van-card__title{word-wrap:break-word}.van-card__title{font-weight:700;line-height:var(--card-title-line-height,16px)}.van-card__desc{color:var(--card-desc-color,#646566);line-height:var(--card-desc-line-height,20px)}.van-card__bottom{line-height:20px}.van-card__price{color:var(--card-price-color,#ee0a24);display:inline-block;font-size:var(--card-price-font-size,12px);font-weight:700}.van-card__price-integer{font-size:var(--card-price-integer-font-size,16px)}.van-card__price-decimal,.van-card__price-integer{font-family:var(--card-price-font-family,Avenir-Heavy,PingFang SC,Helvetica Neue,Arial,sans-serif)}.van-card__origin-price{color:var(--card-origin-price-color,#646566);display:inline-block;font-size:var(--card-origin-price-font-size,10px);margin-left:5px;text-decoration:line-through}.van-card__num{float:right}.van-card__tag{left:0;position:absolute!important;top:2px}.van-card__footer{flex:none;text-align:right;width:100%} |
@ -0,0 +1 @@ | |||
export {}; |
@ -0,0 +1,11 @@ | |||
import { VantComponent } from '../common/component'; | |||
VantComponent({ | |||
props: { | |||
title: String, | |||
border: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
inset: Boolean, | |||
}, | |||
}); |
@ -0,0 +1,3 @@ | |||
{ | |||
"component": true | |||
} |
@ -0,0 +1,11 @@ | |||
<wxs src="../wxs/utils.wxs" module="utils" /> | |||
<view | |||
wx:if="{{ title }}" | |||
class="{{ utils.bem('cell-group__title', { inset }) }}" | |||
> | |||
{{ title }} | |||
</view> | |||
<view class="custom-class {{ utils.bem('cell-group', { inset }) }} {{ border ? 'van-hairline--top-bottom' : '' }}"> | |||
<slot /> | |||
</view> |
@ -0,0 +1 @@ | |||
@import '../common/index.wxss';.van-cell-group--inset{border-radius:var(--cell-group-inset-border-radius,8px);margin:var(--cell-group-inset-padding,0 16px);overflow:hidden}.van-cell-group__title{color:var(--cell-group-title-color,#969799);font-size:var(--cell-group-title-font-size,14px);line-height:var(--cell-group-title-line-height,16px);padding:var(--cell-group-title-padding,16px 16px 8px)}.van-cell-group__title--inset{padding:var(--cell-group-inset-title-padding,16px 16px 8px 32px)} |
@ -0,0 +1 @@ | |||
export {}; |
@ -0,0 +1,38 @@ | |||
import { link } from '../mixins/link'; | |||
import { VantComponent } from '../common/component'; | |||
VantComponent({ | |||
classes: [ | |||
'title-class', | |||
'label-class', | |||
'value-class', | |||
'right-icon-class', | |||
'hover-class', | |||
], | |||
mixins: [link], | |||
props: { | |||
title: null, | |||
value: null, | |||
icon: String, | |||
size: String, | |||
label: String, | |||
center: Boolean, | |||
isLink: Boolean, | |||
required: Boolean, | |||
clickable: Boolean, | |||
titleWidth: String, | |||
customStyle: String, | |||
arrowDirection: String, | |||
useLabelSlot: Boolean, | |||
border: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
titleStyle: String, | |||
}, | |||
methods: { | |||
onClick(event) { | |||
this.$emit('click', event.detail); | |||
this.jumpLink(); | |||
}, | |||
}, | |||
}); |
@ -0,0 +1,6 @@ | |||
{ | |||
"component": true, | |||
"usingComponents": { | |||
"van-icon": "../icon/index" | |||
} | |||
} |
@ -0,0 +1,47 @@ | |||
<wxs src="../wxs/utils.wxs" module="utils" /> | |||
<wxs src="./index.wxs" module="computed" /> | |||
<view | |||
class="custom-class {{ utils.bem('cell', [size, { center, required, borderless: !border, clickable: isLink || clickable }]) }}" | |||
hover-class="van-cell--hover hover-class" | |||
hover-stay-time="70" | |||
style="{{ customStyle }}" | |||
bind:tap="onClick" | |||
> | |||
<van-icon | |||
wx:if="{{ icon }}" | |||
name="{{ icon }}" | |||
class="van-cell__left-icon-wrap" | |||
custom-class="van-cell__left-icon" | |||
/> | |||
<slot wx:else name="icon" /> | |||
<view | |||
style="{{ computed.titleStyle({ titleWidth, titleStyle }) }}" | |||
class="van-cell__title title-class" | |||
> | |||
<block wx:if="{{ title }}">{{ title }}</block> | |||
<slot wx:else name="title" /> | |||
<view wx:if="{{ label || useLabelSlot }}" class="van-cell__label label-class"> | |||
<slot wx:if="{{ useLabelSlot }}" name="label" /> | |||
<block wx:elif="{{ label }}">{{ label }}</block> | |||
</view> | |||
</view> | |||
<view class="van-cell__value value-class"> | |||
<block wx:if="{{ value || value === 0 }}">{{ value }}</block> | |||
<slot wx:else /> | |||
</view> | |||
<van-icon | |||
wx:if="{{ isLink }}" | |||
name="{{ arrowDirection ? 'arrow' + '-' + arrowDirection : 'arrow' }}" | |||
class="van-cell__right-icon-wrap right-icon-class" | |||
custom-class="van-cell__right-icon" | |||
/> | |||
<slot wx:else name="right-icon" /> | |||
<slot name="extra" /> | |||
</view> |
@ -0,0 +1,17 @@ | |||
/* eslint-disable */ | |||
var style = require('../wxs/style.wxs'); | |||
var addUnit = require('../wxs/add-unit.wxs'); | |||
function titleStyle(data) { | |||
return style([ | |||
{ | |||
'max-width': addUnit(data.titleWidth), | |||
'min-width': addUnit(data.titleWidth), | |||
}, | |||
data.titleStyle, | |||
]); | |||
} | |||
module.exports = { | |||
titleStyle: titleStyle, | |||
}; |
@ -0,0 +1 @@ | |||
@import '../common/index.wxss';.van-cell{background-color:var(--cell-background-color,#fff);box-sizing:border-box;color:var(--cell-text-color,#323233);display:flex;font-size:var(--cell-font-size,14px);line-height:var(--cell-line-height,24px);padding:var(--cell-vertical-padding,10px) var(--cell-horizontal-padding,16px);position:relative;width:100%}.van-cell:after{border-bottom:1px solid #ebedf0;bottom:0;box-sizing:border-box;content:" ";left:16px;pointer-events:none;position:absolute;right:16px;transform:scaleY(.5);transform-origin:center}.van-cell--borderless:after{display:none}.van-cell-group{background-color:var(--cell-background-color,#fff)}.van-cell__label{color:var(--cell-label-color,#969799);font-size:var(--cell-label-font-size,12px);line-height:var(--cell-label-line-height,18px);margin-top:var(--cell-label-margin-top,3px)}.van-cell__value{color:var(--cell-value-color,#969799);overflow:hidden;text-align:right;vertical-align:middle}.van-cell__title,.van-cell__value{flex:1}.van-cell__title:empty,.van-cell__value:empty{display:none}.van-cell__left-icon-wrap,.van-cell__right-icon-wrap{align-items:center;display:flex;font-size:var(--cell-icon-size,16px);height:var(--cell-line-height,24px)}.van-cell__left-icon-wrap{margin-right:var(--padding-base,4px)}.van-cell__right-icon-wrap{color:var(--cell-right-icon-color,#969799);margin-left:var(--padding-base,4px)}.van-cell__left-icon{vertical-align:middle}.van-cell__left-icon,.van-cell__right-icon{line-height:var(--cell-line-height,24px)}.van-cell--clickable.van-cell--hover{background-color:var(--cell-active-color,#f2f3f5)}.van-cell--required{overflow:visible}.van-cell--required:before{color:var(--cell-required-color,#ee0a24);content:"*";font-size:var(--cell-font-size,14px);left:var(--padding-xs,8px);position:absolute}.van-cell--center{align-items:center}.van-cell--large{padding-bottom:var(--cell-large-vertical-padding,12px);padding-top:var(--cell-large-vertical-padding,12px)}.van-cell--large .van-cell__title{font-size:var(--cell-large-title-font-size,16px)}.van-cell--large .van-cell__value{font-size:var(--cell-large-value-font-size,16px)}.van-cell--large .van-cell__label{font-size:var(--cell-large-label-font-size,14px)} |
@ -0,0 +1 @@ | |||
export {}; |
@ -0,0 +1,36 @@ | |||
import { useChildren } from '../common/relation'; | |||
import { VantComponent } from '../common/component'; | |||
VantComponent({ | |||
field: true, | |||
relation: useChildren('checkbox', function (target) { | |||
this.updateChild(target); | |||
}), | |||
props: { | |||
max: Number, | |||
value: { | |||
type: Array, | |||
observer: 'updateChildren', | |||
}, | |||
disabled: { | |||
type: Boolean, | |||
observer: 'updateChildren', | |||
}, | |||
direction: { | |||
type: String, | |||
value: 'vertical', | |||
}, | |||
}, | |||
methods: { | |||
updateChildren() { | |||
this.children.forEach((child) => this.updateChild(child)); | |||
}, | |||
updateChild(child) { | |||
const { value, disabled, direction } = this.data; | |||
child.setData({ | |||
value: value.indexOf(child.data.name) !== -1, | |||
parentDisabled: disabled, | |||
direction, | |||
}); | |||
}, | |||
}, | |||
}); |
@ -0,0 +1,3 @@ | |||
{ | |||
"component": true | |||
} |
@ -0,0 +1,5 @@ | |||
<wxs src="../wxs/utils.wxs" module="utils" /> | |||
<view class="{{ utils.bem('checkbox-group', [{ horizontal: direction === 'horizontal' }]) }}"> | |||
<slot /> | |||
</view> |
@ -0,0 +1 @@ | |||
@import '../common/index.wxss';.van-checkbox-group--horizontal{display:flex;flex-wrap:wrap} |
@ -0,0 +1 @@ | |||
export {}; |
@ -0,0 +1,77 @@ | |||
import { useParent } from '../common/relation'; | |||
import { VantComponent } from '../common/component'; | |||
function emit(target, value) { | |||
target.$emit('input', value); | |||
target.$emit('change', value); | |||
} | |||
VantComponent({ | |||
field: true, | |||
relation: useParent('checkbox-group'), | |||
classes: ['icon-class', 'label-class'], | |||
props: { | |||
value: Boolean, | |||
disabled: Boolean, | |||
useIconSlot: Boolean, | |||
checkedColor: String, | |||
labelPosition: { | |||
type: String, | |||
value: 'right', | |||
}, | |||
labelDisabled: Boolean, | |||
shape: { | |||
type: String, | |||
value: 'round', | |||
}, | |||
iconSize: { | |||
type: null, | |||
value: 20, | |||
}, | |||
}, | |||
data: { | |||
parentDisabled: false, | |||
direction: 'vertical', | |||
}, | |||
methods: { | |||
emitChange(value) { | |||
if (this.parent) { | |||
this.setParentValue(this.parent, value); | |||
} | |||
else { | |||
emit(this, value); | |||
} | |||
}, | |||
toggle() { | |||
const { parentDisabled, disabled, value } = this.data; | |||
if (!disabled && !parentDisabled) { | |||
this.emitChange(!value); | |||
} | |||
}, | |||
onClickLabel() { | |||
const { labelDisabled, parentDisabled, disabled, value } = this.data; | |||
if (!disabled && !labelDisabled && !parentDisabled) { | |||
this.emitChange(!value); | |||
} | |||
}, | |||
setParentValue(parent, value) { | |||
const parentValue = parent.data.value.slice(); | |||
const { name } = this.data; | |||
const { max } = parent.data; | |||
if (value) { | |||
if (max && parentValue.length >= max) { | |||
return; | |||
} | |||
if (parentValue.indexOf(name) === -1) { | |||
parentValue.push(name); | |||
emit(parent, parentValue); | |||
} | |||
} | |||
else { | |||
const index = parentValue.indexOf(name); | |||
if (index !== -1) { | |||
parentValue.splice(index, 1); | |||
emit(parent, parentValue); | |||
} | |||
} | |||
}, | |||
}, | |||
}); |
@ -0,0 +1,6 @@ | |||
{ | |||
"component": true, | |||
"usingComponents": { | |||
"van-icon": "../icon/index" | |||
} | |||
} |
@ -0,0 +1,31 @@ | |||
<wxs src="../wxs/utils.wxs" module="utils" /> | |||
<wxs src="./index.wxs" module="computed" /> | |||
<view class="{{ utils.bem('checkbox', [{ horizontal: direction === 'horizontal' }]) }} custom-class"> | |||
<view | |||
wx:if="{{ labelPosition === 'left' }}" | |||
class="label-class {{ utils.bem('checkbox__label', [labelPosition, { disabled: disabled || parentDisabled }]) }}" | |||
bindtap="onClickLabel" | |||
> | |||
<slot /> | |||
</view> | |||
<view class="van-checkbox__icon-wrap" bindtap="toggle"> | |||
<slot wx:if="{{ useIconSlot }}" name="icon" /> | |||
<van-icon | |||
wx:else | |||
name="success" | |||
size="0.8em" | |||
class="{{ utils.bem('checkbox__icon', [shape, { disabled: disabled || parentDisabled, checked: value }]) }}" | |||
style="{{ computed.iconStyle(checkedColor, value, disabled, parentDisabled, iconSize) }}" | |||
custom-class="icon-class" | |||
custom-style="line-height: 1.25em;" | |||
/> | |||
</view> | |||
<view | |||
wx:if="{{ labelPosition === 'right' }}" | |||
class="label-class {{ utils.bem('checkbox__label', [labelPosition, { disabled: disabled || parentDisabled }]) }}" | |||
bindtap="onClickLabel" | |||
> | |||
<slot /> | |||
</view> | |||
</view> |
@ -0,0 +1,20 @@ | |||
/* eslint-disable */ | |||
var style = require('../wxs/style.wxs'); | |||
var addUnit = require('../wxs/add-unit.wxs'); | |||
function iconStyle(checkedColor, value, disabled, parentDisabled, iconSize) { | |||
var styles = { | |||
'font-size': addUnit(iconSize), | |||
}; | |||
if (checkedColor && value && !disabled && !parentDisabled) { | |||
styles['border-color'] = checkedColor; | |||
styles['background-color'] = checkedColor; | |||
} | |||
return style(styles); | |||
} | |||
module.exports = { | |||
iconStyle: iconStyle, | |||
}; |
@ -0,0 +1 @@ | |||
@import '../common/index.wxss';.van-checkbox{align-items:center;display:flex;overflow:hidden;-webkit-user-select:none;user-select:none}.van-checkbox--horizontal{margin-right:12px}.van-checkbox__icon-wrap,.van-checkbox__label{line-height:var(--checkbox-size,20px)}.van-checkbox__icon-wrap{flex:none}.van-checkbox__icon{align-items:center;border:1px solid var(--checkbox-border-color,#c8c9cc);box-sizing:border-box;color:transparent;display:flex;font-size:var(--checkbox-size,20px);height:1em;justify-content:center;text-align:center;transition-duration:var(--checkbox-transition-duration,.2s);transition-property:color,border-color,background-color;width:1em}.van-checkbox__icon--round{border-radius:100%}.van-checkbox__icon--checked{background-color:var(--checkbox-checked-icon-color,#1989fa);border-color:var(--checkbox-checked-icon-color,#1989fa);color:#fff}.van-checkbox__icon--disabled{background-color:var(--checkbox-disabled-background-color,#ebedf0);border-color:var(--checkbox-disabled-icon-color,#c8c9cc)}.van-checkbox__icon--disabled.van-checkbox__icon--checked{color:var(--checkbox-disabled-icon-color,#c8c9cc)}.van-checkbox__label{word-wrap:break-word;color:var(--checkbox-label-color,#323233);padding-left:var(--checkbox-label-margin,10px)}.van-checkbox__label--left{float:left;margin:0 var(--checkbox-label-margin,10px) 0 0}.van-checkbox__label--disabled{color:var(--checkbox-disabled-label-color,#c8c9cc)}.van-checkbox__label:empty{margin:0} |
@ -0,0 +1,4 @@ | |||
/// <reference types="miniprogram-api-typings" /> | |||
declare type CanvasContext = WechatMiniprogram.CanvasContext; | |||
export declare function adaptor(ctx: CanvasContext & Record<string, unknown>): CanvasContext; | |||
export {}; |
@ -0,0 +1,43 @@ | |||
export function adaptor(ctx) { | |||
// @ts-ignore | |||
return Object.assign(ctx, { | |||
setStrokeStyle(val) { | |||
ctx.strokeStyle = val; | |||
}, | |||
setLineWidth(val) { | |||
ctx.lineWidth = val; | |||
}, | |||
setLineCap(val) { | |||
ctx.lineCap = val; | |||
}, | |||
setFillStyle(val) { | |||
ctx.fillStyle = val; | |||
}, | |||
setFontSize(val) { | |||
ctx.font = String(val); | |||
}, | |||
setGlobalAlpha(val) { | |||
ctx.globalAlpha = val; | |||
}, | |||
setLineJoin(val) { | |||
ctx.lineJoin = val; | |||
}, | |||
setTextAlign(val) { | |||
ctx.textAlign = val; | |||
}, | |||
setMiterLimit(val) { | |||
ctx.miterLimit = val; | |||
}, | |||
setShadow(offsetX, offsetY, blur, color) { | |||
ctx.shadowOffsetX = offsetX; | |||
ctx.shadowOffsetY = offsetY; | |||
ctx.shadowBlur = blur; | |||
ctx.shadowColor = color; | |||
}, | |||
setTextBaseline(val) { | |||
ctx.textBaseline = val; | |||
}, | |||
createCircularGradient() { }, | |||
draw() { }, | |||
}); | |||
} |
@ -0,0 +1 @@ | |||
export {}; |
@ -0,0 +1,193 @@ | |||
import { BLUE, WHITE } from '../common/color'; | |||
import { VantComponent } from '../common/component'; | |||
import { getSystemInfoSync } from '../common/utils'; | |||
import { isObj } from '../common/validator'; | |||
import { canIUseCanvas2d } from '../common/version'; | |||
import { adaptor } from './canvas'; | |||
function format(rate) { | |||
return Math.min(Math.max(rate, 0), 100); | |||
} | |||
const PERIMETER = 2 * Math.PI; | |||
const BEGIN_ANGLE = -Math.PI / 2; | |||
const STEP = 1; | |||
VantComponent({ | |||
props: { | |||
text: String, | |||
lineCap: { | |||
type: String, | |||
value: 'round', | |||
}, | |||
value: { | |||
type: Number, | |||
value: 0, | |||
observer: 'reRender', | |||
}, | |||
speed: { | |||
type: Number, | |||
value: 50, | |||
}, | |||
size: { | |||
type: Number, | |||
value: 100, | |||
observer() { | |||
this.drawCircle(this.currentValue); | |||
}, | |||
}, | |||
fill: String, | |||
layerColor: { | |||
type: String, | |||
value: WHITE, | |||
}, | |||
color: { | |||
type: null, | |||
value: BLUE, | |||
observer() { | |||
this.setHoverColor().then(() => { | |||
this.drawCircle(this.currentValue); | |||
}); | |||
}, | |||
}, | |||
type: { | |||
type: String, | |||
value: '', | |||
}, | |||
strokeWidth: { | |||
type: Number, | |||
value: 4, | |||
}, | |||
clockwise: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
}, | |||
data: { | |||
hoverColor: BLUE, | |||
}, | |||
methods: { | |||
getContext() { | |||
const { type, size } = this.data; | |||
if (type === '' || !canIUseCanvas2d()) { | |||
const ctx = wx.createCanvasContext('van-circle', this); | |||
return Promise.resolve(ctx); | |||
} | |||
const dpr = getSystemInfoSync().pixelRatio; | |||
return new Promise((resolve) => { | |||
wx.createSelectorQuery() | |||
.in(this) | |||
.select('#van-circle') | |||
.node() | |||
.exec((res) => { | |||
const canvas = res[0].node; | |||
const ctx = canvas.getContext(type); | |||
if (!this.inited) { | |||
this.inited = true; | |||
canvas.width = size * dpr; | |||
canvas.height = size * dpr; | |||
ctx.scale(dpr, dpr); | |||
} | |||
resolve(adaptor(ctx)); | |||
}); | |||
}); | |||
}, | |||
setHoverColor() { | |||
const { color, size } = this.data; | |||
if (isObj(color)) { | |||
return this.getContext().then((context) => { | |||
const LinearColor = context.createLinearGradient(size, 0, 0, 0); | |||
Object.keys(color) | |||
.sort((a, b) => parseFloat(a) - parseFloat(b)) | |||
.map((key) => LinearColor.addColorStop(parseFloat(key) / 100, color[key])); | |||
this.hoverColor = LinearColor; | |||
}); | |||
} | |||
this.hoverColor = color; | |||
return Promise.resolve(); | |||
}, | |||
presetCanvas(context, strokeStyle, beginAngle, endAngle, fill) { | |||
const { strokeWidth, lineCap, clockwise, size } = this.data; | |||
const position = size / 2; | |||
const radius = position - strokeWidth / 2; | |||
context.setStrokeStyle(strokeStyle); | |||
context.setLineWidth(strokeWidth); | |||
context.setLineCap(lineCap); | |||
context.beginPath(); | |||
context.arc(position, position, radius, beginAngle, endAngle, !clockwise); | |||
context.stroke(); | |||
if (fill) { | |||
context.setFillStyle(fill); | |||
context.fill(); | |||
} | |||
}, | |||
renderLayerCircle(context) { | |||
const { layerColor, fill } = this.data; | |||
this.presetCanvas(context, layerColor, 0, PERIMETER, fill); | |||
}, | |||
renderHoverCircle(context, formatValue) { | |||
const { clockwise } = this.data; | |||
// 结束角度 | |||
const progress = PERIMETER * (formatValue / 100); | |||
const endAngle = clockwise | |||
? BEGIN_ANGLE + progress | |||
: 3 * Math.PI - (BEGIN_ANGLE + progress); | |||
this.presetCanvas(context, this.hoverColor, BEGIN_ANGLE, endAngle); | |||
}, | |||
drawCircle(currentValue) { | |||
const { size } = this.data; | |||
this.getContext().then((context) => { | |||
context.clearRect(0, 0, size, size); | |||
this.renderLayerCircle(context); | |||
const formatValue = format(currentValue); | |||
if (formatValue !== 0) { | |||
this.renderHoverCircle(context, formatValue); | |||
} | |||
context.draw(); | |||
}); | |||
}, | |||
reRender() { | |||
// tofector 动画暂时没有想到好的解决方案 | |||
const { value, speed } = this.data; | |||
if (speed <= 0 || speed > 1000) { | |||
this.drawCircle(value); | |||
return; | |||
} | |||
this.clearMockInterval(); | |||
this.currentValue = this.currentValue || 0; | |||
const run = () => { | |||
this.interval = setTimeout(() => { | |||
if (this.currentValue !== value) { | |||
if (Math.abs(this.currentValue - value) < STEP) { | |||
this.currentValue = value; | |||
} | |||
else if (this.currentValue < value) { | |||
this.currentValue += STEP; | |||
} | |||
else { | |||
this.currentValue -= STEP; | |||
} | |||
this.drawCircle(this.currentValue); | |||
run(); | |||
} | |||
else { | |||
this.clearMockInterval(); | |||
} | |||
}, 1000 / speed); | |||
}; | |||
run(); | |||
}, | |||
clearMockInterval() { | |||
if (this.interval) { | |||
clearTimeout(this.interval); | |||
this.interval = null; | |||
} | |||
}, | |||
}, | |||
mounted() { | |||
this.currentValue = this.data.value; | |||
this.setHoverColor().then(() => { | |||
this.drawCircle(this.currentValue); | |||
}); | |||
}, | |||
destroyed() { | |||
this.clearMockInterval(); | |||
}, | |||
}); |
@ -0,0 +1,3 @@ | |||
{ | |||
"component": true | |||
} |
@ -0,0 +1,9 @@ | |||
<wxs src="../wxs/utils.wxs" module="utils" /> | |||
<view class="van-circle"> | |||
<canvas class="van-circle__canvas" type="{{ type }}" style="width: {{ utils.addUnit(size) }};height:{{ utils.addUnit(size) }}" id="van-circle" canvas-id="van-circle"></canvas> | |||
<view wx:if="{{ !text }}" class="van-circle__text"> | |||
<slot></slot> | |||
</view> | |||
<cover-view wx:else class="van-circle__text">{{ text }}</cover-view> | |||
</view> |
@ -0,0 +1 @@ | |||
@import '../common/index.wxss';.van-circle{display:inline-block;position:relative;text-align:center}.van-circle__text{color:var(--circle-text-color,#323233);left:0;position:absolute;top:50%;transform:translateY(-50%);width:100%} |
@ -0,0 +1 @@ | |||
export {}; |
@ -0,0 +1,9 @@ | |||
import { useParent } from '../common/relation'; | |||
import { VantComponent } from '../common/component'; | |||
VantComponent({ | |||
relation: useParent('row'), | |||
props: { | |||
span: Number, | |||
offset: Number, | |||
}, | |||
}); |
@ -0,0 +1,3 @@ | |||
{ | |||
"component": true | |||
} |
@ -0,0 +1,9 @@ | |||
<wxs src="../wxs/utils.wxs" module="utils" /> | |||
<wxs src="./index.wxs" module="computed" /> | |||
<view | |||
class="custom-class {{ utils.bem('col', [span]) }} {{ offset ? 'van-col--offset-' + offset : '' }}" | |||
style="{{ computed.rootStyle({ gutter }) }}" | |||
> | |||
<slot /> | |||
</view> |
@ -0,0 +1,18 @@ | |||
/* eslint-disable */ | |||
var style = require('../wxs/style.wxs'); | |||
var addUnit = require('../wxs/add-unit.wxs'); | |||
function rootStyle(data) { | |||
if (!data.gutter) { | |||
return ''; | |||
} | |||
return style({ | |||
'padding-right': addUnit(data.gutter / 2), | |||
'padding-left': addUnit(data.gutter / 2), | |||
}); | |||
} | |||
module.exports = { | |||
rootStyle: rootStyle, | |||
}; |
@ -0,0 +1 @@ | |||
@import '../common/index.wxss';.van-col{box-sizing:border-box;float:left}.van-col--1{width:4.16666667%}.van-col--offset-1{margin-left:4.16666667%}.van-col--2{width:8.33333333%}.van-col--offset-2{margin-left:8.33333333%}.van-col--3{width:12.5%}.van-col--offset-3{margin-left:12.5%}.van-col--4{width:16.66666667%}.van-col--offset-4{margin-left:16.66666667%}.van-col--5{width:20.83333333%}.van-col--offset-5{margin-left:20.83333333%}.van-col--6{width:25%}.van-col--offset-6{margin-left:25%}.van-col--7{width:29.16666667%}.van-col--offset-7{margin-left:29.16666667%}.van-col--8{width:33.33333333%}.van-col--offset-8{margin-left:33.33333333%}.van-col--9{width:37.5%}.van-col--offset-9{margin-left:37.5%}.van-col--10{width:41.66666667%}.van-col--offset-10{margin-left:41.66666667%}.van-col--11{width:45.83333333%}.van-col--offset-11{margin-left:45.83333333%}.van-col--12{width:50%}.van-col--offset-12{margin-left:50%}.van-col--13{width:54.16666667%}.van-col--offset-13{margin-left:54.16666667%}.van-col--14{width:58.33333333%}.van-col--offset-14{margin-left:58.33333333%}.van-col--15{width:62.5%}.van-col--offset-15{margin-left:62.5%}.van-col--16{width:66.66666667%}.van-col--offset-16{margin-left:66.66666667%}.van-col--17{width:70.83333333%}.van-col--offset-17{margin-left:70.83333333%}.van-col--18{width:75%}.van-col--offset-18{margin-left:75%}.van-col--19{width:79.16666667%}.van-col--offset-19{margin-left:79.16666667%}.van-col--20{width:83.33333333%}.van-col--offset-20{margin-left:83.33333333%}.van-col--21{width:87.5%}.van-col--offset-21{margin-left:87.5%}.van-col--22{width:91.66666667%}.van-col--offset-22{margin-left:91.66666667%}.van-col--23{width:95.83333333%}.van-col--offset-23{margin-left:95.83333333%}.van-col--24{width:100%}.van-col--offset-24{margin-left:100%} |
@ -0,0 +1,2 @@ | |||
/// <reference types="miniprogram-api-typings" /> | |||
export declare function setContentAnimate(context: WechatMiniprogram.Component.TrivialInstance, expanded: boolean, mounted: boolean): void; |
@ -0,0 +1,39 @@ | |||
import { getRect } from '../common/utils'; | |||
function useAnimation(context, expanded, mounted, height) { | |||
const animation = wx.createAnimation({ | |||
duration: 0, | |||
timingFunction: 'ease-in-out', | |||
}); | |||
if (expanded) { | |||
if (height === 0) { | |||
animation.height('auto').top(1).step(); | |||
} | |||
else { | |||
animation | |||
.height(height) | |||
.top(1) | |||
.step({ | |||
duration: mounted ? 300 : 1, | |||
}) | |||
.height('auto') | |||
.step(); | |||
} | |||
context.setData({ | |||
animation: animation.export(), | |||
}); | |||
return; | |||
} | |||
animation.height(height).top(0).step({ duration: 1 }).height(0).step({ | |||
duration: 300, | |||
}); | |||
context.setData({ | |||
animation: animation.export(), | |||
}); | |||
} | |||
export function setContentAnimate(context, expanded, mounted) { | |||
getRect(context, '.van-collapse-item__content') | |||
.then((rect) => rect.height) | |||
.then((height) => { | |||
useAnimation(context, expanded, mounted, height); | |||
}); | |||
} |
@ -0,0 +1 @@ | |||
export {}; |
@ -0,0 +1,59 @@ | |||
import { VantComponent } from '../common/component'; | |||
import { useParent } from '../common/relation'; | |||
import { setContentAnimate } from './animate'; | |||
VantComponent({ | |||
classes: ['title-class', 'content-class'], | |||
relation: useParent('collapse'), | |||
props: { | |||
name: null, | |||
title: null, | |||
value: null, | |||
icon: String, | |||
label: String, | |||
disabled: Boolean, | |||
clickable: Boolean, | |||
border: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
isLink: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
}, | |||
data: { | |||
expanded: false, | |||
}, | |||
mounted() { | |||
this.updateExpanded(); | |||
this.mounted = true; | |||
}, | |||
methods: { | |||
updateExpanded() { | |||
if (!this.parent) { | |||
return; | |||
} | |||
const { value, accordion } = this.parent.data; | |||
const { children = [] } = this.parent; | |||
const { name } = this.data; | |||
const index = children.indexOf(this); | |||
const currentName = name == null ? index : name; | |||
const expanded = accordion | |||
? value === currentName | |||
: (value || []).some((name) => name === currentName); | |||
if (expanded !== this.data.expanded) { | |||
setContentAnimate(this, expanded, this.mounted); | |||
} | |||
this.setData({ index, expanded }); | |||
}, | |||
onClick() { | |||
if (this.data.disabled) { | |||
return; | |||
} | |||
const { name, expanded } = this.data; | |||
const index = this.parent.children.indexOf(this); | |||
const currentName = name == null ? index : name; | |||
this.parent.switch(currentName, !expanded); | |||
}, | |||
}, | |||
}); |
@ -0,0 +1,6 @@ | |||
{ | |||
"component": true, | |||
"usingComponents": { | |||
"van-cell": "../cell/index" | |||
} | |||
} |
@ -0,0 +1,44 @@ | |||
<wxs src="../wxs/utils.wxs" module="utils" /> | |||
<view class="van-collapse-item custom-class {{ index !== 0 ? 'van-hairline--top' : '' }}"> | |||
<van-cell | |||
title="{{ title }}" | |||
title-class="title-class" | |||
icon="{{ icon }}" | |||
value="{{ value }}" | |||
label="{{ label }}" | |||
is-link="{{ isLink }}" | |||
clickable="{{ clickable }}" | |||
border="{{ border && expanded }}" | |||
class="{{ utils.bem('collapse-item__title', { disabled, expanded }) }}" | |||
right-icon-class="van-cell__right-icon" | |||
custom-class="van-cell" | |||
hover-class="van-cell--hover" | |||
bind:click="onClick" | |||
> | |||
<slot | |||
name="title" | |||
slot="title" | |||
/> | |||
<slot | |||
name="icon" | |||
slot="icon" | |||
/> | |||
<slot name="value" /> | |||
<slot | |||
name="right-icon" | |||
slot="right-icon" | |||
/> | |||
</van-cell> | |||
<view | |||
class="{{ utils.bem('collapse-item__wrapper') }}" | |||
style="height: 0;" | |||
animation="{{ animation }}" | |||
> | |||
<view | |||
class="van-collapse-item__content content-class" | |||
> | |||
<slot /> | |||
</view> | |||
</view> | |||
</view> |
@ -0,0 +1 @@ | |||
@import '../common/index.wxss';.van-collapse-item__title .van-cell__right-icon{transform:rotate(90deg);transition:transform var(--collapse-item-transition-duration,.3s)}.van-collapse-item__title--expanded .van-cell__right-icon{transform:rotate(-90deg)}.van-collapse-item__title--disabled .van-cell,.van-collapse-item__title--disabled .van-cell__right-icon{color:var(--collapse-item-title-disabled-color,#c8c9cc)!important}.van-collapse-item__title--disabled .van-cell--hover{background-color:#fff!important}.van-collapse-item__wrapper{overflow:hidden}.van-collapse-item__content{background-color:var(--collapse-item-content-background-color,#fff);color:var(--collapse-item-content-text-color,#969799);font-size:var(--collapse-item-content-font-size,13px);line-height:var(--collapse-item-content-line-height,1.5);padding:var(--collapse-item-content-padding,15px)} |
@ -0,0 +1 @@ | |||
export {}; |
@ -0,0 +1,46 @@ | |||
import { VantComponent } from '../common/component'; | |||
import { useChildren } from '../common/relation'; | |||
VantComponent({ | |||
relation: useChildren('collapse-item'), | |||
props: { | |||
value: { | |||
type: null, | |||
observer: 'updateExpanded', | |||
}, | |||
accordion: { | |||
type: Boolean, | |||
observer: 'updateExpanded', | |||
}, | |||
border: { | |||
type: Boolean, | |||
value: true, | |||
}, | |||
}, | |||
methods: { | |||
updateExpanded() { | |||
this.children.forEach((child) => { | |||
child.updateExpanded(); | |||
}); | |||
}, | |||
switch(name, expanded) { | |||
const { accordion, value } = this.data; | |||
const changeItem = name; | |||
if (!accordion) { | |||
name = expanded | |||
? (value || []).concat(name) | |||
: (value || []).filter((activeName) => activeName !== name); | |||
} | |||
else { | |||
name = expanded ? name : ''; | |||
} | |||
if (expanded) { | |||
this.$emit('open', changeItem); | |||
} | |||
else { | |||
this.$emit('close', changeItem); | |||
} | |||
this.$emit('change', name); | |||
this.$emit('input', name); | |||
}, | |||
}, | |||
}); |
@ -0,0 +1,3 @@ | |||
{ | |||
"component": true | |||
} |
@ -0,0 +1,3 @@ | |||
<view class="custom-class van-collapse {{ border ? 'van-hairline--top-bottom' : '' }}"> | |||
<slot /> | |||
</view> |
@ -0,0 +1 @@ | |||
@import '../common/index.wxss'; |