Merge branch 'develop' of http://25.13.9.101:9000/K17_AITS/tra-app into develop

This commit is contained in:
杨航
2025-10-29 14:37:48 +08:00
26 changed files with 1043 additions and 180 deletions
+1 -1
View File
@@ -19,7 +19,7 @@
</template>
<script setup>
import { ref, reactive, onMounted, nextTick, computed, toRaw, watch } from 'vue';
import { ref, reactive, onMounted, nextTick, computed, watch } from 'vue';
import { optionErrorIcon, optionSuccessIcon } from '@/common/imgSvg';
const emit = defineEmits(['click_option']);
+17
View File
@@ -0,0 +1,17 @@
<template>
<view class="">
<uni-popup ref="popup" border-radius="10px 10px 0 0">
</uni-popup>
</view>
</template>
<script setup>
const popup = ref(null)
const open = () => {
}
defineExpose({open})
</script>
<style></style>
@@ -0,0 +1,417 @@
<template>
<view class="">
<uni-popup ref="popup">
<view class="popup-content" @touchmove.stop>
<view class="fl1"></view>
<view class="max-div">
<view class="popup_back_div" @click="close">
<image :src="optionErrorIcon('#C8BBB7')" class="img"></image>
</view>
<view class="title_div">
<image class="img" src="@/static/images/pointsAndRank/badge-wheat-left.png"></image>
<view class="title">每日签到</view>
<image class="img" src="@/static/images/pointsAndRank/badge-wheat-right.png"></image>
</view>
<view class="continuous-check-in-div">
<image class="img" src="@/static/images/pointsAndRank/badge-icon.png"></image>
<text class="text">
您已连续签到
<text class="number">27</text>
</text>
</view>
<scroll-view scroll-y="true" class="scroll-Y" :show-scrollbar="false">
<view class="calendar-div">
<view class="calendar-line" v-for="(line, lineIndex) in dateGroups">
<view
class="calendar-day"
v-for="(day, dayIndex) in line.days"
:class="{ hide: day.index > 30, expand: expand }"
>
<view class="calendar-day-bg" :class="[day.type, isSigned ? 'signed' : 'no-signed']">
<image
v-if="day.type === 'past' || (day.type === 'today' && isSigned)"
:src="optionSuccessIcon('#FFFFFF')"
class="img"
></image>
<text v-else>+{{ day.text }}</text>
<view class="check-in-tip"></view>
</view>
<view class="calendar-day-title">
{{ day.date }}
</view>
</view>
</view>
</view>
</scroll-view>
<view class="switch-div" @click="switchStatus()">
<view class="back_div">
<view class="back-icon"></view>
</view>
</view>
<view class="button-div">
<uv-button
class="button"
text="签到"
:custom-style="customStyle"
:color="buttonColor"
@click="expand = !expand"
></uv-button>
</view>
</view>
<view class="fl1"></view>
</view>
</uni-popup>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { optionErrorIcon, optionSuccessIcon } from '@/common/imgSvg';
const popup = ref(null);
const buttonColor = 'linear-gradient( 270deg, #E0914A 0%, #EDBE7F 100%)';
const customStyle = {
borderRadius: '40rpx' //圆角
};
const dateGroups = ref([]);
const expand = ref(true); // 展开状态
const isSigned = ref(false); // 今日签到状态
// 切换显示状态
const switchStatus = () => {
}
// 退出签到
const close = () => {
popup.value.close();
}
/**
* 生成35天日期列表(分5组,每组7天),包含类型标记和text字段
* 以"前X天"为第一天,第1天显示1,每7天显示5,第30天显示30
* @param {number} X - 前X天的天数(0-35之间的整数,总天数=35)
* @returns {Array<{
* groupIndex: number, // 组索引(0-4
* days: Array<{
* date: string, // mm-dd格式日期
* type: 'past' | 'today' | 'future', // 日期类型
* index: number, // 相对今天的索引(负数为过去,正数为未来)
* text: string // 显示文本(1/5/30
* }>
* }>} 分组后的日期列表
*/
function generateGroupedDateList(X) {
if (X < 0 || X > 35 || !Number.isInteger(X)) {
throw new Error('X必须是0到35之间的整数');
}
const allDays = [];
const today = new Date();
const todayDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());
// 生成前X天到后(35-X)天的所有日期(共35天)
for (let i = -X; i <= 35 - X - 1; i++) {
const currentDate = new Date(today);
currentDate.setDate(today.getDate() + i);
const pureDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate());
// 确定日期类型
let type;
if (pureDate < todayDate) type = 'past';
else if (pureDate > todayDate) type = 'future';
else type = 'today';
// 格式化日期
const month = String(currentDate.getMonth() + 1).padStart(2, '0');
const day = String(currentDate.getDate()).padStart(2, '0');
// 计算当前是第几天(以"前X天"为第1天)
const dayNumber = i - -X + 1; // 核心计算:转换为从1开始的序列
// 计算text字段
let text = '1'; // 默认显示1
if (dayNumber === 30) {
text = '30'; // 第30天显示30
} else if ((dayNumber % 30) % 7 === 0) {
text = '5'; // 每7天(第7、14、21、28、35天)显示5
}
allDays.push({
date: `${month}.${day}`,
type,
index: i - -X + 1,
text,
i
});
}
// 每7天分为一组,共5组
const groupedList = [];
for (let i = 0; i < 5; i++) {
const start = i * 7;
const end = start + 7;
groupedList.push({
groupIndex: i,
days: allDays.slice(start, end)
});
}
return groupedList;
}
// 示例:X=10时,以"10天前"为第1天,生成35天列表
try {
const X = 10;
dateGroups.value = generateGroupedDateList(X);
console.log(`${X}天前为第1天的35天分组日期:`);
dateGroups.value.forEach((group) => {
console.log(`\n第${group.groupIndex + 1}组:`);
console.log(
group.days.map((day) => ({
日期: day.date,
天数序号: day.index, // 显示当前是第几天
text: day.text,
类型: day.type
}))
);
});
} catch (err) {
console.error(err.message);
}
const open = () => {
console.log('111111111');
popup.value.open();
};
defineExpose({ open, close });
</script>
<style scoped lang="scss">
// 日期
.calendar-day {
text-align: center;
// 隐藏展开时超过30天的样式
&.hide.expand {
.calendar-day-title {
width: 70rpx;
color: #fff;
}
.calendar-day-bg {
display: none;
}
}
.calendar-day-bg {
width: 70rpx;
height: 84rpx;
border-radius: 8rpx;
// 前面日期,代表已签到
display: flex;
align-items: center;
justify-content: center;
position: relative;
font-family: Arial, Arial;
font-size: 32rpx;
.img {
width: 32rpx;
margin-bottom: 6rpx;
}
&.past {
background-color: #ffd07c;
}
// 未来日期,代表未签到
&.future {
color: #d88f50;
font-weight: bold;
background: #ffe6b8;
border: 4rpx solid #ffd58a;
}
// 当前已签到和未签到
&.signed.today {
background-color: #ffd07c;
}
&.no-signed.today {
color: #d88f50;
font-weight: bold;
background: #ffe6b8;
border: 4rpx solid #ffd58a;
}
// 当天的签到小图标
.check-in-tip {
display: none;
}
&.today > .check-in-tip {
display: block;
position: absolute;
top: 0;
right: 0;
width: 30rpx;
height: 30rpx;
font-size: 20rpx;
border-radius: 50%;
border: 2rpx solid #fff;
box-shadow: 0 0 4rpx #fef5e6;
color: #fff;
font-weight: 400;
background-color: #f8831c;
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
/* 2. 解决文字被边框挤压:清除默认内边距,重置行高 */
padding: 0; /* 清除默认内边距(部分元素默认有padding) */
line-height: 1; /* 行高与字体大小一致,避免垂直方向多余空间 */
/* 3. 旋转30度(transform 旋转属性) */
transform: translate(30%, -40%) rotate(-30deg);
}
}
.calendar-day-title {
margin: 8rpx 0;
font-family: ArialMT;
font-size: 22rpx;
color: #999999;
line-height: 28rpx;
text-align: center;
font-style: normal;
}
}
.scroll-Y {
/**
* 26rpx 主盒子内间距
* 68rpx 标题高度
* 128rpx 日历高度
* 16rpx 日历下外间距
* 92rpx 下方按钮盒子高度
* 80rpx 切换盒子高度
*/
height: calc(100% - 26rpx - 68rpx - 128rpx - 16rpx - 92rpx - 80rpx - 8rpx );
}
.switch-div {
display: flex;
justify-content: center;
align-items: center;
height: 60rpx;
margin: 10rpx 30%;
.back_div {
.back-icon {
position: relative;
width: 40rpx;
height: 40rpx;
cursor: pointer;
}
.back-icon::before,
.back-icon::after {
content: '';
position: absolute;
transition: all 0.3s ease;
}
.back-icon::after {
top: 25%;
left: 25%;
width: 40%;
height: 40%;
border-top: 2rpx solid #bfbfbf;
border-left: 2rpx solid #bfbfbf;
transform: rotate(45deg);
}
}
}
.calendar-div {
display: flex;
flex-direction: column;
.calendar-line {
display: flex;
justify-content: space-between;
}
}
.button-div {
height: 92rpx;
width: 442rpx;
margin: 0 auto;
.button {
width: 100%;
height: 100%;
}
}
.continuous-check-in-div {
display: flex;
border-bottom: 2rpx solid #efefef;
margin-bottom: 16rpx;
padding-top: 8rpx;
height: 128rpx;
.img {
width: 112rpx;
height: 102rpx;
}
.text {
margin-left: 16rpx;
font-weight: 400;
font-size: 30rpx;
height: 82rpx;
color: #333333;
display: flex;
align-items: flex-end;
}
.number {
font-weight: 600;
color: #0066ff;
font-family: Arial Black;
}
}
.title_div {
display: flex;
align-items: center;
justify-content: center;
margin-top: 34rpx;
height: 68rpx;
.img {
width: 26rpx;
height: 44rpx;
}
.title {
font-family: AlimamaShuHeiTi, AlimamaShuHeiTi;
font-weight: bold;
font-size: 46rpx;
color: #d88f50;
margin: 0rpx 30rpx;
text-align: center;
}
}
.popup_back_div {
width: 60rpx;
height: 60rpx;
position: absolute;
top: 20rpx;
right: 20rpx;
.img {
margin: 10rpx;
width: 40rpx;
height: 40rpx;
}
}
.popup-content {
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
padding: 40rpx 0;
}
.max-div {
width: 80vw;
background-color: #fefbfa;
border-radius: 38rpx;
position: relative;
padding: 26rpx;
overflow: hidden;
margin-top: var(--status-bar-height);
margin-bottom: 120rpx;
}
</style>
@@ -0,0 +1,8 @@
<template>
</template>
<script>
</script>
<style>
</style>