协同宣发
352
src/apps/AppCooperationPropaganda/AppCooperationPropaganda.vue
Normal file
@@ -0,0 +1,352 @@
|
||||
<template>
|
||||
<div class="AppCooperationPropaganda">
|
||||
<AiTopFixed>
|
||||
<div class="search">
|
||||
<div class="searchBox">
|
||||
<u-search placeholder="请输入任务名称" v-model="taskTitle" clearabled @search="searchBtn" @clear="taskTitle='',getList()" :show-action="false"></u-search>
|
||||
</div>
|
||||
<div class="filterBtn" @click="filterShow = true"><img src="./images/shaixuan.png" alt="">筛选</div>
|
||||
</div>
|
||||
</AiTopFixed>
|
||||
<div class="resident_list" v-if="list.length">
|
||||
<div class="card" @click="toDetail(item)" v-for="(item,index) in list" :key="index">
|
||||
<div class="card_title">
|
||||
<div class="card_left">{{ item.taskTitle }}</div>
|
||||
<div class="card_right"><span :class="item.status==0? 'status0': item.status==1? 'status1': item.status==2? 'status2':
|
||||
item.status == 3? 'status3':item.status==4? 'status4': 'status5'"></span>{{ $dict.getLabel('mstStatus', item.status) }}</div>
|
||||
</div>
|
||||
<div>群发时间:<span>{{ item.choiceTime }}</span></div>
|
||||
<div>共需<span class="num">{{ item.groupOwnerCount || 0 }}</span>名成员完成群发,目前已完成<span class="num">{{ item.completionRate || 0 }}%</span></div>
|
||||
<div>
|
||||
创建部门:
|
||||
<span v-if="item.createUserDeptName">{{ item.createUserDeptName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<AiEmpty description="暂无数据" v-if="!list.length"/>
|
||||
<u-popup v-model="filterShow" mode="bottom" border-radius="14">
|
||||
<div class="popup">
|
||||
<div class="tips"></div>
|
||||
<div class="title">
|
||||
<div
|
||||
class="cancel"
|
||||
@click.stop="(filterShow = false), (timeSelect = 0)"
|
||||
>
|
||||
取消
|
||||
</div>
|
||||
<p>筛选条件</p>
|
||||
<div class="confirm" @click.stop="selectConfirm">确定</div>
|
||||
</div>
|
||||
<scroll-view class="select-content" scroll-y="true">
|
||||
<div class="type-list">
|
||||
<div class="type-title">创建人</div>
|
||||
<AiPagePicker type="custom" :selected.sync="userIdList" nodeKey="createUserId" :ops="{url:`./selectUser`,label: 'id'}">
|
||||
<div class="page_picker">
|
||||
<span class="label" v-if="userIdList.length">已选择</span>
|
||||
<span v-else style="color:#999;">请选择</span>
|
||||
<u-icon name="arrow-right" color="#303133" size="24" style="margin-left:8px;"/>
|
||||
</div>
|
||||
</AiPagePicker>
|
||||
</div>
|
||||
<div class="type-list">
|
||||
<div class="type-title">群发时间</div>
|
||||
<div class="item">
|
||||
<div>开始时间</div>
|
||||
<div style="display: flex;">
|
||||
<u-input v-model="startTime" disabled placeholder="请选择开始时间" @click="showStart = true" />
|
||||
<u-icon name="arrow-right"></u-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div>结束时间</div>
|
||||
<div style="display: flex;">
|
||||
<u-input v-model="endTime" disabled placeholder="请选择结束时间" @click="showEnd = true" />
|
||||
<u-icon name="arrow-right"></u-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</scroll-view>
|
||||
<u-picker mode="time" v-model="showStart" @confirm="confirmStart"></u-picker>
|
||||
<u-picker mode="time" v-model="showEnd" @confirm="confirmEnd"></u-picker>
|
||||
<div class="popBtn">
|
||||
<div @click="reset">重置</div>
|
||||
<div @click="selectConfirm">确认</div>
|
||||
</div>
|
||||
</div>
|
||||
</u-popup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'AppCooperationPropaganda',
|
||||
appName: '协同宣发',
|
||||
data() {
|
||||
return {
|
||||
current: 1,
|
||||
name: '',
|
||||
list: [],
|
||||
filterShow: false,
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
start: "",
|
||||
end: "",
|
||||
showStart: false,
|
||||
showEnd: false,
|
||||
taskTitle: '',
|
||||
createUserId: '',
|
||||
userList: [],
|
||||
userIdList: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toDetail(item) {
|
||||
uni.navigateTo({url: `./cooperationDetail?id=${item.id}&time=${item.createTime}`})
|
||||
},
|
||||
searchBtn() {
|
||||
this.current = 1
|
||||
this.list = [],
|
||||
this.getList()
|
||||
},
|
||||
getList() {
|
||||
this.$http.post(`/app/appmasssendingtask/list`, null, {
|
||||
params: {
|
||||
current: this.current,
|
||||
taskTitle: this.taskTitle,
|
||||
startTime: this.start,
|
||||
endTime: this.end,
|
||||
createUserId: this.createUserId,
|
||||
}
|
||||
}).then(res=> {
|
||||
if(res?.data) {
|
||||
this.list = this.current == 1? res.data.records : [...this.list,...res.data.records]
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
reset() {
|
||||
this.start = '',
|
||||
this.end = '',
|
||||
this.startTime = '',
|
||||
this.endTime = ''
|
||||
this.userIdList = []
|
||||
this.createUserId = ''
|
||||
uni.setStorageSync('userSelect', [])
|
||||
},
|
||||
|
||||
selectConfirm() {
|
||||
if(this.userIdList.length) {
|
||||
this.createUserId = this.userIdList?.[0].userId
|
||||
}
|
||||
|
||||
this.start = this.startTime,
|
||||
this.end = this.endTime
|
||||
let startTmp = this.start.split("-");
|
||||
let endTmp = this.end.split("-");
|
||||
let stT = new Date(startTmp[0], startTmp[1], startTmp[2]);
|
||||
let edT = new Date(endTmp[0], endTmp[1], endTmp[2]);
|
||||
if (stT.getTime() > edT.getTime()) {
|
||||
this.$u.toast("开始日期不能大于结束日期!");
|
||||
this.filterShow = true
|
||||
return
|
||||
}
|
||||
this.filterShow = false
|
||||
this.current = 1
|
||||
this.list = []
|
||||
this.getList()
|
||||
},
|
||||
confirmStart(val) {
|
||||
this.startTime = val.year + '-' + val.month + '-' + val.day
|
||||
},
|
||||
confirmEnd(val) {
|
||||
this.endTime = val.year + '-' + val.month + '-' + val.day
|
||||
},
|
||||
},
|
||||
onShow() {
|
||||
document.title = '协同宣发'
|
||||
this.$dict.load(['mstStatus']).then(() => {
|
||||
this.list = []
|
||||
this.current = 1
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
onReachBottom() {
|
||||
this.current ++
|
||||
this.getList()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppCooperationPropaganda {
|
||||
.search {
|
||||
display: flex;
|
||||
height: 80px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.searchBox {
|
||||
width: 562px;
|
||||
}
|
||||
.filterBtn {
|
||||
img {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.resident_list {
|
||||
padding: 24px 32px 20px 32px;
|
||||
box-sizing: border-box;
|
||||
.card {
|
||||
background: #FFF;
|
||||
border-radius: 16px;
|
||||
padding: 30px;
|
||||
margin-bottom: 24px;
|
||||
& > div {
|
||||
padding: 10px 0;
|
||||
}
|
||||
.num {
|
||||
color: #3AA0FF;
|
||||
}
|
||||
.card_title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.card_left {
|
||||
font-size: 32px;
|
||||
color: #000000;
|
||||
font-weight: 600;
|
||||
}
|
||||
.card_right {
|
||||
span {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
// background: #3399FF;
|
||||
border-radius: 50%;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.status0 {
|
||||
background: #FFA938;
|
||||
}
|
||||
.status1 {
|
||||
background: #FF6758;
|
||||
}
|
||||
.status2 {
|
||||
background: #3399FF;
|
||||
}
|
||||
.status3 {
|
||||
background: #FF6758;
|
||||
}
|
||||
.status4 {
|
||||
background: #3399FF;
|
||||
}
|
||||
.status5 {
|
||||
background: #1CCEB0;
|
||||
}
|
||||
.status6 {
|
||||
background: #666666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.popup {
|
||||
box-sizing: border-box;
|
||||
// height: 800px;
|
||||
.tips {
|
||||
width: 80px;
|
||||
height: 6px;
|
||||
background: #dddddd;
|
||||
border-radius: 4px;
|
||||
padding: 0 32px;
|
||||
box-sizing: border-box;
|
||||
margin: 32px auto 8px auto;
|
||||
}
|
||||
.title {
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
font-size: 34px;
|
||||
font-family: PingFangSC-Medium, PingFang SC;
|
||||
font-weight: 500;
|
||||
color: #222;
|
||||
padding: 0 32px;
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 32px;
|
||||
.cancel {
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
color: #aaa;
|
||||
}
|
||||
.confirm {
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
text-align: right;
|
||||
color: #333;
|
||||
}
|
||||
p {
|
||||
display: inline-block;
|
||||
width: calc(100% - 400px);
|
||||
text-align: center;
|
||||
font-size: 28px;
|
||||
}
|
||||
}
|
||||
.select-content {
|
||||
height: calc(100% - 100px);
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.type-list {
|
||||
padding: 0 32px;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 32px;
|
||||
.type-title {
|
||||
line-height: 108px;
|
||||
font-size: 32px;
|
||||
font-family: PingFangSC-Medium, PingFang SC;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
.item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
& > div:last-child {
|
||||
::v-deep .uni-input-input,
|
||||
::v-deep .uni-input-placeholder {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
.active {
|
||||
background: #1365dd;
|
||||
color: #fff;
|
||||
}
|
||||
.user {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
.popBtn {
|
||||
display: flex;
|
||||
height: 98px;
|
||||
line-height: 98px;
|
||||
div {
|
||||
width: 50%;
|
||||
border: 2px solid #3399ff;
|
||||
text-align: center;
|
||||
}
|
||||
div:first-child {
|
||||
color: #3399ff;
|
||||
}
|
||||
div:last-child {
|
||||
color: #fff;
|
||||
background: #3399ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
.page_picker {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
510
src/apps/AppCooperationPropaganda/cooperationDetail.vue
Normal file
@@ -0,0 +1,510 @@
|
||||
<template>
|
||||
<div class="cooperationDetail">
|
||||
<AiTopFixed>
|
||||
<div class="tab-select">
|
||||
<div
|
||||
class="item"
|
||||
:class="tabIndex == index ? 'active' : ''"
|
||||
v-for="(item, index) in tabs"
|
||||
:key="index"
|
||||
@click="tabClick(index)"
|
||||
>
|
||||
{{ item }}<span></span>
|
||||
</div>
|
||||
</div>
|
||||
</AiTopFixed>
|
||||
|
||||
<div class="content">
|
||||
<div class="header">
|
||||
<div class="header_left">
|
||||
<div>{{ detail.taskTitle }} <span :class="detail.status==0? 'status0': detail.status==1? 'status1': detail.status==2? 'status2':
|
||||
detail.status == 3? 'status3':detail.status==4? 'status4': 'status5'">{{ $dict.getLabel('mstStatus', detail.status) }}</span></div>
|
||||
<div>
|
||||
创建时间: <span>{{ createTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header_right" @click="toDetail">查看详情</div>
|
||||
</div>
|
||||
|
||||
<div class="pieEcharts">
|
||||
<div class="pie_info">
|
||||
<div class="tips" v-if="detail.status">
|
||||
数据更新于<span>{{ info.remindTime }}</span>
|
||||
</div>
|
||||
<div class="pie_card">
|
||||
<div id="pieEcharts"></div>
|
||||
<div class="pie_right">
|
||||
<div>
|
||||
<span>{{
|
||||
tabIndex == 0 ? "计划执行成员:" : "计划送达居民群:"
|
||||
}}</span>
|
||||
<span>{{ info.planCount || 0 }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{
|
||||
tabIndex == 0 ? "未执行成员:" : "未送达居民群:"
|
||||
}}</span>
|
||||
<span>{{ info.unExecutedCount || 0 }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{
|
||||
tabIndex == 0 ? "已执行成员:" : "已送达居民群:"
|
||||
}}</span>
|
||||
<span>{{ info.executedCount || 0 }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{
|
||||
tabIndex == 0 ? "无法执行成员:" : "无法送达居民群:"
|
||||
}}</span>
|
||||
<span>{{ info.cannotExecuteCount || 0 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="detail.status == 4" class="btn" @click="remindSend">提醒成员发送</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list_content">
|
||||
<div class="list_card">
|
||||
<div class="tab" v-show="update0">
|
||||
<u-subsection
|
||||
:list="subsection0"
|
||||
mode="button"
|
||||
activeColor="#3c9cff"
|
||||
:current="subIndex0"
|
||||
@change="changeSub0"
|
||||
></u-subsection>
|
||||
</div>
|
||||
|
||||
<div class="tab" v-show="update1">
|
||||
<u-subsection
|
||||
:list="subsection1"
|
||||
mode="button"
|
||||
activeColor="#3c9cff"
|
||||
:current="subIndex1"
|
||||
@change="changeSub1"
|
||||
></u-subsection>
|
||||
</div>
|
||||
|
||||
<AiTable
|
||||
:data="tableData"
|
||||
:colConfigs="tabIndex == 0 ? colConfigs0 : colConfigs1"
|
||||
v-if="tableData.length"/>
|
||||
<AiEmpty v-if="!tableData.length" description="暂无数据"></AiEmpty>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import echarts from "echarts";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tabs: ["成员统计", "居民群统计"],
|
||||
tabIndex: 0,
|
||||
pieEcharts: null,
|
||||
subIndex0: 0,
|
||||
subIndex1: 0,
|
||||
tableData: [],
|
||||
createTime: "",
|
||||
id: "",
|
||||
info: {},
|
||||
current: 1,
|
||||
firstClickTime: "",
|
||||
currentClickTime: "",
|
||||
detail: {},
|
||||
|
||||
subsection0: [
|
||||
{ name: "未执行" },
|
||||
{ name: "已执行" },
|
||||
{ name: "无法执行" },
|
||||
],
|
||||
subsection1: [
|
||||
{ name: "未送达" },
|
||||
{ name: "已送达" },
|
||||
{ name: "无法送达" },
|
||||
],
|
||||
update0: true,
|
||||
update1: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
colConfigs0() {
|
||||
return [
|
||||
{ prop: "groupOwnerName", label: "成员" },
|
||||
{ label: "预计送达居民群", prop: "groupCount" },
|
||||
];
|
||||
},
|
||||
colConfigs1() {
|
||||
return [
|
||||
{ label: "居民群", prop: "groupName" },
|
||||
{ label: "群人数", prop: "memberCount" },
|
||||
{ prop: "groupOwnerName", label: "群主" },
|
||||
];
|
||||
},
|
||||
},
|
||||
onLoad(o) {
|
||||
this.id = o.id;
|
||||
this.createTime = o.time;
|
||||
},
|
||||
methods: {
|
||||
tabClick(index) {
|
||||
this.tabIndex = index;
|
||||
if(this.tabIndex == 0) {
|
||||
this.subsection = [
|
||||
{ name: "未执行" },
|
||||
{ name: "已执行" },
|
||||
{ name: "无法执行" },
|
||||
]
|
||||
this.update0 = true
|
||||
this.update1 = false
|
||||
this.$forceUpdate()
|
||||
} else if(this.tabIndex == 1) {
|
||||
this.subsection = [
|
||||
{ name: "未送达" },
|
||||
{ name: "已送达" },
|
||||
{ name: "无法送达" },
|
||||
]
|
||||
this.update0 = false
|
||||
this.update1 = true
|
||||
this.$forceUpdate()
|
||||
}
|
||||
this.getStatistics();
|
||||
},
|
||||
|
||||
getDetail() {
|
||||
this.$http
|
||||
.post(`/app/appmasssendingtask/queryDetailById?id=${this.id}`)
|
||||
.then((res) => {
|
||||
if (res?.data) {
|
||||
this.detail = res.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
toDetail() {
|
||||
uni.navigateTo({ url: `./detail?id=${this.id}` });
|
||||
},
|
||||
// 提醒发送
|
||||
remindSend() {
|
||||
uni.getSystemInfo({
|
||||
success: (res)=>{
|
||||
if(res.platform == "ios") {
|
||||
this.firstClickTime = new Date(this.detail.remindTime.replace(/-/g, "/")).getTime() || 0
|
||||
} else {
|
||||
this.firstClickTime = new Date(this.detail.remindTime).getTime() || 0
|
||||
}
|
||||
}
|
||||
});
|
||||
this.currentClickTime = +new Date();
|
||||
let time = this.currentClickTime - this.firstClickTime;
|
||||
if (time >= 3600000) {
|
||||
this.$http.post("/app/appmasssendingtask/remindSend", null, {
|
||||
params: {
|
||||
id: this.id,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res?.code == 0) {
|
||||
this.$u.toast("已提醒成员发送");
|
||||
this.getDetail()
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
} else {
|
||||
time = 3600000 - time;
|
||||
const min = Math.floor(time / 60000); // 分钟
|
||||
let second = Math.floor(time / 1000); // 秒
|
||||
second %= 60;
|
||||
let msg = ``;
|
||||
if (min > 0 && second > 0) {
|
||||
msg = `${min}分钟${second}秒后可以再次点击`;
|
||||
} else if (min > 0 && second <= 0) {
|
||||
msg = `${min}分钟后可以再次点击`;
|
||||
} else if (min <= 0 && second > 0) {
|
||||
msg = `${second}秒后可以再次点击`;
|
||||
}
|
||||
this.$u.toast(msg);
|
||||
}
|
||||
},
|
||||
// 切换分段器
|
||||
changeSub0(index) {
|
||||
this.subIndex0 = index;
|
||||
this.getStatistics();
|
||||
},
|
||||
changeSub1(index) {
|
||||
this.subIndex1 = index;
|
||||
this.getStatistics();
|
||||
},
|
||||
// 获取数据
|
||||
getStatistics() {
|
||||
this.$http
|
||||
.post(`/app/appmasssendingtask/detailStatistics`, null, {
|
||||
params: {
|
||||
type: this.tabIndex,
|
||||
sendStatus: this.tabIndex==0? this.subIndex0: this.subIndex1,
|
||||
taskId: this.id,
|
||||
current: this.current,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res?.data) {
|
||||
this.info = res.data;
|
||||
this.tableData = res.data.executedList.records;
|
||||
setTimeout(()=>{
|
||||
this.getPieEcharts();
|
||||
}, 1000)
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 饼图
|
||||
getPieEcharts() {
|
||||
this.pieEcharts = echarts.init(document.getElementById("pieEcharts"));
|
||||
this.pieEcharts.setOption({
|
||||
tooltip: {
|
||||
show: false,
|
||||
},
|
||||
color: ["#1684fc", "#ccc"],
|
||||
series: [
|
||||
{
|
||||
name: this.tabIndex == 0 ? "任务完成率" : "群发送达率",
|
||||
type: "pie",
|
||||
radius: ["50%", "70%"],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
normal: {
|
||||
show: false,
|
||||
position: "center",
|
||||
},
|
||||
},
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: this.info.executedCount,
|
||||
name: "已执行成员",
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
formatter: ({ name, value }) => {
|
||||
let num = value / this.info.planCount * 100
|
||||
if (this.tabIndex == 0) {
|
||||
return num % 1==0? `{name|任务达成率\n\n}{value|${num}%}`: `{name|任务达成率\n\n}{value|${ num.toFixed(1) }%}`;
|
||||
} else {
|
||||
return num % 1==0? `{name|群发送达率\n\n}{value|${num}%}`: `{name|群发送达率\n\n}{value|${ num.toFixed(1) }%}`;
|
||||
}
|
||||
},
|
||||
textStyle: {
|
||||
fontSize: 16,
|
||||
},
|
||||
rich: {
|
||||
name: {
|
||||
color: "#999",
|
||||
|
||||
},
|
||||
value: {
|
||||
color: "#000000",
|
||||
fontSize: 26,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
value: this.info.planCount - this.info.executedCount ,
|
||||
name: "未执行成员"
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
},
|
||||
onShow() {
|
||||
document.title = "群发居民群统计";
|
||||
this.$dict.load("mstStatus")
|
||||
this.getStatistics();
|
||||
this.getDetail();
|
||||
},
|
||||
mounted() {
|
||||
this.getPieEcharts();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cooperationDetail {
|
||||
::v-deep .AiTopFixed .content {
|
||||
padding: 0;
|
||||
}
|
||||
::v-deep .emptyWrap {
|
||||
border: 2px solid #d0d4dc;
|
||||
border-radius: 8px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
.tab-select {
|
||||
width: 100%;
|
||||
height: 96px;
|
||||
line-height: 96px;
|
||||
background: #3975c6;
|
||||
display: flex;
|
||||
|
||||
.item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
font-size: 28px;
|
||||
font-family: PingFangSC-Regular, PingFang SC;
|
||||
color: #cddcf0;
|
||||
}
|
||||
|
||||
.active {
|
||||
font-family: PingFangSC-Medium, PingFang SC;
|
||||
font-weight: 500;
|
||||
position: relative;
|
||||
color: #fff;
|
||||
|
||||
span {
|
||||
width: 48px;
|
||||
height: 4px;
|
||||
background: #fff;
|
||||
position: absolute;
|
||||
bottom: 14px;
|
||||
left: 50%;
|
||||
margin-left: -24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
// height: 160px;
|
||||
padding: 32px;
|
||||
box-sizing: border-box;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.header_left {
|
||||
width: calc(100% - 120px);
|
||||
div:first-child {
|
||||
color: #000000;
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 10px;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
padding: 0 8px;
|
||||
border: 1px solid;
|
||||
border-radius: 6px;
|
||||
font-size: 26px;
|
||||
font-weight: normal;
|
||||
margin-left: 8px;
|
||||
}
|
||||
.status0 {
|
||||
color: #FFA938 !important;
|
||||
}
|
||||
.status1 {
|
||||
color: #FF6758 !important;
|
||||
}
|
||||
.status2 {
|
||||
color: #3399FF !important;
|
||||
}
|
||||
.status3 {
|
||||
color: #FF6758 !important;
|
||||
}
|
||||
.status4 {
|
||||
color: #3399FF !important;
|
||||
}
|
||||
.status5 {
|
||||
color: #1CCEB0 !important;
|
||||
}
|
||||
.status6 {
|
||||
color: #666666 !important;
|
||||
}
|
||||
}
|
||||
div:last-child {
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
.header_right {
|
||||
width: 120px;
|
||||
color: #5297ff;
|
||||
}
|
||||
}
|
||||
|
||||
.pieEcharts {
|
||||
width: 100%;
|
||||
padding: 32px;
|
||||
box-sizing: border-box;
|
||||
.pie_info {
|
||||
background: #fff;
|
||||
border-radius: 16px;
|
||||
padding-bottom: 20px;
|
||||
box-sizing: border-box;
|
||||
.tips {
|
||||
color: #666666;
|
||||
padding: 40px 32px 0 32px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.pie_card {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
#pieEcharts {
|
||||
width: 60%;
|
||||
height: 400px;
|
||||
}
|
||||
::v-deep .emptyWrap {
|
||||
width: 60%;
|
||||
}
|
||||
.pie_right {
|
||||
width: 40%;
|
||||
padding-right: 30px;
|
||||
box-sizing: border-box;
|
||||
div {
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
}
|
||||
.btn {
|
||||
margin: 0 auto;
|
||||
width: 90%;
|
||||
height: 80px;
|
||||
line-height: 80px;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
background: #3aa0ff;
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list_content {
|
||||
padding: 0 32px 32px 32px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.list_card {
|
||||
background: #fff;
|
||||
border-radius: 16px;
|
||||
padding: 30px 30px;
|
||||
|
||||
.tab {
|
||||
margin-bottom: 34px;
|
||||
|
||||
::v-deep .u-subsection uni-view{
|
||||
background: #eeef !important;
|
||||
}
|
||||
}
|
||||
|
||||
.sub-select {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
313
src/apps/AppCooperationPropaganda/detail.vue
Normal file
@@ -0,0 +1,313 @@
|
||||
<template>
|
||||
<div class="detail">
|
||||
<div class="task">
|
||||
<div class="task_title">群发客户群</div>
|
||||
<div class="task_content">
|
||||
<div class="item">
|
||||
<span>任务名称</span>
|
||||
<span>{{ data.taskTitle }}</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span>创建人</span>
|
||||
<span>{{ data.createUserName }}</span>
|
||||
</div>
|
||||
<div class="item" v-if="data.enableExamine == 1">
|
||||
<span>审批人</span>
|
||||
<span>
|
||||
<span v-for="(item, index) in approver" :key="index" style="color: #333;">{{ item.examineUserName + '、' }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span>所在部门</span>
|
||||
<span style="display: flex;">
|
||||
<div v-if="data.createUserDeptName">{{ data.createUserDeptName }}</div>
|
||||
</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span>群发时间</span>
|
||||
<span>{{ data.choiceTime }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="task_results" v-if="data.enableExamine == 1">
|
||||
<img v-if="data.status == 1" src="./images/refuse.png" alt="">
|
||||
<img v-if="data.status == 2" src="./images/pass.png" alt="">
|
||||
</div>
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="scope">
|
||||
<span>群发范围</span>
|
||||
<span v-if="data.sendScope==0">全部{{ data.receiveGroupCount || 0}}个居民群</span>
|
||||
<span v-if="data.sendScope==1 || data.sendScope==2">按条件筛选的{{ data.receiveGroupCount || 0}}个居民群</span>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>群发内容</p>
|
||||
<div>
|
||||
<!-- 文本 -->
|
||||
<div class="textarea" v-show="content.length">{{ content }}</div>
|
||||
<!-- 图片 -->
|
||||
<div class="pictures" v-show="picList.length">
|
||||
<image v-for="(item, index) in picList" :key="index" :src="item.imgPicUrl" @click.stop="previewImages(picList, item.imgPicUrl)"/>
|
||||
</div>
|
||||
<!-- 视频 -->
|
||||
<div class="video" v-show="videoList.length">
|
||||
<video v-for="(item, index) in videoList" :key="index" :src="item.imgPicUrl"/>
|
||||
</div>
|
||||
<!-- 文件 -->
|
||||
<div class="file" v-show="fileList.length">
|
||||
<div class="file_item" v-for="(item,index) in fileList" :key="index" @click="prevFile(item.sysFile)">
|
||||
<img src="./images/files.png" alt="">
|
||||
<div>{{ item.sysFile.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 网页 -->
|
||||
<div class="webpage" v-show="webpage.length">
|
||||
<p>链接地址</p>
|
||||
<a v-for="(item, index) in webpage" :key="index" :href="item.linkUrl">
|
||||
<div v-if="item.linkTitle">{{item.linkTitle}}</div>
|
||||
<div v-else>{{ item.linkUrl }}</div>
|
||||
</a>
|
||||
</div>
|
||||
<!-- 小程序 -->
|
||||
<div class="miniapp" v-show="miniapp.length">
|
||||
<p>小程序</p>
|
||||
<div v-for="(item, index) in miniapp" :key="index">{{item.mpTitle}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn" v-if="data.status==0 && data.haveExaminPower">
|
||||
<div class="refuse" @click="refuseBtn">审核拒绝</div>
|
||||
<div class="pass" @click="passBtn">审核通过</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState ,mapActions } from "vuex";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
id: "",
|
||||
data: {},
|
||||
content: '',
|
||||
picList: [],
|
||||
videoList: [],
|
||||
fileList: [],
|
||||
webpage: [],
|
||||
miniapp: [],
|
||||
pictres: [],
|
||||
options: '',
|
||||
approver: [], //审批人
|
||||
}
|
||||
},
|
||||
onLoad(o) {
|
||||
this.id = o.id
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
methods: {
|
||||
getDetail() {
|
||||
this.$http.post(`/app/appmasssendingtask/queryDetailById?id=${this.id}`).then(res=> {
|
||||
if (res?.data) {
|
||||
this.data = res.data
|
||||
this.content = res.data.contents.filter(v=> v.msgType == 0)?.[0].content
|
||||
this.picList = res.data.contents.filter(v=> v.msgType == 1)
|
||||
this.videoList = res.data.contents.filter(v=> v.msgType == 2)
|
||||
this.fileList = res.data.contents.filter(v=> v.msgType == 3)
|
||||
this.webpage = res.data.contents.filter(v=> v.msgType == 4)
|
||||
this.miniapp = res.data.contents.filter(v=> v.msgType == 5)
|
||||
this.approver = res.data.examines
|
||||
// if(res.data.status==1) { // 拒绝
|
||||
// this.approver = res.data.examines.filter(e=> e.examineStatus == 2)
|
||||
// } else { // 通过
|
||||
// this.approver = res.data.examines
|
||||
// }
|
||||
}
|
||||
})
|
||||
},
|
||||
previewImages(images, img) {
|
||||
uni.previewImage({
|
||||
urls: images.map(v => v.imgPicUrl),
|
||||
current: img
|
||||
})
|
||||
},
|
||||
...mapActions(['previewFile']),
|
||||
prevFile(file) {
|
||||
this.$loading()
|
||||
this.previewFile({ ...file }).then(()=>{
|
||||
this.$hideLoading()
|
||||
})
|
||||
},
|
||||
// 拒绝
|
||||
refuseBtn() {
|
||||
this.pass = 0
|
||||
this.$confirm('确认审核拒绝该任务?').then(() => {
|
||||
this.examine()
|
||||
})
|
||||
},
|
||||
// 通过
|
||||
passBtn() {
|
||||
this.pass = 1
|
||||
this.$confirm('确认审核通过该任务?').then(() => {
|
||||
this.examine()
|
||||
})
|
||||
},
|
||||
examine() {
|
||||
this.$http.post(`/app/appmasssendingtask/examine`,null,{
|
||||
params: {
|
||||
pass: this.pass,
|
||||
id: this.id,
|
||||
options: this.options
|
||||
}
|
||||
}).then(res => {
|
||||
if(res?.code == 0) {
|
||||
if(this.pass == 0) {
|
||||
this.$u.toast('任务已拒绝')
|
||||
} else if(this.pass == 1) {
|
||||
this.$u.toast('任务审核通过')
|
||||
}
|
||||
this.getDetail()
|
||||
}
|
||||
}).catch(()=> {
|
||||
})
|
||||
},
|
||||
},
|
||||
onShow() {
|
||||
document.title = "群发审批"
|
||||
this.getDetail()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.detail {
|
||||
padding: 32px 32px 140px 32px;
|
||||
box-sizing: border-box;
|
||||
.task {
|
||||
position: relative;
|
||||
margin-bottom: 24px;
|
||||
background: #FFF;
|
||||
border-radius: 8px;
|
||||
box-shadow: inset 0px -1px 0px 0px #DDDDDD;
|
||||
.task_title {
|
||||
padding: 26px 32px;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 2px solid #DDDDDD;
|
||||
}
|
||||
.task_content {
|
||||
padding: 0 32px 26px 32px;
|
||||
box-sizing: border-box;
|
||||
.item {
|
||||
display: flex;
|
||||
padding-top: 26px;
|
||||
box-sizing: border-box;
|
||||
span:first-child {
|
||||
width: 160px;
|
||||
color: #999999;
|
||||
}
|
||||
span:last-child {
|
||||
width: calc(100% - 160px);
|
||||
}
|
||||
}
|
||||
}
|
||||
.task_results {
|
||||
position: absolute;
|
||||
right: 30px;
|
||||
top: 30px;
|
||||
img {
|
||||
width: 160px;
|
||||
height: 130px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
background: #FFF;
|
||||
border-radius: 8px;
|
||||
padding: 26px 32px;
|
||||
box-sizing: border-box;
|
||||
.scope {
|
||||
display: flex;
|
||||
margin-bottom: 16px;
|
||||
span:first-child {
|
||||
width: 160px;
|
||||
color: #999;
|
||||
}
|
||||
span:last-child {
|
||||
width: calc(100% - 160px);
|
||||
}
|
||||
}
|
||||
.content {
|
||||
p {
|
||||
color: #999;
|
||||
}
|
||||
.textarea,
|
||||
.pictures,
|
||||
.video,
|
||||
.file,
|
||||
.webpage,
|
||||
.miniapp {
|
||||
background: #F9F9F9;
|
||||
border-radius: 4px;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
margin-top: 26px;
|
||||
}
|
||||
.pictures {
|
||||
margin-top: 16px;
|
||||
image {
|
||||
width: 190px;
|
||||
height: 190px;
|
||||
margin-right: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
image:nth-child(3n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
.video {
|
||||
video {
|
||||
height: 300px;
|
||||
}
|
||||
}
|
||||
.file {
|
||||
.file_item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
img {
|
||||
width: 96px;
|
||||
height: 96px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 112px;
|
||||
line-height: 112px;
|
||||
font-size: 32px;
|
||||
z-index: 9;
|
||||
.refuse {
|
||||
width: 40%;
|
||||
height: 100%;
|
||||
background: #FFF;
|
||||
color: #FF4466;
|
||||
text-align: center;
|
||||
}
|
||||
.pass {
|
||||
width: 60%;
|
||||
height: 100%;
|
||||
background: #3975C6;
|
||||
color: #FFF;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
BIN
src/apps/AppCooperationPropaganda/images/files.png
Normal file
|
After Width: | Height: | Size: 955 B |
BIN
src/apps/AppCooperationPropaganda/images/gird--select-icon.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
src/apps/AppCooperationPropaganda/images/local-icon.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
src/apps/AppCooperationPropaganda/images/pass.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
src/apps/AppCooperationPropaganda/images/refuse.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
src/apps/AppCooperationPropaganda/images/right-icon.png
Normal file
|
After Width: | Height: | Size: 373 B |
BIN
src/apps/AppCooperationPropaganda/images/shaixuan.png
Normal file
|
After Width: | Height: | Size: 663 B |
BIN
src/apps/AppCooperationPropaganda/images/tx@2x.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
src/apps/AppCooperationPropaganda/images/xz.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
src/apps/AppCooperationPropaganda/images/xzh.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
233
src/apps/AppCooperationPropaganda/selectUser.vue
Normal file
@@ -0,0 +1,233 @@
|
||||
<template>
|
||||
<section class="selectUser">
|
||||
<div class="header-middle">
|
||||
<div class="userCards" v-for="e in userList" :key="e.userId">
|
||||
<div class="imges">
|
||||
<div class="imgselect" :class="{ 'checked': e.isChecked }" @click.stop="itemCheck(e)" />
|
||||
<img src="./images/tx@2x.png" alt="" class="avatras"/>
|
||||
</div>
|
||||
<div class="rights fill">
|
||||
<div class="applicationNames">
|
||||
<AiOpenData type="userName" :openid="e.userId"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<AiEmpty description="暂无数据" v-if="!userList"/>
|
||||
</div>
|
||||
<div class="subBtn" @click="submit">
|
||||
<div>确定选择</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: "selectUser",
|
||||
appName: "选择创建人",
|
||||
data() {
|
||||
return {
|
||||
selected: {},
|
||||
userList: [],
|
||||
current: 1,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
hasData() {
|
||||
return this.userList?.length > 0
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.selected = uni.getStorageSync('userSelect') || []
|
||||
this.getCreateUserList()
|
||||
},
|
||||
methods: {
|
||||
isSelected(userId) {
|
||||
return this.selected.userId===userId
|
||||
},
|
||||
getCreateUserList() {
|
||||
this.userList = []
|
||||
this.$http.post(`/app/appmasssendingtask/createUserlist`).then(res => {
|
||||
if (res?.data) {
|
||||
this.userList = res.data.map(e => ({userId: e, isChecked: this.isSelected(e)}))
|
||||
}
|
||||
})
|
||||
},
|
||||
itemCheck(row) {
|
||||
this.userList.forEach(e => e.isChecked = false)
|
||||
const index = this.userList.findIndex(o => {
|
||||
return row.userId===o.userId
|
||||
})
|
||||
this.userList[index].isChecked = true
|
||||
this.selected = this.userList[index]
|
||||
},
|
||||
submit() {
|
||||
if(!this.selected.userId) {
|
||||
return this.$u.toast('请选择创建人')
|
||||
}
|
||||
uni.$emit("pagePicker:custom", [this.selected])
|
||||
uni.setStorageSync('userSelect', this.selected)
|
||||
uni.navigateBack()
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.selectUser {
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
|
||||
.header-top {
|
||||
background: #fff;
|
||||
padding: 20px 32px;
|
||||
}
|
||||
|
||||
.header-middle {
|
||||
padding-bottom: 140px;
|
||||
|
||||
.hint {
|
||||
padding: 28px 20px 28px 32px;
|
||||
line-height: 56px;
|
||||
box-shadow: 0 1px 0 0 #e4e5e6;
|
||||
font-size: 30px;
|
||||
font-weight: 500;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.empty-div {
|
||||
height: 16px;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.imges {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.imgselect {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
vertical-align: middle;
|
||||
background-image: url("./images/xz.png");
|
||||
background-position: center;
|
||||
background-size: 100% 100%;
|
||||
|
||||
&.checked {
|
||||
background-image: url("./images/xzh.png");
|
||||
}
|
||||
}
|
||||
|
||||
.avatras {
|
||||
width: 74px;
|
||||
height: 74px;
|
||||
border-radius: 8px;
|
||||
margin-left: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
.cards {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 120px;
|
||||
line-height: 120px;
|
||||
padding: 0 0 0 32px;
|
||||
|
||||
|
||||
img {
|
||||
width: 74px;
|
||||
height: 74px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.rightes {
|
||||
width: calc(100% - 160px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 32px;
|
||||
border-bottom: 1px solid #e4e5e6;
|
||||
|
||||
.applicationNames {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 36px;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.imgs {
|
||||
flex-shrink: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.userCards {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 120px;
|
||||
line-height: 120px;
|
||||
padding: 0 0 0 32px;
|
||||
|
||||
.rights {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-left: 32px;
|
||||
border-bottom: 1px solid #e4e5e6;
|
||||
padding-right: 40px;
|
||||
height: inherit;
|
||||
|
||||
.applicationNames {
|
||||
font-size: 36px;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.idNumbers {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.subBtn {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 118px;
|
||||
background: #f4f8fb;
|
||||
|
||||
div {
|
||||
width: 192px;
|
||||
height: 80px;
|
||||
line-height: 80px;
|
||||
text-align: center;
|
||||
background: #1365dd;
|
||||
border-radius: 4px;
|
||||
font-size: 32px;
|
||||
color: #fff;
|
||||
margin: 20px 34px 0 0;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.color-3F8DF5 {
|
||||
color: #3F8DF5;
|
||||
}
|
||||
|
||||
.mar-h4 {
|
||||
margin: 0 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
903
src/apps/AppPropagandaStatistics/AppPropagandaStatistics.vue
Normal file
@@ -0,0 +1,903 @@
|
||||
<template>
|
||||
<div class="AppPropagandaStatistics">
|
||||
<div class="calendar_header">
|
||||
<u-section
|
||||
title="宣发日历"
|
||||
:show-line="false"
|
||||
sub-title="查看更多"
|
||||
@click="readMore"
|
||||
></u-section>
|
||||
</div>
|
||||
<div class="threeDays">
|
||||
<!-- 昨天 -->
|
||||
<div class="yesterday">
|
||||
<div class="itemYesterday">昨天<span>{{ nowMonth }}.{{ nowDate - 1 }}</span></div>
|
||||
|
||||
<div v-if="calendarList && calendarList[nowDate - 1] && calendarList[nowDate - 1].taskList.length">
|
||||
<div v-for="(item,index) in calendarList[nowDate - 1].taskList.slice(0, 2)" :key="index">{{item.taskTitle}}</div>
|
||||
<div v-if="calendarList[nowDate - 1].taskList.length > 2 && showYes">
|
||||
<div v-for="(item,index) in calendarList[nowDate - 1].taskList.slice(2, calendarList[nowDate - 1].taskList.length)" :key="index">{{item.taskTitle}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!(calendarList && calendarList[nowDate - 1] && calendarList[nowDate - 1].taskList.length)">暂无宣发任务</div>
|
||||
<div class="isShow" v-if="calendarList && calendarList[nowDate - 1] && calendarList[nowDate - 1].taskList.length && calendarList[nowDate - 1].taskList.length > 2" @click="showYes = !showYes">{{ showYes ? "收起" : "展开" }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 今天 -->
|
||||
<div class="today">
|
||||
<div class="itemToday">今天<span>{{ nowMonth }}.{{ nowDate }}</span></div>
|
||||
|
||||
<div v-if="calendarList && calendarList[nowDate] && calendarList[nowDate].taskList.length">
|
||||
<div v-for="(item,index) in calendarList[nowDate].taskList.slice(0, 2)" :key="index">{{item.taskTitle}}</div>
|
||||
<div v-if="calendarList[nowDate].taskList.length > 2 && showTo">
|
||||
<div v-for="(item,index) in calendarList[nowDate].taskList.slice(2, calendarList[nowDate].taskList.length)" :key="index">{{item.taskTitle}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!(calendarList && calendarList[nowDate] && calendarList[nowDate].taskList.length>0)">暂无宣发任务</div>
|
||||
<div class="isShow" v-if="calendarList && calendarList[nowDate] && calendarList[nowDate].taskList.length && calendarList[nowDate].taskList.length > 2" @click="showTo=!showTo">{{ showTo ? "收起" : "展开" }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 明天 -->
|
||||
<div class="tomorrow">
|
||||
<div class="itemTomorrow">明天<span>{{ nowMonth }}.{{ nowDate + 1 }}</span></div>
|
||||
|
||||
<div v-if="calendarList && calendarList[nowDate + 1] && calendarList[nowDate + 1].taskList.length">
|
||||
<div v-for="(item,index) in calendarList[nowDate + 1].taskList.slice(0, 2)" :key="index">{{item.taskTitle}}</div>
|
||||
<div v-if="calendarList[nowDate + 1].taskList.length > 2 && showTom">
|
||||
<div v-for="(item,index) in calendarList[nowDate + 1].taskList.slice(2, calendarList[nowDate + 1].taskList.length)" :key="index">{{item.taskTitle}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!(calendarList && calendarList[nowDate + 1] && calendarList[nowDate + 1].taskList.length)">暂无宣发任务</div>
|
||||
<div class="isShow" v-if="calendarList && calendarList[nowDate + 1] && calendarList[nowDate + 1].taskList.length && calendarList[nowDate + 1].taskList.length > 2" @click="showTom=!showTom">{{ showTom ? "收起" : "展开" }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 折线图 -->
|
||||
<div class="brokenEcharts">
|
||||
<div class="broken_title">
|
||||
<div class="broken_left">宣发效果</div>
|
||||
<div class="broken_right" @click="filterShow = true">
|
||||
<img src="./images/shaixuan.png" alt="" />筛选
|
||||
</div>
|
||||
</div>
|
||||
<div class="broken_statistics">
|
||||
<div class="broken_item">
|
||||
<div>创建宣发任务数</div>
|
||||
<div>{{ data.createCount || 0 }}</div>
|
||||
</div>
|
||||
<div class="broken_item">
|
||||
<div>执行宣发次数</div>
|
||||
<div>{{ data.executeCount || 0 }}</div>
|
||||
</div>
|
||||
<div class="broken_item">
|
||||
<div>触达人次</div>
|
||||
<div>{{ data.receiveCount || 0 }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="title">宣发任务数</div>
|
||||
<div id="brokenEcharts3"></div>
|
||||
<div class="title" >宣发次数</div>
|
||||
<div id="brokenEcharts2"></div>
|
||||
<div class="title" >触达人次</div>
|
||||
<div id="brokenEcharts1"></div>
|
||||
</div>
|
||||
<div class="columnarEcharts" v-if="colData.length">
|
||||
<div class="broken_title">
|
||||
<div class="broken_left">宣发明细</div>
|
||||
<div class="broken_right">
|
||||
<span
|
||||
:class="detailType == 0 ? 'active' : ''"
|
||||
@click="detailType = 0, getColData()"
|
||||
>近7天</span
|
||||
>
|
||||
<span
|
||||
:class="detailType == 1 ? 'active' : ''"
|
||||
@click="detailType = 1, getColData()"
|
||||
>近30天</span
|
||||
>
|
||||
<span
|
||||
:class="detailType == 2 ? 'active' : ''"
|
||||
@click="detailType = 2, getColData()"
|
||||
>近1年</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div id="columnarEcharts"></div>
|
||||
</div>
|
||||
|
||||
<u-popup v-model="filterShow" mode="bottom" border-radius="14">
|
||||
<div class="popup">
|
||||
<div class="tips"></div>
|
||||
<div class="title">
|
||||
<div
|
||||
class="cancel"
|
||||
@click.stop="filterShow = false, timeSelect = 0"
|
||||
>
|
||||
取消
|
||||
</div>
|
||||
<p>筛选条件</p>
|
||||
<div class="confirm" @click.stop="selectConfirm">确定</div>
|
||||
</div>
|
||||
<scroll-view class="select-content" scroll-y="true">
|
||||
<div class="type-list">
|
||||
<div class="type-title">宣发时间</div>
|
||||
<div
|
||||
class="item"
|
||||
v-for="(item, index) in timeList"
|
||||
:key="index"
|
||||
:class="index == timeSelect ? 'active' : ''"
|
||||
@click.stop="checkTime(index)"
|
||||
>
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="type-list">
|
||||
<div class="type-title">宣发部门</div>
|
||||
<div @click="getDept" class="dept">
|
||||
<div v-if="departmentId">
|
||||
<AiOpenData type="departmentName" :openid="departmentId"/>
|
||||
</div>
|
||||
<div v-if="!departmentId">请选择部门</div>
|
||||
<u-icon name="arrow-right"></u-icon>
|
||||
</div>
|
||||
</div>
|
||||
</scroll-view>
|
||||
<div class="popBtn">
|
||||
<div @click="reset">重置</div>
|
||||
<div @click="selectConfirm">确认</div>
|
||||
</div>
|
||||
</div>
|
||||
<u-popup v-model="customShow" mode="bottom" border-radius="14" closeable>
|
||||
<div class="customPop">
|
||||
<div class="startTime">
|
||||
<div>开始时间:</div>
|
||||
<div style="display: flex; justify-content: space-between">
|
||||
<u-input
|
||||
v-model="startTime"
|
||||
placeholder="请选择开始时间"
|
||||
disabled
|
||||
@click="showStart = true"
|
||||
/>
|
||||
<u-icon name="arrow-right"></u-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="endTime">
|
||||
<div>结束时间:</div>
|
||||
<div style="display: flex; justify-content: space-between">
|
||||
<u-input
|
||||
v-model="endTime"
|
||||
placeholder="请选择结束时间"
|
||||
disabled
|
||||
@click="showEnd = true"
|
||||
/>
|
||||
<u-icon name="arrow-right"></u-icon>
|
||||
</div>
|
||||
</div>
|
||||
<u-picker
|
||||
mode="time"
|
||||
v-model="showStart"
|
||||
@confirm="confirmStart"
|
||||
></u-picker>
|
||||
<u-picker
|
||||
mode="time"
|
||||
v-model="showEnd"
|
||||
@confirm="confirmEnd"
|
||||
></u-picker>
|
||||
<div class="timeBtn" @click="handleTime">确定</div>
|
||||
</div>
|
||||
</u-popup>
|
||||
</u-popup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import echarts from "echarts";
|
||||
import { mapState, mapActions } from 'vuex'
|
||||
export default {
|
||||
name: "AppPropagandaStatistics",
|
||||
appName: "宣发统计",
|
||||
data() {
|
||||
return {
|
||||
isShow: false,
|
||||
brokenEcharts1: null,
|
||||
brokenEcharts2: null,
|
||||
brokenEcharts3: null,
|
||||
columnarEcharts: null,
|
||||
filterShow: false,
|
||||
customShow: false,
|
||||
showYes: false,
|
||||
showTo: false,
|
||||
showTom: false,
|
||||
timeList: ["近7天", "近30天", "近1年", "自定义"],
|
||||
timeSelect: 0,
|
||||
start: "",
|
||||
end: "",
|
||||
departmentId: '',
|
||||
departList: [],
|
||||
nowMonth: "",
|
||||
nowDate: "",
|
||||
calendarList: [],
|
||||
detailType: 0,
|
||||
timeType: "",
|
||||
departId: "",
|
||||
startTime: "",
|
||||
endTime: "",
|
||||
start: "",
|
||||
end: "",
|
||||
showStart: false,
|
||||
showEnd: false,
|
||||
resX: [],
|
||||
resY: [],
|
||||
res2Y: [],
|
||||
res3Y: [],
|
||||
colData: [],
|
||||
data: {}
|
||||
};
|
||||
},
|
||||
|
||||
onShow() {
|
||||
document.title = "宣发统计";
|
||||
this.getBrokenDate();
|
||||
this.getData();
|
||||
this.getColData();
|
||||
this.getNowDate();
|
||||
},
|
||||
mounted() {
|
||||
this.getBrokenEcharts1();
|
||||
this.getBrokenEcharts2();
|
||||
this.getBrokenEcharts3();
|
||||
this.getColumnarEcharts();
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['initOpenData', 'transCanvas','selectEnterpriseContact']),
|
||||
checkTime(index) {
|
||||
if (index == 3) {
|
||||
this.timeSelect = index;
|
||||
this.customShow = true;
|
||||
this.showStart = false;
|
||||
this.showEnd = false;
|
||||
} else {
|
||||
this.timeSelect = index;
|
||||
}
|
||||
},
|
||||
|
||||
readMore() {
|
||||
uni.navigateTo({ url: `./calendarInfo` });
|
||||
},
|
||||
// 重置
|
||||
reset() {
|
||||
this.timeType = 0;
|
||||
this.timeSelect = 0;
|
||||
this.start = "";
|
||||
this.end = "";
|
||||
this.departId = "";
|
||||
this.departmentId = "";
|
||||
},
|
||||
|
||||
selectConfirm() {
|
||||
if (this.timeSelect == 3) {
|
||||
this.detailType = this.timeSelect;
|
||||
this.start = this.startTime;
|
||||
this.end = this.endTime;
|
||||
} else {
|
||||
this.detailType = this.timeSelect || 0;
|
||||
}
|
||||
this.departId = this.departmentId
|
||||
this.getBrokenDate();
|
||||
this.filterShow = false;
|
||||
},
|
||||
|
||||
confirmStart(val) {
|
||||
this.startTime = val.year + "-" + val.month + "-" + val.day;
|
||||
},
|
||||
|
||||
confirmEnd(val) {
|
||||
this.endTime = val.year + "-" + val.month + "-" + val.day;
|
||||
},
|
||||
|
||||
handleTime() {
|
||||
this.start = this.startTime;
|
||||
this.end = this.endTime;
|
||||
let startTmp = this.start.split("-");
|
||||
let endTmp = this.end.split("-");
|
||||
let stT = new Date(startTmp[0], startTmp[1], startTmp[2]);
|
||||
let edT = new Date(endTmp[0], endTmp[1], endTmp[2]);
|
||||
if (stT.getTime() > edT.getTime()) {
|
||||
this.$u.toast("开始日期不能大于结束日期!");
|
||||
this.customShow = true
|
||||
return
|
||||
}
|
||||
this.customShow = false;
|
||||
},
|
||||
|
||||
getNowDate() {
|
||||
let date = new Date();
|
||||
this.nowDate = date.getDate();
|
||||
this.nowMonth = date.getMonth() + 1;
|
||||
},
|
||||
// 宣发日历
|
||||
getData() {
|
||||
this.$http
|
||||
.post(`/app/appmasssendingtask/statisticsCalendar`, null, {
|
||||
params: {},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res?.data) {
|
||||
this.calendarList = res.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 宣发效果
|
||||
getBrokenDate() {
|
||||
this.$http
|
||||
.post(`/app/appmasssendingtask/statisticsEffect`, null, {
|
||||
params: {
|
||||
type: this.timeSelect,
|
||||
startTime: this.start,
|
||||
endTime: this.end,
|
||||
departId: this.departId
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res?.data) {
|
||||
this.data = res.data;
|
||||
if (this.timeType == 0) {
|
||||
this.resX = res.data.trend.map(
|
||||
(e) =>
|
||||
e.ymd.substring(5, 7) + "-" + e.ymd.substring(8, 10)
|
||||
);
|
||||
} else if (this.timeType == 1) {
|
||||
this.resX = res.data.trend.map(
|
||||
(e) =>
|
||||
e.ymd.substring(5, 7) + "-" + e.ymd.substring(8, 10)
|
||||
);
|
||||
} else if (this.timeType == 2) {
|
||||
this.resX = res.data.trend.map(
|
||||
(e) =>
|
||||
e.ymd.substring(0, 4) + "-" + e.ymd.substring(5, 7)
|
||||
);
|
||||
}
|
||||
this.resY = res.data.trend.map((e) => e.receiveCount);
|
||||
this.res2Y = res.data.trend.map((e) => e.executeCount);
|
||||
this.res3Y = res.data.trend.map((e) => e.createCount);
|
||||
this.getBrokenEcharts1();
|
||||
this.getBrokenEcharts2();
|
||||
this.getBrokenEcharts3();
|
||||
}
|
||||
});
|
||||
},
|
||||
// 触发人数
|
||||
getBrokenEcharts1() {
|
||||
this.brokenEcharts1 = echarts.init(
|
||||
document.getElementById("brokenEcharts1")
|
||||
);
|
||||
this.brokenEcharts1.setOption({
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
},
|
||||
grid: {
|
||||
left: "2%",
|
||||
right: "5%",
|
||||
bottom: "2%",
|
||||
containLabel: true,
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: "slider",
|
||||
xAxisIndex: [0],
|
||||
filterMode: "filter",
|
||||
},
|
||||
],
|
||||
xAxis: {
|
||||
type: "category",
|
||||
boundaryGap: false,
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
data: this.resX,
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: "line",
|
||||
data: this.resY,
|
||||
lineStyle: {
|
||||
color: "#4B87FE",
|
||||
},
|
||||
itemStyle: {
|
||||
color: "#4E8EEE",
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
// 宣发次数
|
||||
getBrokenEcharts2() {
|
||||
this.brokenEcharts2 = echarts.init(
|
||||
document.getElementById("brokenEcharts2")
|
||||
);
|
||||
this.brokenEcharts2.setOption({
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
},
|
||||
grid: {
|
||||
left: "2%",
|
||||
right: "5%",
|
||||
bottom: "2%",
|
||||
containLabel: true,
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: "slider",
|
||||
xAxisIndex: [0],
|
||||
filterMode: "filter",
|
||||
},
|
||||
],
|
||||
calculable: true,
|
||||
xAxis: {
|
||||
type: "category",
|
||||
boundaryGap: false,
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
data: this.resX,
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: "line",
|
||||
data: this.res2Y,
|
||||
lineStyle: {
|
||||
color: "#32C5FF",
|
||||
},
|
||||
itemStyle: {
|
||||
color: "#31C1FA",
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
// 宣发任务数
|
||||
getBrokenEcharts3() {
|
||||
this.brokenEcharts3 = echarts.init(
|
||||
document.getElementById("brokenEcharts3")
|
||||
);
|
||||
this.brokenEcharts3.setOption({
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
},
|
||||
grid: {
|
||||
left: "2%",
|
||||
right: "5%",
|
||||
bottom: "2%",
|
||||
containLabel: true,
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: "slider",
|
||||
xAxisIndex: [0],
|
||||
filterMode: "filter",
|
||||
},
|
||||
],
|
||||
xAxis: {
|
||||
type: "category",
|
||||
boundaryGap: false,
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
data: this.resX,
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: "line",
|
||||
data: this.res3Y,
|
||||
lineStyle: {
|
||||
color: "#FFAA44",
|
||||
},
|
||||
itemStyle: {
|
||||
color: "#FFAA44",
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
|
||||
// 宣发明细
|
||||
getColData() {
|
||||
this.$http.post(`/app/appmasssendingtask/statisticsDepart`, null, {
|
||||
params: {
|
||||
type: this.detailType,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.code ===0) {
|
||||
if(res.data && res.data.length) {
|
||||
this.colData = res.data
|
||||
let items = [], xData = [], yData = []
|
||||
res.data.forEach((item) => {
|
||||
const i = {type: 'departmentName', id: item.deptId, corpid: this.user.corpId}
|
||||
items.push(i)
|
||||
yData.push(item.taskCount)
|
||||
})
|
||||
|
||||
this.initOpenData({canvas:true})
|
||||
setTimeout(() => {
|
||||
this.transCanvas(items).then((data) => {
|
||||
data.items.map((a) => {
|
||||
xData.push(a.data)
|
||||
})
|
||||
this.getColumnarEcharts(xData, yData)
|
||||
})
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
// 柱状图
|
||||
getColumnarEcharts(xData, yData) {
|
||||
this.columnarEcharts = echarts.init(
|
||||
document.getElementById("columnarEcharts")
|
||||
);
|
||||
this.columnarEcharts.setOption({
|
||||
dataZoom: [
|
||||
{
|
||||
type: "slider",
|
||||
xAxisIndex: [0],
|
||||
filterMode: "filter",
|
||||
},
|
||||
],
|
||||
xAxis: {
|
||||
type: "category",
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
data: xData,
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: yData,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: "#5087ec",
|
||||
label: {
|
||||
show: true, //开启显示
|
||||
position: 'top', //在上方显示
|
||||
textStyle: {
|
||||
fontSize: 13,
|
||||
color: '#666'
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
type: "bar",
|
||||
barWidth: 22,
|
||||
barGap: '20%',
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
// 选择部门
|
||||
getDept() {
|
||||
this.selectEnterpriseContact({
|
||||
fromDepartmentId: 0,
|
||||
mode: "single",
|
||||
type: ["department"],
|
||||
selectedDepartmentIds: this.departList?.map(e => e.id)
|
||||
}).then((res)=>{
|
||||
if(res?.departmentList) {
|
||||
this.departmentId = res.departmentList[0].id
|
||||
}
|
||||
}
|
||||
).catch((err) => {
|
||||
console.log(err);
|
||||
})
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppPropagandaStatistics {
|
||||
.calendar_header {
|
||||
padding: 26px 32px;
|
||||
box-sizing: border-box;
|
||||
background: #fff;
|
||||
::v-deep .u-section__title__text {
|
||||
font-size: 32px;
|
||||
}
|
||||
}
|
||||
.threeDays {
|
||||
background: #fff;
|
||||
padding: 8px 32px 12px 32px;
|
||||
box-sizing: border-box;
|
||||
.yesterday,
|
||||
.today,
|
||||
.tomorrow {
|
||||
background: #f7f8fa;
|
||||
margin-bottom: 32px;
|
||||
padding: 30px 0 30px 40px;
|
||||
box-sizing: border-box;
|
||||
.isShow {
|
||||
color: #3aa0ff;
|
||||
}
|
||||
.itemYesterday,
|
||||
.itemToday,
|
||||
.itemTomorrow {
|
||||
color: #999999;
|
||||
span {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.yesterday {
|
||||
border-left: 6px solid #fbd444;
|
||||
}
|
||||
.today {
|
||||
border-left: 6px solid #50cb74;
|
||||
}
|
||||
.tomorrow {
|
||||
border-left: 6px solid #3aa0ff;
|
||||
}
|
||||
}
|
||||
|
||||
.brokenEcharts,
|
||||
.columnarEcharts {
|
||||
margin: 24px 0 24px 0;
|
||||
padding: 0 32px 32px 32px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.broken_title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
height: 96px;
|
||||
align-items: center;
|
||||
|
||||
.broken_left {
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.broken_right {
|
||||
font-size: 24px;
|
||||
|
||||
img {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
span {
|
||||
margin-right: 12px;
|
||||
width: 108px;
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.active {
|
||||
background: #3399ff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.broken_statistics {
|
||||
display: flex;
|
||||
padding: 24px 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
.broken_item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
|
||||
div:first-child {
|
||||
font-size: 24px;
|
||||
color: #999999;
|
||||
padding: 10px 0;
|
||||
}
|
||||
div:last-child {
|
||||
font-size: 36px;
|
||||
color: #000000;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
padding: 30px 0;
|
||||
box-sizing: border-box;
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.brokenEcharts,
|
||||
.columnarEcharts {
|
||||
background: #fff;
|
||||
|
||||
#brokenEcharts1,
|
||||
#brokenEcharts2,
|
||||
#brokenEcharts3,
|
||||
#columnarEcharts {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
background: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.popup {
|
||||
box-sizing: border-box;
|
||||
.tips {
|
||||
width: 80px;
|
||||
height: 6px;
|
||||
background: #dddddd;
|
||||
border-radius: 4px;
|
||||
padding: 0 32px;
|
||||
box-sizing: border-box;
|
||||
margin: 32px auto 8px auto;
|
||||
}
|
||||
.title {
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
font-size: 34px;
|
||||
font-family: PingFangSC-Medium, PingFang SC;
|
||||
font-weight: 500;
|
||||
color: #222;
|
||||
padding: 0 32px;
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 32px;
|
||||
.cancel {
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
color: #aaa;
|
||||
}
|
||||
.confirm {
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
text-align: right;
|
||||
color: #333;
|
||||
}
|
||||
p {
|
||||
display: inline-block;
|
||||
width: calc(100% - 400px);
|
||||
text-align: center;
|
||||
font-size: 28px;
|
||||
}
|
||||
}
|
||||
.select-content {
|
||||
height: calc(100% - 100px);
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.type-list {
|
||||
padding: 0 32px;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 32px;
|
||||
.type-title {
|
||||
line-height: 108px;
|
||||
font-size: 32px;
|
||||
font-family: PingFangSC-Medium, PingFang SC;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
.item {
|
||||
display: inline-block;
|
||||
width: 210px;
|
||||
text-align: center;
|
||||
line-height: 64px;
|
||||
background: #f3f4f7;
|
||||
border-radius: 4px;
|
||||
margin: 0 16px 16px 0;
|
||||
font-size: 28px;
|
||||
font-family: PingFangSC-Regular, PingFang SC;
|
||||
color: #333;
|
||||
}
|
||||
.active {
|
||||
background: #1365dd;
|
||||
color: #fff;
|
||||
}
|
||||
.dept {
|
||||
display: flex;
|
||||
justify-content: space-between
|
||||
}
|
||||
}
|
||||
.popBtn {
|
||||
display: flex;
|
||||
height: 98px;
|
||||
line-height: 98px;
|
||||
div {
|
||||
width: 50%;
|
||||
border: 2px solid #3399ff;
|
||||
text-align: center;
|
||||
}
|
||||
div:first-child {
|
||||
color: #3399ff;
|
||||
}
|
||||
div:last-child {
|
||||
color: #fff;
|
||||
background: #3399ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.customPop {
|
||||
padding: 80px 32px 20px 32px;
|
||||
box-sizing: border-box;
|
||||
height: 660px;
|
||||
|
||||
.startTime,
|
||||
.endTime {
|
||||
border-bottom: 1px solid #ddd;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.timeBtn {
|
||||
width: 100%;
|
||||
background: #3399ff;
|
||||
height: 80px;
|
||||
line-height: 80px;
|
||||
text-align: center;
|
||||
border-radius: 16px;
|
||||
color: #fff;
|
||||
margin-top: 164px;
|
||||
}
|
||||
|
||||
::v-deep .u-close {
|
||||
z-index: auto;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
208
src/apps/AppPropagandaStatistics/calendarInfo.vue
Normal file
@@ -0,0 +1,208 @@
|
||||
<template>
|
||||
<div class="calendarInfo">
|
||||
<div class="calendar">
|
||||
<uni-calendar :insert="true" :selected="selected" :lunar="false" @bindDateChange="setDate" @change="change" @monthSwitch="changeMonth"/>
|
||||
</div>
|
||||
|
||||
<div class="dailyMatters">
|
||||
<div v-if="list && list.length">
|
||||
<div>
|
||||
<div v-for="(item, index) in list.slice(0,3)" :key="index" :class="{'color1':index%4==0,'color2':index%4==1,'color3':index%4==2,'color4':index%4==3}" class="daily_item">
|
||||
<div>{{ item.createTime.substring(10, 16) }}</div>
|
||||
<div>{{ item.taskTitle }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="show">
|
||||
<div v-for="(item, index) in list.slice(3, list.length)" :key="index"
|
||||
:class="{'color1': index % 4 == 3,'color2': index % 4 == 0,'color3': index % 4 == 1,'color4': index % 4 == 2 }" class="daily_item">
|
||||
<div>{{ item.createTime.substring(10, 16) }}</div>
|
||||
<div>{{ item.taskTitle }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="readMore" v-show="!show && list.length > 3" @click="show = true">查看更多</div>
|
||||
</div>
|
||||
<AiEmpty description="暂无宣发" v-else></AiEmpty>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uniCalendar from "./uni-calendar/uni-calendar.vue"
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
date: '',
|
||||
selected: [{date: ''}],
|
||||
list: [],
|
||||
show: false,
|
||||
calendarList: {},
|
||||
year: '',
|
||||
month: '',
|
||||
day: '',
|
||||
yyyyMM: '',
|
||||
}
|
||||
},
|
||||
components: {
|
||||
uniCalendar
|
||||
},
|
||||
created() {
|
||||
this.getNowDay()
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
// 切换月
|
||||
changeMonth(e) {
|
||||
if(e.month<=9) {
|
||||
this.yyyyMM = e.year + '0' + e.month
|
||||
|
||||
} else if(e.month > 9) {
|
||||
this.yyyyMM = e.year + e.month
|
||||
}
|
||||
this.month = e.month
|
||||
this.getData()
|
||||
},
|
||||
// 切换日
|
||||
change(val) {
|
||||
this.date = val.fulldate
|
||||
this.day = val.date
|
||||
this.getData()
|
||||
},
|
||||
|
||||
setDate(v) {
|
||||
this.yyyyMM = v.detail.value.replace('-', '')
|
||||
this.getData()
|
||||
},
|
||||
|
||||
getNowDay() {
|
||||
const date = new Date()
|
||||
this.year = date.getFullYear()
|
||||
this.month = date.getMonth() + 1
|
||||
this.day = date.getDate()
|
||||
},
|
||||
|
||||
toGroup() {
|
||||
uni.navigateTo({url: './groupSendResident'})
|
||||
},
|
||||
getData() {
|
||||
this.$http.post(`/app/appmasssendingtask/statisticsCalendar`, null, {
|
||||
params: {
|
||||
yyyyMM: this.yyyyMM,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res?.data) {
|
||||
this.calendarList = res.data;
|
||||
let arr = Object.keys(res.data).map(key => (res.data[key]))
|
||||
this.list = arr[this.day - 1]?.taskList
|
||||
let calList = arr.filter(item=> (item.taskList && item.taskList.length > 0))
|
||||
this.selected = calList.map(item=> {
|
||||
if(item.day>=1 && item.day<=9) {
|
||||
if(this.month>=1 && this.month <=9) {
|
||||
return {
|
||||
date: this.year + '-' + '0' + this.month + '-' + '0' + item.day
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
date: this.year + '-' + this.month + '-' + '0' + item.day
|
||||
}
|
||||
}
|
||||
} else if(item.day> 9) {
|
||||
if(this.month > 9) {
|
||||
return {
|
||||
date: this.year + '-' + this.month + '-' + item.day
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
date: this.year + '-' + '0' + this.month + '-' + item.day
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
onShow() {
|
||||
document.title = '宣发日历'
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.calendarInfo {
|
||||
::v-deep .uni-calendar-item__weeks-box-circle {
|
||||
top: 77%;
|
||||
right: 45%;
|
||||
border-radius: 12px;
|
||||
}
|
||||
::v-deep .uni-calendar__header {
|
||||
height: 76px;
|
||||
justify-content: space-around;
|
||||
border-bottom-style: none;
|
||||
}
|
||||
::v-deep .uni-calendar__weeks-day {
|
||||
border-bottom-style: none;
|
||||
}
|
||||
::v-deep .uni-calendar__weeks-day-text,
|
||||
::v-deep .uni-calendar__header-text,
|
||||
::v-deep .uni-calendar-item__weeks-box-text {
|
||||
font-size: 28px;
|
||||
}
|
||||
::v-deep .uni-calendar__header-btn {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-left-color: #5297FF;
|
||||
border-top-color: #5297FF;
|
||||
}
|
||||
::v-deep .uni-calendar__backtoday {
|
||||
display: none
|
||||
}
|
||||
|
||||
::v-deep .calendarInfo .calendar {
|
||||
height: 750px !important;
|
||||
}
|
||||
|
||||
.calendar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 750px;
|
||||
}
|
||||
|
||||
.dailyMatters {
|
||||
padding: 750px 30px 30px 30px;
|
||||
box-sizing: border-box;
|
||||
.daily_item {
|
||||
background: #FFF;
|
||||
padding: 30px 20px 30px 50px;
|
||||
margin-bottom: 30px;
|
||||
border-radius: 0px 16px 16px 0px;
|
||||
|
||||
div:first-child {
|
||||
color: #999999;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
.color1 {
|
||||
border-left: 6px solid #3AA0FF;
|
||||
}
|
||||
.color2 {
|
||||
border-left: 6px solid #50CB74;
|
||||
}
|
||||
.color3 {
|
||||
border-left: 6px solid #9D73D9;
|
||||
}
|
||||
.color4 {
|
||||
border-left: 6px solid #435289;
|
||||
}
|
||||
|
||||
.readMore {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
color: #3F8DF5;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
BIN
src/apps/AppPropagandaStatistics/images/shaixuan.png
Normal file
|
After Width: | Height: | Size: 663 B |
546
src/apps/AppPropagandaStatistics/uni-calendar/calendar.js
Normal file
@@ -0,0 +1,546 @@
|
||||
/**
|
||||
* @1900-2100区间内的公历、农历互转
|
||||
* @charset UTF-8
|
||||
* @github https://github.com/jjonline/calendar.js
|
||||
* @Author Jea杨(JJonline@JJonline.Cn)
|
||||
* @Time 2014-7-21
|
||||
* @Time 2016-8-13 Fixed 2033hex、Attribution Annals
|
||||
* @Time 2016-9-25 Fixed lunar LeapMonth Param Bug
|
||||
* @Time 2017-7-24 Fixed use getTerm Func Param Error.use solar year,NOT lunar year
|
||||
* @Version 1.0.3
|
||||
* @公历转农历:calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0]
|
||||
* @农历转公历:calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0]
|
||||
*/
|
||||
/* eslint-disable */
|
||||
var calendar = {
|
||||
|
||||
/**
|
||||
* 农历1900-2100的润大小信息表
|
||||
* @Array Of Property
|
||||
* @return Hex
|
||||
*/
|
||||
lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909
|
||||
0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919
|
||||
0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929
|
||||
0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939
|
||||
0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949
|
||||
0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959
|
||||
0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969
|
||||
0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979
|
||||
0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989
|
||||
0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999
|
||||
0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009
|
||||
0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019
|
||||
0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029
|
||||
0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039
|
||||
0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049
|
||||
/** Add By JJonline@JJonline.Cn**/
|
||||
0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059
|
||||
0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069
|
||||
0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079
|
||||
0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089
|
||||
0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099
|
||||
0x0d520], // 2100
|
||||
|
||||
/**
|
||||
* 公历每个月份的天数普通表
|
||||
* @Array Of Property
|
||||
* @return Number
|
||||
*/
|
||||
solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
|
||||
|
||||
/**
|
||||
* 天干地支之天干速查表
|
||||
* @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
|
||||
* @return Cn string
|
||||
*/
|
||||
Gan: ['\u7532', '\u4e59', '\u4e19', '\u4e01', '\u620a', '\u5df1', '\u5e9a', '\u8f9b', '\u58ec', '\u7678'],
|
||||
|
||||
/**
|
||||
* 天干地支之地支速查表
|
||||
* @Array Of Property
|
||||
* @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
|
||||
* @return Cn string
|
||||
*/
|
||||
Zhi: ['\u5b50', '\u4e11', '\u5bc5', '\u536f', '\u8fb0', '\u5df3', '\u5348', '\u672a', '\u7533', '\u9149', '\u620c', '\u4ea5'],
|
||||
|
||||
/**
|
||||
* 天干地支之地支速查表<=>生肖
|
||||
* @Array Of Property
|
||||
* @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
|
||||
* @return Cn string
|
||||
*/
|
||||
Animals: ['\u9f20', '\u725b', '\u864e', '\u5154', '\u9f99', '\u86c7', '\u9a6c', '\u7f8a', '\u7334', '\u9e21', '\u72d7', '\u732a'],
|
||||
|
||||
/**
|
||||
* 24节气速查表
|
||||
* @Array Of Property
|
||||
* @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
|
||||
* @return Cn string
|
||||
*/
|
||||
solarTerm: ['\u5c0f\u5bd2', '\u5927\u5bd2', '\u7acb\u6625', '\u96e8\u6c34', '\u60ca\u86f0', '\u6625\u5206', '\u6e05\u660e', '\u8c37\u96e8', '\u7acb\u590f', '\u5c0f\u6ee1', '\u8292\u79cd', '\u590f\u81f3', '\u5c0f\u6691', '\u5927\u6691', '\u7acb\u79cb', '\u5904\u6691', '\u767d\u9732', '\u79cb\u5206', '\u5bd2\u9732', '\u971c\u964d', '\u7acb\u51ac', '\u5c0f\u96ea', '\u5927\u96ea', '\u51ac\u81f3'],
|
||||
|
||||
/**
|
||||
* 1900-2100各年的24节气日期速查表
|
||||
* @Array Of Property
|
||||
* @return 0x string For splice
|
||||
*/
|
||||
sTermInfo: ['9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f',
|
||||
'97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||
'97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa',
|
||||
'97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f',
|
||||
'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f',
|
||||
'97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa',
|
||||
'97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2',
|
||||
'9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f',
|
||||
'97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||
'97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||
'97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722',
|
||||
'9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f',
|
||||
'97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||
'97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||
'97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722',
|
||||
'9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f',
|
||||
'97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
|
||||
'97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
|
||||
'9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722',
|
||||
'7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||
'97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||
'97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
|
||||
'9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722',
|
||||
'7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||
'97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||
'97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
|
||||
'9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722',
|
||||
'7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
|
||||
'97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
|
||||
'9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
|
||||
'7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
|
||||
'7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||
'97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
|
||||
'9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
|
||||
'7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
|
||||
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||
'97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
|
||||
'9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
|
||||
'7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721',
|
||||
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2',
|
||||
'977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
|
||||
'7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
|
||||
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd',
|
||||
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
|
||||
'977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
|
||||
'7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
|
||||
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd',
|
||||
'7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
|
||||
'977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
|
||||
'7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721',
|
||||
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5',
|
||||
'7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722',
|
||||
'7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
|
||||
'7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
|
||||
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35',
|
||||
'7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
|
||||
'7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721',
|
||||
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd',
|
||||
'7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35',
|
||||
'7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
|
||||
'7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721',
|
||||
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5',
|
||||
'7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35',
|
||||
'665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
|
||||
'7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
|
||||
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35',
|
||||
'7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722'],
|
||||
|
||||
/**
|
||||
* 数字转中文速查表
|
||||
* @Array Of Property
|
||||
* @trans ['日','一','二','三','四','五','六','七','八','九','十']
|
||||
* @return Cn string
|
||||
*/
|
||||
nStr1: ['\u65e5', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341'],
|
||||
|
||||
/**
|
||||
* 日期转农历称呼速查表
|
||||
* @Array Of Property
|
||||
* @trans ['初','十','廿','卅']
|
||||
* @return Cn string
|
||||
*/
|
||||
nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'],
|
||||
|
||||
/**
|
||||
* 月份转农历称呼速查表
|
||||
* @Array Of Property
|
||||
* @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊']
|
||||
* @return Cn string
|
||||
*/
|
||||
nStr3: ['\u6b63', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d', '\u5341', '\u51ac', '\u814a'],
|
||||
|
||||
/**
|
||||
* 返回农历y年一整年的总天数
|
||||
* @param lunar Year
|
||||
* @return Number
|
||||
* @eg:var count = calendar.lYearDays(1987) ;//count=387
|
||||
*/
|
||||
lYearDays: function (y) {
|
||||
var i; var sum = 348
|
||||
for (i = 0x8000; i > 0x8; i >>= 1) { sum += (this.lunarInfo[y - 1900] & i) ? 1 : 0 }
|
||||
return (sum + this.leapDays(y))
|
||||
},
|
||||
|
||||
/**
|
||||
* 返回农历y年闰月是哪个月;若y年没有闰月 则返回0
|
||||
* @param lunar Year
|
||||
* @return Number (0-12)
|
||||
* @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6
|
||||
*/
|
||||
leapMonth: function (y) { // 闰字编码 \u95f0
|
||||
return (this.lunarInfo[y - 1900] & 0xf)
|
||||
},
|
||||
|
||||
/**
|
||||
* 返回农历y年闰月的天数 若该年没有闰月则返回0
|
||||
* @param lunar Year
|
||||
* @return Number (0、29、30)
|
||||
* @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29
|
||||
*/
|
||||
leapDays: function (y) {
|
||||
if (this.leapMonth(y)) {
|
||||
return ((this.lunarInfo[y - 1900] & 0x10000) ? 30 : 29)
|
||||
}
|
||||
return (0)
|
||||
},
|
||||
|
||||
/**
|
||||
* 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法
|
||||
* @param lunar Year
|
||||
* @return Number (-1、29、30)
|
||||
* @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29
|
||||
*/
|
||||
monthDays: function (y, m) {
|
||||
if (m > 12 || m < 1) { return -1 }// 月份参数从1至12,参数错误返回-1
|
||||
return ((this.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29)
|
||||
},
|
||||
|
||||
/**
|
||||
* 返回公历(!)y年m月的天数
|
||||
* @param solar Year
|
||||
* @return Number (-1、28、29、30、31)
|
||||
* @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30
|
||||
*/
|
||||
solarDays: function (y, m) {
|
||||
if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
|
||||
var ms = m - 1
|
||||
if (ms == 1) { // 2月份的闰平规律测算后确认返回28或29
|
||||
return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28)
|
||||
} else {
|
||||
return (this.solarMonth[ms])
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 农历年份转换为干支纪年
|
||||
* @param lYear 农历年的年份数
|
||||
* @return Cn string
|
||||
*/
|
||||
toGanZhiYear: function (lYear) {
|
||||
var ganKey = (lYear - 3) % 10
|
||||
var zhiKey = (lYear - 3) % 12
|
||||
if (ganKey == 0) ganKey = 10// 如果余数为0则为最后一个天干
|
||||
if (zhiKey == 0) zhiKey = 12// 如果余数为0则为最后一个地支
|
||||
return this.Gan[ganKey - 1] + this.Zhi[zhiKey - 1]
|
||||
},
|
||||
|
||||
/**
|
||||
* 公历月、日判断所属星座
|
||||
* @param cMonth [description]
|
||||
* @param cDay [description]
|
||||
* @return Cn string
|
||||
*/
|
||||
toAstro: function (cMonth, cDay) {
|
||||
var s = '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf'
|
||||
var arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]
|
||||
return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7'// 座
|
||||
},
|
||||
|
||||
/**
|
||||
* 传入offset偏移量返回干支
|
||||
* @param offset 相对甲子的偏移量
|
||||
* @return Cn string
|
||||
*/
|
||||
toGanZhi: function (offset) {
|
||||
return this.Gan[offset % 10] + this.Zhi[offset % 12]
|
||||
},
|
||||
|
||||
/**
|
||||
* 传入公历(!)y年获得该年第n个节气的公历日期
|
||||
* @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起
|
||||
* @return day Number
|
||||
* @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春
|
||||
*/
|
||||
getTerm: function (y, n) {
|
||||
if (y < 1900 || y > 2100) { return -1 }
|
||||
if (n < 1 || n > 24) { return -1 }
|
||||
var _table = this.sTermInfo[y - 1900]
|
||||
var _info = [
|
||||
parseInt('0x' + _table.substr(0, 5)).toString(),
|
||||
parseInt('0x' + _table.substr(5, 5)).toString(),
|
||||
parseInt('0x' + _table.substr(10, 5)).toString(),
|
||||
parseInt('0x' + _table.substr(15, 5)).toString(),
|
||||
parseInt('0x' + _table.substr(20, 5)).toString(),
|
||||
parseInt('0x' + _table.substr(25, 5)).toString()
|
||||
]
|
||||
var _calday = [
|
||||
_info[0].substr(0, 1),
|
||||
_info[0].substr(1, 2),
|
||||
_info[0].substr(3, 1),
|
||||
_info[0].substr(4, 2),
|
||||
|
||||
_info[1].substr(0, 1),
|
||||
_info[1].substr(1, 2),
|
||||
_info[1].substr(3, 1),
|
||||
_info[1].substr(4, 2),
|
||||
|
||||
_info[2].substr(0, 1),
|
||||
_info[2].substr(1, 2),
|
||||
_info[2].substr(3, 1),
|
||||
_info[2].substr(4, 2),
|
||||
|
||||
_info[3].substr(0, 1),
|
||||
_info[3].substr(1, 2),
|
||||
_info[3].substr(3, 1),
|
||||
_info[3].substr(4, 2),
|
||||
|
||||
_info[4].substr(0, 1),
|
||||
_info[4].substr(1, 2),
|
||||
_info[4].substr(3, 1),
|
||||
_info[4].substr(4, 2),
|
||||
|
||||
_info[5].substr(0, 1),
|
||||
_info[5].substr(1, 2),
|
||||
_info[5].substr(3, 1),
|
||||
_info[5].substr(4, 2)
|
||||
]
|
||||
return parseInt(_calday[n - 1])
|
||||
},
|
||||
|
||||
/**
|
||||
* 传入农历数字月份返回汉语通俗表示法
|
||||
* @param lunar month
|
||||
* @return Cn string
|
||||
* @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月'
|
||||
*/
|
||||
toChinaMonth: function (m) { // 月 => \u6708
|
||||
if (m > 12 || m < 1) { return -1 } // 若参数错误 返回-1
|
||||
var s = this.nStr3[m - 1]
|
||||
s += '\u6708'// 加上月字
|
||||
return s
|
||||
},
|
||||
|
||||
/**
|
||||
* 传入农历日期数字返回汉字表示法
|
||||
* @param lunar day
|
||||
* @return Cn string
|
||||
* @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一'
|
||||
*/
|
||||
toChinaDay: function (d) { // 日 => \u65e5
|
||||
var s
|
||||
switch (d) {
|
||||
case 10:
|
||||
s = '\u521d\u5341'; break
|
||||
case 20:
|
||||
s = '\u4e8c\u5341'; break
|
||||
break
|
||||
case 30:
|
||||
s = '\u4e09\u5341'; break
|
||||
break
|
||||
default :
|
||||
s = this.nStr2[Math.floor(d / 10)]
|
||||
s += this.nStr1[d % 10]
|
||||
}
|
||||
return (s)
|
||||
},
|
||||
|
||||
/**
|
||||
* 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春”
|
||||
* @param y year
|
||||
* @return Cn string
|
||||
* @eg:var animal = calendar.getAnimal(1987) ;//animal='兔'
|
||||
*/
|
||||
getAnimal: function (y) {
|
||||
return this.Animals[(y - 4) % 12]
|
||||
},
|
||||
|
||||
/**
|
||||
* 传入阳历年月日获得详细的公历、农历object信息 <=>JSON
|
||||
* @param y solar year
|
||||
* @param m solar month
|
||||
* @param d solar day
|
||||
* @return JSON object
|
||||
* @eg:console.log(calendar.solar2lunar(1987,11,01));
|
||||
*/
|
||||
solar2lunar: function (y, m, d) { // 参数区间1900.1.31~2100.12.31
|
||||
// 年份限定、上限
|
||||
if (y < 1900 || y > 2100) {
|
||||
return -1// undefined转换为数字变为NaN
|
||||
}
|
||||
// 公历传参最下限
|
||||
if (y == 1900 && m == 1 && d < 31) {
|
||||
return -1
|
||||
}
|
||||
// 未传参 获得当天
|
||||
if (!y) {
|
||||
var objDate = new Date()
|
||||
} else {
|
||||
var objDate = new Date(y, parseInt(m) - 1, d)
|
||||
}
|
||||
var i; var leap = 0; var temp = 0
|
||||
// 修正ymd参数
|
||||
var y = objDate.getFullYear()
|
||||
var m = objDate.getMonth() + 1
|
||||
var d = objDate.getDate()
|
||||
var offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) / 86400000
|
||||
for (i = 1900; i < 2101 && offset > 0; i++) {
|
||||
temp = this.lYearDays(i)
|
||||
offset -= temp
|
||||
}
|
||||
if (offset < 0) {
|
||||
offset += temp; i--
|
||||
}
|
||||
|
||||
// 是否今天
|
||||
var isTodayObj = new Date()
|
||||
var isToday = false
|
||||
if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) {
|
||||
isToday = true
|
||||
}
|
||||
// 星期几
|
||||
var nWeek = objDate.getDay()
|
||||
var cWeek = this.nStr1[nWeek]
|
||||
// 数字表示周几顺应天朝周一开始的惯例
|
||||
if (nWeek == 0) {
|
||||
nWeek = 7
|
||||
}
|
||||
// 农历年
|
||||
var year = i
|
||||
var leap = this.leapMonth(i) // 闰哪个月
|
||||
var isLeap = false
|
||||
|
||||
// 效验闰月
|
||||
for (i = 1; i < 13 && offset > 0; i++) {
|
||||
// 闰月
|
||||
if (leap > 0 && i == (leap + 1) && isLeap == false) {
|
||||
--i
|
||||
isLeap = true; temp = this.leapDays(year) // 计算农历闰月天数
|
||||
} else {
|
||||
temp = this.monthDays(year, i)// 计算农历普通月天数
|
||||
}
|
||||
// 解除闰月
|
||||
if (isLeap == true && i == (leap + 1)) { isLeap = false }
|
||||
offset -= temp
|
||||
}
|
||||
// 闰月导致数组下标重叠取反
|
||||
if (offset == 0 && leap > 0 && i == leap + 1) {
|
||||
if (isLeap) {
|
||||
isLeap = false
|
||||
} else {
|
||||
isLeap = true; --i
|
||||
}
|
||||
}
|
||||
if (offset < 0) {
|
||||
offset += temp; --i
|
||||
}
|
||||
// 农历月
|
||||
var month = i
|
||||
// 农历日
|
||||
var day = offset + 1
|
||||
// 天干地支处理
|
||||
var sm = m - 1
|
||||
var gzY = this.toGanZhiYear(year)
|
||||
|
||||
// 当月的两个节气
|
||||
// bugfix-2017-7-24 11:03:38 use lunar Year Param `y` Not `year`
|
||||
var firstNode = this.getTerm(y, (m * 2 - 1))// 返回当月「节」为几日开始
|
||||
var secondNode = this.getTerm(y, (m * 2))// 返回当月「节」为几日开始
|
||||
|
||||
// 依据12节气修正干支月
|
||||
var gzM = this.toGanZhi((y - 1900) * 12 + m + 11)
|
||||
if (d >= firstNode) {
|
||||
gzM = this.toGanZhi((y - 1900) * 12 + m + 12)
|
||||
}
|
||||
|
||||
// 传入的日期的节气与否
|
||||
var isTerm = false
|
||||
var Term = null
|
||||
if (firstNode == d) {
|
||||
isTerm = true
|
||||
Term = this.solarTerm[m * 2 - 2]
|
||||
}
|
||||
if (secondNode == d) {
|
||||
isTerm = true
|
||||
Term = this.solarTerm[m * 2 - 1]
|
||||
}
|
||||
// 日柱 当月一日与 1900/1/1 相差天数
|
||||
var dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10
|
||||
var gzD = this.toGanZhi(dayCyclical + d - 1)
|
||||
// 该日期所属的星座
|
||||
var astro = this.toAstro(m, d)
|
||||
|
||||
return { 'lYear': year, 'lMonth': month, 'lDay': day, 'Animal': this.getAnimal(year), 'IMonthCn': (isLeap ? '\u95f0' : '') + this.toChinaMonth(month), 'IDayCn': this.toChinaDay(day), 'cYear': y, 'cMonth': m, 'cDay': d, 'gzYear': gzY, 'gzMonth': gzM, 'gzDay': gzD, 'isToday': isToday, 'isLeap': isLeap, 'nWeek': nWeek, 'ncWeek': '\u661f\u671f' + cWeek, 'isTerm': isTerm, 'Term': Term, 'astro': astro }
|
||||
},
|
||||
|
||||
/**
|
||||
* 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON
|
||||
* @param y lunar year
|
||||
* @param m lunar month
|
||||
* @param d lunar day
|
||||
* @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可]
|
||||
* @return JSON object
|
||||
* @eg:console.log(calendar.lunar2solar(1987,9,10));
|
||||
*/
|
||||
lunar2solar: function (y, m, d, isLeapMonth) { // 参数区间1900.1.31~2100.12.1
|
||||
var isLeapMonth = !!isLeapMonth
|
||||
var leapOffset = 0
|
||||
var leapMonth = this.leapMonth(y)
|
||||
var leapDay = this.leapDays(y)
|
||||
if (isLeapMonth && (leapMonth != m)) { return -1 }// 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
|
||||
if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) { return -1 }// 超出了最大极限值
|
||||
var day = this.monthDays(y, m)
|
||||
var _day = day
|
||||
// bugFix 2016-9-25
|
||||
// if month is leap, _day use leapDays method
|
||||
if (isLeapMonth) {
|
||||
_day = this.leapDays(y, m)
|
||||
}
|
||||
if (y < 1900 || y > 2100 || d > _day) { return -1 }// 参数合法性效验
|
||||
|
||||
// 计算农历的时间差
|
||||
var offset = 0
|
||||
for (var i = 1900; i < y; i++) {
|
||||
offset += this.lYearDays(i)
|
||||
}
|
||||
var leap = 0; var isAdd = false
|
||||
for (var i = 1; i < m; i++) {
|
||||
leap = this.leapMonth(y)
|
||||
if (!isAdd) { // 处理闰月
|
||||
if (leap <= i && leap > 0) {
|
||||
offset += this.leapDays(y); isAdd = true
|
||||
}
|
||||
}
|
||||
offset += this.monthDays(y, i)
|
||||
}
|
||||
// 转换闰月农历 需补充该年闰月的前一个月的时差
|
||||
if (isLeapMonth) { offset += day }
|
||||
// 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点)
|
||||
var stmap = Date.UTC(1900, 1, 30, 0, 0, 0)
|
||||
var calObj = new Date((offset + d - 31) * 86400000 + stmap)
|
||||
var cY = calObj.getUTCFullYear()
|
||||
var cM = calObj.getUTCMonth() + 1
|
||||
var cD = calObj.getUTCDate()
|
||||
|
||||
return this.solar2lunar(cY, cM, cD)
|
||||
}
|
||||
}
|
||||
|
||||
export default calendar
|
||||
12
src/apps/AppPropagandaStatistics/uni-calendar/i18n/en.json
Normal file
@@ -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": "六"
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
<template>
|
||||
<view class="uni-calendar-item__weeks-box" :class="{
|
||||
'uni-calendar-item--disable':weeks.disable,
|
||||
'uni-calendar-item--isDay':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--after-checked':weeks.afterMultiple,
|
||||
}"
|
||||
@click="choiceDate(weeks)">
|
||||
<view class="uni-calendar-item__weeks-box-item">
|
||||
<text v-if="selected&&weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text>
|
||||
<text class="uni-calendar-item__weeks-box-text" :class="{
|
||||
'uni-calendar-item--isDay-text': 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--before-checked':weeks.beforeMultiple,
|
||||
'uni-calendar-item--multiple': weeks.multiple,
|
||||
'uni-calendar-item--after-checked':weeks.afterMultiple,
|
||||
'uni-calendar-item--disable':weeks.disable,
|
||||
}">{{weeks.date}}</text>
|
||||
<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':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--after-checked':weeks.afterMultiple,
|
||||
}">{{todayText}}</text>
|
||||
<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':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--after-checked':weeks.afterMultiple,
|
||||
'uni-calendar-item--disable':weeks.disable,
|
||||
}">{{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="{
|
||||
'uni-calendar-item--extra':weeks.extraInfo.info,
|
||||
'uni-calendar-item--isDay-text':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--before-checked':weeks.beforeMultiple,
|
||||
'uni-calendar-item--multiple': weeks.multiple,
|
||||
'uni-calendar-item--after-checked':weeks.afterMultiple,
|
||||
'uni-calendar-item--disable':weeks.disable,
|
||||
}">{{weeks.extraInfo.info}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
initVueI18n
|
||||
} from '@dcloudio/uni-i18n'
|
||||
import messages from './i18n/index.js'
|
||||
const { t } = initVueI18n(messages)
|
||||
export default {
|
||||
emits:['change'],
|
||||
props: {
|
||||
weeks: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
calendar: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
selected: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
lunar: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
todayText() {
|
||||
return t("uni-calender.today")
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
choiceDate(weeks) {
|
||||
this.$emit('change', weeks)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<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-color-primary: #2979ff;
|
||||
.uni-calendar-item__weeks-box {
|
||||
flex: 1;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-box-text {
|
||||
font-size: $uni-font-size-base;
|
||||
color: $uni-text-color;
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-lunar-text {
|
||||
font-size: $uni-font-size-sm;
|
||||
color: $uni-text-color;
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-box-item {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-box-circle {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 8px;
|
||||
background-color: $uni-color-error;
|
||||
|
||||
}
|
||||
|
||||
.uni-calendar-item--disable {
|
||||
background-color: rgba(249, 249, 249, $uni-opacity-disabled);
|
||||
color: $uni-text-color-disable;
|
||||
}
|
||||
|
||||
.uni-calendar-item--isDay-text {
|
||||
color: $uni-color-primary;
|
||||
}
|
||||
|
||||
.uni-calendar-item--isDay {
|
||||
background-color: $uni-color-primary;
|
||||
opacity: 0.8;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.uni-calendar-item--extra {
|
||||
color: $uni-color-error;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.uni-calendar-item--checked {
|
||||
background-color: $uni-color-primary;
|
||||
color: #fff;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.uni-calendar-item--multiple {
|
||||
background-color: $uni-color-primary;
|
||||
color: #fff;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.uni-calendar-item--before-checked {
|
||||
background-color: #ff5a5f;
|
||||
color: #fff;
|
||||
}
|
||||
.uni-calendar-item--after-checked {
|
||||
background-color: #ff5a5f;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
563
src/apps/AppPropagandaStatistics/uni-calendar/uni-calendar.vue
Normal file
@@ -0,0 +1,563 @@
|
||||
<template>
|
||||
<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__content" :class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow}">
|
||||
<view v-if="!insert" class="uni-calendar__header uni-calendar--fixed-top">
|
||||
<view class="uni-calendar__header-btn-box" @click="close">
|
||||
<text class="uni-calendar__header-text uni-calendar--fixed-width">{{cancelText}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__header-btn-box" @click="confirm">
|
||||
<text class="uni-calendar__header-text uni-calendar--fixed-width">{{okText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="uni-calendar__header">
|
||||
<view class="uni-calendar__header-btn-box" @click.stop="pre">
|
||||
<view class="uni-calendar__header-btn uni-calendar--left"></view>
|
||||
</view>
|
||||
<picker mode="date" :value="date" fields="month" @change="bindDateChange">
|
||||
<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>
|
||||
<text class="uni-calendar__backtoday" @click="backtoday">{{todayText}}</text>
|
||||
|
||||
</view>
|
||||
<view class="uni-calendar__box">
|
||||
<view v-if="showMonth" class="uni-calendar__box-bg">
|
||||
<text class="uni-calendar__box-bg-text">{{nowDate.month}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__weeks">
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{SUNText}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{monText}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{TUEText}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{WEDText}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{THUText}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{FRIText}}</text>
|
||||
</view>
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{SATText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<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">
|
||||
<calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar" :selected="selected" :lunar="lunar" @change="choiceDate"></calendar-item>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Calendar from './util.js';
|
||||
import calendarItem from './uni-calendar-item.vue'
|
||||
import {
|
||||
initVueI18n
|
||||
} from '@dcloudio/uni-i18n'
|
||||
import messages from './i18n/index.js'
|
||||
const { t } = initVueI18n(messages)
|
||||
/**
|
||||
* 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 {
|
||||
components: {
|
||||
calendarItem
|
||||
},
|
||||
emits:['close','confirm','change','monthSwitch'],
|
||||
props: {
|
||||
date: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
selected: {
|
||||
type: Array,
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
lunar: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
startDate: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
endDate: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
range: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
insert: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showMonth: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
clearDate: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
weeks: [],
|
||||
calendar: {},
|
||||
nowDate: '',
|
||||
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: {
|
||||
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) {
|
||||
this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
|
||||
this.weeks = this.cale.weeks
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 获取日历方法实例
|
||||
this.cale = new Calendar({
|
||||
// date: new Date(),
|
||||
selected: this.selected,
|
||||
startDate: this.startDate,
|
||||
endDate: this.endDate,
|
||||
range: this.range,
|
||||
})
|
||||
// 选中某一天
|
||||
// this.cale.setDate(this.date)
|
||||
this.init(this.date)
|
||||
// this.setDay
|
||||
},
|
||||
methods: {
|
||||
// 取消穿透
|
||||
clean() {},
|
||||
bindDateChange(e) {
|
||||
const value = e.detail.value + '-1'
|
||||
this.$emit('bindDateChange',e)
|
||||
// console.log(this.cale.getDate(value));
|
||||
this.init(value)
|
||||
},
|
||||
/**
|
||||
* 初始化日期显示
|
||||
* @param {Object} date
|
||||
*/
|
||||
init(date) {
|
||||
this.cale.setDate(date)
|
||||
this.weeks = this.cale.weeks
|
||||
this.nowDate = this.calendar = this.cale.getInfo(date)
|
||||
},
|
||||
/**
|
||||
* 打开日历弹窗
|
||||
*/
|
||||
open() {
|
||||
// 弹窗模式并且清理数据
|
||||
if (this.clearDate && !this.insert) {
|
||||
this.cale.cleanMultipleStatus()
|
||||
// this.cale.setDate(this.date)
|
||||
this.init(this.date)
|
||||
}
|
||||
this.show = true
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.aniMaskShow = true
|
||||
}, 50)
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 关闭日历弹窗
|
||||
*/
|
||||
close() {
|
||||
this.aniMaskShow = false
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.show = false
|
||||
this.$emit('close')
|
||||
}, 300)
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 确认按钮
|
||||
*/
|
||||
confirm() {
|
||||
this.setEmit('confirm')
|
||||
this.close()
|
||||
},
|
||||
/**
|
||||
* 变化触发
|
||||
*/
|
||||
change() {
|
||||
if (!this.insert) return
|
||||
this.setEmit('change')
|
||||
},
|
||||
/**
|
||||
* 选择月份触发
|
||||
*/
|
||||
monthSwitch() {
|
||||
let {
|
||||
year,
|
||||
month
|
||||
} = this.nowDate
|
||||
this.$emit('monthSwitch', {
|
||||
year,
|
||||
month: Number(month)
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 派发事件
|
||||
* @param {Object} name
|
||||
*/
|
||||
setEmit(name) {
|
||||
let {
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
fullDate,
|
||||
lunar,
|
||||
extraInfo
|
||||
} = this.calendar
|
||||
this.$emit(name, {
|
||||
range: this.cale.multipleStatus,
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
fulldate: fullDate,
|
||||
lunar,
|
||||
extraInfo: extraInfo || {}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 选择天触发
|
||||
* @param {Object} weeks
|
||||
*/
|
||||
choiceDate(weeks) {
|
||||
if (weeks.disable) return
|
||||
this.calendar = weeks
|
||||
// 设置多选
|
||||
this.cale.setMultiple(this.calendar.fullDate)
|
||||
this.weeks = this.cale.weeks
|
||||
this.change()
|
||||
},
|
||||
/**
|
||||
* 回到今天
|
||||
*/
|
||||
backtoday() {
|
||||
console.log(this.cale.getDate(new Date()).fullDate);
|
||||
let date = this.cale.getDate(new Date()).fullDate
|
||||
// this.cale.setDate(date)
|
||||
this.init(date)
|
||||
this.change()
|
||||
},
|
||||
/**
|
||||
* 上个月
|
||||
*/
|
||||
pre() {
|
||||
const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate
|
||||
this.setDate(preDate)
|
||||
this.monthSwitch()
|
||||
|
||||
},
|
||||
/**
|
||||
* 下个月
|
||||
*/
|
||||
next() {
|
||||
const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate
|
||||
this.setDate(nextDate)
|
||||
this.monthSwitch()
|
||||
},
|
||||
/**
|
||||
* 设置日期
|
||||
* @param {Object} date
|
||||
*/
|
||||
setDate(date) {
|
||||
this.cale.setDate(date)
|
||||
this.weeks = this.cale.weeks
|
||||
this.nowDate = this.cale.getInfo(date)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<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 {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.uni-calendar__mask {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: $uni-bg-color-mask;
|
||||
transition-property: opacity;
|
||||
transition-duration: 0.3s;
|
||||
opacity: 0;
|
||||
/* #ifndef APP-NVUE */
|
||||
z-index: 99;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-calendar--mask-show {
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
.uni-calendar--fixed {
|
||||
position: fixed;
|
||||
/* #ifdef APP-NVUE */
|
||||
bottom: 0;
|
||||
/* #endif */
|
||||
left: 0;
|
||||
right: 0;
|
||||
transition-property: transform;
|
||||
transition-duration: 0.3s;
|
||||
transform: translateY(460px);
|
||||
/* #ifndef APP-NVUE */
|
||||
bottom: calc(var(--window-bottom));
|
||||
z-index: 99;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-calendar--ani-show {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.uni-calendar__content {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.uni-calendar__header {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 50px;
|
||||
border-bottom-color: $uni-border-color;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
.uni-calendar--fixed-top {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
border-top-color: $uni-border-color;
|
||||
border-top-style: solid;
|
||||
border-top-width: 1px;
|
||||
}
|
||||
|
||||
.uni-calendar--fixed-width {
|
||||
width: 50px;
|
||||
// padding: 0 15px;
|
||||
}
|
||||
|
||||
.uni-calendar__backtoday {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 25rpx;
|
||||
padding: 0 5px;
|
||||
padding-left: 10px;
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
font-size: 12px;
|
||||
border-top-left-radius: 25px;
|
||||
border-bottom-left-radius: 25px;
|
||||
color: $uni-text-color;
|
||||
background-color: $uni-bg-color-hover;
|
||||
}
|
||||
|
||||
.uni-calendar__header-text {
|
||||
text-align: center;
|
||||
width: 100px;
|
||||
font-size: $uni-font-size-base;
|
||||
color: $uni-text-color;
|
||||
}
|
||||
|
||||
.uni-calendar__header-btn-box {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.uni-calendar__header-btn {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-left-color: $uni-text-color-placeholder;
|
||||
border-left-style: solid;
|
||||
border-left-width: 2px;
|
||||
border-top-color: $uni-color-subtitle;
|
||||
border-top-style: solid;
|
||||
border-top-width: 2px;
|
||||
}
|
||||
|
||||
.uni-calendar--left {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.uni-calendar--right {
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
|
||||
|
||||
.uni-calendar__weeks {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.uni-calendar__weeks-item {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.uni-calendar__weeks-day {
|
||||
flex: 1;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 45px;
|
||||
border-bottom-color: #F5F5F5;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
.uni-calendar__weeks-day-text {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.uni-calendar__box {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.uni-calendar__box-bg {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.uni-calendar__box-bg-text {
|
||||
font-size: 200px;
|
||||
font-weight: bold;
|
||||
color: $uni-text-color-grey;
|
||||
opacity: 0.1;
|
||||
text-align: center;
|
||||
/* #ifndef APP-NVUE */
|
||||
line-height: 1;
|
||||
/* #endif */
|
||||
}
|
||||
</style>
|
||||
350
src/apps/AppPropagandaStatistics/uni-calendar/util.js
Normal file
@@ -0,0 +1,350 @@
|
||||
import CALENDAR from './calendar.js'
|
||||
|
||||
class Calendar {
|
||||
constructor({
|
||||
date,
|
||||
selected,
|
||||
startDate,
|
||||
endDate,
|
||||
range
|
||||
} = {}) {
|
||||
// 当前日期
|
||||
this.date = this.getDate(new Date()) // 当前初入日期
|
||||
// 打点信息
|
||||
this.selected = selected || [];
|
||||
// 范围开始
|
||||
this.startDate = startDate
|
||||
// 范围结束
|
||||
this.endDate = endDate
|
||||
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 = {
|
||||
before: '',
|
||||
after: '',
|
||||
data: []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置开始日期
|
||||
*/
|
||||
resetSatrtDate(startDate) {
|
||||
// 范围开始
|
||||
this.startDate = startDate
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置结束日期
|
||||
*/
|
||||
resetEndDate(endDate) {
|
||||
// 范围结束
|
||||
this.endDate = endDate
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任意时间
|
||||
*/
|
||||
getDate(date, AddDayCount = 0, str = 'day') {
|
||||
if (!date) {
|
||||
date = new Date()
|
||||
}
|
||||
if (typeof date !== 'object') {
|
||||
date = date.replace(/-/g, '/')
|
||||
}
|
||||
const dd = new Date(date)
|
||||
switch (str) {
|
||||
case 'day':
|
||||
dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
break
|
||||
case 'month':
|
||||
if (dd.getDate() === 31) {
|
||||
dd.setDate(dd.getDate() + AddDayCount)
|
||||
} else {
|
||||
dd.setMonth(dd.getMonth() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
}
|
||||
break
|
||||
case 'year':
|
||||
dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
break
|
||||
}
|
||||
const y = dd.getFullYear()
|
||||
const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
|
||||
const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
|
||||
return {
|
||||
fullDate: y + '-' + m + '-' + d,
|
||||
year: y,
|
||||
month: m,
|
||||
date: d,
|
||||
day: dd.getDay()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取上月剩余天数
|
||||
*/
|
||||
_getLastMonthDays(firstDay, full) {
|
||||
let dateArr = []
|
||||
for (let i = firstDay; i > 0; i--) {
|
||||
const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
|
||||
dateArr.push({
|
||||
date: beforeDate,
|
||||
month: full.month - 1,
|
||||
lunar: this.getlunar(full.year, full.month - 1, beforeDate),
|
||||
disable: true
|
||||
})
|
||||
}
|
||||
return dateArr
|
||||
}
|
||||
/**
|
||||
* 获取本月天数
|
||||
*/
|
||||
_currentMonthDys(dateData, full) {
|
||||
let dateArr = []
|
||||
let fullDate = this.date.fullDate
|
||||
for (let i = 1; i <= dateData; i++) {
|
||||
let nowDate = full.year + '-' + (full.month < 10 ?
|
||||
full.month : full.month) + '-' + (i < 10 ?
|
||||
'0' + i : i)
|
||||
// 是否今天
|
||||
let isDay = fullDate === nowDate
|
||||
// 获取打点信息
|
||||
let info = this.selected && this.selected.find((item) => {
|
||||
if (this.dateEqual(nowDate, item.date)) {
|
||||
return item
|
||||
}
|
||||
})
|
||||
|
||||
// 日期禁用
|
||||
let disableBefore = true
|
||||
let disableAfter = true
|
||||
if (this.startDate) {
|
||||
// let dateCompBefore = this.dateCompare(this.startDate, fullDate)
|
||||
// disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
|
||||
disableBefore = this.dateCompare(this.startDate, nowDate)
|
||||
}
|
||||
|
||||
if (this.endDate) {
|
||||
// let dateCompAfter = this.dateCompare(fullDate, this.endDate)
|
||||
// disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
|
||||
disableAfter = this.dateCompare(nowDate, this.endDate)
|
||||
}
|
||||
let multiples = this.multipleStatus.data
|
||||
let checked = false
|
||||
let multiplesStatus = -1
|
||||
if (this.range) {
|
||||
if (multiples) {
|
||||
multiplesStatus = multiples.findIndex((item) => {
|
||||
return this.dateEqual(item, nowDate)
|
||||
})
|
||||
}
|
||||
if (multiplesStatus !== -1) {
|
||||
checked = true
|
||||
}
|
||||
}
|
||||
let data = {
|
||||
fullDate: nowDate,
|
||||
year: full.year,
|
||||
date: i,
|
||||
multiple: this.range ? checked : false,
|
||||
beforeMultiple: this.dateEqual(this.multipleStatus.before, nowDate),
|
||||
afterMultiple: this.dateEqual(this.multipleStatus.after, nowDate),
|
||||
month: full.month,
|
||||
lunar: this.getlunar(full.year, full.month, i),
|
||||
disable: !(disableBefore && disableAfter),
|
||||
isDay
|
||||
}
|
||||
if (info) {
|
||||
data.extraInfo = info
|
||||
}
|
||||
|
||||
dateArr.push(data)
|
||||
}
|
||||
return dateArr
|
||||
}
|
||||
/**
|
||||
* 获取下月天数
|
||||
*/
|
||||
_getNextMonthDays(surplus, full) {
|
||||
let dateArr = []
|
||||
for (let i = 1; i < surplus + 1; i++) {
|
||||
dateArr.push({
|
||||
date: i,
|
||||
month: Number(full.month) + 1,
|
||||
lunar: this.getlunar(full.year, Number(full.month) + 1, i),
|
||||
disable: true
|
||||
})
|
||||
}
|
||||
return dateArr
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期详情
|
||||
* @param {Object} date
|
||||
*/
|
||||
getInfo(date) {
|
||||
if (!date) {
|
||||
date = new Date()
|
||||
}
|
||||
const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate)
|
||||
return dateInfo
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较时间大小
|
||||
*/
|
||||
dateCompare(startDate, endDate) {
|
||||
// 计算截止时间
|
||||
startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
|
||||
// 计算详细项的截止时间
|
||||
endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
|
||||
if (startDate <= endDate) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较时间是否相等
|
||||
*/
|
||||
dateEqual(before, after) {
|
||||
// 计算截止时间
|
||||
before = new Date(before.replace('-', '/').replace('-', '/'))
|
||||
// 计算详细项的截止时间
|
||||
after = new Date(after.replace('-', '/').replace('-', '/'))
|
||||
if (before.getTime() - after.getTime() === 0) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取日期范围内所有日期
|
||||
* @param {Object} begin
|
||||
* @param {Object} end
|
||||
*/
|
||||
geDateAll(begin, end) {
|
||||
var arr = []
|
||||
var ab = begin.split('-')
|
||||
var ae = end.split('-')
|
||||
var db = new Date()
|
||||
db.setFullYear(ab[0], ab[1] - 1, ab[2])
|
||||
var de = new Date()
|
||||
de.setFullYear(ae[0], ae[1] - 1, ae[2])
|
||||
var unixDb = db.getTime() - 24 * 60 * 60 * 1000
|
||||
var unixDe = de.getTime() - 24 * 60 * 60 * 1000
|
||||
for (var k = unixDb; k <= unixDe;) {
|
||||
k = k + 24 * 60 * 60 * 1000
|
||||
arr.push(this.getDate(new Date(parseInt(k))).fullDate)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
/**
|
||||
* 计算阴历日期显示
|
||||
*/
|
||||
getlunar(year, month, date) {
|
||||
return CALENDAR.solar2lunar(year, month, date)
|
||||
}
|
||||
/**
|
||||
* 设置打点
|
||||
*/
|
||||
setSelectInfo(data, value) {
|
||||
this.selected = value
|
||||
this._getWeek(data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取多选状态
|
||||
*/
|
||||
setMultiple(fullDate) {
|
||||
let {
|
||||
before,
|
||||
after
|
||||
} = this.multipleStatus
|
||||
|
||||
if (!this.range) return
|
||||
if (before && after) {
|
||||
this.multipleStatus.before = ''
|
||||
this.multipleStatus.after = ''
|
||||
this.multipleStatus.data = []
|
||||
} else {
|
||||
if (!before) {
|
||||
this.multipleStatus.before = fullDate
|
||||
} else {
|
||||
this.multipleStatus.after = fullDate
|
||||
if (this.dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
|
||||
this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
|
||||
} else {
|
||||
this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
|
||||
}
|
||||
}
|
||||
}
|
||||
this._getWeek(fullDate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取每周数据
|
||||
* @param {Object} dateData
|
||||
*/
|
||||
_getWeek(dateData) {
|
||||
const {
|
||||
year,
|
||||
month
|
||||
} = this.getDate(dateData)
|
||||
let firstDay = new Date(year, month - 1, 1).getDay()
|
||||
let currentDay = new Date(year, month, 0).getDate()
|
||||
let dates = {
|
||||
lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天
|
||||
currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数
|
||||
nextMonthDays: [], // 下个月开始几天
|
||||
weeks: []
|
||||
}
|
||||
let canlender = []
|
||||
const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
|
||||
dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
|
||||
canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
|
||||
let weeks = {}
|
||||
// 拼接数组 上个月开始几天 + 本月天数+ 下个月开始几天
|
||||
for (let i = 0; i < canlender.length; i++) {
|
||||
if (i % 7 === 0) {
|
||||
weeks[parseInt(i / 7)] = new Array(7)
|
||||
}
|
||||
weeks[parseInt(i / 7)][i % 7] = canlender[i]
|
||||
}
|
||||
this.canlender = canlender
|
||||
this.weeks = weeks
|
||||
}
|
||||
|
||||
//静态方法
|
||||
// static init(date) {
|
||||
// if (!this.instance) {
|
||||
// this.instance = new Calendar(date);
|
||||
// }
|
||||
// return this.instance;
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
export default Calendar
|
||||