You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

375 lines
8.6 KiB

  1. <template>
  2. <view class="uv-calendar-body">
  3. <view class="uv-calendar__header">
  4. <view class="uv-calendar__header-btn-box" @click.stop="pre">
  5. <view class="uv-calendar__header-btn uv-calendar--left"></view>
  6. </view>
  7. <picker mode="date" :value="getDate" fields="month" @change="bindDateChange">
  8. <text class="uv-calendar__header-text">{{ (nowDate.year||'') +' / '+( nowDate.month||'')}}</text>
  9. </picker>
  10. <view class="uv-calendar__header-btn-box" @click.stop="next">
  11. <view class="uv-calendar__header-btn uv-calendar--right"></view>
  12. </view>
  13. <text class="uv-calendar__backtoday" @click="backToday">{{todayText}}</text>
  14. </view>
  15. <view class="uv-calendar__box">
  16. <view v-if="showMonth" class="uv-calendar__box-bg">
  17. <text class="uv-calendar__box-bg-text">{{nowDate.month}}</text>
  18. </view>
  19. <view class="uv-calendar__weeks uv-calendar__weeks-week">
  20. <view class="uv-calendar__weeks-day">
  21. <text class="uv-calendar__weeks-day-text">{{SUNText}}</text>
  22. </view>
  23. <view class="uv-calendar__weeks-day">
  24. <text class="uv-calendar__weeks-day-text">{{monText}}</text>
  25. </view>
  26. <view class="uv-calendar__weeks-day">
  27. <text class="uv-calendar__weeks-day-text">{{TUEText}}</text>
  28. </view>
  29. <view class="uv-calendar__weeks-day">
  30. <text class="uv-calendar__weeks-day-text">{{WEDText}}</text>
  31. </view>
  32. <view class="uv-calendar__weeks-day">
  33. <text class="uv-calendar__weeks-day-text">{{THUText}}</text>
  34. </view>
  35. <view class="uv-calendar__weeks-day">
  36. <text class="uv-calendar__weeks-day-text">{{FRIText}}</text>
  37. </view>
  38. <view class="uv-calendar__weeks-day">
  39. <text class="uv-calendar__weeks-day-text">{{SATText}}</text>
  40. </view>
  41. </view>
  42. <view class="uv-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
  43. <view class="uv-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
  44. <calendar-item class="uv-calendar-item--hook" :weeks="weeks" :rangeInfoText="rangeInfoText(weeks)" :multiple="multiple" :range="range" :calendar="calendar" :selected="selected" :lunar="lunar" :color="color" @change="choiceDate"></calendar-item>
  45. </view>
  46. </view>
  47. </view>
  48. </view>
  49. </template>
  50. <script>
  51. import mpMixin from '@/uni_modules/uv-ui-tools/libs/mixin/mpMixin.js';
  52. import mixin from '@/uni_modules/uv-ui-tools/libs/mixin/mixin.js';
  53. import CalendarItem from './calendar-item.vue';
  54. import { initVueI18n } from '@dcloudio/uni-i18n';
  55. import i18nMessages from './i18n/index.js';
  56. const { t } = initVueI18n(i18nMessages);
  57. export default {
  58. mixins: [mpMixin, mixin],
  59. components: {
  60. CalendarItem
  61. },
  62. props: {
  63. date: {
  64. type: [String,Array],
  65. default: ''
  66. },
  67. nowDate: {
  68. type: [String, Object],
  69. default: ''
  70. },
  71. weeks: {
  72. type: [Array, Object],
  73. default () {
  74. return []
  75. }
  76. },
  77. calendar: {
  78. type: Object,
  79. default () {
  80. return {}
  81. }
  82. },
  83. selected: {
  84. type: Array,
  85. default () {
  86. return []
  87. }
  88. },
  89. lunar: {
  90. type: Boolean,
  91. default: false
  92. },
  93. showMonth: {
  94. type: Boolean,
  95. default: true
  96. },
  97. color: {
  98. type: String,
  99. default: '#3c9cff'
  100. },
  101. startText: {
  102. type: String,
  103. default: '开始'
  104. },
  105. endText: {
  106. type: String,
  107. default: '结束'
  108. },
  109. range: {
  110. type: Boolean,
  111. default: false
  112. },
  113. multiple: {
  114. type: Boolean,
  115. default: false
  116. },
  117. // 是否允许日期范围的起止时间为同一天,mode = range时有效
  118. allowSameDay: {
  119. type: Boolean,
  120. default: false
  121. }
  122. },
  123. computed: {
  124. getDate() {
  125. return Array.isArray(this.date) ? this.date[0] : this.date;
  126. },
  127. /**
  128. * for i18n
  129. */
  130. todayText() {
  131. return t("uv-calender.today")
  132. },
  133. monText() {
  134. return t("uv-calender.MON")
  135. },
  136. TUEText() {
  137. return t("uv-calender.TUE")
  138. },
  139. WEDText() {
  140. return t("uv-calender.WED")
  141. },
  142. THUText() {
  143. return t("uv-calender.THU")
  144. },
  145. FRIText() {
  146. return t("uv-calender.FRI")
  147. },
  148. SATText() {
  149. return t("uv-calender.SAT")
  150. },
  151. SUNText() {
  152. return t("uv-calender.SUN")
  153. },
  154. rangeInfoText(weeks) {
  155. return weeks=> {
  156. if(this.allowSameDay && weeks.beforeRange && weeks.afterRange && weeks.dateEqual) {
  157. return this.setInfo(weeks,`${this.startText}/${this.endText}`);
  158. }
  159. if(weeks.beforeRange) {
  160. return this.setInfo(weeks,this.startText);
  161. }
  162. if(weeks.afterRange) {
  163. return this.setInfo(weeks,this.endText);
  164. }
  165. if(weeks.extraInfo?.info_old == ' ') {
  166. weeks.extraInfo.info = null;
  167. }else if(weeks.extraInfo?.info_old) {
  168. weeks.extraInfo.info = weeks.extraInfo.info_old;
  169. }
  170. }
  171. }
  172. },
  173. methods: {
  174. setInfo(weeks,text) {
  175. this.setInfoOld(weeks);
  176. if(weeks.extraInfo) {
  177. weeks.extraInfo.info = text;
  178. }else {
  179. weeks.extraInfo = {
  180. info: text
  181. }
  182. }
  183. },
  184. setInfoOld(weeks) {
  185. if(weeks.extraInfo) {
  186. weeks.extraInfo.info_old = weeks.extraInfo.info ? weeks.extraInfo.info_old || weeks.extraInfo.info : ' ';
  187. }
  188. },
  189. bindDateChange(e) {
  190. this.$emit('bindDateChange', e);
  191. },
  192. backToday() {
  193. this.$emit('backToday');
  194. },
  195. pre() {
  196. this.$emit('pre');
  197. },
  198. next() {
  199. this.$emit('next');
  200. },
  201. choiceDate(e) {
  202. this.$emit('choiceDate', e);
  203. }
  204. }
  205. }
  206. </script>
  207. <style scoped lang="scss">
  208. @mixin flex($direction: row) {
  209. /* #ifndef APP-NVUE */
  210. display: flex;
  211. /* #endif */
  212. flex-direction: $direction;
  213. }
  214. $uv-bg-color-mask: rgba($color: #000000, $alpha: 0.4);
  215. $uv-border-color: #EDEDED !default;
  216. $uv-text-color: #333;
  217. $uv-bg-color-hover: #f1f1f1;
  218. $uv-font-size-base: 14px;
  219. $uv-text-color-placeholder: #808080;
  220. $uv-color-subtitle: #555555;
  221. $uv-text-color-grey: #999;
  222. .uv-calendar {
  223. @include flex(column);
  224. }
  225. .uv-calendar__mask {
  226. position: fixed;
  227. bottom: 0;
  228. top: 0;
  229. left: 0;
  230. right: 0;
  231. background-color: $uv-bg-color-mask;
  232. transition-property: opacity;
  233. transition-duration: 0.3s;
  234. opacity: 0;
  235. /* #ifndef APP-NVUE */
  236. z-index: 99;
  237. /* #endif */
  238. }
  239. .uv-calendar--mask-show {
  240. opacity: 1
  241. }
  242. .uv-calendar--fixed {
  243. position: fixed;
  244. /* #ifdef APP-NVUE */
  245. bottom: 0;
  246. /* #endif */
  247. left: 0;
  248. right: 0;
  249. transition-property: transform;
  250. transition-duration: 0.3s;
  251. transform: translateY(460px);
  252. /* #ifndef APP-NVUE */
  253. bottom: calc(var(--window-bottom));
  254. z-index: 99;
  255. /* #endif */
  256. }
  257. .uv-calendar--ani-show {
  258. transform: translateY(0);
  259. }
  260. .uv-calendar__content {
  261. background-color: #fff;
  262. }
  263. .uv-calendar__header {
  264. position: relative;
  265. @include flex;
  266. justify-content: center;
  267. align-items: center;
  268. height: 50px;
  269. border-bottom-color: $uv-border-color;
  270. border-bottom-style: solid;
  271. border-bottom-width: 1px;
  272. }
  273. .uv-calendar--fixed-top {
  274. @include flex;
  275. justify-content: space-between;
  276. border-top-color: $uv-border-color;
  277. border-top-style: solid;
  278. border-top-width: 1px;
  279. }
  280. .uv-calendar--fixed-width {
  281. width: 50px;
  282. }
  283. .uv-calendar__backtoday {
  284. position: absolute;
  285. right: 0;
  286. top: 25rpx;
  287. padding: 0 5px;
  288. padding-left: 10px;
  289. height: 25px;
  290. line-height: 25px;
  291. font-size: 12px;
  292. border-top-left-radius: 25px;
  293. border-bottom-left-radius: 25px;
  294. color: $uv-text-color;
  295. background-color: $uv-bg-color-hover;
  296. }
  297. .uv-calendar__header-text {
  298. text-align: center;
  299. width: 100px;
  300. font-size: $uv-font-size-base;
  301. color: $uv-text-color;
  302. }
  303. .uv-calendar__header-btn-box {
  304. @include flex;
  305. align-items: center;
  306. justify-content: center;
  307. width: 50px;
  308. height: 50px;
  309. }
  310. .uv-calendar__header-btn {
  311. width: 10px;
  312. height: 10px;
  313. border-left-color: $uv-text-color-placeholder;
  314. border-left-style: solid;
  315. border-left-width: 2px;
  316. border-top-color: $uv-color-subtitle;
  317. border-top-style: solid;
  318. border-top-width: 2px;
  319. }
  320. .uv-calendar--left {
  321. transform: rotate(-45deg);
  322. }
  323. .uv-calendar--right {
  324. transform: rotate(135deg);
  325. }
  326. .uv-calendar__weeks {
  327. position: relative;
  328. @include flex;
  329. }
  330. .uv-calendar__weeks-week {
  331. padding: 0 0 2rpx;
  332. }
  333. .uv-calendar__weeks-item {
  334. flex: 1;
  335. }
  336. .uv-calendar__weeks-day {
  337. flex: 1;
  338. @include flex(column);
  339. justify-content: center;
  340. align-items: center;
  341. height: 45px;
  342. border-bottom-color: #F5F5F5;
  343. border-bottom-style: solid;
  344. border-bottom-width: 1px;
  345. }
  346. .uv-calendar__weeks-day-text {
  347. font-size: 14px;
  348. }
  349. .uv-calendar__box {
  350. position: relative;
  351. }
  352. .uv-calendar__box-bg {
  353. @include flex(column);
  354. justify-content: center;
  355. align-items: center;
  356. position: absolute;
  357. top: 0;
  358. left: 0;
  359. right: 0;
  360. bottom: 0;
  361. }
  362. .uv-calendar__box-bg-text {
  363. font-size: 200px;
  364. font-weight: bold;
  365. color: $uv-text-color-grey;
  366. opacity: 0.1;
  367. text-align: center;
  368. /* #ifndef APP-NVUE */
  369. line-height: 1;
  370. /* #endif */
  371. }
  372. </style>