feat: 库存查询

property-only-app
wx-jincw 3 months ago
parent 944a245f8a
commit 53bf699166

@ -0,0 +1,19 @@
import request from '@/utils/request.js';
// 库存列表
export function getStockList(params) {
return request.get(
'autogencode/ckcargostock/newList',
params,
{ useAdminUrl: true }
);
}
// 库存明细
export function getStockDetail(params) {
return request.get(
'autogencode/ckcargostock/list',
params,
{ useAdminUrl: true }
);
}

@ -8,7 +8,8 @@
// | Author: CRMEB Team <admin@crmeb.com> // | Author: CRMEB Team <admin@crmeb.com>
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
//移动端商城API //移动端商城API
let domain = 'https://fzbfwy.com/mobile-api' // let domain = 'https://fzbfwy.com/mobile-api'
let domain = 'http://crmebxcx.test.jiutianda.cn'
module.exports = { module.exports = {
// 请求域名 格式: https://您的域名 // 请求域名 格式: https://您的域名
@ -17,7 +18,8 @@ module.exports = {
// #ifdef MP // #ifdef MP
HTTP_REQUEST_URL: domain, HTTP_REQUEST_URL: domain,
// #endif // #endif
HTTP_ADMIN_URL:'https://fzbfwy.com/prod-api', //PC后台的API请求地址上传图片用,影响h5上传头像 HTTP_ADMIN_URL:'https://crmeb.test.jiutianda.cn',
// HTTP_ADMIN_URL:'https://fzbfwy.com/prod-api', //PC后台的API请求地址上传图片用,影响h5上传头像
// #ifdef H5 // #ifdef H5
//H5接口是浏览器地址 //H5接口是浏览器地址
// HTTP_REQUEST_URL: window.location.protocol+"//"+window.location.host, // HTTP_REQUEST_URL: window.location.protocol+"//"+window.location.host,

@ -238,6 +238,18 @@
// #endif // #endif
} }
}, },
{
"path": "stock/detail",
"style": {
"navigationBarTitleText": "库存明细",
"navigationBarBackgroundColor": "#409EFF",
"navigationBarTextStyle": "white"
// #ifdef H5
,
"navigationStyle": "custom"
// #endif
}
},
{ {
"path": "approval/index", "path": "approval/index",
"style": { "style": {

@ -75,25 +75,25 @@
<image class="image" src="/static/images/wg/wg_buy.png"></image> <image class="image" src="/static/images/wg/wg_buy.png"></image>
</view> </view>
<view class="menu-txt">采购操作</view> <view class="menu-txt">采购操作</view>
</navigator> </navigator> -->
<navigator class='item' url='/pages/supply_chain/stock/index' hover-class='none'> <navigator class='item' url='/pages/supply_chain/stock/index' hover-class='none'>
<view class='pictrue picsmall'> <view class='pictrue picsmall'>
<image class="image" src="/static/images/wg/wg_stock.png"></image> <image class="image" src="/static/images/wg/wg_stock.png"></image>
</view> </view>
<view class="menu-txt">库存查询</view> <view class="menu-txt">库存查询</view>
</navigator> </navigator>
<navigator class='item' url='/pages/supply_chain/approval/index' hover-class='none'> <!-- <navigator class='item' url='/pages/supply_chain/approval/index' hover-class='none'>
<view class='pictrue picsmall'> <view class='pictrue picsmall'>
<image class="image" src="/static/images/wg/wg_audit.png"></image> <image class="image" src="/static/images/wg/wg_audit.png"></image>
</view> </view>
<view class="menu-txt">审批处理</view> <view class="menu-txt">审批处理</view>
</navigator> </navigator> -->
<navigator class='item' url='/pages/supply_chain/material_receipt/index' hover-class='none'> <navigator class='item' url='/pages/supply_chain/material_receipt/index' hover-class='none'>
<view class='pictrue picsmall'> <view class='pictrue picsmall'>
<image class="image" src="/static/images/wg/wg_get.png"></image> <image class="image" src="/static/images/wg/wg_get.png"></image>
</view> </view>
<view class="menu-txt">物资领用</view> <view class="menu-txt">物资领用</view>
</navigator> --> </navigator>
<navigator class='item' url='/pages/supply_chain/complaint/index' hover-class='none'> <navigator class='item' url='/pages/supply_chain/complaint/index' hover-class='none'>
<view class='pictrue picsmall'> <view class='pictrue picsmall'>
<image class="image" src="/static/images/wg/wg_jy.png"></image> <image class="image" src="/static/images/wg/wg_jy.png"></image>

@ -0,0 +1,215 @@
<template>
<view class="detail-page">
<view class="content">
<view class="header">
<view class="back-btn" @click="goBack">
<text class="iconfont icon-xiangzuo"></text>
<text>返回</text>
</view>
<view class="title">库存变化明细</view>
</view>
<!-- 明细列表 -->
<view class="detail-section">
<view class="detail-list" v-if="detailItems.length > 0">
<view class="detail-item" v-for="(item, index) in detailItems" :key="index">
<view class="item-header">
<text class="item-date">{{ formatDate(item.stockDate) }}</text>
<text class="item-bill">{{ item.billNumber }}</text>
</view>
<view class="item-body">
<view class="info-item">
<text class="label">仓库名称</text>
<text class="value">{{ item.stockName }}</text>
</view>
<view class="info-item">
<text class="label">供应商</text>
<text class="value">{{ item.custName }}</text>
</view>
<view class="info-item">
<text class="label">商品名称</text>
<text class="value">{{ item.cargoName }}</text>
</view>
<view class="info-item">
<text class="label">商品编号</text>
<text class="value">{{ item.hsCode }}</text>
</view>
<view class="info-item">
<text class="label">商品数量</text>
<text class="value">{{ item.cargoWt }}</text>
</view>
<view class="info-item">
<text class="label">商品价值</text>
<text class="value">{{ item.cargoValue }}</text>
</view>
</view>
</view>
</view>
<view class="empty-list" v-else>
<text>暂无明细数据</text>
</view>
</view>
</view>
</view>
</template>
<script>
import { getStockDetail } from '@/api/stock';
export default {
data() {
return {
detailItems: [],
loading: false,
cargoId: '',
custId: '',
queryParams: {
pageNum: 1,
pageSize: 10,
cargoId: null,
custId: null
}
};
},
onLoad(options) {
if (options.cargoId && options.custId) {
this.cargoId = options.cargoId;
this.custId = options.custId;
this.queryParams.cargoId = options.cargoId;
this.queryParams.custId = options.custId;
this.getDetailList();
}
},
methods: {
//
formatDate(timestamp) {
if (!timestamp) return '';
const date = new Date(timestamp);
return date.toISOString().split('T')[0];
},
//
getDetailList() {
this.loading = true;
// API
getStockDetail(this.queryParams).then((res) => {
this.detailItems = res.data.list || [];
this.loading = false;
}).catch((err) => {
console.error('获取明细列表失败:', err);
this.loading = false;
});
},
//
goBack() {
uni.navigateBack();
}
}
};
</script>
<style lang="scss">
.detail-page {
.content {
.header {
display: flex;
align-items: center;
padding: 30rpx;
background-color: #fff;
border-bottom: 1rpx solid #eee;
.back-btn {
display: flex;
align-items: center;
padding: 10rpx;
.iconfont {
font-size: 28rpx;
color: #333;
margin-right: 10rpx;
}
text {
font-size: 24rpx;
color: #333;
}
}
.title {
flex: 1;
font-size: 28rpx;
font-weight: 600;
color: #333;
text-align: center;
margin-right: 60rpx;
}
}
.detail-section {
padding: 30rpx;
.detail-list {
.detail-item {
background-color: #fff;
border-radius: 10rpx;
padding: 20rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
.item-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 15rpx;
padding-bottom: 15rpx;
border-bottom: 1rpx solid #eee;
.item-date {
font-size: 24rpx;
color: #333;
font-weight: 600;
}
.item-bill {
font-size: 22rpx;
color: #666;
}
}
.item-body {
.info-item {
display: flex;
margin-bottom: 10rpx;
.label {
width: 140rpx;
font-size: 24rpx;
color: #666;
}
.value {
flex: 1;
font-size: 24rpx;
color: #333;
}
}
}
}
}
.empty-list {
display: flex;
align-items: center;
justify-content: center;
height: 200rpx;
background-color: #f5f5f5;
border-radius: 10rpx;
text {
font-size: 24rpx;
color: #999;
}
}
}
}
}
</style>

@ -4,117 +4,180 @@
<!-- 搜索和筛选 --> <!-- 搜索和筛选 -->
<view class="search-section"> <view class="search-section">
<view class="search-box"> <view class="search-box">
<input type="text" v-model="searchKeyword" placeholder="搜索物资名称" /> <input type="text" v-model="queryParams.gdsSeqno" placeholder="搜索商品名称、编码、供应商" />
<view class="search-btn" @click="searchStock"></view> <view class="search-btn" @click="searchStock"></view>
</view> </view>
<view class="filter-box"> <view class="filter-box">
<view class="filter-item" @click="toggleFilter('category')"> <view class="filter-item" @click="toggleSortMenu">
<text>{{ selectedCategory || '全部类别' }}</text> <text>{{ sortText }}</text>
<text class="iconfont icon-xiangxia"></text> <text class="iconfont" :class="sortIcon"></text>
</view> </view>
<view class="filter-item" @click="toggleFilter('location')"> <view class="filter-item">
<text>{{ selectedLocation || '全部位置' }}</text> <view class="date-picker-container">
<text class="iconfont icon-xiangxia"></text> <view v-if="selectedDate" class="clear-btn" @click.stop="clearDate">
<text class="iconfont icon-cha"></text>
</view> </view>
<view class="date-text" @click="openCalendar">
<text>{{ selectedDate || '入库日期' }}</text>
<text class="iconfont icon-xiangxia"></text>
</view> </view>
</view> </view>
<!-- 库存预警 -->
<view class="alert-section" v-if="alertItems.length > 0">
<view class="alert-title">
<text class="iconfont icon-jinggao"></text>
<text>库存预警</text>
</view> </view>
<view class="alert-list">
<view class="alert-item" v-for="(item, index) in alertItems" :key="index">
<text class="item-name">{{ item.name }}</text>
<text class="item-stock">当前库存{{ item.stock }}</text>
<text class="item-min">最低库存{{ item.minStock }}</text>
</view> </view>
<!-- 排序菜单 -->
<view class="sort-menu" v-if="showSortMenu">
<view class="sort-item" @click="setSort('')"></view>
<view class="sort-item" @click="setSort('asc')"></view>
<view class="sort-item" @click="setSort('desc')"></view>
</view> </view>
</view> </view>
<!-- 库存列表 --> <!-- 库存列表 -->
<view class="stock-section"> <view class="stock-section">
<view class="stock-title">库存列表</view> <view class="stock-title">库存列表</view>
<view class="stock-list"> <view class="stock-list" v-if="stockItems.length > 0">
<view class="stock-item" v-for="(item, index) in stockItems" :key="index"> <view class="stock-item" v-for="(item, index) in stockItems" :key="index">
<view class="item-header"> <view class="item-header">
<text class="item-name">{{ item.name }}</text> <text class="item-name">{{ item.cargoName }}</text>
<text class="item-status" :class="item.stock <= item.minStock ? 'status-warning' : 'status-normal'">
{{ item.stock <= item.minStock ? '库存不足' : '库存正常' }}
</text>
</view> </view>
<view class="item-body"> <view class="item-body">
<view class="info-item"> <view class="info-item">
<text class="label">当前库存</text> <text class="label">商品编码</text>
<text class="value">{{ item.stock }}</text> <text class="value">{{ item.hsCode }}</text>
</view> </view>
<view class="info-item"> <view class="info-item">
<text class="label">最低库存</text> <text class="label">供应商</text>
<text class="value">{{ item.minStock }}</text> <text class="value">{{ item.custName }}</text>
</view> </view>
<view class="info-item"> <view class="info-item">
<text class="label">库存位置</text> <text class="label">库存数量</text>
<text class="value">{{ item.location }}</text> <text class="value">{{ item.cargoWt }}</text>
</view> </view>
<view class="info-item"> <view class="info-item">
<text class="label">物资类别</text> <text class="label">入库日期</text>
<text class="value">{{ item.category }}</text> <text class="value">{{ formatDate(item.stockDate) }}</text>
</view>
<view class="info-item">
<text class="label">最后更新</text>
<text class="value">{{ item.updateTime }}</text>
</view> </view>
</view> </view>
<view class="item-footer"> <view class="item-footer">
<view class="detail-btn" @click="viewStockDetail(item.id)"></view> <view class="detail-btn" @click="viewStockDetail(item)"></view>
</view>
</view> </view>
</view> </view>
<view class="empty-list" v-else>
<text>暂无库存数据</text>
</view> </view>
</view> </view>
</view> </view>
<!-- 日历组件 -->
<uni-calendar
ref="calendar"
:insert="false"
:range="false"
:start-date="'2020-01-01'"
:end-date="'2030-12-31'"
@confirm="confirm"
></uni-calendar>
</view> </view>
</template> </template>
<script> <script>
import { getStockList } from '@/api/stock';
export default { export default {
data() { data() {
return { return {
searchKeyword: '', sortOrder: '', // '''asc''desc'
selectedCategory: '', sortField: 'cargoWt', //
selectedLocation: '', sortText: '排序',
alertItems: [ sortIcon: 'icon-xiangxia',
{ id: 1, name: '有机蔬菜', stock: 20, minStock: 30, location: '仓库A区', category: '食材' }, showSortMenu: false,
{ id: 3, name: '肉类食材', stock: 15, minStock: 20, location: '冷库C区', category: '食材' } selectedDate: '',
], stockItems: [],
stockItems: [ loading: false,
{ id: 1, name: '有机蔬菜', stock: 20, minStock: 30, location: '仓库A区', category: '食材', updateTime: '2026-03-07 10:00' }, queryParams: {
{ id: 2, name: '新鲜水果', stock: 40, minStock: 25, location: '仓库B区', category: '食材', updateTime: '2026-03-07 09:30' }, pageNum: 1,
{ id: 3, name: '肉类食材', stock: 15, minStock: 20, location: '冷库C区', category: '食材', updateTime: '2026-03-06 18:00' }, pageSize: 10,
{ id: 4, name: '海鲜产品', stock: 25, minStock: 15, location: '冷库D区', category: '食材', updateTime: '2026-03-06 17:30' }, gdsSeqno: null,
{ id: 5, name: '维修耗材', stock: 50, minStock: 20, location: '仓库E区', category: '耗材', updateTime: '2026-03-05 14:00' }, stockDateStr: null,
{ id: 6, name: '办公用品', stock: 30, minStock: 15, location: '仓库F区', category: '办公', updateTime: '2026-03-05 13:30' } sortField: null,
] sortOrder: null
}
}; };
}, },
mounted() {
this.getStockList();
},
methods: { methods: {
searchStock() { //
uni.showToast({ formatDate(dateStr) {
title: '搜索功能开发中', if (!dateStr) return '';
icon: 'none' // 10
}); return dateStr.toString().substring(0, 10);
}, },
toggleFilter(type) { //
uni.showToast({ getStockList() {
title: '筛选功能开发中', this.loading = true;
icon: 'none' // API
getStockList(this.queryParams).then((res) => {
this.stockItems = res.data.list || [];
this.loading = false;
}).catch((err) => {
console.error('获取库存列表失败:', err);
this.loading = false;
}); });
}, },
viewStockDetail(id) { //
uni.showToast({ searchStock() {
title: '查看库存详情', this.queryParams.pageNum = 1;
icon: 'none' this.getStockList();
},
//
toggleSortMenu() {
this.showSortMenu = !this.showSortMenu;
if (this.showSortMenu) {
this.showDatePicker = false;
}
},
//
setSort(order) {
this.sortOrder = order;
if (order === '') {
this.sortText = '排序';
this.sortIcon = 'icon-xiangxia';
this.queryParams.sortField = null;
this.queryParams.sortOrder = null;
} else {
this.sortText = `库存数量${order === 'asc' ? '升序' : '降序'}`;
this.sortIcon = order === 'asc' ? 'icon-xiangshang' : 'icon-xiangxia';
this.queryParams.sortField = this.sortField;
this.queryParams.sortOrder = order;
}
this.showSortMenu = false;
this.getStockList();
},
//
openCalendar() {
this.$refs.calendar.open();
},
//
confirm(e) {
// console.log(e);
this.selectedDate = e.fulldate;
this.queryParams.stockDateStr = e.fulldate;
this.getStockList();
},
//
clearDate() {
this.selectedDate = '';
this.queryParams.stockDateStr = null;
this.getStockList();
},
//
viewStockDetail(item) {
uni.navigateTo({
url: `./detail?id=${item.id}&cargoId=${item.cargoId}&custId=${item.custId}`
}); });
} }
} }
@ -128,6 +191,7 @@ export default {
.search-section { .search-section {
margin-bottom: 30rpx; margin-bottom: 30rpx;
position: relative;
.search-box { .search-box {
display: flex; display: flex;
@ -167,6 +231,15 @@ export default {
border-radius: 20rpx; border-radius: 20rpx;
margin-right: 20rpx; margin-right: 20rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1); box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
cursor: pointer;
.date-picker-container {
display: flex;
align-items: center;
.date-text {
display: flex;
align-items: center;
text { text {
font-size: 24rpx; font-size: 24rpx;
@ -177,61 +250,63 @@ export default {
.iconfont { .iconfont {
font-size: 20rpx; font-size: 20rpx;
color: #666; color: #666;
} transition: transform 0.3s;
}
} }
} }
.alert-section { .clear-btn {
background-color: #FFF7E6; margin-right: 10rpx;
border-radius: 10rpx; padding: 5rpx;
padding: 20rpx;
margin-bottom: 30rpx;
border-left: 4rpx solid #FA8C16;
.alert-title {
display: flex;
align-items: center;
margin-bottom: 15rpx;
.iconfont { .iconfont {
font-size: 28rpx; font-size: 24rpx;
color: #FA8C16; color: #999;
margin-right: 10rpx;
&:hover {
color: #ff4d4f;
}
}
}
} }
text { text {
font-size: 26rpx; font-size: 24rpx;
font-weight: 600;
color: #333; color: #333;
margin-right: 10rpx;
}
.iconfont {
font-size: 20rpx;
color: #666;
transition: transform 0.3s;
}
} }
} }
.alert-list { //
.alert-item { .sort-menu {
display: flex; position: absolute;
align-items: center; top: 100%;
left: 0;
background-color: #fff; background-color: #fff;
border-radius: 8rpx; border-radius: 10rpx;
padding: 15rpx; box-shadow: 0 5rpx 15rpx rgba(0, 0, 0, 0.1);
margin-bottom: 10rpx; z-index: 100;
margin-top: 10rpx;
width: 200rpx;
.item-name { .sort-item {
flex: 1; padding: 15rpx 20rpx;
font-size: 24rpx; font-size: 24rpx;
color: #333; color: #333;
font-weight: 600; border-bottom: 1rpx solid #eee;
}
.item-stock { &:last-child {
font-size: 22rpx; border-bottom: none;
color: #FA8C16;
margin-right: 20rpx;
} }
.item-min { &:hover {
font-size: 22rpx; background-color: #f5f5f5;
color: #666;
} }
} }
} }
@ -256,7 +331,6 @@ export default {
.item-header { .item-header {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between;
margin-bottom: 15rpx; margin-bottom: 15rpx;
.item-name { .item-name {
@ -264,22 +338,6 @@ export default {
font-weight: 600; font-weight: 600;
color: #333; color: #333;
} }
.item-status {
padding: 5rpx 15rpx;
border-radius: 15rpx;
font-size: 20rpx;
}
.status-warning {
background-color: #FFF7E6;
color: #FA8C16;
}
.status-normal {
background-color: #F6FFED;
color: #52C41A;
}
} }
.item-body { .item-body {
@ -290,7 +348,7 @@ export default {
margin-bottom: 10rpx; margin-bottom: 10rpx;
.label { .label {
width: 120rpx; width: 140rpx;
font-size: 24rpx; font-size: 24rpx;
color: #666; color: #666;
} }
@ -317,7 +375,23 @@ export default {
} }
} }
} }
.empty-list {
display: flex;
align-items: center;
justify-content: center;
height: 200rpx;
background-color: #f5f5f5;
border-radius: 10rpx;
text {
font-size: 24rpx;
color: #999;
}
}
} }
} }
} }
</style> </style>

@ -0,0 +1,30 @@
## 1.4.122024-09-21
- 修复 calendar在选择日期范围后重新选择日期需要点两次的Bug
## 1.4.112024-01-10
- 修复 回到今天时,月份显示不一致问题
## 1.4.102023-04-10
- 修复 某些情况 monthSwitch 未触发的Bug
## 1.4.92023-02-02
- 修复 某些情况切换月份错误的Bug
## 1.4.82023-01-30
- 修复 某些情况切换月份错误的Bug [详情](https://ask.dcloud.net.cn/question/161964)
## 1.4.72022-09-16
- 优化 支持使用 uni-scss 控制主题色
## 1.4.62022-09-08
- 修复 表头年月切换导致改变当前日期为选择月1号且未触发change事件的Bug
## 1.4.52022-02-25
- 修复 条件编译 nvue 不支持的 css 样式的Bug
## 1.4.42022-02-25
- 修复 条件编译 nvue 不支持的 css 样式的Bug
## 1.4.32021-09-22
- 修复 startDate、 endDate 属性失效的Bug
## 1.4.22021-08-24
- 新增 支持国际化
## 1.4.12021-08-05
- 修复 弹出层被 tabbar 遮盖的Bug
## 1.4.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.3.162021-05-12
- 新增 组件示例地址
## 1.3.152021-02-04
- 调整为uni_modules目录规范

@ -351,10 +351,8 @@ var calendar = {
s = '\u521d\u5341'; break s = '\u521d\u5341'; break
case 20: case 20:
s = '\u4e8c\u5341'; break s = '\u4e8c\u5341'; break
break
case 30: case 30:
s = '\u4e09\u5341'; break s = '\u4e09\u5341'; break
break
default : default :
s = this.nStr2[Math.floor(d / 10)] s = this.nStr2[Math.floor(d / 10)]
s += this.nStr1[d % 10] s += this.nStr1[d % 10]

@ -0,0 +1,12 @@
{
"uni-calender.ok": "ok",
"uni-calender.cancel": "cancel",
"uni-calender.today": "today",
"uni-calender.MON": "MON",
"uni-calender.TUE": "TUE",
"uni-calender.WED": "WED",
"uni-calender.THU": "THU",
"uni-calender.FRI": "FRI",
"uni-calender.SAT": "SAT",
"uni-calender.SUN": "SUN"
}

@ -0,0 +1,8 @@
import en from './en.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
en,
'zh-Hans': zhHans,
'zh-Hant': zhHant
}

@ -0,0 +1,12 @@
{
"uni-calender.ok": "确定",
"uni-calender.cancel": "取消",
"uni-calender.today": "今日",
"uni-calender.SUN": "日",
"uni-calender.MON": "一",
"uni-calender.TUE": "二",
"uni-calender.WED": "三",
"uni-calender.THU": "四",
"uni-calender.FRI": "五",
"uni-calender.SAT": "六"
}

@ -0,0 +1,12 @@
{
"uni-calender.ok": "確定",
"uni-calender.cancel": "取消",
"uni-calender.today": "今日",
"uni-calender.SUN": "日",
"uni-calender.MON": "一",
"uni-calender.TUE": "二",
"uni-calender.WED": "三",
"uni-calender.THU": "四",
"uni-calender.FRI": "五",
"uni-calender.SAT": "六"
}

@ -3,7 +3,9 @@
'uni-calendar-item--disable':weeks.disable, 'uni-calendar-item--disable':weeks.disable,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay, 'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':(calendar.fullDate === weeks.fullDate && !weeks.isDay) , 'uni-calendar-item--checked':(calendar.fullDate === weeks.fullDate && !weeks.isDay) ,
'uni-calendar-item--multiple': weeks.multiple 'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
}" }"
@click="choiceDate(weeks)"> @click="choiceDate(weeks)">
<view class="uni-calendar-item__weeks-box-item"> <view class="uni-calendar-item__weeks-box-item">
@ -12,28 +14,36 @@
'uni-calendar-item--isDay-text': weeks.isDay, 'uni-calendar-item--isDay-text': weeks.isDay,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay, 'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay, 'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple, 'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
'uni-calendar-item--disable':weeks.disable, 'uni-calendar-item--disable':weeks.disable,
}">{{weeks.date}}</text> }">{{weeks.date}}</text>
<text v-if="!lunar&&!weeks.extraInfo && weeks.isDay" class="uni-calendar-item__weeks-lunar-text" :class="{ <text v-if="!lunar&&!weeks.extraInfo && weeks.isDay" class="uni-calendar-item__weeks-lunar-text" :class="{
'uni-calendar-item--isDay-text':weeks.isDay, 'uni-calendar-item--isDay-text':weeks.isDay,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay, 'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay, 'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple, 'uni-calendar-item--multiple': weeks.multiple,
}">今天</text> 'uni-calendar-item--after-checked':weeks.afterMultiple,
}">{{todayText}}</text>
<text v-if="lunar&&!weeks.extraInfo" class="uni-calendar-item__weeks-lunar-text" :class="{ <text v-if="lunar&&!weeks.extraInfo" class="uni-calendar-item__weeks-lunar-text" :class="{
'uni-calendar-item--isDay-text':weeks.isDay, 'uni-calendar-item--isDay-text':weeks.isDay,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay, 'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay, 'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple, 'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
'uni-calendar-item--disable':weeks.disable, 'uni-calendar-item--disable':weeks.disable,
}">{{weeks.isDay?'今天': (weeks.lunar.IDayCn === '初一'?weeks.lunar.IMonthCn:weeks.lunar.IDayCn)}}</text> }">{{weeks.isDay ? todayText : (weeks.lunar.IDayCn === '初一'?weeks.lunar.IMonthCn:weeks.lunar.IDayCn)}}</text>
<text v-if="weeks.extraInfo&&weeks.extraInfo.info" class="uni-calendar-item__weeks-lunar-text" :class="{ <text v-if="weeks.extraInfo&&weeks.extraInfo.info" class="uni-calendar-item__weeks-lunar-text" :class="{
'uni-calendar-item--extra':weeks.extraInfo.info, 'uni-calendar-item--extra':weeks.extraInfo.info,
'uni-calendar-item--isDay-text':weeks.isDay, 'uni-calendar-item--isDay-text':weeks.isDay,
'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay, 'uni-calendar-item--isDay':calendar.fullDate === weeks.fullDate && weeks.isDay,
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay, 'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && !weeks.isDay,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple, 'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
'uni-calendar-item--disable':weeks.disable, 'uni-calendar-item--disable':weeks.disable,
}">{{weeks.extraInfo.info}}</text> }">{{weeks.extraInfo.info}}</text>
</view> </view>
@ -41,7 +51,12 @@
</template> </template>
<script> <script>
import { initVueI18n } from '@dcloudio/uni-i18n'
import i18nMessages from './i18n/index.js'
const { t } = initVueI18n(i18nMessages)
export default { export default {
emits:['change'],
props: { props: {
weeks: { weeks: {
type: Object, type: Object,
@ -66,6 +81,11 @@
default: false default: false
} }
}, },
computed: {
todayText() {
return t("uni-calender.today")
},
},
methods: { methods: {
choiceDate(weeks) { choiceDate(weeks) {
this.$emit('change', weeks) this.$emit('change', weeks)
@ -75,6 +95,13 @@
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
$uni-font-size-base:14px;
$uni-text-color:#333;
$uni-font-size-sm:12px;
$uni-color-error: #e43d33;
$uni-opacity-disabled: 0.3;
$uni-text-color-disable:#c0c0c0;
$uni-primary: #2979ff !default;
.uni-calendar-item__weeks-box { .uni-calendar-item__weeks-box {
flex: 1; flex: 1;
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
@ -124,11 +151,11 @@
} }
.uni-calendar-item--isDay-text { .uni-calendar-item--isDay-text {
color: $uni-color-primary; color: $uni-primary;
} }
.uni-calendar-item--isDay { .uni-calendar-item--isDay {
background-color: $uni-color-primary; background-color: $uni-primary;
opacity: 0.8; opacity: 0.8;
color: #fff; color: #fff;
} }
@ -139,14 +166,22 @@
} }
.uni-calendar-item--checked { .uni-calendar-item--checked {
background-color: $uni-color-primary; background-color: $uni-primary;
color: #fff; color: #fff;
opacity: 0.8; opacity: 0.8;
} }
.uni-calendar-item--multiple { .uni-calendar-item--multiple {
background-color: $uni-color-primary; background-color: $uni-primary;
color: #fff; color: #fff;
opacity: 0.8; opacity: 0.8;
} }
.uni-calendar-item--before-checked {
background-color: #ff5a5f;
color: #fff;
}
.uni-calendar-item--after-checked {
background-color: #ff5a5f;
color: #fff;
}
</style> </style>

@ -1,24 +1,27 @@
<template> <template>
<view class="uni-calendar" @touchmove.stop.prevent="clean"> <view class="uni-calendar">
<view v-if="!insert&&show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}" @click="clean"></view> <view v-if="!insert&&show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}" @click="clean"></view>
<view v-if="insert || show" class="uni-calendar__content" :class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow}"> <view v-if="insert || show" class="uni-calendar__content" :class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow}">
<view v-if="!insert" class="uni-calendar__header uni-calendar--fixed-top"> <view v-if="!insert" class="uni-calendar__header uni-calendar--fixed-top">
<view class="uni-calendar__header-btn-box" @click="close"> <view class="uni-calendar__header-btn-box" @click="close">
<text class="uni-calendar__header-text uni-calendar--fixed-width">取消</text> <text class="uni-calendar__header-text uni-calendar--fixed-width">{{cancelText}}</text>
</view> </view>
<view class="uni-calendar__header-btn-box" @click="confirm"> <view class="uni-calendar__header-btn-box" @click="confirm">
<text class="uni-calendar__header-text uni-calendar--fixed-width">确定</text> <text class="uni-calendar__header-text uni-calendar--fixed-width">{{okText}}</text>
</view> </view>
</view> </view>
<view class="uni-calendar__header"> <view class="uni-calendar__header">
<view class="uni-calendar__header-btn-box" @click="pre"> <view class="uni-calendar__header-btn-box" @click.stop="pre">
<view class="uni-calendar__header-btn uni-calendar--left"></view> <view class="uni-calendar__header-btn uni-calendar--left"></view>
</view> </view>
<text class="uni-calendar__header-text">{{ (nowDate.year||'') +'年'+( nowDate.month||'') +'月'}}</text> <picker mode="date" :value="date" fields="month" @change="bindDateChange">
<view class="uni-calendar__header-btn-box" @click="next"> <text class="uni-calendar__header-text">{{ (nowDate.year||'') +' / '+( nowDate.month||'')}}</text>
</picker>
<view class="uni-calendar__header-btn-box" @click.stop="next">
<view class="uni-calendar__header-btn uni-calendar--right"></view> <view class="uni-calendar__header-btn uni-calendar--right"></view>
</view> </view>
<text class="uni-calendar__backtoday" @click="backtoday"></text> <text class="uni-calendar__backtoday" @click="backToday">{{todayText}}</text>
</view> </view>
<view class="uni-calendar__box"> <view class="uni-calendar__box">
<view v-if="showMonth" class="uni-calendar__box-bg"> <view v-if="showMonth" class="uni-calendar__box-bg">
@ -26,30 +29,30 @@
</view> </view>
<view class="uni-calendar__weeks"> <view class="uni-calendar__weeks">
<view class="uni-calendar__weeks-day"> <view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text"></text> <text class="uni-calendar__weeks-day-text">{{SUNText}}</text>
</view> </view>
<view class="uni-calendar__weeks-day"> <view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text"></text> <text class="uni-calendar__weeks-day-text">{{monText}}</text>
</view> </view>
<view class="uni-calendar__weeks-day"> <view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text"></text> <text class="uni-calendar__weeks-day-text">{{TUEText}}</text>
</view> </view>
<view class="uni-calendar__weeks-day"> <view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text"></text> <text class="uni-calendar__weeks-day-text">{{WEDText}}</text>
</view> </view>
<view class="uni-calendar__weeks-day"> <view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text"></text> <text class="uni-calendar__weeks-day-text">{{THUText}}</text>
</view> </view>
<view class="uni-calendar__weeks-day"> <view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text"></text> <text class="uni-calendar__weeks-day-text">{{FRIText}}</text>
</view> </view>
<view class="uni-calendar__weeks-day"> <view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text"></text> <text class="uni-calendar__weeks-day-text">{{SATText}}</text>
</view> </view>
</view> </view>
<view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex"> <view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
<view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex"> <view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
<uni-calendar-item :weeks="weeks" :calendar="calendar" :selected="selected" :lunar="lunar" @change="choiceDate"></uni-calendar-item> <calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar" :selected="selected" :lunar="lunar" @change="choiceDate"></calendar-item>
</view> </view>
</view> </view>
</view> </view>
@ -59,69 +62,75 @@
<script> <script>
import Calendar from './util.js'; import Calendar from './util.js';
import uniCalendarItem from './uni-calendar-item.vue' import CalendarItem from './uni-calendar-item.vue'
import { initVueI18n } from '@dcloudio/uni-i18n'
import i18nMessages from './i18n/index.js'
const { t } = initVueI18n(i18nMessages)
/**
* Calendar 日历
* @description 日历组件可以查看日期选择任意范围内的日期打点操作常用场景如酒店日期预订火车机票选择购买日期上下班打卡等
* @tutorial https://ext.dcloud.net.cn/plugin?id=56
* @property {String} date 自定义当前时间默认为今天
* @property {Boolean} lunar 显示农历
* @property {String} startDate 日期选择范围-开始日期
* @property {String} endDate 日期选择范围-结束日期
* @property {Boolean} range 范围选择
* @property {Boolean} insert = [true|false] 插入模式,默认为false
* @value true 弹窗模式
* @value false 插入模式
* @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容
* @property {Array} selected 打点期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]
* @property {Boolean} showMonth 是否选择月份为背景
* @event {Function} change 日期改变`insert :ture` 时生效
* @event {Function} confirm 确认选择`insert :false` 时生效
* @event {Function} monthSwitch 切换月份时触发
* @example <uni-calendar :insert="true":lunar="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
*/
export default { export default {
components: { components: {
uniCalendarItem CalendarItem
}, },
emits:['close','confirm','change','monthSwitch'],
props: { props: {
/**
* 当前日期
*/
date: { date: {
type: String, type: String,
default: '' default: ''
}, },
/**
* 打点日期
*/
selected: { selected: {
type: Array, type: Array,
default () { default () {
return [] return []
} }
}, },
/**
* 是否开启阴历日期
*/
lunar: { lunar: {
type: Boolean, type: Boolean,
default: false default: false
}, },
/**
* 开始时间
*/
startDate: { startDate: {
type: String, type: String,
default: '' default: ''
}, },
/**
* 结束时间
*/
endDate: { endDate: {
type: String, type: String,
default: '' default: ''
}, },
/**
* 范围
*/
range: { range: {
type: Boolean, type: Boolean,
default: false default: false
}, },
/**
* 插入
*/
insert: { insert: {
type: Boolean, type: Boolean,
default: true default: true
}, },
/**
* 是否显示月份背景
*/
showMonth: { showMonth: {
type: Boolean, type: Boolean,
default: true default: true
},
clearDate: {
type: Boolean,
default: true
} }
}, },
data() { data() {
@ -133,54 +142,139 @@
aniMaskShow: false aniMaskShow: false
} }
}, },
computed:{
/**
* for i18n
*/
okText() {
return t("uni-calender.ok")
},
cancelText() {
return t("uni-calender.cancel")
},
todayText() {
return t("uni-calender.today")
},
monText() {
return t("uni-calender.MON")
},
TUEText() {
return t("uni-calender.TUE")
},
WEDText() {
return t("uni-calender.WED")
},
THUText() {
return t("uni-calender.THU")
},
FRIText() {
return t("uni-calender.FRI")
},
SATText() {
return t("uni-calender.SAT")
},
SUNText() {
return t("uni-calender.SUN")
},
},
watch: { watch: {
date(newVal) {
// this.cale.setDate(newVal)
this.init(newVal)
},
startDate(val){
this.cale.resetSatrtDate(val)
this.cale.setDate(this.nowDate.fullDate)
this.weeks = this.cale.weeks
},
endDate(val){
this.cale.resetEndDate(val)
this.cale.setDate(this.nowDate.fullDate)
this.weeks = this.cale.weeks
},
selected(newVal) { selected(newVal) {
this.cale.setSelectInfo(this.nowDate.fullDate, newVal) this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
this.weeks = this.cale.weeks this.weeks = this.cale.weeks
} }
}, },
created() { created() {
//
this.cale = new Calendar({ this.cale = new Calendar({
date: this.date,
selected: this.selected, selected: this.selected,
startDate: this.startDate, startDate: this.startDate,
endDate: this.endDate, endDate: this.endDate,
range: this.range, range: this.range,
}) })
this.init(this.cale.date.fullDate) this.init(this.date)
}, },
methods: { methods: {
// 穿 // 穿
clean() {}, clean() {},
bindDateChange(e) {
const value = e.detail.value + '-1'
this.setDate(value)
const { year,month } = this.cale.getDate(value)
this.$emit('monthSwitch', {
year,
month
})
},
/**
* 初始化日期显示
* @param {Object} date
*/
init(date) { init(date) {
this.cale.setDate(date)
this.weeks = this.cale.weeks this.weeks = this.cale.weeks
this.nowDate = this.calendar = this.cale.getInfo(date) this.nowDate = this.calendar = this.cale.getInfo(date)
}, },
/**
* 打开日历弹窗
*/
open() { open() {
//
if (this.clearDate && !this.insert) {
this.cale.cleanMultipleStatus()
// this.cale.setDate(this.date)
this.init(this.date)
}
this.show = true this.show = true
this.$nextTick(() => { this.$nextTick(() => {
setTimeout(()=>{ setTimeout(() => {
this.aniMaskShow = true this.aniMaskShow = true
},50) }, 50)
}) })
}, },
/**
* 关闭日历弹窗
*/
close() { close() {
this.aniMaskShow = false this.aniMaskShow = false
this.$nextTick(() => { this.$nextTick(() => {
setTimeout(() => { setTimeout(() => {
this.show = false this.show = false
this.$emit('close')
}, 300) }, 300)
}) })
}, },
/**
* 确认按钮
*/
confirm() { confirm() {
this.setEmit('confirm') this.setEmit('confirm')
this.close() this.close()
}, },
/**
* 变化触发
*/
change() { change() {
if (!this.insert) return if (!this.insert) return
this.setEmit('change') this.setEmit('change')
}, },
/**
* 选择月份触发
*/
monthSwitch() { monthSwitch() {
let { let {
year, year,
@ -191,6 +285,10 @@
month: Number(month) month: Number(month)
}) })
}, },
/**
* 派发事件
* @param {Object} name
*/
setEmit(name) { setEmit(name) {
let { let {
year, year,
@ -210,6 +308,10 @@
extraInfo: extraInfo || {} extraInfo: extraInfo || {}
}) })
}, },
/**
* 选择天触发
* @param {Object} weeks
*/
choiceDate(weeks) { choiceDate(weeks) {
if (weeks.disable) return if (weeks.disable) return
this.calendar = weeks this.calendar = weeks
@ -218,23 +320,43 @@
this.weeks = this.cale.weeks this.weeks = this.cale.weeks
this.change() this.change()
}, },
backtoday() { /**
this.cale.setDate(this.date) * 回到今天
this.weeks = this.cale.weeks */
this.nowDate = this.calendar = this.cale.getInfo(this.date) backToday() {
const nowYearMonth = `${this.nowDate.year}-${this.nowDate.month}`
const date = this.cale.getDate(new Date())
const todayYearMonth = `${date.year}-${date.month}`
this.init(date.fullDate)
if(nowYearMonth !== todayYearMonth) {
this.monthSwitch()
}
this.change() this.change()
}, },
/**
* 上个月
*/
pre() { pre() {
const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate
this.setDate(preDate) this.setDate(preDate)
this.monthSwitch() this.monthSwitch()
}, },
/**
* 下个月
*/
next() { next() {
const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate
this.setDate(nextDate) this.setDate(nextDate)
this.monthSwitch() this.monthSwitch()
}, },
/**
* 设置日期
* @param {Object} date
*/
setDate(date) { setDate(date) {
this.cale.setDate(date) this.cale.setDate(date)
this.weeks = this.cale.weeks this.weeks = this.cale.weeks
@ -245,6 +367,14 @@
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
$uni-bg-color-mask: rgba($color: #000000, $alpha: 0.4);
$uni-border-color: #EDEDED;
$uni-text-color: #333;
$uni-bg-color-hover:#f1f1f1;
$uni-font-size-base:14px;
$uni-text-color-placeholder: #808080;
$uni-color-subtitle: #555555;
$uni-text-color-grey:#999;
.uni-calendar { .uni-calendar {
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
display: flex; display: flex;
@ -273,13 +403,16 @@
.uni-calendar--fixed { .uni-calendar--fixed {
position: fixed; position: fixed;
/* #ifdef APP-NVUE */
bottom: 0; bottom: 0;
/* #endif */
left: 0; left: 0;
right: 0; right: 0;
transition-property: transform; transition-property: transform;
transition-duration: 0.3s; transition-duration: 0.3s;
transform: translateY(460px); transform: translateY(460px);
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
bottom: calc(var(--window-bottom));
z-index: 99; z-index: 99;
/* #endif */ /* #endif */
} }
@ -319,7 +452,6 @@
.uni-calendar--fixed-width { .uni-calendar--fixed-width {
width: 50px; width: 50px;
// padding: 0 15px;
} }
.uni-calendar__backtoday { .uni-calendar__backtoday {
@ -400,6 +532,7 @@
border-bottom-style: solid; border-bottom-style: solid;
border-bottom-width: 1px; border-bottom-width: 1px;
} }
.uni-calendar__weeks-day-text { .uni-calendar__weeks-day-text {
font-size: 14px; font-size: 14px;
} }

@ -9,7 +9,7 @@ class Calendar {
range range
} = {}) { } = {}) {
// 当前日期 // 当前日期
this.date = this.getDate(date) // 当前初入日期 this.date = this.getDate(new Date()) // 当前初入日期
// 打点信息 // 打点信息
this.selected = selected || []; this.selected = selected || [];
// 范围开始 // 范围开始
@ -18,15 +18,46 @@ class Calendar {
this.endDate = endDate this.endDate = endDate
this.range = range this.range = range
// 多选状态 // 多选状态
this.cleanMultipleStatus()
// 每周日期
this.weeks = {}
// this._getWeek(this.date.fullDate)
}
/**
* 设置日期
* @param {Object} date
*/
setDate(date) {
this.selectDate = this.getDate(date)
this._getWeek(this.selectDate.fullDate)
}
/**
* 清理多选状态
*/
cleanMultipleStatus() {
this.multipleStatus = { this.multipleStatus = {
before: '', before: '',
after: '', after: '',
data: [] data: []
} }
// 每周日期 }
this.weeks = {}
/**
* 重置开始日期
*/
resetSatrtDate(startDate) {
// 范围开始
this.startDate = startDate
this._getWeek(this.date.fullDate) }
/**
* 重置结束日期
*/
resetEndDate(endDate) {
// 范围结束
this.endDate = endDate
} }
/** /**
@ -45,10 +76,20 @@ class Calendar {
dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期 dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
break break
case 'month': case 'month':
if (dd.getDate() === 31) { if (dd.getDate() === 31 && AddDayCount>0) {
dd.setDate(dd.getDate() + AddDayCount) dd.setDate(dd.getDate() + AddDayCount)
} else { } else {
dd.setMonth(dd.getMonth() + AddDayCount) // 获取AddDayCount天后的日期 const preMonth = dd.getMonth()
dd.setMonth(preMonth + AddDayCount) // 获取AddDayCount天后的日期
const nextMonth = dd.getMonth()
// 处理 pre 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
if(AddDayCount<0 && preMonth!==0 && nextMonth-preMonth>AddDayCount){
dd.setMonth(nextMonth+(nextMonth-preMonth+AddDayCount))
}
// 处理 next 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
if(AddDayCount>0 && nextMonth-preMonth>AddDayCount){
dd.setMonth(nextMonth-(nextMonth-preMonth-AddDayCount))
}
} }
break break
case 'year': case 'year':
@ -91,7 +132,6 @@ class Calendar {
let dateArr = [] let dateArr = []
let fullDate = this.date.fullDate let fullDate = this.date.fullDate
for (let i = 1; i <= dateData; i++) { for (let i = 1; i <= dateData; i++) {
let isinfo = false
let nowDate = full.year + '-' + (full.month < 10 ? let nowDate = full.year + '-' + (full.month < 10 ?
full.month : full.month) + '-' + (i < 10 ? full.month : full.month) + '-' + (i < 10 ?
'0' + i : i) '0' + i : i)
@ -108,15 +148,16 @@ class Calendar {
let disableBefore = true let disableBefore = true
let disableAfter = true let disableAfter = true
if (this.startDate) { if (this.startDate) {
let dateCompBefore = this.dateCompare(this.startDate, fullDate) // let dateCompBefore = this.dateCompare(this.startDate, fullDate)
disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate) // disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
disableBefore = this.dateCompare(this.startDate, nowDate)
} }
if (this.endDate) { if (this.endDate) {
let dateCompAfter = this.dateCompare(fullDate, this.endDate) // let dateCompAfter = this.dateCompare(fullDate, this.endDate)
disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate) // disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
disableAfter = this.dateCompare(nowDate, this.endDate)
} }
let multiples = this.multipleStatus.data let multiples = this.multipleStatus.data
let checked = false let checked = false
let multiplesStatus = -1 let multiplesStatus = -1
@ -130,15 +171,16 @@ class Calendar {
checked = true checked = true
} }
} }
let data = { let data = {
fullDate: nowDate, fullDate: nowDate,
year: full.year, year: full.year,
date: i, date: i,
multiple: this.range ? checked : false, multiple: this.range ? checked : false,
beforeMultiple: this.dateEqual(this.multipleStatus.before, nowDate),
afterMultiple: this.dateEqual(this.multipleStatus.after, nowDate),
month: full.month, month: full.month,
lunar: this.getlunar(full.year, full.month, i), lunar: this.getlunar(full.year, full.month, i),
disable: !disableBefore || !disableAfter, disable: !(disableBefore && disableAfter),
isDay isDay
} }
if (info) { if (info) {
@ -164,13 +206,7 @@ class Calendar {
} }
return dateArr return dateArr
} }
/**
* 设置日期
* @param {Object} date
*/
setDate(date) {
this._getWeek(date)
}
/** /**
* 获取当前日期详情 * 获取当前日期详情
* @param {Object} date * @param {Object} date
@ -257,12 +293,12 @@ class Calendar {
before, before,
after after
} = this.multipleStatus } = this.multipleStatus
if (!this.range) return if (!this.range) return
if (before && after) { if (before && after) {
this.multipleStatus.before = '' this.multipleStatus.before = fullDate
this.multipleStatus.after = '' this.multipleStatus.after = ''
this.multipleStatus.data = [] this.multipleStatus.data = []
this._getWeek(fullDate)
} else { } else {
if (!before) { if (!before) {
this.multipleStatus.before = fullDate this.multipleStatus.before = fullDate
@ -273,9 +309,9 @@ class Calendar {
} else { } else {
this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before); this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
} }
this._getWeek(fullDate)
} }
} }
this._getWeek(fullDate)
} }
/** /**
@ -284,11 +320,8 @@ class Calendar {
*/ */
_getWeek(dateData) { _getWeek(dateData) {
const { const {
fullDate,
year, year,
month, month
date,
day
} = this.getDate(dateData) } = this.getDate(dateData)
let firstDay = new Date(year, month - 1, 1).getDay() let firstDay = new Date(year, month - 1, 1).getDay()
let currentDay = new Date(year, month, 0).getDate() let currentDay = new Date(year, month, 0).getDate()

@ -0,0 +1,86 @@
{
"id": "uni-calendar",
"displayName": "uni-calendar 日历",
"version": "1.4.12",
"description": "日历组件",
"keywords": [
"uni-ui",
"uniui",
"日历",
"",
"打卡",
"日历选择"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y",
"alipay": "n"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

@ -0,0 +1,103 @@
## Calendar 日历
> **组件名uni-calendar**
> 代码块: `uCalendar`
日历组件
> **注意事项**
> 为了避免错误使用,给大家带来不好的开发体验,请在使用组件前仔细阅读下面的注意事项,可以帮你避免一些错误。
> - 本组件农历转换使用的js是 [@1900-2100区间内的公历、农历互转](https://github.com/jjonline/calendar.js)
> - 仅支持自定义组件模式
> - `date`属性传入的应该是一个 String ,如: 2019-06-27 ,而不是 new Date()
> - 通过 `insert` 属性来确定当前的事件是 @change 还是 @confirm 。理应合并为一个事件,但是为了区分模式,现使用两个事件,这里需要注意
> - 弹窗模式下无法阻止后面的元素滚动,如有需要阻止,请在弹窗弹出后,手动设置滚动元素为不可滚动
### 安装方式
本组件符合[easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)规范,`HBuilderX 2.5.5`起,只需将本组件导入项目,在页面`template`中即可直接使用,无需在页面中`import`和注册`components`。
如需通过`npm`方式使用`uni-ui`组件,另见文档:[https://ext.dcloud.net.cn/plugin?id=55](https://ext.dcloud.net.cn/plugin?id=55)
### 基本用法
在 ``template`` 中使用组件
```html
<view>
<uni-calendar
:insert="true"
:lunar="true"
:start-date="'2019-3-2'"
:end-date="'2019-5-20'"
@change="change"
/>
</view>
```
### 通过方法打开日历
需要设置 `insert``false`
```html
<view>
<uni-calendar
ref="calendar"
:insert="false"
@confirm="confirm"
/>
<button @click="open">打开日历</button>
</view>
```
```javascript
export default {
data() {
return {};
},
methods: {
open(){
this.$refs.calendar.open();
},
confirm(e) {
console.log(e);
}
}
};
```
## API
### Calendar Props
| 属性名 | 类型 | 默认值| 说明 |
| - | - | - | - |
| date | String |- | 自定义当前时间,默认为今天 |
| lunar | Boolean | false | 显示农历 |
| startDate | String |- | 日期选择范围-开始日期 |
| endDate | String |- | 日期选择范围-结束日期 |
| range | Boolean | false | 范围选择 |
| insert | Boolean | false | 插入模式,可选值ture插入模式false弹窗模式默认为插入模式 |
|clearDate |Boolean |true |弹窗模式是否清空上次选择内容 |
| selected | Array |- | 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}] |
|showMonth | Boolean | true | 是否显示月份为背景 |
### Calendar Events
| 事件名 | 说明 |返回值|
| - | - | - |
| open | 弹出日历组件,`insert :false` 时生效|- |
## 组件示例
点击查看:[https://hellouniapp.dcloud.net.cn/pages/extUI/calendar/calendar](https://hellouniapp.dcloud.net.cn/pages/extUI/calendar/calendar)
Loading…
Cancel
Save