|
|
|
@ -1,10 +1,438 @@
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { ref } from 'vue'
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<view>签到</view>
|
|
|
|
|
<view class="checkin-container">
|
|
|
|
|
<!-- 累计时间显示 -->
|
|
|
|
|
<view>
|
|
|
|
|
<span>{{qdttitle}}</span>
|
|
|
|
|
</view>
|
|
|
|
|
<view v-if="finish==='no'">
|
|
|
|
|
<div class="time-display">
|
|
|
|
|
<span>累计时间</span>
|
|
|
|
|
<span>{{ formattedTime }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div v-if="selecttype === '普通签到'">
|
|
|
|
|
<!-- 立即签到按钮 -->
|
|
|
|
|
<button
|
|
|
|
|
v-if="totalTime > 0 "
|
|
|
|
|
@click="handleCheckIn"
|
|
|
|
|
class="checkin-button"
|
|
|
|
|
>
|
|
|
|
|
立即签到
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-if="selecttype === '伪签到'">
|
|
|
|
|
<!-- 立即签到按钮 -->
|
|
|
|
|
<button
|
|
|
|
|
v-if="totalTime > 0 "
|
|
|
|
|
@click="handleCheckIn"
|
|
|
|
|
class="checkin-button"
|
|
|
|
|
>
|
|
|
|
|
立即签到
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-if="selecttype === '密码签到'">
|
|
|
|
|
<div class="password-checkin">
|
|
|
|
|
<p>请输入签到密码</p>
|
|
|
|
|
<input type="password" v-model="password" placeholder="密码" />
|
|
|
|
|
<button @click="handlePasswordCheckIn">完成密码签到</button>
|
|
|
|
|
<div v-if="passwordCheckInResult" :class="['checkin-result', passwordCheckInResult === '签到成功' ? 'success' : 'error']">
|
|
|
|
|
{{ passwordCheckInResult }}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-if="selecttype === '二维码签到'">
|
|
|
|
|
<div class="scan-checkin">
|
|
|
|
|
<p>请扫描二维码进行签到</p>
|
|
|
|
|
<button @click="onDecode" class="scan-button">开始扫码</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<!-- 不可签到状态 -->
|
|
|
|
|
<div v-if="totalTime <= 0 && checkInResult !== '签到成功'" class="checkin-result">
|
|
|
|
|
不可签到
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<view v-if="finish==='finish'">
|
|
|
|
|
<!-- 签到成功提示 -->
|
|
|
|
|
<div v-if="selecttype!=='伪签到'" class="checkin-result">
|
|
|
|
|
{{ checkInResult }}
|
|
|
|
|
</div>
|
|
|
|
|
<div v-if="selecttype==='伪签到'" class="checkin-result">
|
|
|
|
|
请诚信学习
|
|
|
|
|
</div>
|
|
|
|
|
<div v-if="checkInResult === '签到成功'" class="checkin-result-time">
|
|
|
|
|
{{qidndaotime}}
|
|
|
|
|
</div>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { ref, onMounted, onUnmounted, computed } from 'vue';
|
|
|
|
|
import {onLoad} from "@dcloudio/uni-app";
|
|
|
|
|
import moment from "moment";
|
|
|
|
|
|
|
|
|
|
// 类型判断
|
|
|
|
|
const selecttype = ref('扫描签到');
|
|
|
|
|
const initialTime = 10; // 初始时间为 60 秒(可以根据需要调整)
|
|
|
|
|
const totalTime = ref(initialTime);
|
|
|
|
|
const intervalId = ref<number | null>(null); // 修改了此处的类型定义
|
|
|
|
|
const uid=ref('123')
|
|
|
|
|
const qdttitle=ref('')
|
|
|
|
|
// 累计时间格式化
|
|
|
|
|
const formattedTime = computed(() => {
|
|
|
|
|
const minutes = Math.floor(totalTime.value / 60);
|
|
|
|
|
const seconds = totalTime.value % 60;
|
|
|
|
|
return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const password = ref(''); // 密码输入框的值
|
|
|
|
|
const passwordCheckInResult = ref(''); // 密码签到结果
|
|
|
|
|
const endtime=ref('')
|
|
|
|
|
const finish=ref('no')
|
|
|
|
|
const qidndaotime=ref('')
|
|
|
|
|
const checkInResult = ref('');
|
|
|
|
|
const handlePasswordCheckIn = () => {
|
|
|
|
|
// 模拟密码验证逻辑
|
|
|
|
|
const correctPassword = '123456'; // 正确的密码(实际应用中应从后端获取)
|
|
|
|
|
|
|
|
|
|
if (totalTime.value > 0) {
|
|
|
|
|
uni.request({
|
|
|
|
|
url: 'http://localhost:3400/apistu/qdstuinclass_password',
|
|
|
|
|
method: 'POST',
|
|
|
|
|
data: { // 注意:GET 请求的参数需放在 `data` 而非 `params` 字段:ml-citation{ref="8" data="citationList"}
|
|
|
|
|
uuid: uid.value,
|
|
|
|
|
kch:'202413501',
|
|
|
|
|
kctime:'n8z1A1',
|
|
|
|
|
xuehao: '202413501062',
|
|
|
|
|
output:'no',
|
|
|
|
|
password:password.value,
|
|
|
|
|
time:moment().format('YYYY-MM-DD HH:mm:ss')
|
|
|
|
|
},
|
|
|
|
|
success: (res) => { /* ... */
|
|
|
|
|
if(res.data.stats==="ok") {
|
|
|
|
|
console.log(res.data);
|
|
|
|
|
passwordCheckInResult.value = '签到成功';
|
|
|
|
|
stopTimer(); // 签到后停止计时
|
|
|
|
|
}else{
|
|
|
|
|
uni.showModal({
|
|
|
|
|
title: '提示',
|
|
|
|
|
content: '签到密码错误',
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
passwordCheckInResult.value = '签到时间已结束';
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
onLoad((options) => {
|
|
|
|
|
console.log('load', options)
|
|
|
|
|
if(options) {
|
|
|
|
|
|
|
|
|
|
console.log('options:', options.uuid)
|
|
|
|
|
uni.request({
|
|
|
|
|
url: 'http://localhost:3400/apistu/getinclassactivestu_ex',
|
|
|
|
|
method: 'GET',
|
|
|
|
|
data: { // 注意:GET 请求的参数需放在 `data` 而非 `params` 字段:ml-citation{ref="8" data="citationList"}
|
|
|
|
|
uuid: options.uuid,
|
|
|
|
|
xuehao:'202413501062'
|
|
|
|
|
},
|
|
|
|
|
success: (res) => { /* ... */
|
|
|
|
|
console.log(res.data)
|
|
|
|
|
if(res.data.length>0) {
|
|
|
|
|
|
|
|
|
|
qidndaotime.value = res.data[0].time;
|
|
|
|
|
checkInResult.value = '签到成功';
|
|
|
|
|
finish.value = 'finish'
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
uid.value=options.uuid
|
|
|
|
|
|
|
|
|
|
uni.request({
|
|
|
|
|
url: 'http://localhost:3400/apistu/getinclassactive',
|
|
|
|
|
method: 'GET',
|
|
|
|
|
data: { // 注意:GET 请求的参数需放在 `data` 而非 `params` 字段:ml-citation{ref="8" data="citationList"}
|
|
|
|
|
uuid: options.uuid
|
|
|
|
|
},
|
|
|
|
|
success: (res) => { /* ... */
|
|
|
|
|
console.log(res.data)
|
|
|
|
|
let infor=JSON.parse(res.data.infor)
|
|
|
|
|
console.log(infor.endtime)
|
|
|
|
|
endtime.value = infor.endtime
|
|
|
|
|
qdttitle.value=infor.title
|
|
|
|
|
selecttype.value=infor.lxA
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
// 启动倒计时
|
|
|
|
|
const startTimer = () => {
|
|
|
|
|
intervalId.value = setInterval(() => {
|
|
|
|
|
if (totalTime.value > 0) {
|
|
|
|
|
|
|
|
|
|
totalTime.value=moment(endtime.value).diff(moment(),'seconds')
|
|
|
|
|
} else {
|
|
|
|
|
stopTimer();
|
|
|
|
|
}
|
|
|
|
|
}, 1000);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 停止倒计时
|
|
|
|
|
const stopTimer = () => {
|
|
|
|
|
if (intervalId.value !== null) {
|
|
|
|
|
clearInterval(intervalId.value);
|
|
|
|
|
intervalId.value = null;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 立即签到
|
|
|
|
|
|
|
|
|
|
const handleCheckIn = () => {
|
|
|
|
|
if (totalTime.value > 0) {
|
|
|
|
|
// 模拟签到逻辑
|
|
|
|
|
checkInResult.value = '签到成功';
|
|
|
|
|
|
|
|
|
|
stopTimer(); // 签到后停止计时
|
|
|
|
|
uni.request({
|
|
|
|
|
url: 'http://localhost:3400/apistu/qdstuinclass',
|
|
|
|
|
method: 'POST',
|
|
|
|
|
data: { // 注意:GET 请求的参数需放在 `data` 而非 `params` 字段:ml-citation{ref="8" data="citationList"}
|
|
|
|
|
uuid: uid.value,
|
|
|
|
|
kch:'202413501',
|
|
|
|
|
kctime:'n8z1A1',
|
|
|
|
|
xuehao: '202413501062',
|
|
|
|
|
output:'no',
|
|
|
|
|
time:moment().format('YYYY-MM-DD HH:mm:ss')
|
|
|
|
|
},
|
|
|
|
|
success: (res) => { /* ... */
|
|
|
|
|
finish.value='finish'
|
|
|
|
|
checkInResult.value = '签到成功';
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
checkInResult.value = '已过签到时间';
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 处理扫描结果
|
|
|
|
|
const onDecode = () => {
|
|
|
|
|
uni.scanCode({
|
|
|
|
|
success: (res) => {
|
|
|
|
|
console.log('扫码结果:', res.result);
|
|
|
|
|
|
|
|
|
|
if (totalTime.value > 0) {
|
|
|
|
|
console.log(1245)
|
|
|
|
|
if(JSON.parse(res.result).qduuid){
|
|
|
|
|
uni.request({
|
|
|
|
|
url: 'http://localhost:3400/apistu/qdstuinclass_qrcode1',
|
|
|
|
|
method: 'POST',
|
|
|
|
|
data: { // 注意:GET 请求的参数需放在 `data` 而非 `params` 字段:ml-citation{ref="8" data="citationList"}
|
|
|
|
|
uuid: uid.value,
|
|
|
|
|
kch:'202413501',
|
|
|
|
|
kctime:'n8z1A1',
|
|
|
|
|
xuehao: '202413501062',
|
|
|
|
|
output:'no',
|
|
|
|
|
qduuid:JSON.parse(res.result).qduuid,
|
|
|
|
|
time:moment().format('YYYY-MM-DD HH:mm:ss')
|
|
|
|
|
},
|
|
|
|
|
success: (res_2) => { /* ... */
|
|
|
|
|
if(res_2.data.stats==="ok") {
|
|
|
|
|
console.log(res.data);
|
|
|
|
|
passwordCheckInResult.value = '签到成功';
|
|
|
|
|
uni.$emit('finish', uid.value)
|
|
|
|
|
stopTimer(); // 签到后停止计时
|
|
|
|
|
}else{
|
|
|
|
|
uni.showModal({
|
|
|
|
|
title: '提示',
|
|
|
|
|
content: '签到密码错误',
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
checkInResult.value = '签到成功';
|
|
|
|
|
|
|
|
|
|
stopTimer();
|
|
|
|
|
} else {
|
|
|
|
|
checkInResult.value = '已过签到时间';
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
fail: (err) => {
|
|
|
|
|
console.error('扫码失败:', err);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 页面挂载时启动倒计时
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
startTimer();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 页面卸载时停止倒计时
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
stopTimer();
|
|
|
|
|
});
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
</style>
|
|
|
|
|
.checkin-container {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
height: 100vh; /* 使容器高度为视口高度 */
|
|
|
|
|
padding: 20px;
|
|
|
|
|
background-color: #f9f9f9;
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.time-display {
|
|
|
|
|
text-align: center;
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
font-size: 14px; /* 缩小“累计时间”文本的字体大小 */
|
|
|
|
|
color: #333;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.time-display span:first-child {
|
|
|
|
|
display: block;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
color: #666;
|
|
|
|
|
margin-bottom: 5px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.time-display span:last-child {
|
|
|
|
|
font-size: 36px;
|
|
|
|
|
color: #333;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.checkin-button {
|
|
|
|
|
background-color: #ff4d4f;
|
|
|
|
|
color: white;
|
|
|
|
|
border: none;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
width: 150px; /* 进一步增大按钮尺寸 */
|
|
|
|
|
height: 150px;
|
|
|
|
|
font-size: 24px; /* 增大按钮内文字的字体大小 */
|
|
|
|
|
transition: background-color 0.3s;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
margin: 20px 0; /* 调整按钮与上下元素的间距 */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.checkin-button:hover {
|
|
|
|
|
background-color: #e53935;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.checkin-result {
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
color: green;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.password-checkin {
|
|
|
|
|
text-align: center;
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.password-checkin p {
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
color: #333;
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.password-checkin input {
|
|
|
|
|
padding: 10px;
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
border: 1px solid #ccc;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
width: 200px;
|
|
|
|
|
text-align: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.password-checkin button {
|
|
|
|
|
background-color: #ff4d4f;
|
|
|
|
|
color: white;
|
|
|
|
|
border: none;
|
|
|
|
|
border-radius: 50px;
|
|
|
|
|
width: 150px;
|
|
|
|
|
height: 40px;
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
transition: background-color 0.3s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.password-checkin button:hover {
|
|
|
|
|
background-color: #e53935;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.checkin-result {
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
margin-left: 10px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.checkin-result.success {
|
|
|
|
|
color: green;
|
|
|
|
|
}
|
|
|
|
|
.checkin-result-time {
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
color: #7f8fa6;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.checkin-result-time.success {
|
|
|
|
|
color: green;
|
|
|
|
|
}
|
|
|
|
|
.checkin-result.error {
|
|
|
|
|
color: red;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.scan-checkin {
|
|
|
|
|
text-align: center;
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.scan-checkin p {
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
color: #333;
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
}
|
|
|
|
|
.scan-button {
|
|
|
|
|
background-color: #4CAF50; /* 绿色背景 */
|
|
|
|
|
color: white;
|
|
|
|
|
border: none;
|
|
|
|
|
border-radius: 50px; /* 圆角按钮 */
|
|
|
|
|
padding: 12px 24px;
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
width: 80%;
|
|
|
|
|
max-width: 300px;
|
|
|
|
|
margin: 10px auto;
|
|
|
|
|
display: block;
|
|
|
|
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); /* 阴影增加质感 */
|
|
|
|
|
transition: background-color 0.3s ease, transform 0.2s ease;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.scan-button:hover {
|
|
|
|
|
background-color: #45a049;
|
|
|
|
|
transform: translateY(-2px); /* 微动效果 */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.scan-button:active {
|
|
|
|
|
transform: scale(0.98); /* 按下缩小一点 */
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|