Selaa lähdekoodia

uni app x 适配

xuexiuyun 1 kuukausi sitten
vanhempi
sitoutus
7b0b1696e6
100 muutettua tiedostoa jossa 2537 lisäystä ja 724 poistoa
  1. 9 0
      .hbuilderx/launch.json
  2. 0 1
      common/icon-map.ts
  3. 10 6
      components/CustomBottomNav.uvue
  4. 59 51
      components/u-floating/u-floating.vue
  5. 33 33
      components/u-icon/u-icon.vue
  6. 84 134
      components/u-switch/u-switch.vue
  7. 12 0
      pages.json
  8. 272 0
      pages/console/setOrderTime.uvue
  9. 523 46
      pages/index/account.uvue
  10. 217 201
      pages/index/console.uvue
  11. 563 43
      pages/index/my.uvue
  12. 258 208
      pages/index/order.uvue
  13. 496 0
      pages/login/login.uvue
  14. BIN
      static/icons/1首页.png
  15. BIN
      static/imagesInfo/bg-color.png
  16. BIN
      static/testInfo/corner.png
  17. BIN
      static/testInfo/demo.png
  18. 1 1
      uni.scss
  19. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772434718197.kotlin_module
  20. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772434816268.kotlin_module
  21. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772435670955.kotlin_module
  22. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772435680645.kotlin_module
  23. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772435695927.kotlin_module
  24. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772435721710.kotlin_module
  25. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772435728190.kotlin_module
  26. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772435741634.kotlin_module
  27. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772435749122.kotlin_module
  28. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772435755062.kotlin_module
  29. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772435796134.kotlin_module
  30. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772435906415.kotlin_module
  31. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772435911332.kotlin_module
  32. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772435920488.kotlin_module
  33. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772435948598.kotlin_module
  34. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772435963188.kotlin_module
  35. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772435985011.kotlin_module
  36. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772436001848.kotlin_module
  37. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772436009596.kotlin_module
  38. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772436037214.kotlin_module
  39. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772436043926.kotlin_module
  40. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772436242749.kotlin_module
  41. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772436244390.kotlin_module
  42. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772436272312.kotlin_module
  43. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772436302892.kotlin_module
  44. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772436319354.kotlin_module
  45. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772436344676.kotlin_module
  46. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772436361284.kotlin_module
  47. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772436733800.kotlin_module
  48. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772437610570.kotlin_module
  49. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772437705447.kotlin_module
  50. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772437836165.kotlin_module
  51. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772437973296.kotlin_module
  52. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772438151611.kotlin_module
  53. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772438156947.kotlin_module
  54. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772440202111.kotlin_module
  55. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772440529303.kotlin_module
  56. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772440532467.kotlin_module
  57. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772441493825.kotlin_module
  58. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772441588196.kotlin_module
  59. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772441633868.kotlin_module
  60. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772441687059.kotlin_module
  61. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772441832109.kotlin_module
  62. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772442451647.kotlin_module
  63. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772442516524.kotlin_module
  64. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772442569539.kotlin_module
  65. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772442638337.kotlin_module
  66. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772442721256.kotlin_module
  67. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772442758637.kotlin_module
  68. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772442844375.kotlin_module
  69. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772443394650.kotlin_module
  70. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772443417537.kotlin_module
  71. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772443424598.kotlin_module
  72. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772443680217.kotlin_module
  73. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772443803263.kotlin_module
  74. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772443825886.kotlin_module
  75. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772443835362.kotlin_module
  76. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772443849693.kotlin_module
  77. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772443899993.kotlin_module
  78. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772443922738.kotlin_module
  79. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772443929290.kotlin_module
  80. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772443956932.kotlin_module
  81. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772443973209.kotlin_module
  82. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772444474875.kotlin_module
  83. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772445200251.kotlin_module
  84. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772445327427.kotlin_module
  85. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772446342807.kotlin_module
  86. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772447952898.kotlin_module
  87. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772500095554.kotlin_module
  88. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772500864715.kotlin_module
  89. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772501258196.kotlin_module
  90. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772501263533.kotlin_module
  91. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772501584342.kotlin_module
  92. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772501758323.kotlin_module
  93. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772502004975.kotlin_module
  94. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772502185181.kotlin_module
  95. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772502332541.kotlin_module
  96. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772502355210.kotlin_module
  97. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772502518489.kotlin_module
  98. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772502592501.kotlin_module
  99. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772505204120.kotlin_module
  100. BIN
      unpackage/cache/.app-android/class/META-INF/main-1772506283108.kotlin_module

+ 9 - 0
.hbuilderx/launch.json

@@ -0,0 +1,9 @@
+{
+    "version" : "1.0",
+    "configurations" : [
+        {
+            "playground" : "standard",
+            "type" : "uni-app:app-android"
+        }
+    ]
+}

+ 0 - 1
common/icon-map.ts

@@ -2,7 +2,6 @@
 // 由脚本自动生成,请勿手动修改
 export const iconMap = {
   "alipay": "/static/icons/alipay.svg",
-  "arrow_down (1)": "/static/icons/arrow_down (1).svg",
   "arrow_down": "/static/icons/arrow_down.svg",
   "arrow_left": "/static/icons/arrow_left.svg",
   "arrow_right": "/static/icons/arrow_right.svg",

+ 10 - 6
components/CustomBottomNav.uvue

@@ -1,10 +1,13 @@
 <template>
 	<view class="bottom-nav">
-		    <!-- 底座(可加背景色或阴影) -->
-		    <view class="tabbar-platform"></view>
+		<!-- 底座(可加背景色或阴影) -->
+		<view class="tabbar-platform">
+		</view>
 		<view v-for="(item, index) in tabs" :key="index" class="nav-item" :class="{ active: currentIndex === index }"
-			@click="handleClick(index)">
-			<text class="nav-text">{{ item.text }}</text>
+		@click="handleClick(index)">
+			<text class="nav-text">
+				{{ item.text }}
+			</text>
 		</view>
 	</view>
 </template>
@@ -60,7 +63,7 @@
 		justify-content: space-around;
 		align-items: flex-end;
 		padding: 10rpx 0 ;
-		
+
 		z-index: 1;
 	}
 
@@ -68,7 +71,8 @@
 	.nav-item {
 		width: 80rpx;
 		height: 80rpx;
-		border-radius: 50%;
+		border-radius: 40rpx;
+		/* half of width to make circle */
 		display: flex;
 		justify-content: center;
 		align-items: center;

+ 59 - 51
components/u-floating/u-floating.vue

@@ -1,57 +1,65 @@
 <template>
-    <view class="floating-button" :style="{ top: top + 'px', left: left + 'px' }" @touchstart="onTouchStart"
-        @touchmove="onTouchMove" @touchend="onTouchEnd">
-        <text class="textIcon icon-jingwuicon_svg-" style="font-size: 60rpx;color: #FF4D4D;"></text>
-    </view>
+	<view class="floating-button" :style="{ top: top + 'px', left: left + 'px' }" @touchstart="onTouchStart"
+		@touchmove="onTouchMove" @touchend="onTouchEnd">
+		<text class="textIcon icon-jingwuicon_svg-" style="font-size: 60rpx;color: #FF4D4D;"></text>
+	</view>
 </template>
 
-<script>
-export default {
-    name: 'FloatingButton',
-    data() {
-        return {
-            top: 430,
-            left: 20,
-            startX: 0,
-            startY: 0,
-            dragging: false
-        };
-    },
-    methods: {
-        onTouchStart(event) {
-            this.startX = event.touches[0].clientX;
-            this.startY = event.touches[0].clientY;
-            this.dragging = true;
-        },
-        onTouchMove(event) {
-            if (this.dragging) {
-                const deltaX = event.touches[0].clientX - this.startX;
-                const deltaY = event.touches[0].clientY - this.startY;
-                this.startX = event.touches[0].clientX;
-                this.startY = event.touches[0].clientY;
-                this.top += deltaY;
-                this.left += deltaX;
-            }
-        },
-        onTouchEnd() {
-            this.dragging = false;
-        }
-    }
-};
+<script lang="uts">
+	type TouchItem = {
+		clientX : number
+		clientY : number
+	}
+	type TouchEvent = {
+		touches : Array<TouchItem>
+	}
+	export default {
+		name: 'FloatingButton',
+		data() {
+			return {
+				top: 430,
+				left: 20,
+				startX: 0,
+				startY: 0,
+				dragging: false
+			};
+		},
+		methods: {
+			onTouchStart(event : TouchEvent) {
+				this.startX = event.touches[0].clientX
+				this.startY = event.touches[0].clientY
+				this.dragging = true
+			},
+			onTouchMove(event : TouchEvent) {
+				if (this.dragging) {
+					const deltaX = event.touches[0].clientX - this.startX
+					const deltaY = event.touches[0].clientY - this.startY
+					this.startX = event.touches[0].clientX
+					this.startY = event.touches[0].clientY
+					this.top += deltaY
+					this.left += deltaX
+				}
+			},
+			onTouchEnd() {
+				this.dragging = false
+			}
+		}
+	}
 </script>
 
 <style scoped>
-.floating-button {
-    position: fixed;
-    z-index: 9999;
-    background-color: #fff;
-    padding: 10px;
-    border-radius: 50%;
-    width: 70rpx;
-    height: 70rpx;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
-}
-</style>
+	.floating-button {
+		position: fixed;
+		z-index: 9999;
+		background-color: #fff;
+		padding: 20rpx; /* converted from 10px */
+		/* use explicit half of width to create perfect circle in rpx */
+		border-radius: 35rpx;
+		width: 70rpx;
+		height: 70rpx;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		box-shadow: 0 4rpx 10rpx rgba(0, 0, 0, 0.3);
+	}
+</style>

+ 33 - 33
components/u-icon/u-icon.vue

@@ -1,42 +1,42 @@
 <template>
-  <image
-    :src="resolvedSrc"
-    :style="{ width: size + 'px', height: size + 'px' }"
-    mode="aspectFit"
-    @click="handleClick"
-  />
+	<image class="u-icon-img" :src="resolvedSrc" :style="{ width: (size??0) + 'px', height: (size??0) + 'px' }"
+		mode="aspectFit" @click="handleClick" />
 </template>
 
 <script lang="uts">
-  import { iconMap } from '@/common/icon-map';
+	import { iconMap } from '@/common/icon-map';
 
-  export default {
-    props: {
-      name: String,
-      src: String,
-      size: Number,
-      active: Boolean
-    },
-    computed: {
-      resolvedSrc(): string {
-        if (this.src) return this.src;
-        if (this.name) {
-          const key = this.active ? `${this.name}-active` : this.name;
-          return iconMap[key] || iconMap[this.name] || '';
-        }
-        return '';
-      }
-    },
-    methods: {
-      handleClick() {
-        this.$emit('click');
-      }
-    }
-  };
+	export default {
+		props: {
+			name: String,
+			src: String,
+			size: Number,
+			active: Boolean
+		},
+		computed: {
+			resolvedSrc() : string {
+				if (this.src != null) return this.src;
+				if (this.name != null) {
+					const key = (this.active == true ? `${this.name}-active` : this.name) as string;
+					const iconFromKey = iconMap[key] as string | null;
+					if (iconFromKey != null) return iconFromKey;
+					const iconFromName = iconMap[this.name] as string | null;
+					if (iconFromName != null) return iconFromName;
+					return '';
+				}
+				return '';
+			}
+		},
+		methods: {
+			handleClick() {
+				this.$emit('click');
+			}
+		}
+	};
 </script>
 
 <style>
-image {
-  display: block;
-}
+	.u-icon-img {
+		/* display: block; */
+	}
 </style>

+ 84 - 134
components/u-switch/u-switch.vue

@@ -1,46 +1,61 @@
 <template>
-	<view class="container" @click="toggleSwitch">
-		<label :class="isOn ? 'switch-checked' : 'switch-nochecked'">
-			<view class="open">{{ activeText }}</view>
-			<view class="close">{{ inactiveText }}</view>
-		</label>
-	</view>
+  <view class="container" @click="toggleSwitch">
+    <view :class="['switch', isOn ? 'switch-checked' : 'switch-nochecked']">
+      <!-- background handled by switch itself -->
+      <view
+        class="switch-handle"
+        :style="isOn ? 'left: 0;' : 'right: 0;'"
+      ></view>
+      <text v-if="isOn">{{ activeText }}</text>
+      <text v-else>{{ inactiveText }}</text>
+    </view>
+  </view>
 </template>
 
 <script setup>
 	import {
-		ref,
-		watch,
+	ref,
+	watch,
 	} from 'vue';
 
 	const props = defineProps({
-		value: {
-			type: Boolean,
-			default: false
-		},
-		activeText: {
-			type: String,
-			default: '已上线'
-		},
-		inactiveText: {
-			type: String,
-			default: '已下线'
-		},
-		activeValue: {
-			type: [Number, String, Boolean],
-			default: true
-		},
-		inactiveValue: {
-			type: [Number, String, Boolean],
-			default: false
-		},
-	});
+			value: {
+				type: Boolean,
+				default: false
+			},
+			activeText: {
+				type: String,
+				default: '已上线'
+			},
+			inactiveText: {
+				type: String,
+				default: '已下线'
+			},
+			activeValue: {
+				type: [Number,
+					String,
+				Boolean],
+				default: true
+			},
+			inactiveValue: {
+				type: [Number,
+					String,
+				Boolean],
+				default: false
+			},
+		});
 
 	const emit = defineEmits(['update:value', 'change']);
 
 	const isOn = ref(props.value);
-	watch(() => props.value, (newVal) => {
-		isOn.value = newVal;
+	
+	// keep `isOn` in sync when prop changes using watchEffect to avoid
+	// generics/return-type confusion in UTS.
+	watchEffect(() => {
+		const v = props.value;
+		if (v != null) {
+			isOn.value = v as boolean;
+		}
 	});
 
 	const toggleSwitch = () => {
@@ -51,107 +66,42 @@
 </script>
 
 <style lang="scss" scoped>
-	.container {
-		width: 156rpx;
-		padding: 10rpx;
-
-		label {
-			position: relative;
-			display: block;
-			border-radius: 40rpx;
-			width: 100%;
-
-			&:before {
-				content: " ";
-				display: block;
-				border-radius: 50rpx;
-				height: 50rpx;
-				background-color: #d5d5d5;
-				transform: scale(1, 1);
-				transition: all 0.3s ease;
-			}
-
-			&:after {
-				content: "";
-				position: absolute;
-				top: 3rpx;
-				left: 0;
-				width: 44rpx;
-				height: 44rpx;
-				border-radius: 50%;
-				background: #fff;
-				border: 2rpx solid #e0e0e0;
-				box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.12);
-				transition: all 0.3s cubic-bezier(.4, 0, .2, 1);
-				z-index: 2;
-			}
-		}
-
-		%font-style {
-			top: 0;
-			color: #ffffff;
-			font-size: 28rpx;
-			height: 100%;
-			line-height: 50rpx;
-			position: absolute;
-			transition: all 1s ease;
-		}
-
-		.switch-checked {
-			&:after {
-				left: unset;
-				right: 5rpx;
-				top: 1.5rpx;
-				border: 2rpx solid #FFDA59;
-			}
-
-			&:before {
-				background-color: #FFDA59;
-			}
-
-			.close {
-				display: none;
-			}
-		}
-
-		.switch-nochecked {
-			&:before {
-				background-color: #d5d5d5;
-			}
-
-			&:after {
-				left: 5rpx;
-				top: 1.5rpx;
-				border: 2rpx solid #d5d5d5;
-			}
-
-			.open {
-				display: none;
-			}
-		}
-
-		.open {
-			left: 20rpx;
-			@extend %font-style;
-			font-size: 26rpx;
-			color: #56441B;
-			display: flex;
-			align-items: center;
-			height: 56rpx;
-			position: absolute;
-			top: 0;
-		}
-
-		.close {
-			right: 20rpx;
-			@extend %font-style;
-			font-size: 26rpx;
-			color: #56441B;
-			display: flex;
-			align-items: center;
-			height: 56rpx;
-			position: absolute;
-			top: 0;
-		}
-	}
+.container {
+  width: 156rpx;
+}
+
+.switch {
+  position: relative;
+  width: 156rpx; /* match container */
+  height: 50rpx;
+  border-radius: 40rpx;
+  background-color: #d5d5d5;
+  transition: background-color 0.3s ease;
+  text-align: center;
+  align-items: center;
+  justify-content: center;
+}
+
+.switch-handle {
+  position: absolute;
+  top: 3rpx;
+  //   left: 3rpx;
+  width: 44rpx;
+  height: 44rpx;
+  border-radius: 22rpx; /* half of 44rpx handle to make it circular */
+  background: #fff;
+  border: 2rpx solid #e0e0e0;
+  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.12);
+  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.switch-checked {
+  background-color: #ffda59;
+}
+.switch-nochecked {
+  background-color: #d5d5d5;
+}
+.switch-checked .switch-handle {
+  left: 109rpx; /* moved to other side */
+}
 </style>

+ 12 - 0
pages.json

@@ -23,6 +23,18 @@
 			"style": {
 				"navigationBarTitleText": "账户"
 			}
+		},
+		{
+			"path": "pages/console/setOrderTime",
+			"style": {
+				"navigationBarTitleText": "接单时间"
+			}
+		},
+		{
+			"path": "pages/login/login",
+			"style": {
+				"navigationBarTitleText": ""
+			}
 		}
 	],
 

+ 272 - 0
pages/console/setOrderTime.uvue

@@ -0,0 +1,272 @@
+<!-- 设置时间 -->
+<template>
+	<view class="body" :style="'padding-top:' + bottomHeight">
+		<view style="width: 100%;height: 48rpx;"></view>
+		<view class="head-box" @click="allTime">全部可接单</view>
+		<scroll-view scroll-y="true" class="list">
+			<view class="ss-flex-2 div-time-flag-box">
+				<view :class="item?.isSelect ? 'conter-xz' : 'conter-xx'" v-for="item in timeArr"
+					@click.stop="chooseTime(item)" :key="item.start_time">
+					<view :class="item?.isSelect ? 'kjd-time' : 'xx-time'">{{ item.start_time }}</view>
+					<view :class="item?.isSelect ? 'kjd-text' : 'xx-text'">{{ item?.isSelect ? '可接单' : '休息' }}</view>
+				</view>
+			</view>
+		</scroll-view>
+		<view class="save-box" @click="handleSave">保存设置</view>
+	</view>
+</template>
+<script setup>
+	import {
+		ref
+	} from 'vue';
+	import {
+		onShow
+	} from '@dcloudio/uni-app';
+	//接口
+	import workbenchesInfoApi from '@/sheep/api/masterProject/workbenches';
+
+	const allIndex = ref(1)
+	const timeArr = ref(Array.from({ length: 48 }, (_, i) => ({
+		start_time: `${Math.floor(i / 2) < 10 ? '0' : ''}${Math.floor(i / 2)}:${i % 2 === 0 ? '00' : '30'}`,
+		end_time: `${Math.floor((i + 1) / 2) < 10 ? '0' : ''}${Math.floor((i + 1) / 2)}:${(i + 1) % 2 === 0 ? '00' : '30'}`,
+		isSelect: false
+	})))
+	onShow(() => {
+		allIndex.value = 1
+		getCoachTime()
+	})
+	//获取技师的时间设置
+	const getCoachTime = async () => {
+		// 先全部置为未选中
+		timeArr.value.forEach(item => item.isSelect = false);
+
+		const res = await workbenchesInfoApi.getWorkTimeSetting();
+		const timeRanges = res.data?.time_ranges || [];
+
+		// 全部可接单
+		if (
+			timeRanges.length === 1 &&
+			timeRanges[0].start_time === '00:00' &&
+			timeRanges[0].end_time === '24:00'
+		) {
+			allTime();
+			return;
+		}
+
+		// 遍历所有时间段,判断是否在任一 time_range 内
+		timeArr.value.forEach(item => {
+			const itemTime = item.start_time;
+			for (const range of timeRanges) {
+				if (
+					compareTime(itemTime, range.start_time) >= 0 &&
+					compareTime(itemTime, range.end_time) < 0
+				) {
+					item.isSelect = true;
+					break;
+				}
+			}
+		});
+	};
+
+	// 时间字符串比较函数,返回 1/0/-1
+	function compareTime(t1, t2) {
+		// t1, t2: "09:00"
+		const [h1, m1] = t1.split(':').map(Number);
+		const [h2, m2] = t2.split(':').map(Number);
+		if (h1 > h2) return 1;
+		if (h1 < h2) return -1;
+		if (m1 > m2) return 1;
+		if (m1 < m2) return -1;
+		return 0;
+	}
+
+	//点击单个时间
+	const chooseTime = async (item) => {
+		if (item.isSelect) {
+			item.isSelect = false
+		} else {
+			item.isSelect = true
+		}
+	}
+	//全部可接单
+	const allTime = async () => {
+		timeArr.value.forEach(item => {
+			item.isSelect = true;
+		});
+		allIndex.value = 2
+	}
+	/**
+	 * 保存排班设置
+	 * @returns {Promise<void>}
+	 */
+	const handleSave = async () => {
+		//获取可接单时间段
+		const kjTime = []
+		for (let i = 0; i < timeArr.value.length; i++) {
+			const item = timeArr.value[i]
+			if (item?.isSelect) {
+				kjTime.push(item)
+			}
+		}
+		if (kjTime.length === 0) {
+			uni.showToast({
+				title: '请至少选择一个可接单时间段',
+				icon: 'none',
+				duration: 2000
+			})
+			return
+		}
+
+		try {
+			const scheduleData = {
+				time_ranges: kjTime.filter(range => range.isSelect).map(range => ({
+					start_time: range.start_time,
+					end_time: range.end_time
+				}))
+			};
+			await workbenchesInfoApi.editWorkTimeSetting(scheduleData);
+			uni.showToast({
+				title: '保存成功',
+				icon: 'success',
+				duration: 2000
+			});
+			setTimeout(() => {
+				uni.reLaunch({
+					url: '/pages/masterProject/homePage/index'
+				})
+			}, 2300);
+
+		} catch (error) {
+			uni.showToast({
+				title: '保存失败,请重试',
+				icon: 'none'
+			});
+		}
+	};
+
+	const bottomHeight = ref('0rpx');
+	// #ifdef APP-PlUS
+	//获取顶部安全距离
+	const app = uni.getSystemInfoSync();
+	const bottomHeightOne = app.statusBarHeight + 'rpx';
+	bottomHeight.value = bottomHeightOne
+	// #endif
+</script>
+<style scoped lang="scss">
+	//设置时间样式
+	.head-box {
+		width: 184rpx;
+		height: 66rpx;
+		line-height: 66rpx;
+		text-align: center;
+		border-radius: 16rpx;
+		background-color: #FFDA59;
+		color: #3D444E;
+		font-size: 28rpx;
+		font-weight: 550;
+		letter-spacing: 3rpx;
+		margin-left: 32rpx;
+		box-sizing: border-box;
+	}
+
+
+	.div-time-flag-box {
+		width: 96%;
+		margin-left: 3%;
+		flex-wrap: wrap;
+		box-sizing: border-box;
+	}
+
+	.conter-xz {
+		width: 158rpx;
+		height: 90rpx;
+		background-color: #FFFBEF;
+		border: 2rpx solid #FFDB5F;
+		border-radius: 16rpx;
+		margin-bottom: 22rpx;
+		margin-right: 22rpx;
+		box-sizing: border-box;
+	}
+
+	.kjd-time {
+		font-size: 28rpx;
+		color: #3A3330;
+		font-weight: 500;
+		margin-top: 10rpx;
+		text-align: center;
+	}
+
+	.kjd-text {
+		font-size: 26rpx;
+		color: #3A3330;
+		font-weight: 500;
+		letter-spacing: 2rpx;
+		text-align: center;
+	}
+
+	.conter-xx {
+		width: 158rpx;
+		height: 94rpx;
+		background-color: #F3F3F3;
+		border-radius: 16rpx;
+		margin-bottom: 22rpx;
+		margin-right: 22rpx;
+		box-sizing: border-box;
+	}
+
+	.xx-time {
+		font-size: 28rpx;
+		color: #9B9B9B;
+		margin-top: 10rpx;
+		text-align: center;
+	}
+
+	.xx-text {
+		font-size: 26rpx;
+		color: #9B9B9B;
+		letter-spacing: 2rpx;
+		text-align: center;
+	}
+
+	.save-box {
+		position: absolute;
+		bottom: 30rpx;
+		left: 0;
+		width: 78%;
+		margin-left: 11%;
+		height: 100rpx;
+		line-height: 100rpx;
+		text-align: center;
+		background-color: #FFDA59;
+		border-radius: 24rpx;
+		font-size: 34rpx;
+		color: #3A3330;
+		font-weight: 550;
+		letter-spacing: 3rpx;
+		box-sizing: border-box;
+	}
+
+	//old样式
+	.icon-navigation {
+		font-size: 32rpx;
+		color: #3D444E;
+		font-weight: 700;
+	}
+
+	// 上中下布局样式
+	// .body {
+	//     position: relative;
+	//     width: 100vw;
+	//     height: 100vh;
+	//     background-color: #FFFFFF;
+	//     box-sizing: border-box;
+	// }
+
+	.list {
+		position: absolute;
+		top: 180rpx;
+		left: 0;
+		bottom: 150rpx;
+		box-sizing: border-box;
+	}
+</style>

+ 523 - 46
pages/index/account.uvue

@@ -1,52 +1,529 @@
 <template>
-  <view class="page">
-    <view class="content">当前页面:{{ currentTabName }}</view>
-
-    <!-- 自定义底部导航 -->
-    <CustomBottomNav 
-      :current-index="currentTab" 
-      @change="onTabChange" 
-    />
-  </view>
+	<view class="page-container">
+
+		<!-- 1. 资产卡片区域 -->
+		<view class="asset-card">
+			<!-- 总资产 -->
+			<view class="total-asset-section row-between">
+				<text class="label">
+					我的资产(元)
+				</text>
+				<view class="amount-row row-start">
+					<!-- 修复:确保 totalAsset 已定义 -->
+					<text class="amount">
+						{{ totalAsset }}
+					</text>
+					<u-icon type="eye" size="20" color="#333">
+					</u-icon>
+				</view>
+				<!-- 修复:确保 refreshData 已定义 -->
+				<view class="refresh-btn row-center" @click="refreshData">
+					<u-icon type="refresh" size="18" color="#333">
+					</u-icon>
+					<text>
+						刷新
+					</text>
+				</view>
+			</view>
+
+			<!-- 累计收益 & 打车费 -->
+			<view class="income-section row-start">
+				<!-- 左侧:累计收益 -->
+				<view class="income-item column">
+					<view class="income-header row-start">
+						<text class="income-label">
+							累计收益(元)
+						</text>
+						<u-icon type="help" size="16" color="#999">
+						</u-icon>
+					</view>
+					<view class="income-main row-between">
+						<!-- 修复:确保 cumulativeIncome 已定义 -->
+						<text class="income-value">
+							{{ cumulativeIncome }}
+						</text>
+						<!-- 修复:确保 handleWithdraw 已定义 -->
+						<view class="withdraw-btn" @click="handleWithdraw('income')">
+							提现
+						</view>
+					</view>
+					<view class="income-detail row-start">
+						<view class="detail-item column-center">
+							<text class="detail-label">
+								冻结(元)
+							</text>
+							<!-- 修复:确保 frozenIncome 已定义 -->
+							<text class="detail-value">
+								{{ frozenIncome }}
+							</text>
+						</view>
+						<view class="divider">
+						</view>
+						<view class="detail-item column-center">
+							<text class="detail-label">
+								可提现(元)
+							</text>
+							<text class="detail-value highlight">
+								{{ availableIncome }}
+							</text>
+						</view>
+					</view>
+				</view>
+
+				<!-- 右侧:打车费 -->
+				<view class="income-item column">
+					<view class="income-header row-start">
+						<text class="income-label">
+							打车费(元)
+						</text>
+						<u-icon type="help" size="16" color="#999">
+						</u-icon>
+					</view>
+					<view class="income-main row-between">
+						<text class="income-value">
+							{{ taxiFee }}
+						</text>
+						<view class="transfer-btn" @click="handleTransfer('taxi')">
+							转出
+						</view>
+					</view>
+					<view class="income-detail row-start">
+						<view class="detail-item column-center">
+							<text class="detail-label">
+								冻结(元)
+							</text>
+							<text class="detail-value">
+								{{ frozenTaxi }}
+							</text>
+						</view>
+						<view class="divider">
+						</view>
+						<view class="detail-item column-center">
+							<text class="detail-label">
+								可使用(元)
+							</text>
+							<text class="detail-value highlight">
+								{{ availableTaxi }}
+							</text>
+						</view>
+					</view>
+				</view>
+			</view>
+
+			<!-- 提现记录入口 -->
+			<view class="record-entry row-between" @click="viewWithdrawRecords">
+				<text>
+					提现记录
+				</text>
+				<u-icon type="arrowright" size="16" color="#999">
+				</u-icon>
+			</view>
+		</view>
+
+		<!-- 2. 本月账单标题 -->
+		<view class="bill-header row-between">
+			<text class="bill-title">
+				本月账单
+			</text>
+			<text class="view-all" @click="viewAllBills">
+				查看全部
+			</text>
+		</view>
+
+		<!-- 3. 账单列表 -->
+		<view class="bill-list column">
+			<view v-for="(bill, idx) in bills" :key="idx" class="bill-card column">
+
+				<!-- 订单号行 -->
+				<view class="order-id-row row-between">
+					<text class="order-id">
+						订单号:{{ bill.orderId }}
+					</text>
+					<u-icon type="arrowright" size="16" color="#999">
+					</u-icon>
+				</view>
+
+				<!-- 项目与金额 -->
+				<view class="project-amount-row row-between">
+					<text class="project-name">
+						{{ bill.projectName }}
+					</text>
+					<text :class="['amount', bill.amount > 0 ? 'positive' : 'negative']">
+						{{ bill.amount > 0 ? '+' : '' }}{{ Math.abs(bill.amount).toFixed(2) }}
+						</text>
+					</view>
+
+					<!-- 分成说明 -->
+					<view class="split-info column">
+						<text class="split-type">
+							{{ bill.splitType }}
+						</text>
+						<text class="split-detail">
+							{{ bill.splitDetail }}
+						</text>
+					</view>
+
+					<!-- 记录时间 -->
+					<view class="time-row row-between">
+						<text class="time-label">
+							记录时间
+						</text>
+						<text class="time-value">
+							{{ bill.recordTime }}
+						</text>
+					</view>
+
+				</view>
+			</view>
+
+		</view>
 </template>
 
-<script setup lang="ts">
-import { ref, computed } from 'vue';
-import CustomBottomNav from '@/components/CustomBottomNav.uvue';
-
-// 当前选中索引
-const currentTab = ref(3);
-
-// 根据索引获取名称(用于演示)
-const tabNames = ['小丁', '理疗', '预约', '商户', '我的'];
-const currentTabName = computed(() => tabNames[currentTab.value]);
-
-// 切换 Tab
-const onTabChange = (index: number) => {
-  currentTab.value = index;
-
-  // 可选:跳转到对应 tabBar 页面
-  const pages = [
-    '/pages/index/index',
-    '/pages/index/therapy',
-    '/pages/index/order',
-    '/pages/index/merchant',
-    '/pages/index/my'
-  ];
-  uni.switchTab({ url: pages[index] });
-};
+<script setup lang="uts">
+	import { ref } from 'vue';
+
+	// --- 数据定义 ---
+	const totalAsset = ref('1978.2');
+	const cumulativeIncome = ref('1889');
+	const frozenIncome = ref('1000');
+	const availableIncome = ref('889');
+	const taxiFee = ref('89.2');
+	const frozenTaxi = ref('50');
+	const availableTaxi = ref('49.2');
+
+	// ✅ 修复点 1: 定义类型 (可以用 interface 或 type)
+	type BillItem = {
+		orderId : string;
+		projectName : string;
+		amount : number;
+		splitType : string;
+		splitDetail : string;
+		recordTime : string;
+	};
+
+	// ✅ 修复点 2: 初始化时不写泛型 <BillItem[]>,让 TS 自动推断
+	// 或者写成: const bills = ref<BillItem[]>([]); 然后单独 push,但直接推断最方便
+	const bills = ref([
+			{
+				orderId: '202506091311123009874638',
+				projectName: '中式推拿',
+				amount: 170.00,
+				splitType: '首单分成',
+				splitDetail: '基本套餐车费收入 x90%=20\n项目套餐收入 x50%=150',
+				recordTime: '2025-06-09 13:58'
+			},
+			{
+				orderId: '202506091311123009874638',
+				projectName: '中式推拿',
+				amount: 150.00,
+				splitType: '加钟分成',
+				splitDetail: '项目套餐收入 x71%+(70%+等级v1)=150',
+				recordTime: '2025-06-09 13:58'
+			},
+			{
+				orderId: '202506091311123009874638',
+				projectName: '中式推拿订单退款',
+				amount: -150.00,
+				splitType: '首单分成',
+				splitDetail: '基本套餐车费收入 x90%=20\n项目套餐收入 x50%=150',
+				recordTime: '2025-06-09 13:58'
+			},
+			{
+				orderId: '',
+				projectName: '打车费转出',
+				amount: -50.00,
+				splitType: '分成',
+				splitDetail: '打车费转出刘大锤账户:45.00元\n费率:0.1 手续费:5.00元',
+				recordTime: '2025-06-09 13:58'
+			}
+		] as BillItem[]); // 如果自动推断不准,可以在末尾加 'as BillItem[]' 进行断言
+
+	// --- 方法定义 ---
+	const refreshData = () => {
+		uni.showLoading({ title: '刷新中...' });
+		setTimeout(() => {
+				uni.hideLoading();
+				uni.showToast({ title: '刷新成功', icon: 'success' });
+				totalAsset.value = (parseFloat(totalAsset.value) + 0.1).toFixed(1);
+			}, 800);
+	};
+
+	const handleWithdraw = (type : string) => {
+		const amount = type === 'income' ? availableIncome.value : '0';
+		uni.showModal({
+				title: '提现确认',
+				content: `确定要提现 ${amount} 元吗?`,
+				success: (res) => {
+					if (res.confirm) {
+						uni.showToast({ title: '提现申请已提交', icon: 'success' });
+					}
+				}
+			});
+	};
+
+	const handleTransfer = (type : string) => {
+		uni.showModal({
+				title: '转出确认',
+				content: '确定要将打车费转出到其他账户吗?',
+				success: (res) => {
+					if (res.confirm) {
+						uni.showToast({ title: '转出成功', icon: 'success' });
+					}
+				}
+			});
+	};
+
+	const viewWithdrawRecords = () => {
+		uni.showToast({ title: '查看提现记录', icon: 'none' });
+	};
+
+	const viewAllBills = () => {
+		uni.showToast({ title: '查看全部账单', icon: 'none' });
+	};
 </script>
 
-<style scoped>
-.page {
-  min-height: 100vh;
-  padding-bottom: 100rpx; /* 防止内容被遮挡 */
-  background-color: #f8f8f8;
-  padding: 20rpx;
-}
-
-.content {
-  font-size: 32rpx;
-  color: #333;
-}
+<style>
+	/*
+	⚠️ UniApp X 样式规范:
+	1. 不写 display: flex (view 默认就是)
+	2. 不写 display: block/inline-block
+	3. 布局靠 flex-direction (默认 column, 需 row 时手动改)
+	4. 不写 border-radius: 50% (用具体数值)
+	5. 只用类名选择器
+	*/
+
+	/* --- 辅助布局类 (核心) --- */
+	.row-between {
+		flex-direction: row;
+		justify-content: space-between;
+		align-items: center;
+	}
+
+	.row-start {
+		flex-direction: row;
+		align-items: center;
+		/* gap: 10rpx; */
+	}
+
+	.row-center {
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+	}
+
+	.column {
+		flex-direction: column;
+	}
+
+	.column-center {
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+	}
+
+	/* --- 页面容器 --- */
+	.page-container {
+		background-color: #f5f6f8;
+		/* min-height: 100vh; */
+		padding-bottom: 40rpx;
+	}
+
+	/* --- 资产卡片 --- */
+	.asset-card {
+		background: linear-gradient(180deg, #fff9e6 0%, #ffeaa7 100%);
+		margin: 20rpx;
+		border-radius: 16rpx;
+		padding: 30rpx;
+		box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
+	}
+
+	.total-asset-section {
+		margin-bottom: 30rpx;
+	}
+
+	.label {
+		font-size: 26rpx;
+		color: #666;
+	}
+
+	.amount-row {
+		/* gap: 10rpx; */
+	}
+
+	.amount {
+		font-size: 48rpx;
+		font-weight: bold;
+		color: #333;
+	}
+
+	.refresh-btn {
+		padding: 10rpx 20rpx;
+		background: #ffffff;
+		border-radius: 30rpx;
+		border: 1rpx solid #ddd;
+		font-size: 24rpx;
+		color: #333;
+	}
+
+	/* 收益分区 */
+	.income-section {
+		/* gap: 30rpx; */
+		margin-bottom: 20rpx;
+	}
+
+	.income-item {
+		flex: 1;
+		/* gap: 15rpx; */
+	}
+
+
+	.income-label {
+		font-size: 24rpx;
+		color: #666;
+	}
+
+	.income-main {
+		/* 继承 row-between */
+	}
+
+	.income-value {
+		font-size: 40rpx;
+		font-weight: bold;
+		color: #333;
+	}
+
+	.withdraw-btn,
+	.transfer-btn {
+		font-size: 24rpx;
+		padding: 8rpx 20rpx;
+		border-radius: 20rpx;
+		background: #ffffff;
+		border: 1rpx solid;
+	}
+
+	.withdraw-btn {
+		color: #ff9900;
+		border-color: #ff9900;
+	}
+
+	.transfer-btn {
+		color: #52c41a;
+		border-color: #52c41a;
+	}
+
+	/* 明细部分 */
+	.income-detail {
+		background: rgba(255, 255, 255, 0.6);
+		border-radius: 12rpx;
+		padding: 15rpx;
+		/* gap: 20rpx; */
+	}
+
+	.detail-item {
+		flex: 1;
+		/* gap: 4rpx; */
+	}
+
+	.detail-label {
+		font-size: 22rpx;
+		color: #999;
+	}
+
+	.detail-value {
+		font-size: 28rpx;
+		font-weight: bold;
+		color: #333;
+	}
+
+	.detail-value.highlight {
+		color: #ff9900;
+	}
+
+	.divider {
+		width: 1rpx;
+		background: #ddd;
+		margin: 0 10rpx;
+	}
+
+	/* 提现记录入口 */
+	.record-entry {
+		padding: 20rpx 0;
+		border-top: 1rpx solid rgba(0, 0, 0, 0.05);
+		font-size: 28rpx;
+		color: #333;
+	}
+
+	/* --- 账单标题 --- */
+	.bill-header {
+		padding: 20rpx 30rpx;
+		margin-top: 20rpx;
+	}
+
+	.bill-title {
+		font-size: 32rpx;
+		font-weight: bold;
+		color: #333;
+	}
+
+	.view-all {
+		font-size: 26rpx;
+		color: #666;
+	}
+
+	/* --- 账单列表 --- */
+	.bill-list {
+		padding: 0 20rpx;
+		/* gap: 20rpx; */
+	}
+
+	.bill-card {
+		background: #ffffff;
+		border-radius: 16rpx;
+		padding: 30rpx;
+		box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
+		/* gap: 15rpx; */
+	}
+
+	.order-id-row {
+		font-size: 26rpx;
+		color: #666;
+	}
+
+	.project-amount-row {
+		/* 继承 row-between */
+	}
+
+	.project-name {
+		font-size: 30rpx;
+		font-weight: bold;
+		color: #333;
+	}
+
+	.amount.positive {
+		color: #ff4d4f;
+		font-size: 32rpx;
+		font-weight: bold;
+	}
+
+	.amount.negative {
+		color: #333;
+		font-size: 32rpx;
+		font-weight: bold;
+	}
+
+	.split-info {
+		font-size: 24rpx;
+		color: #999;
+		line-height: 1.4;
+	}
+
+	.split-type {
+		font-weight: 400;
+		color: #666;
+	}
+
+	.time-row {
+		font-size: 24rpx;
+		color: #999;
+	}
 </style>

+ 217 - 201
pages/index/console.uvue

@@ -1,203 +1,217 @@
 <template>
-	<view class="page">
-		<view class="upContent">
-		</view>
-		<view class="city-info">
-			<view class="city-text-box">
-				<text>
-					当前城市:{{ cityInfo }}
-				</text>
-			</view>
-			<u-icon name="notification" :size="24" />
-		</view>
-		<!-- 用户卡片 -->
-		<view class="user-card ">
-			<image class="user-bg wh" src="@/static/imagesInfo/bg-icon.png" mode="scaleToFill">
+	<scroll-view style="flex:1">
+
+		<view class="page">
+			<image class="upContent" src="@/static/imagesInfo/bg-color.png" mode="aspectFill">
 			</image>
-			<view class="user-info">
-				<view class="user-left">
-					<view class="user-info">
-						<text class="user-name">
-							刘大锤
-						</text>
-						<view class="tags">
-							<text class="tag-new">
-								新人实习
+			<view class="city-info">
+				<view class="city-text-box">
+					<text>
+						当前城市:{{ cityInfo }}
+					</text>
+				</view>
+				<u-icon name="notification" :size="24" />
+			</view>
+			<!-- 用户卡片 -->
+			<view class="user-card ">
+				<image class="user-bg" src="@/static/imagesInfo/bg-icon.png" mode="scaleToFill">
+				</image>
+				<view class="user-info" style="padding: 20rpx;">
+					<view class="user-left">
+						<view class="user-info">
+							<text class="user-name">
+								刘大锤
 							</text>
+							<view class="tags">
+								<text class="tag-new">
+									新人实习
+								</text>
 
+							</view>
+							<u-icon name="edit" :size="18" />
+							<text class="tag">
+								编辑
+							</text>
+						</view>
+						<view class="user-info">
+							<u-icon name="customer-interests" :size="18" />
+							<text class="user-role">
+								小丁理疗师
+							</text>
+							<u-icon name="store" :size="18" />
+							<text class="user-shop">
+								佳人有约
+							</text>
+
+						</view>
+						<view class="online-switch">
+							<u-switch :checked="isOnline" @change="toggleOnline" />
 						</view>
-						<u-icon name="edit" :size="18" />
-						<text class="tag">
-							编辑
-						</text>
 					</view>
-					<view class="user-info">
-						<u-icon name="customer-interests" :size="18" />
-						<text class="user-role">
-							小丁理疗师
+					<view class="user-right">
+						<text class="text-time-box">
+							入驻时间
 						</text>
-						<u-icon name="store" :size="18" />
-						<text class="user-shop">
-							佳人有约
+						<text class="text-time-box" style="margin-top: 5rpx;">2026.03.01{{
+							coachInfo?.created_at.split(' ')[0] }}
 						</text>
-
-					</view>
-					<view class="online-switch">
-						<u-switch :checked="isOnline" @change="toggleOnline" />
+						<image v-if="coachInfo!=null && coachInfo.avatar_url!=null" @click.stop="jumpMasterInfo"
+						:src="coachInfo!.avatar_url!.url"
+						style="width: 138rpx;height:138rpx;border-radius: 69rpx;margin-top: 15rpx;"
+						mode="aspectFit">
+						</image>
+						<image v-else src="/static/testInfo/boy-nickname.png"
+						style="width: 138rpx;height:138rpx;border-radius: 69rpx;margin-top: 15rpx;"
+						mode="aspectFit">
+						</image>
 					</view>
 				</view>
-				<view class="user-right">
 
-					<text class="text-time-box">
-						入驻时间
+				<view class="location-bar user-info">
+					<u-icon name="navigation" :size="18" />
+					<text class="location-text">
+						当前定位:烟台市楚凤一街1号楚凤花园
 					</text>
-					<text class="text-time-box" style="margin-top: 5rpx;">{{
-						coachInfo?.created_at.split(' ')[0] }}
+					<text class="location-btn">
+						手动更新
 					</text>
-					<image v-if="coachInfo?.avatar_url" @click.stop="jumpMasterInfo"
-					:src="coachInfo?.avatar_url?.url"
-					style="width: 138rpx;height:138rpx;border-radius: 50%;margin-top: 15rpx;" mode="aspectFit">
-					</image>
-					<image v-else src="/static/testInfo/boy-nickname.png"
-					style="width: 138rpx;height:138rpx;border-radius: 50%;margin-top: 15rpx;" mode="aspectFit">
-					</image>
 
 				</view>
-			</view>
 
-			<view class="location-bar user-info">
-				<u-icon name="navigation" :size="18" />
-				<text class="location-text">
-					当前定位:烟台市楚凤一街1号楚凤花园
-				</text>
-				<text class="location-btn">
-					手动更新
-				</text>
-
-			</view>
-		</view>
-		<!-- 本月数据 -->
-		<view class="stats-row">
-			<view class="stat-item">
-				<text class="stat-label">
-					本月收益(元)
-				</text>
-				<text class="stat-value">
-					2234.88
-				</text>
 			</view>
-			<view class="stat-divider">
-			</view>
-			<view class="stat-item">
-				<text class="stat-label">
-					本月接单量(单)
-				</text>
-				<text class="stat-value">
-					2234.88
-				</text>
-			</view>
-			<view class="stat-divider">
-			</view>
-			<view class="stat-item">
-				<text class="stat-label">
-					本月退单率
-				</text>
-				<text class="stat-value">
-					30%
-				</text>
-			</view>
-		</view>
-
-		<!-- 功能按钮 -->
-		<view class="func-grid">
-			<view class="func-item" v-for="(item, i) in funcList" :key="i">
-				<view  @click.stop="jumpSetProject">
-					<image style="width: 92rpx;height: 92rpx;" :src="item.iconUrl"
-					mode="aspectFit">
-					</image>
-					<text class="func-label">
-						{{ item.label }}
+			<!-- 本月数据 -->
+			<view class="stats-row">
+				<view class="stat-item">
+					<text class="stat-label">
+						本月收益(元)
+					</text>
+					<text class="stat-value">
+						2234.88
 					</text>
 				</view>
-
-			</view>
-		</view>
-
-		<!-- 数据统计 -->
-		<view class="data-section">
-			<view class="section-header">
-				<text class="section-title">
-					数据统计
-				</text>
-				<text class="section-more">
-					查看全部 >
+				<view class="stat-divider">
+				</view>
+				<view class="stat-item">
+					<text class="stat-label">
+						本月接单量(单)
+					</text>
+					<text class="stat-value">
+						2234.88
 					</text>
 				</view>
-				<view class="data-grid">
-					<view class="data-item" v-for="(item, i) in dataStats" :key="i">
-						<text class="data-value">
-							{{ item.value }}
-						</text>
-						<text class="data-label">
+				<view class="stat-divider">
+				</view>
+				<view class="stat-item">
+					<text class="stat-label">
+						本月退单率
+					</text>
+					<text class="stat-value">
+						30%
+					</text>
+				</view>
+			</view>
+
+			<!-- 功能按钮 -->
+			<view class="func-grid">
+				<view class="func-item" v-for="(item, i) in funcList" :key="i">
+					<view @click.stop="jumpSetProject">
+						<image style="width: 92rpx;height: 92rpx;" :src="item.iconUrl" mode="aspectFit">
+						</image>
+						<text class="func-label">
 							{{ item.label }}
 						</text>
 					</view>
+
 				</view>
 			</view>
 
-			<!-- 客户评价 -->
-			<view class="eval-section">
+			<!-- 数据统计 -->
+			<view class="data-section">
 				<view class="section-header">
 					<text class="section-title">
-						客户评价
+						数据统计
 					</text>
 					<text class="section-more">
 						查看全部 >
 						</text>
 					</view>
-					<view class="eval-tags">
-						<text class="eval-tag" v-for="(tag, i) in evalTags" :key="i">
-							{{ tag.text }} {{ tag.count ? tag.count : '' }}
-						</text>
+					<view class="data-grid">
+						<view class="data-item" v-for="(item, i) in dataStats" :key="i">
+							<text class="data-value">
+								{{ item.value }}
+							</text>
+							<text class="data-label">
+								{{ item.label }}
+							</text>
+						</view>
 					</view>
-					<view class="eval-item">
-						<image class="eval-avatar" src="/static/testInfo/boy-nickname.png" mode="aspectFill" />
-						<view class="eval-content">
-							<view class="eval-top">
-								<text class="eval-name">
-									匿名评价
-								</text>
-								<text class="eval-date">
-									2025-04-24
+				</view>
+
+				<!-- 客户评价 -->
+				<view class="eval-section">
+					<view class="section-header">
+						<text class="section-title">
+							客户评价
+						</text>
+						<text class="section-more">
+							查看全部 >
+							</text>
+						</view>
+						<view class="eval-tags">
+							<text class="eval-tag" v-for="(tag, i) in evalTags" :key="i">
+								{{ tag.text }} {{ tag.count > 0 ? tag.count : '' }}
 								</text>
 							</view>
-							<view class="eval-stars">
-								<text>
-									⭐⭐⭐⭐☆
-								</text>
-								<view class="stat-divider">
+							<view class="eval-item">
+								<image class="eval-avatar" src="/static/testInfo/boy-nickname.png" mode="aspectFill" />
+								<view class="eval-content">
+									<view class="eval-top">
+										<text class="eval-name">
+											匿名评价
+										</text>
+										<text class="eval-date">
+											2025-04-24
+										</text>
+									</view>
+									<view class="eval-stars">
+										<text>
+											⭐⭐⭐⭐☆
+										</text>
+										<view class="stat-divider">
+										</view>
+										<text class="eval-service">
+											泰式松骨
+										</text>
+									</view>
+									<text class="eval-comment">
+										服务到位
+									</text>
 								</view>
-								<text class="eval-service">
-									泰式松骨
-								</text>
 							</view>
-							<text class="eval-comment">
-								服务到位
-							</text>
 						</view>
+						<!-- 做一个悬浮球 -->
+						<u-floating @dblclick="callPolice" />
 					</view>
-				</view>
-				<!-- 做一个悬浮球 -->
-				<u-floating @dblclick="callPolice" />
-			</view>
-
+				</scroll-view>
 </template>
 
-<script setup lang="ts">
+<script setup lang="uts">
 	import { ref, computed } from 'vue';
 	import { colors } from '@/common/theme';
+
 	// 状态
 	const isOnline = ref(true);
+	const cityInfo = ref('')
+	// 头像url类型
+	type AvatarUrl = {
+		url : string
+	}
+	// 技师信息(空对象,字段可为null)
+	type CoachInfo = {
+		created_at : string | null
+		avatar_url : AvatarUrl | null
+	}
+	const coachInfo = ref<CoachInfo | null>(null);
 
 	// 切换上线状态
 	const toggleOnline = () => {
@@ -214,10 +228,21 @@
 		{ iconUrl: '/static/imagesInfo/gengxin-wz.png', label: '位置更新' }
 	];
 
+	// 跳转到技师详情
+	const jumpMasterInfo = () => {
+		console.log('jumpMasterInfo invoked');
+		// 在这里可以执行导航或其他逻辑
+	};
+
 	// 功能按钮点击处理
 	const jumpSetProject = () => {
 		console.log('jumpSetProject invoked');
 		// 在这里可以执行导航或其他逻辑
+		//在起始页面跳转到test.vue页面并传递参数
+		uni.navigateTo({
+				url: 'setOrderTime?id=1&name=uniapp'
+			});
+
 	};
 
 	// 悬浮球双击处理
@@ -235,31 +260,33 @@
 		{ value: '19%', label: '退单率' }
 	];
 
-	// 评价标签
-	const evalTags = [
-		{ text: '不良引导' },
-		{ text: '手法不好', count: 101 },
-		{ text: '性格温柔', count: 198 },
-		{ text: '服务到位', count: 10 }
+	// 评价标签数据
+	// 使用类型别名避免 UTS 对内联对象字面量的限制
+	type EvalTag = { text : string; count : number };
+	const evalTags : EvalTag[] = [
+		{ text: '不良引导', count: 0 },
+	{ text: '手法不好', count: 101 },
+	{ text: '性格温柔', count: 198 },
+	{ text: '服务到位', count: 10 }
 	];
 </script>
 
 <style>
 	.page {
-		min-height: 100vh;
-		background-color: $uni-bg-color-grey;
+		/* width: 100%;
+		commented out because percentage unsupported
+		*/
 		padding: 24rpx;
+
 	}
 
 	.upContent {
-		height: 50%;
-		background-image: linear-gradient(180deg, #FFDA59 0%, rgba(255, 255, 255, 0) 100%);
-		background-repeat: no-repeat;
-		background-size: cover;
+		height: 900rpx;
+		width: 750rpx;
 		position: fixed;
 		top: 0;
 		left: 0;
-		width: 100%;
+		z-index: -1;
 	}
 
 	.city-info {
@@ -270,24 +297,23 @@
 	/* 用户卡片 */
 	.user-card {
 		border-radius: 16rpx;
-		padding: 20rpx;
-		/* 如需更明显的分层可加阴影 */
-		box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
-		height: auto;
-		position: relative;
-		z-index: ;
-		margin-top: 16rpx;
+		/* padding: 20rpx; */
+		/* margin-top: 16rpx; */
 		margin-bottom: 32rpx;
+		box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
 	}
 
 	.user-bg {
 		position: absolute;
-		top: 0;
+		/* top: 0;
 		left: 0;
-		width: 100%;
-		/* object-fit: cover; */
-	}
+		right: 0;
+		bottom: 0;
+		*/
+		right: 0;
+		width: 702rpx
 
+	}
 	.user-info {
 		/* display: flex; */
 		flex-direction: row;
@@ -312,12 +338,10 @@
 		/* 绿色透明度渐变 */
 		background: linear-gradient(180deg, rgba(207, 221, 62, 0.69) 0%, rgba(162, 184, 29, 1) 100%);
 		color: #FFFFFF;
-		width: 160rpx;
-		line-height: 40rpx;
 		border-radius: 24rpx;
-		text-align: center;
-		margin: 0 20rpx;
+		margin: 0 16rpx;
 		font-size: 28rpx;
+		padding:6rpx 12rpx ;
 	}
 
 	.tag-edit {
@@ -332,8 +356,6 @@
 	}
 
 	.online-switch {
-		display: flex;
-		align-items: center;
 		margin-top: 24rpx;
 	}
 
@@ -344,16 +366,9 @@
 	}
 
 	.user-right {
-		display: flex;
-		/* flex-direction: column; */
 		align-items: center;
-		/* position: absolute; */
 		width: 180rpx;
 		height: 245rpx;
-		/* top: 0;
-		right: 20rpx;
-		*/
-		/* text-align: center; */
 		z-index: 1;
 		margin-right: 14rpx;
 	}
@@ -379,7 +394,8 @@
 	.avatar {
 		width: 120rpx;
 		height: 120rpx;
-		border-radius: 50%;
+		border-radius: 60rpx;
+		/* half of width/height */
 		border: 4rpx solid #FFFFFF;
 	}
 
@@ -387,7 +403,7 @@
 		display: flex;
 		align-items: center;
 		background-image: linear-gradient(to right, #FFF9E1 0%, #FFF1BF 100%);
-		padding: 10rpx;
+		padding: 10rpx 20rpx;
 		border-radius: 18rpx;
 		margin-top: 30rpx;
 		font-size: 24rpx;
@@ -417,7 +433,7 @@
 	.stats-row {
 		display: flex;
 		flex-direction: row;
-		width: 100%;
+		/* width: 100%; removed percentage, flex children will stretch */
 		text-align: center;
 		background-color: #FFFFFF;
 		margin-bottom: 32rpx;
@@ -434,7 +450,7 @@
 	.stat-label {
 		font-size: 26rpx;
 		color: #999999;
-		display: block;
+		/* display: block not supported; default inline behavior is fine */
 		margin-bottom: 24rpx;
 		text-align: center;
 	}
@@ -495,7 +511,7 @@
 
 	.section-title {
 		font-size: 32rpx;
-		font-weight: 500;
+		font-weight: 400;
 		color: #333333;
 	}
 
@@ -518,7 +534,7 @@
 		font-size: 36rpx;
 		font-weight: bold;
 		color: #333333;
-		display: block;
+		/* display property not needed */
 		margin-bottom: 8rpx;
 	}
 
@@ -540,7 +556,7 @@
 		display: flex;
 		/* flex-wrap: wrap; */
 		flex-direction: row;
-		gap: 16rpx;
+		/* gap: 16rpx; */
 		margin-bottom: 32rpx;
 	}
 
@@ -554,14 +570,14 @@
 
 	.eval-item {
 		/* display: flex; */
-		gap: 24rpx;
+		/* gap: 24rpx; */
 		flex-direction: row;
 	}
 
 	.eval-avatar {
 		width: 80rpx;
 		height: 80rpx;
-		border-radius: 50%;
+		border-radius: 40rpx;
 	}
 
 	.eval-content {
@@ -577,7 +593,7 @@
 
 	.eval-name {
 		/* font-size: 28rpx; */
-		font-weight: 500;
+		font-weight: 400;
 		color: #333333;
 	}
 
@@ -604,4 +620,4 @@
 		font-size: 26rpx;
 		color: #333333;
 	}
-</style>
+</style>

+ 563 - 43
pages/index/my.uvue

@@ -1,52 +1,572 @@
 <template>
-  <view class="page">
-    <view class="content">当前页面:{{ currentTabName }}</view>
-
-    <!-- 自定义底部导航 -->
-    <CustomBottomNav 
-      :current-index="currentTab" 
-      @change="onTabChange" 
-    />
+  <view class="page-container">
+
+    <!-- 1. 用户信息头部 -->
+    <view class="user-header">
+      <image :src="userInfo['avatar']" class="avatar" mode="aspectFill" />
+      <view class="user-info">
+        <text class="username">
+          {{ userInfo['name'] }}
+        </text>
+        <view class="badge-row">
+          <text class="badge vip">
+            王牌
+          </text>
+        </view>
+      </view>
+      <view class="header-actions">
+        <view class="action-item" @click="contactService">
+          <u-icon type="customer-service" size="24" color="#666">
+          </u-icon>
+          <text>
+            客服
+          </text>
+        </view>
+        <view class="action-item" @click="openSettings">
+          <u-icon type="gear" size="24" color="#666">
+          </u-icon>
+          <text>
+            设置
+          </text>
+        </view>
+      </view>
+    </view>
+
+    <!-- 2. 等级卡片 -->
+    <view class="level-card">
+      <view class="level-main">
+        <text class="level-title">
+          V{{ userInfo['level'] }}
+        </text>
+        <text class="level-sub">
+          成长值 {{ userInfo['growthValue'] }}
+        </text>
+      </view>
+      <view class="level-progress">
+        <text class="progress-text">
+          还差{{ userInfo['nextLevelGap'] }}成长值可升至V{{ userInfo['nextLevel'] }}
+        </text>
+        <view class="progress-bar">
+          <view class="progress-fill" :style="{ width: progressWidth }">
+          </view>
+        </view>
+        <view class="progress-labels">
+          <text>
+            V1
+          </text>
+          <text>
+            V2
+          </text>
+        </view>
+      </view>
+      <view class="level-badge" @click="viewLevelDetail">
+        <u-icon type="vip" size="40" color="#ffffff">
+        </u-icon>
+        <text>
+          我的等级
+        </text>
+      </view>
+    </view>
+
+    <!-- 3. 我的档案 -->
+    <view class="section-title">
+      我的档案
+    </view>
+    <view class="profile-stats">
+      <view class="stat-item">
+        <text class="stat-value">
+          60
+        </text>
+        <text class="stat-label">
+          签约
+        </text>
+      </view>
+      <view class="stat-item">
+        <text class="stat-value">
+          21
+        </text>
+        <text class="stat-label">
+          解约
+        </text>
+      </view>
+      <view class="stat-item">
+        <u-icon type="location" size="24" color="#666">
+        </u-icon>
+        <text class="stat-label">
+          异地签到
+        </text>
+      </view>
+      <view class="stat-item">
+        <u-icon type="cart" size="24" color="#666">
+        </u-icon>
+        <text class="stat-label">
+          购买物料
+        </text>
+      </view>
+    </view>
+
+    <!-- 4. 我的工具 -->
+    <view class="section-title">
+      我的工具
+    </view>
+    <view class="tools-grid">
+      <view class="tool-item" v-for="(tool, idx) in tools" :key="idx" @click="handleToolClick(tool)">
+        <u-icon :type="tool.icon" size="32" :color="tool.color">
+        </u-icon>
+        <text class="tool-name">
+          {{ tool.name }}
+        </text>
+      </view>
+    </view>
+
+    <!-- 5. 推广卡片 -->
+    <view class="promo-cards">
+      <!-- 邀请好友 -->
+      <view class="promo-card invite" @click="inviteFriends">
+        <view class="promo-content">
+          <text class="promo-title">
+            邀请好友赚钱
+          </text>
+          <text class="promo-subtitle">
+            单次最高可奖200元
+          </text>
+        </view>
+        <u-icon type="gift" size="40" color="#ffd700">
+        </u-icon>
+      </view>
+
+      <!-- 我的团队 -->
+      <view class="promo-card team" @click="viewTeam">
+        <view class="promo-content">
+          <text class="promo-title">
+            我的团队
+          </text>
+          <text class="promo-subtitle">
+            团队成员100人
+          </text>
+        </view>
+        <u-icon type="person" size="40" color="#4a90e2">
+        </u-icon>
+      </view>
+    </view>
+
+    <!-- 6. 城市合伙人 banner -->
+    <view class="partner-banner" @click="joinPartner">
+      <view class="partner-content">
+        <text class="partner-title">
+          寻找城市合伙人
+        </text>
+        <text class="partner-subtitle">
+          全新盈利模式助你创业
+        </text>
+      </view>
+      <view class="partner-icon">
+        <u-icon type="person" size="50" color="#ffffff">
+        </u-icon>
+        <u-icon type="person" size="30" color="#ffffff" style="margin-left: -20rpx;">
+        </u-icon>
+      </view>
+    </view>
+
   </view>
 </template>
 
 <script setup lang="ts">
-import { ref, computed } from 'vue';
-import CustomBottomNav from '@/components/CustomBottomNav.uvue';
-
-// 当前选中索引
-const currentTab = ref(3);
-
-// 根据索引获取名称(用于演示)
-const tabNames = ['小丁', '理疗', '预约', '商户', '我的'];
-const currentTabName = computed(() => tabNames[currentTab.value]);
-
-// 切换 Tab
-const onTabChange = (index: number) => {
-  currentTab.value = index;
-
-  // 可选:跳转到对应 tabBar 页面
-  const pages = [
-    '/pages/index/index',
-    '/pages/index/therapy',
-    '/pages/index/order',
-    '/pages/index/merchant',
-    '/pages/index/my'
-  ];
-  uni.switchTab({ url: pages[index] });
-};
+  import { ref, reactive } from 'vue';
+
+  // --- 用户信息 ---
+
+	type UserInfo = {
+		name : string;
+		avatar : string;
+		level : number;
+		growthValue : number;
+		nextLevel : number;
+		nextLevelGap : number;
+		progressPercent : number;
+	}
+  const userInfo = reactive<UserInfo>({
+      name: '刘大锤',
+      avatar: 'https://via.placeholder.com/100x100/4a90e2/ffffff?text=LD', // 替换为实际头像
+      level: 30,
+      growthValue: 50,
+      nextLevel: 2,
+      nextLevelGap: 15,
+      progressPercent: 75 // (50 / (50+15)) * 100 ≈ 75%
+    });
+
+  // computed helpers to satisfy UTS inference rules
+  // convert percent to a fixed rpx width (assuming 750rpx full width)
+  const progressWidth = computed(() => `${userInfo.progressPercent * 7.5}rpx`);
+
+  // --- 工具列表 ---
+
+	type ToolItem = {
+		name : string;
+		icon : string;
+		color : string;
+	};
+
+  // avoid generic parameter on ref which earlier triggered an "interface does not
+  // have constructors" error; cast the initial value instead.
+  const tools = ref([
+      { name: '学习园地', icon: 'book', color: '#ff9900' },
+      { name: '问题反馈', icon: 'chat', color: '#52c41a' },
+      { name: '定制优惠', icon: 'wallet', color: '#1890ff' },
+      { name: 'VIP俱乐部', icon: 'vip', color: '#faad14' }
+    ] as ToolItem[]);
+
+  // --- 方法 ---
+  const contactService = () => {
+    uni.showToast({ title: '联系客服', icon: 'none' });
+  };
+
+  const openSettings = () => {
+    uni.showToast({ title: '打开设置', icon: 'none' });
+  };
+
+  const viewLevelDetail = () => {
+    uni.showToast({ title: '查看等级详情', icon: 'none' });
+  };
+
+  const handleToolClick = (tool : ToolItem) => {
+    uni.showToast({ title: `点击${tool.name}`, icon: 'none' });
+  };
+
+  const inviteFriends = () => {
+    uni.showModal({
+        title: '邀请好友',
+        content: '分享链接邀请好友加入,单次最高可获奖励200元!',
+        success: (res) => {
+          if (res.confirm) {
+            uni.showToast({ title: '已生成邀请链接', icon: 'success' });
+          }
+        }
+      });
+  };
+
+  const viewTeam = () => {
+    uni.showToast({ title: '查看团队成员', icon: 'none' });
+  };
+
+  const joinPartner = () => {
+    uni.showModal({
+        title: '城市合伙人',
+        content: '全新盈利模式助你创业,立即申请成为城市合伙人!',
+        success: (res) => {
+          if (res.confirm) {
+            uni.showToast({ title: '申请已提交', icon: 'success' });
+          }
+        }
+      });
+  };
 </script>
 
 <style scoped>
-.page {
-  min-height: 100vh;
-  padding-bottom: 100rpx; /* 防止内容被遮挡 */
-  background-color: #f8f8f8;
-  padding: 20rpx;
-}
-
-.content {
-  font-size: 32rpx;
-  color: #333;
-}
+  /*
+  UniApp X 默认 page 是 flex-direction: column
+  所以 .page-container 会自动垂直排列子元素
+  */
+
+  .page-container {
+    background-color: #f5f6f8;
+    /* min-height: 100vh unsupported */
+    min-height: 1000rpx;
+    /* width: 100%; default block behavior */
+    box-sizing: border-box;
+    padding: 20rpx;
+    /* gap: 20rpx; */
+    /* 各模块间间距 */
+  }
+
+  /* --- 用户头部 --- */
+  .user-header {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    /* gap: 20rpx; */
+    padding: 20rpx;
+    background: #ffffff;
+    border-radius: 16rpx;
+    box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
+  }
+
+  .avatar {
+    width: 100rpx;
+    height: 100rpx;
+    border-radius: 50rpx;
+    border: 2rpx solid #eee;
+  }
+
+  .user-info {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    /*  */
+  }
+
+  .username {
+    font-size: 32rpx;
+    font-weight: bold;
+    color: #333;
+  }
+
+  .badge-row {
+    display: flex;
+    flex-direction: row;
+    /* gap: 10rpx; */
+  }
+
+  .badge {
+    font-size: 22rpx;
+    padding: 4rpx 12rpx;
+    border-radius: 20rpx;
+    font-weight: bold;
+  }
+
+  .badge.vip {
+    background: linear-gradient(90deg, #4a90e2, #67b26f);
+    color: #ffffff;
+  }
+
+  .header-actions {
+    display: flex;
+    flex-direction: row;
+    /* gap: 30rpx; */
+  }
+
+  .action-item {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    /* gap: 4rpx; unsupported */
+    font-size: 22rpx;
+    color: #666;
+  }
+
+  /* --- 等级卡片 --- */
+  .level-card {
+    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+    border-radius: 16rpx;
+    padding: 30rpx;
+    color: #ffffff;
+    position: relative;
+    overflow: hidden;
+  }
+
+  .level-main {
+    display: flex;
+    flex-direction: row;
+    align-items: flex-start;
+    /* baseline unsupported */
+    /* gap: 15rpx; not supported by uvue */
+    margin-bottom: 20rpx;
+  }
+
+  .level-title {
+    font-size: 48rpx;
+    font-weight: bold;
+  }
+
+  .level-sub {
+    font-size: 28rpx;
+    opacity: 0.9;
+  }
+
+  .level-progress {
+    margin-bottom: 20rpx;
+  }
+
+  .progress-text {
+    font-size: 24rpx;
+    opacity: 0.8;
+    margin-bottom: 10rpx;
+    /* display:block removed; inline text is fine */
+  }
+
+  .progress-bar {
+    /* width: 100%; */
+    /* 全宽默认,无需指定百分比 */
+    height: 12rpx;
+    background: rgba(255, 255, 255, 0.3);
+    border-radius: 6rpx;
+    overflow: hidden;
+    margin-bottom: 8rpx;
+  }
+
+  .progress-fill {
+    /* 使用与父容器相同的固定高度 */
+    height: 12rpx;
+    background: #ffffff;
+    border-radius: 6rpx;
+    transition: width 0.3s ease;
+  }
+
+  .progress-labels {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    font-size: 22rpx;
+    opacity: 0.7;
+  }
+
+  .level-badge {
+    position: absolute;
+    top: 20rpx;
+    right: 20rpx;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    /*  */
+    font-size: 24rpx;
+    opacity: 0.9;
+  }
+
+  /* --- 章节标题 --- */
+  .section-title {
+    font-size: 30rpx;
+    font-weight: bold;
+    color: #333;
+    margin-top: 10rpx;
+    margin-bottom: 15rpx;
+    padding-left: 10rpx;
+    border-left: 4rpx solid #4a90e2;
+  }
+
+  /* --- 档案统计 --- */
+  .profile-stats {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-around;
+    background: #ffffff;
+    border-radius: 16rpx;
+    padding: 30rpx 20rpx;
+    box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
+  }
+
+  .stat-item {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+
+  }
+
+  .stat-value {
+    font-size: 32rpx;
+    font-weight: bold;
+    color: #333;
+  }
+
+  .stat-label {
+    font-size: 24rpx;
+    color: #666;
+  }
+
+  /* --- 工具网格 --- */
+  .tools-grid {
+    display: flex;
+    flex-direction: row;
+    flex-wrap: wrap;
+    /* gap: 20rpx; */
+    background: #ffffff;
+    border-radius: 16rpx;
+    padding: 30rpx;
+    box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
+  }
+
+  .tool-item {
+    /* width: calc(25% - 15rpx); not supported */
+    width: 168rpx;
+    /* approximate quarter width */
+    /* 4列,减去gap */
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    /* gap: 10rpx; */
+    padding: 20rpx 0;
+  }
+
+  .tool-name {
+    font-size: 24rpx;
+    color: #666;
+    text-align: center;
+  }
+
+  /* --- 推广卡片 --- */
+  .promo-cards {
+    display: flex;
+    flex-direction: row;
+    /* gap: 20rpx; */
+  }
+
+  .promo-card {
+    flex: 1;
+    border-radius: 16rpx;
+    padding: 25rpx;
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
+  }
+
+  .promo-card.invite {
+    background: linear-gradient(135deg, #fff9e6 0%, #ffeaa7 100%);
+  }
+
+  .promo-card.team {
+    background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
+  }
+
+  .promo-content {
+    display: flex;
+    flex-direction: column;
+    /*  */
+  }
+
+  .promo-title {
+    font-size: 28rpx;
+    font-weight: bold;
+    color: #333;
+  }
+
+  .promo-subtitle {
+    font-size: 24rpx;
+    color: #666;
+  }
+
+  /* --- 合伙人 Banner --- */
+  .partner-banner {
+    background: linear-gradient(135deg, #ff9a9e 0%, #fad0c4 100%);
+    border-radius: 16rpx;
+    padding: 30rpx;
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    color: #ffffff;
+    box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
+  }
+
+  .partner-content {
+    display: flex;
+    flex-direction: column;
+    /* gap: 10rpx; */
+  }
+
+  .partner-title {
+    font-size: 32rpx;
+    font-weight: bold;
+  }
+
+  .partner-subtitle {
+    font-size: 26rpx;
+    opacity: 0.9;
+  }
+
+  .partner-icon {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+  }
 </style>

+ 258 - 208
pages/index/order.uvue

@@ -1,64 +1,68 @@
 <template>
-  <view class="container">
-    <!-- 状态标签页 (顶部) -->
-    <scroll-view scroll-x class="tab-bar" show-scrollbar="false">
-      <view
-      v-for="(tab, index) in tabs"
-      :key="index"
-      :class="['tab-item', { active: currentTab === index }]"
-      @click="currentTab = index"
-      >
-        {{ tab }}
-        <!-- 仅在新订单下显示黄色下划线 -->
-        <view v-if="index === 0" class="underline">
+  <view class="page-container">
+
+    <!-- 1. 顶部标签栏 (Scroll View) -->
+    <scroll-view scroll-x class="tab-scroll" show-scrollbar="false" :enable-flex="true">
+      <view class="tab-wrapper">
+        <view v-for="(tab, index) in tabs" :key="index"
+        :class="['tab-item', currentTab === index ? 'active' : '']" @click="currentTab = index">
+          <text>
+            {{ tab }}
+          </text>
+          <!-- 激活下的黄色短线 -->
+          <view v-if="currentTab === index" class="tab-indicator">
+          </view>
         </view>
       </view>
     </scroll-view>
 
-    <!-- 订单列表区域 -->
+    <!-- 2. 订单列表 -->
     <view class="order-list">
-      <view v-for="(order, idx) in orders" :key="idx" class="order-card">
+      <view v-for="(order, idx) in orders" :key="order['id']" class="order-card">
 
-        <!-- 1. 头部:时间与状态 -->
+        <!-- Card Header: 时间 & 状态 -->
         <view class="card-header">
           <text class="time-text">
-            预约时间:{{ order.time }}
+            预约时间:{{ order['time'] }}
           </text>
-          <text class="status-tag paid">
+          <text class="status-badge paid">
             已支付
           </text>
         </view>
 
-        <!-- 2. 服务信息行 -->
-        <view class="service-row">
-          <image :src="order.image" class="service-img" mode="aspectFill" />
-          <view class="service-info">
-            <view class="title-row">
+        <!-- Card Body: 服务信息 (左图右文) -->
+        <view class="service-section">
+          <image :src="order['image']" class="service-image" mode="aspectFill" />
+          <view class="service-details">
+            <view class="service-title-row">
               <text class="service-name">
-                {{ order.serviceName }}
+                {{ order['serviceName'] }}
               </text>
-              <text class="price">
-                ¥{{ order.price }}
+              <text v-for="(tag, tIdx) in tagList(order)" :key="tIdx" :class="['tag-pill', tag.type]">
+                {{ tag.text }}
               </text>
+
             </view>
+            <view class="contact-info-row">
+              <text class="contact-info">
+                联系人:{{ order['contact'] }}
+              </text>
 
-            <view class="tags-row">
-              <text v-for="(tag, tIdx) in order.tags" :key="tIdx" :class="['tag', tag.type]">
-                {{ tag.text }}
+              <text class="tag-pill green ">
+                新客
               </text>
-            </view>
 
-            <text class="contact-text">
-              联系人:{{ order.contact }}
-            </text>
+            </view>
           </view>
+          <text class="service-price">
+            ¥{{ order.price }}
+          </text>
         </view>
-
-        <!-- 3. 地址与距离 -->
-        <view class="address-row">
-          <uni-icons type="location" size="16" color="#999">
-          </uni-icons>
-          <text class="address-text">
+        <!-- Card Address: 地址 & 距离 -->
+        <view class="address-section">
+          <u-icon type="location" size="16" color="#999999">
+          </u-icon>
+          <text class="address-content">
             {{ order.address }}
           </text>
           <text class="distance-text">
@@ -66,45 +70,37 @@
           </text>
         </view>
 
-        <!-- 4. 预估收入 -->
+        <!-- Card Income: 预估收入 -->
         <view class="income-section">
           <text class="income-label">
             预估收入
           </text>
-          <view class="income-value-box">
-            <text class="income-value">
+          <view class="income-value-group">
+            <text class="income-main">
               ¥{{ order.income }}
             </text>
-            <text class="income-note">
+            <text class="income-sub">
               (含路费)
             </text>
           </view>
         </view>
 
-        <!-- 5. 底部操作按钮 -->
-        <view class="action-buttons">
-          <view class="btn btn-nav" @click="handleNav(order.address)">
-            <uni-icons type="navigation" size="14" color="#333">
-            </uni-icons>
+        <!-- Card Actions: 按钮组 -->
+        <view class="action-section">
+          <view class="btn btn-nav" @click="onNavigate(order.address)">
+            <u-icon type="navigation" size="14" color="#333333">
+            </u-icon>
             <text>
               地址导航
             </text>
           </view>
-          <view class="btn btn-transfer" @click="handleTransfer(order.id)">
+          <text class="btn btn-transfer" @click="onTransfer(order.id)">
             我要转单
-          </view>
-          <view class="btn btn-confirm" @click="handleConfirm(order.id)">
+          </text>
+          <text class="btn btn-confirm" @click="onConfirm(order.id)">
             确认接单
-          </view>
+          </text>
         </view>
-
-      </view>
-
-      <!-- 空状态提示 (可选) -->
-      <view v-if="orders.length === 0" class="empty-state">
-        <text>
-          暂无相关订单
-        </text>
       </view>
     </view>
   </view>
@@ -113,7 +109,7 @@
 <script setup lang="ts">
   import { ref } from 'vue';
 
-  // --- 数据定义 ---
+  // --- 数据 ---
   const tabs = ['新订单',
     '进行中',
     '取消/售后',
@@ -121,101 +117,125 @@
   '全部'];
   const currentTab = ref(0);
 
-  // 模拟订单数据
-  const orders = ref([
-      {
-        id: 101,
-        time: '2025-06-18 4:00',
-        serviceName: '润养SPA',
-        tags: [
-          { text: '上门', type: 'orange-outline' },
-          { text: '首单', type: 'orange-outline' },
-          { text: '新客', type: 'green-outline' }
-        ],
-        contact: '刘',
-        price: '286.6',
-        address: '烟台 芝罘区楚风一街楚凤花园(烟台吾悦)广场附近',
-        distance: '2.24',
-        income: '186.6',
-        // 请替换为实际图片路径,或使用占位图
-        image: 'https://via.placeholder.com/100x100/ffccaa/ffffff?text=SPA'
-      },
-      {
-        id: 102,
-        time: '2025-06-18 8:00',
-        serviceName: '润养SPA',
-        tags: [
-          { text: '加钟', type: 'green-outline' }
-        ],
-        contact: '刘',
-        price: '286.6',
-        address: '烟台 芝罘区楚风一街楚凤花园(烟台吾悦)广场附近',
-        distance: '2.24',
-        income: '186.6',
-        image: 'https://via.placeholder.com/100x100/ffccaa/ffffff?text=SPA'
-      }
-    ]);
-
-  // --- 事件处理 ---
-  const handleNav = (address: string) => {
-    uni.showToast({ title: '打开地图导航', icon: 'none' });
-    // 实际逻辑: uni.openLocation(...)
+	type OrderTag = {
+		text : string;
+		type : 'orange' | 'green' | 'red';
+	}
+
+	type OrderItem = {
+		id : number;
+		time : string;
+		serviceName : string;
+		tags : OrderTag[];
+		contact : string;
+		price : string;
+		address : string;
+		distance : string;
+		income : string;
+		image : string;
+	};
+
+  // orders data – no need for reactivity, use a plain typed array
+  const orders : OrderItem[] = [
+    {
+      id: 1,
+      time: '2025-06-18 4:00',
+      serviceName: '润养SPA',
+      tags: [
+        { text: '上门', type: 'orange' } as OrderTag,
+        { text: '首单', type: 'orange' } as OrderTag,
+      ],
+      contact: '刘',
+      price: '286.6',
+      address: '烟台 芝罘区楚风一街楚凤花园(烟台吾悦)广场附近',
+      distance: '2.24',
+      income: '186.6',
+      image: '/static/testInfo/demo.png'
+    },
+    {
+      id: 2,
+      time: '2025-06-18 8:00',
+      serviceName: '润养SPA',
+      tags: [
+        { text: '加钟', type: 'red' } as OrderTag
+      ],
+      contact: '刘',
+      price: '286.6',
+      address: '烟台 芝罘区楚风一街楚凤花园(烟台吾悦)广场附近',
+      distance: '2.24',
+      income: '186.6',
+      image: '/static/testInfo/demo.png'
+    }
+  ] as OrderItem[];
+
+  // --- 方法 ---
+  const onNavigate = (addr : string) => {
+    uni.showToast({ title: '启动导航', icon: 'none' });
   };
 
-  const handleTransfer = (id: number) => {
+  // helper used in template to give v-for a typed array source
+  function tagList(order: OrderItem): OrderTag[] {
+    return order.tags;
+  }
+
+  const onTransfer = (id : number) => {
     uni.showModal({
-        title: '提示',
-        content: '确定要转单吗?',
+        title: '转单确认',
+        content: '确定将此订单转给其他技师吗?',
         success: (res) => {
-          if (res.confirm) {
-            uni.showToast({ title: '转单成功', icon: 'success' });
-          }
+          if (res.confirm) uni.showToast({ title: '转单成功', icon: 'success' });
         }
       });
   };
 
-  const handleConfirm = (id: number) => {
-    uni.showLoading({ title: '接单中...' });
+  const onConfirm = (id : number) => {
+    uni.showLoading({ title: '处理中...' });
     setTimeout(() => {
         uni.hideLoading();
         uni.showToast({ title: '接单成功', icon: 'success' });
-      }, 800);
+      }, 600);
   };
 </script>
 
 <style scoped>
-  /* 容器:去掉上下 padding,让内容贴边或根据父容器决定 */
-  .container {
+  .page-container {
     background-color: #f5f6f8;
-    /* 浅灰背景 */
-    min-height: 100vh;
-    width: 100%;
+    /* min-height: 100vh; unsupported by uvue, replace with fixed value or remove */
+    min-height: 1000rpx;
+    /* width: 100%; */ /* 默认块级元素已撑满父容器 */
+    /* 确保内部元素不溢出 */
+    box-sizing: border-box;
   }
 
-  /* --- 标签栏样式 --- */
-  .tab-bar {
-    width: 100%;
-    white-space: nowrap;
+  /* --- Tab 区域 --- */
+  .tab-scroll {
+    /* width: 100%; */ /* 不使用百分比 */
     background-color: #ffffff;
-    padding: 0 20rpx;
-    box-sizing: border-box;
-    /* 去掉滚动条 */
-    scrollbar-width: none;
+    /* 固定高度或自适应 */
+    height: 88rpx;
   }
-  /* 兼容 H5/APP 隐藏滚动条 */
-  .tab-bar ::v-deep(.uni-scroll-view::-webkit-scrollbar) {
-    display: none;
-    width: 0;
-    height: 0;
+
+  .tab-wrapper {
+    display: flex;
+    /* 内部横向排列 */
+    flex-direction: row;
+    align-items: center;
+    /* 直接使用固定高度匹配 .tab-scroll */
+    height: 88rpx;
+    padding: 0 20rpx;
+    white-space: nowrap;
   }
 
   .tab-item {
-    display: inline-block;
-    padding: 24rpx 30rpx;
+    position: relative;
+    padding: 0 30rpx;
+    /* 高度与容器一致,避免百分比 */
+    height: 88rpx;
+    display: flex;
+    align-items: center;
+    justify-content: center;
     font-size: 30rpx;
     color: #666666;
-    position: relative;
-    margin-right: 10rpx;
   }
 
   .tab-item.active {
@@ -223,231 +243,261 @@
     font-weight: bold;
   }
 
-  .underline {
+  .tab-indicator {
     position: absolute;
-    bottom: 10rpx;
-    left: 50%;
-    transform: translateX(-50%);
+    bottom: 16rpx;
+    left: 0;
+    right: 0;
+    margin: 0 auto;
     width: 40rpx;
     height: 6rpx;
     background-color: #ffc107;
-    /* 黄色下划线 */
     border-radius: 3rpx;
   }
 
-  /* --- 订单列表 --- */
+  /* --- 列表区域 --- */
   .order-list {
     padding: 20rpx;
-    box-sizing: border-box;
-
+    /* 垂直排列卡片 */
+    display: flex;
+    flex-direction: column;
+    /* gap: 20rpx; */
   }
 
   .order-card {
     background-color: #ffffff;
     border-radius: 16rpx;
     padding: 30rpx;
-    margin-bottom: 24rpx;
-    box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
-    flex-direction: row;
+    /* 卡片内部也是垂直流 */
+    display: flex;
+    flex-direction: column;
+    /* gap: 20rpx; */
   }
 
   /* 1. 头部 */
   .card-header {
     display: flex;
+    flex-direction: row;
+    /* 左右布局 */
     justify-content: space-between;
     align-items: center;
-    margin-bottom: 24rpx;
   }
 
   .time-text {
     font-size: 28rpx;
-    color: #333;
-    font-weight: 500;
+    color: #333333;
+    font-weight: 400;
+    /* use supported weight */
   }
 
-  .status-tag {
+  .status-badge {
     font-size: 24rpx;
     padding: 6rpx 16rpx;
     border-radius: 20rpx;
   }
-  .status-tag.paid {
+
+  .status-badge.paid {
     background-color: #fff7e6;
     color: #ff9900;
   }
 
-  /* 2. 服务信息 */
-  .service-row {
+  /* 2. 服务信息 (左图右文) */
+  .service-section {
     display: flex;
+    flex-direction: row;
+    /* 关键:横向排列图和文 */
     align-items: flex-start;
-    margin-bottom: 20rpx;
+    /* gap: 20rpx; */
   }
 
-  .service-img {
+  .service-image {
     width: 110rpx;
     height: 110rpx;
     border-radius: 12rpx;
-    margin-right: 20rpx;
-    background-color: #eee;
+    background-color: #f0f0f0;
+    flex-shrink: 0;
+    /* 防止图片被压缩 */
   }
 
-  .service-info {
+  .service-details {
     flex: 1;
     display: flex;
-    flex-direction: column;
+    /* flex-direction: column; */
+    /* 文字内部垂直排列 */
     justify-content: space-between;
-    height: 110rpx;
+    /* height: 110rpx; */
+
   }
 
-  .title-row {
+  .service-title-row {
     display: flex;
-    justify-content: space-between;
+    flex-direction: row;
+    /* justify-content: space-between; */
     align-items: center;
   }
 
   .service-name {
     font-size: 32rpx;
     font-weight: bold;
-    color: #333;
+    color: #333333;
   }
 
-  .price {
+  .service-price {
     font-size: 34rpx;
     font-weight: bold;
-    color: #333;
+    color: #333333;
   }
 
-  .tags-row {
+  .tags-container {
     display: flex;
-    gap: 12rpx;
+    flex-direction: row;
+    /* gap: 12rpx; */
     flex-wrap: wrap;
   }
 
-  .tag {
+  .tag-pill {
     font-size: 22rpx;
     padding: 4rpx 12rpx;
     border-radius: 20rpx;
-    border: 1rpx solid;
+    border-width: 1rpx;
+    border-style: solid;
     line-height: 1.2;
   }
 
-  /* 标签颜色变体 */
-  .tag.orange-outline {
+  .tag-pill.orange {
     color: #ff9900;
     border-color: #ff9900;
     background-color: #fffaf0;
   }
-  .tag.green-outline {
+
+  .tag-pill.green {
     color: #52c41a;
     border-color: #52c41a;
     background-color: #f6ffed;
   }
 
-  .contact-text {
+  .tag-pill.red {
+    color: #ff4d4f;
+    border-color: #ff4d4f;
+    background-color: #fff1f0;
+  }
+
+  .contact-info-row {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    /* gap: 20rpx; */
+  }
+
+  .contact-info {
     font-size: 26rpx;
-    color: #999;
+    color: #999999;
   }
 
-  /* 3. 地址行 */
-  .address-row {
+  /* 3. 地址 */
+  .address-section {
     display: flex;
+    flex-direction: row;
     align-items: flex-start;
-    margin-bottom: 20rpx;
     padding-bottom: 20rpx;
-    border-bottom: 1rpx solid #f5f5f5;
+    border-bottom-width: 1rpx;
+    border-bottom-color: #f5f5f5;
+    border-bottom-style: solid;
+    /* gap: 10rpx; */
   }
 
-  .address-text {
+  .address-content {
     flex: 1;
     font-size: 26rpx;
-    color: #666;
-    margin-left: 10rpx;
+    color: #666666;
     line-height: 1.4;
-    /* 多行省略 */
-    display: -webkit-box;
+    /* multi-line ellipsis removed; not supported by uvue */
+    /* display: -webkit-box;
     -webkit-line-clamp: 2;
     -webkit-box-orient: vertical;
     overflow: hidden;
+    */
   }
 
   .distance-text {
     font-size: 24rpx;
-    color: #999;
-    margin-left: 10rpx;
+    color: #999999;
     white-space: nowrap;
+    margin-left: 10rpx;
   }
 
-  /* 4. 收入区域 */
+  /* 4. 收入 */
   .income-section {
     display: flex;
+    flex-direction: row;
     justify-content: space-between;
     align-items: center;
-    margin-bottom: 24rpx;
   }
 
   .income-label {
     font-size: 28rpx;
-    color: #666;
+    color: #666666;
   }
 
-  .income-value-box {
+  .income-value-group {
     display: flex;
-    align-items: baseline;
+    flex-direction: row;
+    align-items: center;
+    /* baseline not supported */
+    /*  */
   }
 
-  .income-value {
+  .income-main {
     font-size: 36rpx;
     font-weight: bold;
     color: #ff4d4f;
-    /* 红色金额 */
-    margin-right: 8rpx;
   }
 
-  .income-note {
+  .income-sub {
     font-size: 24rpx;
-    color: #999;
+    color: #999999;
   }
 
   /* 5. 按钮组 */
-  .action-buttons {
+  .action-section {
     display: flex;
+    flex-direction: row;
     justify-content: space-between;
-    gap: 20rpx;
+    /* gap: 20rpx; */
   }
 
   .btn {
     flex: 1;
     height: 72rpx;
+    border-radius: 36rpx;
+    font-size: 28rpx;
+    font-weight: 400;
     display: flex;
+    flex-direction: row;
+    /* 按钮内图标和文字横向 */
     justify-content: center;
     align-items: center;
-    border-radius: 36rpx;
-    font-size: 28rpx;
-    font-weight: 500;
+    /*  */
   }
 
   .btn-nav {
     background-color: #f5f5f5;
-    color: #333;
-    gap: 8rpx;
+    color: #333333;
   }
 
   .btn-transfer {
     background-color: #ffffff;
     color: #ff9900;
-    border: 1rpx solid #ff9900;
+    border-width: 1rpx;
+    border-color: #ff9900;
+    border-style: solid;
   }
 
   .btn-confirm {
     background-color: #ffc107;
-    /* 黄色实心 */
-    color: #333;
-    border: 1rpx solid #ffc107;
-  }
-
-  .empty-state {
-    text-align: center;
-    padding: 100rpx 0;
-    color: #999;
-    font-size: 28rpx;
+    color: #333333;
+    border-width: 1rpx;
+    border-color: #ffc107;
+    border-style: solid;
   }
 </style>

+ 496 - 0
pages/login/login.uvue

@@ -0,0 +1,496 @@
+<template>
+	<view class="page-container">
+		<view class="close-btn" @click="goBack">
+			<uni-icons type="closeempty" size="24" color="#333">
+			</uni-icons>
+		</view>
+
+		<view class="header-section">
+			<text class="hello-text">
+				Hello!
+			</text>
+			<text class="welcome-text">
+				欢迎来到小丁到家
+			</text>
+			<image src="/static/logo-massage.png" class="logo-img" mode="aspectFit">
+			</image>
+		</view>
+
+		<view class="form-section">
+			<view class="input-box">
+				<input class="input-field" type="number" placeholder="请输入手机号码" v-model="phone" maxlength="11" />
+			</view>
+
+			<view class="input-box row-between">
+				<input class="input-field" type="number" placeholder="请输入验证码" v-model="code" maxlength="6" />
+				<text class="code-btn" :class="{ disabled: !canSend }" @click="sendCode">
+					{{ codeText }}
+				</text>
+			</view>
+
+			<view class="login-btn" :class="{ disabled: !canLogin }" @click="doLogin">
+				登录
+			</view>
+
+			<view class="agree-row row-start">
+				<checkbox :checked="isAgree" @change="onAgreeChange" style="transform: scale(0.8);" />
+				<view class="agree-content">
+					<text class="agree-text">
+						我已阅读并同意
+						<text class="link-text">
+							《用户协议》
+						</text>
+						<text class="link-text">
+							《隐私政策》
+						</text>
+						<text class="link-text">
+							《上门按摩服务行业平台公约》
+						</text>
+						,未注册的手机号将自动创建小丁到家账号
+					</text>
+				</view>
+			</view>
+		</view>
+
+		<view class="footer-section">
+			<view class="divider-row row-center">
+				<view class="line">
+				</view>
+				<text class="divider-text">
+					其他登录方式
+				</text>
+				<view class="line">
+				</view>
+			</view>
+			<view class="methods-row row-center">
+				<view class="method-item column-center" @click="oneKeyNav">
+					<view class="icon-box blue-bg">
+						<uni-icons type="checkmark" size="20" color="#fff">
+						</uni-icons>
+					</view>
+					<text class="method-name">
+						一键登录
+					</text>
+				</view>
+				<view class="method-item column-center" @click="wechatLogin">
+					<view class="icon-box green-bg">
+						<uni-icons type="weixin" size="20" color="#fff"></uni-icons>
+					</view>
+					<text class="method-name">
+						微信登录
+					</text>
+				</view>
+			</view>
+		</view>
+
+		<view v-if="showModal" class="modal-mask" @click="showModal=false">
+			<view class="modal-box" @click.stop>
+				<text class="modal-title">
+					服务协议及隐私政策
+				</text>
+
+				<scroll-view scroll-y class="modal-scroll">
+					<text class="modal-welcome">
+						欢迎您使用小丁到家!
+					</text>
+					<text class="modal-desc">
+						请你务必审慎阅读、并充分理解
+						<text class="modal-link">
+							《用户协议》
+						</text>
+						和
+						<text class="modal-link">
+							《隐私政策》
+						</text>
+						,协议内容包括但不限于:
+					</text>
+					<text class="modal-list">
+						1、在您使用软件及服务的过程中,向您提供相关基本功能,我们将根据合法、正当、必要的原则,收集或使用必要的个人信息;
+					</text>
+					<text class="modal-list">
+						2、基于您的授权,我们可能会获取您的地理位置、相册、相机等相关软件权限;
+					</text>
+					<text class="modal-list">
+						3、我们会采取符合标准的技术措施和数据安全措施来保护您的个人信息安全;
+					</text>
+					<text class="modal-list">
+						4、您可以查询,更正,管理您的个人信息,我们也提供账户注销的渠道;
+					</text>
+					<text class="modal-footer">
+						如您同意以上协议内容,请点击“同意”开始使用我们的产品和服务,我们依法尽全力保护您的个人信息。
+					</text>
+				</scroll-view>
+
+				<view class="modal-btns row-between">
+					<text class="modal-btn reject" @click="rejectAgreement">
+						拒绝并退出
+					</text>
+					<text class="modal-btn agree" @click="agreeAgreement">
+						同意
+					</text>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script setup lang="uts">
+	import { ref, computed } from 'vue';
+
+	const phone = ref<string>('');
+	const code = ref<string>('');
+	const isAgree = ref<boolean>(false);
+	const showModal = ref<boolean>(false);
+	const countdown = ref<number>(0);
+
+	// 定义定时器变量
+	let timer : number | null = null;
+
+	const canSend = computed(() => phone.value.length === 11 && countdown.value === 0);
+	const canLogin = computed(() => phone.value.length === 11 && code.value.length === 6 && isAgree.value);
+	const codeText = computed(() => countdown.value > 0 ? `${countdown.value}s 后重试` : '获取验证码');
+
+	const goBack = () => uni.navigateBack();
+	const oneKeyNav = () => uni.navigateTo({ url: '/pages/login/login-one-key' });
+	const wechatLogin = () => uni.showToast({ title: '微信登录开发中', icon: 'none' });
+
+	const sendCode = () => {
+		if (!canSend.value) return;
+
+		// ✅ 修复核心:先取值到局部常量,再操作
+		const currentTimer = timer;
+		if (currentTimer !== null) {
+			clearInterval(currentTimer);
+		}
+		timer = null;
+
+		countdown.value = 60;
+		uni.showToast({ title: '验证码已发送', icon: 'success' });
+
+		timer = setInterval(() => {
+				countdown.value--;
+				if (countdown.value <= 0) {
+					// ✅ 同样在闭包内先取局部常量
+					const t = timer;
+					if (t !== null) {
+						clearInterval(t);
+					}
+					timer = null;
+					countdown.value = 0;
+				}
+			}, 1000);
+	};
+
+	const onAgreeChange = (e : any) => {
+		// UTS 中 any 类型必须 as 成具体类型再访问属性
+		const evt = e as UTSJSONObject;
+		if (evt != null) {
+			const detail = evt["detail"] as UTSJSONObject | null;
+			if (detail != null) {
+				const value = detail["value"] as Boolean | null;
+				isAgree.value = (value != null) && value;
+				return;
+			}
+		}
+		isAgree.value = false;
+	};
+
+	const doLogin = () => {
+		if (!canLogin.value) {
+			uni.showToast({ title: isAgree.value ? '请填写完整信息' : '请先同意协议', icon: 'none' });
+			return;
+		}
+		uni.showLoading({ title: '登录中...' });
+		setTimeout(() => {
+				uni.hideLoading();
+				uni.showToast({ title: '登录成功', icon: 'success' });
+			}, 1500);
+	};
+
+	const rejectAgreement = () => {
+		showModal.value = false;
+		uni.showToast({ title: '您拒绝了协议', icon: 'none' });
+	};
+
+	const agreeAgreement = () => {
+		showModal.value = false;
+		isAgree.value = true;
+		uni.showToast({ title: '已同意协议', icon: 'success' });
+	};
+</script>
+
+<style>
+	.page-container {
+		background: linear-gradient(180deg, #e0f7fa 0%, #fff8e1 100%);
+		height: 100%;
+		padding: 40rpx 30rpx;
+		box-sizing: border-box;
+	}
+
+	.close-btn {
+		position: absolute;
+		top: 40rpx;
+		right: 30rpx;
+		z-index: 10;
+	}
+
+	.header-section {
+		align-items: center;
+		margin-bottom: 60rpx;
+	}
+
+	.hello-text {
+		font-size: 48rpx;
+		font-weight: bold;
+		color: #333;
+		margin-bottom: 10rpx;
+	}
+
+	.welcome-text {
+		font-size: 32rpx;
+		color: #666;
+		margin-bottom: 30rpx;
+	}
+
+	.logo-img {
+		width: 300rpx;
+		height: 300rpx;
+		border-radius: 150rpx;
+		background-color: rgba(255, 255, 255, 0.3);
+	}
+
+	.form-section {
+		margin-bottom: 60rpx;
+	}
+
+	.input-box {
+		background-color: #ffffff;
+		border-radius: 30rpx;
+		padding: 20rpx 30rpx;
+		margin-bottom: 30rpx;
+		box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
+	}
+
+	.input-field {
+		flex: 1;
+		font-size: 28rpx;
+		color: #333;
+	}
+
+	.code-btn {
+		font-size: 26rpx;
+		color: #ffc107;
+		font-weight: bold;
+		white-space: nowrap;
+	}
+
+	.code-btn.disabled {
+		color: #ccc;
+	}
+
+	.login-btn {
+		background: linear-gradient(90deg, #ffc107, #ffca2c);
+		color: #ffffff;
+		font-size: 32rpx;
+		font-weight: bold;
+		text-align: center;
+		padding: 24rpx 0;
+		border-radius: 30rpx;
+		margin-bottom: 30rpx;
+		box-shadow: 0 4rpx 12rpx rgba(255, 193, 7, 0.3);
+	}
+
+	.login-btn.disabled {
+		background: #ddd;
+		color: #999;
+		box-shadow: none;
+	}
+
+	.agree-row {
+		align-items: flex-start;
+	}
+
+	.agree-content {
+		flex: 1;
+		margin-left: 10rpx;
+	}
+
+	.agree-text {
+		font-size: 24rpx;
+		color: #999;
+		line-height: 1.6;
+	}
+
+	.link-text {
+		color: #00b894;
+		border-bottom: 1rpx solid #00b894;
+	}
+
+	.footer-section {
+		margin-top: auto;
+	}
+
+	.divider-row {
+		margin-bottom: 40rpx;
+		align-items: center;
+	}
+
+	.line {
+		flex: 1;
+		height: 1rpx;
+		background-color: #ddd;
+	}
+
+	.divider-text {
+		font-size: 26rpx;
+		color: #999;
+		margin: 0 20rpx;
+	}
+
+	.methods-row {
+		justify-content: center;
+		margin-bottom: 40rpx;
+	}
+
+	.method-item {
+		margin-right: 60rpx;
+		align-items: center;
+	}
+
+	.method-item:last-child {
+		margin-right: 0;
+	}
+
+	.icon-box {
+		width: 80rpx;
+		height: 80rpx;
+		border-radius: 40rpx;
+		justify-content: center;
+		align-items: center;
+		margin-bottom: 15rpx;
+	}
+
+	.blue-bg {
+		background: linear-gradient(135deg, #4a90e2, #67b26f);
+	}
+
+	.green-bg {
+		background: linear-gradient(135deg, #00b894, #00cec9);
+	}
+
+	.method-name {
+		font-size: 26rpx;
+		color: #666;
+	}
+
+	.modal-mask {
+		position: fixed;
+		top: 0;
+		left: 0;
+		right: 0;
+		bottom: 0;
+		background-color: rgba(0, 0, 0, 0.5);
+		justify-content: center;
+		align-items: center;
+		z-index: 100;
+	}
+
+	.modal-box {
+		background-color: #ffffff;
+		border-radius: 20rpx;
+		padding: 40rpx 30rpx;
+		width: 600rpx;
+		max-height: 800rpx;
+		flex-direction: column;
+	}
+
+	.modal-title {
+		font-size: 36rpx;
+		font-weight: bold;
+		color: #333;
+		text-align: center;
+		margin-bottom: 20rpx;
+	}
+
+	.modal-scroll {
+		flex: 1;
+		margin-bottom: 20rpx;
+	}
+
+	.modal-welcome {
+		font-size: 28rpx;
+		color: #333;
+		margin-bottom: 15rpx;
+	}
+
+	.modal-desc {
+		font-size: 26rpx;
+		color: #666;
+		line-height: 1.6;
+		margin-bottom: 15rpx;
+	}
+
+	.modal-link {
+		color: #00b894;
+		border-bottom: 1rpx solid #00b894;
+	}
+
+	.modal-list {
+		font-size: 26rpx;
+		color: #666;
+		line-height: 1.6;
+		margin-bottom: 10rpx;
+	}
+
+	.modal-footer {
+		font-size: 26rpx;
+		color: #666;
+		line-height: 1.6;
+		margin-bottom: 10rpx;
+	}
+
+	.modal-btns {
+		border-top: 1rpx solid #eee;
+		padding-top: 20rpx;
+	}
+
+	.modal-btn {
+		flex: 1;
+		text-align: center;
+		font-size: 28rpx;
+		font-weight: bold;
+		padding: 15rpx 0;
+	}
+
+	.modal-btn.reject {
+		color: #999;
+		margin-right: 20rpx;
+	}
+
+	.modal-btn.agree {
+		color: #00b894;
+	}
+
+	.row-between {
+		flex-direction: row;
+		justify-content: space-between;
+		align-items: center;
+	}
+
+	.row-start {
+		flex-direction: row;
+		align-items: flex-start;
+	}
+
+	.row-center {
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+	}
+
+	.column-center {
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+	}
+</style>

BIN
static/icons/1首页.png


BIN
static/imagesInfo/bg-color.png


BIN
static/testInfo/corner.png


BIN
static/testInfo/demo.png


+ 1 - 1
uni.scss

@@ -52,7 +52,7 @@ $uni-img-size-lg:80rpx;
 $uni-border-radius-sm: 4rpx;
 $uni-border-radius-base: 6rpx;
 $uni-border-radius-lg: 12rpx;
-$uni-border-radius-circle: 50%;
+$uni-border-radius-circle: 50rpx; /* use fixed rpx instead of percentage */
 
 /* 水平间距 */
 $uni-spacing-row-sm: 10rpx;

BIN
unpackage/cache/.app-android/class/META-INF/main-1772434718197.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772434816268.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772435670955.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772435680645.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772435695927.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772435721710.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772435728190.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772435741634.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772435749122.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772435755062.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772435796134.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772435906415.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772435911332.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772435920488.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772435948598.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772435963188.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772435985011.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772436001848.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772436009596.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772436037214.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772436043926.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772436242749.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772436244390.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772436272312.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772436302892.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772436319354.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772436344676.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772436361284.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772436733800.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772437610570.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772437705447.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772437836165.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772437973296.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772438151611.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772438156947.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772440202111.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772440529303.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772440532467.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772441493825.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772441588196.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772441633868.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772441687059.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772441832109.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772442451647.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772442516524.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772442569539.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772442638337.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772442721256.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772442758637.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772442844375.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772443394650.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772443417537.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772443424598.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772443680217.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772443803263.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772443825886.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772443835362.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772443849693.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772443899993.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772443922738.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772443929290.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772443956932.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772443973209.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772444474875.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772445200251.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772445327427.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772446342807.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772447952898.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772500095554.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772500864715.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772501258196.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772501263533.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772501584342.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772501758323.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772502004975.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772502185181.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772502332541.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772502355210.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772502518489.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772502592501.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772505204120.kotlin_module


BIN
unpackage/cache/.app-android/class/META-INF/main-1772506283108.kotlin_module


Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä