| src/App.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/api/login.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/pages.json | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/pages/attendance/checkin.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/pages/attendance/report.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/pages/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/pages/login.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/pages_template/pages/login/index2.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/App.vue
@@ -28,6 +28,8 @@ console.log("ä½¿ç¨ plus.push.getClientInfo è·å客æ·ç«¯æ è¯"); plus.push.getClientInfoAsync(info => { console.log("客æ·ç«¯æ¨éæ è¯:", info); uni.setStorageSync("clientid", info.clientid); // è¿éå¯ä»¥å°å®¢æ·ç«¯æ è¯åéå°æå¡å¨ }); setTimeout(() => { src/api/login.js
@@ -48,4 +48,13 @@ method: 'get', params: params }) } // åé客æ·ç«¯æ¨éæ è¯å°æå¡å¨ export function updateClientId(data) { return request({ url: '/system/client/addOrUpdateClientId', method: 'post', data: data }) } src/pages.json
@@ -856,6 +856,20 @@ "navigationBarTitleText": "å¹è®è®°å½", "navigationStyle": "custom" } }, { "path": "pages/attendance/checkin", "style": { "navigationBarTitleText": "æå¡ç¾å°", "navigationStyle": "custom" } }, { "path": "pages/attendance/report", "style": { "navigationBarTitleText": "è夿¥æ¥", "navigationStyle": "custom" } } ], "subPackages": [ src/pages/attendance/checkin.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,855 @@ <template> <view class="attendance-checkin"> <!-- 页é¢å¤´é¨ --> <PageHeader title="æå¡ç¾å°" @back="goBack" /> <!-- 仿¥èå¤åºå --> <view class="today-attendance"> <view class="attendance-header"> <text class="attendance-title">仿¥èå¤</text> </view> <!-- çæ¬¡ä¿¡æ¯ --> <view class="shift-info"> <view class="shift-item"> <u-icon name="calendar" color="#348fe2" size="16"></u-icon> <text class="shift-text">ç½ç: 09:00-18:00</text> </view> <!-- <view v-if="todayRecord?.checkInTime" class="shift-item"> <u-icon name="checkmark-circle" color="#4cd964" size="16"></u-icon> <text class="shift-text">{{ todayRecord.checkInTime }}å·²æå¡</text> </view> --> </view> <!-- æå¡æé® --> <view class="checkin-button-container"> <view class="checkin-button-wrapper"> <view class="checkin-button" :class="{ 'disabled': checkInOutText === 'å·²æå¡' }" @click="handleCheckInOut"> <text class="checkin-button-text">{{ checkInOutText }}</text> <text class="checkin-time">{{ nowTime.split(' ')[1] }}</text> </view> </view> <!-- æå¡èå´ç¶æ --> </view> </view> <!-- æçèå¤è®°å½ --> <view class="attendance-records"> <view class="records-header"> <text class="records-title">仿¥èå¤</text> <view @click="navigateToReport" class="detail-button">æ¥ç详æ </view> </view> <!-- åå·¥ä¿¡æ¯ --> <view class="employee-info"> <view class="info-item"> <text class="info-label">é¨é¨</text> <text class="info-value">{{ currentUser.dept }}</text> </view> <view class="info-item"> <text class="info-label">å§å</text> <text class="info-value">{{ currentUser.name }}</text> </view> <view class="info-item"> <text class="info-label">å·¥å·</text> <text class="info-value">{{ currentUser.no }}</text> </view> </view> <!-- 仿¥èå¤ç¶æ --> <view class="today-status"> <u-icon :name="todayRecord ? 'checkmark-circle' : 'close-circle'" :color="todayRecord ? '#4cd964' : '#ff3b30'" size="16"></u-icon> <text class="status-text"> {{ todayRecord ? `仿¥èå¤: ä¸ç ${todayRecord.checkInTime}` : '仿¥æªæå¡' }} </text> </view> <!-- ä¸çèå¤ç¶æ --> <view v-if="todayRecord && todayRecord.checkOutTime" class="today-status"> <u-icon :name="todayRecord ? 'checkmark-circle' : 'close-circle'" :color="todayRecord ? '#4cd964' : '#ff3b30'" size="16"></u-icon> <text class="status-text"> {{ `仿¥èå¤: ä¸ç ${todayRecord.checkOutTime}` }} </text> </view> <!-- æå¡ç¶æ --> <view v-if="todayRecord" class="today-status"> <u-icon :name="todayRecord.status === 'normal' ? 'checkmark-circle' : 'clock'" :color="todayRecord.status === 'normal' ? '#4cd964' : '#ff3b30'" size="16"></u-icon> <text class="status-text"> {{ `æå¡ç¶æ: ${todayRecord.statusText}` }} </text> </view> <view v-else class="today-status"> <u-icon name="clock" color="#ff3b30" size="16"></u-icon> <text class="status-text"> æå¡ç¶æ: ç¼ºå¡ </text> </view> </view> </view> </template> <script setup> import { ref, reactive, computed, onMounted, onBeforeUnmount } from "vue"; import PageHeader from "@/components/PageHeader.vue"; // 模æå½åç»å½åå·¥ const currentUser = reactive({ id: 1, name: "å¼ ä¸", no: "E10001", dept: "ç产ä¸é¨", }); // 模æèå¤åå§æ°æ® const rawAttendance = ref([ { id: 2, date: "2026-02-08", userId: 1, name: "å¼ ä¸", no: "E10001", dept: "ç产ä¸é¨", checkInTime: "09:15", checkOutTime: "18:05", workHours: 8.8, status: "late", statusText: "è¿å°", remark: "å äº¤éæ¥å µè¿å°", }, { id: 3, date: "2026-02-07", userId: 1, name: "å¼ ä¸", no: "E10001", dept: "ç产ä¸é¨", checkInTime: "08:45", checkOutTime: "18:30", workHours: 9.7, status: "normal", statusText: "æ£å¸¸", remark: "å ç0.5å°æ¶", }, ]); // å½åæ¶é´å±ç¤º const nowTime = ref(""); let timer = null; // è¿åä¸ä¸é¡µ const goBack = () => { uni.navigateBack(); }; // æå¡èå´ç¶æ const inCheckRange = ref(true); // å½åä½ç½® const currentLocation = ref(null); const updateNowTime = () => { const now = new Date(); const Y = now.getFullYear(); const M = String(now.getMonth() + 1).padStart(2, "0"); const D = String(now.getDate()).padStart(2, "0"); const h = String(now.getHours()).padStart(2, "0"); const m = String(now.getMinutes()).padStart(2, "0"); const s = String(now.getSeconds()).padStart(2, "0"); nowTime.value = `${Y}-${M}-${D} ${h}:${m}:${s}`; }; // 仿¥æ¥æ const todayStr = computed(() => nowTime.value.slice(0, 10)); // 彿¥å½ååå·¥èå¤è®°å½ const todayRecord = computed(() => rawAttendance.value.find( item => item.userId === currentUser.id && item.date === todayStr.value ) ); // æå¡æé®ææ¬ const checkInOutText = computed(() => { if (!todayRecord.value || !todayRecord.value.checkInTime) { return "ä¸çæå¡"; } if (!todayRecord.value.checkOutTime) { return "ä¸çæå¡"; } return "å·²æå¡"; }); // çææè¿æ¥æ const recentDates = computed(() => { const dates = []; const today = new Date(); // è·åæè¿7å¤©çæ¥æ for (let i = 6; i >= 0; i--) { const date = new Date(today); date.setDate(today.getDate() - i); const dateStr = `${date.getFullYear()}-${String( date.getMonth() + 1 ).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`; const hasRecord = rawAttendance.value.some(item => item.date === dateStr); dates.push({ date: dateStr, day: date.getDate(), isToday: i === 0, hasRecord, }); } return dates; }); // 导èªå°è¯¦ç»æ¥åé¡µé¢ const navigateToReport = () => { uni.navigateTo({ url: "/pages/attendance/report", }); }; // è·åä½ç½®æé const getLocationPermission = () => { return new Promise((resolve, reject) => { // #ifdef APP-PLUS uni.getAppAuthorizeSetting({ success: res => { if (res.authSetting["scope.userLocation"]) { resolve(true); } else { uni.requestAppAuthorize({ scope: "scope.userLocation", success: res => { resolve(res.authSetting["scope.userLocation"]); }, fail: err => { reject(err); }, }); } }, fail: err => { reject(err); }, }); // #else // éAPPç¯å¢ç´æ¥è¿åæå resolve(true); // #endif }); }; // è·åå½åä½ç½® const getCurrentLocation = () => { return new Promise((resolve, reject) => { uni.getLocation({ type: "wgs84", success: res => { currentLocation.value = res; // æ¨¡ææ£æ¥æ¯å¦å¨æå¡èå´å ï¼å®é 项ç®ä¸åºæ ¹æ®å ¬å¸ä½ç½®åå 许çåå¾è¿è¡è®¡ç®ï¼ // è¿éç®å模æä¸ºå§ç»å¨èå´å inCheckRange.value = true; resolve(res); }, fail: err => { console.error("è·åä½ç½®å¤±è´¥:", err); // 失败æ¶é»è®¤å 许æå¡ï¼å®é 项ç®ä¸åºæ ¹æ®ä¸å¡éæ±å¤çï¼ inCheckRange.value = true; reject(err); }, }); }); }; // æå¡é»è¾ï¼ä» å端模æï¼ const handleCheckInOut = async () => { // æ£æ¥æ¯å¦å¨æå¡èå´å if (!inCheckRange.value) { uni.showToast({ title: "ä¸å¨æå¡èå´å ï¼æ æ³æå¡", icon: "none", }); return; } const [dateStr, timeStr] = nowTime.value.split(" "); if (!dateStr || !timeStr) return; // ä¸çæå¡ if (!todayRecord.value) { const newId = rawAttendance.value.length ? Math.max(...rawAttendance.value.map(i => i.id)) + 1 : 1; const status = timeStr > "09:00:00" ? "late" : "normal"; const statusText = status === "late" ? "è¿å°" : "æ£å¸¸"; rawAttendance.value.push({ id: newId, date: dateStr, userId: currentUser.id, name: currentUser.name, no: currentUser.no, dept: currentUser.dept, checkInTime: timeStr.slice(0, 5), checkOutTime: "", workHours: null, status, statusText, remark: "", }); uni.showToast({ title: "ä¸çæå¡æå", icon: "success", }); } else if (!todayRecord.value.checkOutTime) { // ä¸çæå¡ todayRecord.value.checkOutTime = timeStr.slice(0, 5); // ç®åæ 9:00-18:00 计ç®å·¥æ¶ const start = todayRecord.value.checkInTime || "09:00"; const [sh, sm] = start.split(":").map(v => parseInt(v, 10)); const [eh, em] = todayRecord.value.checkOutTime .split(":") .map(v => parseInt(v, 10)); const diff = (eh * 60 + em - (sh * 60 + sm)) / 60; todayRecord.value.workHours = Number(Math.max(diff, 0).toFixed(1)); // æ©é夿ï¼18:00 å离å¼è§ä¸ºæ©éï¼åªç¤ºæï¼ if (timeStr < "18:00:00") { if (todayRecord.value.status === "late") { // æ¢è¿å°åæ©é todayRecord.value.status = "late-early"; todayRecord.value.statusText = "è¿å° + æ©é"; } else { // ä» æ©é todayRecord.value.status = "early"; todayRecord.value.statusText = "æ©é"; } } else if (todayRecord.value.status === "normal") { todayRecord.value.statusText = "æ£å¸¸"; } uni.showToast({ title: "ä¸çæå¡æå", icon: "success", }); } else { uni.showToast({ title: "仿¥å·²å®æä¸ä¸çæå¡", icon: "none", }); } }; onMounted(async () => { updateNowTime(); timer = setInterval(updateNowTime, 1000); // è·åä½ç½®æéå¹¶æ£æ¥ä½ç½® try { await getLocationPermission(); await getCurrentLocation(); } catch (error) { console.error("ä½ç½®æéè·å失败:", error); } }); onBeforeUnmount(() => { if (timer) { clearInterval(timer); } }); </script> <style scoped lang="scss"> // å ¨å±åé $primary-color: #2c7be5; $primary-light: #4a90e2; $success-color: #4cd964; $warning-color: #ff9500; $danger-color: #ff3b30; $text-primary: #333333; $text-secondary: #666666; $text-tertiary: #999999; $bg-color: #f5f7fa; $card-bg: #ffffff; $border-color: #e8e8e8; $shadow-sm: 0 2rpx 8rpx rgba(0, 0, 0, 0.08); $shadow-md: 0 4rpx 16rpx rgba(0, 0, 0, 0.12); $shadow-lg: 0 8rpx 24rpx rgba(0, 0, 0, 0.15); .attendance-checkin { min-height: 100vh; background-color: $bg-color; padding-bottom: 30rpx; background-image: linear-gradient(135deg, #f5f7fa 0%, #e4e8f0 100%); display: flex; flex-direction: column; } /* 仿¥èå¤åºå */ .today-attendance { background-color: $card-bg; margin: 20rpx; border-radius: 16rpx; box-shadow: $shadow-md; padding: 32rpx; transition: all 0.3s ease; flex: 1; display: flex; flex-direction: column; } .today-attendance:hover { box-shadow: $shadow-lg; transform: translateY(-2rpx); } .attendance-header { margin-bottom: 24rpx; display: flex; align-items: center; } .attendance-title { font-size: 18px; font-weight: 600; color: $text-primary; position: relative; padding-left: 16rpx; } .attendance-title::before { content: ""; position: absolute; left: 0; top: 50%; transform: translateY(-50%); width: 4rpx; height: 20rpx; background-color: $primary-color; border-radius: 2rpx; } /* çæ¬¡ä¿¡æ¯ */ .shift-info { margin-bottom: 36rpx; padding: 20rpx; background-color: rgba($primary-color, 0.05); border-radius: 12rpx; border-left: 4rpx solid $primary-color; } .shift-item { display: flex; align-items: center; margin-bottom: 16rpx; } .shift-item:last-child { margin-bottom: 0; } .shift-item u-icon { margin-right: 14rpx; transition: all 0.3s ease; } .shift-item:hover u-icon { transform: scale(1.1); } .shift-text { font-size: 14px; color: $text-secondary; font-weight: 500; } /* æå¡æé®å®¹å¨ */ .checkin-button-container { display: flex; flex-direction: column; align-items: center; margin-bottom: 20rpx; flex: 1; justify-content: center; } /* æå¡æé® */ .checkin-button-wrapper { position: relative; margin-bottom: 36rpx; margin-top: 40rpx; } .checkin-button { width: 260rpx; height: 260rpx; border-radius: 50%; background: linear-gradient(135deg, $primary-color, $primary-light); display: flex; flex-direction: column; align-items: center; justify-content: center; box-shadow: 0 8rpx 32rpx rgba($primary-color, 0.4); transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); cursor: pointer; position: relative; overflow: hidden; } .checkin-button::before { content: ""; position: absolute; top: -50%; left: -50%; width: 200%; height: 200%; background: linear-gradient( 45deg, transparent, rgba(255, 255, 255, 0.1), transparent ); transform: rotate(45deg); animation: shine 3s infinite; opacity: 0; } @keyframes shine { 0% { transform: translateX(-100%) rotate(45deg); opacity: 0; } 50% { opacity: 0.3; } 100% { transform: translateX(100%) rotate(45deg); opacity: 0; } } .checkin-button:hover:not(.disabled) { transform: scale(1.08); box-shadow: 0 12rpx 40rpx rgba($primary-color, 0.5); } .checkin-button:active:not(.disabled) { transform: scale(0.98); } .checkin-button.disabled { background: linear-gradient(135deg, #d1d1d6, #e5e5ea); box-shadow: $shadow-sm; cursor: not-allowed; } .checkin-button-text { font-size: 22px; font-weight: 700; color: #ffffff; margin-bottom: 12rpx; text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1); z-index: 1; } .checkin-time { font-size: 16px; color: rgba(255, 255, 255, 0.95); font-weight: 500; z-index: 1; } /* æå¡èå´ç¶æ */ .location-status { display: flex; align-items: center; margin-top: 16rpx; padding: 16rpx 24rpx; background-color: rgba($success-color, 0.05); border-radius: 8rpx; border-left: 4rpx solid $success-color; transition: all 0.3s ease; } .location-status.warning { background-color: rgba($danger-color, 0.05); border-left-color: $danger-color; } .location-status u-icon { margin-right: 10rpx; animation: pulse 2s infinite; } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.1); } 100% { transform: scale(1); } } .location-text { font-size: 14px; color: $text-secondary; font-weight: 500; } .location-text.warning { color: $danger-color; } /* èå¤è®°å½åºå */ .attendance-records { background-color: $card-bg; margin: 0 20rpx 20rpx; border-radius: 16rpx; box-shadow: $shadow-md; padding: 32rpx; transition: all 0.3s ease; } .attendance-records:hover { box-shadow: $shadow-lg; transform: translateY(-2rpx); } .records-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24rpx; padding-bottom: 16rpx; border-bottom: 1rpx solid $border-color; } .records-title { font-size: 16px; font-weight: 600; color: $text-primary; position: relative; padding-left: 12rpx; width: 300rpx; } .records-title::before { content: ""; position: absolute; left: 0; top: 50%; transform: translateY(-50%); width: 3rpx; height: 16rpx; background-color: $primary-color; border-radius: 1.5rpx; } .detail-button { font-size: 14px; color: $primary-color; font-weight: 500; transition: all 0.3s ease; padding: 8rpx 16rpx; border-radius: 6rpx; float: right; } .detail-button:hover { background-color: rgba($primary-color, 0.1); transform: translateX(4rpx); } /* åå·¥ä¿¡æ¯ */ .employee-info { background-color: rgba($primary-color, 0.05); border-radius: 12rpx; padding: 20rpx; margin-bottom: 24rpx; } .info-item { display: flex; align-items: center; margin-bottom: 12rpx; } .info-item:last-child { margin-bottom: 0; } .info-label { font-size: 13px; color: $text-secondary; font-weight: 500; width: 80rpx; } .info-value { font-size: 13px; color: $text-primary; font-weight: 500; flex: 1; } /* æ¥æéæ©å¨ */ .date-picker { margin-bottom: 24rpx; } .weekday { display: inline-block; width: 44rpx; text-align: center; font-size: 12px; color: $text-tertiary; margin-bottom: 12rpx; font-weight: 500; } .date-items { display: flex; justify-content: space-between; } .date-item { width: 44rpx; height: 44rpx; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 14px; color: $text-secondary; background-color: rgba($primary-color, 0.05); transition: all 0.3s ease; cursor: pointer; } .date-item:hover { background-color: rgba($primary-color, 0.1); transform: scale(1.1); } .date-item.active { background-color: $primary-color; color: #ffffff; font-weight: 600; box-shadow: 0 2rpx 8rpx rgba($primary-color, 0.3); } .date-item.has-record { position: relative; } .date-item.has-record::after { content: ""; position: absolute; bottom: 4rpx; width: 8rpx; height: 8rpx; border-radius: 50%; background-color: $success-color; box-shadow: 0 1rpx 2rpx rgba($success-color, 0.3); } /* 仿¥èå¤ç¶æ */ .today-status { display: flex; align-items: center; margin-top: 24rpx; padding: 20rpx; background-color: rgba($primary-color, 0.05); border-radius: 12rpx; transition: all 0.3s ease; } .today-status:hover { background-color: rgba($primary-color, 0.08); } .today-status u-icon { margin-right: 14rpx; transition: all 0.3s ease; } .today-status:hover u-icon { transform: scale(1.1); } .status-text { font-size: 14px; color: $text-secondary; font-weight: 500; margin-left: 10rpx; } /* ååºå¼è°æ´ */ @media (max-width: 375px) { .today-attendance, .attendance-records { margin: 12rpx; padding: 24rpx; } .checkin-button { width: 220rpx; height: 220rpx; } .checkin-button-text { font-size: 20px; } .checkin-time { font-size: 14px; } .weekday { width: 38rpx; } .date-item { width: 38rpx; height: 38rpx; } } /* å¨ç»ææ */ @keyframes fadeInUp { from { opacity: 0; transform: translateY(20rpx); } to { opacity: 1; transform: translateY(0); } } .today-attendance, .attendance-records { animation: fadeInUp 0.5s ease-out; } .attendance-records { animation-delay: 0.2s; } </style> src/pages/attendance/report.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,505 @@ <template> <view class="attendance-report"> <!-- 页é¢å¤´é¨ --> <PageHeader title="è夿¥æ¥" @back="goBack" /> <!-- æç´¢åçéåºå --> <view class="search-section"> <view class="search-bar"> <view @click="selectDate" class="search-input"> <view class="search-text">{{ searchForm.date? searchForm.date : 'è¯·éæ©æ¥æ' }}</view> </view> <view class="filter-button" @click="clearDate"> <u-icon name="close-circle" size="24" color="#999"></u-icon> </view> </view> </view> <!-- æ¥æéæ©å¨ --> <up-datetime-picker :show="showDatePicker" mode="date" v-model="currentDate" @confirm="handleDateConfirm" @cancel="showDatePicker = false" title="æç´¢æ¥æ" /> <view class="record-list"> <view v-for="(item) in tableData" :key="item.id" class="record-item-card" :class="{ 'abnormal': item.status !== 'normal' }"> <view class="record-item-header"> <text class="record-date">{{ item.date }}</text> <u-tag :type="item.status === 'normal' ? 'success' : 'error'" size="small"> {{ item.statusText }} </u-tag> </view> <view class="record-item-body"> <view class="record-detail"> <text class="detail-label">åå·¥</text> <text class="detail-value">{{ item.name }} ({{ item.no }})</text> </view> <view class="record-detail"> <text class="detail-label">é¨é¨</text> <text class="detail-value">{{ item.dept }}</text> </view> <view class="record-detail"> <text class="detail-label">ä¸çæ¶é´</text> <text class="detail-value">{{ item.checkInTime ? item.checkInTime : '缺å¡' }}</text> </view> <view class="record-detail"> <text class="detail-label">ä¸çæ¶é´</text> <text class="detail-value">{{ item.checkOutTime? item.checkOutTime : '缺å¡' }}</text> </view> <view class="record-detail"> <text class="detail-label">å·¥æ¶</text> <text class="detail-value">{{ item.workHours ? item.workHours + 'å°æ¶' : '-' }}</text> </view> <view v-if="item.remark" class="record-detail"> <text class="detail-label">夿³¨</text> <text class="detail-value">{{ item.remark }}</text> </view> </view> </view> <!-- ç©ºç¶æ --> <view v-if="tableData.length === 0" class="empty-state"> <u-icon name="clock-o" size="60" color="#999"></u-icon> <text class="empty-text">ææ èå¤è®°å½</text> </view> </view> <!-- å¯¼åºæé® --> <!-- <view class="export-section"> <u-button type="default" size="medium" text="导åºè夿¥æ¥" @click="handleExport" class="export-btn"></u-button> </view> --> </view> </template> <script setup> import { ref, reactive, onMounted } from "vue"; import PageHeader from "@/components/PageHeader.vue"; import dayjs from "dayjs"; // 模æå½åç»å½åå·¥ const currentUser = reactive({ id: 1, name: "å¼ ä¸", no: "E10001", dept: "ç产ä¸é¨", }); // é¨é¨é项 const deptOptions = [ { label: "ç产ä¸é¨", value: "ç产ä¸é¨" }, { label: "ç产äºé¨", value: "ç产äºé¨" }, { label: "设å¤ç»´æ¤é¨", value: "设å¤ç»´æ¤é¨" }, { label: "è´¨æ£é¨", value: "è´¨æ£é¨" }, ]; // 模æèå¤åå§æ°æ® const rawAttendance = ref([ { id: 1, date: "2026-02-09", userId: 1, name: "å¼ ä¸", no: "E10001", dept: "ç产ä¸é¨", checkInTime: "08:58", checkOutTime: "", workHours: null, status: "normal", statusText: "æ£å¸¸", remark: "", }, { id: 2, date: "2026-02-08", userId: 1, name: "å¼ ä¸", no: "E10001", dept: "ç产ä¸é¨", checkInTime: "09:15", checkOutTime: "18:05", workHours: 8.8, status: "late", statusText: "è¿å°", remark: "å äº¤éæ¥å µè¿å°", }, { id: 3, date: "2026-02-07", userId: 1, name: "å¼ ä¸", no: "E10001", dept: "ç产ä¸é¨", checkInTime: "08:45", checkOutTime: "18:30", workHours: 9.7, status: "normal", statusText: "æ£å¸¸", remark: "å ç0.5å°æ¶", }, { id: 4, date: "2026-02-06", userId: 1, name: "å¼ ä¸", no: "E10001", dept: "ç产ä¸é¨", checkInTime: "08:50", checkOutTime: "17:45", workHours: 8.9, status: "early", statusText: "æ©é", remark: "å®¶ä¸æäºæå离å¼", }, { id: 5, date: "2026-02-05", userId: 1, name: "å¼ ä¸", no: "E10001", dept: "ç产ä¸é¨", checkInTime: "08:40", checkOutTime: "18:20", workHours: 9.7, status: "normal", statusText: "æ£å¸¸", remark: "å ç0.5å°æ¶", }, ]); // æ¥è¯¢è¡¨å const searchForm = reactive({ dept: "", date: "", }); // è¡¨æ ¼æ°æ® const tableData = ref([]); // è¿åä¸ä¸é¡µ const goBack = () => { uni.navigateBack(); }; // æ¥æéæ©å¨ const showDatePicker = ref(false); const currentDate = ref(new Date()); // å¤çæ¥æéæ© const handleDateConfirm = e => { currentDate.value = e.value; searchForm.date = dayjs(e.value).format("YYYY-MM-DD"); showDatePicker.value = false; handleQuery(); }; // æ¾ç¤ºæ¥æéæ©å¨ const selectDate = () => { showDatePicker.value = true; }; // æ¸ é¤æ¥æéæ© const clearDate = () => { searchForm.date = ""; handleQuery(); }; // æ¥è¯¢ const recomputeTable = () => { const list = rawAttendance.value.filter(item => { if (searchForm.dept && item.dept !== searchForm.dept) { return false; } if (searchForm.date && item.date !== searchForm.date) { return false; } return true; }); tableData.value = list; }; const handleQuery = () => { recomputeTable(); }; const resetSearch = () => { searchForm.dept = ""; searchForm.date = ""; recomputeTable(); }; // 导åºï¼æ¼ç¤ºï¼ const handleExport = () => { uni.showToast({ title: "å½å为æ¼ç¤ºé¡µé¢ï¼å¯¼åºåè½æªå¯¹æ¥å®é æ¥å£", icon: "none", }); }; onMounted(() => { // é»è®¤å±ç¤ºå½å¤©æ°æ® // const today = new Date(); // const Y = today.getFullYear(); // const M = String(today.getMonth() + 1).padStart(2, "0"); // const D = String(today.getDate()).padStart(2, "0"); // searchForm.date = `${Y}-${M}-${D}`; recomputeTable(); }); </script> <style scoped lang="scss"> // å ¨å±åé $primary-color: #2c7be5; $primary-light: #4a90e2; $success-color: #4cd964; $warning-color: #ff9500; $danger-color: #ff3b30; $text-primary: #333333; $text-secondary: #666666; $text-tertiary: #999999; $bg-color: #f5f7fa; $card-bg: #ffffff; $border-color: #e8e8e8; $shadow-sm: 0 2rpx 8rpx rgba(0, 0, 0, 0.08); $shadow-md: 0 4rpx 16rpx rgba(0, 0, 0, 0.12); $shadow-lg: 0 8rpx 24rpx rgba(0, 0, 0, 0.15); .attendance-report { min-height: 100vh; background-color: $bg-color; padding-bottom: 30rpx; background-image: linear-gradient(135deg, #f5f7fa 0%, #e4e8f0 100%); } /* æç´¢åçéåºå */ .search-section { background-color: $card-bg; margin: 20rpx; border-radius: 16rpx; box-shadow: $shadow-md; padding: 20rpx; margin-bottom: 24rpx; transition: all 0.3s ease; } .search-section:hover { box-shadow: $shadow-lg; transform: translateY(-2rpx); } .search-bar { display: flex; align-items: center; background-color: rgba($primary-color, 0.05); border-radius: 8rpx; padding: 0 16rpx; height: 70rpx; } .search-input { flex: 1; height: 100%; display: flex; align-items: center; } .search-text { font-size: 14px; color: $text-tertiary; height: 70rpx; line-height: 70rpx; margin-left: 8rpx; } .filter-button { padding: 8rpx; transition: all 0.3s ease; } .filter-button:hover { background-color: rgba($primary-color, 0.1); border-radius: 4rpx; } /* è®°å½å表 */ .record-list { margin: 0 20rpx 24rpx; } .record-item-card { background-color: $card-bg; border-radius: 16rpx; box-shadow: $shadow-md; margin-bottom: 24rpx; overflow: hidden; transition: all 0.3s ease; } .record-item-card:hover { box-shadow: $shadow-lg; transform: translateY(-2rpx); } .record-item-card.abnormal { background-color: rgba($danger-color, 0.05); border-left: 4rpx solid $danger-color; } .record-item-header { background-color: rgba($primary-color, 0.05); padding: 20rpx; display: flex; justify-content: space-between; align-items: center; border-bottom: 1rpx solid $border-color; } .record-date { font-size: 14px; font-weight: 600; color: $text-primary; } .record-item-body { padding: 24rpx; } .record-detail { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16rpx; padding: 8rpx 0; border-bottom: 1rpx solid rgba($border-color, 0.5); } .record-detail:last-child { margin-bottom: 0; border-bottom: none; } .detail-label { font-size: 13px; color: $text-secondary; font-weight: 500; } .detail-value { font-size: 13px; color: $text-primary; font-weight: 500; } /* ç©ºç¶æ */ .empty-state { background-color: $card-bg; border-radius: 16rpx; box-shadow: $shadow-md; text-align: center; padding: 120rpx 0; margin: 0 20rpx; transition: all 0.3s ease; } .empty-state:hover { box-shadow: $shadow-lg; } .empty-text { font-size: 14px; color: $text-tertiary; margin-top: 24rpx; font-weight: 500; } /* å¯¼åºæé® */ .export-section { text-align: center; margin: 0 20rpx 30rpx; } .export-btn { width: 100%; border-radius: 8rpx; border: 1rpx solid $primary-color; color: $primary-color; transition: all 0.3s ease; } .export-btn:hover { background-color: $primary-color; color: #ffffff; box-shadow: 0 4rpx 12rpx rgba($primary-color, 0.3); transform: translateY(-2rpx); } /* ååºå¼è°æ´ */ @media (max-width: 375px) { .search-section, .record-list, .empty-state, .export-section { margin: 12rpx; } .search-section { padding: 16rpx; } .record-item-body { padding: 20rpx; } } /* å¨ç»ææ */ @keyframes fadeInUp { from { opacity: 0; transform: translateY(20rpx); } to { opacity: 1; transform: translateY(0); } } .search-section, .record-item-card, .empty-state, .export-section { animation: fadeInUp 0.5s ease-out; } .record-item-card { animation-delay: 0.1s; } .record-item-card:nth-child(2) { animation-delay: 0.2s; } .record-item-card:nth-child(3) { animation-delay: 0.3s; } .empty-state { animation-delay: 0.2s; } .export-section { animation-delay: 0.3s; } </style> src/pages/index.vue
@@ -374,6 +374,10 @@ icon: "/static/images/icon/kehubaifang@2x.png", label: "å®¢æ·æè®¿", }, { icon: "/static/images/icon/guzhangfenxi@2x.png", label: "æå¡ç¾å°", }, ]); // ç产管æ§åè½æ°æ® @@ -733,7 +737,11 @@ url: "/pages/safeProduction/safetyTrainingAssessment/index", }); break; case "æå¡ç¾å°": uni.navigateTo({ url: "/pages/attendance/checkin", }); break; default: uni.showToast({ title: `ç¹å»äº${item.label}`, src/pages/login.vue
@@ -1,259 +1,302 @@ <template> <view class="normal-login-container"> <view class="logo-content"> <text>è´¦å·å¯ç ç»å½</text> </view> <view class="login-form-content"> <view class="input-item flex align-center"> <up-input prefixIcon="account" placeholder="请è¾å ¥è´¦å·" border="bottom" @blur="getUserLoginFacotryList" maxlength="30" v-model="loginForm.userName" clearable></up-input> </view> <view class="input-item flex align-center"> <up-input prefixIcon="lock" placeholder="请è¾å ¥å¯ç " border="bottom" maxlength="20" v-model="loginForm.password" clearable type="password"></up-input> </view> <view> <button @click="handleLogin" class="login-btn cu-btn block bg-blue lg round">ç»å½</button> </view> </view> <!-- è®°ä½å¯ç é项 --> <view class="remember-password"> <up-checkbox :customStyle="{marginBottom: '8px'}" label="è®°ä½å¯ç " name="agree" usedAlone v-model:checked="rememberPassword" > </up-checkbox> </view> </view> <view class="normal-login-container"> <view class="logo-content"> <text>è´¦å·å¯ç ç»å½</text> </view> <view class="login-form-content"> <view class="input-item flex align-center"> <up-input prefixIcon="account" placeholder="请è¾å ¥è´¦å·" border="bottom" @blur="getUserLoginFacotryList" maxlength="30" v-model="loginForm.userName" clearable></up-input> </view> <view class="input-item flex align-center"> <up-input prefixIcon="lock" placeholder="请è¾å ¥å¯ç " border="bottom" maxlength="20" v-model="loginForm.password" clearable type="password"></up-input> </view> <view> <button @click="handleLogin" class="login-btn cu-btn block bg-blue lg round">ç»å½</button> </view> </view> <!-- è®°ä½å¯ç é项 --> <view class="remember-password"> <up-checkbox :customStyle="{marginBottom: '8px'}" label="è®°ä½å¯ç " name="agree" usedAlone v-model:checked="rememberPassword"> </up-checkbox> </view> </view> </template> <script setup> import {modal} from "@/plugins"; import { modal } from "@/plugins"; const showToast = (message) => { uni.showToast({ title: message, icon: 'none' }) } import { userLoginFacotryList} from '@/api/login' import { ref, onMounted } from "vue"; import useUserStore from '@/store/modules/user' import { getWxCode } from '@/utils/geek'; import { wxLogin } from '@/api/oauth'; import { setToken } from '@/utils/auth'; import View from "@/pages/procurementManagement/procurementLedger/view.vue"; const userStore = useUserStore() const useWxLogin = ref(false); // æ¯å¦ä½¿ç¨å¾®ä¿¡ç»å½ const rememberPassword = ref(false); // è®°ä½å¯ç const loginForm = ref({ userName: "", password: "", currentFatoryName: "", }); const factoryList = ref([]) // å ¬å¸å表 const showToast = message => { uni.showToast({ title: message, icon: "none", }); }; import { userLoginFacotryList, updateClientId } from "@/api/login"; import { ref, onMounted } from "vue"; import useUserStore from "@/store/modules/user"; import { getWxCode } from "@/utils/geek"; import { wxLogin } from "@/api/oauth"; import { setToken } from "@/utils/auth"; import View from "@/pages/procurementManagement/procurementLedger/view.vue"; const userStore = useUserStore(); const useWxLogin = ref(false); // æ¯å¦ä½¿ç¨å¾®ä¿¡ç»å½ const rememberPassword = ref(false); // è®°ä½å¯ç const loginForm = ref({ userName: "", password: "", currentFatoryName: "", }); const factoryList = ref([]); // å ¬å¸å表 // ä¿åå¯ç å°æ¬å°åå¨ function savePassword() { if (rememberPassword.value) { uni.setStorageSync('remembered_username', loginForm.value.userName); uni.setStorageSync('remembered_password', loginForm.value.password); uni.setStorageSync('remember_password', true); } else { uni.removeStorageSync('remembered_username'); uni.removeStorageSync('remembered_password'); uni.setStorageSync('remember_password', false); } } // ä¿åå¯ç å°æ¬å°åå¨ function savePassword() { if (rememberPassword.value) { uni.setStorageSync("remembered_username", loginForm.value.userName); uni.setStorageSync("remembered_password", loginForm.value.password); uni.setStorageSync("remember_password", true); } else { uni.removeStorageSync("remembered_username"); uni.removeStorageSync("remembered_password"); uni.setStorageSync("remember_password", false); } } // 仿¬å°åå¨å è½½å¯ç function loadPassword() { const remembered = uni.getStorageSync('remember_password'); if (remembered) { rememberPassword.value = true; const savedUsername = uni.getStorageSync('remembered_username'); const savedPassword = uni.getStorageSync('remembered_password'); if (savedUsername) { loginForm.value.userName = savedUsername; } if (savedPassword) { loginForm.value.password = savedPassword; } } } // 仿¬å°åå¨å è½½å¯ç function loadPassword() { const remembered = uni.getStorageSync("remember_password"); if (remembered) { rememberPassword.value = true; const savedUsername = uni.getStorageSync("remembered_username"); const savedPassword = uni.getStorageSync("remembered_password"); if (savedUsername) { loginForm.value.userName = savedUsername; } if (savedPassword) { loginForm.value.password = savedPassword; } } } if (useWxLogin.value) { getWxCode().then(res => { console.log(res); wxLogin('miniapp',res).then(res => { if(res.token != null){ setToken(res.token); loginSuccess() } }); }) } if (useWxLogin.value) { getWxCode().then(res => { console.log(res); wxLogin("miniapp", res).then(res => { if (res.token != null) { setToken(res.token); loginSuccess(); } }); }); } function getUserLoginFacotryList() { if(loginForm.value.userName){ userLoginFacotryList({userName:loginForm.value.userName}).then(res => { console.log('res',res) // æ£æ¥res.dataæ¯å¦ä¸ºæ°ç» if (res.data && Array.isArray(res.data)) { // éæ°ç»è£ æ°æ®æ ¼å¼ï¼deptIdåæidï¼deptNameåæname factoryList.value = res.data.map(item => ({ id: item.deptId, name: item.deptName })) } else { // 妿res.data䏿¯æ°ç»ï¼è®¾ç½®ä¸ºç©ºæ°ç» factoryList.value = [] } }).catch(error => { showToast('è·åå ¬å¸å表失败:', error) factoryList.value = [] }) }else { factoryList.value = [] } } function getUserLoginFacotryList() { if (loginForm.value.userName) { userLoginFacotryList({ userName: loginForm.value.userName }) .then(res => { console.log("res", res); // æ£æ¥res.dataæ¯å¦ä¸ºæ°ç» if (res.data && Array.isArray(res.data)) { // éæ°ç»è£ æ°æ®æ ¼å¼ï¼deptIdåæidï¼deptNameåæname factoryList.value = res.data.map(item => ({ id: item.deptId, name: item.deptName, })); } else { // 妿res.data䏿¯æ°ç»ï¼è®¾ç½®ä¸ºç©ºæ°ç» factoryList.value = []; } }) .catch(error => { showToast("è·åå ¬å¸å表失败:", error); factoryList.value = []; }); } else { factoryList.value = []; } } async function handleLogin() { if (loginForm.value.userName === "") { showToast("请è¾å ¥æ¨çè´¦å·") } else if (loginForm.value.password === "") { showToast("请è¾å ¥æ¨çå¯ç ") } else { showToast("ç»å½ä¸ï¼è¯·èå¿çå¾ ...") pwdLogin() } }; // å¯ç ç»å½ async function pwdLogin() { userStore.loginCheckFactory(loginForm.value).then(() => { modal.closeLoading() // ç»å½æååä¿åå¯ç savePassword(); loginSuccess() }).catch(() => { modal.closeLoading() }) }; async function handleLogin() { if (loginForm.value.userName === "") { showToast("请è¾å ¥æ¨çè´¦å·"); } else if (loginForm.value.password === "") { showToast("请è¾å ¥æ¨çå¯ç "); } else { showToast("ç»å½ä¸ï¼è¯·èå¿çå¾ ..."); pwdLogin(); } } // å¯ç ç»å½ async function pwdLogin() { userStore .loginCheckFactory(loginForm.value) .then(() => { modal.closeLoading(); // ç»å½æååä¿åå¯ç savePassword(); loginSuccess(); }) .catch(() => { modal.closeLoading(); }); } function loginSuccess(result) { // è®¾ç½®ç¨æ·ä¿¡æ¯ userStore.getInfo().then(res => { uni.switchTab({ url: '/pages/index' }); }) } // 页é¢å è½½æ¶æ£æ¥æ¯å¦æä¿åçå¯ç onMounted(() => { loadPassword(); getUserLoginFacotryList() }); function loginSuccess(result) { // è®¾ç½®ç¨æ·ä¿¡æ¯ userStore.getInfo().then(res => { // ç»å½æååï¼å°å®¢æ·ç«¯æ¨éæ è¯åéå°æå¡å¨ sendClientIdToServer(); uni.switchTab({ url: "/pages/index", }); }); } // å°å®¢æ·ç«¯æ¨éæ è¯åéå°æå¡å¨ function sendClientIdToServer() { // è·åæ¬å°åå¨ç客æ·ç«¯æ è¯ const clientId = uni.getStorageSync("clientid"); if (clientId) { console.log("ç»å½æåï¼åå¤åé客æ·ç«¯æ è¯å°æå¡å¨:", clientId); // è¿éè°ç¨å端æ¥å£åé客æ·ç«¯æ è¯ updateClientId({ cid: clientId }) .then(res => { console.log("æå¡å¨ååº:", res); if (res.code === 200) { console.log("客æ·ç«¯æ è¯å·²æååéå°æå¡å¨"); } else { console.log("æå¡å¨è¿åé误:", res.msg); } }) .catch(error => { console.log("åé客æ·ç«¯æ è¯å°æå¡å¨å¤±è´¥:", error); }); // 示ä¾ï¼api.updateClientId({ clientId: clientId }); // ç±äºæ²¡æå ·ä½çæ¥å£ï¼è¿éåªæå°æ¥å¿ console.log("客æ·ç«¯æ è¯å·²åéå°æå¡å¨"); } else { console.log("æªè·åå°å®¢æ·ç«¯æ¨éæ è¯"); } } // 页é¢å è½½æ¶æ£æ¥æ¯å¦æä¿åçå¯ç onMounted(() => { loadPassword(); getUserLoginFacotryList(); }); </script> <style lang="scss"> page { background-color: #ffffff; } page { background-color: #ffffff; } .normal-login-container { width: 100%; height: 100vh; .logo-content { width: 90%; font-weight: 400; font-size: 30px; color: #333333; margin: 80px 0 0 30px; image { border-radius: 4px; } .title { margin-left: 10px; } } .u-checkbox { margin-left: 34px; } .login-form-content { text-align: center; margin: 58px auto; padding: 0 30px; .input-item { margin: 30px auto; height: 45px; .icon { font-size: 38rpx; margin-left: 10px; color: #999; } .input { width: 100%; font-size: 14px; line-height: 20px; text-align: left; padding-left: 15px; } } .select-container { flex: 1; border-bottom: 1px solid #e5e5e5; padding: 6px 9px; :deep(.up-select) { border: none; background: transparent; .up-select__label { font-size: 14px; color: #333; } .up-select__value { font-size: 14px; color: #333; } } } .login-btn { margin-top: 60px; height: 50px; background: linear-gradient( 140deg, #00BAFF 0%, #006CFB 100%); box-shadow: 0px 4px 10px 0px rgba(3,88,185,0.2); border-radius: 40px 40px 40px 40px; } .xieyi { color: #333; margin-top: 20px; } .login-code { height: 38px; float: right; .login-code-img { height: 38px; position: absolute; margin-left: 10px; width: 200rpx; } } } } .normal-login-container { width: 100%; height: 100vh; .logo-content { width: 90%; font-weight: 400; font-size: 30px; color: #333333; margin: 80px 0 0 30px; image { border-radius: 4px; } .title { margin-left: 10px; } } .u-checkbox { margin-left: 34px; } .login-form-content { text-align: center; margin: 58px auto; padding: 0 30px; .input-item { margin: 30px auto; height: 45px; .icon { font-size: 38rpx; margin-left: 10px; color: #999; } .input { width: 100%; font-size: 14px; line-height: 20px; text-align: left; padding-left: 15px; } } .select-container { flex: 1; border-bottom: 1px solid #e5e5e5; padding: 6px 9px; :deep(.up-select) { border: none; background: transparent; .up-select__label { font-size: 14px; color: #333; } .up-select__value { font-size: 14px; color: #333; } } } .login-btn { margin-top: 60px; height: 50px; background: linear-gradient(140deg, #00baff 0%, #006cfb 100%); box-shadow: 0px 4px 10px 0px rgba(3, 88, 185, 0.2); border-radius: 40px 40px 40px 40px; } .xieyi { color: #333; margin-top: 20px; } .login-code { height: 38px; float: right; .login-code-img { height: 38px; position: absolute; margin-left: 10px; width: 200rpx; } } } } </style> src/pages_template/pages/login/index2.vue
@@ -1,662 +1,719 @@ <template> <view> <view class="normal-login-container " v-if="page == 'login'"> <view class="left" @click="back"> <image src="../../../static/uview/demo/backTop.png" mode="" style="height: 30rpx;"></image> </view> <view class="scale-in-center"> <view class="logo-content align-center justify-center flex"> <text class="title">å·¥ä½äººåå ¥å£</text> </view> <view class="login-form-content"> <view class="input-item flex align-center"> <view class="iconfont icon-user icon"></view> <input v-model="loginForm.username" class="input" type="text" placeholder="请è¾å ¥è´¦å·" maxlength="30" /> </view> <view class="input-item flex align-center"> <view class="iconfont icon-password icon"></view> <input v-model="loginForm.password" type="password" class="input" placeholder="请è¾å ¥å¯ç " maxlength="20" /> </view> <view class="input-item flex align-center" style="width: 60%;margin: 0px;" v-if="captchaEnabled"> <view class="iconfont icon-code icon"></view> <input v-model="loginForm.code" type="number" class="input" placeholder="请è¾å ¥éªè¯ç " maxlength="4" /> <view class="login-code"> <image :src="codeUrl" @click="getCode" class="login-code-img"></image> </view> </view> <view class="action-btn"> <button @click="handleLogin" class="login-btn cu-btn block bg-blue lg round">ç»å½</button> </view> </view> </view> </view> <!-- ç»å½ --> <view v-else> <view class="container"> <view class="cover slide-top1" :style="'animation-play-state:' + play[2]"> <view class="masking slide-top" :class="[collapsedClass, { animating: isAnimating }]" ref="fixedViewRef" :style="'animation-play-state:' + play[0]"> <uni-row> <text class="text-first">欢è¿ä½¿ç¨</text> <text class="text-second">æ ¡å访客</text> <text class="text-third">é¢çº¦ç³»ç»</text> <view :class="{ active: isActive === true, button: isActive !== true }" @click="startplay" :style="'animation-play-state:' + play[1]"> <uni-row> <text class="text-fifth">访客ç»å½</text> </uni-row> </view> <view class="shadow1" :style="'animation-play-state:' + play[1]" /> <view class="shadow2" :style="'animation-play-state:' + play[1]" /> <view class="shadow3" :style="'animation-play-state:' + play[1]" /> <image style="width: 100%;height: 1050rpx;opacity: 0.05;border-radius: 0 0 400rpx 400rpx;position: absolute;" src="../../../static/uview/common/gray-logo.png"></image> <text class="text-forth" @click="login()">è´¦å·å¯ç ç»å½</text> </uni-row> </view> </view> <view class="sec-masking"> <uni-row> <text class="text-sixth">çæ¬å·: v1.0</text> </uni-row> </view> </view> </view> </view> <view> <view class="normal-login-container " v-if="page == 'login'"> <view class="left" @click="back"> <image src="../../../static/uview/demo/backTop.png" mode="" style="height: 30rpx;"></image> </view> <view class="scale-in-center"> <view class="logo-content align-center justify-center flex"> <text class="title">å·¥ä½äººåå ¥å£</text> </view> <view class="login-form-content"> <view class="input-item flex align-center"> <view class="iconfont icon-user icon"></view> <input v-model="loginForm.username" class="input" type="text" placeholder="请è¾å ¥è´¦å·" maxlength="30" /> </view> <view class="input-item flex align-center"> <view class="iconfont icon-password icon"></view> <input v-model="loginForm.password" type="password" class="input" placeholder="请è¾å ¥å¯ç " maxlength="20" /> </view> <view class="input-item flex align-center" style="width: 60%;margin: 0px;" v-if="captchaEnabled"> <view class="iconfont icon-code icon"></view> <input v-model="loginForm.code" type="number" class="input" placeholder="请è¾å ¥éªè¯ç " maxlength="4" /> <view class="login-code"> <image :src="codeUrl" @click="getCode" class="login-code-img"></image> </view> </view> <view class="action-btn"> <button @click="handleLogin" class="login-btn cu-btn block bg-blue lg round">ç»å½</button> </view> </view> </view> </view> <!-- ç»å½ --> <view v-else> <view class="container"> <view class="cover slide-top1" :style="'animation-play-state:' + play[2]"> <view class="masking slide-top" :class="[collapsedClass, { animating: isAnimating }]" ref="fixedViewRef" :style="'animation-play-state:' + play[0]"> <uni-row> <text class="text-first">欢è¿ä½¿ç¨</text> <text class="text-second">æ ¡å访客</text> <text class="text-third">é¢çº¦ç³»ç»</text> <view :class="{ active: isActive === true, button: isActive !== true }" @click="startplay" :style="'animation-play-state:' + play[1]"> <uni-row> <text class="text-fifth">访客ç»å½</text> </uni-row> </view> <view class="shadow1" :style="'animation-play-state:' + play[1]" /> <view class="shadow2" :style="'animation-play-state:' + play[1]" /> <view class="shadow3" :style="'animation-play-state:' + play[1]" /> <image style="width: 100%;height: 1050rpx;opacity: 0.05;border-radius: 0 0 400rpx 400rpx;position: absolute;" src="../../../static/uview/common/gray-logo.png"></image> <text class="text-forth" @click="login()">è´¦å·å¯ç ç»å½</text> </uni-row> </view> </view> <view class="sec-masking"> <uni-row> <text class="text-sixth">çæ¬å·: v1.0</text> </uni-row> </view> </view> </view> </view> </template> <script setup> import { ref, reactive, computed, onMounted } from 'vue' import useUserStore from '@/store/modules/user' import tab from '@/plugins/tab' import modal from '@/plugins/modal' import { ref, reactive, computed, onMounted } from "vue"; import { updateClientId } from "@/api/login"; import useUserStore from "@/store/modules/user"; import tab from "@/plugins/tab"; import modal from "@/plugins/modal"; const src = ref("staticimagessoutheast.jpg") const isActive = ref(false) const isFixedViewVisible = ref(true) const animationType = ref("up") // å¯éå¼ï¼right æ up const isAnimating = ref(false) // æ§å¶å¨ç»æ§è¡ç¶æ const play = ref(["paused", "paused", "paused"]) const page = ref("index") const src = ref("staticimagessoutheast.jpg"); const isActive = ref(false); const isFixedViewVisible = ref(true); const animationType = ref("up"); // å¯éå¼ï¼right æ up const isAnimating = ref(false); // æ§å¶å¨ç»æ§è¡ç¶æ const play = ref(["paused", "paused", "paused"]); const page = ref("index"); const codeUrl = ref("") const captchaEnabled = ref(true) const loginForm = reactive({ username: "admin", password: "admin123", code: "", uuid: '' }) const codeUrl = ref(""); const captchaEnabled = ref(true); const loginForm = reactive({ username: "admin", password: "admin123", code: "", uuid: "", }); const collapsedClass = computed(() => { return isFixedViewVisible.value ? "" : `collapsed-${animationType.value}`; }) const collapsedClass = computed(() => { return isFixedViewVisible.value ? "" : `collapsed-${animationType.value}`; }); onMounted(() => { getCode() }) onMounted(() => { getCode(); }); const login = () => { play.value[2] = "running" setTimeout(() => { page.value = 'login' }, 1000) } const login = () => { play.value[2] = "running"; setTimeout(() => { page.value = "login"; }, 1000); }; const back = () => { page.value = 'index' play.value[0] = "paused" play.value[1] = "paused" play.value[2] = "paused" } const startplay = () => { play.value[1] = "running" isActive.value = true; setTimeout(() => { isActive.value = false; }, 300); if (isAnimating.value) { return; } isAnimating.value = false; // å¼å§å¨ç»æ§è¡ play.value[0] = "running" isFixedViewVisible.value = !isFixedViewVisible.value; setTimeout(() => { uni.navigateBack({ delta: 1 }); }, 1000) } const back = () => { page.value = "index"; play.value[0] = "paused"; play.value[1] = "paused"; play.value[2] = "paused"; }; const startplay = () => { play.value[1] = "running"; isActive.value = true; setTimeout(() => { isActive.value = false; }, 300); if (isAnimating.value) { return; } isAnimating.value = false; // å¼å§å¨ç»æ§è¡ play.value[0] = "running"; isFixedViewVisible.value = !isFixedViewVisible.value; setTimeout(() => { uni.navigateBack({ delta: 1 }); }, 1000); }; // è·åå¾å½¢éªè¯ç const getCode = () => { let res = {} captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled if (captchaEnabled.value) { codeUrl.value = 'data:image/gif;base64,' + res.img loginForm.uuid = res.uuid } } // è·åå¾å½¢éªè¯ç const getCode = () => { let res = {}; captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled; if (captchaEnabled.value) { codeUrl.value = "data:image/gif;base64," + res.img; loginForm.uuid = res.uuid; } }; // ç»å½æ¹æ³ const handleLogin = async () => { if (loginForm.username === "") { modal.msgError("请è¾å ¥æ¨çè´¦å·") } else if (loginForm.password === "") { modal.msgError("请è¾å ¥æ¨çå¯ç ") } else if (loginForm.code === "" && captchaEnabled.value) { modal.msgError("请è¾å ¥éªè¯ç ") } else { modal.loading("ç»å½ä¸ï¼è¯·èå¿çå¾ ...") pwdLogin() } } // ç»å½æ¹æ³ const handleLogin = async () => { if (loginForm.username === "") { modal.msgError("请è¾å ¥æ¨çè´¦å·"); } else if (loginForm.password === "") { modal.msgError("请è¾å ¥æ¨çå¯ç "); } else if (loginForm.code === "" && captchaEnabled.value) { modal.msgError("请è¾å ¥éªè¯ç "); } else { modal.loading("ç»å½ä¸ï¼è¯·èå¿çå¾ ..."); pwdLogin(); } }; // å¯ç ç»å½ const pwdLogin = async () => { useUserStore().login(loginForm).then(() => { modal.closeLoading() loginSuccess() }).catch(() => { if (captchaEnabled.value) { getCode() } }) } // å¯ç ç»å½ const pwdLogin = async () => { useUserStore() .login(loginForm) .then(() => { modal.closeLoading(); loginSuccess(); }) .catch(() => { if (captchaEnabled.value) { getCode(); } }); }; // ç»å½æååï¼å¤ç彿° const loginSuccess = (result) => { // è®¾ç½®ç¨æ·ä¿¡æ¯ useUserStore().getInfo().then(res => { tab.reLaunch('/pages/index') }) } // ç»å½æååï¼å¤ç彿° const loginSuccess = result => { // è®¾ç½®ç¨æ·ä¿¡æ¯ useUserStore() .getInfo() .then(res => { // ç»å½æååï¼å°å®¢æ·ç«¯æ¨éæ è¯åéå°æå¡å¨ sendClientIdToServer(); tab.reLaunch("/pages/index"); }); }; // å°å®¢æ·ç«¯æ¨éæ è¯åéå°æå¡å¨ const sendClientIdToServer = () => { // è·åæ¬å°åå¨ç客æ·ç«¯æ è¯ const clientId = uni.getStorageSync("clientid"); if (clientId) { console.log("ç»å½æåï¼åå¤åé客æ·ç«¯æ è¯å°æå¡å¨:", clientId); // è¿éè°ç¨å端æ¥å£åé客æ·ç«¯æ è¯ // 示ä¾ï¼api.updateClientId({ clientId: clientId }); updateClientId({ cid: clientId }) .then(res => { console.log("æå¡å¨ååº:", res); if (res.code === 200) { console.log("客æ·ç«¯æ è¯å·²æååéå°æå¡å¨"); } else { console.log("æå¡å¨è¿åé误:", res.msg); } }) .catch(error => { console.log("åé客æ·ç«¯æ è¯å°æå¡å¨å¤±è´¥:", error); }); // ç±äºæ²¡æå ·ä½çæ¥å£ï¼è¿éåªæå°æ¥å¿ console.log("客æ·ç«¯æ è¯å·²åéå°æå¡å¨"); } else { console.log("æªè·åå°å®¢æ·ç«¯æ¨éæ è¯"); } }; </script> <style lang="scss"> page { background-color: #ffffff; } page { background-color: #ffffff; } .left { display: flex; width: 50rpx; height: 50rpx; position: fixed; top: 0px; padding: 10rpx; } .left { display: flex; width: 50rpx; height: 50rpx; position: fixed; top: 0px; padding: 10rpx; } .cover { position: absolute; width: 100%; height: 1250rpx; z-index: 9997; } .cover { position: absolute; width: 100%; height: 1250rpx; z-index: 9997; } .normal-login-container { width: 100%; margin-top: 200rpx; .normal-login-container { width: 100%; margin-top: 200rpx; .logo-content { width: 100%; font-size: 21px; text-align: center; padding-top: 15%; .logo-content { width: 100%; font-size: 21px; text-align: center; padding-top: 15%; image { border-radius: 4px; } image { border-radius: 4px; } .title { margin-left: 10px; } } .title { margin-left: 10px; } } .login-form-content { text-align: center; margin: 20px auto; margin-top: 15%; width: 80%; .login-form-content { text-align: center; margin: 20px auto; margin-top: 15%; width: 80%; .input-item { margin: 20px auto; background-color: #f5f6f7; height: 45px; border-radius: 20px; .input-item { margin: 20px auto; background-color: #f5f6f7; height: 45px; border-radius: 20px; .icon { font-size: 38rpx; margin-left: 10px; color: #999; } .icon { font-size: 38rpx; margin-left: 10px; color: #999; } .input { width: 100%; font-size: 14px; line-height: 20px; text-align: left; padding-left: 15px; } .input { width: 100%; font-size: 14px; line-height: 20px; text-align: left; padding-left: 15px; } } } .login-btn { margin-top: 40px; height: 45px; } .login-btn { margin-top: 40px; height: 45px; } .xieyi { color: #333; margin-top: 20px; } .xieyi { color: #333; margin-top: 20px; } .login-code { height: 38px; float: right; .login-code { height: 38px; float: right; .login-code-img { height: 38px; position: absolute; margin-left: 10px; width: 200rpx; } } } } .login-code-img { height: 38px; position: absolute; margin-left: 10px; width: 200rpx; } } } } .container { position: relative; } .active { position: absolute; width: 280rpx; height: 280rpx; left: 50%; margin-left: -140rpx; top: 533rpx; bottom: 533rpx; border-radius: 50%; z-index: 9999; background: linear-gradient( 180deg, rgba(110, 109, 122, 0.595), rgba(46, 87, 190, 0.714) 70.792%, rgb(17, 120, 222) 100% ); box-shadow: inset 0 0 10px 5px rgba(101, 97, 97, 0.5); } .masking { position: absolute; top: -200rpx; width: 100%; height: 1250rpx; background-color: #9acafc; border-radius: 0 0 400rpx 400rpx; box-shadow: 0px 5px 8px rgba(0, 0, 0, 0.27); transition: transform 0.3s ease-out; z-index: 9998; padding: 200rpx 0 0 0; } .collapsed-up { transform: translateY(-100%); } .button { position: absolute; width: 280rpx; height: 280rpx; left: 50%; margin-left: -140rpx; top: 533rpx; bottom: 533rpx; border-radius: 50%; transition: background-color 0.3s; z-index: 9999; background: linear-gradient( 180deg, rgba(60, 53, 239, 0.595), rgba(63, 117, 255, 0.714) 70.792%, rgb(70, 161, 253) 100% ); // box-shadow: 0px 0px 62rpx rgba(1, 7, 22, 0.468); box-shadow: 0 0 10px rgba(0, 0, 0, 0.3) inset; } .shadow1 { position: absolute; width: 280rpx; height: 280rpx; left: 50%; margin-left: -140rpx; top: 533rpx; bottom: 533rpx; border-radius: 50%; border-width: 4rpx; border-color: rgb(70, 161, 253); transition: background-color 0.3s; z-index: 9998; background-color: rgba(70, 161, 253, 0); .container { position: relative; } // box-shadow: 0px 0px 62rpx rgba(1, 7, 22, 0.468); .active { position: absolute; width: 280rpx; height: 280rpx; left: 50%; margin-left: -140rpx; top: 533rpx; bottom: 533rpx; border-radius: 50%; z-index: 9999; box-shadow: 0 0 10px rgba(0, 0, 0, 0.3) inset; -webkit-animation-name: "ripple1"; /*å¨ç»å±æ§åï¼ä¹å°±æ¯æä»¬åé¢keyframeså®ä¹çå¨ç»å*/ -webkit-animation-duration: 0.3s; /*å¨ç»æç»æ¶é´*/ -webkit-animation-timing-function: ease; /*å¨ç»é¢çï¼åtransition-timing-functionæ¯ä¸æ ·ç*/ -webkit-animation-delay: 0s; /*å¨ç»å»¶è¿æ¶é´*/ -webkit-animation-direction: normal; /*å®ä¹å¨ç»æ¹å¼*/ } background: linear-gradient(180deg, rgba(110, 109, 122, 0.595), rgba(46, 87, 190, 0.714) 70.792%, rgb(17, 120, 222) 100%); box-shadow: inset 0 0 10px 5px rgba(101, 97, 97, 0.5); } .shadow2 { position: absolute; width: 280rpx; height: 280rpx; left: 50%; margin-left: -140rpx; top: 533rpx; bottom: 533rpx; border-radius: 50%; border-width: 4rpx; border-color: rgb(70, 161, 253); transition: background-color 0.3s; z-index: 9998; background-color: rgba(70, 161, 253, 0); .masking { position: absolute; top: -200rpx; width: 100%; height: 1250rpx; background-color: #9acafc; border-radius: 0 0 400rpx 400rpx; box-shadow: 0px 5px 8px rgba(0, 0, 0, 0.27); transition: transform 0.3s ease-out; z-index: 9998; padding: 200rpx 0 0 0; } // box-shadow: 0px 0px 62rpx rgba(1, 7, 22, 0.468); .collapsed-up { transform: translateY(-100%); } box-shadow: 0 0 10px rgba(0, 0, 0, 0.3) inset; -webkit-animation-name: "ripple2"; /*å¨ç»å±æ§åï¼ä¹å°±æ¯æä»¬åé¢keyframeså®ä¹çå¨ç»å*/ -webkit-animation-duration: 0.4s; /*å¨ç»æç»æ¶é´*/ -webkit-animation-timing-function: ease; /*å¨ç»é¢çï¼åtransition-timing-functionæ¯ä¸æ ·ç*/ -webkit-animation-delay: 0.1s; /*å¨ç»å»¶è¿æ¶é´*/ -webkit-animation-direction: normal; /*å®ä¹å¨ç»æ¹å¼*/ } .button { position: absolute; width: 280rpx; height: 280rpx; left: 50%; margin-left: -140rpx; top: 533rpx; bottom: 533rpx; border-radius: 50%; transition: background-color 0.3s; z-index: 9999; .shadow3 { position: absolute; width: 280rpx; height: 280rpx; left: 50%; margin-left: -140rpx; top: 533rpx; bottom: 533rpx; border-radius: 50%; border-width: 4rpx; border-color: rgb(70, 161, 253); transition: background-color 0.3s; z-index: 9998; background-color: rgba(70, 161, 253, 0); background: linear-gradient(180deg, rgba(60, 53, 239, 0.595), rgba(63, 117, 255, 0.714) 70.792%, rgb(70, 161, 253) 100%); // box-shadow: 0px 0px 62rpx rgba(1, 7, 22, 0.468); // box-shadow: 0px 0px 62rpx rgba(1, 7, 22, 0.468); box-shadow: 0 0 10px rgba(0, 0, 0, .3) inset; box-shadow: 0 0 10px rgba(0, 0, 0, 0.3) inset; -webkit-animation-name: "ripple3"; /*å¨ç»å±æ§åï¼ä¹å°±æ¯æä»¬åé¢keyframeså®ä¹çå¨ç»å*/ -webkit-animation-duration: 0.5s; /*å¨ç»æç»æ¶é´*/ -webkit-animation-timing-function: ease; /*å¨ç»é¢çï¼åtransition-timing-functionæ¯ä¸æ ·ç*/ -webkit-animation-delay: 0.2s; /*å¨ç»å»¶è¿æ¶é´*/ -webkit-animation-direction: normal; /*å®ä¹å¨ç»æ¹å¼*/ } } .button.disabled { pointer-events: none; /* ç¦ç¨æé®çç¹å»äºä»¶ */ opacity: 0.5; /* åéæææ */ } .shadow1 { position: absolute; width: 280rpx; height: 280rpx; left: 50%; margin-left: -140rpx; top: 533rpx; bottom: 533rpx; border-radius: 50%; border-width: 4rpx; border-color: rgb(70, 161, 253); transition: background-color 0.3s; z-index: 9998; background-color: rgba(70, 161, 253, 0); .text-first { position: absolute; width: 256rpx; height: 84rpx; left: 50%; transform: translateX(-50%); top: 250rpx; bottom: 986.67rpx; // box-shadow: 0px 0px 62rpx rgba(1, 7, 22, 0.468); color: rgb(255, 255, 255); font-family: "Microsoft YaHei"; font-size: 64rpx; font-weight: 400; line-height: 84rpx; letter-spacing: 0rpx; text-align: center; } box-shadow: 0 0 10px rgba(0, 0, 0, .3) inset; -webkit-animation-name: 'ripple1'; /*å¨ç»å±æ§åï¼ä¹å°±æ¯æä»¬åé¢keyframeså®ä¹çå¨ç»å*/ -webkit-animation-duration: 0.3s; /*å¨ç»æç»æ¶é´*/ -webkit-animation-timing-function: ease; /*å¨ç»é¢çï¼åtransition-timing-functionæ¯ä¸æ ·ç*/ -webkit-animation-delay: 0s; /*å¨ç»å»¶è¿æ¶é´*/ -webkit-animation-direction: normal; /*å®ä¹å¨ç»æ¹å¼*/ } .text-second { position: absolute; width: 256rpx; height: 84rpx; left: 50%; transform: translateX(-50%); top: 350rpx; bottom: 986.67rpx; .shadow2 { position: absolute; width: 280rpx; height: 280rpx; left: 50%; margin-left: -140rpx; top: 533rpx; bottom: 533rpx; border-radius: 50%; border-width: 4rpx; border-color: rgb(70, 161, 253); transition: background-color 0.3s; z-index: 9998; background-color: rgba(70, 161, 253, 0); color: rgb(255, 255, 255); font-family: "Microsoft YaHei"; font-size: 64rpx; font-weight: 400; line-height: 84rpx; letter-spacing: 0rpx; text-align: center; } // box-shadow: 0px 0px 62rpx rgba(1, 7, 22, 0.468); box-shadow: 0 0 10px rgba(0, 0, 0, .3) inset; -webkit-animation-name: 'ripple2'; /*å¨ç»å±æ§åï¼ä¹å°±æ¯æä»¬åé¢keyframeså®ä¹çå¨ç»å*/ -webkit-animation-duration: 0.4s; /*å¨ç»æç»æ¶é´*/ -webkit-animation-timing-function: ease; /*å¨ç»é¢çï¼åtransition-timing-functionæ¯ä¸æ ·ç*/ -webkit-animation-delay: 0.1s; /*å¨ç»å»¶è¿æ¶é´*/ -webkit-animation-direction: normal; /*å®ä¹å¨ç»æ¹å¼*/ } .shadow3 { position: absolute; width: 280rpx; height: 280rpx; left: 50%; margin-left: -140rpx; top: 533rpx; bottom: 533rpx; border-radius: 50%; border-width: 4rpx; border-color: rgb(70, 161, 253); transition: background-color 0.3s; z-index: 9998; background-color: rgba(70, 161, 253, 0); // box-shadow: 0px 0px 62rpx rgba(1, 7, 22, 0.468); box-shadow: 0 0 10px rgba(0, 0, 0, .3) inset; -webkit-animation-name: 'ripple3'; /*å¨ç»å±æ§åï¼ä¹å°±æ¯æä»¬åé¢keyframeså®ä¹çå¨ç»å*/ -webkit-animation-duration: 0.5s; /*å¨ç»æç»æ¶é´*/ -webkit-animation-timing-function: ease; /*å¨ç»é¢çï¼åtransition-timing-functionæ¯ä¸æ ·ç*/ -webkit-animation-delay: 0.2s; /*å¨ç»å»¶è¿æ¶é´*/ -webkit-animation-direction: normal; /*å®ä¹å¨ç»æ¹å¼*/ } .button.disabled { pointer-events: none; /* ç¦ç¨æé®çç¹å»äºä»¶ */ opacity: 0.5; /* åéæææ */ } .text-first { position: absolute; width: 256rpx; height: 84rpx; left: 50%; transform: translateX(-50%); top: 250rpx; bottom: 986.67rpx; color: rgb(255, 255, 255); font-family: "Microsoft YaHei"; font-size: 64rpx; font-weight: 400; line-height: 84rpx; letter-spacing: 0rpx; text-align: center; } .text-second { position: absolute; width: 256rpx; height: 84rpx; left: 50%; transform: translateX(-50%); top: 350rpx; bottom: 986.67rpx; color: rgb(255, 255, 255); font-family: "Microsoft YaHei"; font-size: 64rpx; font-weight: 400; line-height: 84rpx; letter-spacing: 0rpx; text-align: center; } .text-third { position: absolute; width: 200rpx; height: 60rpx; left: 50%; transform: translateX(-50%); top: 450rpx; bottom: 615rpx; margin: 0 auto; color: rgb(255, 255, 255); font-family: "Microsoft YaHei"; font-size: 50rpx; font-weight: 400; line-height: 60rpx; letter-spacing: 0rpx; text-align: center; } .text-forth { position: absolute; width: 180rpx; height: 36rpx; left: 0; right: 0; top: 948rpx; bottom: 330rpx; margin: 0 auto; color: rgb(255, 255, 255); font-family: "Microsoft YaHei"; font-size: 27rpx; font-weight: 400; line-height: 36rpx; letter-spacing: 0rpx; text-align: center; text-decoration-line: underline; } .text-third { position: absolute; width: 200rpx; height: 60rpx; left: 50%; transform: translateX(-50%); top: 450rpx; bottom: 615rpx; margin: 0 auto; .text-fifth { position: absolute; width: 120rpx; height: 150rpx; left: 0; right: 0; top: 60rpx; bottom: 418rpx; margin: 0 auto; color: rgb(255, 255, 255); font-family: "Microsoft YaHei"; font-size: 50rpx; font-weight: 400; line-height: 60rpx; letter-spacing: 0rpx; text-align: center; } color: rgb(255, 255, 255); font-family: "Microsoft YaHei"; font-size: 60rpx; font-weight: 400; line-height: 80rpx; letter-spacing: 0rpx; text-align: center; } .text-forth { position: absolute; width: 180rpx; height: 36rpx; left: 0; right: 0; top: 948rpx; bottom: 330rpx; margin: 0 auto; .text-sixth { position: absolute; width: 100rpx; height: 17rpx; margin: 0 auto; top: 710rpx; left: 50%; transform: translateX(-50%); padding: 0 179rpx 7rpx 180rpx; z-index: 9997; color: rgb(255, 255, 255); font-family: "Microsoft YaHei"; font-size: 27rpx; font-weight: 400; line-height: 36rpx; letter-spacing: 0rpx; text-align: center; text-decoration-line: underline; } color: rgb(15, 15, 15); font-family: "Microsoft YaHei"; font-size: 17rpx; font-weight: 400; line-height: 17rpx; letter-spacing: 0; text-align: left; } .text-fifth { position: absolute; width: 120rpx; height: 150rpx; left: 0; right: 0; top: 60rpx; bottom: 418rpx; margin: 0 auto; .sec-masking { position: fixed; bottom: 0; width: 100%; height: 750rpx; background-color: #ffffff; z-index: 9996; } color: rgb(255, 255, 255); font-family: "Microsoft YaHei"; font-size: 60rpx; font-weight: 400; line-height: 80rpx; letter-spacing: 0rpx; text-align: center; } .slide-top { -webkit-animation: slide-top 1s cubic-bezier(0.600, -0.280, 0.735, 0.045) both; animation: slide-top 1s cubic-bezier(0.600, -0.280, 0.735, 0.045) both; } .text-sixth { position: absolute; width: 100rpx; height: 17rpx; margin: 0 auto; top: 710rpx; left: 50%; transform: translateX(-50%); padding: 0 179rpx 7rpx 180rpx; z-index: 9997; .slide-top1 { -webkit-animation: slide-top1 1s cubic-bezier(0.600, -0.280, 0.735, 0.045) both; animation: slide-top1 1s cubic-bezier(0.600, -0.280, 0.735, 0.045) both; } color: rgb(15, 15, 15); font-family: "Microsoft YaHei"; font-size: 17rpx; font-weight: 400; line-height: 17rpx; letter-spacing: 0; text-align: left; } .scale-in-center { animation: scale-in-center 0.4s cubic-bezier(0.250, 0.460, 0.450, 0.940) both; } .sec-masking { position: fixed; bottom: 0; width: 100%; height: 750rpx; background-color: #ffffff; z-index: 9996; } @-webkit-keyframes slide-top { 0% { -webkit-transform: translateY(0); transform: translateY(0); } .slide-top { -webkit-animation: slide-top 1s cubic-bezier(0.6, -0.28, 0.735, 0.045) both; animation: slide-top 1s cubic-bezier(0.6, -0.28, 0.735, 0.045) both; } 100% { -webkit-transform: translateY(-1050px); transform: translateY(-1050px); } } .slide-top1 { -webkit-animation: slide-top1 1s cubic-bezier(0.6, -0.28, 0.735, 0.045) both; animation: slide-top1 1s cubic-bezier(0.6, -0.28, 0.735, 0.045) both; } @-webkit-keyframes slide-top1 { 0% { -webkit-transform: translateY(0); transform: translateY(0); } .scale-in-center { animation: scale-in-center 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94) both; } 100% { -webkit-transform: translateY(-1050px); transform: translateY(-1050px); } } @-webkit-keyframes slide-top { 0% { -webkit-transform: translateY(0); transform: translateY(0); } @keyframes ripple1 { 0% { transform: scale(1); } 100% { -webkit-transform: translateY(-1050px); transform: translateY(-1050px); } } 100% { transform: scale(1.4); opacity: 0; @-webkit-keyframes slide-top1 { 0% { -webkit-transform: translateY(0); transform: translateY(0); } } } 100% { -webkit-transform: translateY(-1050px); transform: translateY(-1050px); } } @keyframes ripple2 { 0% { transform: scale(1); } @keyframes ripple1 { 0% { transform: scale(1); } 100% { transform: scale(1.5); opacity: 0; 100% { transform: scale(1.4); opacity: 0; } } } } @keyframes ripple2 { 0% { transform: scale(1); } @keyframes ripple3 { 0% { transform: scale(1); } 100% { transform: scale(1.5); opacity: 0; } } 100% { transform: scale(1.6); opacity: 0; @keyframes ripple3 { 0% { transform: scale(1); } } } 100% { transform: scale(1.6); opacity: 0; } } @keyframes slide-top { 0% { -webkit-transform: translateY(0); transform: translateY(0); } @keyframes slide-top { 0% { -webkit-transform: translateY(0); transform: translateY(0); } 100% { -webkit-transform: translateY(-1050px); transform: translateY(-1050px); } } 100% { -webkit-transform: translateY(-1050px); transform: translateY(-1050px); } } @keyframes slide-top1 { 0% { -webkit-transform: translateY(0); transform: translateY(0); } @keyframes slide-top1 { 0% { -webkit-transform: translateY(0); transform: translateY(0); } 100% { -webkit-transform: translateY(-1050px); transform: translateY(-1050px); } } 100% { -webkit-transform: translateY(-1050px); transform: translateY(-1050px); } } @keyframes scale-in-center { 0% { transform: scale(0); opacity: 1; } @keyframes scale-in-center { 0% { transform: scale(0); opacity: 1; } 100% { transform: scale(1); opacity: 1; } } 100% { transform: scale(1); opacity: 1; } } </style>