uview-pro 0.5.16 → 0.5.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +41 -18
- package/components/u-alert-tips/u-alert-tips.vue +1 -1
- package/components/u-calendar/types.ts +44 -2
- package/components/u-calendar/u-calendar.vue +553 -162
- package/components/u-popup/u-popup.vue +48 -2
- package/components/u-th/u-th.vue +1 -1
- package/locale/lang/en-US.ts +3 -1
- package/locale/lang/zh-CN.ts +3 -1
- package/package.json +1 -1
- package/types/global.d.ts +1 -1
package/changelog.md
CHANGED
|
@@ -1,32 +1,55 @@
|
|
|
1
|
-
## 0.5.
|
|
1
|
+
## 0.5.17(2026-04-15)
|
|
2
2
|
|
|
3
|
-
###
|
|
3
|
+
### 🐛 Bug Fixes | Bug 修复
|
|
4
4
|
|
|
5
|
-
- **
|
|
6
|
-
- **u-
|
|
7
|
-
- **u-
|
|
8
|
-
- **u-textarea:** u-textarea组件新增size属性,支持small/default/large预设值以及自定义数值(#137) ([47296e8](https://github.com/anyup/uView-Pro/commit/47296e8669d419d41959dff01de758a610122d34))
|
|
9
|
-
- **u-checkbox:** u-checkbox,u-checkbox-group支持small/default/large预设尺寸配置,优化组件样式(#137) ([e8918e2](https://github.com/anyup/uView-Pro/commit/e8918e28a413d861e05a213d49f9a1b39af17964))
|
|
10
|
-
- **u-radio:** u-radio,u-radio-group支持small/default/large预设尺寸配置(#137) ([51af7f8](https://github.com/anyup/uView-Pro/commit/51af7f8f86eed99ee159738e43d5dc2d5c6747c8))
|
|
11
|
-
- **u-switch:** u-switch支持small/default/large预设尺寸配置(#137) ([6041d52](https://github.com/anyup/uView-Pro/commit/6041d52338172d40957e3ed7af1dde01aa7de074))
|
|
12
|
-
- **u-form:** 新增表单大小配置功能,u-form支持小、中、大三种尺寸设置(#137) ([324adb9](https://github.com/anyup/uView-Pro/commit/324adb99de9dfbb72a0a0c40748c11323d3b9470))
|
|
13
|
-
- **u-tag:** 为深色模式标签添加边框样式,保持统一性 ([84d0ad6](https://github.com/anyup/uView-Pro/commit/84d0ad6c805d570e216beaa2dc586687a5aae848))
|
|
5
|
+
- **demo:** 修复topTips组件演示示例在小程序中不弹出的问题,需设置自定义navbar高度 ([0c72d24](https://github.com/anyup/uView-Pro/commit/0c72d24cd77f4ba6b6cb411810fcf5f0bd1d3272))
|
|
6
|
+
- **u-table:** 修复表格表头暗黑模式背景色问题 ([c7fd1a5](https://github.com/anyup/uView-Pro/commit/c7fd1a58e87c4efb84ccf737fe9d1e755908ba8f))
|
|
7
|
+
- **u-alert-tips:** 修复关闭按钮颜色样式问题 ([94001cf](https://github.com/anyup/uView-Pro/commit/94001cf79a03ea75695e414a7971e7ec39f445b6))
|
|
14
8
|
|
|
15
|
-
###
|
|
9
|
+
### ✨ Features | 新功能
|
|
16
10
|
|
|
17
|
-
-
|
|
18
|
-
- **
|
|
19
|
-
- **
|
|
11
|
+
- **theme:** 更新主题配置和本地化文本 ([4caa2ed](https://github.com/anyup/uView-Pro/commit/4caa2edf9542f7f2b0a7bb9870585390f0241e80))
|
|
12
|
+
- **u-calendar:** 增强日历组件功能,支持多种日历模式:打卡签到、节假日标记、价格日历等场景,支持自定义插槽功能,动态价格显示;支持选中日期,只读模式设置;修复范围选择背景色样式问题 ([7a9250e](https://github.com/anyup/uView-Pro/commit/7a9250eb49f6694286bb0c3dad7bc9780ae95864))
|
|
13
|
+
- **u-popup:** 新增inline模式支持,允许弹窗组件直接插入页面内容而非传统弹窗形式 ([2e8890c](https://github.com/anyup/uView-Pro/commit/2e8890ca3c9cacb90739b33cb0e38db7e2bdb473))
|
|
14
|
+
- **u-calendar:** 统一日期格式YYYY-MM-DD,确保跨组件日期处理的一致性 ([092cc53](https://github.com/anyup/uView-Pro/commit/092cc5392b64990342c43fcbac9aec1bfa2bf982))
|
|
20
15
|
|
|
21
|
-
###
|
|
16
|
+
### ♻️ Code Refactoring | 代码重构
|
|
22
17
|
|
|
23
|
-
- **
|
|
24
|
-
- **u-form:** 修复移除字段时方法不存在的错误 ([58ada99](https://github.com/anyup/uView-Pro/commit/58ada99a8cbd44874eebfd305a4aeb721add8558))
|
|
18
|
+
- **u-calendar:** 重构日历组件模板,统一页面和弹窗模式的日历组件结构 ([42894b8](https://github.com/anyup/uView-Pro/commit/42894b850f903e2471ca42e02f0379443139838b))
|
|
25
19
|
|
|
26
20
|
### 👥 Contributors
|
|
27
21
|
|
|
28
22
|
<a href="https://github.com/anyup"><img src="https://github.com/anyup.png?size=40" width="40" height="40" alt="anyup" title="anyup"/></a>
|
|
29
23
|
|
|
24
|
+
## 0.5.16(2026-03-26)
|
|
25
|
+
|
|
26
|
+
### ✨ Features | 新功能
|
|
27
|
+
|
|
28
|
+
- **web:** 浏览器平台添加触摸模拟器支持 ([cf96a73](https://github.com/anyup/uView-Pro/commit/cf96a73e09512291143954401aa7850ac59f1207))
|
|
29
|
+
- **u-button:** 新增 large、small 按钮尺寸选项,丰富按钮尺寸规格 ([053d7e8](https://github.com/anyup/uView-Pro/commit/053d7e8ab92af403cdfde36369f38a2aded27288))
|
|
30
|
+
- **u-input:** u-input添加size属性,支持small/default/large预设值以及自定义尺寸(#137) ([afed961](https://github.com/anyup/uView-Pro/commit/afed961f65c86bd84a2b02828bb361480c7f95b3))
|
|
31
|
+
- **u-textarea:** u-textarea组件新增size属性,支持small/default/large预设值以及自定义数值(#137) ([47296e8](https://github.com/anyup/uView-Pro/commit/47296e8669d419d41959dff01de758a610122d34))
|
|
32
|
+
- **u-checkbox:** u-checkbox,u-checkbox-group支持small/default/large预设尺寸配置,优化组件样式(#137) ([e8918e2](https://github.com/anyup/uView-Pro/commit/e8918e28a413d861e05a213d49f9a1b39af17964))
|
|
33
|
+
- **u-radio:** u-radio,u-radio-group支持small/default/large预设尺寸配置(#137) ([51af7f8](https://github.com/anyup/uView-Pro/commit/51af7f8f86eed99ee159738e43d5dc2d5c6747c8))
|
|
34
|
+
- **u-switch:** u-switch支持small/default/large预设尺寸配置(#137) ([6041d52](https://github.com/anyup/uView-Pro/commit/6041d52338172d40957e3ed7af1dde01aa7de074))
|
|
35
|
+
- **u-form:** 新增表单大小配置功能,u-form支持小、中、大三种尺寸设置(#137) ([324adb9](https://github.com/anyup/uView-Pro/commit/324adb99de9dfbb72a0a0c40748c11323d3b9470))
|
|
36
|
+
- **u-tag:** 为深色模式标签添加边框样式,保持统一性 ([84d0ad6](https://github.com/anyup/uView-Pro/commit/84d0ad6c805d570e216beaa2dc586687a5aae848))
|
|
37
|
+
|
|
38
|
+
### ♻️ Code Refactoring | 代码重构
|
|
39
|
+
|
|
40
|
+
- 添加调试模式配置并重构日志系统 ([a52a3f7](https://github.com/anyup/uView-Pro/commit/a52a3f7d6be7d8332a67c1d8458f4e65e0a0204e))
|
|
41
|
+
- **props:** 移除baseProps公共属性并内联到各组件,修复uni_modules引入方式在微信小程序正式打包运行报错的问题 ([f30f779](https://github.com/anyup/uView-Pro/commit/f30f7792a48679afc3cf705a5eb0b182591fe9b5))
|
|
42
|
+
- **form:** 调整表单大小配置位置 ([45ffecd](https://github.com/anyup/uView-Pro/commit/45ffecd3522df85cdaaa62ecb9c33d7839443586))
|
|
43
|
+
|
|
44
|
+
### 🐛 Bug Fixes | Bug 修复
|
|
45
|
+
|
|
46
|
+
- **useChildren:** 修复组件关系工具子组件ID缓存问题,避免同组件多次调用useChildren时重复注册 ([3a8c659](https://github.com/anyup/uView-Pro/commit/3a8c659ce596b483559cf4b061d0b54d784a902b))
|
|
47
|
+
- **u-form:** 修复移除字段时方法不存在的错误 ([58ada99](https://github.com/anyup/uView-Pro/commit/58ada99a8cbd44874eebfd305a4aeb721add8558))
|
|
48
|
+
|
|
49
|
+
### 👥 Contributors
|
|
50
|
+
|
|
51
|
+
<a href="https://github.com/anyup"><img src="https://github.com/anyup.png?size=40" width="40" height="40" alt="anyup" title="anyup"/></a>
|
|
52
|
+
|
|
30
53
|
## 0.5.15(2026-03-25)
|
|
31
54
|
|
|
32
55
|
### 🐛 Bug Fixes | Bug 修复
|
|
@@ -54,7 +54,7 @@ export const CalendarProps = {
|
|
|
54
54
|
/** 选中|起始结束日期字体颜色 */
|
|
55
55
|
activeColor: { type: String, default: 'var(--u-white-color)' },
|
|
56
56
|
/** 范围内日期背景色 */
|
|
57
|
-
rangeBgColor: { type: String, default: '
|
|
57
|
+
rangeBgColor: { type: String, default: 'var(--u-type-primary-light)' },
|
|
58
58
|
/** 范围内日期字体颜色 */
|
|
59
59
|
rangeColor: { type: String, default: () => getColor('primary') },
|
|
60
60
|
/** mode=range时生效,起始日期自定义文案 */
|
|
@@ -65,6 +65,8 @@ export const CalendarProps = {
|
|
|
65
65
|
btnType: { type: String as PropType<ThemeType>, default: 'primary' },
|
|
66
66
|
/** 当前选中日期带选中效果 */
|
|
67
67
|
isActiveCurrent: { type: Boolean, default: true },
|
|
68
|
+
/** 初始化时是否默认选中今天,优先级低于 defaultDate/startDate/endDate */
|
|
69
|
+
defaultSelectToday: { type: Boolean, default: true },
|
|
68
70
|
/** 切换年月是否触发事件 mode=date时生效 */
|
|
69
71
|
isChange: { type: Boolean, default: false },
|
|
70
72
|
/** 是否显示右上角的关闭图标 */
|
|
@@ -74,7 +76,47 @@ export const CalendarProps = {
|
|
|
74
76
|
/** 是否显示农历 */
|
|
75
77
|
showLunar: { type: Boolean, default: false },
|
|
76
78
|
/** 是否在页面中显示 */
|
|
77
|
-
isPage: { type: Boolean, default: false }
|
|
79
|
+
isPage: { type: Boolean, default: false },
|
|
80
|
+
/** 默认选中的日期,mode=date时生效,格式:2024-01-01 */
|
|
81
|
+
defaultDate: { type: String, default: '' },
|
|
82
|
+
/** 默认选中的开始日期,mode=range时生效,格式:2024-01-01 */
|
|
83
|
+
startDate: { type: String, default: '' },
|
|
84
|
+
/** 默认选中的结束日期,mode=range时生效,格式:2024-01-01 */
|
|
85
|
+
endDate: { type: String, default: '' },
|
|
86
|
+
/** 是否只读,只读模式下禁止点击选择日期 */
|
|
87
|
+
readonly: { type: Boolean, default: false },
|
|
88
|
+
/** 已打卡日期列表,格式:['2024-01-01', '2024-01-02'] */
|
|
89
|
+
checkedDates: { type: Array as PropType<string[]>, default: () => [] },
|
|
90
|
+
/** 打卡日期背景色 */
|
|
91
|
+
checkedBgColor: { type: String, default: 'var(--u-type-warning)' },
|
|
92
|
+
/** 打卡日期字体颜色 */
|
|
93
|
+
checkedColor: { type: String, default: 'var(--u-white-color)' },
|
|
94
|
+
/** 今日是否已打卡 */
|
|
95
|
+
todayChecked: { type: Boolean, default: false },
|
|
96
|
+
/** 今日已打卡背景色 */
|
|
97
|
+
todayCheckedBgColor: { type: String, default: 'var(--u-type-success)' },
|
|
98
|
+
/** 未打卡日期背景色 */
|
|
99
|
+
uncheckedBgColor: { type: String, default: 'var(--u-light-color)' },
|
|
100
|
+
/** 未打卡日期字体颜色 */
|
|
101
|
+
uncheckedColor: { type: String, default: 'var(--u-white-color)' },
|
|
102
|
+
/** 是否启用打卡签到模式(未打卡日期显示灰色) */
|
|
103
|
+
checkinMode: { type: Boolean, default: false },
|
|
104
|
+
/** 节假日列表,格式:['2024-01-01', '2024-01-02'] */
|
|
105
|
+
holidays: { type: Array as PropType<string[]>, default: () => [] },
|
|
106
|
+
/** 节假日文字颜色 */
|
|
107
|
+
holidayColor: { type: String, default: 'var(--u-type-error)' },
|
|
108
|
+
/** 加班日列表,格式:['2024-01-06', '2024-01-07'] */
|
|
109
|
+
workdays: { type: Array as PropType<string[]>, default: () => [] },
|
|
110
|
+
/** 加班日文字颜色 */
|
|
111
|
+
workdayColor: { type: String, default: 'var(--u-type-primary)' },
|
|
112
|
+
/** 节日配置,格式:{ '2024-04-04': '清明节', '2024-04-01': '愚人节' } */
|
|
113
|
+
festivals: { type: Object as PropType<Record<string, string>>, default: () => ({}) },
|
|
114
|
+
/** 节日文字颜色 */
|
|
115
|
+
festivalColor: { type: String, default: 'var(--u-type-primary)' },
|
|
116
|
+
/** 是否显示内置节日(中国传统节日) */
|
|
117
|
+
showFestival: { type: Boolean, default: false },
|
|
118
|
+
/** 是否启用自定义日期内容插槽(微信小程序需要显式声明) */
|
|
119
|
+
useDateSlot: { type: Boolean, default: false }
|
|
78
120
|
};
|
|
79
121
|
|
|
80
122
|
export type CalendarProps = ExtractPropTypes<typeof CalendarProps>;
|
|
@@ -1,124 +1,22 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<view v-if="props.isPage" class="u-calendar" :class="props.customClass" :style="$u.toStyle(customStyle)">
|
|
3
|
-
<!-- <view class="u-calendar__header">
|
|
4
|
-
<view class="u-calendar__header__text" v-if="!slots.tooltip">
|
|
5
|
-
{{ toolTip }}
|
|
6
|
-
</view>
|
|
7
|
-
<slot v-else name="tooltip" />
|
|
8
|
-
</view> -->
|
|
9
|
-
<view class="u-calendar__action u-flex u-row-center">
|
|
10
|
-
<view class="u-calendar__action__icon">
|
|
11
|
-
<u-icon
|
|
12
|
-
v-if="changeYear"
|
|
13
|
-
name="arrow-left-double"
|
|
14
|
-
:color="yearArrowColor"
|
|
15
|
-
@click="changeYearHandler(0)"
|
|
16
|
-
></u-icon>
|
|
17
|
-
</view>
|
|
18
|
-
<view class="u-calendar__action__icon">
|
|
19
|
-
<u-icon
|
|
20
|
-
v-if="changeMonth"
|
|
21
|
-
name="arrow-left"
|
|
22
|
-
:color="monthArrowColor"
|
|
23
|
-
@click="changeMonthHandler(0)"
|
|
24
|
-
></u-icon>
|
|
25
|
-
</view>
|
|
26
|
-
<view class="u-calendar__action__text">{{ showTitle }}</view>
|
|
27
|
-
<view class="u-calendar__action__icon">
|
|
28
|
-
<u-icon
|
|
29
|
-
v-if="changeMonth"
|
|
30
|
-
name="arrow-right"
|
|
31
|
-
:color="monthArrowColor"
|
|
32
|
-
@click="changeMonthHandler(1)"
|
|
33
|
-
></u-icon>
|
|
34
|
-
</view>
|
|
35
|
-
<view class="u-calendar__action__icon">
|
|
36
|
-
<u-icon
|
|
37
|
-
v-if="changeYear"
|
|
38
|
-
name="arrow-right-double"
|
|
39
|
-
:color="yearArrowColor"
|
|
40
|
-
@click="changeYearHandler(1)"
|
|
41
|
-
></u-icon>
|
|
42
|
-
</view>
|
|
43
|
-
</view>
|
|
44
|
-
<view class="u-calendar__week-day">
|
|
45
|
-
<view class="u-calendar__week-day__text" v-for="(item, index) in weekDayZh" :key="index">{{ item }}</view>
|
|
46
|
-
</view>
|
|
47
|
-
<view class="u-calendar__content">
|
|
48
|
-
<!-- 前置空白部分 -->
|
|
49
|
-
<block v-for="(item, index) in weekdayArr" :key="index">
|
|
50
|
-
<view class="u-calendar__content__item"></view>
|
|
51
|
-
</block>
|
|
52
|
-
<view
|
|
53
|
-
class="u-calendar__content__item"
|
|
54
|
-
:class="{
|
|
55
|
-
'u-hover-class': openDisAbled(year, month, index + 1),
|
|
56
|
-
'u-calendar__content--start-date':
|
|
57
|
-
(mode == 'range' && startDate == `${year}-${month}-${index + 1}`) || mode == 'date',
|
|
58
|
-
'u-calendar__content--end-date':
|
|
59
|
-
(mode == 'range' && endDate == `${year}-${month}-${index + 1}`) || mode == 'date'
|
|
60
|
-
}"
|
|
61
|
-
:style="{ backgroundColor: getColor(index, 1) }"
|
|
62
|
-
v-for="(item, index) in daysArr"
|
|
63
|
-
:key="index"
|
|
64
|
-
@tap="dateClick(index)"
|
|
65
|
-
>
|
|
66
|
-
<view class="u-calendar__content__item__inner" :style="{ color: getColor(index, 2) }">
|
|
67
|
-
<view>{{ index + 1 }}</view>
|
|
68
|
-
</view>
|
|
69
|
-
<view
|
|
70
|
-
class="u-calendar__content__item__tips"
|
|
71
|
-
:style="{ color: activeColor }"
|
|
72
|
-
v-if="mode == 'range' && startDate == `${year}-${month}-${index + 1}` && startDate != endDate"
|
|
73
|
-
>
|
|
74
|
-
{{ startText }}
|
|
75
|
-
</view>
|
|
76
|
-
<view
|
|
77
|
-
class="u-calendar__content__item__tips"
|
|
78
|
-
:style="{ color: activeColor }"
|
|
79
|
-
v-if="mode == 'range' && endDate == `${year}-${month}-${index + 1}`"
|
|
80
|
-
>
|
|
81
|
-
{{ endText }}
|
|
82
|
-
</view>
|
|
83
|
-
<view
|
|
84
|
-
v-if="
|
|
85
|
-
props.showLunar &&
|
|
86
|
-
!(mode == 'range' && startDate == `${year}-${month}-${index + 1}` && startDate != endDate) &&
|
|
87
|
-
!(mode == 'range' && endDate == `${year}-${month}-${index + 1}`)
|
|
88
|
-
"
|
|
89
|
-
class="u-calendar__content__item__tips"
|
|
90
|
-
:style="{ color: getColor(index, 2) }"
|
|
91
|
-
>
|
|
92
|
-
{{ lunarArr[index]?.dayCn === '初一' ? lunarArr[index].monthCn : (lunarArr[index]?.dayCn ?? '') }}
|
|
93
|
-
</view>
|
|
94
|
-
</view>
|
|
95
|
-
<view class="u-calendar__content__bg-month">{{ month }}</view>
|
|
96
|
-
</view>
|
|
97
|
-
<!-- <view class="u-calendar__bottom">
|
|
98
|
-
<view class="u-calendar__bottom__choose">
|
|
99
|
-
<text>{{ mode == 'date' ? activeDate : startDate }}</text>
|
|
100
|
-
<text v-if="endDate">至{{ endDate }}</text>
|
|
101
|
-
</view>
|
|
102
|
-
<view class="u-calendar__bottom__btn">
|
|
103
|
-
<u-button :type="btnType" shape="circle" size="default" @click="btnFix(false)">确定</u-button>
|
|
104
|
-
</view>
|
|
105
|
-
</view> -->
|
|
106
|
-
</view>
|
|
107
2
|
<u-popup
|
|
108
|
-
v-else
|
|
109
|
-
:maskCloseAble="maskCloseAble"
|
|
110
|
-
mode="bottom"
|
|
111
|
-
:popup="false"
|
|
112
3
|
v-model="popupValue"
|
|
113
4
|
length="auto"
|
|
5
|
+
:maskCloseAble="maskCloseAble"
|
|
6
|
+
:mode="props.isPage ? 'inline' : 'bottom'"
|
|
7
|
+
:popup="false"
|
|
114
8
|
:safeAreaInsetBottom="safeAreaInsetBottom"
|
|
115
|
-
@close="close"
|
|
116
9
|
:z-index="uZIndex"
|
|
117
10
|
:border-radius="borderRadius"
|
|
118
11
|
:closeable="closeable"
|
|
12
|
+
@close="close"
|
|
119
13
|
>
|
|
120
|
-
<view
|
|
121
|
-
|
|
14
|
+
<view
|
|
15
|
+
class="u-calendar"
|
|
16
|
+
:class="[props.customClass, { 'u-calendar--page': props.isPage }]"
|
|
17
|
+
:style="$u.toStyle(customStyle)"
|
|
18
|
+
>
|
|
19
|
+
<view class="u-calendar__header" v-if="!props.isPage">
|
|
122
20
|
<view class="u-calendar__header__text" v-if="!slots.tooltip">
|
|
123
21
|
{{ toolTip }}
|
|
124
22
|
</view>
|
|
@@ -174,53 +72,121 @@
|
|
|
174
72
|
:class="{
|
|
175
73
|
'u-hover-class': openDisAbled(year, month, index + 1),
|
|
176
74
|
'u-calendar__content--start-date':
|
|
177
|
-
(mode == 'range' && startDate == `${year}-${month}-${index + 1}`) ||
|
|
75
|
+
(mode == 'range' && startDate == `${year}-${formatNum(month)}-${formatNum(index + 1)}`) ||
|
|
76
|
+
mode == 'date',
|
|
178
77
|
'u-calendar__content--end-date':
|
|
179
|
-
(mode == 'range' && endDate == `${year}-${month}-${index + 1}`) ||
|
|
78
|
+
(mode == 'range' && endDate == `${year}-${formatNum(month)}-${formatNum(index + 1)}`) ||
|
|
79
|
+
mode == 'date',
|
|
80
|
+
'u-calendar__content--checked': isCheckedDate(index + 1),
|
|
81
|
+
'u-calendar__content--today-checked': isTodayChecked(index + 1),
|
|
82
|
+
'u-calendar__content--checkin-mode': props.checkinMode
|
|
83
|
+
}"
|
|
84
|
+
:style="{
|
|
85
|
+
backgroundColor:
|
|
86
|
+
!props.checkinMode && props.checkedDates.length === 0 && !props.todayChecked
|
|
87
|
+
? getColor(index, 1)
|
|
88
|
+
: ''
|
|
180
89
|
}"
|
|
181
|
-
:style="{ backgroundColor: getColor(index, 1) }"
|
|
182
90
|
v-for="(item, index) in daysArr"
|
|
183
91
|
:key="index"
|
|
184
92
|
@tap="dateClick(index)"
|
|
185
93
|
>
|
|
186
|
-
<view class="u-calendar__content__item__inner" :style="{ color: getColor(index, 2) }">
|
|
187
|
-
<view>{{ index + 1 }}</view>
|
|
188
|
-
</view>
|
|
189
|
-
<view
|
|
190
|
-
class="u-calendar__content__item__tips"
|
|
191
|
-
:style="{ color: activeColor }"
|
|
192
|
-
v-if="mode == 'range' && startDate == `${year}-${month}-${index + 1}` && startDate != endDate"
|
|
193
|
-
>
|
|
194
|
-
{{ startText }}
|
|
195
|
-
</view>
|
|
196
|
-
<view
|
|
197
|
-
class="u-calendar__content__item__tips"
|
|
198
|
-
:style="{ color: activeColor }"
|
|
199
|
-
v-if="mode == 'range' && endDate == `${year}-${month}-${index + 1}`"
|
|
200
|
-
>
|
|
201
|
-
{{ endText }}
|
|
202
|
-
</view>
|
|
203
94
|
<view
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
) &&
|
|
211
|
-
!(mode == 'range' && endDate == `${year}-${month}-${index + 1}`)
|
|
212
|
-
"
|
|
213
|
-
class="u-calendar__content__item__tips"
|
|
214
|
-
:style="{ color: getColor(index, 2) }"
|
|
95
|
+
class="u-calendar__content__item__inner"
|
|
96
|
+
:class="{ 'u-calendar__content__item__inner--today-checked': isTodayChecked(index + 1) }"
|
|
97
|
+
:style="{
|
|
98
|
+
color: getCheckinTextColor(index + 1) || getColor(index, 2),
|
|
99
|
+
backgroundColor: getCheckinColor(index + 1)
|
|
100
|
+
}"
|
|
215
101
|
>
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
102
|
+
<!-- 今日已打卡时显示对勾,否则显示日期 -->
|
|
103
|
+
<view v-if="isTodayChecked(index + 1)" class="u-calendar__content__item__checkmark">
|
|
104
|
+
<u-icon name="checkmark" size="36" :color="props.checkedColor"></u-icon>
|
|
105
|
+
</view>
|
|
106
|
+
<template v-else>
|
|
107
|
+
<!-- 自定义日期内容插槽 - 优先级最高 -->
|
|
108
|
+
<template v-if="props.useDateSlot">
|
|
109
|
+
<view class="u-calendar__content__item__day">{{ index + 1 }}</view>
|
|
110
|
+
<view
|
|
111
|
+
class="u-calendar__content__item__lunar"
|
|
112
|
+
:style="{ color: getSlotColor(index + 1) }"
|
|
113
|
+
>
|
|
114
|
+
<slot name="date" :date="getDateInfo(index + 1)"></slot>
|
|
115
|
+
</view>
|
|
116
|
+
</template>
|
|
117
|
+
<template v-else>
|
|
118
|
+
<!-- 日期数字右上角标记:休/班 -->
|
|
119
|
+
<view
|
|
120
|
+
v-if="isHoliday(index + 1)"
|
|
121
|
+
class="u-calendar__content__item__mark u-calendar__content__item__mark--holiday"
|
|
122
|
+
:style="{ color: getHolidayWorkdayColor(index + 1, props.holidayColor) }"
|
|
123
|
+
>
|
|
124
|
+
{{ t('uCalendar.holiday') }}
|
|
125
|
+
</view>
|
|
126
|
+
<view
|
|
127
|
+
v-else-if="isWorkday(index + 1)"
|
|
128
|
+
class="u-calendar__content__item__mark u-calendar__content__item__mark--workday"
|
|
129
|
+
:style="{ color: getHolidayWorkdayColor(index + 1, props.workdayColor) }"
|
|
130
|
+
>
|
|
131
|
+
{{ t('uCalendar.workday') }}
|
|
132
|
+
</view>
|
|
133
|
+
<view class="u-calendar__content__item__day">{{ index + 1 }}</view>
|
|
134
|
+
<!-- 范围选择开始日期显示"开始" -->
|
|
135
|
+
<view
|
|
136
|
+
v-if="
|
|
137
|
+
mode == 'range' &&
|
|
138
|
+
startDate == `${year}-${formatNum(month)}-${formatNum(index + 1)}` &&
|
|
139
|
+
startDate != endDate
|
|
140
|
+
"
|
|
141
|
+
class="u-calendar__content__item__lunar"
|
|
142
|
+
:style="{ color: activeColor }"
|
|
143
|
+
>
|
|
144
|
+
{{ startText }}
|
|
145
|
+
</view>
|
|
146
|
+
<!-- 范围选择结束日期显示"结束" -->
|
|
147
|
+
<view
|
|
148
|
+
v-else-if="
|
|
149
|
+
mode == 'range' &&
|
|
150
|
+
endDate == `${year}-${formatNum(month)}-${formatNum(index + 1)}`
|
|
151
|
+
"
|
|
152
|
+
class="u-calendar__content__item__lunar"
|
|
153
|
+
:style="{ color: activeColor }"
|
|
154
|
+
>
|
|
155
|
+
{{ endText }}
|
|
156
|
+
</view>
|
|
157
|
+
<!-- 节日名称 -->
|
|
158
|
+
<view
|
|
159
|
+
v-else-if="getFestival(index + 1)"
|
|
160
|
+
class="u-calendar__content__item__lunar u-calendar__content__item__festival"
|
|
161
|
+
:style="{ color: getHolidayWorkdayColor(index + 1, props.festivalColor) }"
|
|
162
|
+
>
|
|
163
|
+
{{ getFestival(index + 1) }}
|
|
164
|
+
</view>
|
|
165
|
+
<!-- 农历 -->
|
|
166
|
+
<view
|
|
167
|
+
v-else-if="props.showLunar"
|
|
168
|
+
class="u-calendar__content__item__lunar"
|
|
169
|
+
:style="{ color: getCheckinLunarColor(index + 1) || getColor(index, 2) }"
|
|
170
|
+
>
|
|
171
|
+
{{
|
|
172
|
+
lunarArr[index]?.dayCn === '初一'
|
|
173
|
+
? lunarArr[index].monthCn
|
|
174
|
+
: (lunarArr[index]?.dayCn ?? '')
|
|
175
|
+
}}
|
|
176
|
+
</view>
|
|
177
|
+
<!-- 占位元素:当有节日/农历数据时保持高度一致 -->
|
|
178
|
+
<view
|
|
179
|
+
v-else-if="props.showFestival"
|
|
180
|
+
class="u-calendar__content__item__lunar u-calendar__content__item__placeholder"
|
|
181
|
+
></view>
|
|
182
|
+
</template>
|
|
183
|
+
</template>
|
|
219
184
|
</view>
|
|
220
185
|
</view>
|
|
221
186
|
<view class="u-calendar__content__bg-month">{{ month }}</view>
|
|
222
187
|
</view>
|
|
223
|
-
|
|
188
|
+
<!-- 页面模式下不显示确定按钮,选择完成自动触发change事件 -->
|
|
189
|
+
<view class="u-calendar__bottom" v-if="!props.isPage">
|
|
224
190
|
<view class="u-calendar__bottom__choose">
|
|
225
191
|
<text>{{ mode == 'date' ? activeDate : startDate }}</text>
|
|
226
192
|
<text v-if="endDate">{{ t('uCalendar.to') }}{{ endDate }}</text>
|
|
@@ -288,6 +254,11 @@ import Calendar from '../../libs/util/calendar';
|
|
|
288
254
|
* @property {String} btn-type 底部确定按钮的主题(默认 'primary')
|
|
289
255
|
* @property {String} toolTip 顶部提示文字,如设置名为tooltip的slot,此参数将失效(默认 '选择日期')
|
|
290
256
|
* @property {Boolean} closeable 是否显示右上角的关闭图标(默认true)
|
|
257
|
+
* @property {Boolean} is-page 是否在页面中直接显示,不使用弹窗(默认false)
|
|
258
|
+
* @property {String} default-date 默认选中的日期,mode=date时生效,格式:2024-01-01
|
|
259
|
+
* @property {String} start-date 默认选中的开始日期,mode=range时生效,格式:2024-01-01
|
|
260
|
+
* @property {String} end-date 默认选中的结束日期,mode=range时生效,格式:2024-01-01
|
|
261
|
+
* @property {Boolean} readonly 是否只读,只读模式下禁止点击选择日期(默认false)
|
|
291
262
|
* @example <u-calendar v-model="show" :mode="mode"></u-calendar>
|
|
292
263
|
*/
|
|
293
264
|
|
|
@@ -332,8 +303,29 @@ const weekDayZh = ref([
|
|
|
332
303
|
t('uCalendar.sat')
|
|
333
304
|
]);
|
|
334
305
|
|
|
306
|
+
// 内置中国传统节日(公历日期,格式:MM-DD)
|
|
307
|
+
const builtInFestivals: Record<string, string> = {
|
|
308
|
+
'01-01': '元旦',
|
|
309
|
+
'02-14': '情人节',
|
|
310
|
+
'03-08': '妇女节',
|
|
311
|
+
'03-12': '植树节',
|
|
312
|
+
'04-01': '愚人节',
|
|
313
|
+
'05-01': '劳动节',
|
|
314
|
+
'05-04': '青年节',
|
|
315
|
+
'06-01': '儿童节',
|
|
316
|
+
'07-01': '建党节',
|
|
317
|
+
'08-01': '建军节',
|
|
318
|
+
'09-10': '教师节',
|
|
319
|
+
'10-01': '国庆节',
|
|
320
|
+
'11-11': '光棍节',
|
|
321
|
+
'12-25': '圣诞节'
|
|
322
|
+
};
|
|
323
|
+
|
|
335
324
|
const dataChange = computed(() => `${props.mode}-${props.minDate}-${props.maxDate}`);
|
|
336
325
|
const lunarChange = computed(() => props.showLunar);
|
|
326
|
+
const defaultDateChange = computed(
|
|
327
|
+
() => `${props.defaultDate}-${props.startDate}-${props.endDate}-${props.defaultSelectToday}`
|
|
328
|
+
);
|
|
337
329
|
// 如果用户有传递z-index值,优先使用
|
|
338
330
|
const uZIndex = computed(() => (props.zIndex ? props.zIndex : $u.zIndex.popup));
|
|
339
331
|
const popupValue = computed({
|
|
@@ -359,6 +351,10 @@ watch([dataChange, lunarChange], () => {
|
|
|
359
351
|
init();
|
|
360
352
|
});
|
|
361
353
|
|
|
354
|
+
watch(defaultDateChange, () => {
|
|
355
|
+
init();
|
|
356
|
+
});
|
|
357
|
+
|
|
362
358
|
onMounted(() => {
|
|
363
359
|
init();
|
|
364
360
|
});
|
|
@@ -371,7 +367,7 @@ onMounted(() => {
|
|
|
371
367
|
function getColor(index: number, type: number) {
|
|
372
368
|
let color = type == 1 ? '' : props.color;
|
|
373
369
|
let dayNum = index + 1;
|
|
374
|
-
let date = `${year.value}-${month.value}-${dayNum}`;
|
|
370
|
+
let date = `${year.value}-${formatNum(month.value)}-${formatNum(dayNum)}`;
|
|
375
371
|
let timestamp = new Date(date.replace(/\-/g, '/')).getTime();
|
|
376
372
|
let start = startDate.value.replace(/\-/g, '/');
|
|
377
373
|
let end = endDate.value.replace(/\-/g, '/');
|
|
@@ -383,6 +379,218 @@ function getColor(index: number, type: number) {
|
|
|
383
379
|
return color;
|
|
384
380
|
}
|
|
385
381
|
|
|
382
|
+
/**
|
|
383
|
+
* 判断日期是否已打卡
|
|
384
|
+
*/
|
|
385
|
+
function isCheckedDate(dayNum: number) {
|
|
386
|
+
const date = `${year.value}-${formatNum(month.value)}-${formatNum(dayNum)}`;
|
|
387
|
+
return props.checkedDates.includes(date);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* 判断是否是今日且已打卡
|
|
392
|
+
* 优先级:1. todayChecked 属性 2. 自动判断 checkedDates 中是否包含今天
|
|
393
|
+
*/
|
|
394
|
+
function isTodayChecked(dayNum: number) {
|
|
395
|
+
const date = `${year.value}-${formatNum(month.value)}-${formatNum(dayNum)}`;
|
|
396
|
+
// 首先检查是否是今天
|
|
397
|
+
if (date !== today.value) {
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
// 优先级1:手动设置的 todayChecked
|
|
401
|
+
if (props.todayChecked) {
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
404
|
+
// 优先级2:自动判断 checkedDates 中是否包含今天
|
|
405
|
+
if (props.checkedDates.includes(date)) {
|
|
406
|
+
return true;
|
|
407
|
+
}
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* 获取打卡日期背景色
|
|
413
|
+
*/
|
|
414
|
+
function getCheckinColor(dayNum: number) {
|
|
415
|
+
const date = `${year.value}-${formatNum(month.value)}-${formatNum(dayNum)}`;
|
|
416
|
+
const isToday = date === today.value;
|
|
417
|
+
const isInCheckedDates = props.checkedDates.includes(date);
|
|
418
|
+
|
|
419
|
+
// 只有在打卡签到模式下或设置了打卡数据时才返回颜色
|
|
420
|
+
if (!props.checkinMode && props.checkedDates.length === 0 && !props.todayChecked) {
|
|
421
|
+
return '';
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// 今日已打卡显示绿色(优先级:todayChecked > 自动判断)
|
|
425
|
+
if (isToday && (props.todayChecked || isInCheckedDates)) {
|
|
426
|
+
return props.todayCheckedBgColor;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// 其他已打卡日期显示橙色
|
|
430
|
+
if (isInCheckedDates) {
|
|
431
|
+
return props.checkedBgColor;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// 打卡签到模式下,未打卡日期显示灰色
|
|
435
|
+
if (props.checkinMode) {
|
|
436
|
+
return props.uncheckedBgColor;
|
|
437
|
+
}
|
|
438
|
+
return '';
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* 获取打卡日期文字颜色
|
|
443
|
+
*/
|
|
444
|
+
function getCheckinTextColor(dayNum: number) {
|
|
445
|
+
// 只有在打卡签到模式下或设置了打卡数据时才返回颜色
|
|
446
|
+
if (!props.checkinMode && props.checkedDates.length === 0 && !props.todayChecked) {
|
|
447
|
+
return '';
|
|
448
|
+
}
|
|
449
|
+
const date = `${year.value}-${formatNum(month.value)}-${formatNum(dayNum)}`;
|
|
450
|
+
// 已打卡日期显示白色文字
|
|
451
|
+
if (props.checkedDates.includes(date) || (date === today.value && props.todayChecked)) {
|
|
452
|
+
return props.checkedColor;
|
|
453
|
+
}
|
|
454
|
+
// 打卡签到模式下,未打卡日期显示白色文字
|
|
455
|
+
if (props.checkinMode) {
|
|
456
|
+
return props.uncheckedColor;
|
|
457
|
+
}
|
|
458
|
+
return '';
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* 获取打卡日期农历文字颜色
|
|
463
|
+
*/
|
|
464
|
+
function getCheckinLunarColor(dayNum: number) {
|
|
465
|
+
// 只有在打卡签到模式下或设置了打卡数据时才返回颜色
|
|
466
|
+
if (!props.checkinMode && props.checkedDates.length === 0 && !props.todayChecked) {
|
|
467
|
+
return '';
|
|
468
|
+
}
|
|
469
|
+
const date = `${year.value}-${formatNum(month.value)}-${formatNum(dayNum)}`;
|
|
470
|
+
// 已打卡日期的农历显示白色文字
|
|
471
|
+
if (props.checkedDates.includes(date) || (date === today.value && props.todayChecked)) {
|
|
472
|
+
return props.checkedColor;
|
|
473
|
+
}
|
|
474
|
+
// 打卡签到模式下,未打卡日期的农历显示白色文字
|
|
475
|
+
if (props.checkinMode) {
|
|
476
|
+
return props.uncheckedColor;
|
|
477
|
+
}
|
|
478
|
+
return '';
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* 获取自定义插槽的颜色
|
|
483
|
+
* 当选中日期时显示白色,否则显示默认颜色
|
|
484
|
+
*/
|
|
485
|
+
function getSlotColor(dayNum: number) {
|
|
486
|
+
const date = `${year.value}-${formatNum(month.value)}-${formatNum(dayNum)}`;
|
|
487
|
+
// 选中日期的自定义内容显示白色(仅在 isActiveCurrent 为 true 时)
|
|
488
|
+
if (props.isActiveCurrent && (activeDate.value === date || startDate.value === date || endDate.value === date)) {
|
|
489
|
+
return props.activeColor;
|
|
490
|
+
}
|
|
491
|
+
// 打卡签到模式下使用对应的颜色
|
|
492
|
+
if (props.checkinMode || props.checkedDates.length > 0 || props.todayChecked) {
|
|
493
|
+
return getCheckinLunarColor(dayNum) || props.color;
|
|
494
|
+
}
|
|
495
|
+
return props.color;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* 获取日期信息,用于自定义插槽
|
|
500
|
+
*/
|
|
501
|
+
function getDateInfo(dayNum: number) {
|
|
502
|
+
const dateStr = `${year.value}-${formatNum(month.value)}-${formatNum(dayNum)}`;
|
|
503
|
+
const dateObj = new Date(dateStr.replace(/\-/g, '/'));
|
|
504
|
+
const dayOfWeek = dateObj.getDay();
|
|
505
|
+
const weekNames = [
|
|
506
|
+
t('uCalendar.sun'),
|
|
507
|
+
t('uCalendar.mon'),
|
|
508
|
+
t('uCalendar.tue'),
|
|
509
|
+
t('uCalendar.wed'),
|
|
510
|
+
t('uCalendar.thu'),
|
|
511
|
+
t('uCalendar.fri'),
|
|
512
|
+
t('uCalendar.sat')
|
|
513
|
+
];
|
|
514
|
+
|
|
515
|
+
const isSelected = activeDate.value === dateStr || startDate.value === dateStr || endDate.value === dateStr;
|
|
516
|
+
|
|
517
|
+
return {
|
|
518
|
+
year: year.value,
|
|
519
|
+
month: month.value,
|
|
520
|
+
day: dayNum,
|
|
521
|
+
date: dateStr,
|
|
522
|
+
week: weekNames[dayOfWeek],
|
|
523
|
+
weekNum: dayOfWeek,
|
|
524
|
+
isToday: dateStr === today.value,
|
|
525
|
+
isHoliday: props.holidays.includes(dateStr),
|
|
526
|
+
isWorkday: props.workdays.includes(dateStr),
|
|
527
|
+
isChecked: props.checkedDates.includes(dateStr),
|
|
528
|
+
isSelected,
|
|
529
|
+
isTodayChecked: dateStr === today.value && props.todayChecked,
|
|
530
|
+
lunar: lunarArr[dayNum - 1] || null
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* 判断是否是节假日
|
|
536
|
+
*/
|
|
537
|
+
function isHoliday(dayNum: number) {
|
|
538
|
+
const date = `${year.value}-${formatNum(month.value)}-${formatNum(dayNum)}`;
|
|
539
|
+
return props.holidays.includes(date);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* 判断是否是加班日
|
|
544
|
+
*/
|
|
545
|
+
function isWorkday(dayNum: number) {
|
|
546
|
+
const date = `${year.value}-${formatNum(month.value)}-${formatNum(dayNum)}`;
|
|
547
|
+
return props.workdays.includes(date);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* 获取节日名称(合并内置节日和用户自定义节日)
|
|
552
|
+
* 用户传入空字符串可覆盖内置节日,表示不显示该节日
|
|
553
|
+
* 支持两种格式:
|
|
554
|
+
* 1. 年-月-日:特定年份的节日,如 '2024-04-04': '清明节'
|
|
555
|
+
* 2. 月-日:每年的固定节日,如 '04-04': '清明节'
|
|
556
|
+
*/
|
|
557
|
+
function getFestival(dayNum: number) {
|
|
558
|
+
if (!props.showFestival && Object.keys(props.festivals).length === 0) {
|
|
559
|
+
return '';
|
|
560
|
+
}
|
|
561
|
+
const date = `${year.value}-${formatNum(month.value)}-${formatNum(dayNum)}`;
|
|
562
|
+
const monthDay = `${formatNum(month.value)}-${formatNum(dayNum)}`;
|
|
563
|
+
|
|
564
|
+
// 优先检查用户自定义节日(特定年份格式)
|
|
565
|
+
if (date in props.festivals) {
|
|
566
|
+
return props.festivals[date];
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// 然后检查用户自定义节日(每年固定格式,月-日)
|
|
570
|
+
if (monthDay in props.festivals) {
|
|
571
|
+
return props.festivals[monthDay];
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// 最后检查内置节日(如果启用了 showFestival)
|
|
575
|
+
if (props.showFestival && builtInFestivals[monthDay]) {
|
|
576
|
+
return builtInFestivals[monthDay];
|
|
577
|
+
}
|
|
578
|
+
return '';
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* 获取节假日/加班日文字颜色
|
|
583
|
+
* 当选中日期时显示白色,否则显示对应的颜色
|
|
584
|
+
*/
|
|
585
|
+
function getHolidayWorkdayColor(dayNum: number, defaultColor: string) {
|
|
586
|
+
const date = `${year.value}-${formatNum(month.value)}-${formatNum(dayNum)}`;
|
|
587
|
+
// 选中日期的节假日/加班日显示白色
|
|
588
|
+
if (activeDate.value === date || startDate.value === date || endDate.value === date) {
|
|
589
|
+
return props.activeColor;
|
|
590
|
+
}
|
|
591
|
+
return defaultColor;
|
|
592
|
+
}
|
|
593
|
+
|
|
386
594
|
/**
|
|
387
595
|
* 初始化日历数据
|
|
388
596
|
*/
|
|
@@ -396,10 +604,72 @@ function init() {
|
|
|
396
604
|
year.value = now.getFullYear();
|
|
397
605
|
month.value = now.getMonth() + 1;
|
|
398
606
|
day.value = now.getDate();
|
|
399
|
-
today.value = `${now.getFullYear()}-${month.value}-${day.value}`;
|
|
400
|
-
activeDate.value = today.value;
|
|
607
|
+
today.value = `${now.getFullYear()}-${formatNum(month.value)}-${formatNum(day.value)}`;
|
|
401
608
|
min.value = initDate(String(props.minDate));
|
|
402
609
|
max.value = initDate(String(props.maxDate) || today.value);
|
|
610
|
+
|
|
611
|
+
// 处理默认选中日期
|
|
612
|
+
// 优先级1: defaultDate / startDate / endDate(显式指定日期)
|
|
613
|
+
// 优先级2: defaultSelectToday(默认选中今天)
|
|
614
|
+
// 优先级3: 不选中任何日期
|
|
615
|
+
if (props.mode === 'date' && props.defaultDate) {
|
|
616
|
+
// 单选模式:使用 defaultDate(优先级1)
|
|
617
|
+
const defaultDateObj = new Date(props.defaultDate.replace(/\-/g, '/'));
|
|
618
|
+
if (!isNaN(defaultDateObj.getTime())) {
|
|
619
|
+
year.value = defaultDateObj.getFullYear();
|
|
620
|
+
month.value = defaultDateObj.getMonth() + 1;
|
|
621
|
+
day.value = defaultDateObj.getDate();
|
|
622
|
+
// 统一格式为 YYYY-MM-DD,与 getColor 中的格式一致
|
|
623
|
+
activeDate.value = `${year.value}-${formatNum(month.value)}-${formatNum(day.value)}`;
|
|
624
|
+
} else if (props.defaultSelectToday) {
|
|
625
|
+
activeDate.value = today.value;
|
|
626
|
+
} else {
|
|
627
|
+
activeDate.value = '';
|
|
628
|
+
}
|
|
629
|
+
} else if (props.mode === 'range' && (props.startDate || props.endDate)) {
|
|
630
|
+
// 范围模式:使用 startDate 和 endDate(优先级1)
|
|
631
|
+
const startDateObj = props.startDate ? new Date(props.startDate.replace(/\-/g, '/')) : null;
|
|
632
|
+
const endDateObj = props.endDate ? new Date(props.endDate.replace(/\-/g, '/')) : null;
|
|
633
|
+
|
|
634
|
+
if (startDateObj && !isNaN(startDateObj.getTime())) {
|
|
635
|
+
// 设置当前显示月份为开始日期所在月份
|
|
636
|
+
year.value = startDateObj.getFullYear();
|
|
637
|
+
month.value = startDateObj.getMonth() + 1;
|
|
638
|
+
|
|
639
|
+
// 设置开始日期 - 统一格式为 YYYY-MM-DD
|
|
640
|
+
startYear.value = startDateObj.getFullYear();
|
|
641
|
+
startMonth.value = startDateObj.getMonth() + 1;
|
|
642
|
+
startDay.value = startDateObj.getDate();
|
|
643
|
+
startDate.value = `${startYear.value}-${formatNum(startMonth.value)}-${formatNum(startDay.value)}`;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
if (endDateObj && !isNaN(endDateObj.getTime())) {
|
|
647
|
+
// 设置结束日期 - 统一格式为 YYYY-MM-DD
|
|
648
|
+
endYear.value = endDateObj.getFullYear();
|
|
649
|
+
endMonth.value = endDateObj.getMonth() + 1;
|
|
650
|
+
endDay.value = endDateObj.getDate();
|
|
651
|
+
endDate.value = `${endYear.value}-${formatNum(endMonth.value)}-${formatNum(endDay.value)}`;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
isStart.value = true;
|
|
655
|
+
activeDate.value = '';
|
|
656
|
+
} else if (props.defaultSelectToday) {
|
|
657
|
+
// 优先级2:默认选中今天
|
|
658
|
+
activeDate.value = today.value;
|
|
659
|
+
resetRangeState();
|
|
660
|
+
} else {
|
|
661
|
+
// 优先级3:不选中任何日期
|
|
662
|
+
activeDate.value = '';
|
|
663
|
+
resetRangeState();
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
changeData();
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* 重置范围选择状态
|
|
671
|
+
*/
|
|
672
|
+
function resetRangeState() {
|
|
403
673
|
startDate.value = '';
|
|
404
674
|
startYear.value = 0;
|
|
405
675
|
startMonth.value = 0;
|
|
@@ -409,7 +679,6 @@ function init() {
|
|
|
409
679
|
endDay.value = 0;
|
|
410
680
|
endDate.value = '';
|
|
411
681
|
isStart.value = true;
|
|
412
|
-
changeData();
|
|
413
682
|
}
|
|
414
683
|
|
|
415
684
|
/**
|
|
@@ -429,10 +698,10 @@ function initDate(date: string) {
|
|
|
429
698
|
*/
|
|
430
699
|
function openDisAbled(yearNum: number, monthNum: number, dayNum: number) {
|
|
431
700
|
let bool = true;
|
|
432
|
-
let date = `${yearNum}/${monthNum}/${dayNum}`;
|
|
701
|
+
let date = `${yearNum}/${formatNum(monthNum)}/${formatNum(dayNum)}`;
|
|
433
702
|
// let today = this.today.replace(/\-/g, '/');
|
|
434
|
-
let minStr = min.value ? `${min.value.year}/${min.value.month}/${min.value.day}` : '';
|
|
435
|
-
let maxStr = max.value ? `${max.value.year}/${max.value.month}/${max.value.day}` : '';
|
|
703
|
+
let minStr = min.value ? `${min.value.year}/${formatNum(min.value.month)}/${formatNum(min.value.day)}` : '';
|
|
704
|
+
let maxStr = max.value ? `${max.value.year}/${formatNum(max.value.month)}/${formatNum(max.value.day)}` : '';
|
|
436
705
|
let timestamp = new Date(date).getTime();
|
|
437
706
|
if (min.value && max.value && timestamp >= new Date(minStr).getTime() && timestamp <= new Date(maxStr).getTime()) {
|
|
438
707
|
bool = false;
|
|
@@ -575,15 +844,20 @@ function getLunar(year: any, month: any, day: any) {
|
|
|
575
844
|
* 日期点击事件
|
|
576
845
|
*/
|
|
577
846
|
function dateClick(dayIdx: number) {
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
847
|
+
// 只读模式下禁止点击
|
|
848
|
+
if (props.readonly) return;
|
|
849
|
+
|
|
581
850
|
const d = dayIdx + 1;
|
|
582
851
|
if (!openDisAbled(year.value, month.value, d)) {
|
|
583
852
|
day.value = d;
|
|
584
|
-
let date = `${year.value}-${month.value}-${d}`;
|
|
853
|
+
let date = `${year.value}-${formatNum(month.value)}-${formatNum(d)}`;
|
|
585
854
|
if (props.mode == 'date') {
|
|
586
855
|
activeDate.value = date;
|
|
856
|
+
// 页面模式下,单选日期选择完成自动触发change事件
|
|
857
|
+
// 打卡签到模式下,弹窗模式也立即触发change事件
|
|
858
|
+
if (props.isPage || props.checkinMode) {
|
|
859
|
+
btnFix(true);
|
|
860
|
+
}
|
|
587
861
|
} else {
|
|
588
862
|
let compare =
|
|
589
863
|
new Date(date.replace(/\-/g, '/')).getTime() < new Date(startDate.value.replace(/\-/g, '/')).getTime();
|
|
@@ -604,6 +878,10 @@ function dateClick(dayIdx: number) {
|
|
|
604
878
|
endMonth.value = month.value;
|
|
605
879
|
endDay.value = day.value;
|
|
606
880
|
isStart.value = true;
|
|
881
|
+
// 页面模式下,范围选择完成(选了结束日期)自动触发change事件
|
|
882
|
+
if (props.isPage) {
|
|
883
|
+
btnFix(true);
|
|
884
|
+
}
|
|
607
885
|
}
|
|
608
886
|
}
|
|
609
887
|
}
|
|
@@ -630,7 +908,8 @@ function getWeekText(date: string) {
|
|
|
630
908
|
* 确定按钮事件
|
|
631
909
|
*/
|
|
632
910
|
function btnFix(show: boolean) {
|
|
633
|
-
|
|
911
|
+
// 页面模式下不关闭,弹窗模式下关闭
|
|
912
|
+
if (!show && !props.isPage) {
|
|
634
913
|
close();
|
|
635
914
|
}
|
|
636
915
|
if (props.mode == 'date') {
|
|
@@ -642,7 +921,7 @@ function btnFix(show: boolean) {
|
|
|
642
921
|
let result = `${y}-${formatNum(m)}-${formatNum(d)}`;
|
|
643
922
|
let weekText = getWeekText(result);
|
|
644
923
|
let isToday = false;
|
|
645
|
-
if (
|
|
924
|
+
if (result == today.value) {
|
|
646
925
|
// 今天
|
|
647
926
|
isToday = true;
|
|
648
927
|
}
|
|
@@ -698,6 +977,11 @@ function btnFix(show: boolean) {
|
|
|
698
977
|
.u-calendar {
|
|
699
978
|
color: $u-content-color;
|
|
700
979
|
|
|
980
|
+
&--page {
|
|
981
|
+
background-color: var(--u-bg-white);
|
|
982
|
+
border-radius: 16rpx;
|
|
983
|
+
}
|
|
984
|
+
|
|
701
985
|
&__header {
|
|
702
986
|
width: 100%;
|
|
703
987
|
box-sizing: border-box;
|
|
@@ -762,6 +1046,39 @@ function btnFix(show: boolean) {
|
|
|
762
1046
|
border-bottom-left-radius: 8rpx;
|
|
763
1047
|
}
|
|
764
1048
|
|
|
1049
|
+
&--checked {
|
|
1050
|
+
.u-calendar__content__item__inner {
|
|
1051
|
+
width: 80rpx;
|
|
1052
|
+
height: 80rpx;
|
|
1053
|
+
border-radius: 50%;
|
|
1054
|
+
display: flex;
|
|
1055
|
+
align-items: center;
|
|
1056
|
+
justify-content: center;
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
&--today-checked {
|
|
1061
|
+
.u-calendar__content__item__inner {
|
|
1062
|
+
width: 80rpx;
|
|
1063
|
+
height: 80rpx;
|
|
1064
|
+
border-radius: 50%;
|
|
1065
|
+
display: flex;
|
|
1066
|
+
align-items: center;
|
|
1067
|
+
justify-content: center;
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
&--checkin-mode {
|
|
1072
|
+
.u-calendar__content__item__inner {
|
|
1073
|
+
width: 80rpx;
|
|
1074
|
+
height: 80rpx;
|
|
1075
|
+
border-radius: 50%;
|
|
1076
|
+
display: flex;
|
|
1077
|
+
align-items: center;
|
|
1078
|
+
justify-content: center;
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
|
|
765
1082
|
&__item {
|
|
766
1083
|
width: 14.2857%;
|
|
767
1084
|
@include vue-flex;
|
|
@@ -779,8 +1096,6 @@ function btnFix(show: boolean) {
|
|
|
779
1096
|
justify-content: center;
|
|
780
1097
|
flex-direction: column;
|
|
781
1098
|
font-size: 32rpx;
|
|
782
|
-
position: relative;
|
|
783
|
-
border-radius: 50%;
|
|
784
1099
|
|
|
785
1100
|
&__desc {
|
|
786
1101
|
width: 100%;
|
|
@@ -795,6 +1110,61 @@ function btnFix(show: boolean) {
|
|
|
795
1110
|
}
|
|
796
1111
|
}
|
|
797
1112
|
|
|
1113
|
+
&__day {
|
|
1114
|
+
font-size: 32rpx;
|
|
1115
|
+
line-height: 1;
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
&__lunar {
|
|
1119
|
+
font-size: 22rpx;
|
|
1120
|
+
line-height: 1;
|
|
1121
|
+
margin-top: 2rpx;
|
|
1122
|
+
transform: scale(0.85);
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
// 节假日/加班日标签样式
|
|
1126
|
+
&__holiday,
|
|
1127
|
+
&__workday {
|
|
1128
|
+
font-size: 22rpx;
|
|
1129
|
+
line-height: 1;
|
|
1130
|
+
margin-top: 2rpx;
|
|
1131
|
+
transform: scale(0.85);
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
// 右上角标记样式(休/班)
|
|
1135
|
+
&__mark {
|
|
1136
|
+
position: absolute;
|
|
1137
|
+
top: 8rpx;
|
|
1138
|
+
right: 8rpx;
|
|
1139
|
+
font-size: 24rpx;
|
|
1140
|
+
line-height: 1;
|
|
1141
|
+
transform: scale(0.75);
|
|
1142
|
+
z-index: 1;
|
|
1143
|
+
|
|
1144
|
+
&--holiday {
|
|
1145
|
+
color: var(--u-type-error);
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
&--workday {
|
|
1149
|
+
color: var(--u-type-primary);
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
// 节日名称样式(与农历保持一致)
|
|
1154
|
+
&__festival {
|
|
1155
|
+
font-size: 22rpx;
|
|
1156
|
+
line-height: 1;
|
|
1157
|
+
transform: scale(0.85);
|
|
1158
|
+
color: var(--u-type-primary);
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
// 占位元素样式
|
|
1162
|
+
&__placeholder {
|
|
1163
|
+
min-height: 22rpx;
|
|
1164
|
+
margin-top: 2rpx;
|
|
1165
|
+
opacity: 0;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
798
1168
|
&__tips {
|
|
799
1169
|
width: 100%;
|
|
800
1170
|
font-size: 24rpx;
|
|
@@ -807,6 +1177,27 @@ function btnFix(show: boolean) {
|
|
|
807
1177
|
bottom: 8rpx;
|
|
808
1178
|
z-index: 2;
|
|
809
1179
|
}
|
|
1180
|
+
|
|
1181
|
+
&__check-icon {
|
|
1182
|
+
position: absolute;
|
|
1183
|
+
right: 4rpx;
|
|
1184
|
+
top: 4rpx;
|
|
1185
|
+
z-index: 3;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
&__checkmark {
|
|
1189
|
+
@include vue-flex;
|
|
1190
|
+
align-items: center;
|
|
1191
|
+
justify-content: center;
|
|
1192
|
+
width: 100%;
|
|
1193
|
+
height: 100%;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
&__inner--today-checked {
|
|
1197
|
+
@include vue-flex;
|
|
1198
|
+
align-items: center;
|
|
1199
|
+
justify-content: center;
|
|
1200
|
+
}
|
|
810
1201
|
}
|
|
811
1202
|
|
|
812
1203
|
&__bg-month {
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
|
+
<!-- inline 模式:直接渲染内容,不显示为弹窗 -->
|
|
3
|
+
<view v-if="props.mode === 'inline'" class="u-popup-inline" :class="customClass" :style="inlineStyle">
|
|
4
|
+
<slot />
|
|
5
|
+
</view>
|
|
6
|
+
<!-- 弹窗模式 -->
|
|
2
7
|
<view
|
|
3
|
-
v-if="visibleSync"
|
|
8
|
+
v-else-if="visibleSync"
|
|
4
9
|
class="u-drawer"
|
|
5
10
|
:style="$u.toStyle({ zIndex: Number(uZIndex) - 1 }, customStyle)"
|
|
6
11
|
:class="customClass"
|
|
@@ -78,7 +83,7 @@ import { PopupProps } from './types';
|
|
|
78
83
|
* popup 弹窗
|
|
79
84
|
* @description 弹出层容器,用于展示弹窗、信息提示等内容,支持上、下、左、右和中部弹出。组件只提供容器,内部内容由用户自定义
|
|
80
85
|
* @tutorial https://uviewpro.cn/zh/components/popup.html
|
|
81
|
-
* @property {String} mode 弹出方向(默认left
|
|
86
|
+
* @property {String} mode 弹出方向(默认left),新增 inline 模式可直接插入页面
|
|
82
87
|
* @property {Boolean} mask 是否显示遮罩(默认true)
|
|
83
88
|
* @property {Stringr | Number} length mode=left | 见官网说明(默认auto)
|
|
84
89
|
* @property {Boolean} zoom 是否开启缩放动画,只在mode为center时有效(默认true)
|
|
@@ -96,6 +101,7 @@ import { PopupProps } from './types';
|
|
|
96
101
|
* @event {Function} open 弹出层打开
|
|
97
102
|
* @event {Function} close 弹出层收起
|
|
98
103
|
* @example <u-popup v-model="show"><view>出淤泥而不染,濯清涟而不妖</view></u-popup>
|
|
104
|
+
* @example <u-popup mode="inline"><view>直接插入页面内容</view></u-popup>
|
|
99
105
|
*/
|
|
100
106
|
|
|
101
107
|
const props = defineProps(PopupProps);
|
|
@@ -106,6 +112,25 @@ const visibleSync = ref(false);
|
|
|
106
112
|
const showDrawer = ref(false);
|
|
107
113
|
const timer = ref<ReturnType<typeof setTimeout> | null>(null);
|
|
108
114
|
const closeFromInner = ref(false); // value的值改变,是发生在内部还是外部
|
|
115
|
+
|
|
116
|
+
// inline 模式的样式
|
|
117
|
+
const inlineStyle = computed(() => {
|
|
118
|
+
let style: Record<string, any> = {};
|
|
119
|
+
if (props.width) style.width = getUnitValue(props.width);
|
|
120
|
+
if (props.height) style.height = getUnitValue(props.height);
|
|
121
|
+
if (props.borderRadius) style.borderRadius = `${props.borderRadius}rpx`;
|
|
122
|
+
// 合并用户自定义样式
|
|
123
|
+
if (props.customStyle) {
|
|
124
|
+
if (typeof props.customStyle === 'string') {
|
|
125
|
+
// 简单处理字符串样式
|
|
126
|
+
style = { ...style };
|
|
127
|
+
} else {
|
|
128
|
+
Object.assign(style, props.customStyle);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return style;
|
|
132
|
+
});
|
|
133
|
+
|
|
109
134
|
// 根据mode的位置,设定其弹窗的宽度(mode = left|right),或者高度(mode = top|bottom)
|
|
110
135
|
const style = computed(() => {
|
|
111
136
|
let style: Record<string, any> = {};
|
|
@@ -171,6 +196,8 @@ const uZIndex = computed(() => (props.zIndex ? props.zIndex : $u.zIndex.popup));
|
|
|
171
196
|
watch(
|
|
172
197
|
() => props.modelValue,
|
|
173
198
|
val => {
|
|
199
|
+
// inline 模式下不响应 modelValue 变化
|
|
200
|
+
if (props.mode === 'inline') return;
|
|
174
201
|
if (val) {
|
|
175
202
|
open();
|
|
176
203
|
} else if (!closeFromInner.value) {
|
|
@@ -181,6 +208,8 @@ watch(
|
|
|
181
208
|
);
|
|
182
209
|
|
|
183
210
|
onMounted(() => {
|
|
211
|
+
// inline 模式下不执行弹窗逻辑
|
|
212
|
+
if (props.mode === 'inline') return;
|
|
184
213
|
if (props.modelValue) open();
|
|
185
214
|
});
|
|
186
215
|
|
|
@@ -203,6 +232,8 @@ function maskClick() {
|
|
|
203
232
|
* 关闭弹窗
|
|
204
233
|
*/
|
|
205
234
|
function close() {
|
|
235
|
+
// inline 模式下不执行关闭逻辑
|
|
236
|
+
if (props.mode === 'inline') return;
|
|
206
237
|
// 标记关闭是内部发生的,否则修改了value值,导致watch中对value检测,导致再执行一遍close
|
|
207
238
|
// 造成@close事件触发两次
|
|
208
239
|
closeFromInner.value = true;
|
|
@@ -213,6 +244,8 @@ function close() {
|
|
|
213
244
|
* 中部弹出时,点击内容区域关闭弹窗
|
|
214
245
|
*/
|
|
215
246
|
function modeCenterClose(mode: string) {
|
|
247
|
+
// inline 模式下不执行关闭逻辑
|
|
248
|
+
if (props.mode === 'inline') return;
|
|
216
249
|
// 中部弹出时,需要.u-drawer-content将居中内容,此元素会铺满屏幕,点击需要关闭弹窗
|
|
217
250
|
// 让其只在mode=center时起作用
|
|
218
251
|
if (mode != 'center' || !props.maskCloseAble) return;
|
|
@@ -223,6 +256,8 @@ function modeCenterClose(mode: string) {
|
|
|
223
256
|
* 打开弹窗
|
|
224
257
|
*/
|
|
225
258
|
function open() {
|
|
259
|
+
// inline 模式下不执行打开逻辑
|
|
260
|
+
if (props.mode === 'inline') return;
|
|
226
261
|
change('visibleSync', 'showDrawer', true);
|
|
227
262
|
}
|
|
228
263
|
|
|
@@ -232,6 +267,8 @@ function open() {
|
|
|
232
267
|
* 打开时,先渲染组件,延时一定时间再让遮罩和弹窗的动画起作用
|
|
233
268
|
*/
|
|
234
269
|
function change(param1: 'showDrawer' | 'visibleSync', param2: 'visibleSync' | 'showDrawer', status: boolean) {
|
|
270
|
+
// inline 模式下不执行状态变更
|
|
271
|
+
if (props.mode === 'inline') return;
|
|
235
272
|
// 如果this.popup为false,意味着为picker,actionsheet等组件调用了popup组件
|
|
236
273
|
if (props.popup === true) {
|
|
237
274
|
emit('update:modelValue', status);
|
|
@@ -262,6 +299,15 @@ function change(param1: 'showDrawer' | 'visibleSync', param2: 'visibleSync' | 's
|
|
|
262
299
|
<style scoped lang="scss">
|
|
263
300
|
@import '../../libs/css/style.components.scss';
|
|
264
301
|
|
|
302
|
+
// inline 模式样式
|
|
303
|
+
.u-popup-inline {
|
|
304
|
+
/* #ifndef APP-NVUE */
|
|
305
|
+
display: block;
|
|
306
|
+
/* #endif */
|
|
307
|
+
position: relative;
|
|
308
|
+
background-color: var(--u-bg-white);
|
|
309
|
+
}
|
|
310
|
+
|
|
265
311
|
.u-drawer {
|
|
266
312
|
/* #ifndef APP-NVUE */
|
|
267
313
|
display: block;
|
package/components/u-th/u-th.vue
CHANGED
package/locale/lang/en-US.ts
CHANGED
package/locale/lang/zh-CN.ts
CHANGED
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "uview-pro",
|
|
3
3
|
"name": "uview-pro",
|
|
4
4
|
"displayName": "【支持鸿蒙】uView Pro|基于Vue3+TS的高质量UI组件库,支持多主题、暗黑模式、多语言",
|
|
5
|
-
"version": "0.5.
|
|
5
|
+
"version": "0.5.17",
|
|
6
6
|
"description": "uView Pro是基于Vue3+TS的多平台UI框架,提供80+高质量组件、便捷工具和常用模板,支持多主题、暗黑模式、多语言,支持H5/APP/鸿蒙/小程序多端开发。已在鸿蒙应用商店上架,欢迎体验!",
|
|
7
7
|
"main": "index.ts",
|
|
8
8
|
"module": "index.ts",
|
package/types/global.d.ts
CHANGED
|
@@ -209,7 +209,7 @@ export type PickerParams = {
|
|
|
209
209
|
timestamp?: boolean;
|
|
210
210
|
};
|
|
211
211
|
|
|
212
|
-
export type PopupMode = 'left' | 'right' | 'top' | 'bottom' | 'center';
|
|
212
|
+
export type PopupMode = 'left' | 'right' | 'top' | 'bottom' | 'center' | 'inline';
|
|
213
213
|
export type PopupCloseIconPos = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
214
214
|
|
|
215
215
|
// Row水平排列方式,可选值为`start`(或`flex-start`)、`end`(或`flex-end`)、`center`、`around`(或`space-around`)、`between`(或`space-between`)
|