first commit

This commit is contained in:
Ls
2026-02-12 12:19:20 +08:00
commit 219fd9be5c
529 changed files with 169918 additions and 0 deletions

View File

@@ -0,0 +1,450 @@
<template>
<view v-if="loading" class="skeleton-container">
<!-- 接单状态骨架屏 -->
<view class="skeleton-status-section">
<view class="skeleton-title"></view>
<view class="skeleton-status-button"></view>
</view>
<!-- 热门接单区域骨架屏 -->
<view class="skeleton-map-section">
<view class="skeleton-title"></view>
<view class="skeleton-map-placeholder"></view>
<view class="skeleton-map-tip"></view>
</view>
<!-- 服务范围骨架屏 -->
<view class="skeleton-service-section">
<view class="skeleton-title"></view>
<view class="skeleton-service-card">
<view class="skeleton-icon"></view>
<view class="skeleton-text"></view>
<view class="skeleton-switch"></view>
</view>
</view>
<!-- 提示信息骨架屏 -->
<view class="skeleton-tip-section">
<view class="skeleton-tip-card">
<view class="skeleton-icon"></view>
<view class="skeleton-tip-text"></view>
</view>
<view class="skeleton-tip-card">
<view class="skeleton-icon"></view>
<view class="skeleton-tip-text"></view>
</view>
</view>
</view>
<view v-else class="online-management-page">
<!-- 接单状态 -->
<view class="status-section">
<view class="status-card">
<text class="section-title">接单状态</text>
<view class="status-button" @click="toggleStatus()" :class="{ 'online': isOnline, 'offline': !isOnline }">
<text class="status-text">{{ isOnline ? '接单中 · 点击下线' : '已下线 · 点击上线' }}</text>
</view>
</view>
</view>
<!-- 热门接单区域 -->
<view class="map-section">
<text class="section-title">热门接单区域</text>
<view class="map-container">
<!-- 地图占位,使用黑边白底样式 -->
<view class="map-placeholder">
<view class="map-content">
<!-- 模拟地图上的区域标记 -->
<view class="map-area red-area"></view>
<view class="map-area yellow-area"></view>
<view class="map-area green-area"></view>
<text class="map-label">地图加载中...</text>
</view>
</view>
<text class="map-tip">红色区域订单更多,建议在此范围内接单</text>
</view>
</view>
<!-- 服务范围 -->
<text class="section-title">服务范围</text>
<view class="service-card">
<view class="range-setting">
<view class="range-left">
<up-icon name="map" size="20" color="#1890ff" style="margin-right: 16rpx;"></up-icon>
<text class="range-text">手动划定接单范围</text>
</view>
<up-switch v-model="manualRangeEnabled" size="20" @change="handleRangeSwitchChange"></up-switch>
</view>
</view>
<!-- 提示信息 -->
<view class="tip-card info">
<up-icon name="info-circle" size="20" color="#1890ff" style="margin-right: 16rpx;"></up-icon>
<text class="tip-text">上线后系统将自动推送附近订单,您可在'任务'查看并抢单。</text>
</view>
<view class="tip-card warning">
<up-icon name="warning" size="20" color="#fa8c16" style="margin-right: 16rpx;"></up-icon>
<text class="tip-text">请确保在服务区域内接单,超出范围可能影响配送效率和收入。</text>
</view>
</view>
</template>
<script setup lang="ts">
import { onLoad } from '@dcloudio/uni-app';
import { ref } from 'vue';
let loading = ref(true)
// 接单状态
const isOnline = ref(true);
// 是否启用手动划定范围
const manualRangeEnabled = ref(false);
onLoad(() => {
setTimeout(()=>{
loading.value=false
},1000)
})
// 切换在线状态
const toggleStatus = () => {
const newStatus = !isOnline.value;
// 显示确认对话框
uni.showModal({
title: newStatus ? '确认上线' : '确认下线',
content: newStatus ? '上线后将接收订单推送,确定要上线吗?' : '下线后将停止接收订单推送,确定要下线吗?',
success: (res) => {
if (res.confirm) {
isOnline.value = newStatus;
uni.showToast({
title: newStatus ? '已成功上线' : '已成功下线',
icon: 'success'
});
}
}
});
};
// 处理范围开关变化
const handleRangeSwitchChange = (value : boolean) => {
manualRangeEnabled.value = value;
};
</script>
<style scoped lang="scss">
/* 页面基础样式 */
.online-management-page {
margin: 20rpx;
}
/* 标题通用样式 */
.section-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
margin-bottom: 24rpx;
}
/* 状态区域 */
.status-section {
background-color: #fff;
padding: 30rpx;
margin-bottom: 20rpx;
border-radius: 20rpx;
}
.status-card {
display: flex;
flex-direction: column;
}
.status-button {
height: 86rpx;
border-radius: 60rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
font-weight: 600;
transition: all 0.3s ease;
}
.status-button.online {
background-color: #52c41a;
color: #fff;
}
.status-button.offline {
background-color: #d9d9d9;
color: #666;
}
.status-button:active {
opacity: 0.8;
}
/* 地图区域 */
.map-section {
background-color: #fff;
padding: 30rpx;
margin-bottom: 20rpx;
border-radius: 20rpx;
}
.map-container {
display: flex;
flex-direction: column;
}
.map-placeholder {
width: 100%;
height: 500rpx;
border: 2rpx solid #ddd;
background-color: #fff;
border-radius: 12rpx;
margin-bottom: 20rpx;
overflow: hidden;
}
.map-content {
width: 100%;
height: 100%;
position: relative;
background-color: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
}
/* 地图上的区域标记 */
.map-area {
position: absolute;
border-radius: 50%;
opacity: 0.3;
}
.red-area {
width: 300rpx;
height: 300rpx;
background-color: #ff4d4f;
top: 120rpx;
right: 150rpx;
z-index: 3;
}
.yellow-area {
width: 250rpx;
height: 250rpx;
background-color: #faad14;
top: 80rpx;
left: 120rpx;
z-index: 2;
}
.green-area {
width: 200rpx;
height: 200rpx;
background-color: #52c41a;
bottom: 100rpx;
right: 200rpx;
z-index: 1;
}
.map-label {
font-size: 28rpx;
color: #999;
z-index: 10;
}
.map-tip {
font-size: 26rpx;
color: #666;
line-height: 1.5;
}
/* 服务范围 */
.service-range-section {
background-color: #fff;
padding: 30rpx;
margin-bottom: 20rpx;
}
.service-card {
margin-top: 20rpx;
background-color: #fff;
border-radius: 20rpx;
padding: 24rpx;
}
.range-setting {
display: flex;
justify-content: space-between;
align-items: center;
}
.range-left {
display: flex;
align-items: center;
}
.range-text {
font-size: 30rpx;
color: #333;
}
/* 提示信息 */
.tip-card {
display: flex;
align-items: flex-start;
padding: 24rpx;
margin-top: 20rpx;
border-radius: 12rpx;
font-size: 26rpx;
line-height: 1.6;
}
.tip-card.info {
background-color: #F6FFFB;
}
.tip-card.warning {
background-color: #FFFFFF;
}
.tip-text {
flex: 1;
}
/* 骨架屏样式 */
.skeleton-container {
margin: 20rpx;
}
.skeleton-status-section,
.skeleton-map-section,
.skeleton-service-section {
background-color: #fff;
padding: 30rpx;
margin-bottom: 20rpx;
border-radius: 20rpx;
}
.skeleton-tip-section {
padding: 0;
}
.skeleton-title {
height: 32rpx;
width: 160rpx;
background-color: #f0f0f0;
border-radius: 4rpx;
margin-bottom: 24rpx;
animation: shimmer 1.5s infinite;
}
.skeleton-status-button {
height: 86rpx;
width: 100%;
background-color: #f0f0f0;
border-radius: 60rpx;
animation: shimmer 1.5s infinite;
}
.skeleton-map-placeholder {
height: 500rpx;
width: 100%;
background-color: #f0f0f0;
border-radius: 12rpx;
margin-bottom: 20rpx;
animation: shimmer 1.5s infinite;
}
.skeleton-map-tip {
height: 26rpx;
width: 70%;
background-color: #f0f0f0;
border-radius: 4rpx;
animation: shimmer 1.5s infinite;
}
.skeleton-service-card {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx;
background-color: #fafafa;
border-radius: 20rpx;
}
.skeleton-icon {
width: 40rpx;
height: 40rpx;
background-color: #f0f0f0;
border-radius: 4rpx;
animation: shimmer 1.5s infinite;
}
.skeleton-text {
height: 30rpx;
width: 280rpx;
background-color: #f0f0f0;
border-radius: 4rpx;
margin-left: 16rpx;
animation: shimmer 1.5s infinite;
}
.skeleton-switch {
width: 80rpx;
height: 44rpx;
background-color: #f0f0f0;
border-radius: 22rpx;
animation: shimmer 1.5s infinite;
}
.skeleton-tip-card {
display: flex;
align-items: center;
padding: 24rpx;
margin-bottom: 20rpx;
background-color: #fff;
border-radius: 12rpx;
}
.skeleton-tip-text {
flex: 1;
height: 26rpx;
background-color: #f0f0f0;
border-radius: 4rpx;
margin-left: 16rpx;
animation: shimmer 1.5s infinite;
}
/* 骨架屏闪烁动画 */
@keyframes shimmer {
0% {
background-position: -1000px 0;
}
100% {
background-position: 1000px 0;
}
}
.skeleton-title,
.skeleton-status-button,
.skeleton-map-placeholder,
.skeleton-map-tip,
.skeleton-icon,
.skeleton-text,
.skeleton-switch,
.skeleton-tip-text {
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 1000px 100%;
}
</style>

View File

@@ -0,0 +1,567 @@
<template>
<view class="uni-calendar">
<view v-if="!insert&&show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}" @click="clean"></view>
<view v-if="insert || show" class="uni-calendar__content" :class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow}">
<view v-if="!insert" class="uni-calendar__header uni-calendar--fixed-top">
<view class="uni-calendar__header-btn-box" @click="close">
<text class="uni-calendar__header-text uni-calendar--fixed-width">{{cancelText}}</text>
</view>
<view class="uni-calendar__header-btn-box" @click="confirm">
<text class="uni-calendar__header-text uni-calendar--fixed-width">{{okText}}</text>
</view>
</view>
<view class="uni-calendar__header">
<view class="uni-calendar__header-btn-box" @click.stop="pre">
<view class="uni-calendar__header-btn uni-calendar--left"></view>
</view>
<picker mode="date" :value="date" fields="month" @change="bindDateChange">
<text class="uni-calendar__header-text">{{ (nowDate.year||'') +' / '+( nowDate.month||'')}}</text>
</picker>
<view class="uni-calendar__header-btn-box" @click.stop="next">
<view class="uni-calendar__header-btn uni-calendar--right"></view>
</view>
<text class="uni-calendar__backtoday" @click="backToday">{{todayText}}</text>
</view>
<view class="uni-calendar__box">
<view v-if="showMonth" class="uni-calendar__box-bg">
<text class="uni-calendar__box-bg-text">{{nowDate.month}}</text>
</view>
<view class="uni-calendar__weeks">
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{SUNText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{monText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{TUEText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{WEDText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{THUText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{FRIText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{SATText}}</text>
</view>
</view>
<view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
<view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
<calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar" :selected="selected" :lunar="lunar" @change="choiceDate"></calendar-item>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import Calendar from './util.js';
import CalendarItem from './uni-calendar-item.vue'
import { initVueI18n } from '@dcloudio/uni-i18n'
import i18nMessages from './i18n/index.js'
const { t } = initVueI18n(i18nMessages)
/**
* Calendar 日历
* @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等
* @tutorial https://ext.dcloud.net.cn/plugin?id=56
* @property {String} date 自定义当前时间,默认为今天
* @property {Boolean} lunar 显示农历
* @property {String} startDate 日期选择范围-开始日期
* @property {String} endDate 日期选择范围-结束日期
* @property {Boolean} range 范围选择
* @property {Boolean} insert = [true|false] 插入模式,默认为false
* @value true 弹窗模式
* @value false 插入模式
* @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容
* @property {Array} selected 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]
* @property {Boolean} showMonth 是否选择月份为背景
* @event {Function} change 日期改变,`insert :ture` 时生效
* @event {Function} confirm 确认选择`insert :false` 时生效
* @event {Function} monthSwitch 切换月份时触发
* @example <uni-calendar :insert="true":lunar="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
*/
export default {
components: {
CalendarItem
},
emits:['close','confirm','change','monthSwitch'],
props: {
date: {
type: String,
default: ''
},
selected: {
type: Array,
default () {
return []
}
},
lunar: {
type: Boolean,
default: false
},
startDate: {
type: String,
default: ''
},
endDate: {
type: String,
default: ''
},
range: {
type: Boolean,
default: false
},
insert: {
type: Boolean,
default: true
},
showMonth: {
type: Boolean,
default: true
},
clearDate: {
type: Boolean,
default: true
}
},
data() {
return {
show: false,
weeks: [],
calendar: {},
nowDate: '',
aniMaskShow: false
}
},
computed:{
/**
* for i18n
*/
okText() {
return t("uni-calender.ok")
},
cancelText() {
return t("uni-calender.cancel")
},
todayText() {
return t("uni-calender.today")
},
monText() {
return t("uni-calender.MON")
},
TUEText() {
return t("uni-calender.TUE")
},
WEDText() {
return t("uni-calender.WED")
},
THUText() {
return t("uni-calender.THU")
},
FRIText() {
return t("uni-calender.FRI")
},
SATText() {
return t("uni-calender.SAT")
},
SUNText() {
return t("uni-calender.SUN")
},
},
watch: {
date(newVal) {
// this.cale.setDate(newVal)
this.init(newVal)
},
startDate(val){
this.cale.resetSatrtDate(val)
this.cale.setDate(this.nowDate.fullDate)
this.weeks = this.cale.weeks
},
endDate(val){
this.cale.resetEndDate(val)
this.cale.setDate(this.nowDate.fullDate)
this.weeks = this.cale.weeks
},
selected(newVal) {
this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
this.weeks = this.cale.weeks
}
},
created() {
this.cale = new Calendar({
selected: this.selected,
startDate: this.startDate,
endDate: this.endDate,
range: this.range,
})
this.init(this.date)
},
methods: {
// 取消穿透
clean() {},
bindDateChange(e) {
const value = e.detail.value + '-1'
this.setDate(value)
const { year,month } = this.cale.getDate(value)
this.$emit('monthSwitch', {
year,
month
})
},
/**
* 初始化日期显示
* @param {Object} date
*/
init(date) {
this.cale.setDate(date)
this.weeks = this.cale.weeks
this.nowDate = this.calendar = this.cale.getInfo(date)
},
/**
* 打开日历弹窗
*/
open() {
// 弹窗模式并且清理数据
if (this.clearDate && !this.insert) {
this.cale.cleanMultipleStatus()
// this.cale.setDate(this.date)
this.init(this.date)
}
this.show = true
this.$nextTick(() => {
setTimeout(() => {
this.aniMaskShow = true
}, 50)
})
},
/**
* 关闭日历弹窗
*/
close() {
this.aniMaskShow = false
this.$nextTick(() => {
setTimeout(() => {
this.show = false
this.$emit('close')
}, 300)
})
},
/**
* 确认按钮
*/
confirm() {
this.setEmit('confirm')
this.close()
},
/**
* 变化触发
*/
change() {
if (!this.insert) return
this.setEmit('change')
},
/**
* 选择月份触发
*/
monthSwitch() {
let {
year,
month
} = this.nowDate
this.$emit('monthSwitch', {
year,
month: Number(month)
})
},
/**
* 派发事件
* @param {Object} name
*/
setEmit(name) {
let {
year,
month,
date,
fullDate,
lunar,
extraInfo
} = this.calendar
this.$emit(name, {
range: this.cale.multipleStatus,
year,
month,
date,
fulldate: fullDate,
lunar,
extraInfo: extraInfo || {}
})
},
/**
* 选择天触发
* @param {Object} weeks
*/
choiceDate(weeks) {
if (weeks.disable) return
this.calendar = weeks
// 设置多选
this.cale.setMultiple(this.calendar.fullDate)
this.weeks = this.cale.weeks
this.change()
},
/**
* 回到今天
*/
backToday() {
const nowYearMonth = `${this.nowDate.year}-${this.nowDate.month}`
const date = this.cale.getDate(new Date())
const todayYearMonth = `${date.year}-${date.month}`
this.init(date.fullDate)
if(nowYearMonth !== todayYearMonth) {
this.monthSwitch()
}
this.change()
},
/**
* 上个月
*/
pre() {
const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate
this.setDate(preDate)
this.monthSwitch()
},
/**
* 下个月
*/
next() {
const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate
this.setDate(nextDate)
this.monthSwitch()
},
/**
* 设置日期
* @param {Object} date
*/
setDate(date) {
this.cale.setDate(date)
this.weeks = this.cale.weeks
this.nowDate = this.cale.getInfo(date)
}
}
}
</script>
<style lang="scss" scoped>
$uni-bg-color-mask: rgba($color: #000000, $alpha: 0.4);
$uni-border-color: #EDEDED;
$uni-text-color: #333;
$uni-bg-color-hover:#f1f1f1;
$uni-font-size-base:14px;
$uni-text-color-placeholder: #808080;
$uni-color-subtitle: #555555;
$uni-text-color-grey:#999;
.uni-calendar {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
}
.uni-calendar__mask {
position: fixed;
bottom: 0;
top: 0;
left: 0;
right: 0;
background-color: $uni-bg-color-mask;
transition-property: opacity;
transition-duration: 0.3s;
opacity: 0;
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
}
.uni-calendar--mask-show {
opacity: 1
}
.uni-calendar--fixed {
position: fixed;
/* #ifdef APP-NVUE */
bottom: 0;
/* #endif */
left: 0;
right: 0;
transition-property: transform;
transition-duration: 0.3s;
transform: translateY(460px);
/* #ifndef APP-NVUE */
bottom: calc(var(--window-bottom));
z-index: 99;
/* #endif */
}
.uni-calendar--ani-show {
transform: translateY(0);
}
.uni-calendar__content {
background-color: #fff;
}
.uni-calendar__header {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
align-items: center;
height: 50px;
border-bottom-color: $uni-border-color;
border-bottom-style: solid;
border-bottom-width: 1px;
}
.uni-calendar--fixed-top {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
border-top-color: $uni-border-color;
border-top-style: solid;
border-top-width: 1px;
}
.uni-calendar--fixed-width {
width: 50px;
}
.uni-calendar__backtoday {
position: absolute;
right: 0;
top: 25rpx;
padding: 0 5px;
padding-left: 10px;
height: 25px;
line-height: 25px;
font-size: 12px;
border-top-left-radius: 25px;
border-bottom-left-radius: 25px;
color: $uni-text-color;
background-color: $uni-bg-color-hover;
}
.uni-calendar__header-text {
text-align: center;
width: 100px;
font-size: $uni-font-size-base;
color: $uni-text-color;
}
.uni-calendar__header-btn-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
width: 50px;
height: 50px;
}
.uni-calendar__header-btn {
width: 10px;
height: 10px;
border-left-color: $uni-text-color-placeholder;
border-left-style: solid;
border-left-width: 2px;
border-top-color: $uni-color-subtitle;
border-top-style: solid;
border-top-width: 2px;
}
.uni-calendar--left {
transform: rotate(-45deg);
}
.uni-calendar--right {
transform: rotate(135deg);
}
.uni-calendar__weeks {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.uni-calendar__weeks-item {
flex: 1;
}
.uni-calendar__weeks-day {
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
height: 45px;
border-bottom-color: #F5F5F5;
border-bottom-style: solid;
border-bottom-width: 1px;
}
.uni-calendar__weeks-day-text {
font-size: 14px;
}
.uni-calendar__box {
position: relative;
}
.uni-calendar__box-bg {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.uni-calendar__box-bg-text {
font-size: 200px;
font-weight: bold;
color: $uni-text-color-grey;
opacity: 0.1;
text-align: center;
/* #ifndef APP-NVUE */
line-height: 1;
/* #endif */
}
</style>

View File

@@ -0,0 +1,657 @@
<template>
<!-- 骨架屏状态 -->
<view v-if="loading" class="skeleton-loading">
<!-- 收入概览骨架屏 -->
<view class="skeleton-card income-overview">
<view class="skeleton-income-title"></view>
<view class="skeleton-income-amount"></view>
<view class="skeleton-time-tabs">
<view class="skeleton-tab-item"></view>
<view class="skeleton-tab-item"></view>
<view class="skeleton-tab-item"></view>
</view>
<view class="skeleton-month-total"></view>
</view>
<!-- 收入构成骨架屏 -->
<view class="skeleton-card income-composition">
<view class="skeleton-pie-container">
<view class="skeleton-pie-chart"></view>
<view class="skeleton-legend-list">
<view class="skeleton-legend-item" v-for="item in 3">
<view class="skeleton-legend-dot"></view>
<view class="skeleton-legend-text"></view>
</view>
</view>
</view>
</view>
<!-- 钱包区域骨架屏 -->
<view class="skeleton-card wallet-section">
<view class="skeleton-wallet-header">
<view class="skeleton-wallet-title"></view>
<view class="skeleton-wallet-amount"></view>
</view>
<view class="skeleton-withdraw-button"></view>
<view class="skeleton-withdraw-tip"></view>
</view>
<!-- 收入明细骨架屏 -->
<view class="skeleton-card">
<view class="skeleton-detail-title"></view>
</view>
<!-- 明细项骨架屏 -->
<view v-for="index in 3" :key="index" class="skeleton-card detail-list">
<view class="skeleton-detail-content">
<view class="skeleton-icon-placeholder"></view>
<view class="skeleton-detail-info">
<view class="skeleton-order-id"></view>
<view class="skeleton-order-time"></view>
</view>
<view class="skeleton-order-amount"></view>
</view>
</view>
<!-- 加载更多 -->
<view class="skeleton-card" style="display: flex; justify-content: center; ">
<view class="skeleton-detail-title"></view>
</view>
</view>
<!-- 收入概览区域 -->
<view v-else class="income-container">
<view class="income-overview">
<view class="income-header">
<text class="income-title">今日已赚</text>
<text class="income-amount">¥86.50</text>
</view>
<!-- 时间选择标签 -->
<view class="time-tabs">
<text v-for="(item ,index) in timeList" :key="index" @click="changeTab(index)"
:class="{ 'active':currentTime==index }" class="tab-item">{{item}}</text>
</view>
<text class="month-total">本月累计¥1,240.00</text>
</view>
<!-- 收入构成区域 -->
<view class="income-composition">
<!-- 饼图占位区域 -->
<view class="pie-chart-placeholder">
<view id="cahrt" class="pie-chart">
<!-- 黑边白底的饼图占位 -->
</view>
<view class="chart-legend">
<view class="legend-item">
<view class="legend-dot blue"></view>
<text class="legend-text">配送费¥60.50</text>
</view>
<view class="legend-item">
<view class="legend-dot orange"></view>
<text class="legend-text">冲单奖¥20.00</text>
</view>
<view class="legend-item">
<view class="legend-dot green"></view>
<text class="legend-text">恶劣天气补贴¥6.00</text>
</view>
</view>
</view>
</view>
<!-- 钱包区域 -->
<view class="wallet-section">
<view class="wallet-header">
<text class="wallet-title">钱包余额</text>
<text class="wallet-amount">¥86.50</text>
</view>
<u-button class="withdraw-button" @click="Service.GoPage('/pages/order/withdraw')" type="primary">立即提现</u-button>
<text class="withdraw-tip">提现到账时间: T+1工作日</text>
</view>
<!-- 收入明细区域 -->
<view class="detail-header">
<text class="detail-title">收入明细</text>
</view>
<view class="detail-list" @click="Service.GoPage('/pages/order/incomeDetail')" v-for="(item, index) in 3"
:key="index">
<view class="detail-content">
<view class="icon-placeholder">
<image :src="Service.GetIconImg('/static/index/income/order.png')"
style="width: 55rpx; height: 55rpx;" mode=""></image>
</view>
<view class="detail-info">
<text class="order-id">订单 MT20251020123456</text>
<text class="order-time">10-20 18:35</text>
</view>
<text class="order-amount">+¥5.50</text>
</view>
</view>
<up-loadmore :status="status" />
<view class="" style="width: 100vw; height: 100rpx; ">
</view>
</view>
</template>
<script setup lang="ts">
import { onLoad } from '@dcloudio/uni-app';
import { ref, onMounted } from 'vue';
import * as echarts from 'echarts';
import { Service } from '@/Service/Service';
let loading = ref(true)
let timeList = ref([
'今日',
'本周',
'本月'
])
let currentTime = ref(0)
let status = ref('nomore')
let test = ref(10)
let option = ref({
tooltip: {
'show': false
},
legend: {
'show': false
},
series: [
{
name: 'Access From',
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: true,
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: false,
fontSize: 40,
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: [
{ value: test.value, name: "配送奖", itemStyle: { color: '#1890FF' } },
{ value: 735, name: "冲单奖", itemStyle: { color: '#52C41A' } },
{ value: 580, name: "恶劣天气奖", itemStyle: { color: '#FF4D4F' } }
]
}
]
})
onLoad(() => {
setTimeout(() => {
loading.value = false
setTimeout(() => {
draw()
}, 1000)
}, 1000)
})
onMounted(() => {
})
const draw = () => {
let chartDom = ref(document.getElementById('cahrt'))
let myChart = ref(echarts.init(chartDom.value))
myChart.value.setOption(option.value)
}
const changeTab = (index : number) => {
currentTime.value = index
}
</script>
<style scoped>
.income-container {
padding: 20rpx;
background-color: #f5f5f5;
min-height: 100vh;
box-sizing: border-box;
}
/* 收入概览区域 */
.income-overview {
background-color: #fff;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 20rpx;
}
.income-header {
margin-bottom: 20rpx;
}
.income-title {
font-size: 28rpx;
color: #666;
display: block;
margin-bottom: 10rpx;
}
.income-amount {
font-size: 48rpx;
font-weight: bold;
color: #ff4d4f;
}
/* 时间标签 */
.time-tabs {
display: flex;
margin-bottom: 20rpx;
}
.tab-item {
font-size: 28rpx;
color: #666;
margin-right: 40rpx;
padding-bottom: 10rpx;
}
.tab-item.active {
color: #1890ff;
border-bottom: 3rpx solid #1890ff;
}
.month-total {
font-size: 26rpx;
color: #666;
}
/* 收入构成区域 */
.income-composition {
background-color: #fff;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 20rpx;
}
/* 饼图占位 */
.pie-chart-placeholder {
display: flex;
align-items: center;
}
.pie-chart {
width: 200rpx;
height: 200rpx;
margin-right: 30rpx;
position: relative;
overflow: hidden;
}
.chart-legend {
flex: 1;
}
.legend-item {
display: flex;
align-items: center;
margin-bottom: 15rpx;
}
.legend-dot {
width: 16rpx;
height: 16rpx;
border-radius: 50%;
margin-right: 10rpx;
}
.legend-dot.blue {
background-color: var(--nav-mian);
}
.legend-dot.orange {
background-color: var(--nav-vice);
}
.legend-dot.green {
background-color: var(--nav-diluted);
}
.legend-text {
font-size: 26rpx;
color: #666;
}
/* 钱包区域 */
.wallet-section {
background-color: #fff;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 20rpx;
}
.wallet-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
}
.wallet-title {
font-size: 28rpx;
color: #333;
}
.wallet-amount {
font-size: 36rpx;
font-weight: bold;
color: #ff4d4f;
}
.withdraw-button {
width: 100%;
height: 80rpx;
line-height: 80rpx;
font-size: 32rpx;
border-radius: 40rpx;
background-color: #1890ff;
color: #fff;
margin-bottom: 10rpx;
}
.withdraw-tip {
display: block;
font-size: 22rpx;
color: #999;
text-align: center;
}
/* 收入明细区域 */
.income-detail {
background-color: #fff;
border-radius: 20rpx;
padding: 30rpx;
}
.detail-header {
margin-bottom: 20rpx;
}
.detail-title {
font-size: 28rpx;
font-weight: bold;
color: #333;
}
.detail-content {
display: flex;
align-items: center;
}
.detail-list {
margin: 15rpx 0 0;
background-color: #fff;
padding: 20rpx 30rpx;
border-radius: 20rpx;
}
/* 图标占位符 - 黑边白底 */
.icon-placeholder {
width: 70rpx;
height: 70rpx;
background-color: #E6F7FF;
border-radius: 8rpx;
margin-right: 20rpx;
display: flex;
align-items: center;
justify-content: center;
}
.detail-info {
flex: 1;
}
.order-id {
display: block;
font-size: 26rpx;
color: #333;
margin-bottom: 5rpx;
}
.order-time {
font-size: 24rpx;
color: #999;
}
.order-amount {
font-size: 32rpx;
font-weight: bold;
color: #ff4d4f;
}
/* 没有更多记录 */
.no-more {
text-align: center;
padding: 40rpx 0;
}
.no-more-text {
font-size: 24rpx;
color: #999;
}
/* 骨架屏样式 */
.skeleton-loading .skeleton-card {
background-color: #fff;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 20rpx;
position: relative;
overflow: hidden;
}
/* 收入概览骨架屏 */
.skeleton-income-title {
width: 100rpx;
height: 30rpx;
background-color: #f0f0f0;
border-radius: 4rpx;
margin-bottom: 15rpx;
}
.skeleton-income-amount {
width: 200rpx;
height: 50rpx;
background-color: #f0f0f0;
border-radius: 4rpx;
margin-bottom: 20rpx;
}
.skeleton-time-tabs {
display: flex;
margin-bottom: 20rpx;
}
.skeleton-tab-item {
width: 80rpx;
height: 30rpx;
background-color: #f0f0f0;
border-radius: 4rpx;
margin-right: 40rpx;
}
.skeleton-month-total {
width: 200rpx;
height: 30rpx;
background-color: #f0f0f0;
border-radius: 4rpx;
}
/* 收入构成骨架屏 */
.skeleton-pie-container {
display: flex;
align-items: center;
}
.skeleton-pie-chart {
width: 200rpx;
height: 200rpx;
background-color: #f0f0f0;
border-radius: 50%;
margin-right: 30rpx;
}
.skeleton-legend-list {
flex: 1;
}
.skeleton-legend-item {
display: flex;
align-items: center;
margin-bottom: 15rpx;
}
.skeleton-legend-dot {
width: 16rpx;
height: 16rpx;
background-color: #f0f0f0;
border-radius: 50%;
margin-right: 10rpx;
}
.skeleton-legend-text {
width: 200rpx;
height: 30rpx;
background-color: #f0f0f0;
border-radius: 4rpx;
}
/* 钱包区域骨架屏 */
.skeleton-wallet-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
}
.skeleton-wallet-title {
width: 120rpx;
height: 30rpx;
background-color: #f0f0f0;
border-radius: 4rpx;
}
.skeleton-wallet-amount {
width: 150rpx;
height: 40rpx;
background-color: #f0f0f0;
border-radius: 4rpx;
}
.skeleton-withdraw-button {
width: 100%;
height: 80rpx;
background-color: #f0f0f0;
border-radius: 40rpx;
margin-bottom: 10rpx;
}
.skeleton-withdraw-tip {
width: 300rpx;
height: 24rpx;
background-color: #f0f0f0;
border-radius: 4rpx;
margin: 0 auto;
}
/* 收入明细骨架屏 */
.skeleton-detail-title {
width: 150rpx;
height: 30rpx;
background-color: #f0f0f0;
border-radius: 4rpx;
}
.skeleton-detail-content {
display: flex;
align-items: center;
}
.skeleton-icon-placeholder {
width: 70rpx;
height: 70rpx;
background-color: #f0f0f0;
border-radius: 8rpx;
margin-right: 20rpx;
}
.skeleton-detail-info {
flex: 1;
}
.skeleton-order-id {
width: 300rpx;
height: 30rpx;
background-color: #f0f0f0;
border-radius: 4rpx;
margin-bottom: 10rpx;
}
.skeleton-order-time {
width: 200rpx;
height: 26rpx;
background-color: #f0f0f0;
border-radius: 4rpx;
}
.skeleton-order-amount {
width: 100rpx;
height: 36rpx;
background-color: #f0f0f0;
border-radius: 4rpx;
}
/* 骨架屏动画 */
.skeleton-loading .skeleton-income-title::after,
.skeleton-loading .skeleton-income-amount::after,
.skeleton-loading .skeleton-tab-item::after,
.skeleton-loading .skeleton-month-total::after,
.skeleton-loading .skeleton-pie-chart::after,
.skeleton-loading .skeleton-legend-dot::after,
.skeleton-loading .skeleton-legend-text::after,
.skeleton-loading .skeleton-wallet-title::after,
.skeleton-loading .skeleton-wallet-amount::after,
.skeleton-loading .skeleton-withdraw-button::after,
.skeleton-loading .skeleton-withdraw-tip::after,
.skeleton-loading .skeleton-detail-title::after,
.skeleton-loading .skeleton-icon-placeholder::after,
.skeleton-loading .skeleton-order-id::after,
.skeleton-loading .skeleton-order-time::after,
.skeleton-loading .skeleton-order-amount::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
animation: shimmer 1.5s infinite;
}
@keyframes shimmer {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
</style>