| | |
| | | console.log("ä½¿ç¨ plus.push.getClientInfo è·å客æ·ç«¯æ è¯"); |
| | | plus.push.getClientInfoAsync(info => { |
| | | console.log("客æ·ç«¯æ¨éæ è¯:", info); |
| | | uni.setStorageSync("clientid", info.clientid); |
| | | |
| | | // è¿éå¯ä»¥å°å®¢æ·ç«¯æ è¯åéå°æå¡å¨ |
| | | }); |
| | | setTimeout(() => { |
| | |
| | | params: params |
| | | }) |
| | | } |
| | | |
| | | // åé客æ·ç«¯æ¨éæ è¯å°æå¡å¨ |
| | | export function updateClientId(data) { |
| | | return request({ |
| | | url: '/system/client/addOrUpdateClientId', |
| | | method: 'post', |
| | | data: data |
| | | }) |
| | | } |
| | |
| | | "navigationBarTitleText": "å¹è®è®°å½", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/attendance/checkin", |
| | | "style": { |
| | | "navigationBarTitleText": "æå¡ç¾å°", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/attendance/report", |
| | | "style": { |
| | | "navigationBarTitleText": "è夿¥æ¥", |
| | | "navigationStyle": "custom" |
| | | } |
| | | } |
| | | ], |
| | | "subPackages": [ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <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> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <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> |
| | |
| | | icon: "/static/images/icon/kehubaifang@2x.png", |
| | | label: "å®¢æ·æè®¿", |
| | | }, |
| | | { |
| | | icon: "/static/images/icon/guzhangfenxi@2x.png", |
| | | label: "æå¡ç¾å°", |
| | | }, |
| | | ]); |
| | | |
| | | // ç产管æ§åè½æ°æ® |
| | |
| | | url: "/pages/safeProduction/safetyTrainingAssessment/index", |
| | | }); |
| | | break; |
| | | |
| | | case "æå¡ç¾å°": |
| | | uni.navigateTo({ |
| | | url: "/pages/attendance/checkin", |
| | | }); |
| | | break; |
| | | default: |
| | | uni.showToast({ |
| | | title: `ç¹å»äº${item.label}`, |
| | |
| | | </view> |
| | | <view class="login-form-content"> |
| | | <view class="input-item flex align-center"> |
| | | <up-input prefixIcon="account" placeholder="请è¾å
¥è´¦å·" border="bottom" |
| | | <up-input prefixIcon="account" |
| | | placeholder="请è¾å
¥è´¦å·" |
| | | border="bottom" |
| | | @blur="getUserLoginFacotryList" |
| | | maxlength="30" v-model="loginForm.userName" clearable></up-input> |
| | | 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> |
| | | <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> |
| | | <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'}" |
| | | <up-checkbox :customStyle="{marginBottom: '8px'}" |
| | | label="è®°ä½å¯ç " |
| | | name="agree" |
| | | usedAlone |
| | | v-model:checked="rememberPassword" |
| | | > |
| | | v-model:checked="rememberPassword"> |
| | | </up-checkbox> |
| | | </view> |
| | | </view> |
| | |
| | | <script setup> |
| | | import {modal} from "@/plugins"; |
| | | |
| | | const showToast = (message) => { |
| | | const showToast = message => { |
| | | uni.showToast({ |
| | | title: message, |
| | | icon: 'none' |
| | | }) |
| | | } |
| | | import { userLoginFacotryList} from '@/api/login' |
| | | 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 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 userStore = useUserStore(); |
| | | const useWxLogin = ref(false); // æ¯å¦ä½¿ç¨å¾®ä¿¡ç»å½ |
| | | const rememberPassword = ref(false); // è®°ä½å¯ç |
| | | const loginForm = ref({ |
| | |
| | | password: "", |
| | | currentFatoryName: "", |
| | | }); |
| | | const factoryList = ref([]) // å
¬å¸å表 |
| | | 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); |
| | | 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); |
| | | uni.removeStorageSync("remembered_username"); |
| | | uni.removeStorageSync("remembered_password"); |
| | | uni.setStorageSync("remember_password", false); |
| | | } |
| | | } |
| | | |
| | | // 仿¬å°åå¨å è½½å¯ç |
| | | function loadPassword() { |
| | | const remembered = uni.getStorageSync('remember_password'); |
| | | const remembered = uni.getStorageSync("remember_password"); |
| | | if (remembered) { |
| | | rememberPassword.value = true; |
| | | const savedUsername = uni.getStorageSync('remembered_username'); |
| | | const savedPassword = uni.getStorageSync('remembered_password'); |
| | | const savedUsername = uni.getStorageSync("remembered_username"); |
| | | const savedPassword = uni.getStorageSync("remembered_password"); |
| | | if (savedUsername) { |
| | | loginForm.value.userName = savedUsername; |
| | | } |
| | |
| | | if (useWxLogin.value) { |
| | | getWxCode().then(res => { |
| | | console.log(res); |
| | | wxLogin('miniapp',res).then(res => { |
| | | wxLogin("miniapp", res).then(res => { |
| | | if(res.token != null){ |
| | | setToken(res.token); |
| | | loginSuccess() |
| | | loginSuccess(); |
| | | } |
| | | }); |
| | | }) |
| | | }); |
| | | } |
| | | |
| | | function getUserLoginFacotryList() { |
| | | if(loginForm.value.userName){ |
| | | userLoginFacotryList({userName:loginForm.value.userName}).then(res => { |
| | | console.log('res',res) |
| | | 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 |
| | | })) |
| | | name: item.deptName, |
| | | })); |
| | | } else { |
| | | // 妿res.data䏿¯æ°ç»ï¼è®¾ç½®ä¸ºç©ºæ°ç» |
| | | factoryList.value = [] |
| | | factoryList.value = []; |
| | | } |
| | | }).catch(error => { |
| | | showToast('è·åå
¬å¸å表失败:', error) |
| | | factoryList.value = [] |
| | | }) |
| | | .catch(error => { |
| | | showToast("è·åå
¬å¸å表失败:", error); |
| | | factoryList.value = []; |
| | | }); |
| | | }else { |
| | | factoryList.value = [] |
| | | factoryList.value = []; |
| | | } |
| | | } |
| | | |
| | | async function handleLogin() { |
| | | if (loginForm.value.userName === "") { |
| | | showToast("请è¾å
¥æ¨çè´¦å·") |
| | | showToast("请è¾å
¥æ¨çè´¦å·"); |
| | | } else if (loginForm.value.password === "") { |
| | | showToast("请è¾å
¥æ¨çå¯ç ") |
| | | showToast("请è¾å
¥æ¨çå¯ç "); |
| | | } else { |
| | | showToast("ç»å½ä¸ï¼è¯·èå¿çå¾
...") |
| | | pwdLogin() |
| | | showToast("ç»å½ä¸ï¼è¯·èå¿çå¾
..."); |
| | | pwdLogin(); |
| | | } |
| | | }; |
| | | } |
| | | // å¯ç ç»å½ |
| | | async function pwdLogin() { |
| | | userStore.loginCheckFactory(loginForm.value).then(() => { |
| | | modal.closeLoading() |
| | | userStore |
| | | .loginCheckFactory(loginForm.value) |
| | | .then(() => { |
| | | modal.closeLoading(); |
| | | // ç»å½æååä¿åå¯ç |
| | | savePassword(); |
| | | loginSuccess() |
| | | }).catch(() => { |
| | | modal.closeLoading() |
| | | loginSuccess(); |
| | | }) |
| | | }; |
| | | .catch(() => { |
| | | modal.closeLoading(); |
| | | }); |
| | | } |
| | | |
| | | function loginSuccess(result) { |
| | | // è®¾ç½®ç¨æ·ä¿¡æ¯ |
| | | userStore.getInfo().then(res => { |
| | | // ç»å½æååï¼å°å®¢æ·ç«¯æ¨éæ è¯åéå°æå¡å¨ |
| | | sendClientIdToServer(); |
| | | uni.switchTab({ |
| | | url: '/pages/index' |
| | | 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() |
| | | getUserLoginFacotryList(); |
| | | }); |
| | | </script> |
| | | |
| | |
| | | .login-btn { |
| | | margin-top: 60px; |
| | | height: 50px; |
| | | background: linear-gradient( 140deg, #00BAFF 0%, #006CFB 100%); |
| | | 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; |
| | | } |
| | |
| | | <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 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"> |
| | |
| | | <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="请è¾å
¥è´¦å·" |
| | | <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="请è¾å
¥å¯ç " |
| | | <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="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="请è¾å
¥éªè¯ç " |
| | | <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> |
| | | <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> |
| | | <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]"> |
| | | <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" |
| | | <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;" |
| | | <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> |
| | | <text class="text-forth" |
| | | @click="login()">è´¦å·å¯ç ç»å½</text> |
| | | </uni-row> |
| | | </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 codeUrl = ref(""); |
| | | const captchaEnabled = ref(true); |
| | | const loginForm = reactive({ |
| | | username: "admin", |
| | | password: "admin123", |
| | | code: "", |
| | | uuid: '' |
| | | }) |
| | | uuid: "", |
| | | }); |
| | | |
| | | const collapsedClass = computed(() => { |
| | | return isFixedViewVisible.value ? "" : `collapsed-${animationType.value}`; |
| | | }) |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | getCode() |
| | | }) |
| | | getCode(); |
| | | }); |
| | | |
| | | const login = () => { |
| | | play.value[2] = "running" |
| | | setTimeout(() => { page.value = 'login' }, 1000) |
| | | } |
| | | 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" |
| | | } |
| | | page.value = "index"; |
| | | play.value[0] = "paused"; |
| | | play.value[1] = "paused"; |
| | | play.value[2] = "paused"; |
| | | }; |
| | | const startplay = () => { |
| | | play.value[1] = "running" |
| | | 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) |
| | | 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 |
| | | 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 |
| | | codeUrl.value = "data:image/gif;base64," + res.img; |
| | | loginForm.uuid = res.uuid; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | // ç»å½æ¹æ³ |
| | | const handleLogin = async () => { |
| | | if (loginForm.username === "") { |
| | | modal.msgError("请è¾å
¥æ¨çè´¦å·") |
| | | modal.msgError("请è¾å
¥æ¨çè´¦å·"); |
| | | } else if (loginForm.password === "") { |
| | | modal.msgError("请è¾å
¥æ¨çå¯ç ") |
| | | modal.msgError("请è¾å
¥æ¨çå¯ç "); |
| | | } else if (loginForm.code === "" && captchaEnabled.value) { |
| | | modal.msgError("请è¾å
¥éªè¯ç ") |
| | | modal.msgError("请è¾å
¥éªè¯ç "); |
| | | } else { |
| | | modal.loading("ç»å½ä¸ï¼è¯·èå¿çå¾
...") |
| | | pwdLogin() |
| | | modal.loading("ç»å½ä¸ï¼è¯·èå¿çå¾
..."); |
| | | pwdLogin(); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | // å¯ç ç»å½ |
| | | const pwdLogin = async () => { |
| | | useUserStore().login(loginForm).then(() => { |
| | | modal.closeLoading() |
| | | loginSuccess() |
| | | }).catch(() => { |
| | | if (captchaEnabled.value) { |
| | | getCode() |
| | | } |
| | | useUserStore() |
| | | .login(loginForm) |
| | | .then(() => { |
| | | modal.closeLoading(); |
| | | loginSuccess(); |
| | | }) |
| | | .catch(() => { |
| | | if (captchaEnabled.value) { |
| | | getCode(); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // ç»å½æååï¼å¤ç彿° |
| | | const loginSuccess = (result) => { |
| | | const loginSuccess = result => { |
| | | // è®¾ç½®ç¨æ·ä¿¡æ¯ |
| | | useUserStore().getInfo().then(res => { |
| | | tab.reLaunch('/pages/index') |
| | | }) |
| | | 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 { |
| | |
| | | text-align: left; |
| | | padding-left: 15px; |
| | | } |
| | | |
| | | } |
| | | |
| | | .login-btn { |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | .container { |
| | | position: relative; |
| | | } |
| | |
| | | border-radius: 50%; |
| | | z-index: 9999; |
| | | |
| | | background: linear-gradient(180deg, |
| | | background: linear-gradient( |
| | | 180deg, |
| | | rgba(110, 109, 122, 0.595), |
| | | rgba(46, 87, 190, 0.714) 70.792%, |
| | | rgb(17, 120, 222) 100%); |
| | | rgb(17, 120, 222) 100% |
| | | ); |
| | | box-shadow: inset 0 0 10px 5px rgba(101, 97, 97, 0.5); |
| | | } |
| | | |
| | |
| | | transition: background-color 0.3s; |
| | | z-index: 9999; |
| | | |
| | | background: linear-gradient(180deg, |
| | | background: linear-gradient( |
| | | 180deg, |
| | | rgba(60, 53, 239, 0.595), |
| | | rgba(63, 117, 255, 0.714) 70.792%, |
| | | rgb(70, 161, 253) 100%); |
| | | 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, .3) inset; |
| | | |
| | | box-shadow: 0 0 10px rgba(0, 0, 0, 0.3) inset; |
| | | } |
| | | |
| | | .shadow1 { |
| | |
| | | |
| | | // 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: 'ripple1'; |
| | | box-shadow: 0 0 10px rgba(0, 0, 0, 0.3) inset; |
| | | -webkit-animation-name: "ripple1"; |
| | | /*å¨ç»å±æ§åï¼ä¹å°±æ¯æä»¬åé¢keyframeså®ä¹çå¨ç»å*/ |
| | | -webkit-animation-duration: 0.3s; |
| | | /*å¨ç»æç»æ¶é´*/ |
| | |
| | | |
| | | // 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'; |
| | | box-shadow: 0 0 10px rgba(0, 0, 0, 0.3) inset; |
| | | -webkit-animation-name: "ripple2"; |
| | | /*å¨ç»å±æ§åï¼ä¹å°±æ¯æä»¬åé¢keyframeså®ä¹çå¨ç»å*/ |
| | | -webkit-animation-duration: 0.4s; |
| | | /*å¨ç»æç»æ¶é´*/ |
| | |
| | | |
| | | // 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'; |
| | | box-shadow: 0 0 10px rgba(0, 0, 0, 0.3) inset; |
| | | -webkit-animation-name: "ripple3"; |
| | | /*å¨ç»å±æ§åï¼ä¹å°±æ¯æä»¬åé¢keyframeså®ä¹çå¨ç»å*/ |
| | | -webkit-animation-duration: 0.5s; |
| | | /*å¨ç»æç»æ¶é´*/ |
| | |
| | | } |
| | | |
| | | .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; |
| | | -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; |
| | | } |
| | | |
| | | .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; |
| | | -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; |
| | | } |
| | | |
| | | .scale-in-center { |
| | | animation: scale-in-center 0.4s cubic-bezier(0.250, 0.460, 0.450, 0.940) both; |
| | | animation: scale-in-center 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94) both; |
| | | } |
| | | |
| | | @-webkit-keyframes slide-top { |
| | |
| | | 100% { |
| | | transform: scale(1.4); |
| | | opacity: 0; |
| | | |
| | | } |
| | | } |
| | | |
| | |
| | | 100% { |
| | | transform: scale(1.5); |
| | | opacity: 0; |
| | | |
| | | } |
| | | } |
| | | |
| | |
| | | 100% { |
| | | transform: scale(1.6); |
| | | opacity: 0; |
| | | |
| | | } |
| | | } |
| | | |