npmrun 1 month ago
parent
commit
753018dda3
  1. 1
      assets/style/common.scss
  2. 5
      components/x-calendar/context.uts
  3. 103
      components/x-calendar/util.uts
  4. 15
      components/x-calendar/x-calendar--item.uvue
  5. 63
      components/x-calendar/x-calendar.uvue
  6. 308
      components/x-editor/x-editor.uvue
  7. 30
      components/x-mask/x-mask.uvue
  8. 9
      components/x-navbar/x-navbar.uvue
  9. 2
      components/x-page/x-page.uvue
  10. 66
      components/x-slide-menu/x-slide-menu.uvue
  11. 26
      hooks/createContext/Consumer.uvue
  12. 17
      hooks/createContext/Provider - 副本.uvue
  13. 21
      hooks/createContext/Provider.uvue
  14. 51
      hooks/createContext/createContext - 副本.uts
  15. 47
      hooks/createContext/createContext.uts
  16. 2
      main.uts
  17. 6
      pages.json
  18. 233
      pages/index/index - 副本.uvue
  19. 110
      pages/index/index.uvue

1
assets/style/common.scss

@ -3,4 +3,3 @@
font-family: ZhanKuKuaiLeTi;
src: url('@/assets/fonts/ZhanKuKuaiLeTi2016XiuDingBan-1.ttf');
}

5
components/x-calendar/context.uts

@ -0,0 +1,5 @@
import { createContext } from "@/hooks/createContext/createContext.uts"
const key = "x-calendar--item"
const { Provider, Consumer, useContext } = createContext(key)
export { Provider, Consumer, useContext }

103
components/x-calendar/util.uts

@ -0,0 +1,103 @@
export function getWeek(time : Date) {
let week = time.getDay() // 当前周几
// week = (week - 1) < 0 ? 0 : (week - 1)
if(week == 0) week = 7 // 0 表示周日
return week
}
export function getCurrentMonth(time : Date) : number {
let month = time.getMonth() + 1
return month
}
export function getLastMonth(curDate : Date) {
let lastDate = new Date()
lastDate.setMonth(curDate.getMonth() - 1)
return lastDate
}
export function getLastMonthDay(curDate : Date, offset : number) {
let lastDate = new Date(curDate.getTime())
lastDate.setHours(-24 * offset);
return lastDate
}
export function getNextMonthDay(curDate : Date, offset : number) {
let lastDate = new Date(curDate.getTime())
lastDate.setHours(24 * offset);
return lastDate
}
export function format(time : Date) {
return `${time.getFullYear()}-${time.getMonth() + 1}-${time.getDate()}`
}
export function formatFull(time : Date) {
const year = (time.getFullYear()) + ""
const month = (time.getMonth() + 1) + ""
const date = (time.getDate()) + ""
const hour = (time.getHours()) + ""
const minute = (time.getMinutes()) + ""
const second = (time.getSeconds()) + ""
return `${year}-${month.padStart(2, '0')}-${date.padStart(2, '0')} ${hour.padStart(2, '0')}:${minute.padStart(2, '0')}:${second.padStart(2, '0')}`
}
// 获取当前月份应该有多少天
export function getCurMonthDayNum(time : Date) : number {
let day = 31;
let month = time.getMonth() + 1
let year = time.getFullYear()
if ([1, 3, 5, 7, 8, 10, 12].indexOf(month) != -1) {
day = 31;
} else if ([4, 6, 9, 11].indexOf(month) != -1) {
day = 30;
} else if (year % 4 == 0) {
day = 29
} else {
day = 28
}
return day
}
export function generateDate<T = Date>(_nowDate : Date | string | number, format : (date : Date) => T = (v : Date) => (v as T)) {
if (typeof _nowDate === "string" || typeof _nowDate === "number") {
_nowDate = new Date(_nowDate as string)
}
const allDate : T[] = []
let firstDate = new Date(_nowDate.getTime())
firstDate.setDate(1)
const firstWeek = getWeek(firstDate)
console.log(firstDate.getTime());
for (var i = 1; i < firstWeek; i++) {
const date = getLastMonthDay(firstDate, i)
allDate.unshift(format(new Date(date.getTime())) as T)
}
let curDate = new Date(_nowDate.getTime())
const allDay = getCurMonthDayNum(curDate)
for (var i = 1; i <= getCurMonthDayNum(curDate); i++) {
curDate.setDate(i)
allDate.push(format(new Date(curDate.getTime())) as T)
}
let endDate = new Date(_nowDate.getTime())
endDate.setDate(allDay)
const endWeek = 7 - getWeek(endDate)
for (var i = 1; i <= endWeek; i++) {
const date = getNextMonthDay(endDate, i)
allDate.push(format(new Date(date.getTime())) as T)
}
// 至少6行
if (~~(allDate.length / 7) < 6) {
for (var i = endWeek + 1; i < endWeek + 1 + 7; i++) {
const date = getNextMonthDay(endDate, i)
allDate.push(format(new Date(date.getTime())) as T)
}
}
return allDate
}

15
components/x-calendar/x-calendar--item.uvue

@ -0,0 +1,15 @@
<template>
<Context.Consumer>
<template v-slot="data">
{{data.label}}
</template>
</Context.Consumer>
</template>
<script setup lang="uts">
import Context from "./context.uts"
</script>
<style>
</style>

63
components/x-calendar/x-calendar.uvue

@ -0,0 +1,63 @@
<template>
<view class="x-calendar">
<view class="grid">
{{all.length}}
<view class="grid-item" v-for="(day, index) in all" :key="index">
<view class="grid-item-box">
<view class="grid-item-content">
<Provider contextKey="x-calendar--item" :value="day">1
<Consumer contextKey="x-calendar--item">
<template v-slot="data">
{{data["label"]}}
</template>
</Consumer>
<!-- <slot><text class="grid-item-text">{{ day.label }}</text></slot> -->
</Provider>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { format, generateDate } from "./util.uts"
import { useContext } from "./context.uts"
import Consumer from "@/hooks/createContext/Consumer.uvue"
import Provider from "@/hooks/createContext/Provider.uvue"
const props = withDefaults(defineProps<{
current ?: string
}>(), {
current: format(new Date())
})
interface TItem { label : string; value : Date; }
const currentDate = computed(() => {
return new Date(props.current)
})
const all = computed<any[]>(() => {
const Fn = (v : Date) : any => ({
label: v.getDate() + "",
value: v
} as any)
return generateDate<any>(format(currentDate.value), Fn as (v: Date)=>any)
})
</script>
<style lang="scss" scoped>
.grid {
display: flex;
flex-direction: row;
flex-wrap: wrap;
.grid-item {
width: calc(100% / 6);
display: flex;
align-items: center;
justify-content: center;
}
}
</style>

308
components/x-editor/x-editor.uvue

@ -0,0 +1,308 @@
<template>
<view class="container">
<view class="page-body">
<view class='wrapper'>
<view class='toolbar' @tap="format">
<view :class="formats.bold ? 'ql-active' : ''" class="iconfont icon-zitijiacu" data-name="bold">
</view>
<view :class="formats.italic ? 'ql-active' : ''" class="iconfont icon-zitixieti" data-name="italic">
</view>
<view :class="formats.underline ? 'ql-active' : ''" class="iconfont icon-zitixiahuaxian"
data-name="underline"></view>
<view :class="formats.strike ? 'ql-active' : ''" class="iconfont icon-zitishanchuxian"
data-name="strike">
</view>
<view :class="formats.align === 'left' ? 'ql-active' : ''" class="iconfont icon-zuoduiqi"
data-name="align" data-value="left"></view>
<view :class="formats.align === 'center' ? 'ql-active' : ''" class="iconfont icon-juzhongduiqi"
data-name="align" data-value="center"></view>
<view :class="formats.align === 'right' ? 'ql-active' : ''" class="iconfont icon-youduiqi"
data-name="align" data-value="right"></view>
<view :class="formats.align === 'justify' ? 'ql-active' : ''" class="iconfont icon-zuoyouduiqi"
data-name="align" data-value="justify"></view>
<view :class="formats.lineHeight ? 'ql-active' : ''" class="iconfont icon-line-height"
data-name="lineHeight" data-value="2"></view>
<view :class="formats.letterSpacing ? 'ql-active' : ''" class="iconfont icon-Character-Spacing"
data-name="letterSpacing" data-value="2em"></view>
<view :class="formats.marginTop ? 'ql-active' : ''" class="iconfont icon-722bianjiqi_duanqianju"
data-name="marginTop" data-value="20px"></view>
<view :class="formats.marginBottom ? 'ql-active' : ''" class="iconfont icon-723bianjiqi_duanhouju"
data-name="marginBottom" data-value="20px"></view>
<view :class="formats.fontFamily ? 'ql-active' : ''" class="iconfont icon-font"
data-name="fontFamily" data-value="Pacifico"></view>
<view :class="formats.fontSize === '24px' ? 'ql-active' : ''" class="iconfont icon-fontsize"
data-name="fontSize" data-value="24px"></view>
<view :class="formats.color === '#0000ff' ? 'ql-active' : ''" class="iconfont icon-text_color"
data-name="color" data-value="#0000ff"></view>
<view :class="formats.backgroundColor === '#00ff00' ? 'ql-active' : ''"
class="iconfont icon-fontbgcolor" data-name="backgroundColor" data-value="#00ff00"></view>
<view class="iconfont icon--checklist" data-name="list" data-value="check"></view>
<view :class="formats.list === 'ordered' ? 'ql-active' : ''" class="iconfont icon-youxupailie"
data-name="list" data-value="ordered"></view>
<view :class="formats.list === 'bullet' ? 'ql-active' : ''" class="iconfont icon-wuxupailie"
data-name="list" data-value="bullet"></view>
<view class="iconfont icon-outdent" data-name="indent" data-value="-1"></view>
<view class="iconfont icon-indent" data-name="indent" data-value="+1"></view>
<view :class="formats.header === 1 ? 'ql-active' : ''" class="iconfont icon-format-header-1"
data-name="header" :data-value="1"></view>
<view :class="formats.script === 'sub' ? 'ql-active' : ''" class="iconfont icon-zitixiabiao"
data-name="script" data-value="sub"></view>
<view :class="formats.script === 'super' ? 'ql-active' : ''" class="iconfont icon-zitishangbiao"
data-name="script" data-value="super"></view>
<view :class="formats.direction === 'rtl' ? 'ql-active' : ''" class="iconfont icon-direction-rtl"
data-name="direction" data-value="rtl"></view>
<view class="iconfont icon-date" @tap="insertDate"></view>
<view class="iconfont icon-fengexian" @tap="insertDivider"></view>
<view class="iconfont icon-charutupian" @tap="chooseInsertImage"></view>
<view class="iconfont icon-clearedformat" @tap="removeFormat"></view>
<view class="iconfont icon-undo" @tap="undo"></view>
<view class="iconfont icon-redo" @tap="redo"></view>
<view class="iconfont icon-shanchu" @tap="clearShowModal"></view>
</view>
<view class="editor-wrapper">
<editor id="editor" class="ql-container" placeholder="开始输入..." show-img-size show-img-toolbar
show-img-resize @statuschange="onStatusChange" :read-only="readOnly" @ready="onEditorReady">
</editor>
</view>
<view>
<button @tap="getCon">控制台打印文本内容</button>
</view>
</view>
</view>
</view>
</template>
<script>
type Context = {
id ?: string;
pageId ?: number;
}
export default {
data() {
return {
readOnly: false,
formats: {},
editorCtx: {} as Context,
// 自动化测试
autoTest: false,
undoTest: false,
redoTest: false,
removeFormatTest: false,
insertImageTest: false,
blurTest: false
}
},
onLoad() {
uni.loadFontFace({
family: 'Pacifico',
source: 'url("/static/font/Pacifico-Regular.ttf")',
success() {
console.log('success load font')
},
fail() {
console.log('fail load font load')
}
})
},
methods: {
readOnlyChange() {
this.readOnly = !this.readOnly
},
onEditorReady() {
uni.createSelectorQuery().select('#editor').context((res) => {
this.editorCtx = res.context
}).exec()
},
// 自动化测试专用
setContents(options) {
this.editorCtx.setContents({
delta: {
ops: options
},
success: (res) => {
console.log('setContents-success', res)
},
fail: (err) => {
console.log(err)
}
})
},
blur() {
this.editorCtx.blur({
success: (res) => {
console.log('编辑器失焦:', res)
this.blurTest = true
},
fail: (err) => {
console.log(err)
}
})
},
getCon() {
this.editorCtx.getContents({
success: (res) => {
console.log('文本详情:', res)
},
fail: (err) => {
console.log(err)
}
})
},
undo() {
this.editorCtx.undo({
success: (res) => {
this.undoTest = true
},
fail: (err) => {
this.undoTest = false
}
})
},
redo() {
this.editorCtx.redo({
success: (res) => {
this.redoTest = true
},
fail: (err) => {
this.redoTest = false
}
})
},
format(e) {
let { name, value } = e.target.dataset
if (!name) return
// console.log('format', name, value)
this.editorCtx.format(name, value)
},
onStatusChange(e) {
const formats = e.detail
this.formats = formats
},
insertDivider() {
this.editorCtx.insertDivider({
success: function () {
console.log('insert divider success')
}
})
},
clear() {
this.editorCtx.clear({
success: function (res) {
console.log("clear success")
}
})
},
clearShowModal() {
uni.showModal({
title: '清空编辑器',
content: '确定清空编辑器全部内容?',
success: res => {
if (res.confirm) {
this.clear()
}
}
})
},
removeFormat() {
this.editorCtx.removeFormat({
success: (res) => {
console.log('removeFormat-success', res)
this.removeFormatTest = true
},
fail: (err) => {
this.removeFormatTest = false
}
})
},
insertDate() {
const date = new Date()
const formatDate = `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`
this.editorCtx.insertText({
text: formatDate
})
},
insertImage(image) {
this.editorCtx.insertImage({
src: image,
alt: '图像',
success: () => {
console.log('insert image success')
this.insertImageTest = true
}
})
},
chooseInsertImage() {
uni.chooseImage({
count: 1,
success: (res) => {
this.insertImage(res.tempFilePaths[0])
}
})
}
}
}
</script>
<style>
/* @import "./editor-icon.css"; */
.page-body {
height: calc(100vh - var(--window-top) - var(--status-bar-height));
}
.wrapper {
height: 100%;
}
.editor-wrapper {
height: calc(100vh - var(--window-top) - var(--status-bar-height) - 140px - 46px);
background: #fff;
}
.iconfont {
display: inline-block;
width: 30px;
height: 30px;
cursor: pointer;
font-size: 20px;
margin: 0px 6px;
align-content: center;
}
.toolbar {
box-sizing: border-box;
border-bottom: 0;
font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;
flex-direction: row;
flex-wrap: wrap;
height: 140px;
padding-left: 10px;
}
.ql-container {
box-sizing: border-box;
padding: 12px 15px;
width: 100%;
min-height: 30vh;
height: 100%;
font-size: 16px;
line-height: 1.5;
}
.ql-active {
color: #06c;
}
</style>

30
components/x-mask/x-mask.uvue

@ -0,0 +1,30 @@
<template>
<view class="x-mask">
</view>
</template>
<script>
export default {
name:"x-mask",
data() {
return {
};
}
}
</script>
<style scoped lang="scss">
.x-mask {
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 0;
background-color: rgba(0, 0, 0, .2);
z-index: 999;
}
</style>

9
components/x-navbar/x-navbar.uvue

@ -32,9 +32,6 @@
<style lang="scss">
$navbar__height: 75rpx;
$navbar__bg: white;
$navbar__title__size: 35px;
$navbar__title__color: deeppink;
$navbar__title__family: cursive;
.x-navbar {
@ -59,11 +56,7 @@
justify-content: center;
position: relative;
.x-navbar__content__title {
font-size: $navbar__title__size;
color: $navbar__title__color;
font-family: $navbar__title__family;
}
.x-navbar__content__title {}
&__left {
position: absolute;

2
components/x-page/x-page.uvue

@ -7,6 +7,7 @@
<!-- #ifdef APP -->
</scroll-view>
<!-- #endif -->
<slot name="other"></slot>
</view>
</template>
@ -26,6 +27,7 @@
display: flex;
flex-direction: column;
height: 100%;
position: relative;
}

66
components/x-slide-menu/x-slide-menu.uvue

@ -0,0 +1,66 @@
<template>
<view class="x-slide-menu" v-if="modelValue">
<x-mask @click="handleHide"></x-mask>
<div class="x-slide-menu__content"></div>
</view>
</template>
<script setup lang="uts">
const props = withDefaults(defineProps<{
contentWidth ?: string,
modelValue : boolean
}>(), {
contentWidth: "80%"
})
const emit = defineEmits<{
(e: 'open'): void
(e: 'close'): void
(e: 'update:modelValue', isShow: boolean): void
}>()
watch(() => props.modelValue, (v) => {
if (v) {
emit("open")
} else {
emit("close")
}
})
const state = reactive({})
const computedContentStyle = computed(() => {
return {
width: props.contentWidth
}
})
function handleHide() {
emit("update:modelValue", false)
}
</script>
<style lang="scss" scoped>
.x-slide-menu {
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 100;
&__content {
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 70%;
height: 100%;
background-color: white;
z-index: 1000;
}
}
</style>

26
hooks/createContext/Consumer.uvue

@ -0,0 +1,26 @@
<template>
<view>
</view>
</template>
<script>
export default {
props: {
contextKey: {
type: String,
required: true,
}
},
setup(props) {
const slots = useSlots()
const data = inject(props.contextKey)
const FN : () => VNode = () => renderSlot(slots, 'default', data)
return FN
}
}
</script>
<style>
</style>

17
hooks/createContext/Provider - 副本.uvue

@ -0,0 +1,17 @@
<template></template>
<script>
export default {
props: ["value", "contextKey"],
setup(props, context) {
const slots = useSlots()
provide(props.contextKey, props.value)
const FN : () => VNode = () => renderSlot(slots, 'default')
return () : VNode => h(FN)
}
}
</script>
<style>
</style>

21
hooks/createContext/Provider.uvue

@ -0,0 +1,21 @@
<script>
export default {
name: "asd",
props: {
value: {
type: Object,
required: true,
},
contextKey: {
type: String,
required: true,
}
},
setup(props) {
const slots = useSlots()
provide(props.contextKey, props.value)
const FN : () => VNode = () => renderSlot(slots, 'default')
return FN
}
}
</script>

51
hooks/createContext/createContext - 副本.uts

@ -0,0 +1,51 @@
import { renderSlot } from "vue"
interface IProps {
value : object
}
type ContextValue = {
Provider : any
useContext : () => any
Consumer : any
}
type TCreateContext = (key : string) => ContextValue
export const createContext : TCreateContext = (key) => {
const Provider = {
props: {
value: {
type: Object,
required: true
}
},
setup(props : IProps) {
const slots = useSlots()
provide(key, props.value)
const FN : () => VNode = () => renderSlot(slots, 'default')
return () : VNode => h(FN)
}
}
const useContext : () => any = () : any => {
return inject(key) as any
}
const Consumer = {
setup() {
const slots = useSlots()
const data = useContext()
const FN : () => VNode = () => renderSlot(slots, 'default', data)
return () : VNode => h(FN, {})
}
}
const FnP = Provider
const FnC = Consumer
const value: ContextValue = {
Provider: FnP,
useContext,
Consumer: FnC,
}
return value
}

47
hooks/createContext/createContext.uts

@ -0,0 +1,47 @@
import { renderSlot } from "vue"
import ProviderComp from "./Provider.uvue"
import ConsumerComp from "./Consumer.uvue"
interface IProps {
value : object
}
type ContextValue = {
Provider : any
useContext : () => any
Consumer : any
}
type TCreateContext = (key : string) => ContextValue
export const createContext : TCreateContext = (key) => {
const useContext : () => any = () : any => {
return inject(key) as any
}
// const Consumer = {
// setup() {
// const slots = useSlots()
// const data = useContext()
// const FN : () => VNode = () => renderSlot(slots, 'default', data)
// return () : VNode => h(FN, {})
// }
// }
// const FnC = Consumer
const value : ContextValue = {
Provider: (): VNode=> {
return h(ProviderComp, { contextKey: key },)
},
useContext,
Consumer: h(ConsumerComp, { contextKey: key }),
// Consumer: (): VNode=>{
// const slots = useSlots()
// const data = useContext()
// // const FN : () => VNode = () => renderSlot(slots, 'default', data)
// console.log(data);
// return renderSlot(slots, 'default', data)
// }
}
return value
}

2
main.uts

@ -1,5 +1,5 @@
import App from './App.uvue'
import "@/assets/style/common.scss"
// import "~@/assets/style/common.scss"
import { createSSRApp } from 'vue'
export function createApp() {

6
pages.json

@ -1,4 +1,10 @@
{
"easycom": {
"autoscan": true,
"custom": {
"^(.*)--(.*)": "@/components/$1/$1--$2.uvue"
}
},
"pages": [ //pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",

233
pages/index/index - 副本.uvue

@ -0,0 +1,233 @@
<template>
<x-page>
<x-navbar>
<template v-slot:left>
<view @click="isShowMenu = true" class="">
菜单
</view>
</template>
<text class="navbar-text">LuMi</text>
</x-navbar>
<view class="tabs">
<view class="tab">
<text class="tab-text">{{nowYear}}年{{nowMonth}}月</text>
</view>
</view>
<view class="rili">
<view class="grid">
<view class="grid-item" :style="getGridItemStyle(day)" v-for="day in all" :key="day">
<view class="grid-item-box">
<view class="grid-item-content">
<text class="grid-item-text" :style="getGridItemTextStyle(day)">{{ day.label }}</text>
</view>
</view>
</view>
</view>
</view>
<!-- <text class="clear" @click="click2" v-if="recordDate.length">清除所有</text> -->
<view class="list">
<view class="item" v-for="(item, index) in recordDate">
<text class="label">{{item.label}}</text>
<text class="close" @click="delIem(item, index)">x</text>
</view>
</view>
<view class="float-btn" @click="click">
<text class="float-btn-text">打卡</text>
</view>
<x-calendar>
<!-- <x-calendar--item aa="213"></x-calendar--item> -->
</x-calendar>
<x-slide-menu v-model="isShowMenu"></x-slide-menu>
</x-page>
</template>
<script setup>
import { getCurMonthDayNum, getCurrentMonth, formatFull, getLastMonth, getLastMonthDay, format, getWeek, getNextMonthDay, generateDate } from "@/utils/date.uts"
const isShowMenu = ref(false)
type TItem = { label : string; value : Date; }
const nowDate = ref(new Date())
const nowYear = computed(() => {
return nowDate.value.getFullYear()
})
const nowMonth = computed(() => {
return nowDate.value.getMonth() + 1
})
const recordDate = ref<TItem[]>([])
const all = computed(() => {
return generateDate<TItem>(format(nowDate.value), (v : Date) => ({
label: v.getDate() + "",
value: v
}))
})
const isRecord = (date : Date) => {
let count = 0
for (var i = 0; i < recordDate.value.length; i++) {
var item = recordDate.value[i];
if (format(item.value) == format(date)) {
count++
}
}
return count
}
const isToday = (date : Date) => {
return format(nowDate.value) == format(date)
}
const getGridItemStyle = (day : TItem) => {
const count = isRecord(day.value)
return {
backgroundColor: count ? `rgba(0, 0, 0, ${count * 0.2})` : 'rgba(0, 0, 0, 0.05)'
}
}
const getGridItemTextStyle = (day : TItem) => {
const count = isRecord(day.value)
return {
color: count ? '#ffffff' : isToday(day.value) ? 'black' : 'rgba(0, 0, 0, .08)'
}
}
// const data = uni.getStorageSync("save")
// if (Array.isArray(data as [])) {
// let result : TItem[] = []
// for (let i = 0; i < data.length; i++) {
// let v : number = data[i] as number
// const date = new Date(v)
// result.push({
// label: formatFull(date),
// value: date
// })
// }
// recordDate.value = result
// } else {
recordDate.value = []
// }
//
const click2 = () => {
uni.removeStorageSync("save")
recordDate.value = []
}
const click = () => {
const date = new Date()
recordDate.value.unshift({
label: formatFull(date),
value: date
} as TItem)
uni.setStorageSync("save", unref(recordDate).map(v => v.value.getTime()))
}
const delIem = (item : TItem, index : number) => {
recordDate.value.splice(index, 1)
uni.setStorageSync("save", unref(recordDate))
}
</script>
<style lang="scss" scoped>
.navbar-text {
font-size: 45rpx;
font-family: ZhanKuKuaiLeTi;
}
.tabs {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 25rpx 0 15rpx;
margin-left: -20rpx;
.tab {
margin-left: 20rpx;
.tab-text {
font-size: 45rpx;
font-family: ZhanKuKuaiLeTi;
}
}
}
.clear {
padding: 20rpx 100rpx;
}
.list {
.item {
padding: 20rpx 100rpx;
flex-direction: row;
align-items: center;
.label {
flex: 1;
width: 0;
}
}
}
.rili {
margin-top: -30rpx;
.grid {
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
margin-left: -30rpx;
margin-top: -30rpx;
padding: 30rpx 80rpx 0;
.grid-item {
width: 55rpx;
margin-left: 30rpx;
margin-top: 30rpx;
border-radius: 15rpx;
background-color: rgba(0, 0, 0, 0.05);
.grid-item-box {
padding-bottom: 100%;
position: relative;
.grid-item-content {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
align-items: center;
justify-content: center;
.grid-item-text {
color: rgba(0, 0, 0, .08);
font-size: 25rpx;
}
}
}
}
}
}
.float-btn {
position: fixed;
z-index: 99;
left: 50%;
transform: translate(-50%);
bottom: 100rpx;
width: 100rpx;
height: 100rpx;
align-items: center;
justify-content: center;
border-radius: 100rpx;
background-color: white;
box-shadow:
0 2px 10px rgba(0, 0, 0, 0.1);
.float-btn-text {
font-size: 25rpx;
}
}
</style>

110
pages/index/index.uvue

@ -3,119 +3,13 @@
<x-navbar>
<text class="navbar-text">LuMi</text>
</x-navbar>
<view class="tabs">
<view class="tab">
<text class="tab-text">{{nowYear}}年{{nowMonth}}月</text>
</view>
</view>
<view class="rili">
<view class="grid">
<view class="grid-item" :style="getGridItemStyle(day)" v-for="day in all" :key="day">
<view class="grid-item-box">
<view class="grid-item-content">
<text class="grid-item-text" :style="getGridItemTextStyle(day)">{{ day.label }}</text>
</view>
</view>
</view>
</view>
</view>
<!-- <text class="clear" @click="click2" v-if="recordDate.length">清除所有</text> -->
<view class="list">
<view class="item" v-for="(item, index) in recordDate">
<text class="label">{{item.label}}</text>
<text class="close" @click="delIem(item, index)">x</text>
</view>
</view>
<view class="float-btn" @click="click">
<text class="float-btn-text">打卡</text>
</view>
<x-calendar>
</x-calendar>
</x-page>
</template>
<script setup>
import { getCurMonthDayNum, getCurrentMonth, formatFull, getLastMonth, getLastMonthDay, format, getWeek, getNextMonthDay, generateDate } from "@/utils/date.uts"
type TItem = { label : string; value : Date; }
const nowDate = ref(new Date())
const nowYear = computed(() => {
return nowDate.value.getFullYear()
})
const nowMonth = computed(() => {
return nowDate.value.getMonth() + 1
})
const recordDate = ref<TItem[]>([])
const all = computed(() => {
return generateDate<TItem>(format(nowDate.value), (v : Date) => ({
label: v.getDate() + "",
value: v
}))
})
const isRecord = (date : Date) => {
let count = 0
for (var i = 0; i < recordDate.value.length; i++) {
var item = recordDate.value[i];
if (format(item.value) == format(date)) {
count++
}
}
return count
}
const isToday = (date : Date) => {
return format(nowDate.value) == format(date)
}
const getGridItemStyle = (day : TItem) => {
const count = isRecord(day.value)
return {
backgroundColor: count ? `rgba(0, 0, 0, ${count * 0.2})` : 'rgba(0, 0, 0, 0.05)'
}
}
const getGridItemTextStyle = (day : TItem) => {
const count = isRecord(day.value)
return {
color: count ? '#ffffff' : isToday(day.value) ? 'black' : 'rgba(0, 0, 0, .08)'
}
}
const data = uni.getStorageSync("save")
if (Array.isArray(data as [])) {
let result : TItem[] = []
for (let i = 0; i < data.length; i++) {
let v : number = data[i] as number
const date = new Date(v)
result.push({
label: formatFull(date),
value: date
})
}
recordDate.value = result
} else {
recordDate.value = []
}
const click2 = () => {
uni.removeStorageSync("save")
recordDate.value = []
}
const click = () => {
const date = new Date()
recordDate.value.unshift({
label: formatFull(date),
value: date
} as TItem)
uni.setStorageSync("save", unref(recordDate).map(v => v.value.getTime()))
}
const delIem = (item : TItem, index : number) => {
recordDate.value.splice(index, 1)
uni.setStorageSync("save", unref(recordDate))
}
</script>
<style lang="scss" scoped>

Loading…
Cancel
Save