This commit is contained in:
2025-09-26 17:51:07 +08:00
parent 9654a1cbbd
commit b73e0f8385
20 changed files with 1844 additions and 403 deletions

BIN
dist.zip

Binary file not shown.

View File

@@ -90,6 +90,7 @@ const mainRoutes = {
{ path: '/vipList-userList', component: _import('modules/vipList/userList'), name: 'vipList-userList', meta: { title: 'VIP用户列表', isTab: true } },
{ path: '/vipList-vipDetail', component: _import('modules/vipList/vipDetail'), name: 'vipList-vipDetail', meta: { title: 'VIP详情', isTab: true } },
{ path: '/reportList-vipList', component: _import('modules/reportList/vipList'), name: 'reportList-vipList', meta: { title: 'VIP报表', isTab: true } },
{ path: '/reportList-courseList', component: _import('modules/reportList/courseList'), name: 'reportList-courseList', meta: { title: 'VIP报表', isTab: true } },
],
beforeEnter (to, from, next) {

View File

@@ -2,6 +2,30 @@ import Vue from 'vue';
import mammoth from "mammoth";
export default {
getDate(year, month){
console.log('month at line 5:', month)
const currentDate = new Date();
const currentYear = currentDate.getFullYear();
const currentMonth = currentDate.getMonth() + 1; // 转换为1-12的月份格式
console.log('currentMonth at line 9:', currentMonth)
const today = currentDate.getDate();
console.log('today at line 10:', today)
let targetDate;
// 严格判断:是否为当前年份且当前月份
if (year == currentYear && month == currentMonth) {
// 当月:截止到今天
targetDate = `${year}-${month}-${today}`;
return targetDate;
} else {
// 非当月或非今年:取该月最后一天
// 构造下个月1号再减1天得到当月最后一天
const nextMonthFirstDay = new Date(year, month, 1);
const lastDay = new Date(nextMonthFirstDay - 24 * 60 * 60 * 1000).getDate();
targetDate = `${year}-${month}-${lastDay}`;
return targetDate;
}
},
handleUpload(event, callback) {
const file = event.target.files[0];
if (!file) return;

View File

@@ -79,6 +79,7 @@
params: this.$http.adornParams()
}).then(({data}) => {
if (data && data.code === 0) {
localStorage.setItem('userInfo', JSON.stringify(data.user))
this.loading = false
this.userId = data.user.userId
this.userName = data.user.username

View File

@@ -259,15 +259,15 @@
</div>
<div class="td5 flexbox" style="justify-content: center; align-items: center; width: 150px; text-align:center">
<div style="margin-bottom: 15px; text-align: center;">
<div class="tabContent">
<span class="tabName">备注</span>
<div class="tabContent" style="font-size: 16px!important;">
<span class="tabName" style="font-size: 16px!important;">备注</span>
<span @click="editBeizhu(fitem)">
<icon-svg name="beizhu"
style="width: 14px; height:14px; margin-left: 10px; cursor: pointer;"></icon-svg>
style="width: 14px; height:14px; margin-left: 10px; cursor: pointer;font-size: 16px!important;"></icon-svg>
</span>
</div>
<div class="beizhu tabContent" style="color: red">{{ fitem.remark }}</div>
<div class="beizhu tabContent" style="color: red;font-size: 16px!important;">{{ fitem.remark }}</div>
</div>
</div>
</div>

View File

@@ -1,6 +1,6 @@
<template>
<div class="calendar" style="min-width: 1000px;overflow-x: auto;min-height: 100%;">
<div v-if="allMonthData.length>0" @click="handleExportAll()" style="position: absolute; left: 360px;top:30px;cursor: pointer;color: #006699;font-size: 14px;"><i class="el-icon-download"></i>下载 {{year}} 年全部VIP报表</div>
<div v-if="allMonthData.length>0" @click="handleExportAll()" style="position: absolute; left: 360px;top:30px;cursor: pointer;color: #006699;font-size: 14px;"><i class="el-icon-download"></i>下载 {{selectYear}} 年全部VIP报表</div>
<el-card class="box-card" v-for="(month, mIndex) in allMonthData"
:key="mIndex" >
@@ -8,13 +8,13 @@
<div style="color: #888;font-weight: 700;text-align: center;position: relative;font-size: 20px;">{{ month.month}} <el-button @click="handleExport(Number(month.month))" style="float: right; padding: 3px 0;position: absolute;right: 0px;top: -2px;" type="text"><i class="el-icon-download"></i>下载报表</el-button>
</div>
</div>
<div class="days" style="margin-bottom: 15px;">
<div class="days" >
<!-- <div v-for="d in weekDays" :key="d" class="day header">{{ d }}</div> -->
<!-- <div v-for="blank in month.startWeek" :key="'b'+blank" class="day"></div> -->
<div v-for="d in list" :key="d" class="day header" style="margin-bottom: 10px;">{{ d.title }}</div>
<div v-for="d in list" class="day header" style="margin-bottom: 10px;">{{ d.title }}</div>
<div v-for="d in list" :key="d" class="day" :style="`${d.val=='currentTanxiao'?'background-color:#11cdba30;color:#d00':''}`">{{
<div v-for="d in list" class="day" :style="`${d.val=='currentTanxiao'?'background-color:#11cdba30;color:#d00':''}`">{{
month.total[d.val]
}}</div>
@@ -42,7 +42,7 @@
const currentMonth = now.getMonth() + 1; // 月份从0开始
// 如果是今年只取到当前月否则取12个月
const endMonth = year == currentYear ? currentMonth - 1 : 12;
const endMonth = year == currentYear ? currentMonth : 12;
let months = [];
for (let i = 1; i <= endMonth; i++) {
@@ -55,7 +55,7 @@
export default {
name: "FullYearCalendar",
props: {
year: {
selectYear: {
type: Number,
default: new Date().getFullYear()
},
@@ -90,32 +90,12 @@
};
},
computed: {
// months() {
// let months = [];
// for (let m = 0; m < 12; m++) {
// let firstDay = new Date(this.year, m, 1);
// let lastDay = new Date(this.year, m + 1, 0);
// let daysInMonth = lastDay.getDate();
// let startWeek1 = (firstDay.getDay() + 6) % 7; // 转换为 Mon=0
// let startWeek = (firstDay.getDay() + 6) % 7; // 转换为 Mon=0
// let days = [];
// for (let d = 1; d <= daysInMonth; d++) {
// let dateStr = `${this.year}-${String(m+1).padStart(2,"0")}-${String(d).padStart(2,"0")}`;
// days.push({
// number: d,
// date: dateStr,
// color: this.marks[dateStr] || ""
// });
// }
// months.push({ startWeek, days });
// }
// return months;
// }
},
async created() {
await this.getMonthsByYear(this.year)
await this.getMonthsByYear(this.selectYear)
await this.fetchAllMonthData()
},
methods: {
@@ -134,10 +114,10 @@
return this.$http({
url: this.$http.adornUrl(this.urlList.export),
method: "post",
data: this.$http.adornData({ date: `${this.year}-${m}` }),
data: this.$http.adornData({ date: this.$commonJS.getDate(this.selectYear,m) }),
responseType: "blob"
}).then(res => {
const filename = `VIP报表_${this.year}${m}月下载文件.xlsx`
const filename = `VIP报表_${this.selectYear}${m}月下载文件.xlsx`
const blob = new Blob([res.data], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
})
@@ -175,7 +155,7 @@
async handleExport(mIndex) {
console.log('mIndex at line 120:', mIndex)
var filename = `VIP报表_${this.year}${this.pad(mIndex)}月下载文件.xlsx`;
var filename = `VIP报表_${this.selectYear}${this.pad(mIndex)}月下载文件.xlsx`;
this.$message({
message: "请耐心等待...",
type: "info",
@@ -189,7 +169,7 @@
),
method: "post",
data: this.$http.adornData({
date: `${this.year}-${this.pad(mIndex)}`
date: this.$commonJS.getDate(this.selectYear,this.pad(mIndex))
}),
responseType: "blob" // ⚡⚡⚡一定要加上
}).then(res => {
@@ -235,7 +215,7 @@
async init(){
this.showCurrentMonth = ''
this.showCurrentMonthDate = ''
await this.getMonthsByYear(this.year)
await this.getMonthsByYear(this.selectYear)
await this.fetchAllMonthData()
},
getMonthsByYear(year) {
@@ -254,7 +234,7 @@
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.7)"
});
const year = this.year
const year = this.selectYear
const months = getMonths(year)
console.log('months', months)
// 构造请求数组
@@ -263,7 +243,7 @@
return this.$http({
url: this.$http.adornUrl(this.urlList.list),
method: "post",
data: this.$http.adornData({ date: `${year}-${m}` })
data: this.$http.adornData({ date: this.$commonJS.getDate(year,m) })
}).then(res => {
if (res.data && res.data.code === 0) {
return { month: monthNum, total: res.data.total }
@@ -290,7 +270,7 @@
showClose: true
});
}
if (this.year == new Date().getFullYear()) {
if (this.selectYear == new Date().getFullYear()) {
const now = new Date()
const year = now.getFullYear()
const month = this.pad(now.getMonth() + 1)
@@ -332,7 +312,7 @@
.days {
display: grid;
grid-template-columns: repeat(4, 1fr);
font-size: 16px;
font-size: 17px;
}
.day {
text-align: center;
@@ -349,8 +329,11 @@
.day.blue { background: #ddeeff; color: #004; }
.day.yellow { background: #fff6cc; color: #665500; }
/deep/ .el-card .el-card__header{
padding: 8px 20px !important;
padding: 4px 20px !important;
}
/deep/ .el-card .el-card__body {
padding: 15px !important;
overflow-x: auto !important;
}
</style>

View File

@@ -0,0 +1,443 @@
<template>
<div
class="calendar"
style="min-width: 1000px;overflow-x: auto;min-height: 100%;"
>
<div
v-if="allMonthData.length > 0"
@click="handleExportAll()"
style="position: absolute;left: 360px;top:30px;cursor: pointer;color: #006699;font-size: 14px;"
>
<i class="el-icon-download"></i>下载 {{ year }} 年全部天医币报表
</div>
<el-card
class="box-card"
v-for="(month, mIndex) in allMonthData"
:key="mIndex"
>
<div slot="header" class="clearfix">
<div
style="color: #888;font-weight: 700;text-align: center;position: relative;font-size: 20px;"
>
{{ month.month }}
<el-button
v-if="month && month.total && month.total.length > 0"
@click="handleExport(Number(month.month))"
style="float: right; padding: 3px 0;position: absolute;right: 0px;top: -2px;"
type="text"
><i class="el-icon-download"></i>下载报表</el-button
>
</div>
</div>
<div
class="days"
style=""
v-if="month && month.total && month.total.length > 0"
:style="{
'grid-template-columns': `repeat(${
month.total.length && month.total.length > 2
? 2
: month.total.length
}, 1fr)`
}"
>
<div
v-for="d in month.total"
:key="d"
class="day header"
style="margin-bottom: 4px;text-align:left;"
>
{{ d.type }}
<span style="font-size: 16px;" v-if="d.payType">
<img
src="/static/img/oder_chong.png"
alt=""
style="width: 20px;"
v-if="d.payType == '天医币'"
/>
<img
src="/static/img/pingguo.png"
alt=""
style="width: 18px;margin-top: -6px;"
v-if="d.payType == '苹果'"
/>
<icon-svg
name="weixin"
v-if="d.payType == '微信'"
style=""
></icon-svg>
<icon-svg name="zhifubao" v-if="d.payType == '支付宝'"></icon-svg>
</span>
<div class="day" style="display: inline-block;">: {{ d.amount }}</div>
</div>
<!-- <div
v-for="day in month.days"
:key="day.date"
template
:class="day.color"
>
{{ day.number }}
</div> -->
</div>
<div
v-else
style="font-size: 20px;color: #888;text-align: center;line-height: 100px;"
>
暂无数据
</div>
</el-card>
</div>
</template>
<script>
// 获取当年到当前月的所有月份数组
function getMonths(year) {
const now = new Date();
const currentYear = now.getFullYear();
const currentMonth = now.getMonth() + 1; // 月份从0开始
// 如果是今年只取到当前月否则取12个月
const endMonth = year == currentYear ? currentMonth - 1 : 12;
let months = [];
for (let i = 1; i <= endMonth; i++) {
let monthStr = i < 10 ? "0" + i : i; // 补零
months.push(`${monthStr}`);
}
return months;
}
export default {
name: "FullYearCalendar",
props: {
year: {
type: Number,
default: new Date().getFullYear()
},
// 标记数据,例如:{ "2019-01-05": "red", "2019-03-12": "yellow" }
marks: {
type: Object,
default: () => ({})
},
urlList: {
type: Object,
default: () => ({})
}
},
data() {
return {
showCurrentMonth: "",
showCurrentMonthDate: "",
allMonthData: [],
list: [
{ title: "收入", val: "fee" },
{ title: "月摊销", val: "currentTanxiao" },
{ title: "已摊销", val: "alreadyTanxiao" },
{ title: "剩余摊销", val: "notyetTanxiao" }
],
weekDays: ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
monthNames: [
"一",
"二",
"三",
"四",
"五",
"六",
"七",
"八",
"九",
"十",
"十 一",
"十 二"
]
};
},
computed: {
// months() {
// let months = [];
// for (let m = 0; m < 12; m++) {
// let firstDay = new Date(this.year, m, 1);
// let lastDay = new Date(this.year, m + 1, 0);
// let daysInMonth = lastDay.getDate();
// let startWeek1 = (firstDay.getDay() + 6) % 7; // 转换为 Mon=0
// let startWeek = (firstDay.getDay() + 6) % 7; // 转换为 Mon=0
// let days = [];
// for (let d = 1; d <= daysInMonth; d++) {
// let dateStr = `${this.year}-${String(m+1).padStart(2,"0")}-${String(d).padStart(2,"0")}`;
// days.push({
// number: d,
// date: dateStr,
// color: this.marks[dateStr] || ""
// });
// }
// months.push({ startWeek, days });
// }
// return months;
// }
},
async created() {
await this.getMonthsByYear(this.year);
await this.fetchAllMonthData();
},
methods: {
async handleExportAll() {
const months = this.allMonthData.map(m => m.month);
this.$message({
message: "所有月份的天医币报表正在下载,请耐心等待...",
type: "info",
duration: 6000,
showClose: true
});
// 构造请求数组
const requests = months.map(m => {
return this.$http({
url: this.$http.adornUrl(this.urlList.export),
method: "post",
data: this.$http.adornData({ date: `${this.year}-${m}` }),
responseType: "blob"
})
.then(res => {
const filename = `天医币报表_${this.year}${m}月下载文件.xlsx`;
const blob = new Blob([res.data], {
type:
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
});
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = filename;
link.click();
window.URL.revokeObjectURL(link.href);
return { month: m, success: true };
})
.catch(() => {
return { month: m, success: false };
});
});
// 等待所有请求完成
const results = await Promise.all(requests);
// 统计成功/失败
const successMonths = results.filter(r => r.success).map(r => r.month);
const failMonths = results.filter(r => !r.success).map(r => r.month);
let message = `报表下载完成:成功 ${successMonths.length}`;
if (failMonths.length > 0) {
message += `,失败 ${failMonths.length} 个(失败月份: ${failMonths.join(
"、"
)}`;
}
this.$message({
message,
type: failMonths.length === 0 ? "success" : "warning",
duration: 5000,
showClose: true
});
},
async handleExport(mIndex) {
console.log("mIndex at line 120:", mIndex);
var filename = `天医币报表_${this.year}${this.pad(
mIndex
)}月下载文件.xlsx`;
this.$message({
message: "请耐心等待...",
type: "info",
duration: 3000,
showClose: true
});
try {
this.$http({
url: this.$http.adornUrl(this.urlList.export),
method: "post",
data: this.$http.adornData({
date: `${this.year}-${this.pad(mIndex)}`
}),
responseType: "blob" // ⚡⚡⚡一定要加上
}).then(res => {
// this.$message({
// message: "天医币报表文件下载中,下载完成后文件会自动下载,请耐心等待...",
// type: "info",
// duration: 6000,
// showClose: true
// });
const blob = new Blob([res.data], {
type:
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
});
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = filename;
link.click();
window.URL.revokeObjectURL(link.href); // 释放内存
this.$message({
message: "天医币报表文件下载完成,请注意查看!",
type: "success",
duration: 3000,
showClose: true
});
});
// const res = await axios.post(
// window.SITE_CONFIG.baseUrl+"/master/userContribution/exportContributionStatQuery",
// {
// current: this.current,
// limit: this.limit
// },
// {
// responseType: "blob" // 关键点:告诉 axios 返回的是二进制文件
// }
// );
} catch (err) {
this.$message.error("文件下载失败!");
// console.error("文件下载失败:", err);
}
},
async init() {
this.showCurrentMonth = "";
this.showCurrentMonthDate = "";
await this.getMonthsByYear(this.year);
await this.fetchAllMonthData();
},
getMonthsByYear(year) {
this.months = getMonths(year);
},
pad(num) {
return num < 10 ? "0" + num : num;
},
fetchAllMonthData() {
const loading = this.$loading({
lock: true,
text: "统计中",
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.7)"
});
const year = this.year;
const months = getMonths(year);
console.log("months", months);
// 构造请求数组
const requests = months.map(m => {
const monthNum = m; // 拿到 1,2,3...
return this.$http({
url: this.$http.adornUrl(this.urlList.list),
method: "post",
data: this.$http.adornData({ date: `${year}-${m}` })
})
.then(res => {
if (res.data && res.data.code === 0) {
return { month: monthNum, total: res.data.total };
} else {
return { month: monthNum, total: null, error: "获取失败" };
}
})
.catch(err => {
return {
month: monthNum,
total: null,
error: err.message || "请求出错"
};
});
});
// 并发请求
Promise.all(requests)
.then(resArr => {
console.log("所有月份结果:", resArr);
loading.close();
this.allMonthData = resArr.filter(
r => r.total !== null && r.total.length !== 0
);
if (this.allMonthData.length == 0) {
this.$message({
message: "该年无数据",
type: "warning",
duration: 3000,
showClose: true
});
}
if (this.year == new Date().getFullYear()) {
const now = new Date();
const year = now.getFullYear();
const month = this.pad(now.getMonth() + 1);
const day = this.pad(now.getDate());
this.showCurrentMonth = now.getMonth() + 1;
console.log(
"this.showCurrentMonth at line 111:",
this.showCurrentMonth
);
this.showCurrentMonthDate = `${year}-${month}-${day}`;
console.log("当前完整日期:", this.showCurrentMonthDate);
}
// resArr 是每个月接口返回结果的数组
})
.catch(err => {
console.error("获取所有月份数据失败:", err);
loading.close();
});
}
}
};
</script>
<style scoped>
.calendar {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.month {
background: #fff;
border: 1px solid #ddd;
border-radius: 6px;
padding: 10px;
text-align: center;
}
.month h3 {
margin: 0 0 5px;
font-size: 16px;
}
.days {
display: grid;
grid-template-columns: repeat(4, 1fr);
font-size: 16px;
}
.day {
text-align: center;
padding: 4px;
margin: 2px;
border-radius: 4px;
min-height: 20px;
}
.day.header {
font-weight: bold;
color: #555;
}
.day.red {
background: #ffdddd;
color: #d00;
}
.day.blue {
background: #ddeeff;
color: #004;
}
.day.yellow {
background: #fff6cc;
color: #665500;
}
/deep/ .el-card .el-card__header {
padding: 8px 20px !important;
}
/deep/ .el-card .el-card__body {
padding: 10px !important;
}
</style>

View File

@@ -1,28 +1,85 @@
<template>
<div class="calendar" style="min-width: 1000px;overflow-x: auto;min-height: 100%;">
<div v-if="allMonthData.length>0" @click="handleExportAll()" style="position: absolute;left: 360px;top:30px;cursor: pointer;color: #006699;font-size: 14px;"><i class="el-icon-download"></i>下载 {{year}} 年全部天医币报表</div>
<div
class="calendar"
style="min-width: 1000px;overflow-x: auto;min-height: 100%;"
>
<div
v-if="allMonthData.length > 0"
@click="handleExportAll()"
style="position: absolute;left: 360px;top:30px;cursor: pointer;color: #006699;font-size: 14px;"
>
<i class="el-icon-download"></i>下载 {{ selectYear }} 年全部天医币报表
</div>
<el-card class="box-card" v-for="(month, mIndex) in allMonthData"
:key="mIndex" >
<el-card
class="box-card"
v-for="(month, mIndex) in allMonthData"
:key="mIndex"
>
<div slot="header" class="clearfix">
<div style="color: #888;font-weight: 700;text-align: center;position: relative;font-size: 20px;">{{month.month }} <el-button v-if="month&&month.total&&month.total.length>0" @click="handleExport(Number(month.month))" style="float: right; padding: 3px 0;position: absolute;right: 0px;top: -2px;" type="text"><i class="el-icon-download"></i>下载报表</el-button>
<div
style="color: #888;font-weight: 700;text-align: center;position: relative;font-size: 20px;"
>
{{ month.month }}
<el-button
v-if="month && month.total && month.total.length > 0"
@click="handleExport(Number(month.month))"
style="float: right; padding: 3px 0;position: absolute;right: 0px;top: -2px;"
type="text"
><i class="el-icon-download"></i>下载报表</el-button
>
</div>
</div>
<div class="days" style="margin-bottom: 15px;"v-if="month&&month.total&&month.total.length>0" :style="{'grid-template-columns':`repeat(${month.total.length&&month.total.length>2?2:month.total.length}, 1fr)`}">
<div
class="days"
style=""
:style="{
'grid-template-columns': `repeat(${
month.total.length && month.total.length > 2
? 2
: month.total.length
}, 1fr)`
}"
>
<div
v-for="(d, index) in list"
<div v-for="d in month.total" :key="d" class="day header" style="margin-bottom: 10px;text-align:left;">{{ d.type }}
<span style="font-size: 16px;" v-if="d.payType">
<img src="/static/img/oder_chong.png" alt="" style="width: 20px;" v-if="d.payType=='天医币'">
<img src="/static/img/pingguo.png" alt="" style="width: 18px;margin-top: -6px;" v-if="d.payType=='苹果'">
<icon-svg name="weixin" v-if="d.payType=='微信'" style=""></icon-svg>
<icon-svg name="zhifubao" v-if="d.payType=='支付宝'"></icon-svg>
:style="{
'background-color': d.bg
}"
class="day header"
style="margin-bottom: 0px;padding-top: 10px;padding-bottom: 15px"
>
<div>
<span style="margin-left: 10px;"> {{ d.title }}</span>
</div>
<div
style="font-weight: 500;color: #888;margin-top:10px;font-size: 15px;padding:0 2px;"
>
<li
v-for="item in d.list"
style="text-align: left;margin-top: 10px;"
>
<span style="">
{{ item.title }} :<span
v-if="item.otherTitle"
style="font-size: 12px;color: #808080;"
><br />{{ item.otherTitle }}</span
>
</span>
<div class="day" style="display: inline-block;"> : {{d.amount}}</div>
<span
style="margin-left:4px;color: #333;"
:style="{
color: getAmount(item, index, month) == 0 ? '#888' : '#333'
}"
>
{{ getAmount(item, index, month) }}
</span>
</li>
</div>
</div>
<!-- <div
v-for="day in month.days"
@@ -33,34 +90,37 @@
{{ day.number }}
</div> -->
</div>
<div v-else style="font-size: 20px;color: #888;text-align: center;line-height: 100px;">暂无数据</div>
<p
style="margin: 4px;text-align: left;color: #006699;padding-left: 10px;"
>
APP用户剩余天医币 : {{ month.surplus.surplusPeanutCoin }}
</p>
</el-card>
</div>
</template>
<script>
// 获取当年到当前月的所有月份数组
function getMonths(year) {
const now = new Date()
const currentYear = now.getFullYear()
const currentMonth = now.getMonth() + 1 // 月份从0开始
const now = new Date();
const currentYear = now.getFullYear();
const currentMonth = now.getMonth() + 1; // 月份从0开始
// 如果是今年只取到当前月否则取12个月
const endMonth = (year == currentYear) ? currentMonth-1 : 12
const endMonth = year == currentYear ? currentMonth : 12;
let months = []
let months = [];
for (let i = 1; i <= endMonth; i++) {
let monthStr = i < 10 ? "0" + i : i // 补零
months.push(`${monthStr}`)
let monthStr = i < 10 ? "0" + i : i; // 补零
months.push(`${monthStr}`);
}
return months
return months;
}
export default {
name: "FullYearCalendar",
props: {
year: {
selectYear: {
type: Number,
default: new Date().getFullYear()
},
@@ -76,54 +136,106 @@
},
data() {
return {
showCurrentMonth: '',
showCurrentMonthDate: '',
showCurrentMonth: "",
showCurrentMonthDate: "",
allMonthData: [],
list: [
{title:'收入',val:'fee'} ,
{title:'月摊销',val:'currentTanxiao'},
{title:'已摊销',val:'alreadyTanxiao'},
{title:'剩余摊销',val:'notyetTanxiao'},
{
title: "进项",
val: "jing",
bg: "#1bff000a",
list: [
{ title: "后台微信", val: "weixin", realTitle: "后台充值微信" },
{ title: "后台支付宝", val: "alipay", realTitle: "后台充值支付宝" },
{ title: "后台海外", val: "haiwai", realTitle: "后台充值海外支付" },
{ title: "后台银行转账", val: "", realTitle: "后台充值银行支付" },
{ title: "后台其他", val: "other", realTitle: "后台充值" },
{ title: "App微信充值", val: "appweixin", realTitle: "微信充值" },
{
title: "App支付宝充值",
val: "appalipay",
realTitle: "支付宝充值"
},
{ title: "App苹果充值", val: "appapple", realTitle: "苹果充值" }
]
},
{
title: "出项",
val: "chu",
bg: "#ffc1070f",
list: [
{ title: "购买实物商品", val: "goods", realTitle: "购买商品实物" },
{
title: "购买秒杀课程与课程",
val: "kecheng",
realTitle: "购买商品课程"
},
{
title: "购买实物商品与课程",
val: "kecheng2",
realTitle: "购买商品实物、课程"
},
{title:'报名培训班',val:'train',realTitle: "购买商品培训班"},
// {title:'报名VIP',val:'vip'},
{ title: "后台扣费", val: "deduction" }
]
}
],
weekDays: ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
monthNames: [
"一", "二", "三", "四",
"五", "六", "七", "八",
"九", "十", "十 一", "十 二"
"一",
"二",
"三",
"四",
"五",
"六",
"七",
"八",
"九",
"十",
"十 一",
"十 二"
]
};
},
computed: {
// months() {
// let months = [];
// for (let m = 0; m < 12; m++) {
// let firstDay = new Date(this.year, m, 1);
// let lastDay = new Date(this.year, m + 1, 0);
// let daysInMonth = lastDay.getDate();
// let startWeek1 = (firstDay.getDay() + 6) % 7; // 转换为 Mon=0
// let startWeek = (firstDay.getDay() + 6) % 7; // 转换为 Mon=0
// let days = [];
// for (let d = 1; d <= daysInMonth; d++) {
// let dateStr = `${this.year}-${String(m+1).padStart(2,"0")}-${String(d).padStart(2,"0")}`;
// days.push({
// number: d,
// date: dateStr,
// color: this.marks[dateStr] || ""
// });
// }
// months.push({ startWeek, days });
// }
// return months;
// }
},
async created() {
await this.getMonthsByYear(this.year)
await this.fetchAllMonthData()
await this.getMonthsByYear(this.selectYear);
await this.fetchAllMonthData();
},
methods: {
getAmount(d, index, month) {
// 定义所有可能的匹配规则
const matchRules = [
item => {
// 例如:当类型是特定值时,启用特殊匹配
if (d.val == "other" && item.payMethod == "") {
return `${item.type}` === d.realTitle;
}
return false;
},
item => item.type === d.title,
item => item.type === d.realTitle,
item => `${item.payMethod}${item.type}` === d.realTitle,
item => `${item.type}${item.payMethod}` === d.realTitle,
item => `${item.type}${item.goodsType}` === d.realTitle
// 更复杂的条件组合
];
// 依次检查每个规则,返回第一个匹配项
for (const rule of matchRules) {
const matchedItem = month.total.find(rule);
if (matchedItem) {
return matchedItem.amount;
}
}
// 没有匹配项时返回空字符串
return "0";
},
async handleExportAll() {
const months = this.allMonthData.map(m => m.month);
@@ -139,35 +251,42 @@
return this.$http({
url: this.$http.adornUrl(this.urlList.export),
method: "post",
data: this.$http.adornData({ date: `${this.year}-${m}` }),
data: this.$http.adornData({
date: this.$commonJS.getDate(this.selectYear, m)
}),
responseType: "blob"
}).then(res => {
const filename = `天医币报表_${this.year}${m}月下载文件.xlsx`
})
.then(res => {
const filename = `天医币报表_${this.selectYear}${m}月下载文件.xlsx`;
const blob = new Blob([res.data], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
})
const link = document.createElement("a")
link.href = window.URL.createObjectURL(blob)
link.download = filename
link.click()
window.URL.revokeObjectURL(link.href)
type:
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
});
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = filename;
link.click();
window.URL.revokeObjectURL(link.href);
return { month: m, success: true }
}).catch(() => {
return { month: m, success: false }
})
return { month: m, success: true };
})
.catch(() => {
return { month: m, success: false };
});
});
// 等待所有请求完成
const results = await Promise.all(requests)
const results = await Promise.all(requests);
// 统计成功/失败
const successMonths = results.filter(r => r.success).map(r => r.month)
const failMonths = results.filter(r => !r.success).map(r => r.month)
const successMonths = results.filter(r => r.success).map(r => r.month);
const failMonths = results.filter(r => !r.success).map(r => r.month);
let message = `报表下载完成:成功 ${successMonths.length}`
let message = `报表下载完成:成功 ${successMonths.length}`;
if (failMonths.length > 0) {
message += `,失败 ${failMonths.length} 个(失败月份: ${failMonths.join("、")}`
message += `,失败 ${failMonths.length} 个(失败月份: ${failMonths.join(
"、"
)}`;
}
this.$message({
@@ -179,8 +298,10 @@
},
async handleExport(mIndex) {
console.log('mIndex at line 120:', mIndex)
var filename = `天医币报表_${this.year}${this.pad(mIndex)}月下载文件.xlsx`;
console.log("mIndex at line 120:", mIndex);
var filename = `天医币报表_${this.selectYear}${this.pad(
mIndex
)}月下载文件.xlsx`;
this.$message({
message: "请耐心等待...",
type: "info",
@@ -189,12 +310,10 @@
});
try {
this.$http({
url: this.$http.adornUrl(
this.urlList.export,
),
url: this.$http.adornUrl(this.urlList.export),
method: "post",
data: this.$http.adornData({
date: `${this.year}-${this.pad(mIndex)}`
date: this.$commonJS.getDate(this.selectYear, this.pad(mIndex))
}),
responseType: "blob" // ⚡⚡⚡一定要加上
}).then(res => {
@@ -238,20 +357,18 @@
}
},
async init() {
this.showCurrentMonth = ''
this.showCurrentMonthDate = ''
await this.getMonthsByYear(this.year)
await this.fetchAllMonthData()
this.showCurrentMonth = "";
this.showCurrentMonthDate = "";
await this.getMonthsByYear(this.selectYear);
await this.fetchAllMonthData();
},
getMonthsByYear(year) {
this.months = getMonths(year)
this.months = getMonths(year);
},
}
,pad(num) {
return num < 10 ? "0" + num : num
}
,
pad(num) {
return num < 10 ? "0" + num : num;
},
fetchAllMonthData() {
const loading = this.$loading({
lock: true,
@@ -259,31 +376,42 @@
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.7)"
});
const year = this.year
const months = getMonths(year)
console.log('months', months)
const year = this.selectYear;
const months = getMonths(year);
console.log("months", months);
// 构造请求数组
const requests = months.map(m => {
const monthNum = m // 拿到 1,2,3...
const monthNum = m; // 拿到 1,2,3...
return this.$http({
url: this.$http.adornUrl(this.urlList.list),
method: "post",
data: this.$http.adornData({ date: `${year}-${m}` })
}).then(res => {
data: this.$http.adornData({ date: this.$commonJS.getDate(year, m) })
})
.then(res => {
if (res.data && res.data.code === 0) {
return { month: monthNum, total: res.data.total }
return {
month: monthNum,
total: res.data.total,
surplus: res.data.surplus
};
} else {
return { month: monthNum, total: null, error: "获取失败" }
return { month: monthNum, total: null, error: "获取失败" };
}
}).catch(err => {
return { month: monthNum, total: null, error: err.message || "请求出错" }
})
})
.catch(err => {
return {
month: monthNum,
total: null,
error: err.message || "请求出错"
};
});
});
// 并发请求
Promise.all(requests).then(resArr => {
console.log("所有月份结果:", resArr)
loading.close()
Promise.all(requests)
.then(resArr => {
console.log("所有月份结果:", resArr);
loading.close();
this.allMonthData = resArr.filter(
r => r.total !== null && r.total.length !== 0
);
@@ -295,25 +423,29 @@
showClose: true
});
}
if (this.year == new Date().getFullYear()) {
const now = new Date()
const year = now.getFullYear()
const month = this.pad(now.getMonth() + 1)
const day = this.pad(now.getDate())
if (this.selectYear == new Date().getFullYear()) {
const now = new Date();
const year = now.getFullYear();
const month = this.pad(now.getMonth() + 1);
const day = this.pad(now.getDate());
this.showCurrentMonth = now.getMonth() + 1
console.log('this.showCurrentMonth at line 111:', this.showCurrentMonth)
this.showCurrentMonthDate = `${year}-${month}-${day}`
this.showCurrentMonth = now.getMonth() + 1;
console.log(
"this.showCurrentMonth at line 111:",
this.showCurrentMonth
);
this.showCurrentMonthDate = `${year}-${month}-${day}`;
console.log('当前完整日期:', this.showCurrentMonthDate)
console.log("当前完整日期:", this.showCurrentMonthDate);
}
// resArr 是每个月接口返回结果的数组
}).catch(err => {
console.error("获取所有月份数据失败:", err)
loading.close()
})
.catch(err => {
console.error("获取所有月份数据失败:", err);
loading.close();
});
}
}
},
};
</script>
@@ -321,7 +453,7 @@
.calendar {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
gap: 10px;
}
.month {
background: #fff;
@@ -350,15 +482,25 @@
font-weight: bold;
color: #555;
}
.day.red { background: #ffdddd; color: #d00; }
.day.blue { background: #ddeeff; color: #004; }
.day.yellow { background: #fff6cc; color: #665500; }
.day.red {
background: #ffdddd;
color: #d00;
}
.day.blue {
background: #ddeeff;
color: #004;
}
.day.yellow {
background: #fff6cc;
color: #665500;
}
/deep/ .el-card .el-card__header {
padding: 8px 20px !important;
padding: 4px 20px !important;
}
/deep/ .el-card .el-card__body {
padding:10px !important;
padding: 0px !important;overflow-x: auto !important;
}
li {
list-style: none;
}
</style>

View File

@@ -0,0 +1,473 @@
<template>
<div
class="calendar"
style="min-width: 1000px;overflow-x: auto;min-height: 100%;"
>
<div
v-if="allMonthData.length > 0"
@click="handleExportAll()"
style="position: absolute;left: 360px;top:30px;cursor: pointer;color: #006699;font-size: 14px;"
>
<i class="el-icon-download"></i>下载 {{ selectYear }} 年全部课程报表
</div>
<el-card
class="box-card"
v-for="(month, mIndex) in allMonthData"
:key="mIndex"
>
<div slot="header" class="clearfix">
<div
style="color: #888;font-weight: 700;text-align: center;position: relative;font-size: 20px;"
>
{{ month.month }}
<el-button
v-if="month && month.total && month.total.length > 0"
@click="handleExport(Number(month.month))"
style="float: right; padding: 3px 0;position: absolute;right: 0px;top: -2px;"
type="text"
><i class="el-icon-download"></i>下载报表</el-button
>
</div>
</div>
<div
class="days"
style=""
:style="{
'grid-template-columns': `repeat(${
2
}, 1fr)`
}"
>
<div
v-for="(d,index) in list"
:style="{
'background-color': d.bg
}"
class="day header"
style="margin-bottom: 0px;padding-top: 10px;padding-bottom: 15px"
>
<div >
<span style="margin-left: 10px;"> {{ d.title }}</span>
</div>
<div style="font-weight: 500;color: #888;margin-top:10px;font-size: 15px;padding:0 4px;">
<li v-for="item in d.list" style="text-align: left;margin-top: 10px;">
<span style=""> {{item.title}} :<span v-if="item.otherTitle" style="font-size: 12px;color: #808080;"><br/>{{ item.otherTitle}}</span> </span>
<span style="margin-left: 10px;color: #333;letter-spacing: 0.5px;" v-if="index==0" :style="{
color: getAmount(item, index, month) == 0 ? '#888' : '#333'
}">
{{ getAmount(item,index,month) }}
</span>
<span style="margin-left: 10px;color: #333;letter-spacing: 0.5px;" v-if="index==1">
{{ month.total[0][item.val] }}
</span>
</li>
</div>
</div>
<!-- <div
v-for="day in month.days"
:key="day.date"
template
:class="day.color"
>
{{ day.number }}
</div> -->
</div>
</el-card>
</div>
</template>
<script>
// 获取当年到当前月的所有月份数组
function getMonths(year) {
const now = new Date();
const currentYear = now.getFullYear();
const currentMonth = now.getMonth() + 1; // 月份从0开始
// 如果是今年只取到当前月否则取12个月
const endMonth = year == currentYear ? currentMonth : 12;
let months = [];
for (let i = 1; i <= endMonth; i++) {
let monthStr = i < 10 ? "0" + i : i; // 补零
months.push(`${monthStr}`);
}
return months;
}
export default {
name: "FullYearCalendar",
props: {
selectYear: {
type: Number,
default: new Date().getFullYear()
},
// 标记数据,例如:{ "2019-01-05": "red", "2019-03-12": "yellow" }
marks: {
type: Object,
default: () => ({})
},
urlList: {
type: Object,
default: () => ({})
}
},
data() {
return {
showCurrentMonth: "",
showCurrentMonthDate: "",
allMonthData: [],
list: [
{ title: "收入", val: "jing",bg:'#1bff000a',
list: [
{ title: "后台微信", val: "weixin", realTitle: "后台微信" },
{ title: "后台支付宝", val: "alipay", realTitle: "后台支付宝" },
{ title: "后台海外", val: "haiwai", realTitle: "后台海外支付" },
{ title: "后台银行转账", val: "", realTitle: "后台银行支付" },
{ title: "后台其他", val: "other", realTitle: "后台其他" },
{ title: "App微信", val: "appweixin", realTitle: "微信" },
{
title: "App支付宝",
val: "appalipay",
realTitle: "支付宝"
},
{ title: "App天医币", val: "appapple", realTitle: "天医币" }
]
},
{ title: "摊销", val: "chu",bg:'#ffc1070f',list:[
{title:'金额',val:'fee'},
{title:'已摊销',val:'alreadyTanxiao'},
{title:'月摊销',val:'currentTanxiao'},
{title:'剩余摊销',val:'surplusTanxiao'},
] },
],
weekDays: ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
monthNames: [
"一",
"二",
"三",
"四",
"五",
"六",
"七",
"八",
"九",
"十",
"十 一",
"十 二"
]
};
},
computed: {
},
async created() {
await this.getMonthsByYear(this.selectYear);
await this.fetchAllMonthData();
},
methods: {
getAmount(d, index, month) {
// 定义所有可能的匹配规则
const matchRules = [
item => item.pay_type === d.title,
item => item.pay_type === d.realTitle,
// 更复杂的条件组合
];
// 依次检查每个规则,返回第一个匹配项
for (const rule of matchRules) {
const matchedItem = month.total.find(rule);
if (matchedItem) {
return matchedItem.fee;
}
}
// 没有匹配项时返回空字符串
return "0";
},
async handleExportAll() {
const months = this.allMonthData.map(m => m.month);
this.$message({
message: "所有月份的课程报表正在下载,请耐心等待...",
type: "info",
duration: 6000,
showClose: true
});
// 构造请求数组
const requests = months.map(m => {
return this.$http({
url: this.$http.adornUrl(this.urlList.export),
method: "post",
data: this.$http.adornData({ date: this.$commonJS.getDate(this.selectYear,m )}),
responseType: "blob"
})
.then(res => {
const filename = `课程报表_${this.selectYear}${m}月下载文件.xlsx`;
const blob = new Blob([res.data], {
type:
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
});
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = filename;
link.click();
window.URL.revokeObjectURL(link.href);
return { month: m, success: true };
})
.catch(() => {
return { month: m, success: false };
});
});
// 等待所有请求完成
const results = await Promise.all(requests);
// 统计成功/失败
const successMonths = results.filter(r => r.success).map(r => r.month);
const failMonths = results.filter(r => !r.success).map(r => r.month);
let message = `报表下载完成:成功 ${successMonths.length}`;
if (failMonths.length > 0) {
message += `,失败 ${failMonths.length} 个(失败月份: ${failMonths.join(
"、"
)}`;
}
this.$message({
message,
type: failMonths.length === 0 ? "success" : "warning",
duration: 5000,
showClose: true
});
},
async handleExport(mIndex) {
console.log("mIndex at line 120:", mIndex);
var filename = `课程报表_${this.selectYear}${this.pad(
mIndex
)}月下载文件.xlsx`;
this.$message({
message: "请耐心等待...",
type: "info",
duration: 3000,
showClose: true
});
try {
this.$http({
url: this.$http.adornUrl(this.urlList.export),
method: "post",
data: this.$http.adornData({
date: this.$commonJS.getDate(this.selectYear,this.pad(mIndex))
}),
responseType: "blob" // ⚡⚡⚡一定要加上
}).then(res => {
// this.$message({
// message: "课程报表文件下载中,下载完成后文件会自动下载,请耐心等待...",
// type: "info",
// duration: 6000,
// showClose: true
// });
const blob = new Blob([res.data], {
type:
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
});
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = filename;
link.click();
window.URL.revokeObjectURL(link.href); // 释放内存
this.$message({
message: "课程报表文件下载完成,请注意查看!",
type: "success",
duration: 3000,
showClose: true
});
});
// const res = await axios.post(
// window.SITE_CONFIG.baseUrl+"/master/userContribution/exportContributionStatQuery",
// {
// current: this.current,
// limit: this.limit
// },
// {
// responseType: "blob" // 关键点:告诉 axios 返回的是二进制文件
// }
// );
} catch (err) {
this.$message.error("文件下载失败!");
// console.error("文件下载失败:", err);
}
},
async init() {
this.showCurrentMonth = "";
this.showCurrentMonthDate = "";
await this.getMonthsByYear(this.selectYear);
await this.fetchAllMonthData();
},
getMonthsByYear(year) {
this.months = getMonths(year);
},
pad(num) {
return num < 10 ? "0" + num : num;
},
fetchAllMonthData() {
const loading = this.$loading({
lock: true,
text: "统计中",
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.7)"
});
const year = this.selectYear;
const months = getMonths(year);
console.log("months", months);
// 构造请求数组
const requests = months.map(m => {
const monthNum = m; // 拿到 1,2,3...
return this.$http({
url: this.$http.adornUrl(this.urlList.list),
method: "post",
data: this.$http.adornData({ date: this.$commonJS.getDate(year,m) })
})
.then(res => {
if (res.data && res.data.code === 0) {
return { month: monthNum, total: [res.data.tanxiaoTotal[0],...res.data.income]};
} else {
return { month: monthNum, total: null, error: "获取失败" };
}
})
.catch(err => {
return {
month: monthNum,
total: null,
error: err.message || "请求出错"
};
});
});
// 并发请求
Promise.all(requests)
.then(resArr => {
console.log("所有月份结果:", resArr);
loading.close();
this.allMonthData = resArr.filter(
r => r.total !== null && r.total.length !== 0
);
if (this.allMonthData.length == 0) {
this.$message({
message: "该年无数据",
type: "warning",
duration: 3000,
showClose: true
});
}
if (this.selectYear == new Date().getFullYear()) {
const now = new Date();
const year = now.getFullYear();
const month = this.pad(now.getMonth() + 1);
const day = this.pad(now.getDate());
this.showCurrentMonth = now.getMonth() + 1;
console.log(
"this.showCurrentMonth at line 111:",
this.showCurrentMonth
);
this.showCurrentMonthDate = `${year}-${month}-${day}`;
console.log("当前完整日期:", this.showCurrentMonthDate);
}
// resArr 是每个月接口返回结果的数组
})
.catch(err => {
console.error("获取所有月份数据失败:", err);
loading.close();
});
}
}
};
</script>
<style scoped>
.calendar {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
.month {
background: #fff;
border: 1px solid #ddd;
border-radius: 6px;
padding: 10px;
text-align: center;
}
.month h3 {
margin: 0 0 5px;
font-size: 16px;
}
.days {
display: grid;
grid-template-columns: repeat(4, 1fr);
font-size: 16px;
}
.day {
text-align: center;
padding: 4px;
margin: 2px;
border-radius: 4px;
min-height: 20px;
}
.day.header {
font-weight: bold;
color: #555;
}
.day.red {
background: #ffdddd;
color: #d00;
}
.day.blue {
background: #ddeeff;
color: #004;
}
.day.yellow {
background: #fff6cc;
color: #665500;
}
/deep/ .el-card .el-card__header {
padding: 4px 20px !important;
}
/deep/ .el-card .el-card__body {
padding: 0px !important;overflow-x: auto !important;
}
li{
list-style: none;
}
</style>

View File

@@ -7,7 +7,7 @@
@click="handleExportAll()"
style="position: absolute;left: 360px;top:30px;cursor: pointer;color: #006699;font-size: 14px;"
>
<i class="el-icon-download"></i>下载 {{ year }} 年全部实物报表
<i class="el-icon-download"></i>下载 {{ selectYear }} 年全部实物报表
</div>
<el-card class="box-card" v-for="(month, mIndex) in allMonthData" :key="mIndex">
@@ -27,14 +27,14 @@
</div>
<div
class="days"
style="margin-bottom: 15px;"
>
<!-- <div v-for="d in weekDays" :key="d" class="day header">{{ d }}</div> -->
<!-- <div v-for="blank in month.startWeek" :key="'b'+blank" class="day"></div> -->
<div
v-for="d in list"
:key="d"
class="day header"
style="margin-bottom: 0px;display: flex;justify-content: center;"
>
@@ -47,13 +47,13 @@
></icon-svg>
<icon-svg name="zhifubao" v-if="d.title == '支付宝'"></icon-svg>
<span style="margin-left: 10px;"> {{ d.title }}</span>
<span style="margin-left: 4px;"> {{ d.title }}</span>
</div>
</div>
<div
v-for="d in list"
:key="d"
class="day"
:style="
`${
@@ -63,7 +63,7 @@
}`
"
>
<span style="font-size: 14px;color:#888;"
<span style="font-size: 16px;color:#888;"
>共计{{
allMonthData[mIndex].total.filter(
item => item.payType == d.title
@@ -94,7 +94,7 @@ function getMonths(year) {
const currentMonth = now.getMonth() + 1; // 月份从0开始
// 如果是今年只取到当前月否则取12个月
const endMonth = year == currentYear ? currentMonth - 1 : 12;
const endMonth = year == currentYear ? currentMonth : 12;
let months = [];
for (let i = 1; i <= endMonth; i++) {
@@ -107,7 +107,7 @@ function getMonths(year) {
export default {
name: "FullYearCalendar",
props: {
year: {
selectYear: {
type: Number,
default: new Date().getFullYear()
},
@@ -153,30 +153,10 @@ export default {
};
},
computed: {
// months() {
// let months = [];
// for (let m = 0; m < 12; m++) {
// let firstDay = new Date(this.year, m, 1);
// let lastDay = new Date(this.year, m + 1, 0);
// let daysInMonth = lastDay.getDate();
// let startWeek1 = (firstDay.getDay() + 6) % 7; // 转换为 Mon=0
// let startWeek = (firstDay.getDay() + 6) % 7; // 转换为 Mon=0
// let days = [];
// for (let d = 1; d <= daysInMonth; d++) {
// let dateStr = `${this.year}-${String(m+1).padStart(2,"0")}-${String(d).padStart(2,"0")}`;
// days.push({
// number: d,
// date: dateStr,
// color: this.marks[dateStr] || ""
// });
// }
// months.push({ startWeek, days });
// }
// return months;
// }
},
async created() {
await this.getMonthsByYear(this.year);
await this.getMonthsByYear(this.selectYear);
await this.fetchAllMonthData();
},
methods: {
@@ -195,11 +175,11 @@ export default {
return this.$http({
url: this.$http.adornUrl(this.urlList.export),
method: "post",
data: this.$http.adornData({ date: `${this.year}-${m}` }),
data: this.$http.adornData({ date:this.$commonJS.getDate(this.selectYear,m) }),
responseType: "blob"
})
.then(res => {
const filename = `实物报表_${this.year}${m}月下载文件.xlsx`;
const filename = `实物报表_${this.selectYear}${m}月下载文件.xlsx`;
const blob = new Blob([res.data], {
type:
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
@@ -241,7 +221,7 @@ export default {
async handleExport(mIndex) {
console.log("mIndex at line 120:", mIndex);
var filename = `实物报表_${this.year}${this.pad(
var filename = `实物报表_${this.selectYear}${this.pad(
mIndex
)}月下载文件.xlsx`;
this.$message({
@@ -255,16 +235,11 @@ export default {
url: this.$http.adornUrl(this.urlList.export),
method: "post",
data: this.$http.adornData({
date: `${this.year}-${this.pad(mIndex)}`
date:this.$commonJS.getDate(this.selectYear,this.pad(mIndex))
}),
responseType: "blob" // ⚡⚡⚡一定要加上
}).then(res => {
// this.$message({
// message: "实物报表文件下载中,下载完成后文件会自动下载,请耐心等待...",
// type: "info",
// duration: 6000,
// showClose: true
// });
const blob = new Blob([res.data], {
type:
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
@@ -282,17 +257,7 @@ export default {
showClose: true
});
});
// const res = await axios.post(
// window.SITE_CONFIG.baseUrl+"/master/userContribution/exportContributionStatQuery",
// {
// current: this.current,
// limit: this.limit
// },
// {
// responseType: "blob" // 关键点:告诉 axios 返回的是二进制文件
// }
// );
} catch (err) {
this.$message.error("文件下载失败!");
// console.error("文件下载失败:", err);
@@ -301,7 +266,7 @@ export default {
async init() {
this.showCurrentMonth = "";
this.showCurrentMonthDate = "";
await this.getMonthsByYear(this.year);
await this.getMonthsByYear(this.selectYear);
await this.fetchAllMonthData();
},
getMonthsByYear(year) {
@@ -318,7 +283,7 @@ export default {
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.7)"
});
const year = this.year;
const year = this.selectYear;
const months = getMonths(year);
console.log("months", months);
// 构造请求数组
@@ -327,7 +292,7 @@ export default {
return this.$http({
url: this.$http.adornUrl(this.urlList.list),
method: "post",
data: this.$http.adornData({ date: `${year}-${m}` })
data: this.$http.adornData({ date: this.$commonJS.getDate(year,m) })
})
.then(res => {
if (res.data && res.data.code === 0) {
@@ -362,7 +327,7 @@ export default {
showClose: true
});
}
if (this.year == new Date().getFullYear()) {
if (this.selectYear == new Date().getFullYear()) {
const now = new Date();
const year = now.getFullYear();
const month = this.pad(now.getMonth() + 1);
@@ -408,7 +373,7 @@ export default {
.days {
display: grid;
grid-template-columns: repeat(3, 1fr);
font-size: 16px;
font-size: 18px;
}
.day {
text-align: center;
@@ -436,4 +401,7 @@ export default {
/deep/ .el-card .el-card__header {
padding: 8px 20px !important;
}
/deep/ .el-card .el-card__body {
padding: 15px !important;overflow-x: auto !important;
}
</style>

View File

@@ -34,7 +34,7 @@
</el-form>
<FullYearCalendar :urlList="urlList" ref="refCalendar" :year="Number(currentYear)" :marks="markedDates" v-if="currentYear" />
<FullYearCalendar :urlList="urlList" ref="refCalendar" :selectYear="Number(currentYear)" :marks="markedDates" v-if="currentYear" />

View File

@@ -0,0 +1,102 @@
<template>
<div class="mod-config" >
<el-form
:inline="true"
:model="dataForm"
@keyup.enter.native="getDataList()"
>
<el-form-item>
<div class="block">
<el-date-picker
v-model="currentYear"
type="year"
format="yyyy"
value-format="yyyy" :picker-options="pickerOptions"
placeholder="选择年份"
@change="handleYearChange"
/>
</div>
</el-form-item>
<el-button
type="primary"
size="small"
@click="
handleYearChange();
"
>刷新</el-button
>
</el-form>
<FullYearCalendar :urlList="urlList" ref="refCalendar" :selectYear="Number(currentYear)" :marks="markedDates" v-if="currentYear" />
</div>
</template>
<script>
import FullYearCalendar from "./FullYearCalendarCourse.vue";
export default {
data() {
return {
urlList:{
list:'/master/statistics/getUserCourseBuyInfoTotal',
export:'/master/statistics/getUserCourseBuyInfo',
},
currentYear: '',
dataForm:{},
pickerOptions: {
disabledDate(time) {
// 禁用今年以后的年份
return time.getFullYear() > new Date().getFullYear()
}
},
markedDates: {
"2019-01-01": "red",
"2019-02-14": "blue",
"2019-03-12": "yellow",
"2019-05-20": "blue",
"2019-06-10": "yellow"
}
};
},
components: { FullYearCalendar },
activated() {
this.currentYear = new Date().getFullYear().toString();
this.handleYearChange();
},
methods: {
handleYearChange() {
this.$nextTick(() => {
this.$refs.refCalendar.init();
})
},
}
};
</script>
<style scoped>
/deep/ .mod-config .el-table .el-table__cell {
padding: 4px 0 !important;
box-sizing: border-box;
}
/deep/ .mod-config .el-table .cell,
.el-table th div {
padding: 0 !important;
box-sizing: border-box;
}
/deep/ .el-form .el-form-item{
margin-bottom:10px !important;
}
</style>

View File

@@ -32,7 +32,7 @@
</el-form>
<FullYearCalendar :urlList="urlList" ref="refCalendar" :year="Number(currentYear)" :marks="markedDates" v-if="currentYear" />
<FullYearCalendar :urlList="urlList" ref="refCalendar" :selectYear="Number(currentYear)" :marks="markedDates" v-if="currentYear" />

View File

@@ -32,7 +32,7 @@
>
</el-form>
<FullYearCalendar :urlList="urlList" ref="refCalendar" :year="Number(currentYear)" :marks="markedDates" v-if="currentYear" />
<FullYearCalendar :urlList="urlList" ref="refCalendar" :selectYear="Number(currentYear)" :marks="markedDates" v-if="currentYear" />

View File

@@ -34,6 +34,55 @@
</el-upload>
</el-form-item>
<el-form-item label="支付方式" class="coin_block" prop="payType">
<div>
<el-radio-group v-model="dataForm.payType" >
<el-radio label="微信">微信</el-radio>
<el-radio label="支付宝">支付宝</el-radio>
<el-radio label="银行支付">银行支付</el-radio>
<el-radio label="海外支付">海外支付</el-radio>
<el-radio label="其他">其他</el-radio>
<!-- <el-radio label="其他">其他</el-radio> -->
</el-radio-group>
</div>
</el-form-item>
<el-form-item label="交易流水号">
<el-input
v-model="dataForm.orderSn"
placeholder="交易流水号"
>
</el-input>
</el-form-item>
<el-form-item label="金额">
<el-input
v-model="dataForm.fee"
placeholder="金额"
>
</el-input>
</el-form-item>
<el-form-item label="积分">
<el-input
v-model="dataForm.jf"
placeholder="积分"
>
</el-input>
</el-form-item>
<el-form-item label="备注">
<el-input
type="textarea"
v-model="dataForm.remark"
placeholder="备注"
></el-input>
</el-form-item>
<el-form-item label="解析结果" class="remark_block" v-if="resultStatus">
人员识别成功{{resultData.has.length}}
<span style=" color: #f56c6c;">未识别{{resultData.no.length}}</span>
@@ -88,6 +137,11 @@
file: '',
days: '',
catalogues: [],
"payType":"", //支付方式
"orderSn":"", //交易号
"fee":0, //金额
"jf":0, //积分
"remark":"" //备注
},
dataRule: {
course: [{
@@ -109,7 +163,8 @@
required: true,
message: '文件不能为空',
trigger: 'blur'
}]
}],
payType: [{ required: true, message: "请选择支付方式", trigger: "blur" }]
},
showList: false, //显示模糊数据
dataList: [],
@@ -253,6 +308,11 @@
this.$refs["dataForm"].validate(valid => {
if (valid) {
if(this.dataForm.orderSn==''&&this.dataForm.remark==''){
this.$message.error('请输入备注')
return false
}
this.dataListLoading = true;
this.$http({
url: this.$http.adornUrl("/master/userCourseBuy/AddCourses"),
@@ -260,7 +320,13 @@
data: this.$http.adornData({
catalogue_id: this.dataForm.catalogues.join(','),
days: days,
list: this.resultData.has
list: this.resultData.has,
"orderSn":this.dataForm.orderSn, //交易号
"fee":this.dataForm.fee, //金额
"jf":this.dataForm.jf, //积分
"remark":this.dataForm.remark , //备注
payType:'后台'+this.dataForm.payType,
})
}).then(({ data }) => {
if (data && data.code === 0) {

View File

@@ -97,7 +97,7 @@
>
<template slot-scope="scope">
<el-button
v-if="scope.row.remark.includes('订单编号为')"
v-if="scope.row.remark&&scope.row.remark.includes('订单编号为')"
type="text"
size="small"
@click="addOrUpdateHandle(scope.row)"

View File

@@ -499,6 +499,7 @@
<el-dialog
title="充值天医币"
destroy-on-close
:close-on-click-modal="false"
:visible.sync="adc"
append-to-body
@@ -545,7 +546,8 @@
</el-form-item>
<el-form-item label="支付方式" class="coin_block">
<div>
<el-radio-group v-model="dataForm.payMethod" >
<el-radio-group v-model="pointForm.payMethod" >
<el-radio label="微信">微信</el-radio>
<el-radio label="支付宝">支付宝</el-radio>
<el-radio label="银行支付">银行支付</el-radio>
@@ -911,6 +913,7 @@ export default {
},
// 充值扣款天医币
ck(e) {
this.pointForm={}
this.pointForm = e;
this.pointForm.pointType = 0;
this.adc = true;
@@ -940,7 +943,7 @@ export default {
this.$refs["pointForm"].validate(valid => {
this.$http({
url: this.$http.adornUrl(
`/book/user/pointChange?pointType=${this.pointForm.pointType}&note=${this.pointForm.remark?this.pointForm.remark:''}&pointAmount=${this.pointForm.pointAmount}&id=${this.pointForm.id}`
`/book/user/pointChange?pointType=${this.pointForm.pointType}&note=${this.pointForm.remark?this.pointForm.remark:''}&pointAmount=${this.pointForm.pointAmount}&id=${this.pointForm.id}&payMethod=${this.pointForm.payMethod?`${this.pointForm.payMethod}`:''}&payNo=${this.pointForm.payNo?`${this.pointForm.payNo}`:''}`
),
method: "get",
params: this.$http.adornParams()

View File

@@ -216,12 +216,136 @@
<el-form-item label="开通原因:" prop="come" style="width: 400px">
<el-input v-model="youForm.come" type="textarea" :rows="2" placeholder="请输入内容"></el-input>
</el-form-item>
<el-form-item label="支付方式" class="coin_block" prop="payType">
<div>
<el-radio-group v-model="youForm.payType" >
<el-radio label="微信">微信</el-radio>
<el-radio label="支付宝">支付宝</el-radio>
<el-radio label="银行支付">银行支付</el-radio>
<el-radio label="海外支付">海外支付</el-radio>
<el-radio label="其他">其他</el-radio>
<!-- <el-radio label="其他">其他</el-radio> -->
</el-radio-group>
</div>
</el-form-item>
<el-form-item label="交易流水号">
<el-input
v-model="youForm.orderSn"
placeholder="交易流水号"
>
</el-input>
</el-form-item>
<el-form-item label="金额">
<el-input
v-model="youForm.fee"
placeholder="金额"
>
</el-input>
</el-form-item>
<el-form-item label="积分">
<el-input
v-model="youForm.jf"
placeholder="积分"
>
</el-input>
</el-form-item>
<el-form-item label="备注">
<el-input
type="textarea"
v-model="youForm.remark"
placeholder="备注"
></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogClose">取消</el-button>
<el-button @click="submit" type="primary">确认开通</el-button>
</span>
</el-dialog>
<el-dialog
title="延期"
:close-on-click-modal="false"
:visible.sync="yanVisible"
append-to-body
width="60%"
@close="dialogCloseYan"
>
<el-form style="width:100%"
:model="yanForm"
label-width="100px"
ref="yanForm"
:rules="yanFormRule"
>
<el-form-item label="延期天数:" prop="days" style="width:400px">
<el-input v-model="yanForm.days" placeholder="请输入延期天数"><template slot="append"></template></el-input>
</el-form-item>
<el-form-item label="支付方式" class="coin_block" prop="payType">
<div>
<el-radio-group v-model="yanForm.payType" >
<el-radio label="微信">微信</el-radio>
<el-radio label="支付宝">支付宝</el-radio>
<el-radio label="银行支付">银行支付</el-radio>
<el-radio label="海外支付">海外支付</el-radio>
<el-radio label="其他">其他</el-radio>
<!-- <el-radio label="其他">其他</el-radio> -->
</el-radio-group>
</div>
</el-form-item>
<el-form-item label="交易流水号">
<el-input
v-model="yanForm.orderSn"
placeholder="交易流水号"
>
</el-input>
</el-form-item>
<el-form-item label="金额">
<el-input
v-model="yanForm.fee"
placeholder="金额"
>
</el-input>
</el-form-item>
<el-form-item label="积分">
<el-input
v-model="yanForm.jf"
placeholder="积分"
>
</el-input>
</el-form-item>
<el-form-item label="备注">
<el-input
v-model="yanForm.remark"
placeholder="备注"
>
</el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogCloseYan">取消</el-button>
<el-button @click="submitYan" type="primary">确认延期</el-button>
</span>
</el-dialog>
</div>
</template>
@@ -265,7 +389,13 @@ export default {
catalogueId: [
{ required: true, message: "请选择开通的分部", trigger: "blur" }
],
days: [{ required: true, message: "请选择开通时长", trigger: "blur" }]
days: [{ required: true, message: "请选择开通时长", trigger: "blur" }],
payType: [{ required: true, message: "请选择支付方式", trigger: "blur" }]
},
yanFormRule: {
days: [{ required: true, message: "请选择延期天数", trigger: "blur" }],
payType: [{ required: true, message: "请选择支付方式", trigger: "blur" }]
},
options: [],
timeOptions: [
@@ -313,8 +443,9 @@ export default {
dataListSelections: [],
youVisible: false,
yanVisible: false,
linshiids:[],
yanForm:{},
youForm: {
courseId: null,
cate: [],
@@ -351,31 +482,54 @@ export default {
},
methods: {
delay(val){
this.$prompt('请输入延期天数', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
// inputPattern: /[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?/,
// inputErrorMessage: '邮箱格式不正确'
}).then(({ value }) => {
console.log('value',value)
this.delaySubmit({
this.yanVisible = true;
this.yanForm={
id:val.id,
days:value
})
}).catch(() => {
// this.$message({
// type: 'info',
// message: '取消输入'
days:"",
"payType":"", //支付方式
"orderSn":"", //交易号
"fee":0, //金额
"jf":0, //积分
"remark":"" //备注
}
// this.$prompt('请输入延期天数', '提示', {
// confirmButtonText: '确定',
// cancelButtonText: '取消',
// // inputPattern: /[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?/,
// // inputErrorMessage: '邮箱格式不正确'
// }).then(({ value }) => {
// console.log('value',value)
// this.delaySubmit({
// id:val.id,
// days:value
// })
// }).catch(() => {
// // this.$message({
// // type: 'info',
// // message: '取消输入'
// // });
// });
});
},
submitYan(){
this.$refs['yanForm'].validate(valid => {
if (valid) {
if(this.yanForm.orderSn==''&&this.yanForm.remark==''){
this.$message.error('请输入备注')
return false
}
this.delaySubmit(this.yanForm)
}
})
},
delaySubmit(data){
this.$http({
url: this.$http.adornUrl("/master/userCourseBuy/delayUserCourseBuy"),
method: "post",
data: this.$http.adornData(data)
data: this.$http.adornData({...data,payType:'后台'+this.yanForm.payType,})
}).then(({ data }) => {
if (data && data.code == 0) {
this.yanVisible = false
this.$message.success('操作成功!')
this.getDataList()
} else {
@@ -417,9 +571,15 @@ export default {
this.youForm.catalogueId = this.linshiids.join(',')
this.$refs['youForm'].validate(valid => {
if (valid) {
if(this.youForm.orderSn==''&&this.youForm.remark==''){
this.$message.error('请输入备注')
return false
}
let data = {
userId:this.userId,
...this.youForm
...this.youForm,
payType:'后台'+this.youForm.payType,
}
delete data.cate
console.log('data',data)
@@ -489,7 +649,18 @@ export default {
},
showAddD() {
this.linshiids = []
this.youForm={
courseId: null,
cate: [],
catalogueId: '',
days: "",
come:"", //管理员开通(原因)
"payType":"", //支付方式
"orderSn":"", //交易号
"fee":0, //金额
"jf":0, //积分
"remark":"" //备注
}
this.youVisible = true;
},

View File

@@ -115,6 +115,24 @@
>
</el-input>
</el-form-item>
<el-form-item label="付款时间" class="coin_block">
<div>
<el-date-picker
size="small"
v-model="dataForm.payTime"
type="datetime"
format="yyyy-MM-dd HH:mm:ss"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="选择付款时间"
>
</el-date-picker>
</div>
</el-form-item>
<el-form-item label="金额" class="coin_block">
<div>
<el-input
@@ -324,6 +342,10 @@ export default {
this.$message.error("请输入交易流水号");
return;
}
if (this.dataForm.payTime == "") {
this.$message.error("请选择付款时间");
return;
}
var data = {
...this.dataForm,

View File

@@ -1,5 +1,6 @@
<template>
<div class="mod-config">
<!-- 订单详细更新 -->
<!-- <div class="orderType">
<span v-if="orderDetails.orderStatus == 0" class="item hightLight0"
@@ -259,6 +260,7 @@
<span @click="handleYear('4')">4 年</span>
</div>
</el-form-item>
<el-form-item label="来源" class="coin_block">
<div>
<el-radio-group v-model="dataForm.type">
@@ -300,11 +302,34 @@
clearable
style=""
v-model="dataForm.orderSn"
placeholder="请输入关联订单号"
:placeholder="
dataForm.type == 'order'
? '订单号'
: dataForm.payType == '微信' || dataForm.payType == '支付宝'
? '交易流水号'
: '订单号'
"
>
</el-input>
</div>
</el-form-item>
<el-form-item label="付款时间" class="coin_block">
<div>
<el-date-picker
size="small"
v-model="dataForm.payTime"
type="datetime"
format="yyyy-MM-dd HH:mm:ss"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="选择付款时间"
>
</el-date-picker>
</div>
</el-form-item>
<el-form-item label="金额" class="coin_block">
<div>
<el-input
@@ -439,6 +464,7 @@ export default {
// AddOrUpdate
},
activated() {
this.query.orderSn = this.$route.query.orderSn;
this.query.ordertype = this.$route.query.ordertype;
// console.log(this.$route.query.orderSn)
@@ -520,7 +546,6 @@ export default {
if (this.dataForm.payType) {
delete this.dataForm.orderSn;
}
if (this.dataForm.payType == "海外支付") {
this.dataForm.fee = 0;
@@ -529,12 +554,15 @@ export default {
this.$forceUpdate();
},
dataFormSubmit() {
this.$refs["dataForm"].validate(valid => {
if (valid) {
if (this.dataForm.startTime == "") {
this.$message.error("请选择开始时间");
return;
}
if (this.dataForm.endTime == "") {
this.$message.error("请选择结束时间");
return;
@@ -549,6 +577,7 @@ export default {
this.$message.error("请选择支付方式");
return;
}
if (this.dataForm.type == "order" && !this.dataForm.orderSn) {
this.$message.error("请输入订单号");
return;
@@ -563,7 +592,10 @@ export default {
this.$message.error("请输入交易流水号");
return;
}
if (this.dataForm.payTime == "") {
this.$message.error("请选择付款时间");
return;
}
if (this.dataForm.payType == "海外支付") {
this.dataForm.fee = 0;
this.dataForm.jf = 0;
@@ -590,10 +622,19 @@ export default {
if (data.vipType == 1 || data.vipType == 2) {
data.userVipId = "";
}
if( this.editType == "add"){
if (this.dataForm.type == "master") {
if (localStorage.getItem("userInfo")) {
data.adminId = JSON.parse(
localStorage.getItem("userInfo")
).userId;
} else {
data.adminId = 1;
}
}
}
}
this.$http({
url: this.$http.adornUrl(
@@ -663,6 +704,7 @@ export default {
vipType: data.type,
startTime: "",
endTime: "",
payTime: "",
jf: 0,
fee: 0
};