UNPKG

mp-colorui

Version:

MP ColorUI 是一款基于 Taro 框架并且联合 Color-UI CSS 库开发的多端 UI 组件库(支持小程序端和H5端)

504 lines (500 loc) 19.5 kB
import Nerv from "nervjs"; var _this = this; import Taro from "@tarojs/taro-h5"; import { View, Swiper, SwiperItem } from "@tarojs/components"; import dayjs from "dayjs"; import ClGrid from "../../grid/index"; import ClText from "../../text/index"; import ClFlex from "../../flex/index"; import ClLayout from "../../layout/index"; import ClCard from "../../card/index"; import ClIcon from "../../icon/index"; import { classNames } from "../../../lib/index"; import { BG_COLOR_LIST, TEXT_COLOR_LIST } from "../../../lib/model"; import ClButton from "../../button/index"; import ClTip from "../../tip/index"; import "../index.scss"; export default class Calendar_weapp extends Taro.Component { render() { const props = this.props; const { highlightWeekendColor, calendarType, showType, activeColor, tipDay, backToToday, disabledDay, badge, onChange, onClick, highlightWeekend, specialDay } = props; const FORMAT_DATE = "YYYY-MM-DD"; const THIS_WEEK = "thisWeek"; const PRE_WEEK = "preWeek"; const NEXT_WEEK = "nextWeek"; const PRE_MONTH = "preMonth"; const THIS_MONTH = "thisMonth"; const NEXT_MONTH = "nextMonth"; const today = dayjs().format(FORMAT_DATE); const mapChangeWeekIndex = [PRE_WEEK, THIS_WEEK, NEXT_WEEK]; const mapChangeMonthIndex = [PRE_MONTH, THIS_MONTH, NEXT_MONTH]; const [thisWeek, setThisWeek] = Taro.useState([]); const [preWeek, setPreWeek] = Taro.useState([]); const [nextWeek, setNextWeek] = Taro.useState([]); const [thisMonth, setThisMonth] = Taro.useState([]); const [preMonth, setPreMonth] = Taro.useState([]); const [nextMonth, setNextMonth] = Taro.useState([]); const [chooseDate, setChooseDate] = Taro.useState(today); const [currentDate, setCurrentDate] = Taro.useState(dealYearMonth(dayjs(today))); const [currentActive, setCurrentActive] = Taro.useState(1); const [currentActiveLines, setCurrentActiveLines] = Taro.useState(5); const [showMonths, setShowMonths] = Taro.useState(false); const [currentYear, setCurrentYear] = Taro.useState(dayjs().year()); const selectDate = month => { const year = currentYear; const date = `${year}-${month + 1}-01`; changeMonth(date); setShowMonths(false); setCurrentDate(dealYearMonth(dayjs(date))); }; function dealYearMonth(day) { return `${day.year()}${day.month() + 1}月`; } const clickDate = ({ item }) => { if (item.disabled) return; if (item.empty) return; if (calendarType === "week") { const weeks = { thisWeek, preWeek, nextWeek }; Object.keys(weeks).forEach(week => { weeks[week].forEach(item => item.active = false); }); } else { const months = { thisMonth, preMonth, nextMonth }; Object.keys(months).forEach(month => { months[month].forEach(item => item.active = false); }); } item.active = true; setChooseDate(item.date); onClick && onClick(item.date); }; const getPreNextArray = (index, data) => { const varChange = calendarType === "week" ? { PRE: PRE_WEEK, THIS: THIS_WEEK, NEXT: NEXT_WEEK } : { PRE: PRE_MONTH, THIS: THIS_MONTH, NEXT: NEXT_MONTH }; const dataChange = calendarType === "week" ? { PRE: "tempPreWeek", THIS: "tempThisWeek", NEXT: "tempNextWeek" } : { PRE: "tempPreMonth", THIS: "tempThisMonth", NEXT: "tempNextMonth" }; let current = { [varChange.PRE]: data[dataChange.PRE], [varChange.THIS]: data[dataChange.THIS], [varChange.NEXT]: data[dataChange.NEXT] }; if (index === 0) { current[varChange.PRE] = data[dataChange.THIS]; current[varChange.THIS] = data[dataChange.NEXT]; current[varChange.NEXT] = data[dataChange.PRE]; } if (index === 2) { current[varChange.PRE] = data[dataChange.NEXT]; current[varChange.THIS] = data[dataChange.PRE]; current[varChange.NEXT] = data[dataChange.THIS]; } return current; }; const changeDate = arrayIndex => { let currentDate = ""; if (calendarType === "week") { const oldWeeks = { thisWeek, preWeek, nextWeek }; const showWeeks = oldWeeks[mapChangeWeekIndex[arrayIndex]]; setCurrentDate(dealYearMonth(dayjs(showWeeks[3].date))); currentDate = dayjs(showWeeks[3].date).format("YYYY-MM"); const newWeeks = getWeeks(oldWeeks[mapChangeWeekIndex[arrayIndex]][3].date); const current = getPreNextArray(arrayIndex, newWeeks); setCurrentActive(arrayIndex); setPreWeek(current[PRE_WEEK]); setNextWeek(current[NEXT_WEEK]); setThisWeek(current[THIS_WEEK]); } else { const oldMonths = { thisMonth, preMonth, nextMonth }; const showMonths = oldMonths[mapChangeMonthIndex[arrayIndex]]; currentDate = dayjs(showMonths[8].date).format("YYYY-MM"); setCurrentDate(dealYearMonth(dayjs(showMonths[8].date))); setCurrentActiveLines(Math.ceil(showMonths.length / 7)); const newMonths = getMonths(oldMonths[mapChangeMonthIndex[arrayIndex]][8].date); const current = getPreNextArray(arrayIndex, newMonths); setCurrentActive(arrayIndex); setPreMonth(current[PRE_MONTH]); setNextMonth(current[NEXT_MONTH]); setThisMonth(current[THIS_MONTH]); } onChange && onChange(currentDate); }; function changeMonth(date) { if (calendarType === "week") { const weeks = getWeeks(date); let newIndex = currentActive + 1 > 2 ? 0 : currentActive + 1; setCurrentActive(newIndex); const current = getPreNextArray(newIndex, weeks); setPreWeek(current[PRE_WEEK]); setNextWeek(current[NEXT_WEEK]); setThisWeek(current[THIS_WEEK]); } else { const months = getMonths(date); let newIndex = currentActive + 1 > 2 ? 0 : currentActive + 1; setCurrentActive(newIndex); const current = getPreNextArray(newIndex, months); setPreMonth(current[PRE_MONTH]); setNextMonth(current[NEXT_MONTH]); setThisMonth(current[THIS_MONTH]); } } const handleBackToToday = () => { setChooseDate(today); changeMonth(today); }; function dealEveryDay({ i, currentDay, date }) { const thisNum = i - currentDay; const method = thisNum > 0 ? "add" : "subtract"; const day = dayjs(date)[method](Math.abs(thisNum), "day"); const tipDayArray = tipDay || []; let dateData = { timeStamp: day.valueOf(), date: day.format(FORMAT_DATE), month: day.get("month"), day: day.get("date"), year: day.get("year"), today: today === day.format(FORMAT_DATE), old: dayjs(today).valueOf() - day.valueOf() > 0, active: chooseDate === day.format(FORMAT_DATE), tipTop: "", tipBottom: "", badge: { show: false, color: "red", num: "" }, disabled: false, special: { show: false, color: "green" }, highlight: highlightWeekend ? [0, 6].includes(day.get("day")) : false }; // tip const tipIndex = tipDayArray.findIndex(item => item.date === dateData.date); if (tipIndex >= 0) { const tipData = tipDayArray[tipIndex]; dateData = Object.assign(dateData, { tipTop: tipData.tipTop || "", tipBottom: tipData.tipBottom || "", tipTopColor: tipData.tipTopColor, tipBottomColor: tipData.tipBottomColor }); } // badge if (typeof badge === "string" && dateData.date === badge) { Object.assign(dateData.badge, { show: true }); } else if (badge instanceof Array) { badge.forEach(item => { if (item.date === dateData.date) { Object.assign(dateData.badge, { show: true, color: item.color || "red", num: item.num || "" }); } }); } // disabledDay if (disabledDay instanceof Array) { disabledDay.forEach(item => { if (typeof item === "string") { dateData.disabled = dateData.date === item; } else if (item instanceof Array) { let minDate = item[0] && dayjs(item[0]).valueOf(); let maxDate = item[1] && dayjs(item[1]).valueOf(); if (minDate && maxDate) { dateData.disabled = dateData.timeStamp > minDate && dateData.timeStamp < maxDate; } else if (minDate) { dateData.disabled = dateData.timeStamp > minDate; } else if (maxDate) { dateData.disabled = dateData.timeStamp < maxDate; } } }); } // specialDay if (specialDay instanceof Array) { specialDay.forEach(item => { if (typeof item === "string") { dateData.special.show = item === dateData.date; } else if (typeof item === "object") { const date = item.date; const color = item.color; Object.assign(dateData.special, { date: date === dateData.date, color }); } }); } return dateData; } function getWeeks(date) { const weekday = dayjs(date).day(); const tempThisWeek = []; const tempPreWeek = []; const tempNextWeek = []; let i = -7; while (1) { if (i >= 14) break; const dateData = dealEveryDay({ i, currentDay: weekday, date }); if (i < 0) { tempPreWeek.push(dateData); } else if (i >= 7) { tempNextWeek.push(dateData); } else { tempThisWeek.push(dateData); } i++; } return { tempThisWeek, tempPreWeek, tempNextWeek }; } function fillMonths(months) { const firstDay = months[0]; let weekday = dayjs(firstDay.date).day(); while (weekday) { months.unshift({ timeStamp: weekday, date: "", month: "", day: "", year: "", today: false, old: false, active: false, tipTop: "", tipBottom: "", badge: { show: false, color: "red", num: "" }, disabled: false, special: { show: false, color: "green" }, empty: true }); weekday--; } return months; } function getMonths(date) { const tempThisMonth = []; const tempPreMonth = []; const tempNextMonth = []; const preMonthDays = dayjs(date).subtract(1, "month").daysInMonth(); const thisMonthDays = dayjs(date).daysInMonth(); const thisDays = dayjs(date).date(); const nextMonthDays = dayjs(date).add(1, "month").daysInMonth(); let i = -preMonthDays + 1; while (1) { if (i > nextMonthDays + thisMonthDays) break; const dateData = dealEveryDay({ i, currentDay: thisDays, date }); if (i <= 0) { tempPreMonth.push(dateData); } else if (i > thisMonthDays) { tempNextMonth.push(dateData); } else { tempThisMonth.push(dateData); } i++; } return { tempThisMonth: fillMonths(tempThisMonth), tempPreMonth: fillMonths(tempPreMonth), tempNextMonth: fillMonths(tempNextMonth) }; } // useEffect(() => {}, [preWeek, nextWeek, thisWeek]); Taro.useEffect(() => { if (calendarType === "week") { const weeks = getWeeks(today); setPreWeek(weeks.tempPreWeek); setThisWeek(weeks.tempThisWeek); setNextWeek(weeks.tempNextWeek); } else { const months = getMonths(today); setPreMonth(months.tempPreMonth); setThisMonth(months.tempThisMonth); setNextMonth(months.tempNextMonth); } }, [calendarType]); const weekGridComponent = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"].map((week, index) => <View key={week}> <ClText align={"center"} size={"small"} lineSpacing={"small"} textColor={highlightWeekend ? [0, 6].includes(index) ? highlightWeekendColor : "black" : "black"}> {week} </ClText> </View>); const BGClassName = BG_COLOR_LIST[activeColor || "blue"]; const oldTextClassName = TEXT_COLOR_LIST["gray"]; const weeksComponent = [preWeek, thisWeek, nextWeek].map((week, index) => <SwiperItem key={week[3].date}> <ClGrid col={7}> {week.map(item => <View key={item.timeStamp} onClick={clickDate.bind(this, { item, type: mapChangeWeekIndex[index] })}> <ClLayout padding={"small"} paddingDirection={"vertical"}> <ClFlex align={"center"} justify={"center"}> <View style={{ position: "relative" }} className={classNames(["day-normal", `${item.disabled ? BG_COLOR_LIST["gray"] : ""}`, `${item.special.show && !item.active ? BG_COLOR_LIST[item.special.color] : ""}`, { [BGClassName]: !item.disabled && item.active, [oldTextClassName]: item.old }])}> <View className={classNames([{ ["cu-tag badge"]: item.badge.show }, BG_COLOR_LIST[item.badge.color]])}> {item.badge.num} </View> <ClFlex align={"center"} justify={"center"} direction={"column"}> <ClText size={12} align={"center"} cut={true} style={{ maxWidth: Taro.pxTransform(50) }} textColor={item.active && !item.disabled ? undefined : item.tipTopColor} text={item.tipTop} /> <ClText text={item.day} textColor={!item.active && !item.disabled && item.highlight ? highlightWeekendColor : undefined} /> <ClText size={12} align={"center"} cut={true} style={{ maxWidth: Taro.pxTransform(50) }} textColor={item.active && !item.disabled ? undefined : item.tipBottomColor} text={item.tipBottom} /> </ClFlex> </View> </ClFlex> </ClLayout> </View>)} </ClGrid> </SwiperItem>); const monthsComponent = [preMonth, thisMonth, nextMonth].map((month, index) => <SwiperItem key={month[3].date}> <ClGrid col={7}> {month.map(item => <View key={item.timeStamp} onClick={clickDate.bind(this, { item, type: mapChangeWeekIndex[index] })}> <ClLayout padding={"small"} paddingDirection={"vertical"}> <ClFlex align={"center"} justify={"center"}> <View style={{ position: "relative" }} className={classNames(["day-normal", `${item.disabled ? BG_COLOR_LIST["gray"] : ""}`, `${item.special.show && !item.active ? BG_COLOR_LIST[item.special.color] : ""}`, { [BGClassName]: !item.disabled && item.active, [oldTextClassName]: item.old }])}> <View className={classNames([{ ["cu-tag badge"]: item.badge.show }, BG_COLOR_LIST[item.badge.color]])}> {item.badge.num} </View> <ClFlex align={"center"} justify={"center"} direction={"column"}> <ClText size={12} align={"center"} cut={true} style={{ maxWidth: Taro.pxTransform(50) }} textColor={item.active && !item.disabled ? undefined : item.tipTopColor} text={item.tipTop} /> <ClText text={item.day} textColor={!item.active && !item.disabled && item.highlight ? highlightWeekendColor : undefined} /> <ClText size={12} align={"center"} cut={true} style={{ maxWidth: Taro.pxTransform(50) }} textColor={item.active && !item.disabled ? undefined : item.tipBottomColor} text={item.tipBottom} /> </ClFlex> </View> </ClFlex> </ClLayout> </View>)} </ClGrid> </SwiperItem>); const months = Array.from(Array(12)).map((item, index) => `${index + 1}月`); return <ClCard type={showType}> <View className={classNames([BG_COLOR_LIST["white"], "cuCalendar"])}> <ClLayout padding={"small"} paddingDirection={"bottom"}> <ClFlex justify={"between"} align={"center"}> <ClTip renderMessage={<View> <ClLayout> <ClFlex align={"center"} justify={"between"}> <View onClick={() => { setCurrentYear(currentYear - 1); }}> <ClIcon iconName={"pullleft"} /> </View> <ClText text={currentYear + ""} /> <View onClick={() => { setCurrentYear(currentYear + 1); }}> <ClIcon iconName={"pullright"} /> </View> </ClFlex> </ClLayout> <ClGrid col={4}> {months.map((item, index) => <View key={item} className={classNames(["flex justify-center align-center"])}> <ClLayout margin={"small"} marginDirection={"vertical"}> <ClButton size={"small"} bgColor={"light-gray"} shadow={false} long text={item} onClick={() => { selectDate(index); }} /> </ClLayout> </View>)} </ClGrid> </View>} mode={"click"} width={300} show={showMonths} onChange={() => { setShowMonths(!showMonths); }}> <ClButton shape={"round"} shadow={false} size={"small"}> <ClText className={"chooseDate"} lineSpacing={"normal"} text={currentDate} /> </ClButton> </ClTip> {backToToday ? <View onClick={() => { handleBackToToday(); }}> <ClButton shadow={false} size={"small"}> <ClText className={"backToToday"} lineSpacing={"normal"}></ClText> </ClButton> </View> : ""} </ClFlex> </ClLayout> <View className="week"> <ClGrid col={7} className="solid-bottom"> {weekGridComponent} </ClGrid> <Swiper current={currentActive} circular style={{ width: "100%", height: calendarType === "week" ? Taro.pxTransform(120) : Taro.pxTransform(120 * currentActiveLines) }} onChange={e => { if (currentActive !== e.detail.current) changeDate(e.detail.current); }}> {calendarType === "week" ? weeksComponent : monthsComponent} </Swiper> </View> </View> </ClCard>; } } Calendar_weapp.options = { addGlobalClass: true };