add:redux

master
blak-kong 2 years ago
parent 2a78e35d93
commit 9ca194b3a0

18982
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -36,47 +36,49 @@
"author": "",
"dependencies": {
"@babel/runtime": "^7.7.7",
"@reduxjs/toolkit": "^2.0.1",
"@tarojs/components": "3.6.19",
"@tarojs/helper": "3.6.19",
"@tarojs/plugin-platform-weapp": "3.6.19",
"@tarojs/plugin-framework-react": "3.6.19",
"@tarojs/plugin-platform-alipay": "3.6.19",
"@tarojs/plugin-platform-tt": "3.6.19",
"@tarojs/plugin-platform-swan": "3.6.19",
"@tarojs/plugin-platform-h5": "3.6.19",
"@tarojs/plugin-platform-jd": "3.6.19",
"@tarojs/plugin-platform-qq": "3.6.19",
"@tarojs/plugin-platform-h5": "3.6.19",
"@tarojs/plugin-platform-swan": "3.6.19",
"@tarojs/plugin-platform-tt": "3.6.19",
"@tarojs/plugin-platform-weapp": "3.6.19",
"@tarojs/react": "3.6.19",
"@tarojs/runtime": "3.6.19",
"@tarojs/shared": "3.6.19",
"@tarojs/taro": "3.6.19",
"@tarojs/plugin-framework-react": "3.6.19",
"lodash": "4.17.15",
"taro-ui": "^3.1.0-beta.2",
"@tarojs/react": "3.6.19",
"react": "^18.0.0",
"react-dom": "^18.0.0"
"react-dom": "^18.0.0",
"react-redux": "^9.0.3",
"taro-ui": "^3.2.0"
},
"devDependencies": {
"@babel/core": "^7.8.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.5",
"@tarojs/cli": "3.6.19",
"postcss": "^8.4.18",
"webpack": "^5.78.0",
"@tarojs/taro-loader": "3.6.19",
"@tarojs/webpack5-runner": "3.6.19",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.5",
"react-refresh": "^0.11.0",
"@types/node": "^18.15.11",
"@types/react": "^18.0.0",
"@types/webpack-env": "^1.13.6",
"@typescript-eslint/eslint-plugin": "^5.20.0",
"@typescript-eslint/parser": "^5.20.0",
"babel-preset-taro": "3.6.19",
"eslint": "^8.12.0",
"eslint-config-taro": "3.6.19",
"stylelint": "9.3.0",
"@typescript-eslint/parser": "^5.20.0",
"@typescript-eslint/eslint-plugin": "^5.20.0",
"typescript": "^4.1.0",
"@types/react": "^18.0.0",
"eslint-plugin-react": "^7.8.2",
"eslint-plugin-import": "^2.12.0",
"eslint-plugin-react": "^7.8.2",
"eslint-plugin-react-hooks": "^4.2.0",
"postcss": "^8.4.18",
"react-refresh": "^0.11.0",
"stylelint": "9.3.0",
"ts-node": "^10.9.1",
"@types/node": "^18.15.11"
"typescript": "^4.1.0",
"webpack": "^5.78.0"
}
}

@ -1,25 +1,25 @@
{
"miniprogramRoot": "dist/",
"projectname": "flossom_miniapp",
"description": "",
"appid": "touristappid",
"setting": {
"urlCheck": true,
"es6": false,
"miniprogramRoot": "dist/",
"projectname": "flossom_miniapp",
"description": "",
"appid": "wx815fb6fbd1f5ab3c",
"setting": {
"urlCheck": true,
"es6": false,
"enhance": false,
"compileHotReLoad": false,
"postcss": false,
"preloadBackgroundData": false,
"minified": false,
"newFeature": true,
"autoAudits": false,
"coverView": true,
"showShadowRootInWxmlPanel": false,
"scopeDataCheck": false,
"useCompilerModule": false
},
"compileType": "miniprogram",
"simulatorType": "wechat",
"simulatorPluginLibVersion": {},
"condition": {}
"postcss": false,
"preloadBackgroundData": false,
"minified": false,
"newFeature": true,
"autoAudits": false,
"coverView": true,
"showShadowRootInWxmlPanel": false,
"scopeDataCheck": false,
"useCompilerModule": false
},
"compileType": "miniprogram",
"simulatorType": "wechat",
"simulatorPluginLibVersion": {},
"condition": {}
}

@ -2,8 +2,52 @@ export default defineAppConfig({
pages: [
'pages/index/index',
'pages/initiate/initiate',
'pages/entry/entry'
'pages/entry/entry',
'pages/activity/activity',
"pages/detect/detect",
"pages/shop/shop",
"pages/user/user",
'pages/template/template'
],
"tabBar": {
"custom": true,
"color": "#707070",
"selectedColor": "#CAB18C",
"backgroundColor": "#ffffff",
"borderStyle": "black",
"list": [
{
pagePath: "pages/activity/activity",
text: "活动",
iconPath: "img/tabar/1.png",
selectedIconPath: "img/tabar/11.png",
},
{
pagePath: "pages/detect/detect",
text: "发现",
iconPath: "img/tabar/2.png",
selectedIconPath: "img/tabar/22.png",
},
{
pagePath: "pages/index/index",
text: "主页",
iconPath: "img/tabar/3.png",
selectedIconPath: "img/tabar/33.png",
},
{
pagePath: "pages/shop/shop",
text: "商城",
iconPath: "img/tabar/4.png",
selectedIconPath: "img/tabar/44.png",
},
{
pagePath: "pages/user/user",
text: "我的",
iconPath: "img/tabar/5.png",
selectedIconPath: "img/tabar/55.png",
},
]
},
window: {
backgroundTextStyle: 'light',
navigationBarBackgroundColor: '#fff',

@ -152,3 +152,12 @@ image {
color: #fff;
background-color: #000;
}
.bg-while {
background-color: #fff;
}
/**/
.at-calendar__controller.flex-justify-sb {
justify-content: space-between;
}

@ -1,11 +1,15 @@
import { Component, PropsWithChildren } from 'react'
import './app.less'
import Taro from '@tarojs/taro';
import { Component, PropsWithChildren } from "react";
import "./app.less";
import Taro from "@tarojs/taro";
import "taro-ui/dist/style/index.scss";
import { go } from "./utils/traoAPI";
class App extends Component<PropsWithChildren> {
import { Provider } from "react-redux";
import store from "./store";
taroGlobalData: {
class App extends Component<PropsWithChildren> {
taroGlobalData = {
// domain:'https://flossom.ecolite.com.cn',
// domain: "https://project10.xlovery.com",
domain: "https://flossom.gzlingren.com",
@ -34,52 +38,61 @@ class App extends Component<PropsWithChildren> {
M01: 6,
},
OtaDeviceTypeEnum: {
WL200: 'WL200',
WE100: 'WE100',
FACIALMASK: 'FacialMask',
STAND: 'Stand',
WL200: "WL200",
WE100: "WE100",
FACIALMASK: "FacialMask",
STAND: "Stand",
},
needAuthorization: false, // 是否需要授权隐私
requestUrlList: [],
safeAreaBottom: 0,
deviceChineseName: {
FR100: '',
FR200: '',
FR380: '',
FR390: '',
WL200: '',
M01: '',
WE100: '',
WL200Stand: '舱体',
FR100: "",
FR200: "",
FR380: "",
FR390: "",
WL200: "",
M01: "",
WE100: "",
WL200Stand: "舱体",
},
}
};
// 可以使用所有的 React 生命周期方法
componentDidMount() { }
componentDidMount() {}
// 对应 onLaunch
onLaunch(options) {
console.log("onLaunch", options)
console.log("onLaunch", options);
if (options.scene == 1007 || options.scene == 1008) {
return;
}
const isFirst = Taro.getStorageSync("isWelcome");
if (!isFirst) {
go("/pages/initiate/initiate");
}
setTimeout(() => {
throw new Error("test error");
}, 5000);
}
onError(error) {
console.log("error 错误捕获", error);
}
// 对应 onShow
componentDidShow() { }
componentDidShow() {}
// 对应 onHide
componentDidHide() { }
componentDidHide() {}
// this.props.children 是将要会渲染的页面
render() {
return this.props.children
// return this.props.children
return <Provider store={store} children={this.props.children}></Provider>;
}
}
export default App
export default App;

@ -0,0 +1,38 @@
import { Component } from 'react'
const objectToString = (style: object | string): string => {
if (style && typeof style === 'object') {
let styleStr = ''
Object.keys(style).forEach(key => {
const lowerCaseKey = key.replace(/([A-Z])/g, '-$1').toLowerCase()
styleStr += `${lowerCaseKey}:${style[key]};`
})
return styleStr
} else if (style && typeof style === 'string') {
return style
}
return ''
}
export default class AtComponent<P, S> extends Component<P, S> {
/**
* style
* @param {Object|String} style1
* @param {Object|String} style2
* @returns {String}
*/
mergeStyle(
style1: object | string,
style2: object | string
): object | string {
if (
style1 &&
typeof style1 === 'object' &&
style2 &&
typeof style2 === 'object'
) {
return Object.assign({}, style1, style2)
}
return objectToString(style1) + objectToString(style2)
}
}

@ -0,0 +1,46 @@
// 使用 HOC 以方便为各个页面复用这段逻辑
function createErrorBoundary(Page) {
return class ErrorBoundary extends Component {
el = React.createRef();
state = {
hasError: null,
};
static getDerivedStateFromError() {
return {
hasError: true,
};
}
componentDidCatch(error, errorInfo) {
console.log(error, errorInfo);
}
/* Start 需要手动调用页面组件上的生命周期方法 **/
componentDidShow() {
return this.el.current?.componentDidShow?.();
}
componentDidHide() {
return this.el.current?.componentDidHide?.();
}
onShareAppMessage() {
return this.el.current?.onShareAppMessage?.();
}
//...
/* End 需要手动调用页面组件上的生命周期方法 **/
render() {
return this.state.hasError ? (
<View>Something went wrong.</View>
) : (
<Page ref={this.el} />
);
}
};
}
export default createErrorBoundary;

@ -0,0 +1,287 @@
import Taro from '@tarojs/taro'
import React from 'react'
import { SelectorQuery } from '@tarojs/taro/types/index'
const ENV = Taro.getEnv()
function delay(delayTime = 25): Promise<void> {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, delayTime)
})
}
function delayQuerySelector(
selectorStr: string,
delayTime = 500
): Promise<any[]> {
return new Promise(resolve => {
const selector: SelectorQuery = Taro.createSelectorQuery()
delay(delayTime).then(() => {
selector
.select(selectorStr)
.boundingClientRect()
.exec((res: any[]) => {
resolve(res)
})
})
})
}
function delayGetScrollOffset({ delayTime = 500 }): Promise<any[]> {
return new Promise(resolve => {
delay(delayTime).then(() => {
Taro.createSelectorQuery()
.selectViewport()
.scrollOffset()
.exec((res: any[]) => {
resolve(res)
})
})
})
}
function delayGetClientRect({ selectorStr, delayTime = 500 }): Promise<any[]> {
const selector: SelectorQuery = Taro.createSelectorQuery()
return new Promise(resolve => {
delay(delayTime).then(() => {
selector
.select(selectorStr)
.boundingClientRect()
.exec((res: any[]) => {
resolve(res)
})
})
})
}
function uuid(len = 8, radix = 16): string {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
const value: string[] = []
let i = 0
radix = radix || chars.length
if (len) {
// Compact form
for (i = 0; i < len; i++) value[i] = chars[0 | (Math.random() * radix)]
} else {
// rfc4122, version 4 form
let r
// rfc4122 requires these characters
/* eslint-disable-next-line */
value[8] = value[13] = value[18] = value[23] = '-'
value[14] = '4'
// Fill in random data. At i==19 set the high bits of clock sequence as
// per rfc4122, sec. 4.1.5
for (i = 0; i < 36; i++) {
if (!value[i]) {
r = 0 | (Math.random() * 16)
value[i] = chars[i === 19 ? (r & 0x3) | 0x8 : r]
}
}
}
return value.join('')
}
interface EventDetail {
pageX: number
pageY: number
clientX: number
clientY: number
offsetX: number
offsetY: number
x: number
y: number
}
function getEventDetail(event: any): EventDetail {
let detail: EventDetail
switch (ENV) {
case Taro.ENV_TYPE.WEB:
detail = {
pageX: event.pageX,
pageY: event.pageY,
clientX: event.clientX,
clientY: event.clientY,
offsetX: event.offsetX,
offsetY: event.offsetY,
x: event.x,
y: event.y
}
break
case Taro.ENV_TYPE.WEAPP:
detail = {
pageX: event.touches[0].pageX,
pageY: event.touches[0].pageY,
clientX: event.touches[0].clientX,
clientY: event.touches[0].clientY,
offsetX: event.target.offsetLeft,
offsetY: event.target.offsetTop,
x: event.target.x,
y: event.target.y
}
break
case Taro.ENV_TYPE.ALIPAY:
detail = {
pageX: event.target.pageX,
pageY: event.target.pageY,
clientX: event.target.clientX,
clientY: event.target.clientY,
offsetX: event.target.offsetLeft,
offsetY: event.target.offsetTop,
x: event.target.x,
y: event.target.y
}
break
case Taro.ENV_TYPE.SWAN:
detail = {
pageX: event.changedTouches[0].pageX,
pageY: event.changedTouches[0].pageY,
clientX: event.target.clientX,
clientY: event.target.clientY,
offsetX: event.target.offsetLeft,
offsetY: event.target.offsetTop,
x: event.detail.x,
y: event.detail.y
}
break
default:
detail = {
pageX: 0,
pageY: 0,
clientX: 0,
clientY: 0,
offsetX: 0,
offsetY: 0,
x: 0,
y: 0
}
console.warn('getEventDetail暂未支持该环境')
break
}
return detail
}
function initTestEnv(): void {
if (process.env.NODE_ENV === 'test') {
Taro.initPxTransform({
designWidth: 750,
deviceRatio: {
'640': 2.34 / 2,
'750': 1,
'828': 1.81 / 2
}
})
}
}
function isTest(): boolean {
return process.env.NODE_ENV === 'test'
}
let scrollTop = 0
function handleTouchScroll(flag: any): void {
if (ENV !== Taro.ENV_TYPE.WEB) {
return
}
if (flag) {
scrollTop = document.documentElement.scrollTop
// 使body脱离文档流
document.body.classList.add('at-frozen')
// 把脱离文档流的body拉上去否则页面会回到顶部
document.body.style.top = `${-scrollTop}px`
} else {
document.body.style.top = ''
document.body.classList.remove('at-frozen')
document.documentElement.scrollTop = scrollTop
}
}
function pxTransform(size: number): string {
if (!size) return ''
const designWidth = 750
const deviceRatio = {
640: 2.34 / 2,
750: 1,
828: 1.81 / 2
}
return `${size / deviceRatio[designWidth]}rpx`
}
function objectToString(style: object | string): string {
if (style && typeof style === 'object') {
let styleStr = ''
Object.keys(style).forEach(key => {
const lowerCaseKey = key.replace(/([A-Z])/g, '-$1').toLowerCase()
styleStr += `${lowerCaseKey}:${style[key]};`
})
return styleStr
} else if (style && typeof style === 'string') {
return style
}
return ''
}
/**
* style
* @param {Object|String} style1
* @param {Object|String} style2
* @returns {String}
*/
function mergeStyle(
style1: object | string,
style2: object | string
): object | string {
if (
style1 &&
typeof style1 === 'object' &&
style2 &&
typeof style2 === 'object'
) {
return Object.assign({}, style1, style2)
}
return objectToString(style1) + objectToString(style2)
}
/**
* JSX.Element
* @param {any} props
* @param {string} propName
* @param {string} componentName
* @returns
*/
function isJSXElement(props, propName, componentName) {
if (!React.isValidElement(props[propName])) {
return new Error(
`Invalid prop ${propName} supplied to ${componentName}. It must be a valid JSX element.`
)
}
}
export {
delay,
delayQuerySelector,
uuid,
getEventDetail,
initTestEnv,
isTest,
pxTransform,
handleTouchScroll,
delayGetClientRect,
delayGetScrollOffset,
mergeStyle,
isJSXElement
}

@ -0,0 +1,489 @@
import classnames from "classnames";
import dayjs from "dayjs";
import React from "react";
import Taro, { Events } from "@tarojs/taro";
import { Swiper, SwiperItem, View, Image } from "@tarojs/components";
import {
BaseEventOrig,
ITouch,
ITouchEvent,
} from "@tarojs/components/types/common";
import {
AtCalendarBodyListGroup,
AtCalendarBodyProps,
AtCalendarBodyState,
Calendar,
} from "../../../../types/calendar";
import { delayQuerySelector } from "../../../common/utils";
import generateCalendarGroup from "../common/helper";
import AtCalendarDateList from "../ui/date-list/index";
import AtCalendarDayList from "../ui/day-list/index";
import "./isFolding.less";
const ANIMTE_DURATION = 300;
const defaultProps: Partial<AtCalendarBodyProps> = {
marks: [],
selectedDate: {
end: Date.now(),
start: Date.now(),
},
format: "YYYY-MM-DD",
generateDate: Date.now(),
};
// const events = new Events();
export default class AtCalendarBody extends React.Component<
AtCalendarBodyProps,
Readonly<AtCalendarBodyState>
> {
static defaultProps: Partial<AtCalendarBodyProps> = defaultProps;
public constructor(props: AtCalendarBodyProps) {
super(props);
const {
validDates,
marks,
format,
minDate,
maxDate,
generateDate,
selectedDate,
selectedDates,
} = props;
this.generateFunc = generateCalendarGroup({
validDates,
format,
minDate,
maxDate,
marks,
selectedDates,
});
const listGroup = this.getGroups(generateDate, selectedDate);
this.state = {
listGroup,
offsetSize: 0,
isAnimate: false,
isFolding: false,
temporaryCalendar: [],
temporaryCalendarWeek: [],
};
}
public componentDidMount(): void {
delayQuerySelector(".at-calendar-slider__main").then((res: any) => {
if (res.length) {
this.maxWidth = res[0]?.width;
}
});
this.onChangeFoldingCalendar();
}
public UNSAFE_componentWillReceiveProps(
nextProps: AtCalendarBodyProps
): void {
const {
validDates,
marks,
format,
minDate,
maxDate,
generateDate,
selectedDate,
selectedDates,
} = nextProps;
this.generateFunc = generateCalendarGroup({
validDates,
format,
minDate,
maxDate,
marks,
selectedDates,
});
const listGroup = this.getGroups(generateDate, selectedDate);
this.setState({
offsetSize: 0,
listGroup,
});
}
private changeCount = 0;
private currentSwiperIndex = 1;
private startX = 0;
private swipeStartPoint = 0;
private isPreMonth = false;
private maxWidth = 0;
private isTouching = false;
private generateFunc: (
generateDate: number,
selectedDate: Calendar.SelectedDate,
isShowStatus?: boolean
) => Calendar.ListInfo<Calendar.Item>;
private getGroups = (
generateDate: number,
selectedDate: Calendar.SelectedDate
): AtCalendarBodyListGroup => {
const dayjsDate = dayjs(generateDate);
const arr: AtCalendarBodyListGroup = [];
const preList: Calendar.ListInfo<Calendar.Item> = this.generateFunc(
dayjsDate.subtract(1, "month").valueOf(),
selectedDate
);
const nowList: Calendar.ListInfo<Calendar.Item> = this.generateFunc(
generateDate,
selectedDate,
true
);
const nextList: Calendar.ListInfo<Calendar.Item> = this.generateFunc(
dayjsDate.add(1, "month").valueOf(),
selectedDate
);
const preListIndex =
this.currentSwiperIndex === 0 ? 2 : this.currentSwiperIndex - 1;
const nextListIndex =
this.currentSwiperIndex === 2 ? 0 : this.currentSwiperIndex + 1;
arr[preListIndex] = preList;
arr[nextListIndex] = nextList;
arr[this.currentSwiperIndex] = nowList;
return arr;
};
private handleTouchStart = (e: ITouchEvent): void => {
if (!this.props.isSwiper) {
return;
}
this.isTouching = true;
this.startX = e.touches[0].clientX;
};
private handleTouchMove = (e: ITouchEvent): void => {
if (!this.props.isSwiper) {
return;
}
if (!this.isTouching) return;
const { clientX } = e.touches[0];
const offsetSize = clientX - this.startX;
this.setState({
offsetSize,
});
};
private animateMoveSlide = (offset: number, callback?: () => void): void => {
this.setState(
{
isAnimate: true,
},
() => {
this.setState({
offsetSize: offset,
});
setTimeout(() => {
this.setState(
{
isAnimate: false,
},
() => {
callback?.();
}
);
}, ANIMTE_DURATION);
}
);
};
private handleTouchEnd = (): void => {
if (!this.props.isSwiper) {
return;
}
const { offsetSize } = this.state;
this.isTouching = false;
const isRight = offsetSize > 0;
const breakpoint = this.maxWidth / 2;
const absOffsetSize = Math.abs(offsetSize);
if (absOffsetSize > breakpoint) {
const res = isRight ? this.maxWidth : -this.maxWidth;
return this.animateMoveSlide(res, () => {
this.props.onSwipeMonth(isRight ? -1 : 1);
});
}
this.animateMoveSlide(0);
};
private handleChange = (
e: BaseEventOrig<{
current: number;
source: string;
}>
): void => {
const { current, source } = e.detail;
if (source === "touch") {
this.currentSwiperIndex = current;
this.changeCount += 1;
}
};
private handleAnimateFinish = (): void => {
if (this.changeCount > 0) {
this.props.onSwipeMonth(
this.isPreMonth ? -this.changeCount : this.changeCount
);
this.changeCount = 0;
}
};
private handleSwipeTouchStart = (
e: ITouchEvent & { changedTouches: Array<ITouch> }
): void => {
const { clientY, clientX } = e.changedTouches[0];
this.swipeStartPoint = this.props.isVertical ? clientY : clientX;
};
private handleSwipeTouchEnd = (
e: ITouchEvent & { changedTouches: Array<ITouch> }
): void => {
const { clientY, clientX } = e.changedTouches[0];
this.isPreMonth = this.props.isVertical
? clientY - this.swipeStartPoint > 0
: clientX - this.swipeStartPoint > 0;
};
private onChangeFoldingCalendar = () => {
let { isFolding, listGroup } = this.state;
isFolding = !isFolding;
if (isFolding) {
let toDay = dayjs().format("YYYY-MM-DD");
let selectedDay = listGroup[1].list.find(
(item) => item.isSelected
)?.value;
let startWeekDay = dayjs(selectedDay)
.startOf("week")
.add(1, "day")
.format("YYYY-MM-DD");
let temporaryCalendar = [0, 1, 2, 3, 4, 5, 6].map((dayIndex) => {
let currentItemDay = dayjs(startWeekDay)
.add(dayIndex, "day")
.format("YYYY-MM-DD");
return {
isDisabled: false,
isSelected: currentItemDay === selectedDay,
isSelectedHead: currentItemDay === selectedDay,
isSelectedTail: currentItemDay === selectedDay,
isToday: toDay === currentItemDay,
marks: [],
text: Number(dayjs(currentItemDay).format("DD")),
type: 0,
value: currentItemDay,
};
});
this.setState({ temporaryCalendar });
} else {
let temporaryCalendar = listGroup[1].list;
this.setState({ temporaryCalendar });
}
this.setState({ isFolding });
};
onDayClick(item: any) {
let { temporaryCalendar } = this.state;
let oldValueItem = temporaryCalendar.findIndex((ele) => ele.isSelected);
let newValueItem = temporaryCalendar.findIndex(
(ele) => ele.value === item.value
);
temporaryCalendar[oldValueItem].isSelected = false;
temporaryCalendar[oldValueItem].isSelectedHead = false;
temporaryCalendar[oldValueItem].isSelectedTail = false;
temporaryCalendar[newValueItem].isSelected = true;
temporaryCalendar[newValueItem].isSelectedHead = true;
temporaryCalendar[newValueItem].isSelectedTail = true;
this.setState({ temporaryCalendar });
this.props.onDayClick(item);
}
onSelectDataChange(value: any) {
let { temporaryCalendar } = this.state;
let oldValueItem = temporaryCalendar.findIndex((ele) => ele.isSelected);
let newValueItem = temporaryCalendar.findIndex(
(ele) => ele.value === value
);
temporaryCalendar[oldValueItem].isSelected = false;
temporaryCalendar[oldValueItem].isSelectedHead = false;
temporaryCalendar[oldValueItem].isSelectedTail = false;
temporaryCalendar[newValueItem].isSelected = true;
temporaryCalendar[newValueItem].isSelectedHead = true;
temporaryCalendar[newValueItem].isSelectedTail = true;
this.setState({ temporaryCalendar });
this.props.onDayClick(temporaryCalendar[newValueItem]);
}
public render(): JSX.Element {
const { isSwiper } = this.props;
const { isFolding, isAnimate, offsetSize, listGroup, temporaryCalendar } =
this.state;
Taro.eventCenter.on(
"onSelectDataChange",
this.onSelectDataChange.bind(this)
);
if (!isSwiper) {
return (
<View
className={classnames(
"main",
"at-calendar-slider__main",
`at-calendar-slider__main--${process.env.TARO_ENV}`
)}
>
<AtCalendarDayList />
<View
className={classnames("main__body", "body", {
"main__body--isFolding": isFolding,
})}
>
<View className="body__slider body__slider--now">
{/* <AtCalendarDateList
list={temporaryCalendar}
onClick={this.onDayClick.bind(this)}
onLongClick={this.props.onLongClick}
/> */}
<AtCalendarDateList list={temporaryCalendar} />
</View>
</View>
<View className="arrow_box" onClick={this.onChangeFoldingCalendar}>
<Image
className={classnames("arrow", {
"arrow-rotate": isFolding,
})}
src={require("../../../img/index/arrow-down.png")}
mode="aspectFill"
/>
</View>
</View>
);
}
/* 需要 Taro 组件库维护 Swiper 使 小程序 和 H5 的表现保持一致 */
if (process.env.TARO_ENV === "h5") {
return (
<View
className={classnames(
"main",
"at-calendar-slider__main",
`at-calendar-slider__main--${process.env.TARO_ENV}`
)}
onTouchEnd={this.handleTouchEnd}
onTouchMove={this.handleTouchMove}
onTouchStart={this.handleTouchStart}
>
<AtCalendarDayList />
<View
className={classnames("main__body body", {
"main__body--slider": isSwiper,
"main__body--animate": isAnimate,
})}
style={{
transform: isSwiper
? `translateX(-100%) translate3d(${offsetSize},0,0)`
: "",
WebkitTransform: isSwiper
? `translateX(-100%) translate3d(${offsetSize}px,0,0)`
: "",
}}
>
<View className="body__slider body__slider--pre">
<AtCalendarDateList list={listGroup[0].list} />
</View>
<View className="body__slider body__slider--now">
<AtCalendarDateList
list={temporaryCalendar}
onClick={this.props.onDayClick}
onLongClick={this.props.onLongClick}
/>
</View>
<View className="body__slider body__slider--next">
<AtCalendarDateList list={listGroup[2].list} />
</View>
</View>
</View>
);
}
return (
<View
className={classnames(
"main",
"at-calendar-slider__main",
`at-calendar-slider__main--${process.env.TARO_ENV}`
)}
>
<AtCalendarDayList />
<Swiper
circular
current={1}
skipHiddenItemLayout
className={classnames("main__body", {
"main__body--isFolding": isFolding,
})}
onChange={this.handleChange}
vertical={this.props.isVertical}
onAnimationFinish={this.handleAnimateFinish}
onTouchEnd={this.handleSwipeTouchEnd}
onTouchStart={this.handleSwipeTouchStart}
>
{listGroup.map((item, key) => (
<SwiperItem key={key} itemId={key.toString()}>
<AtCalendarDateList
list={key === 1 ? temporaryCalendar : item.list}
onClick={this.onDayClick.bind(this)}
onLongClick={this.props.onLongClick}
/>
{/* <AtCalendarDateList
list={item.list}
onClick={this.props.onDayClick}
onLongClick={this.props.onLongClick}
/> */}
</SwiperItem>
))}
</Swiper>
<View className="arrow_box" onClick={this.onChangeFoldingCalendar}>
<Image
className={classnames("arrow", {
"arrow-rotate": isFolding,
})}
src={require("../../../img/index/arrow-down.png")}
mode="aspectFill"
/>
</View>
</View>
);
}
}

@ -0,0 +1,60 @@
.at-calendar-slider__main--weapp,
.at-calendar-slider__main--swan {
.main__body--isFolding {
height: 70px;
}
}
/* 样式定制 */
.at-calendar {
// 仅缩放宽度,防止上下抖动
// transform: scale(0.9, 1);
width: 90%;
margin: 0 auto;
color: #333;
}
.at-calendar__header .header__flex-item {
font-size: 26rpx;
}
.at-calendar__header .header__flex,
.at-calendar__list.flex .flex__item-container .container-text {
// color: #333;
}
.at-calendar__list.flex .flex__item {
font-size: 26rpx;
}
.at-calendar__list.flex .flex__item--today {
color: #333;
font-weight: 400;
}
.at-calendar__list.flex
.flex__item--selected-head.flex__item--selected-tail
.flex__item-container {
background: linear-gradient(0deg, #fff0da, #ffe4c0);
}
.at-calendar__list.flex .flex__item-container {
width: 60rpx;
height: 60rpx;
}
.arrow_box {
width: 80rpx;
height: 40rpx;
margin: 0 auto;
// margin-bottom: ;
// padding: 40rpx 80rpx 14rpx;
}
.arrow {
transform: rotate(180deg);
transition-property: all;
transition-duration: 0.5s;
width: 24rpx;
height: 100%;
margin: 0 auto;
}
.arrow-rotate {
transform: rotate(0);
}
/* 样式定制 */

@ -0,0 +1,5 @@
export const TYPE_PRE_MONTH = -1
export const TYPE_NOW_MONTH = 0
export const TYPE_NEXT_MONTH = 1

@ -0,0 +1,123 @@
import dayjs, { Dayjs } from 'dayjs'
import _flow from 'lodash/flow'
import { Calendar } from '../../../../types/calendar'
import * as constant from './constant'
import plugins from './plugins'
const TOTAL = 7 * 6
function getFullItem(
item: Partial<Calendar.Item>,
options: Calendar.GroupOptions,
selectedDate: Calendar.SelectedDate,
isShowStatus?: boolean
): any {
if (options.marks.find(x => x.value === item.value)) {
item.marks = [
{
value: item.value as string
}
]
}
if (!isShowStatus) return item
const bindedPlugins = plugins.map(fn =>
fn.bind(null, {
options,
selectedDate
})
)
return _flow(bindedPlugins)(item)
}
export default function generateCalendarGroup(
options: Calendar.GroupOptions
): (
generateDate: number,
selectedDate: Calendar.SelectedDate,
isShowStatus?: boolean
) => Calendar.ListInfo<Calendar.Item> {
return function (
generateDate: number,
selectedDate: Calendar.SelectedDate,
isShowStatus?: boolean
): Calendar.ListInfo<Calendar.Item> {
const date = dayjs(generateDate)
const { format } = options
// 获取生成日期的第一天 和 最后一天
const firstDate = date.startOf('month')
const lastDate = date.endOf('month')
const preMonthDate = date.subtract(1, 'month')
const list: Calendar.List<Calendar.Item> = []
const nowMonthDays: number = date.daysInMonth()// 获取这个月有多少天
// 因为把周日放到了最后,这里要减一天
const preMonthLastDay = preMonthDate.endOf('month').subtract(1, 'day').day() // 获取上个月最后一天是周几
// 生成上个月的日期
for (let i = 1; i <= preMonthLastDay + 1; i++) {
const thisDate = firstDate.subtract(i, 'day').startOf('day')
let item = {
marks: [],
_value: thisDate,
text: thisDate.date(),
type: constant.TYPE_PRE_MONTH,
value: thisDate.format(format)
}
item = getFullItem(item, options, selectedDate, isShowStatus)
list.push(item)
}
list.reverse()
// 生成这个月的日期
for (let i = 0; i < nowMonthDays; i++) {
const thisDate = firstDate.add(i, 'day').startOf('day')
let item = {
marks: [],
_value: thisDate,
text: thisDate.date(),
type: constant.TYPE_NOW_MONTH,
value: thisDate.format(format)
}
item = getFullItem(item, options, selectedDate, isShowStatus)
list.push(item)
}
// 生成下个月的日期
let i = 1
while (list.length < TOTAL) {
const thisDate = lastDate.add(i++, 'day').startOf('day')
let item = {
marks: [],
_value: thisDate,
text: thisDate.date(),
type: constant.TYPE_NEXT_MONTH,
value: thisDate.format(format)
}
item = getFullItem(item, options, selectedDate, isShowStatus)
list.push(item)
}
return {
list,
value: generateDate
}
}
}
export function getGenerateDate(date: Calendar.DateArg | undefined): Dayjs {
// return dayjs(date)
return dayjs(date).startOf('month')
}

@ -0,0 +1,124 @@
import dayjs from 'dayjs'
import _isEmpty from 'lodash/isEmpty'
import { Calendar } from '../../../../types/calendar'
interface PluginArg {
options: Calendar.GroupOptions
selectedDate: Calendar.SelectedDate
}
export function handleActive(
args: PluginArg,
item: Calendar.Item
): Calendar.Item {
const { selectedDate } = args
const { _value } = item
const { start, end } = selectedDate
const dayjsEnd = dayjs(end)
const dayjsStart = start ? dayjs(start) : dayjsEnd
item.isSelected =
_value?.isSame(dayjsEnd) ||
_value?.isSame(dayjsStart) ||
(_value?.isAfter(dayjsStart) && _value?.isBefore(dayjsEnd))
item.isSelectedHead = _value?.isSame(dayjsStart)
item.isSelectedTail = _value?.isSame(dayjsEnd)
item.isToday = _value?.diff(dayjs(Date.now()).startOf('day'), 'day') === 0
return item
}
export function handleMarks(
args: PluginArg,
item: Calendar.Item
): Calendar.Item {
const { options } = args
const { _value } = item
const { marks } = options
const markList = marks.filter(mark =>
_value ? dayjs(mark.value).startOf('day').isSame(_value) : false
)
item.marks = markList.slice(0, 1)
return item
}
// export function handleSelectedDates (args: PluginArg): Calendar.Item {
// const { item, options } = args
// const { _value } = item
// const { selectedDates } = options
// if (selectedDates.length === 0) return args
// _forEach(selectedDates, date => {
// const { isSelected, isHead, isTail } = item
// // 如果当前 Item 已经具备了 三种状态下 无需继续判断 跳出循环
// if (isSelected) {
// return false
// }
// const { start, end } = date
// const dayjsEnd = dayjs(end).startOf('day')
// const dayjsStart = dayjs(start).startOf('day')
// item.isSelected =
// item.isSelected ||
// (_value.isAfter(dayjsStart) && _value.isBefore(dayjsEnd))
// item.isHead = item.isHead || _value.isSame(dayjsStart)
// item.isTail = item.isTail || _value.isSame(dayjsEnd)
// })
// return item
// }
export function handleDisabled(
args: PluginArg,
item: Calendar.Item
): Calendar.Item {
const { options } = args
const { _value } = item
const { minDate, maxDate } = options
const dayjsMinDate = dayjs(minDate)
const dayjsMaxDate = dayjs(maxDate)
item.isDisabled =
!!(minDate && _value?.isBefore(dayjsMinDate)) ||
!!(maxDate && _value?.isAfter(dayjsMaxDate))
return item
}
export function handleValid(
args: PluginArg,
item: Calendar.Item
): Calendar.Item {
const { options } = args
const { _value } = item
const { validDates } = options
if (!_isEmpty(validDates)) {
const isInclude = validDates.some(date =>
_value ? dayjs(date.value).startOf('day').isSame(_value) : false
)
item.isDisabled = !isInclude
}
delete item._value
return item
}
export default [handleActive, handleMarks, handleDisabled, handleValid]

@ -0,0 +1,77 @@
import classnames from "classnames";
import dayjs, { Dayjs } from "dayjs";
import React from "react";
import { Picker, Text, View } from "@tarojs/components";
import {
AtCalendarControllerProps,
AtCalendarControllerState,
} from "../../../../types/calendar";
export default class AtCalendarController extends React.Component<
AtCalendarControllerProps,
AtCalendarControllerState
> {
public render(): JSX.Element {
const { generateDate, minDate, maxDate, monthFormat, hideArrow } =
this.props;
const dayjsDate: Dayjs = dayjs(generateDate);
const dayjsMinDate: Dayjs | boolean = !!minDate && dayjs(minDate);
const dayjsMaxDate: Dayjs | boolean = !!maxDate && dayjs(maxDate);
const isMinMonth: boolean =
dayjsMinDate && dayjsMinDate.startOf("month").isSame(dayjsDate);
const isMaxMonth: boolean =
dayjsMaxDate && dayjsMaxDate.startOf("month").isSame(dayjsDate);
const minDateValue: string = dayjsMinDate
? dayjsMinDate.format("YYYY-MM")
: "";
const maxDateValue: string = dayjsMaxDate
? dayjsMaxDate.format("YYYY-MM")
: "";
return (
<View className="at-calendar__controller controller flex-justify-sb">
{hideArrow ? null : (
<View
className={classnames("controller__arrow controller__arrow--left", {
"controller__arrow--disabled": isMinMonth,
})}
onClick={this.props.onPreMonth.bind(this, isMinMonth)}
/>
)}
<View style="display: flex;align-items: center;">
<Picker
mode="date"
fields="day"
end={maxDateValue}
start={minDateValue}
onChange={this.props.onSelectDate}
value={dayjsDate.format("YYYY-MM-DD")}
>
{/* <Text className="controller__info"></Text> */}
{/* <Text>{dayjsDate.format(monthFormat)}</Text> */}
<Text>{dayjsDate.format("YYYY.MM.DD")}</Text>
</Picker>
<View
style="margin-left:10rpx"
className="at-icon at-icon-calendar"
></View>
</View>
{hideArrow ? null : (
<View
className={classnames(
"controller__arrow controller__arrow--right",
{
"controller__arrow--disabled": isMaxMonth,
}
)}
onClick={this.props.onNextMonth.bind(this, isMaxMonth)}
/>
)}
</View>
);
}
}

@ -0,0 +1,337 @@
import classnames from "classnames";
import dayjs, { Dayjs } from "dayjs";
import React from "react";
import Taro, { Events } from "@tarojs/taro";
import { View } from "@tarojs/components";
import { BaseEventOrig } from "@tarojs/components/types/common";
import {
AtCalendarDefaultProps,
AtCalendarProps,
AtCalendarPropsWithDefaults,
AtCalendarState,
Calendar,
} from "../../../types/calendar";
import AtCalendarBody from "./body/index";
import AtCalendarController from "./controller/index";
// const events = new Events();
const defaultProps: AtCalendarDefaultProps = {
validDates: [],
marks: [],
isSwiper: true,
hideArrow: false,
isVertical: false,
selectedDates: [],
isMultiSelect: false,
format: "YYYY-MM-DD",
currentDate: Date.now(),
// monthFormat: "YYYY年MM月",
monthFormat: "YYYY-MM-DD",
};
export default class AtCalendar extends React.Component<
AtCalendarProps,
Readonly<AtCalendarState>
> {
static defaultProps: AtCalendarDefaultProps = defaultProps;
public constructor(props: AtCalendarProps) {
super(props);
const { currentDate, isMultiSelect } = props as AtCalendarPropsWithDefaults;
this.state = this.getInitializeState(currentDate, isMultiSelect);
}
public UNSAFE_componentWillReceiveProps(nextProps: AtCalendarProps): void {
const { currentDate, isMultiSelect } = nextProps;
if (!currentDate || currentDate === this.props.currentDate) return;
if (isMultiSelect && this.props.isMultiSelect) {
const { start, end } = currentDate as Calendar.SelectedDate;
const { start: preStart, end: preEnd } = this.props
.currentDate as Calendar.SelectedDate;
if (start === preStart && preEnd === end) {
return;
}
}
const stateValue: AtCalendarState = this.getInitializeState(
currentDate,
isMultiSelect
);
this.setState(stateValue);
}
private getSingleSelectdState = (value: Dayjs): Partial<AtCalendarState> => {
const { generateDate } = this.state;
console.log("generateDate", generateDate);
const stateValue: Partial<AtCalendarState> = {
selectedDate: this.getSelectedDate(value.valueOf()),
};
// const dayjsGenerateDate: Dayjs = value.startOf("month"); // 重置到月份第一天
const dayjsGenerateDate: Dayjs = value;
const generateDateValue: number = dayjsGenerateDate.valueOf();
if (generateDateValue !== generateDate) {
this.triggerChangeDate(dayjsGenerateDate);
stateValue.generateDate = generateDateValue;
}
return stateValue;
};
private getMultiSelectedState = (
value: Dayjs
): Pick<AtCalendarState, "selectedDate"> => {
const { selectedDate } = this.state;
const { end, start } = selectedDate;
const valueUnix: number = value.valueOf();
const state: Pick<AtCalendarState, "selectedDate"> = {
selectedDate,
};
if (end) {
state.selectedDate = this.getSelectedDate(valueUnix, 0);
} else {
state.selectedDate.end = Math.max(valueUnix, +start);
state.selectedDate.start = Math.min(valueUnix, +start);
}
return state;
};
private getSelectedDate = (
start: number,
end?: number
): Calendar.SelectedDate => {
const stateValue: Calendar.SelectedDate = {
start,
end: start,
};
if (typeof end !== "undefined") {
stateValue.end = end;
}
return stateValue;
};
private getInitializeState(
currentDate: Calendar.DateArg | Calendar.SelectedDate,
isMultiSelect?: boolean
): AtCalendarState {
let end: number;
let start: number;
let generateDateValue: number;
if (!currentDate) {
const dayjsStart = dayjs();
start = dayjsStart.startOf("day").valueOf();
// generateDateValue = dayjsStart.startOf("month").valueOf(); // 初始化选择器时间为每月第一天
generateDateValue = dayjsStart.startOf("day").valueOf();
return {
generateDate: generateDateValue,
selectedDate: {
start: "",
},
};
}
if (isMultiSelect) {
const { start: cStart, end: cEnd } = currentDate as Calendar.SelectedDate;
const dayjsStart = dayjs(cStart);
start = dayjsStart.startOf("day").valueOf();
generateDateValue = dayjsStart.startOf("month").valueOf();
end = cEnd ? dayjs(cEnd).startOf("day").valueOf() : start;
} else {
const dayjsStart = dayjs(currentDate as Calendar.DateArg);
start = dayjsStart.startOf("day").valueOf();
// generateDateValue = dayjsStart.startOf("month").valueOf(); // 初始化选择器时间为每月第一天
generateDateValue = dayjsStart.startOf("day").valueOf();
end = start;
}
return {
generateDate: generateDateValue,
selectedDate: this.getSelectedDate(start, end),
};
}
private triggerChangeDate = (value: Dayjs): void => {
const { format } = this.props;
if (typeof this.props.onMonthChange !== "function") return;
this.props.onMonthChange(value.format(format));
};
private setMonth = (vectorCount: number): void => {
const { format } = this.props;
const { generateDate } = this.state;
const _generateDate: Dayjs = dayjs(generateDate).add(vectorCount, "month");
this.setState({
generateDate: _generateDate.valueOf(),
});
if (vectorCount && typeof this.props.onMonthChange === "function") {
this.props.onMonthChange(_generateDate.format(format));
}
};
private handleClickPreMonth = (isMinMonth?: boolean): void => {
if (isMinMonth === true) {
return;
}
this.setMonth(-1);
if (typeof this.props.onClickPreMonth === "function") {
this.props.onClickPreMonth();
}
};
private handleClickNextMonth = (isMaxMonth?: boolean): void => {
if (isMaxMonth === true) {
return;
}
this.setMonth(1);
if (typeof this.props.onClickNextMonth === "function") {
this.props.onClickNextMonth();
}
};
// picker 选择时间改变时触发
private handleSelectDate = (e: BaseEventOrig<{ value: string }>): void => {
const { value } = e.detail;
const _generateDate: Dayjs = dayjs(value);
const _generateDateValue: number = _generateDate.valueOf();
if (this.state.generateDate === _generateDateValue) return;
this.triggerChangeDate(_generateDate);
this.setState({
generateDate: _generateDateValue,
});
Taro.eventCenter.trigger(
"onSelectDataChange",
dayjs(_generateDateValue).format("YYYY-MM-DD")
);
console.log("this.state", this.state);
};
private handleDayClick = (item: Calendar.Item): void => {
console.log("handleDayClick", item);
const { isMultiSelect } = this.props;
const { isDisabled, value } = item;
if (isDisabled) return;
const dayjsDate: Dayjs = dayjs(value);
let stateValue: Partial<AtCalendarState> = {};
if (isMultiSelect) {
stateValue = this.getMultiSelectedState(dayjsDate);
} else {
stateValue = this.getSingleSelectdState(dayjsDate);
}
this.setState(stateValue as AtCalendarState, () => {
this.handleSelectedDate();
});
if (typeof this.props.onDayClick === "function") {
this.props.onDayClick({ value: item.value });
}
};
private handleSelectedDate = (): void => {
const selectDate = this.state.selectedDate;
if (typeof this.props.onSelectDate === "function") {
const info: Calendar.SelectedDate = {
start: dayjs(selectDate.start).format(this.props.format),
};
if (selectDate.end) {
info.end = dayjs(selectDate.end).format(this.props.format);
}
this.props.onSelectDate({
value: info,
});
}
};
private handleDayLongClick = (item: Calendar.Item): void => {
if (typeof this.props.onDayLongClick === "function") {
this.props.onDayLongClick({ value: item.value });
}
};
public render(): JSX.Element {
const { generateDate, selectedDate } = this.state;
console.log(
"render generateDate",
dayjs(generateDate).format("YYYY-MM-DD")
);
const {
validDates,
marks,
format,
minDate,
maxDate,
isSwiper,
className,
hideArrow,
isVertical,
monthFormat,
selectedDates,
} = this.props as AtCalendarPropsWithDefaults;
return (
<View className={classnames("at-calendar", className)}>
<AtCalendarController
minDate={minDate}
maxDate={maxDate}
hideArrow={hideArrow}
monthFormat={monthFormat}
generateDate={generateDate}
onPreMonth={this.handleClickPreMonth}
onNextMonth={this.handleClickNextMonth}
onSelectDate={this.handleSelectDate}
/>
<AtCalendarBody
validDates={validDates}
marks={marks}
format={format}
minDate={minDate}
maxDate={maxDate}
isSwiper={isSwiper}
isVertical={isVertical}
selectedDate={selectedDate}
selectedDates={selectedDates}
generateDate={generateDate}
onDayClick={this.handleDayClick}
onSwipeMonth={this.setMonth}
onLongClick={this.handleDayLongClick}
/>
</View>
);
}
}

@ -0,0 +1,80 @@
import classnames from 'classnames'
import React from 'react'
import { Text, View } from '@tarojs/components'
import { Calendar } from '../../../../../types/calendar'
import * as constant from '../../common/constant'
const MAP: { [key: number]: string } = {
[constant.TYPE_PRE_MONTH]: 'pre',
[constant.TYPE_NOW_MONTH]: 'now',
[constant.TYPE_NEXT_MONTH]: 'next'
}
export interface Props {
list: Calendar.List<Calendar.Item>
onClick?: (item: Calendar.Item) => void
onLongClick?: (item: Calendar.Item) => void
}
export default class AtCalendarList extends React.Component<Props> {
private handleClick = (item: Calendar.Item): void => {
if (typeof this.props.onClick === 'function') {
this.props.onClick(item)
}
}
private handleLongClick = (item: Calendar.Item): void => {
if (typeof this.props.onLongClick === 'function') {
this.props.onLongClick(item)
}
}
public render(): JSX.Element | null {
const { list } = this.props
if (!list || list.length === 0) return null
return (
<View className='at-calendar__list flex'>
{list.map((item: Calendar.Item) => (
<View
key={`list-item-${item.value}`}
onClick={this.handleClick.bind(this, item)}
onLongPress={this.handleLongClick.bind(this, item)}
className={classnames(
'flex__item',
`flex__item--${MAP[item.type]}`,
{
'flex__item--today': item.isToday,
'flex__item--active': item.isActive,
'flex__item--selected': item.isSelected,
'flex__item--selected-head': item.isSelectedHead,
'flex__item--selected-tail': item.isSelectedTail,
'flex__item--blur':
item.isDisabled ||
item.type === constant.TYPE_PRE_MONTH ||
item.type === constant.TYPE_NEXT_MONTH
}
)}
>
<View className='flex__item-container'>
<View className='container-text'>{item.text}</View>
</View>
<View className='flex__item-extra extra'>
{item.marks && item.marks.length > 0 ? (
<View className='extra-marks'>
{item.marks.map((mark, key) => (
<Text key={key} className='mark'>
{mark.value}
</Text>
))}
</View>
) : null}
</View>
</View>
))}
</View>
)
}
}

@ -0,0 +1,20 @@
import React from "react";
import { View } from "@tarojs/components";
export default class AtCalendarHeader extends React.Component {
public render(): JSX.Element {
return (
<View className="at-calendar__header header">
<View className="header__flex">
<View className="header__flex-item"></View>
<View className="header__flex-item"></View>
<View className="header__flex-item"></View>
<View className="header__flex-item"></View>
<View className="header__flex-item"></View>
<View className="header__flex-item"></View>
<View className="header__flex-item"></View>
</View>
</View>
);
}
}

@ -0,0 +1,3 @@
export default {
component: true,
};

@ -0,0 +1 @@
@import "~taro-ui/dist/style/components/modal.scss";

@ -0,0 +1,13 @@
import { AtModal, AtModalHeader, AtModalContent, AtModalAction } from "taro-ui";
{
/* <AtModal isOpened>
<AtModalHeader></AtModalHeader>
<AtModalContent>
</AtModalContent>
<AtModalAction> <Button></Button> <Button></Button> </AtModalAction>
</AtModal> */
}

@ -0,0 +1,3 @@
export default {
component: true,
};

@ -0,0 +1,39 @@
.tab-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 100px;
background: #fff;
display: flex;
pointer-events: auto;
padding-bottom: env(safe-area-inset-bottom);
}
.tab-bar-border {
background-color: rgba(0, 0, 0, 0.33);
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 1px;
transform: scaleY(0.5);
}
.tab-bar-item {
flex: 1;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.tab-bar-item cover-image {
width: 54px;
height: 54px;
}
.tab-bar-item cover-view {
font-size: 20px;
}

@ -0,0 +1,92 @@
import { Component } from "react";
import Taro from "@tarojs/taro";
import { CoverView, CoverImage } from "@tarojs/components";
import "./index.less";
export default class Index extends Component {
state = {
selected: 2,
color: "#999",
selectedColor: "#000",
backgroundColor: "#ffffff",
borderStyle: "black",
list: [
{
pagePath: "pages/activity/activity",
text: "活动",
iconPath: "/img/tabar/1.png",
selectedIconPath: "/img/tabar/11.png",
},
{
pagePath: "pages/detect/detect",
text: "发现",
iconPath: "/img/tabar/2.png",
selectedIconPath: "/img/tabar/22.png",
},
{
pagePath: "pages/index/index",
text: "主页",
iconPath: "/img/tabar/3.png",
selectedIconPath: "/img/tabar/33.png",
},
{
pagePath: "pages/shop/shop",
text: "商城",
iconPath: "/img/tabar/4.png",
selectedIconPath: "/img/tabar/44.png",
},
{
pagePath: "pages/user/user",
text: "我的",
iconPath: "/img/tabar/5.png",
selectedIconPath: "/img/tabar/55.png",
},
],
};
switchTab(index, url) {
this.setSelected(index);
Taro.switchTab({ url: "/" + url });
// setTimeout(() => this.setSelected(index));
}
setSelected(idx: number) {
console.log("setSelected", idx);
this.setState({
selected: idx,
});
}
render() {
const { list, selected, color, selectedColor } = this.state;
return (
<CoverView className="tab-bar">
<CoverView className="tab-bar-border"></CoverView>
{list.map((item, index) => {
return (
<CoverView
key={item.pagePath}
className="tab-bar-item"
onClick={this.switchTab.bind(this, index, item.pagePath)}
>
<CoverImage
src={selected === index ? item.selectedIconPath : item.iconPath}
/>
<CoverView
style={{
color: selected === index ? selectedColor : color,
fontWeight: selected === index ? "500" : "bold",
fontSize: "11px",
}}
>
{item.text}
</CoverView>
</CoverView>
);
})}
</CoverView>
);
}
}

@ -0,0 +1,3 @@
export default definePageConfig({
navigationBarTitleText: "模板页",
});

@ -0,0 +1,49 @@
import { MpSplashDetail, WCUserLogin } from "../../utils/Interface";
import { Component, PropsWithChildren, useEffect, useState } from "react";
import Taro from "@tarojs/taro";
// 引入 Swiper, SwiperItem 组件
import {
View,
Text,
Image,
Video,
Swiper,
SwiperItem,
} from "@tarojs/components";
import "taro-ui/dist/style/components/button.scss"; // 按需引入
import "./activity.less";
const app = Taro.getApp();
import type CustomTabBar from "../../custom-tab-bar";
export default class Activity extends Component<any, any> {
pageCtx = Taro.getCurrentInstance().page;
constructor(props) {
super(props);
this.state = {
name: "activity",
};
}
async onLoad() {
console.log("app", app);
}
componentDidMount() {}
componentWillUnmount() {}
componentDidShow() {
const tabbar = Taro.getTabBar<CustomTabBar>(this.pageCtx);
tabbar?.setSelected(0);
}
componentDidHide() {}
async initData() {}
render() {
let { name } = this.state;
return <View>{name}</View>;
}
}

@ -0,0 +1,3 @@
export default definePageConfig({
navigationBarTitleText: "模板页",
});

@ -0,0 +1,49 @@
import { MpSplashDetail, WCUserLogin } from "../../utils/Interface";
import { Component, PropsWithChildren, useEffect, useState } from "react";
import Taro from "@tarojs/taro";
// 引入 Swiper, SwiperItem 组件
import {
View,
Text,
Image,
Video,
Swiper,
SwiperItem,
} from "@tarojs/components";
import "taro-ui/dist/style/components/button.scss"; // 按需引入
import "./detect.less";
const app = Taro.getApp();
import type CustomTabBar from "../../custom-tab-bar";
export default class Detect extends Component<any, any> {
pageCtx = Taro.getCurrentInstance().page;
constructor(props) {
super(props);
this.state = {
name: "detect",
};
}
async onLoad() {
console.log("app", app);
}
componentDidMount() {}
componentWillUnmount() {}
componentDidShow() {
const tabbar = Taro.getTabBar<CustomTabBar>(this.pageCtx);
tabbar?.setSelected(1);
}
componentDidHide() {}
async initData() {}
render() {
let { name } = this.state;
return <View>{name}</View>;
}
}

@ -0,0 +1,33 @@
/* ----------------------------------------------
* Generated by Animista on 2023-12-8 17:46:25
* Licensed under FreeBSD License.
* See http://animista.net/license for more info.
* w: http://animista.net, t: @cssanimista
* ---------------------------------------------- */
@-webkit-keyframes slide-left {
0% {
-webkit-transform: translateX(300rpx);
transform: translateX(300rpx);
}
100% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
@keyframes slide-left {
0% {
-webkit-transform: translateX(300rpx);
transform: translateX(300rpx);
}
100% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
/* 左侧滑入动画 */
.slide-left {
-webkit-animation: slide-left 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
animation: slide-left 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
}

@ -13,6 +13,8 @@ import {
import "taro-ui/dist/style/components/button.scss"; // 按需引入
import "./entry.less";
import "./Animista.less";
import "./fade.css";
const app = Taro.getApp();
@ -28,7 +30,18 @@ export default class Entry extends Component<any, any> {
current: 0,
toRight: false,
isClick: false,
welcomeList: [],
welcomeList: [
{
title: "花至小程序",
desc: "三步了解花至小程序这里写文案1",
image: "",
},
{
title: "花至小程序",
desc: "三步了解花至小程序这里写文案2",
image: "",
},
],
};
}
@ -113,7 +126,7 @@ export default class Entry extends Component<any, any> {
key={"swiper_" + index}
>
<View
className="body"
className="body FadeInFrame fadein"
style={{
top: menu.top + "px",
height: "calc(" + (100 % -menu.height) + "px)",
@ -121,12 +134,12 @@ export default class Entry extends Component<any, any> {
>
<Image
className="cover"
src="{{item.image}}"
src={item.image}
mode="aspectFill"
></Image>
<View className="bottom">
<View className="text">{item.title}</View>
<View className="txt">{item.desc}</View>
<View className="text slide-left">{item.title}</View>
<View className="txt slide-left">{item.desc}</View>
</View>
</View>
</SwiperItem>

@ -0,0 +1,22 @@
.FadeOutFrame {
opacity: 1;
}
.FadeOutFrame.fadeout {
-webkit-transition: all 1.5s;
-moz-transition: all 1.5s;
-ms-transition: all 1.5s;
-o-transition: all 1.5s;
transition: all 1.5s;
opacity: 0;
}
.FadeInFrame {
opacity: 0;
}
.FadeInFrame.fadein {
-webkit-transition: all 1.5s;
-moz-transition: all 1.5s;
-ms-transition: all 1.5s;
-o-transition: all 1.5s;
transition: all 1.5s;
opacity: 1;
}

@ -0,0 +1,2 @@
错误类型收集
MiniProgramError 页面跳转错误

@ -0,0 +1,3 @@
export default definePageConfig({
navigationBarTitleText: "模板页",
});

@ -0,0 +1,44 @@
import { MpSplashDetail, WCUserLogin } from "../../utils/Interface";
import { Component, PropsWithChildren, useEffect, useState } from "react";
import Taro from "@tarojs/taro";
// 引入 Swiper, SwiperItem 组件
import {
View,
Text,
Image,
Video,
Swiper,
SwiperItem,
} from "@tarojs/components";
import "taro-ui/dist/style/components/button.scss"; // 按需引入
import "./template.less";
const app = Taro.getApp();
export default class Index extends Component<any, any> {
constructor(props) {
super(props);
this.state = {
name: "template模板页",
};
}
async onLoad() {
console.log("app", app);
}
componentDidMount() {}
componentWillUnmount() {}
componentDidShow() {}
componentDidHide() {}
async initData() {}
render() {
let { name } = this.state;
return <View>{name}</View>;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -38,7 +38,7 @@ export default class Index extends Component<any, any> {
const menu = Taro.getMenuButtonBoundingClientRect();
this.setState({ menu });
console.log("menu", menu);
// Taro.setStorageSync("isWelcome", true);
Taro.setStorageSync("isWelcome", true);
// await this.inData();
}
componentDidMount() {
@ -76,19 +76,24 @@ export default class Index extends Component<any, any> {
const { clientX, clientY } = event.changedTouches[0];
const { touchX, touchY } = this.state;
if (clientX - touchX < -50 && Math.abs(clientY - touchY) < 50) {
console.log("clientX - touchX", clientX - touchX, clientX, touchX);
console.log(
"clientX - touchX < -30 && Math.abs(clientY - touchY) > 30",
clientX - touchX < -30,
Math.abs(clientY - touchY) < 30,
Math.abs(clientY - touchY)
);
if (clientX - touchX < -30 && Math.abs(clientY - touchY) < 30) {
this.onEnded();
}
}
onEnded() {
onEnded = () => {
let timeOut: any = null;
return () => {
clearTimeout(timeOut);
timeOut = setTimeout(() => {
go("/pages/entry/entry");
}, 300);
};
}
clearTimeout(timeOut);
timeOut = setTimeout(() => {
go("/pages/entry/entry");
}, 300);
};
render() {
let { menu } = this.state;
@ -101,7 +106,7 @@ export default class Index extends Component<any, any> {
<Swiper className="absolutely">
<SwiperItem
className="absolutely"
onClick={this.onEnded()}
onClick={this.onEnded}
style="background: #ccc"
>
<View

@ -0,0 +1,3 @@
export default definePageConfig({
navigationBarTitleText: "注册",
});

@ -0,0 +1,310 @@
import { MpSplashDetail, WCUserLogin } from "../../utils/Interface";
import { Component, PropsWithChildren, useEffect, useState } from "react";
import Taro from "@tarojs/taro";
// 引入 Swiper, SwiperItem 组件
import {
View,
Text,
Image,
Button,
Video,
Swiper,
SwiperItem,
} from "@tarojs/components";
import "taro-ui/dist/style/components/button.scss"; // 按需引入
import "./template.less";
const app = Taro.getApp();
export default class Register extends Component<any, any> {
constructor(props) {
super(props);
this.state = {
name: "注册",
style:
"width:calc(100% - 100rpx);background:#fff;border-radius: 20rpx;box-shadow: -2rpx 0 12rpx .5rpx rgba(129, 129, 129, 0.1); height: 800rpx; padding: 30rpx;",
titleHeight: "",
menu: {},
isChecked: false,
isRegister: false,
isShow: false,
userAgreement: "",
policy: "",
bg: "",
showPrivacyPopup: false,
showPrivacyContent: false,
skipby: "",
fromUrl: "",
};
}
/**
* --
*/
async onLoad(options) {
// this.checkPrivacy();
// if(options.fromUrl) {
// this.setData({
// fromUrl: options.fromUrl
// })
// }
// if (options.skipby) {
// this.setData({
// skipby: options.skipby
// })
// }
// if (!app.globalData.token) {
// await this.WCUserLogin();
// }
// that = this;
// const menu = wx.getMenuButtonBoundingClientRect();
// const titleHeight = 'height:' + (Number(menu.top) + Number(menu.height) + 10) + 'px;';
// this.setData({titleHeight, menu});
// await this.getBg()
}
onSkip() {
// wx.switchTab({
// url: '/pages/index/index'
// })
}
onSkipTap() {
// app.globalData.bindCodeSkipRegister = true;
// this.onSkip();
}
checkPrivacy() {
// const res = compareVersion('2.32.3');
// const that = this;
// if (res >= 0) {
// // 弹出弹窗
// wx.getPrivacySetting({
// success: res => {
// if (res.needAuthorization) {
// that.setData({
// showPrivacyPopup: true
// });
// app.globalData.needAuthorization = true;
// }
// },
// fail: err => {},
// complete: res => {},
// });
// }
}
onDisagreeTap() {
// // 关闭小程序
// wx.exitMiniProgram({
// success: res=>{},
// fail: err=>{},
// complete: res=>{}
// })
}
async onPrivacyTap() {
// // 打开隐私协议
// go('/pages/xieyi1/xieyi1');
}
onClosePrivacyContentPopup() {
// this.setData({
// showPrivacyContent: false
// });
}
handleAgreePrivacyAuthorization() {
// this.setData({
// showPrivacyPopup: false
// });
// app.globalData.needAuthorization = false;
}
async getBg() {
// const {data} = await MpLoginDetail();
// if (data.code === 200) {
// this.setData({bg: data.data.data.image});
// }
}
onCheck() {
// const {isChecked} = this.data;
// this.setData({isChecked: !isChecked});
}
onSubmit(event) {
// if (event.detail.errMsg !== 'getPhoneNumber:ok') return msg('获取失败');
// const {encryptedData, iv} = event.detail;
// wx.login({
// success: ({code}) => {
// this.onUpdateMobile({encryptedData, iv, code})
// }
// })
}
onUpdateMobile(data) {
// GetUserMobile(data).then((res) => {
// msg('授权成功');
// const mobile = res.data.data.list.phoneNumber;
// loading('注册中');
// UserInfoRegister({mobile}).then((res) => {
// if (res.data.code === 200) {
// this.setData({isRegister: true});
// setTimeout(() => {
// this.onCloseRegister()
// }, 2000)
// }
// });
// })
}
onCloseRegister() {
// if (!this.data.isRegister) return;
// this.setData({isRegister: false});
// if(this.data.fromUrl) {
// const url = this.data.fromUrl
// this.setData({
// fromUrl: '',
// })
// wx.redirectTo({
// url: decodeURIComponent(url),
// })
// } else {
// go('/pages/userInfo/userInfo')
// }
}
onClosePopup() {
// this.setData({isShow: false, userAgreement: null, policy: null});
}
async onPopup(event) {
// const {type} = event.target.dataset
// const request = type === 'agreement' ? await UserAgreement() : await UserPrivacyAgreement();
// const {data} = request;
// if (data.code === 200) {
// this.setData({
// userAgreement: data.data.data?.user_agreement?.value ? formatRichText(data.data.data?.user_agreement?.value) : null,
// policy: data.data.data?.user_privacy_agreement?.value ? formatRichText(data.data.data?.user_privacy_agreement?.value) : null,
// isShow: true
// })
// }
}
componentDidMount() {}
componentWillUnmount() {}
componentDidShow() {}
componentDidHide() {}
async initData() {}
render() {
let { name } = this.state;
let bg = "";
let skipby = "";
let isChecked = false;
return (
<View>
<View style="background:#fff;" className="nav">
<View className="nav_box">
<View className="logo">
<Image src="https://oss.flossom.com/logo2.png" mode="widthFix" />
</View>
</View>
</View>
<View></View>
<View className="main">
<Image className="bg" src={bg} mode="aspectFill"></Image>
</View>
<View className="footer">
<View className="title"></View>
<View className="content">
<Text onClick={this.onPopup} data-type="agreement">
</Text>
<Text onClick={this.onPopup} data-type="policy">
</Text>
</View>
<Button
style={{ opacity: isChecked ? 1 : 0.6 }}
type="primary"
disabled={!isChecked}
open-type="getPhoneNumber"
className="btn_login"
onGetPhoneNumber={this.onSubmit}
>
</Button>
{skipby !== "bindCode" ? (
<View className="checked_box">
<Image
onClick={this.onCheck}
className="icon"
src="/img/welcome/checked.png"
></Image>
<View className="tips">
</View>
</View>
) : (
""
)}
<Image
className="close"
mode="widthFix"
src="/img/close.png"
onClick={this.onSkip}
></Image>
</View>
{skipby == "bindCode" ? (
<View className="skip_footer_box">
<View className="checked_box">
{isChecked ? (
<Image
onClick={this.onCheck}
className="icon"
src="/img/welcome/checked.png"
></Image>
) : (
<Image
onClick={this.onCheck}
className="icon"
src="/img/welcome/unchecked.png"
></Image>
)}
<View className="tips">
</View>
</View>
<View className="skip_footer">
<Button
style="opacity: {{ isChecked ? 1 : .6 }}"
type="primary"
disabled={!isChecked}
open-type="getPhoneNumber"
className="skip_foorer_autoBtn"
onGetPhoneNumber={this.onSubmit}
>
</Button>
<View className="skip_foorer_btn" onClick={this.onSkipTap}>
{" "}
</View>
</View>
</View>
) : (
""
)}
</View>
);
}
}

@ -0,0 +1,3 @@
export default definePageConfig({
navigationBarTitleText: "模板页",
});

@ -0,0 +1,49 @@
import { MpSplashDetail, WCUserLogin } from "../../utils/Interface";
import { Component, PropsWithChildren, useEffect, useState } from "react";
import Taro from "@tarojs/taro";
// 引入 Swiper, SwiperItem 组件
import {
View,
Text,
Image,
Video,
Swiper,
SwiperItem,
} from "@tarojs/components";
import "taro-ui/dist/style/components/button.scss"; // 按需引入
import "./shop.less";
const app = Taro.getApp();
import type CustomTabBar from "../../custom-tab-bar";
export default class Shop extends Component<any, any> {
pageCtx = Taro.getCurrentInstance().page;
constructor(props) {
super(props);
this.state = {
name: "shop",
};
}
async onLoad() {
console.log("app", app);
}
componentDidMount() {}
componentWillUnmount() {}
componentDidShow() {
const tabbar = Taro.getTabBar<CustomTabBar>(this.pageCtx);
tabbar?.setSelected(3);
}
componentDidHide() {}
async initData() {}
render() {
let { name } = this.state;
return <View>{name}</View>;
}
}

@ -0,0 +1,3 @@
export default definePageConfig({
navigationBarTitleText: "我的",
});

@ -0,0 +1,49 @@
import { MpSplashDetail, WCUserLogin } from "../../utils/Interface";
import { Component, PropsWithChildren, useEffect, useState } from "react";
import Taro from "@tarojs/taro";
// 引入 Swiper, SwiperItem 组件
import {
View,
Text,
Image,
Video,
Swiper,
SwiperItem,
} from "@tarojs/components";
import "taro-ui/dist/style/components/button.scss"; // 按需引入
import "./user.less";
const app = Taro.getApp();
import type CustomTabBar from "../../custom-tab-bar";
export default class User extends Component<any, any> {
pageCtx = Taro.getCurrentInstance().page;
constructor(props) {
super(props);
this.state = {
name: "user",
};
}
async onLoad() {
console.log("app", app);
}
componentDidMount() {}
componentWillUnmount() {}
componentDidShow() {
const tabbar = Taro.getTabBar<CustomTabBar>(this.pageCtx);
tabbar?.setSelected(4);
}
componentDidHide() {}
async initData() {}
render() {
let { name } = this.state;
return <View>{name}</View>;
}
}

@ -0,0 +1,22 @@
import { createSlice } from "@reduxjs/toolkit";
const counterSlice = createSlice({
name: "counter", // store的名字
initialState: {
counter: 100,
},
reducers: {
addNumber(state, action) {
// 这里可以拿到state直接赋值在最开始的写法中我们需要通过{ ...state, ...newObj }返回一个新的对象
state.counter = state.counter + action.payload;
},
subNumber(state, { payload }) {
state.counter = state.counter - payload;
},
},
});
// 创建好store之后我们仍需要将Slice对象的actions和reducer导出
// 这里的addNumber和subNumber其实就是一个actionCreator()调用即可获得一个action对象
// 例如 addNumber(12)的返回值是{ type: 'addNumber', payload: 12}这样一个action对象
export const { addNumber, subNumber } = counterSlice.actions;
export default counterSlice.reducer;

@ -0,0 +1,12 @@
import { configureStore } from "@reduxjs/toolkit";
// 导入counter模块下的reducer函数
import counterReducer from "./features/counter";
const store = configureStore({
reducer: {
// 每个reducer都可以理解成一个子仓库
counter: counterReducer,
},
});
export default store;

231
types/calendar.d.ts vendored

@ -0,0 +1,231 @@
import dayjs from 'dayjs'
import { BaseEvent } from '@tarojs/components/types/common'
// #region Calendar
declare namespace Calendar {
export type DateArg = string | number
export type classNameType =
| string
| Array<string>
| { [key: string]: boolean }
export interface Mark {
value: DateArg
}
export interface ValidDate {
value: DateArg
}
export interface Item {
value: string
_value?: dayjs.Dayjs
text: number
type: number
marks: Array<Mark>
isActive?: boolean
isToday?: boolean
isBeforeMin?: boolean
isAfterMax?: boolean
isDisabled?: boolean
isSelected?: boolean
isSelectedHead?: boolean
isSelectedTail?: boolean
}
export interface SelectedDate {
end?: Calendar.DateArg
start: Calendar.DateArg
}
export interface GroupOptions {
validDates: Array<ValidDate>
marks: Array<Mark>
format: string
selectedDates: Array<SelectedDate>
minDate?: DateArg
maxDate?: DateArg
}
export type List<T> = Array<T>
export type ListInfo<T> = {
value: number
list: List<T>
}
}
export default Calendar
export { Calendar }
// #endregion
// #region AtCalendar
export interface AtCalendarPropsBase {
format?: string
validDates?: Array<Calendar.ValidDate>
minDate?: Calendar.DateArg
maxDate?: Calendar.DateArg
isSwiper?: boolean
marks?: Array<Calendar.Mark>
monthFormat?: string
hideArrow?: boolean
isVertical?: boolean
className?: Calendar.classNameType
onClickPreMonth?: () => void
onClickNextMonth?: () => void
onSelectDate?: (item: { value: Calendar.SelectedDate }) => void
onDayClick?: (item: { value: string }) => void
onDayLongClick?: (item: { value: string }) => void
onMonthChange?: (value: string) => void
}
export interface AtCalendarSingleSelectedProps extends AtCalendarPropsBase {
isMultiSelect?: false
currentDate?: Calendar.DateArg
}
export interface AtCalendarMutilSelectedProps extends AtCalendarPropsBase {
isMultiSelect?: true
currentDate?: Calendar.SelectedDate
}
export type AtCalendarProps =
| AtCalendarSingleSelectedProps
| AtCalendarMutilSelectedProps
export interface AtCalendarDefaultProps {
format: string
isSwiper: boolean
validDates: Array<Calendar.ValidDate>
marks: Array<Calendar.Mark>
currentDate: Calendar.DateArg | Calendar.SelectedDate
monthFormat: string
hideArrow: boolean
isVertical: boolean
isMultiSelect: boolean
selectedDates: Array<Calendar.SelectedDate>
}
export interface AtCalendarState {
generateDate: number
selectedDate: Calendar.SelectedDate
}
export type AtCalendarPropsWithDefaults = AtCalendarProps &
AtCalendarDefaultProps
// #endregion
// #region AtCalendarController
export interface AtCalendarControllerProps {
generateDate: Calendar.DateArg
minDate?: Calendar.DateArg
maxDate?: Calendar.DateArg
hideArrow: boolean
monthFormat: string
onPreMonth: () => void
onNextMonth: () => void
onSelectDate: (e: BaseEvent) => void
}
export interface AtCalendarControllerState { }
// #endregion
// #region AtCalendarBody
export type AtCalendarBodyListGroup = Array<Calendar.ListInfo<Calendar.Item>>
export interface AtCalendarBodyProps {
format: string
validDates: Array<Calendar.ValidDate>
marks: Array<Calendar.Mark>
isSwiper: boolean
minDate?: Calendar.DateArg
maxDate?: Calendar.DateArg
isVertical: boolean
generateDate: number
selectedDate: Calendar.SelectedDate
selectedDates: Array<Calendar.SelectedDate> | []
onDayClick: (item: Calendar.Item) => void
onSwipeMonth: (vectorCount: number) => void
onLongClick: (item: Calendar.Item) => void
}
export interface AtCalendarBodyState {
temporaryCalendarWeek: any
temporaryCalendar: any
isFolding: boolean
isAnimate: boolean
offsetSize: number
listGroup: AtCalendarBodyListGroup
}
// #endregion

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save