MS-IOHQJGHXZHQD\Administrator 6 dagen geleden
bovenliggende
commit
24bb57efe3

+ 1 - 1
src/App.vue

@@ -126,7 +126,7 @@ page {
 // 弹窗
 .modal-wrap {
 	width: 590rpx;
-	height: 314rpx;
+	//height: 314rpx;
 	background: #fff;
 	border-radius: 16rpx;
 

+ 7 - 21
src/api/dynamic.js

@@ -1,26 +1,5 @@
 import request from "@/utils/request.js";
 
-// 发现-动态列表
-export function discoverList(data) {
-    return request({
-        method: 'get',
-        url: '/api/moment/v1/list',
-        data
-    });
-}
-
-
-
-// 技师动态列表
-export function jsDynamicList(data) {
-    return request({
-        method: 'get',
-        url: '/api/moment/v1/queryMomentByTechnicianId',
-        data
-    });
-}
-
-//guo
 
 //  查询草稿箱列表
 export function draftList(data) {
@@ -64,4 +43,11 @@ export function dynamicEdit(data) {
         data
     });
 }
+// 删除动态
+export function dynamicDelete(data) {
+    return request({
+        method: 'delete',
+        url: '/api/moment/v1/' + data.momentId
+    });
+}
 

+ 45 - 1
src/api/workbench.js

@@ -33,4 +33,48 @@ export function getSkillList(data) {
 		    'Authorization': `tf:${uni.getStorageSync('access-token')}`
 		}
     });
-}
+}
+// 查询商户合同记录
+export function getContractRecords(data) {
+    return request({
+        method: 'get',
+        url: '/technician/technician/getContractRecords',
+        data,
+		header: {
+		    'Authorization': `tf:${uni.getStorageSync('access-token')}`
+		}
+    });
+}
+// 查询城市列表
+export function getCityList(data) {
+    return request({
+        method: 'get',
+        url: '/cityOperationApplication/getCityList',
+        data,
+		header: {
+		    'Authorization': `tf:${uni.getStorageSync('access-token')}`
+		}
+    });
+}
+// 保存城市运营申请
+export function saveCity(data) {
+    return request({
+        method: 'post',
+        url: '/cityOperationApplication/saveCity',
+        data,
+		header: {
+		    'Authorization': `tf:${uni.getStorageSync('access-token')}`
+		}
+    });
+}
+// 免车费设置
+export function saveFareSetting(data) {
+    return request({
+        method: 'post',
+        url: '/project/fare/setting/save',
+        data,
+		header: {
+		    'Authorization': `tf:${uni.getStorageSync('access-token')}`
+		}
+    });
+}

+ 359 - 86
src/components/cl-upload/cl-upload/cl-upload.vue

@@ -5,100 +5,79 @@
 			<view v-for="(item, index) in previewList" @tap="clickSelectedFile(item, index)" class="file-list-row"
 				:style="[rowStyle]" :key="index">
 
-				<image 
-					class="_image" 
-					v-if="fileUrlType(item) === 'image'" 
-					:src="item.path" 
-					:style="[imgStyle]" 
+				<image class="_image" v-if="fileUrlType(item) === 'image'" :src="item.path" :style="[imgStyle]"
 					mode="aspectFill">
 				</image>
 
+				<!-- 音频文件显示 - 使用原生 audio 标签 -->
+				<view v-else-if="fileUrlType(item) === 'audio'" class="_audio" :style="[imgStyle]">
+					<audio v-if="item.path" controls :src="item.path" class="audio-player">Your browser does not support the audio element.</audio>
+						
+				</view>
+
 				<view v-else class="_video" :style="[imgStyle]">
 
 					<!-- #ifdef MP-WEIXIN || MP-ALIPAY -->
-					<video 
-						v-if="!autoUpload || cloudType === 'other'" 
-						class="_video" 
-						:style="[imgStyle]"
-						:src="item.path" 
-						:show-center-play-btn="false" 
-						:show-fullscreen-btn="false"
-						:show-play-btn="false" 
-						:show-loading="false" 
-						:enable-progress-gesture="false" 
-						:controls="false">
+					<video v-if="!autoUpload || cloudType === 'other'" class="_video" :style="[imgStyle]"
+						:src="item.path" :show-center-play-btn="false" :show-fullscreen-btn="false"
+						:show-play-btn="false" :show-loading="false" :enable-progress-gesture="false" :controls="false">
 						<view @tap="previewVideo(item, index)" class="play">
 							<image style="width: 100%;" :src="playImg" mode="widthFix"></image>
 						</view>
 					</video>
 
 					<!-- #endif -->
-					
+
 					<!-- #ifdef APP-PLUS -->
-					<video
-						v-if="cloudType === 'other'" 
-						class="_video" 
-						:style="[imgStyle]" 
-						:src="item.path"
-						:poster="item.path"
-						:controls="false"
-						:show-center-play-btn="false" 
-						:show-fullscreen-btn="false" 
-						:show-play-btn="false"
-						:show-loading="false" 
-						:enable-progress-gesture="false">
+					<video v-if="cloudType === 'other'" class="_video" :style="[imgStyle]" :src="item.path"
+						:poster="item.path" :controls="false" :show-center-play-btn="false" :show-fullscreen-btn="false"
+						:show-play-btn="false" :show-loading="false" :enable-progress-gesture="false">
 						<cover-image class="app_play" :src="playImg" @tap="previewVideo(item, index)"></cover-image>
 						<cover-view class="remove" v-if="remove" @tap="deleteSelectedFile(item, index)">
-							<cover-image class="image" :src="deleteImg" mode="widthFix" @tap="deleteSelectedFile(item, index)"></cover-image>
+							<cover-image class="image" :src="deleteImg" mode="widthFix"
+								@tap="deleteSelectedFile(item, index)"></cover-image>
 						</cover-view>
 					</video>
 					<!-- #endif -->
-					
+
 					<!-- #ifndef MP-WEIXIN || MP-ALIPAY || APP-PLUS -->
-					<video 
-						v-if="cloudType === 'other'" 
-						class="_video" 
-						:autoplay="false"
-						:style="[imgStyle]" 
-						:src="item.path"
-						:controls="false"
-						:show-center-play-btn="false" 
-						:show-fullscreen-btn="false" 
-						:show-play-btn="false"
-						:show-loading="false" 
-						:enable-progress-gesture="false" >
-						<cover-view  @tap="previewVideo(item, index)" class="play">
+					<video v-if="cloudType === 'other'" class="_video" :autoplay="false" :style="[imgStyle]"
+						:src="item.path" :controls="false" :show-center-play-btn="false" :show-fullscreen-btn="false"
+						:show-play-btn="false" :show-loading="false" :enable-progress-gesture="false">
+						<cover-view @tap="previewVideo(item, index)" class="play">
 							<cover-image style="width: 100%;" :src="playImg" mode="widthFix"></cover-image>
 						</cover-view>
 					</video>
-					
+
 					<!-- #endif -->
-					
+
 					<template v-else>
 						<cl-image class="pay" :style="[imgStyle]" :cloudType="cloudType"
 							:src="(item.poster || item.path)"></cl-image>
-						
+
 						<view class="play" @tap="previewVideo(item, index)">
 							<image class="play-img" :src="playImg" mode="widthFix"></image>
 						</view>
 					</template>
 
 				</view>
-				
+
 				<view class="remove" v-if="remove" @tap.stop="deleteSelectedFile(item, index)">
 					<image class="image" :src="deleteImg" mode="widthFix"></image>
 				</view>
 			</view>
 
-			<view v-if="add && FileList.length < max" @tap="selectFileTypeOnAdd" :style="[rowStyle]" class="file-list-row">
+			<view v-if="add && FileList.length < max" @tap="selectFileTypeOnAdd" :style="[rowStyle]"
+				class="file-list-row">
 				<slot name="addImg">
 					<div class="add-image">
 						<view>
-							<image class="_image" style="width: 52rpx;height: 52rpx;" :src="addImg" mode="widthFix"></image>
-						  <view style="font-weight: 400;font-size: 26rpx;color: #C9CDD4;margin-top: -13rpx;">上传</view>
+							<image class="_image" style="width: 52rpx;height: 52rpx;" :src="addImg" mode="widthFix">
+							</image>
+							<view style="font-weight: 400;font-size: 26rpx;color: #C9CDD4;margin-top: -13rpx;">上传</view>
 
 						</view>
-						
+
 					</div>
 				</slot>
 			</view>
@@ -146,7 +125,7 @@ export default {
 			type: String,
 			default: 'file'
 		},
-		// 文件类型 'image', 'video', 'all'
+		// 文件类型 'image', 'video', 'audio', 'all'
 		fileType: {
 			type: String,
 			default: 'all'
@@ -163,13 +142,18 @@ export default {
 			type: Object,
 			default: () => { }
 		},
+		// 上传音频参数
+		audioFromData: {
+			type: Object,
+			default: () => { }
+		},
 
 		// 必选参数,上传的地址
 		action: {
 			type: String,
 			default: ''
 		},
-		
+
 		// 启用目录, 仅unicloud阿里云支持
 		// https://uniapp.dcloud.net.cn/uniCloud/storage.html#storage-dir
 		cloudPathAsRealPath: {
@@ -225,6 +209,11 @@ export default {
 			type: Number,
 			default: 0
 		},
+		// 音频最大上传数量
+		maxAudio: {
+			type: Number,
+			default: 0
+		},
 		// 列表样式
 		listStyle: {
 			type: Object,
@@ -275,6 +264,11 @@ export default {
 			type: String,
 			default: 'https://mp-61599c79-d7ee-4a75-a24b-e5a288da6dd3.cdn.bspapp.com/cloudstorage/cde4362d-7ec7-4cac-a692-12e1f576be1e.png'
 		},
+		// 暂停按钮图片
+		pauseImg: {
+			type: String,
+			default: 'https://mp-61599c79-d7ee-4a75-a24b-e5a288da6dd3.cdn.bspapp.com/cloudstorage/cde4362d-7ec7-4cac-a692-12e1f576be1e.png'
+		},
 	},
 	data() {
 		return {
@@ -284,6 +278,24 @@ export default {
 			// 预览视频地址
 			tempVideoUrl: '',
 
+			// 预览音频地址
+			tempAudioUrl: '',
+			// 音频播放状态
+			isAudioPlaying: false,
+			// 当前音频播放时间
+			currentAudioTime: 0,
+			// 音频总时长
+			totalAudioDuration: 0,
+			// 音频进度
+			audioProgress: 0,
+			// 音频管理器
+			audioManager: null,
+
+
+			// 当前音频索引
+			currentAudioIndex: -1,
+
+
 			// 临时文件列表
 			tempFile_paths: [],
 
@@ -378,17 +390,17 @@ export default {
 			const deleteFileFromList = () => {
 				const tempFileIndex = this.tempFile_paths.indexOf(item || item.path);
 
-				if (tempFileIndex > -1) { 
+				if (tempFileIndex > -1) {
 					this.tempFile_paths.splice(tempFileIndex, 1)
 				}
 
-				this.FileList.splice(selectedFileIndex, 1) 
+				this.FileList.splice(selectedFileIndex, 1)
 
-        // 检查文件列表是否为空,如果为空则触发重置事件
+				// 检查文件列表是否为空,如果为空则触发重置事件
 				if (this.FileList.length === 0) {
 					this.$emit('onError', '文件列表为空');
 				}
-        
+
 				// #ifdef VUE2 
 				this.$emit('input', this.FileList)
 				// #endif
@@ -427,15 +439,18 @@ export default {
 					break;
 				case 'all':
 					uni.showActionSheet({
-						itemList: ['相册', '视频'],
+						itemList: ['相册', '视频', '音频'],
 						success: (res) => {
 							const tapIndex = res.tapIndex;
 							if (tapIndex === 0) {
-                this.$emit('onMediaTypeSelect', 'image');
+								this.$emit('onMediaTypeSelect', 'image');
 								this.handleFileSelection(1);
-							} else {
-                this.$emit('onMediaTypeSelect', 'video');
+							} else if (tapIndex === 1) {
+								this.$emit('onMediaTypeSelect', 'video');
 								this.handleFileSelection(2);
+							} else {
+								this.$emit('onMediaTypeSelect', 'audio');
+								this.handleFileSelection(3);
 							}
 						},
 						fail: (res) => {
@@ -443,6 +458,9 @@ export default {
 						}
 					});
 					break;
+				case 'audio':
+					this.handleFileSelection(3);
+					break;
 				default:
 					this.handleFileSelection(1);
 					break;
@@ -452,7 +470,7 @@ export default {
 
 		/**
 		 * 从本地选择文件。
-		 * @param { number } updataType 选择类型 1:图片 2视频
+		 * @param { number } updataType 选择类型 1:图片 2视频 3音频
 		 * */
 		async handleFileSelection(updataType) {
 			const that = this;
@@ -482,7 +500,7 @@ export default {
 						// 限制图片上传尺寸
 						if (that.imageFormData?.size ?? false) {
 							const maxSize = that.imageFormData.size * 1024 * 1024
-							
+
 							tempFiles.map((imgInfo, index) => {
 								if (imgInfo.size > maxSize) {
 									tempFiles.splice(index, 1)
@@ -599,31 +617,179 @@ export default {
 
 				})
 			}
+
+			if (updataType === 3) {
+
+				// 限制音频最大上传数量
+				const AUDIO_REGEXP = /\.(mp3|wav|ogg|m4a)/i
+				const audioList = await that.FileList.filter(item => {
+					const fileUrl = item?.url ?? item
+					return AUDIO_REGEXP.test(fileUrl)
+				})
+
+				if (that.maxAudio > 0 && audioList.length >= that.maxAudio) {
+					that.$emit('onAudioMax', that.maxAudio, audioList.length)
+					return uni.showToast({
+						title: '音频数量已超出',
+						duration: 2000,
+						icon: 'none'
+					});
+				}
+
+				const data = Object.assign({}, {
+					// 录音最长时间,单位秒,默认 60
+					maxDuration: 60,
+					// 录音结束后是否自动播放录音,默认 false
+					autoPlay: false,
+				}, this.audioFromData)
+				// #ifdef MP-WEIXIN || MP-ALIPAY || MP-BAIDU || MP-TOUTIAO
+				uni.chooseAudio({
+					...data,
+					success: (res) => {
+						let tempFilePath = { ...res }
+						tempFilePath['path'] = res.tempFilePath
+
+						// 限制音频上传尺寸
+						if (that.audioFromData?.size ?? false) {
+							const maxSize = that.audioFromData.size * 1024 * 1024
+
+							if (tempFilePath.size > maxSize) {
+								uni.showToast({
+									title: `音频最大上传${that.audioFromData.size}MB`,
+									duration: 2000,
+									icon: 'none'
+								});
+								return false;
+							}
+						}
+						if (that.autoUpload) {
+							that.onBeforeUploadFile(tempFilePath, 'audio')
+						} else {
+							that.FileList.push(tempFilePath)
+							that.tempFile_paths.push(tempFilePath)
+						}
+					},
+					fail(err) {
+						console.error('选择音频失败', err)
+						that.$emit('onError', err)
+					}
+				})
+				// #endif
+
+				// #ifdef H5
+				// 使用 input file 选择音频
+				that.chooseAudioByInput();
+				// #endif
+
+
+				// #ifndef MP-WEIXIN || MP-ALIPAY || MP-BAIDU || MP-TOUTIAO || H5
+				// 其他平台提示不支持
+				uni.showToast({
+					title: '当前平台不支持音频选择',
+					duration: 2000,
+					icon: 'none'
+				});
+				// #endif
+			}
+		},
+		chooseAudioByInput() {
+			const that = this;
+			const input = document.createElement('input');
+			input.type = 'file';
+			input.accept = 'audio/*';
+			input.style.display = 'none';
+			document.body.appendChild(input);
+
+			input.onchange = function (e) {
+				const file = e.target.files[0];
+				if (!file) return;
+
+				// 限制音频上传尺寸
+				if (that.audioFromData?.size) {
+					const maxSize = that.audioFromData.size * 1024 * 1024;
+					if (file.size > maxSize) {
+						uni.showToast({
+							title: '音频最大上传' + that.audioFromData.size + 'MB',
+							duration: 2000,
+							icon: 'none'
+						});
+						document.body.removeChild(input);
+						return;
+					}
+				}
+
+				const tempFilePath = {
+					path: URL.createObjectURL(file),
+					name: file.name,
+					size: file.size,
+					duration: 0
+				};
+
+				// 使用 Audio 对象获取音频时长
+				const audio = new Audio(tempFilePath.path);
+				audio.onloadedmetadata = function () {
+					tempFilePath.duration = audio.duration || 0;
+
+					if (that.autoUpload) {
+						that.onBeforeUploadFile(tempFilePath, 'audio');
+					} else {
+						that.FileList.push(tempFilePath);
+						that.tempFile_paths.push(tempFilePath);
+					}
+
+					document.body.removeChild(input);
+				};
+				audio.onerror = function () {
+					// 如果获取时长失败,使用默认值继续
+					if (that.autoUpload) {
+						that.onBeforeUploadFile(tempFilePath, 'audio');
+					} else {
+						that.FileList.push(tempFilePath);
+						that.tempFile_paths.push(tempFilePath);
+					}
+
+					document.body.removeChild(input);
+				};
+			};
+
+			input.click();
 		},
 
+		
 		/**
 		 * 上传前钩子
 		 * @param { tempFile } 临时文件
+		 * @param { string } type 文件类型 'image', 'video', 'audio'
 		 * @return { Promise }
-		 * */ 
-		onBeforeUploadFile(tempFile) {
+		 * */
+		onBeforeUploadFile(tempFile, type) {
 			if (this.useBeforeUpload) {
-				return this.$emit('beforeUpload', tempFile, () => {
-					return this.updataFile(tempFile);
+				return this.$emit('beforeUpload', tempFile, type, () => {
+					return this.updataFile(tempFile, type);
 				})
 			}
-			return this.updataFile(tempFile);
+			return this.updataFile(tempFile, type);
 		},
 
 		/**
 		 * 上传文件到服务器
 		 * @param { tempFile } 临时文件
+		 * @param { string } type 文件类型 'image', 'video', 'audio'
 		 * @return { Promise }
 		 * */
-		updataFile(tempFile) {
+		updataFile(tempFile, type) {
 			const that = this;
 			const filePath = tempFile.path || tempFile;
-			const fileType = this.fileUrlType(filePath) == 'image' ? '.png' : '.mp4';
+			let fileType;
+			if (type === 'image') {
+				fileType = '.png';
+			} else if (type === 'video') {
+				fileType = '.mp4';
+			} else if (type === 'audio') {
+				fileType = '.mp3';
+			} else {
+				fileType = this.fileUrlType(filePath) == 'image' ? '.png' : this.fileUrlType(filePath) == 'audio' ? '.mp3' : '.mp4';
+			}
 			const fileName = tempFile.name || Date.now() + fileType;
 
 			uni.showLoading({
@@ -642,7 +808,7 @@ export default {
 						fileType: fileType,
 						// #endif
 						cloudPathAsRealPath: this.cloudPathAsRealPath,
-						
+
 						onUploadProgress: (progressEvent) => {
 							const percentCompleted = Math.round(
 								(progressEvent.loaded * 100) / progressEvent.total
@@ -650,16 +816,24 @@ export default {
 							that.$emit('onProgress', percentCompleted)
 						},
 						success(result) {
+							// 保留文件类型信息,用于显示
+							const fileInfo = {
+								path: result.fileID,
+								name: fileName,
+								duration: tempFile.duration || 0,
+								type: type
+							};
+
 							if (that.autoUpload) {
-								that.FileList.push(result.fileID)
+								that.FileList.push(fileInfo)
 							} else {
 								that.FileList.map((item, index) => {
 									if (item === filePath || item.path === filePath) {
-										that.FileList.splice(index, 1, result.fileID)
+										that.FileList.splice(index, 1, fileInfo)
 									}
 								})
 							}
-							
+
 							// #ifdef VUE2
 							that.$emit('input', that.FileList)
 							// #endif
@@ -696,7 +870,7 @@ export default {
 					success: (uploadFileRes) => {
 						const data = JSON.parse(uploadFileRes.data)
 						uni.hideLoading();
-						that.success(data,tempFile)
+						that.success(data, tempFile)
 
 						if (!this.autoUpload) {
 							that.FileList.map((item, index) => {
@@ -754,8 +928,8 @@ export default {
 		 * @param {array} data 上传成功后的数据
 		 * @return {array} 返回数据
 		 * */
-		success(data,tempFile) {
-			this.$emit('onSuccess', data,tempFile);
+		success(data, tempFile) {
+			this.$emit('onSuccess', data, tempFile);
 
 			// 自定义数据结构-选择性开启
 			// const list = data.map(item=> {
@@ -889,20 +1063,26 @@ export default {
 		},
 
 		/**
-		 * 是否img类型
+		 * 文件类型判断
 		 * @param {string, object} item 文件信息
-		 * @return {boolean} 是否img类型
+		 * @return {string} 文件类型 'image', 'video', 'audio'
 		 * */
 		fileUrlType(file) {
+			// 如果文件对象有 type 属性,直接使用
+			if (file.type) {
+				return file.type;
+			}
 			const filePath = file.path || file;
-
 			if (this.isBase64(filePath)) return 'image'
 
 			const fileType = filePath.split('.').pop();
 
 			const IMAGE_REGEXP = /(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg|image)/i
+			const AUDIO_REGEXP = /(mp3|wav|ogg|m4a|audio)/i
 			if (IMAGE_REGEXP.test(fileType)) {
 				return 'image';
+			} else if (AUDIO_REGEXP.test(fileType)) {
+				return 'audio';
 			} else {
 				return 'video';
 			}
@@ -911,6 +1091,14 @@ export default {
 		isBase64(str) {
 			if (str === '' || typeof str !== 'string') return console.error('文件路径错误, base64', str);
 			return str.includes('blob:') || str.includes('data:image');
+		},
+
+		// 组件销毁时释放音频资源
+		onUnmounted() {
+			if (this.audioManager) {
+				this.audioManager.destroy();
+				this.audioManager = null;
+			}
 		}
 	}
 }
@@ -926,7 +1114,7 @@ export default {
 			display: inline-flex;
 			align-items: center;
 			position: relative;
-			
+
 			.play-img {
 				width: 100%;
 			}
@@ -942,7 +1130,7 @@ export default {
 				height: 100%;
 				overflow: hidden;
 			}
-			
+
 			.video-fixed {
 				position: absolute;
 				top: 0;
@@ -953,7 +1141,7 @@ export default {
 				border-radius: 10rpx;
 				z-index: 96;
 			}
-			
+
 			.play {
 				position: absolute;
 				top: 50%;
@@ -962,7 +1150,7 @@ export default {
 				width: 30%;
 				z-index: 95;
 			}
-			
+
 			.app_play {
 				position: absolute;
 				top: 50%;
@@ -1042,5 +1230,90 @@ export default {
 			top: 5vh
 		}
 	}
+
+	._audio {
+		position: relative;
+		width: 100%;
+		height: 100%;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+		background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+		border-radius: 10rpx;
+		overflow: hidden;
+	}
+
+	.audio-icon {
+		width: 60rpx;
+		height: 60rpx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		background: rgba(255, 255, 255, 0.3);
+		border-radius: 50%;
+	}
+
+	.audio-img {
+		width: 30rpx;
+		height: 30rpx;
+	}
+
+	.audio-duration {
+		color: #fff;
+		font-size: 24rpx;
+		margin-top: 10rpx;
+	}
+
+	// 音频预览弹窗样式
+	.audio-block {
+		position: absolute;
+		top: 50%;
+		left: 50%;
+		transform: translate(-50%, -50%);
+		width: 80%;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.audio-play-btn {
+		width: 120rpx;
+		height: 120rpx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		background: rgba(255, 255, 255, 0.2);
+		border-radius: 50%;
+		margin-bottom: 30rpx;
+	}
+
+	.audio-progress {
+		width: 100%;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+	}
+
+	.progress-bar {
+		width: 100%;
+		height: 6rpx;
+		background: rgba(255, 255, 255, 0.3);
+		border-radius: 3rpx;
+		overflow: hidden;
+		margin-bottom: 10rpx;
+	}
+
+	.progress-fill {
+		height: 100%;
+		background: #fff;
+		border-radius: 3rpx;
+	}
+
+	.progress-text {
+		color: #fff;
+		font-size: 24rpx;
+	}
 }
-</style>
+</style>

+ 1435 - 1312
src/pages/index/index.vue

@@ -120,7 +120,7 @@
 			</view>
 
 			<!-- 我的技能 -->
-			<view class="card skills-section" v-if="skillList"> 
+			<view class="card skills-section" v-if="skillList">
 				<view class="section-header">
 					<view class="section-heading-wrap">
 						<view class="section-heading-box">
@@ -142,7 +142,8 @@
 						<view class="skill-info">
 							<view class="skill-name one-line-text">{{ skillList[0].projectName }}</view>
 							<view class="skill-tags" v-if="skillList[0].highlight && skillList[0].highlight.length">
-								<view class="skill-tag" v-for="(tag, tagIndex) in skillList[0].highlight" :key="tagIndex">
+								<view class="skill-tag" v-for="(tag, tagIndex) in skillList[0].highlight"
+									:key="tagIndex">
 									{{ tag }}</view>
 							</view>
 							<view class="skill-price">¥{{ formatMoney(skillList[0].projectCurrentPrice) }}</view>
@@ -257,1436 +258,1558 @@
 				</view>
 			</view>
 		</u-popup>
+		<!-- 退出登录弹窗 -->
+		<u-popup :show="showModal2" mode="center" :round="16" :mask-close-able="false">
+			<view class="modal-wrap">
+				<!-- 标题居中 -->
+				<view class="title">提示</view>
+				<!-- 正文 -->
+				<view class="content">
+					确定退出登录吗?
+				</view>
+				<!-- 底部双按钮(必显示) -->
+				<view class="btn-box">
+					<view class="btn left" @click="showModal2 = false">取消</view>
+					<view class="btn right" @click="goLogout">确定</view>
+				</view>
+			</view>
+		</u-popup>
+		<!-- 技能完善新手引导 -->
+		<view v-show="showSkillGuide" class="guide-full-mask" @click="closeSkillGuide">
+			<!-- 镂空高亮区域 -->
+			<view class="guide-hole" :style="holeStyle"></view>
+			<!-- 提示气泡 -->
+			<view class="guide-tip-pop" :style="tipPopStyle">
+				<text>欢迎入驻~完善你的服务技能标签,用户能快速找到你、下单更多!</text>
+				<view class="guide-hand">👆</view>
+			</view>
+		</view>
 
 	</view>
 </template>
 
 <script>
-	import {
-		getMerchantData,
-		getInfo,
-		myIncome,
-		getStaffWorkData,
-		getWaitOrder,
-		myBank,
-		getProjectByJsId,
-		netStaffWork,
-		getJsLocation,
-	} from '@/api/index';
-	import {
-		orderDeatails,
-		takeOrder,
-		refuseOrder
-	} from '@/api/order.js';
-
-	import {
-		switchToOffline,
-		getSkillList
-	} from '@/api/workbench.js';
-
-	export default {
-		data() {
-			return {
-				showModal: false, // 控制弹窗显隐
-				merchantInfo: {},
-				cJsId: '',
-				isWorking: false,
-				todayOrderCount: '6',
-				bankCardCount: '3',
-				ratingScore: '4.8',
-				onlineHours: '3',
-				workStartTime: null,
-				restStartTime: null,
-				balance: 12341.56,
-				myIncome: {
-					tAmount: '12341.56',
-					wAmount: '12341.56',
-					yAmount: '12341.56',
-					gAmount: '12341.56',
-					kAmount: '12341.56',
-					deductAmount: '12341.56',
-				},
-				pendingOrder: true,
-				currentAddress: '',
-				showRejectPopup: false,
-				rejectReason: '',
-				showStatusPopup: false,
-				statusDraft: 'working',
-				slideX: 0,
-				slideStartX: 0,
-				slideMax: 0,
-				isSliding: false,
-				skillList: [],
-				public: this.$globalData.publicUrl, //图片前缀
-				serviceTag: '', //服务标签(1:按摩推拿 2:陪玩)
-				moreFeatures: [
-					{ label: '免车费', icon: '/static/workbench/freeCar.png', path: '/workbench/fare/index' },
-					{ label: '开通新技能', icon: '/static/workbench/newSkill.png', path: '/workbench/skill/add' },
-					{ label: '我的合同', icon: '/static/workbench/contract.png', path: '/workbench/contract/index' },
-					{ label: '我的资料', icon: '/static/workbench/info.png', path: '/pages/join/applyJoin?title=编辑资料' },
-					{ label: '城市管理', icon: '/static/workbench/city.png', path: '/workbench/city/index' },
-				],
-				auditStatus: 0,
+import {
+	getMerchantData,
+	getInfo,
+	myIncome,
+	getStaffWorkData,
+	getWaitOrder,
+	myBank,
+	getProjectByJsId,
+	netStaffWork,
+	logout,
+	getJsLocation,
+} from '@/api/index';
+import {
+	orderDeatails,
+	takeOrder,
+	refuseOrder
+} from '@/api/order.js';
+
+import {
+	switchToOffline,
+	getSkillList
+} from '@/api/workbench.js';
+
+export default {
+	data() {
+		return {
+			showModal2: false, // 控制退出登录弹窗显隐
+			showModal: false, // 控制弹窗显隐
+			merchantInfo: {},
+			cJsId: '',
+			isWorking: false,
+			todayOrderCount: '6',
+			bankCardCount: '3',
+			ratingScore: '4.8',
+			onlineHours: '3',
+			workStartTime: null,
+			restStartTime: null,
+			balance: 12341.56,
+			myIncome: {
+				tAmount: '12341.56',
+				wAmount: '12341.56',
+				yAmount: '12341.56',
+				gAmount: '12341.56',
+				kAmount: '12341.56',
+				deductAmount: '12341.56',
+			},
+			pendingOrder: true,
+			currentAddress: '',
+			showRejectPopup: false,
+			rejectReason: '',
+			showStatusPopup: false,
+			statusDraft: 'working',
+			slideX: 0,
+			slideStartX: 0,
+			slideMax: 0,
+			isSliding: false,
+			skillList: [],
+			public: this.$globalData.publicUrl, //图片前缀
+			serviceTag: '', //服务标签(1:按摩推拿 2:陪玩)
+			moreFeatures: [
+				{ label: '免车费', icon: '/static/workbench/freeCar.png', path: '/workbench/fare/index' },
+				{ label: '开通新技能', icon: '/static/workbench/newSkill.png', path: '/workbench/skill/add' },
+				{ label: '我的合同', icon: '/static/workbench/contract.png', path: '/workbench/contract/index' },
+				{ label: '我的资料', icon: '/static/workbench/info.png', path: '/pages/join/applyJoin?title=编辑资料' },
+				{ label: '城市管理', icon: '/static/workbench/city.png', path: '/workbench/city/index' },
+				{ label: '退出登录', icon: '/static/workbench/logout.png', },
+			],
+			auditStatus: 0,
+			// 原有数据不动,追加下面两行
+			showSkillGuide: false,
+			holeStyle: {},
+			tipPopStyle: {}
+		}
+	},
+	computed: {
+		orderTitle() {
+			if (!this.pendingOrder) return ''
+			const goods = this.pendingOrder.cGoods || []
+			return goods[0]?.cTitle || '服务项目'
+		},
+		orderServiceTime() {
+			if (!this.pendingOrder) return ''
+			return this.formatOrderTime(
+				this.pendingOrder.reachTime || this.pendingOrder.dtCreateTime || ''
+			)
+		},
+		deductionAmount() {
+			return (
+				this.myIncome.kAmount ??
+				this.myIncome.deductAmount ??
+				this.myIncome.dAmount ??
+				0
+			)
+		},
+		orderAddress() {
+			if (!this.pendingOrder) return ''
+			return this.pendingOrder.address || this.pendingOrder.atlasAdd || ''
+		},
+		isNewCustomer() {
+			return this.pendingOrder?.nB2 == 1
+		},
+	},
+	onShow() {
+		setTimeout(() => {
+			this.loadPageData()
+			this.getSkillList();
+			// 新增:判断是否需要展示技能引导
+			const guideFlag = uni.getStorageSync('merchant_skill_manage_guide')
+			if (!guideFlag && this.auditStatus === 2) { // 仅审核通过正式商户展示
+				this.$nextTick(() => this.getManageBtnRect())
 			}
+		}, 300)
+
+	},
+	async onLoad() {
+		this.auditStatus = await this.checkMerchantStatus()
+		this.auditStatus = 0 //guo
+		if (this.auditStatus == 0 || this.auditStatus == 3) {
+			this.showModal = true
+			return
+		}
+		if (this.auditStatus == 1) {
+			uni.showToast({
+				title: '入驻审核中,暂无操作权限',
+				icon: 'none'
+			})
+
+		}
+		console.log('onLoad')
+
+	},
+	methods: {
+		
+		//查询商户状态  auditStatus 审核状态:-1-申请入住,0-待入驻,1-待审核,2-审核通过,3-审核驳回"
+		async checkMerchantStatus() {
+			const openid = uni.getStorageSync('wx_copenid')
+			const merchantInfo = await this.$utils.checkMerchantStatus(openid)
+			if (!merchantInfo) return
+			this.cJsId = merchantInfo.merchant.id; //用户id
+			/**
+			 * 服务标签(1:按摩推拿 2:陪玩)
+			 */
+			this.serviceTag = merchantInfo.merchant.serviceTag
+			uni.setStorageSync('serviceTag', merchantInfo.merchant.serviceTag)
+			uni.setStorageSync('userId', merchantInfo.merchant.id)
+			return merchantInfo.merchant.auditStatus//用户状态
+
 		},
-		computed: {
-			orderTitle() {
-				if (!this.pendingOrder) return ''
-				const goods = this.pendingOrder.cGoods || []
-				return goods[0]?.cTitle || '服务项目'
-			},
-			orderServiceTime() {
-				if (!this.pendingOrder) return ''
-				return this.formatOrderTime(
-					this.pendingOrder.reachTime || this.pendingOrder.dtCreateTime || ''
-				)
-			},
-			deductionAmount() {
-				return (
-					this.myIncome.kAmount ??
-					this.myIncome.deductAmount ??
-					this.myIncome.dAmount ??
-					0
-				)
-			},
-			orderAddress() {
-				if (!this.pendingOrder) return ''
-				return this.pendingOrder.address || this.pendingOrder.atlasAdd || ''
-			},
-			isNewCustomer() {
-				return this.pendingOrder?.nB2 == 1
-			},
+		// 我在想想:关闭弹窗
+		cancel() {
+			this.showModal = false
 		},
-		onShow() {
-			setTimeout(() => {
-				this.loadPageData()
-				this.getSkillList();
-			},300)
-				
+		// 立即入驻:跳转入驻页
+		goEnter() {
+			this.showModal = false
+			uni.navigateTo({
+				url: '/pages/join/applyJoin' // 替换你的入驻页面路径
+			})
 		},
-		async onLoad() {
-			this.auditStatus = await this.checkMerchantStatus()
-			//this.auditStatus=0 //guo
-			if(this.auditStatus == 0 || this.auditStatus == 3){
-					this.showModal = true
-					return
+		loadPageData() {
+			// this.fetchMerchantInfo()
+			// this.fetchWalletInfo()
+			// this.fetchIncome()
+			// this.fetchWorkData()
+			// this.fetchBankCards()
+		},
+
+		getSkillList() {
+			let params = {
+				auditStatus: "1", //审核状态:0-待审核,1-审核通过,2-审核驳回
+				userId: this.cJsId, //商户ID
+				typeId: this.serviceTag //服务标签ID
 			}
-			if(this.auditStatus == 1){
-				uni.showToast({
-					title: '入驻审核中,暂无操作权限',
-					icon: 'none'
-				})	
-				
+			getSkillList(params).then(res => {
+				console.log('res----我的技能', res)
+				if (res.data.code == 200) {
+					this.skillList = res.data.result;
+				}
+			})
+		},
+		fetchMerchantInfo() {
+			const params = {
+				cOpenId: uni.getStorageSync('wx_copenid')
 			}
-			console.log('onLoad')
-			
+			getMerchantData(params).then(res => {
+				if (res.data.code != 200 || !res.data.data) return
+				const data = res.data.data
+				this.merchantInfo = data
+				this.cJsId = data.id
+				this.isWorking = data.nStatus2 == '0'
+				this.ratingScore = data.nStar != null ? Number(data.nStar).toFixed(1) : '0.0'
+				this.workStartTime = data.dtWorkStart || data.dtOnlineStart || null
+				this.restStartTime = data.dtRestStart || data.restStartTime || null
+				this.syncCurrentAddress(data)
+				this.fetchTodayOrders()
+				this.fetchPendingOrder()
+				this.fetchSkills()
+			})
 		},
-		methods: {
-			//查询商户状态  auditStatus 审核状态:-1-申请入住,0-待入驻,1-待审核,2-审核通过,3-审核驳回"
-			 async checkMerchantStatus() {
-				const openid = uni.getStorageSync('wx_copenid')
-				const merchantInfo = await this.$utils.checkMerchantStatus(openid)
-				if(!merchantInfo) return
-				this.cJsId = merchantInfo.merchant.id; //用户id
-				/**
-				 * 服务标签(1:按摩推拿 2:陪玩)
-				 */
-				this.serviceTag = merchantInfo.merchant.serviceTag
-				uni.setStorageSync('serviceTag', merchantInfo.merchant.serviceTag)
-				uni.setStorageSync('userId', merchantInfo.merchant.id)
-				return merchantInfo.merchant.auditStatus//用户状态
-				
-			},
-			// 我在想想:关闭弹窗
-			cancel() {
-				this.showModal = false
-			},
-			// 立即入驻:跳转入驻页
-			goEnter() {
-				this.showModal = false
-				uni.navigateTo({
-					url: '/pages/join/applyJoin' // 替换你的入驻页面路径
-				})
-			},
-			loadPageData() {
-				// this.fetchMerchantInfo()
-				// this.fetchWalletInfo()
-				// this.fetchIncome()
-				// this.fetchWorkData()
-				// this.fetchBankCards()
-			},
-			
-			getSkillList() {
-				let params = {
-					auditStatus: "1", //审核状态:0-待审核,1-审核通过,2-审核驳回
-					userId: this.cJsId, //商户ID
-					typeId: this.serviceTag //服务标签ID
+		fetchWalletInfo() {
+			getInfo().then(res => {
+				if (res.data.code == 200 && res.data.data) {
+					this.cJsId = res.data.data.id;
 				}
-				getSkillList(params).then(res => {
-					console.log('res----我的技能', res)
-					if (res.data.code == 200) {
-						this.skillList = res.data.result;
-					}
-				})
-			},
-			fetchMerchantInfo() {
-				const params = {
-					cOpenId: uni.getStorageSync('wx_copenid')
+			})
+		},
+		fetchIncome() {
+			myIncome().then(res => {
+				if (res.data.code == 200 && res.data.data) {
+					this.myIncome = res.data.data
 				}
-				getMerchantData(params).then(res => {
-					if (res.data.code != 200 || !res.data.data) return
-					const data = res.data.data
-					this.merchantInfo = data
-					this.cJsId = data.id
-					this.isWorking = data.nStatus2 == '0'
-					this.ratingScore = data.nStar != null ? Number(data.nStar).toFixed(1) : '0.0'
-					this.workStartTime = data.dtWorkStart || data.dtOnlineStart || null
-					this.restStartTime = data.dtRestStart || data.restStartTime || null
-					this.syncCurrentAddress(data)
-					this.fetchTodayOrders()
-					this.fetchPendingOrder()
-					this.fetchSkills()
-				})
-			},
-			fetchWalletInfo() {
-				getInfo().then(res => {
-					if (res.data.code == 200 && res.data.data) {
-						this.cJsId = res.data.data.id;
-					}
-				})
-			},
-			fetchIncome() {
-				myIncome().then(res => {
-					if (res.data.code == 200 && res.data.data) {
-						this.myIncome = res.data.data
-					}
-				})
-			},
-			fetchWorkData() {
-				getStaffWorkData({
-					openId: uni.getStorageSync('wx_copenid')
-				}).then(res => {
-					if (res.data.code == 200 && res.data.data) {
-						const minutes = res.data.data.onLine || 0
-						// this.onlineHours = (minutes / 60).toFixed(1).replace(/\.0$/, '')
-					}
-				})
-			},
-			fetchBankCards() {
-				myBank().then(res => {
-					if (res.data.code == 200 && Array.isArray(res.data.data)) {
-						// this.bankCardCount = res.data.data.length
-					}
-				})
-			},
-			fetchTodayOrders() {
-				if (!this.cJsId) return
-				getWaitOrder({
-					cJsId: this.cJsId
-				}).then(res => {
-					if (res.data.code == 200) {
-						this.todayOrderCount = res.data.data || 0
-					}
-				})
-			},
-			fetchSkills() {
-				// TODO: 接口联调后开启,当前使用假数据展示
-				return
-				const openId = uni.getStorageSync('wx_copenid')
-				if (!openId) return
-				getProjectByJsId({
-					openId
-				}).then(res => {
-					if (res.data.code == 200 && Array.isArray(res.data.data)) {
-						this.skillList = res.data.data
-					}
-				})
-			},
-			fetchPendingOrder() {
-				if (!this.cJsId) return
-				orderDeatails({
-					cJsId: this.cJsId,
-					nStatus: 0,
-					current: 1,
-					size: 1,
-				}).then(res => {
-					if (res.data.code == 200 && res.data.data?.records?.length) {
-						this.pendingOrder = res.data.data.records[0]
-						this.slideX = 0
-						this.initSlideRange()
-					} else {
-						this.pendingOrder = null
-					}
-				})
-			},
-			formatMoney(amount) {
-				const num = parseFloat(amount)
-				if (isNaN(num)) return '0.00'
-				return num.toFixed(2)
-			},
-			skillPriceUnit(item) {
-				if (item.cUnit) return `/${item.cUnit}`
-				if (item.nMinute) return '/小时'
-				return ''
-			},
-			formatOrderTime(timeStr) {
-				if (!timeStr) return ''
-				const str = String(timeStr)
-				const d = new Date(str.replace(/-/g, '/'))
-				if (Number.isNaN(d.getTime())) return str
-				const m = d.getMonth() + 1
-				const day = d.getDate()
-				const hh = String(d.getHours()).padStart(2, '0')
-				const mm = String(d.getMinutes()).padStart(2, '0')
-				if (str.includes('-') && str.length > 16) {
-					const end = str.slice(11, 16)
-					if (end && end !== `${hh}:${mm}`) {
-						return `${m}月${day}日 ${hh}:${mm}至${end}`
-					}
+			})
+		},
+		fetchWorkData() {
+			getStaffWorkData({
+				openId: uni.getStorageSync('wx_copenid')
+			}).then(res => {
+				if (res.data.code == 200 && res.data.data) {
+					const minutes = res.data.data.onLine || 0
+					// this.onlineHours = (minutes / 60).toFixed(1).replace(/\.0$/, '')
 				}
-				return `${m}月${day}日 ${hh}:${mm}`
-			},
-			getStatusDurationHours(type) {
-				const since =
-					type === 'working' ?
+			})
+		},
+		fetchBankCards() {
+			myBank().then(res => {
+				if (res.data.code == 200 && Array.isArray(res.data.data)) {
+					// this.bankCardCount = res.data.data.length
+				}
+			})
+		},
+		fetchTodayOrders() {
+			if (!this.cJsId) return
+			getWaitOrder({
+				cJsId: this.cJsId
+			}).then(res => {
+				if (res.data.code == 200) {
+					this.todayOrderCount = res.data.data || 0
+				}
+			})
+		},
+		fetchSkills() {
+			// TODO: 接口联调后开启,当前使用假数据展示
+			return
+			const openId = uni.getStorageSync('wx_copenid')
+			if (!openId) return
+			getProjectByJsId({
+				openId
+			}).then(res => {
+				if (res.data.code == 200 && Array.isArray(res.data.data)) {
+					this.skillList = res.data.data
+				}
+			})
+		},
+		fetchPendingOrder() {
+			if (!this.cJsId) return
+			orderDeatails({
+				cJsId: this.cJsId,
+				nStatus: 0,
+				current: 1,
+				size: 1,
+			}).then(res => {
+				if (res.data.code == 200 && res.data.data?.records?.length) {
+					this.pendingOrder = res.data.data.records[0]
+					this.slideX = 0
+					this.initSlideRange()
+				} else {
+					this.pendingOrder = null
+				}
+			})
+		},
+		formatMoney(amount) {
+			const num = parseFloat(amount)
+			if (isNaN(num)) return '0.00'
+			return num.toFixed(2)
+		},
+		skillPriceUnit(item) {
+			if (item.cUnit) return `/ ${ item.cUnit } `
+			if (item.nMinute) return '/小时'
+			return ''
+		},
+		formatOrderTime(timeStr) {
+			if (!timeStr) return ''
+			const str = String(timeStr)
+			const d = new Date(str.replace(/-/g, '/'))
+			if (Number.isNaN(d.getTime())) return str
+			const m = d.getMonth() + 1
+			const day = d.getDate()
+			const hh = String(d.getHours()).padStart(2, '0')
+			const mm = String(d.getMinutes()).padStart(2, '0')
+			if (str.includes('-') && str.length > 16) {
+				const end = str.slice(11, 16)
+				if (end && end !== `${ hh }:${ mm } `) {
+					return `${ m }月${ day }日 ${ hh }:${ mm }至${ end } `
+				}
+			}
+			return `${ m }月${ day }日 ${ hh }:${ mm } `
+		},
+		getStatusDurationHours(type) {
+			const since =
+				type === 'working' ?
 					this.workStartTime :
 					this.restStartTime
-				if (!since) return 0
-				const start = new Date(String(since).replace(/-/g, '/')).getTime()
-				if (Number.isNaN(start)) return 0
-				return Math.max(0, Math.floor((Date.now() - start) / 3600000))
-			},
-			getStatusDesc(type) {
-				const isCurrent =
-					type === 'working' ? this.isWorking : !this.isWorking
-				if (isCurrent) {
-					const hours = this.getStatusDurationHours(type)
-					if (type === 'working') {
-						return `已连续辛勤工作${hours}个小时`
-					}
-					return `已休息${hours}个小时`
-				}
+			if (!since) return 0
+			const start = new Date(String(since).replace(/-/g, '/')).getTime()
+			if (Number.isNaN(start)) return 0
+			return Math.max(0, Math.floor((Date.now() - start) / 3600000))
+		},
+		getStatusDesc(type) {
+			const isCurrent =
+				type === 'working' ? this.isWorking : !this.isWorking
+			if (isCurrent) {
+				const hours = this.getStatusDurationHours(type)
 				if (type === 'working') {
-					return '早起的人已经接单,勤奋的人账户常满'
+					return `已连续辛勤工作${ hours } 个小时`
 				}
-				return '今日辛苦啦,早点下线休息,注意劳逸结合!'
-			},
-			openStatusPopup() {
-				this.statusDraft = this.isWorking ? 'working' : 'rest'
-				this.showStatusPopup = true
-			},
-			confirmStatusChange() {
-				const wantWorking = this.statusDraft === 'working'
-				this.showStatusPopup = false
-				if (wantWorking === this.isWorking) return
-				this.updateWorkStatus(wantWorking)
+				return `已休息${ hours } 个小时`
+			}
+			if (type === 'working') {
+				return '早起的人已经接单,勤奋的人账户常满'
+			}
+			return '今日辛苦啦,早点下线休息,注意劳逸结合!'
+		},
+		openStatusPopup() {
+			this.statusDraft = this.isWorking ? 'working' : 'rest'
+			this.showStatusPopup = true
+		},
+		confirmStatusChange() {
+			const wantWorking = this.statusDraft === 'working'
+			this.showStatusPopup = false
+			if (wantWorking === this.isWorking) return
+			this.updateWorkStatus(wantWorking)
 
-			},
-			updateWorkStatus(working) {
-				if (!this.cJsId) {
-					uni.showToast({
-						title: '请先登录',
-						icon: 'none'
-					})
-					return
-				}
-				switchToOffline({
-					userId: this.cJsId,
-					forceConfirm: working,
-				}).then(res => {
-					if (res.data.code == 200) {
-						this.isWorking = working
-						const now = new Date().toISOString()
-						if (working) {
-							this.workStartTime = now
-						} else {
-							this.restStartTime = now
-						}
-						uni.showToast({
-							title: working ? '已上线' : '已下线',
-							icon: 'none'
-						})
+		},
+		updateWorkStatus(working) {
+			if (!this.cJsId) {
+				uni.showToast({
+					title: '请先登录',
+					icon: 'none'
+				})
+				return
+			}
+			switchToOffline({
+				userId: this.cJsId,
+				forceConfirm: working,
+			}).then(res => {
+				if (res.data.code == 200) {
+					this.isWorking = working
+					const now = new Date().toISOString()
+					if (working) {
+						this.workStartTime = now
 					} else {
-						uni.showToast({
-							title: res.data.msg || '设置失败',
-							icon: 'none'
-						})
+						this.restStartTime = now
 					}
-				})
-			},
-			async onRejectOrder() {
-				this.auditStatus = await this.checkMerchantStatus()
-				if(this.auditStatus == 0 || this.auditStatus == 3){
-					this.showModal = true
-					return
-				}
-				if(this.auditStatus == 1){
 					uni.showToast({
-						title: '入驻审核中,暂无操作权限',
+						title: working ? '已上线' : '已下线',
 						icon: 'none'
 					})
-					return	
-					
-				}
-				this.showRejectPopup = true
-				this.rejectReason = ''
-			},
-			closeRejectPopup() {
-				this.showRejectPopup = false
-				this.rejectReason = ''
-			},
-			submitReject() {
-				const reason = this.rejectReason.trim()
-				if (!reason) {
+				} else {
 					uni.showToast({
-						title: '拒绝原因不能为空',
+						title: res.data.msg || '设置失败',
 						icon: 'none'
 					})
-					return
 				}
-				refuseOrder({
-					cId: this.pendingOrder.cId,
-					reasonRefusal: reason,
-				}).then(res => {
-					if (res.data.code == 200) {
-						uni.showToast({
-							title: '已拒绝',
-							icon: 'none'
-						})
-						this.closeRejectPopup()
-						this.pendingOrder = null
-						this.fetchTodayOrders()
-					} else {
-						uni.showToast({
-							title: res.data.msg || '操作失败',
-							icon: 'none'
-						})
-					}
+			})
+		},
+		async onRejectOrder() {
+			this.auditStatus = await this.checkMerchantStatus()
+			if (this.auditStatus == 0 || this.auditStatus == 3) {
+				this.showModal = true
+				return
+			}
+			if (this.auditStatus == 1) {
+				uni.showToast({
+					title: '入驻审核中,暂无操作权限',
+					icon: 'none'
 				})
-			},
-			initSlideRange() {
-				this.$nextTick(() => {
-					const query = uni.createSelectorQuery().in(this)
-					query.select('.slide-track').boundingClientRect()
-					query.select('.slide-thumb').boundingClientRect()
-					query.exec(res => {
-						const trackRect = res[0]
-						const thumbRect = res[1]
-						if (trackRect && thumbRect) {
-							this.slideMax = Math.max(0, trackRect.width - thumbRect.width)
-						}
-					})
+				return
+
+			}
+			this.showRejectPopup = true
+			this.rejectReason = ''
+		},
+		closeRejectPopup() {
+			this.showRejectPopup = false
+			this.rejectReason = ''
+		},
+		submitReject() {
+			const reason = this.rejectReason.trim()
+			if (!reason) {
+				uni.showToast({
+					title: '拒绝原因不能为空',
+					icon: 'none'
 				})
-			},
-			async onSlideStart(e) {
-				this.auditStatus = await this.checkMerchantStatus()
-				if(this.auditStatus == 0 || this.auditStatus == 3){
-					this.showModal = true
-					return
-				}
-				if(this.auditStatus == 1){
+				return
+			}
+			refuseOrder({
+				cId: this.pendingOrder.cId,
+				reasonRefusal: reason,
+			}).then(res => {
+				if (res.data.code == 200) {
 					uni.showToast({
-						title: '入驻审核中,暂无操作权限',
+						title: '已拒绝',
+						icon: 'none'
+					})
+					this.closeRejectPopup()
+					this.pendingOrder = null
+					this.fetchTodayOrders()
+				} else {
+					uni.showToast({
+						title: res.data.msg || '操作失败',
 						icon: 'none'
 					})
-					return	
-					
-				}
-				this.isSliding = true
-				this.slideStartX = e.touches[0].clientX - this.slideX
-				this.initSlideRange()
-			},
-			onSlideMove(e) {
-				if (!this.isSliding) return
-				let x = e.touches[0].clientX - this.slideStartX
-				if (x < 0) x = 0
-				if (x > this.slideMax) x = this.slideMax
-				this.slideX = x
-			},
-			onSlideEnd() {
-				if (!this.isSliding) return
-				this.isSliding = false
-				if (this.slideX >= this.slideMax * 0.85) {
-					this.acceptOrder()
 				}
-				this.slideX = 0
-			},
-			acceptOrder() {
-				if (!this.pendingOrder) return
-				uni.showToast({
-					title: '接单失败',
-					icon: 'none'
-				})
-				return;
-				takeOrder({
-					cId: this.pendingOrder.cId
-				}).then(res => {
-					if (res.data.code == 200) {
-						uni.showToast({
-							title: '已接单',
-							icon: 'none'
-						})
-						this.pendingOrder = null
-						this.fetchTodayOrders()
-					} else {
-						uni.showToast({
-							title: res.data.msg || '接单失败',
-							icon: 'none'
-						})
+			})
+		},
+		initSlideRange() {
+			this.$nextTick(() => {
+				const query = uni.createSelectorQuery().in(this)
+				query.select('.slide-track').boundingClientRect()
+				query.select('.slide-thumb').boundingClientRect()
+				query.exec(res => {
+					const trackRect = res[0]
+					const thumbRect = res[1]
+					if (trackRect && thumbRect) {
+						this.slideMax = Math.max(0, trackRect.width - thumbRect.width)
 					}
 				})
-			},
-			goProfile() {
-				uni.navigateTo({
-					url: '/pages/my/indent?title=编辑资料'
-				})
-			},
-			goTodayOrders() {
-				uni.navigateTo({
-					url: '/pages/my/js_order'
-				})
-			},
-			goBankList() {
-				uni.navigateTo({
-					url: '/workbench/bank/index'
-				})
-			},
-			goReviewList() {
-				uni.navigateTo({
-					url: '/workbench/rating/index'
+			})
+		},
+		async onSlideStart(e) {
+			this.auditStatus = await this.checkMerchantStatus()
+			if (this.auditStatus == 0 || this.auditStatus == 3) {
+				this.showModal = true
+				return
+			}
+			if (this.auditStatus == 1) {
+				uni.showToast({
+					title: '入驻审核中,暂无操作权限',
+					icon: 'none'
 				})
-			},
-			async goWithdraw() {
-				this.auditStatus = await this.checkMerchantStatus()
-				if(this.auditStatus == 0 || this.auditStatus == 3){
-					this.showModal = true
-					return
-				}
-				if(this.auditStatus == 1){
+				return
+
+			}
+			this.isSliding = true
+			this.slideStartX = e.touches[0].clientX - this.slideX
+			this.initSlideRange()
+		},
+		onSlideMove(e) {
+			if (!this.isSliding) return
+			let x = e.touches[0].clientX - this.slideStartX
+			if (x < 0) x = 0
+			if (x > this.slideMax) x = this.slideMax
+			this.slideX = x
+		},
+		onSlideEnd() {
+			if (!this.isSliding) return
+			this.isSliding = false
+			if (this.slideX >= this.slideMax * 0.85) {
+				this.acceptOrder()
+			}
+			this.slideX = 0
+		},
+		acceptOrder() {
+			if (!this.pendingOrder) return
+			uni.showToast({
+				title: '接单失败',
+				icon: 'none'
+			})
+			return;
+			takeOrder({
+				cId: this.pendingOrder.cId
+			}).then(res => {
+				if (res.data.code == 200) {
+					uni.showToast({
+						title: '已接单',
+						icon: 'none'
+					})
+					this.pendingOrder = null
+					this.fetchTodayOrders()
+				} else {
 					uni.showToast({
-						title: '入驻审核中,暂无操作权限',
+						title: res.data.msg || '接单失败',
 						icon: 'none'
 					})
-					return	
-					
 				}
-				uni.navigateTo({
-					url: '/workbench/withdraw/apply'
-				})
-			},
-			goIncome() {
-				uni.navigateTo({
-					url: '/workbench/income/index'
-				})
-			},
-			goWithdrawRecord() {
-				uni.navigateTo({
-					url: '/workbench/withdraw/record'
-				})
-			},
-			goSkillManage() {
-				uni.navigateTo({
-					url: `/workbench/skill/index?serviceTag=${this.serviceTag}`
+			})
+		},
+		goProfile() {
+			uni.navigateTo({
+				url: '/pages/my/indent?title=编辑资料'
+			})
+		},
+		goTodayOrders() {
+			uni.navigateTo({
+				url: '/pages/my/js_order'
+			})
+		},
+		goBankList() {
+			uni.navigateTo({
+				url: '/workbench/bank/index'
+			})
+		},
+		goReviewList() {
+			uni.navigateTo({
+				url: '/workbench/rating/index'
+			})
+		},
+		async goWithdraw() {
+			this.auditStatus = await this.checkMerchantStatus()
+			if (this.auditStatus == 0 || this.auditStatus == 3) {
+				this.showModal = true
+				return
+			}
+			if (this.auditStatus == 1) {
+				uni.showToast({
+					title: '入驻审核中,暂无操作权限',
+					icon: 'none'
 				})
-			},
-			syncCurrentAddress(merchantData) {
-				const sl = uni.getStorageSync('staffLocation')
-				if (sl?.address || sl?.name) {
-					this.currentAddress = `${sl.address || ''}${sl.name || ''}`
-					return
-				}
-				const data = merchantData || this.merchantInfo
-				this.currentAddress = data?.address || data?.name || ''
-			},
-			goSwitchAddress() {
-				uni.chooseLocation({
-					success: (res) => {
-						console.log('切换地址', res)
+				return
 
-					}
-				});
-			},
-			async goUpdateAddress() {
-				// if (!this.cJsId) {
-				// 	uni.showToast({ title: '请先登录', icon: 'none' })
-				// 	return
-				// }
-				try {
-					const res = await this.$utils.addressService.chooseLocation()
-					const params = {
-						id: this.cJsId,
-						cPhone: this.merchantInfo.cPhone,
+			}
+			uni.navigateTo({
+				url: '/workbench/withdraw/apply'
+			})
+		},
+		goIncome() {
+			uni.navigateTo({
+				url: '/workbench/income/index'
+			})
+		},
+		goWithdrawRecord() {
+			uni.navigateTo({
+				url: '/workbench/withdraw/record'
+			})
+		},
+		goSkillManage() {
+			uni.navigateTo({
+				url: `/ workbench / skill / index ? serviceTag = ${ this.serviceTag } `
+			})
+		},
+		syncCurrentAddress(merchantData) {
+			const sl = uni.getStorageSync('staffLocation')
+			if (sl?.address || sl?.name) {
+				this.currentAddress = `${ sl.address || '' }${ sl.name || '' } `
+				return
+			}
+			const data = merchantData || this.merchantInfo
+			this.currentAddress = data?.address || data?.name || ''
+		},
+		goSwitchAddress() {
+			uni.chooseLocation({
+				success: (res) => {
+					console.log('切换地址', res)
+
+				}
+			});
+		},
+		async goUpdateAddress() {
+			// if (!this.cJsId) {
+			// 	uni.showToast({ title: '请先登录', icon: 'none' })
+			// 	return
+			// }
+			try {
+				const res = await this.$utils.addressService.chooseLocation()
+				const params = {
+					id: this.cJsId,
+					cPhone: this.merchantInfo.cPhone,
+					name: res.name,
+					address: res.address,
+					latitude: res.latitude,
+					longitude: res.longitude,
+					cOpenId: uni.getStorageSync('wx_copenid'),
+				}
+				const apiRes = await getJsLocation(params)
+				if (apiRes.data.code == 200) {
+					uni.setStorageSync('staffLocation', {
 						name: res.name,
 						address: res.address,
 						latitude: res.latitude,
 						longitude: res.longitude,
-						cOpenId: uni.getStorageSync('wx_copenid'),
-					}
-					const apiRes = await getJsLocation(params)
-					if (apiRes.data.code == 200) {
-						uni.setStorageSync('staffLocation', {
-							name: res.name,
-							address: res.address,
-							latitude: res.latitude,
-							longitude: res.longitude,
-						})
-						this.syncCurrentAddress()
-						uni.showToast({
-							title: '地址已更新',
-							icon: 'none'
-						})
-					} else {
-						uni.showToast({
-							title: apiRes.data.msg || '更新失败',
-							icon: 'none'
-						})
-					}
-				} catch (err) {
-					if (err?.cancelled) return
+					})
+					this.syncCurrentAddress()
 					uni.showToast({
-						title: err?.message || '获取位置失败',
+						title: '地址已更新',
 						icon: 'none'
 					})
-				}
-			},
-			onMoreFeature(item) {
-				if (!item.path) {
+				} else {
 					uni.showToast({
-						title: '功能开发中',
+						title: apiRes.data.msg || '更新失败',
 						icon: 'none'
 					})
-					return
 				}
-				uni.navigateTo({
-					url: item.path
+			} catch (err) {
+				if (err?.cancelled) return
+				uni.showToast({
+					title: err?.message || '获取位置失败',
+					icon: 'none'
 				})
-			},
+			}
 		},
-	}
-</script>
-<style scoped>
-	.uni-modal{
-		background: #eb0000!important;
-		border-radius: 16rpx!important;
-	}
-	</style>
-
-<style lang="scss" scoped>
-	$primary: #1ecbc3;
-	$primary-dark: #0fa89e;
-	$text-main: #333333;
-	$text-sub: #999999;
-	$page-bg: #f6f7f9;
-
-	.workbench {
-		min-height: 100vh;
-		background: $page-bg;
-		position: relative;
-		box-sizing: border-box;
-	}
-
-	.page-bg {
-		position: absolute;
-		top: -170rpx;
-		left: 0;
-		width: 100%;
-		z-index: 0;
-		height: 420rpx;
-	}
-
-	.page-content {
-		position: relative;
-		z-index: 1;
-		padding: 20rpx 24rpx 40rpx;
-		box-sizing: border-box;
-	}
-
-	.card {
-		background: #ffffff;
-		border-radius: 24rpx;
-		margin-bottom: 24rpx;
-		padding: 28rpx 24rpx;
-		box-sizing: border-box;
-		box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.04);
-	}
-
-	.card-address {
-		background: #ffffff;
-		border-radius: 24rpx;
-		margin-bottom: 24rpx;
-		padding: 28rpx 24rpx 0 24rpx;
-		box-sizing: border-box;
-		box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.04);
-	}
-
-	/* 头部 */
-	.header-section {
-		padding: 16rpx 8rpx 32rpx;
-	}
-
-	.header-main {
-		display: flex;
-		align-items: center;
-	}
-
-	.avatar-wrap {
-		width: 112rpx;
-		height: 112rpx;
-		border-radius: 50%;
-		border: 4rpx solid rgba(255, 255, 255, 0.8);
-		overflow: hidden;
-		background: #eee;
-		flex-shrink: 0;
-		box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
-	}
-
-	.avatar {
-		width: 100%;
-		height: 100%;
-	}
-
-	.header-info {
-		margin-left: 24rpx;
-		flex: 1;
-		min-width: 0;
-	}
-
-	.nickname {
-		font-size: 36rpx;
-		color: $text-main;
-		font-weight: 600;
-		line-height: 1.4;
-	}
-
-	.status-bar {
-		display: flex;
-		align-items: center;
-		gap: 16rpx;
-		margin-top: 16rpx;
-	}
-
-	.status-tag {
-		display: flex;
-		align-items: center;
-		padding: 6rpx 16rpx;
-		font-size: 22rpx;
-		border-radius: 24rpx;
-		color: #1D2129;
-		background: linear-gradient(263deg, #45FFD7 0%, #78FFA5 100%);
-	}
-
-	.status-tag-icon {
-		width: 24rpx;
-		height: 24rpx;
-		margin-right: 6rpx;
-	}
-
-	.status-select {
-		display: flex;
-		align-items: center;
-		padding: 6rpx 16rpx;
-		font-size: 22rpx;
-		border-radius: 24rpx;
-		color: $text-main;
-		background: rgba(255, 255, 255, 0.9);
-	}
-
-	.status-arrow {
-		width: 20rpx;
-		height: 20rpx;
-		margin-left: 6rpx;
-	}
-
-	/* 统计栏 */
-	.stats-section {
-		display: flex;
-		justify-content: space-between;
-		padding: 32rpx 16rpx;
-	}
-
-	.stat-item {
-		flex: 1;
-		text-align: center;
-	}
-
-	.stat-value {
-		font-size: 36rpx;
-		color: $text-main;
-		font-weight: 600;
-		line-height: 1.4;
-	}
+		onMoreFeature(item) {
+			if (item.label == '退出登录') {
+				this.showModal2 = true
+				return
+			}
+			if (!item.path) {
+				uni.showToast({
+					title: '功能开发中',
+					icon: 'none'
+				})
+				return
+			}
+			uni.navigateTo({
+				url: item.path
+			})
+		},
+		// 退出登录
+		goLogout() {
+			this.$router.go(0)
+			logout().then(res => {
+				if (res.data.code == 200) {
+					this.showModal2 = false
+					uni.removeStorageSync('access-token')
+					this.$router.go(0)
+					uni.showToast({
+						title: '已退出登录',
+						icon: 'none'
+					})
+				} else {
+					this.showModal2 = false
+				}
+			});
 
-	.stat-label {
-		font-size: 22rpx;
-		color: $text-sub;
-		margin-top: 10rpx;
-	}
+		},
+		// 获取管理按钮坐标,生成镂空引导
+		getManageBtnRect() {
+			const query = uni.createSelectorQuery().in(this)
+			query.select('.section-link')
+				.boundingClientRect(res => {
+					if (!res) return
+					const { top, left, width, height } = res
+					// 镂空挖空样式,遮罩全覆盖只透出按钮
+					this.holeStyle = {
+						position: 'fixed',
+						top: `${top}px`,
+						left: `${left}px`,
+						width: `${width}px`,
+						height: `${height}px`,
+						borderRadius: '12rpx',
+						boxShadow: '0 0 0 9999px rgba(0,0,0,0.65)',
+						zIndex: 99999
+					}
+					// 气泡定位:按钮左上方
+					this.tipPopStyle = {
+						position: 'fixed',
+						top: `${top - 120}px`,
+						left: `${left - 620}rpx
+					}`,
+				background: '#fff',
+				padding: '24rpx',
+				borderRadius: '16rpx',
+				maxWidth: '580rpx',
+				zIndex: 100000
+			}
+			this.showSkillGuide = true
+			}).exec()
+		},
+		// 关闭引导并永久标记完成
+		closeSkillGuide() {
+		this.showSkillGuide = false
+		uni.setStorageSync('merchant_skill_manage_guide', 'done')
+		},
+	},
+}
+</script>
+<style scoped>
+.uni-modal {
+	background: #eb0000 !important;
+	border-radius: 16rpx !important;
+}
+</style>
 
-	.unit {
-		font-size: 24rpx;
-		font-weight: 400;
-		margin-left: 2rpx;
-	}
+<style lang="scss" scoped>
+$primary: #1ecbc3;
+$primary-dark: #0fa89e;
+$text-main: #333333;
+$text-sub: #999999;
+$page-bg: #f6f7f9;
+
+// 新手引导全局遮罩
+.guide-full-mask {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100vw;
+  height: 100vh;
+  z-index: 99998;
+}
+.guide-tip-pop {
+  font-size: 26rpx;
+  color: #333;
+  line-height: 1.6;
+  position: relative;
+}
+.guide-hand {
+  position: absolute;
+  right: -50rpx;
+  bottom: -40rpx;
+  font-size: 50rpx;
+  pointer-events: none;
+}
+
+.workbench {
+	min-height: 100vh;
+	background: $page-bg;
+	position: relative;
+	box-sizing: border-box;
+}
+
+.page-bg {
+	position: absolute;
+	top: -170rpx;
+	left: 0;
+	width: 100%;
+	z-index: 0;
+	height: 420rpx;
+}
+
+.page-content {
+	position: relative;
+	z-index: 1;
+	padding: 20rpx 24rpx 40rpx;
+	box-sizing: border-box;
+}
+
+.card {
+	background: #ffffff;
+	border-radius: 24rpx;
+	margin-bottom: 24rpx;
+	padding: 28rpx 24rpx;
+	box-sizing: border-box;
+	box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.04);
+}
+
+.card-address {
+	background: #ffffff;
+	border-radius: 24rpx;
+	margin-bottom: 24rpx;
+	padding: 28rpx 24rpx 0 24rpx;
+	box-sizing: border-box;
+	box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.04);
+}
+
+/* 头部 */
+.header-section {
+	padding: 16rpx 8rpx 32rpx;
+}
+
+.header-main {
+	display: flex;
+	align-items: center;
+}
+
+.avatar-wrap {
+	width: 112rpx;
+	height: 112rpx;
+	border-radius: 50%;
+	border: 4rpx solid rgba(255, 255, 255, 0.8);
+	overflow: hidden;
+	background: #eee;
+	flex-shrink: 0;
+	box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
+}
+
+.avatar {
+	width: 100%;
+	height: 100%;
+}
+
+.header-info {
+	margin-left: 24rpx;
+	flex: 1;
+	min-width: 0;
+}
+
+.nickname {
+	font-size: 36rpx;
+	color: $text-main;
+	font-weight: 600;
+	line-height: 1.4;
+}
+
+.status-bar {
+	display: flex;
+	align-items: center;
+	gap: 16rpx;
+	margin-top: 16rpx;
+}
+
+.status-tag {
+	display: flex;
+	align-items: center;
+	padding: 6rpx 16rpx;
+	font-size: 22rpx;
+	border-radius: 24rpx;
+	color: #1D2129;
+	background: linear-gradient(263deg, #45FFD7 0%, #78FFA5 100%);
+}
+
+.status-tag-icon {
+	width: 24rpx;
+	height: 24rpx;
+	margin-right: 6rpx;
+}
+
+.status-select {
+	display: flex;
+	align-items: center;
+	padding: 6rpx 16rpx;
+	font-size: 22rpx;
+	border-radius: 24rpx;
+	color: $text-main;
+	background: rgba(255, 255, 255, 0.9);
+}
+
+.status-arrow {
+	width: 20rpx;
+	height: 20rpx;
+	margin-left: 6rpx;
+}
+
+/* 统计栏 */
+.stats-section {
+	display: flex;
+	justify-content: space-between;
+	padding: 32rpx 16rpx;
+}
+
+.stat-item {
+	flex: 1;
+	text-align: center;
+}
+
+.stat-value {
+	font-size: 36rpx;
+	color: $text-main;
+	font-weight: 600;
+	line-height: 1.4;
+}
+
+.stat-label {
+	font-size: 22rpx;
+	color: $text-sub;
+	margin-top: 10rpx;
+}
+
+.unit {
+	font-size: 24rpx;
+	font-weight: 400;
+	margin-left: 2rpx;
+}
+
+/* 钱包 */
+.wallet-section {
+	padding: 32rpx 32rpx;
+	background: radial-gradient(109.56% 48.07% at 10.06% 5%, #E7FDF9 0%, #FFFFFF 100%), #FFFFFF;
+}
+
+.balance-row {
+	display: flex;
+	align-items: center;
+	justify-content: space-between;
+	padding-bottom: 28rpx;
+}
+
+.balance-main {
+	display: flex;
+	flex-direction: column;
+}
+
+.balance-amount {
+	font-size: 56rpx;
+	font-weight: 700;
+	color: $text-main;
+	line-height: 1.2;
+	font-family: DIN, 'Helvetica Neue', sans-serif;
+}
+
+.balance-label {
+	font-size: 24rpx;
+	color: $text-sub;
+	margin-top: 8rpx;
+}
+
+.withdraw-btn {
+	padding: 16rpx 48rpx;
+	background: linear-gradient(90deg, #3dd9cf 0%, #1ecbc3 100%);
+	border-radius: 40rpx;
+	font-size: 28rpx;
+	color: #ffffff;
+	font-weight: 500;
+	flex-shrink: 0;
+	box-shadow: 0 8rpx 20rpx rgba(30, 203, 195, 0.35);
+}
+
+.wallet-grid {
+	display: flex;
+	justify-content: space-between;
+}
+
+.wallet-item {
+	text-align: center;
+}
+
+.wallet-value {
+	font-size: 28rpx;
+	color: $text-main;
+	font-weight: 600;
+	line-height: 1.4;
+}
+
+.wallet-label {
+	font-size: 22rpx;
+	color: $text-sub;
+	margin-top: 10rpx;
+}
+
+/* 新订单 */
+.order-section {
+	margin-bottom: 24rpx;
+	border-radius: 24rpx;
+	overflow: hidden;
+	background: #1D2129;
+	box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.04);
+}
+
+.order-header {
+	position: relative;
+	height: 88rpx;
+
+	.order-header-bg {
+		position: absolute;
+		right: 0;
+		bottom: -10rpx;
 
-	/* 钱包 */
-	.wallet-section {
-		padding: 32rpx 32rpx;
-		background: radial-gradient(109.56% 48.07% at 10.06% 5%, #E7FDF9 0%, #FFFFFF 100%), #FFFFFF;
+		image {
+			width: 410rpx;
+			height: 50rpx;
+		}
 	}
-
-	.balance-row {
+}
+
+
+
+.order-header-content {
+	position: relative;
+	z-index: 1;
+	display: flex;
+	align-items: center;
+	height: 100%;
+	padding: 0 28rpx;
+	font-size: 28rpx;
+	color: #45FFD7;
+	font-weight: 500;
+}
+
+.order-bell {
+	width: 36rpx;
+	height: 36rpx;
+	margin-right: 12rpx;
+}
+
+.order-card {
+	background-color: #fff;
+	margin: 4rpx;
+	border-radius: 24rpx;
+	padding: 28rpx 24rpx 32rpx;
+}
+
+.order-title-row {
+	display: flex;
+	align-items: center;
+	justify-content: space-between;
+	gap: 16rpx;
+}
+
+.order-title {
+	flex: 1;
+	font-size: 32rpx;
+	color: #1D2129;
+	font-weight: 600;
+	line-height: 1.5;
+}
+
+.tag-new {
+	font-size: 28rpx;
+	color: #FF8D2F;
+}
+
+.order-time,
+.order-address {
+	display: flex;
+	align-items: center;
+	font-size: 28rpx;
+	color: #1D2129;
+	margin-top: 10rpx;
+	line-height: 1.6;
+}
+
+.order-icon {
+	width: 28rpx;
+	height: 28rpx;
+	margin-right: 12rpx;
+	margin-top: 4rpx;
+	flex-shrink: 0;
+}
+
+.order-actions {
+	display: flex;
+	align-items: center;
+	gap: 20rpx;
+	margin-top: 32rpx;
+}
+
+.reject-btn {
+	width: 128rpx;
+	height: 88rpx;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	font-size: 26rpx;
+	color: #333333;
+
+	background: rgba(255, 141, 47, 0.12);
+	border-radius: 2000rpx 2000rpx 2000rpx 2000rpx;
+	border: 1rpx solid #FF8D2F;
+}
+
+.slide-wrap {
+	flex: 1;
+}
+
+.slide-track {
+	position: relative;
+	height: 96rpx;
+	background: linear-gradient(263deg, #45FFD7 0%, #7FFFBD 100%), #1D2129;
+	border-radius: 48rpx;
+	overflow: hidden;
+	box-shadow: 0 8rpx 20rpx rgba(30, 203, 195, 0.3);
+}
+
+.slide-hint {
+	position: absolute;
+	left: 0;
+	right: 80rpx;
+	top: 0;
+	bottom: 0;
+	line-height: 96rpx;
+	text-align: center;
+	font-size: 28rpx;
+	color: #000;
+	font-weight: 500;
+	pointer-events: none;
+}
+
+.slide-thumb {
+	position: absolute;
+	left: 0;
+	top: 0;
+	width: 96rpx;
+	height: 96rpx;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	// background: rgba(255, 255, 255, 0.35);
+	border-radius: 50%;
+	z-index: 1;
+}
+
+.slide-thumb .slide-arrow {
+	width: 40rpx;
+	height: 40rpx;
+}
+
+/* 技能 */
+.skills-section {
+	.section-header {
 		display: flex;
 		align-items: center;
 		justify-content: space-between;
-		padding-bottom: 28rpx;
-	}
-
-	.balance-main {
-		display: flex;
-		flex-direction: column;
-	}
-
-	.balance-amount {
-		font-size: 56rpx;
-		font-weight: 700;
-		color: $text-main;
-		line-height: 1.2;
-		font-family: DIN, 'Helvetica Neue', sans-serif;
-	}
-
-	.balance-label {
-		font-size: 24rpx;
-		color: $text-sub;
-		margin-top: 8rpx;
-	}
-
-	.withdraw-btn {
-		padding: 16rpx 48rpx;
-		background: linear-gradient(90deg, #3dd9cf 0%, #1ecbc3 100%);
-		border-radius: 40rpx;
-		font-size: 28rpx;
-		color: #ffffff;
-		font-weight: 500;
-		flex-shrink: 0;
-		box-shadow: 0 8rpx 20rpx rgba(30, 203, 195, 0.35);
+		margin-bottom: 24rpx;
 	}
 
-	.wallet-grid {
+	.section-heading-wrap {
 		display: flex;
-		justify-content: space-between;
-	}
-
-	.wallet-item {
-		text-align: center;
-	}
-
-	.wallet-value {
-		font-size: 28rpx;
-		color: $text-main;
-		font-weight: 600;
-		line-height: 1.4;
-	}
-
-	.wallet-label {
-		font-size: 22rpx;
-		color: $text-sub;
-		margin-top: 10rpx;
-	}
-
-	/* 新订单 */
-	.order-section {
-		margin-bottom: 24rpx;
-		border-radius: 24rpx;
-		overflow: hidden;
-		background: #1D2129;
-		box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.04);
+		align-items: flex-start;
 	}
 
-	.order-header {
+	.section-heading-box {
 		position: relative;
-		height: 88rpx;
-
-		.order-header-bg {
-			position: absolute;
-			right: 0;
-			bottom: -10rpx;
-
-			image {
-				width: 410rpx;
-				height: 50rpx;
-			}
-		}
+		display: inline-flex;
+		flex-direction: column;
 	}
 
-
-
-	.order-header-content {
+	.section-heading {
 		position: relative;
 		z-index: 1;
-		display: flex;
-		align-items: center;
-		height: 100%;
-		padding: 0 28rpx;
-		font-size: 28rpx;
-		color: #45FFD7;
-		font-weight: 500;
-	}
-
-	.order-bell {
-		width: 36rpx;
-		height: 36rpx;
-		margin-right: 12rpx;
-	}
-
-	.order-card {
-		background-color: #fff;
-		margin: 4rpx;
-		border-radius: 24rpx;
-		padding: 28rpx 24rpx 32rpx;
-	}
-
-	.order-title-row {
-		display: flex;
-		align-items: center;
-		justify-content: space-between;
-		gap: 16rpx;
-	}
-
-	.order-title {
-		flex: 1;
 		font-size: 32rpx;
 		color: #1D2129;
 		font-weight: 600;
-		line-height: 1.5;
-	}
-
-	.tag-new {
-		font-size: 28rpx;
-		color: #FF8D2F;
-	}
-
-	.order-time,
-	.order-address {
-		display: flex;
-		align-items: center;
-		font-size: 28rpx;
-		color: #1D2129;
-		margin-top: 10rpx;
-		line-height: 1.6;
+		line-height: 1.4;
+		padding-bottom: 10rpx;
+		background-image: url('/static/workbench/skill.png');
+		background-repeat: no-repeat;
+		background-size: 80%;
 	}
 
-	.order-icon {
-		width: 28rpx;
-		height: 28rpx;
-		margin-right: 12rpx;
-		margin-top: 4rpx;
+	.skill-tip {
+		width: 40rpx;
+		height: 40rpx;
+		margin-left: 8rpx;
+		margin-top: 2rpx;
 		flex-shrink: 0;
 	}
 
-	.order-actions {
-		display: flex;
-		align-items: center;
-		gap: 20rpx;
-		margin-top: 32rpx;
-	}
-
-	.reject-btn {
-		width: 128rpx;
-		height: 88rpx;
+	.section-link {
 		display: flex;
 		align-items: center;
-		justify-content: center;
-		font-size: 26rpx;
-		color: #333333;
-
-		background: rgba(255, 141, 47, 0.12);
-		border-radius: 2000rpx 2000rpx 2000rpx 2000rpx;
-		border: 1rpx solid #FF8D2F;
-	}
-
-	.slide-wrap {
-		flex: 1;
-	}
-
-	.slide-track {
-		position: relative;
-		height: 96rpx;
-		background: linear-gradient(263deg, #45FFD7 0%, #7FFFBD 100%), #1D2129;
-		border-radius: 48rpx;
-		overflow: hidden;
-		box-shadow: 0 8rpx 20rpx rgba(30, 203, 195, 0.3);
-	}
-
-	.slide-hint {
-		position: absolute;
-		left: 0;
-		right: 80rpx;
-		top: 0;
-		bottom: 0;
-		line-height: 96rpx;
-		text-align: center;
 		font-size: 28rpx;
-		color: #000;
-		font-weight: 500;
-		pointer-events: none;
-	}
-
-	.slide-thumb {
-		position: absolute;
-		left: 0;
-		top: 0;
-		width: 96rpx;
-		height: 96rpx;
-		display: flex;
-		align-items: center;
-		justify-content: center;
-		// background: rgba(255, 255, 255, 0.35);
-		border-radius: 50%;
-		z-index: 1;
-	}
-
-	.slide-thumb .slide-arrow {
-		width: 40rpx;
-		height: 40rpx;
-	}
-
-	/* 技能 */
-	.skills-section {
-		.section-header {
-			display: flex;
-			align-items: center;
-			justify-content: space-between;
-			margin-bottom: 24rpx;
-		}
-
-		.section-heading-wrap {
-			display: flex;
-			align-items: flex-start;
-		}
-
-		.section-heading-box {
-			position: relative;
-			display: inline-flex;
-			flex-direction: column;
-		}
-
-		.section-heading {
-			position: relative;
-			z-index: 1;
-			font-size: 32rpx;
-			color: #1D2129;
-			font-weight: 600;
-			line-height: 1.4;
-			padding-bottom: 10rpx;
-			background-image: url('/static/workbench/skill.png');
-			background-repeat: no-repeat;
-			background-size: 80%;
-		}
-
-		.skill-tip {
-			width: 40rpx;
-			height: 40rpx;
-			margin-left: 8rpx;
-			margin-top: 2rpx;
-			flex-shrink: 0;
-		}
-
-		.section-link {
-			display: flex;
-			align-items: center;
-			font-size: 28rpx;
-			color: #86909C;
-			flex-shrink: 0;
-		}
-
-		.link-arrow {
-			width: 30rpx;
-			height: 30rpx;
-			margin-left: 4rpx;
-		}
-	}
-
-	.skill-single {
-		width: 100%;
-	}
-
-	.skill-scroll {
-		width: 100%;
+		color: #86909C;
+		flex-shrink: 0;
 	}
 
-	.skill-list {
-		display: flex;
-		flex-direction: row;
-		flex-wrap: nowrap;
+	.link-arrow {
+		width: 30rpx;
+		height: 30rpx;
+		margin-left: 4rpx;
 	}
+}
 
-	.skill-card {
-		display: flex;
-		align-items: center;
-		padding: 16rpx;
-		border: 1rpx solid #eeeeee;
-		border-radius: 16rpx;
-		background: #ffffff;
-		box-sizing: border-box;
-	}
+.skill-single {
+	width: 100%;
+}
 
-	.skill-card--single {
-		width: 100%;
+.skill-scroll {
+	width: 100%;
+}
 
-		.skill-img {
-			width: 160rpx;
-			height: 160rpx;
-			margin-right: 20rpx;
-		}
-	}
+.skill-list {
+	display: flex;
+	flex-direction: row;
+	flex-wrap: nowrap;
+}
 
-	.skill-card--multi {
-		flex-shrink: 0;
-		width: 380rpx;
-		margin-right: 20rpx;
+.skill-card {
+	display: flex;
+	align-items: center;
+	padding: 16rpx;
+	border: 1rpx solid #eeeeee;
+	border-radius: 16rpx;
+	background: #ffffff;
+	box-sizing: border-box;
+}
 
-		&:last-child {
-			margin-right: 0;
-		}
-	}
+.skill-card--single {
+	width: 100%;
 
 	.skill-img {
-		width: 88rpx;
-		height: 88rpx;
-		background: #f5f5f5;
-		border-radius: 10rpx;
-		overflow: hidden;
-		flex-shrink: 0;
-		margin-right: 14rpx;
-
-		image {
-			width: 100%;
-			height: 100%;
-		}
-	}
-
-	.skill-info {
-		flex: 1;
-		min-width: 0;
-		display: flex;
-		flex-direction: column;
-		justify-content: center;
-	}
-
-	.skill-name {
-		font-size: 28rpx;
-		color: $text-main;
-		margin-bottom: 8rpx;
-		font-weight: 500;
-		line-height: 1.3;
-	}
-
-	.skill-tags {
-		display: flex;
-		flex-wrap: wrap;
-		gap: 8rpx;
-		margin-bottom: 10rpx;
-	}
-
-	.skill-tag {
-		font-size: 20rpx;
-		color: #c9a227;
-		background: #fff8e6;
-		padding: 4rpx 12rpx;
-		border-radius: 6rpx;
-		line-height: 1.4;
+		width: 160rpx;
+		height: 160rpx;
+		margin-right: 20rpx;
 	}
+}
 
-	.skill-price {
-		font-size: 30rpx;
-		color: #ff5d75;
-		font-weight: 600;
-		line-height: 1.2;
-	}
+.skill-card--multi {
+	flex-shrink: 0;
+	width: 380rpx;
+	margin-right: 20rpx;
 
-	.empty-tip {
-		font-size: 26rpx;
-		color: $text-sub;
-		text-align: center;
-		padding: 32rpx 0;
+	&:last-child {
+		margin-right: 0;
 	}
+}
 
-	/* 地址 */
-	.address-section {
-		.address-heading-wrap {
-			display: flex;
-			align-items: flex-start;
-			margin-bottom: 20rpx;
-		}
-
-		.section-heading {
-			font-size: 32rpx;
-			color: #1D2129;
-			font-weight: 600;
-			line-height: 1.4;
-			padding-bottom: 10rpx;
-			background-image: url('/static/workbench/more.png');
-			background-repeat: no-repeat;
-			background-size: 80%;
-		}
+.skill-img {
+	width: 88rpx;
+	height: 88rpx;
+	background: #f5f5f5;
+	border-radius: 10rpx;
+	overflow: hidden;
+	flex-shrink: 0;
+	margin-right: 14rpx;
 
-		.address-tip {
-			width: 40rpx;
-			height: 40rpx;
-			margin-left: 8rpx;
-			margin-top: 2rpx;
-			flex-shrink: 0;
-		}
+	image {
+		width: 100%;
+		height: 100%;
 	}
-
-	.address-row {
+}
+
+.skill-info {
+	flex: 1;
+	min-width: 0;
+	display: flex;
+	flex-direction: column;
+	justify-content: center;
+}
+
+.skill-name {
+	font-size: 28rpx;
+	color: $text-main;
+	margin-bottom: 8rpx;
+	font-weight: 500;
+	line-height: 1.3;
+}
+
+.skill-tags {
+	display: flex;
+	flex-wrap: wrap;
+	gap: 8rpx;
+	margin-bottom: 10rpx;
+}
+
+.skill-tag {
+	font-size: 20rpx;
+	color: #c9a227;
+	background: #fff8e6;
+	padding: 4rpx 12rpx;
+	border-radius: 6rpx;
+	line-height: 1.4;
+}
+
+.skill-price {
+	font-size: 30rpx;
+	color: #ff5d75;
+	font-weight: 600;
+	line-height: 1.2;
+}
+
+.empty-tip {
+	font-size: 26rpx;
+	color: $text-sub;
+	text-align: center;
+	padding: 32rpx 0;
+}
+
+/* 地址 */
+.address-section {
+	.address-heading-wrap {
 		display: flex;
 		align-items: flex-start;
-		margin-bottom: 28rpx;
-	}
-
-	.address-icon {
-		width: 32rpx;
-		height: 32rpx;
-		margin-right: 12rpx;
-		margin-top: 4rpx;
-		flex-shrink: 0;
-	}
-
-	.address-text {
-		flex: 1;
-		font-size: 26rpx;
-		color: #666666;
-		line-height: 1.6;
-	}
-
-	.address-actions {
-		display: flex;
-		align-items: center;
-		border-top: 1rpx solid #f0f0f0;
-	}
-
-	.addr-btn {
-		flex: 1;
-		height: 80rpx;
-		line-height: 80rpx;
-		text-align: center;
-		font-size: 30rpx;
-		color: $text-main;
-	}
-
-	.addr-divider {
-		width: 1rpx;
-		height: 120rpx;
-		background: #e8e8e8;
-	}
-
-	/* 更多功能 */
-	.more-section {
-		.more-heading-wrap {
-			display: flex;
-			align-items: flex-start;
-			margin-bottom: 20rpx;
-		}
-
-		.section-heading {
-			font-size: 32rpx;
-			color: #1D2129;
-			font-weight: 600;
-			line-height: 1.4;
-			padding-bottom: 10rpx;
-			background-image: url('/static/workbench/more.png');
-			background-repeat: no-repeat;
-			background-size: 80%;
-		}
-
-		.more-tip {
-			width: 40rpx;
-			height: 40rpx;
-			margin-left: 8rpx;
-			margin-top: 2rpx;
-			flex-shrink: 0;
-		}
-	}
-
-	.more-grid {
-		display: flex;
-		flex-wrap: wrap;
-	}
-
-	.more-item {
-		width: 25%;
-		display: flex;
-		flex-direction: column;
-		align-items: center;
-		padding: 24rpx 0 8rpx;
-	}
-
-	.more-icon {
-		width: 80rpx;
-		height: 80rpx;
-		margin-bottom: 12rpx;
+		margin-bottom: 20rpx;
 	}
 
-	.more-label {
-		font-size: 24rpx;
-		color: #666666;
-		text-align: center;
+	.section-heading {
+		font-size: 32rpx;
+		color: #1D2129;
+		font-weight: 600;
 		line-height: 1.4;
+		padding-bottom: 10rpx;
+		background-image: url('/static/workbench/more.png');
+		background-repeat: no-repeat;
+		background-size: 80%;
 	}
 
-	/* 弹窗 */
-	.popup-mask {
-		position: fixed;
-		left: 0;
-		top: 0;
-		right: 0;
-		bottom: 0;
-		background: rgba(0, 0, 0, 0.4);
-		z-index: 999;
-		display: flex;
-		align-items: center;
-		justify-content: center;
-	}
-
-	.popup-box {
-		width: 600rpx;
-		background: #fff;
-		border-radius: 8rpx;
-		padding: 32rpx;
-	}
-
-	.popup-title {
-		font-size: 28rpx;
-		color: #333;
-		text-align: center;
-		margin-bottom: 24rpx;
-	}
-
-	.popup-input {
-		width: 100%;
-		height: 72rpx;
-		border: 1rpx solid #ddd;
-		border-radius: 6rpx;
-		padding: 0 20rpx;
-		font-size: 26rpx;
-		box-sizing: border-box;
+	.address-tip {
+		width: 40rpx;
+		height: 40rpx;
+		margin-left: 8rpx;
+		margin-top: 2rpx;
+		flex-shrink: 0;
 	}
-
-	.popup-btns {
+}
+
+.address-row {
+	display: flex;
+	align-items: flex-start;
+	margin-bottom: 28rpx;
+}
+
+.address-icon {
+	width: 32rpx;
+	height: 32rpx;
+	margin-right: 12rpx;
+	margin-top: 4rpx;
+	flex-shrink: 0;
+}
+
+.address-text {
+	flex: 1;
+	font-size: 26rpx;
+	color: #666666;
+	line-height: 1.6;
+}
+
+.address-actions {
+	display: flex;
+	align-items: center;
+	border-top: 1rpx solid #f0f0f0;
+}
+
+.addr-btn {
+	flex: 1;
+	height: 80rpx;
+	line-height: 80rpx;
+	text-align: center;
+	font-size: 30rpx;
+	color: $text-main;
+}
+
+.addr-divider {
+	width: 1rpx;
+	height: 120rpx;
+	background: #e8e8e8;
+}
+
+/* 更多功能 */
+.more-section {
+	.more-heading-wrap {
 		display: flex;
-		gap: 24rpx;
-		margin-top: 32rpx;
-	}
-
-	.popup-btn {
-		flex: 1;
-		height: 72rpx;
-		line-height: 72rpx;
-		text-align: center;
-		border: 1rpx solid #ccc;
-		border-radius: 6rpx;
-		font-size: 28rpx;
-		color: #666;
-
-		&.confirm {
-			background: linear-gradient(90deg, #3dd9cf 0%, #1ecbc3 100%);
-			border-color: #1ecbc3;
-			color: #fff;
-		}
-	}
-
-	.popup-mask.bottom {
-		align-items: flex-end;
-	}
-
-	.status-panel {
-		width: 100%;
-		background: #fff;
-		border-radius: 24rpx 24rpx 0 0;
-		padding: 32rpx;
-		padding-bottom: calc(env(safe-area-inset-bottom) + 32rpx);
-		box-sizing: border-box;
+		align-items: flex-start;
+		margin-bottom: 20rpx;
 	}
 
-	.panel-title {
+	.section-heading {
 		font-size: 32rpx;
+		color: #1D2129;
 		font-weight: 600;
-		color: #333;
-		text-align: center;
-		margin-bottom: 32rpx;
-	}
-
-	.status-option {
-		display: flex;
-		align-items: center;
-		padding: 28rpx 0;
-		border-bottom: 1rpx solid #f5f5f5;
-
-		// &.active .option-name {
-		// 	color: #1ecbc3;
-		// }
-	}
-
-	.option-body {
-		flex: 1;
-		min-width: 0;
+		line-height: 1.4;
+		padding-bottom: 10rpx;
+		background-image: url('/static/workbench/more.png');
+		background-repeat: no-repeat;
+		background-size: 80%;
 	}
 
-	.option-check {
-		font-size: 36rpx;
-		color: #1ecbc3;
-		font-weight: 600;
+	.more-tip {
+		width: 40rpx;
+		height: 40rpx;
+		margin-left: 8rpx;
+		margin-top: 2rpx;
 		flex-shrink: 0;
-		margin-left: 16rpx;
-
-		image {
-			width: 50rpx;
-			height: 50rpx;
-		}
-	}
-
-	.option-name {
-		display: block;
-		font-size: 30rpx;
-		color: #333;
-		font-weight: 500;
-	}
-
-	.option-desc {
-		display: block;
-		font-size: 24rpx;
-		color: #999;
-		margin-top: 8rpx;
-		line-height: 1.5;
-	}
-
-	.panel-btns {
-		display: flex;
-		gap: 24rpx;
-		margin-top: 32rpx;
 	}
-
-	.panel-btn {
-		flex: 1;
-		height: 80rpx;
-		line-height: 80rpx;
-		text-align: center;
-		background: rgba(51, 51, 53, 0.05);
+}
+
+.more-grid {
+	display: flex;
+	flex-wrap: wrap;
+}
+
+.more-item {
+	width: 25%;
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+	padding: 24rpx 0 8rpx;
+}
+
+.more-icon {
+	width: 80rpx;
+	height: 80rpx;
+	margin-bottom: 12rpx;
+}
+
+.more-label {
+	font-size: 24rpx;
+	color: #666666;
+	text-align: center;
+	line-height: 1.4;
+}
+
+/* 弹窗 */
+.popup-mask {
+	position: fixed;
+	left: 0;
+	top: 0;
+	right: 0;
+	bottom: 0;
+	background: rgba(0, 0, 0, 0.4);
+	z-index: 999;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+}
+
+.popup-box {
+	width: 600rpx;
+	background: #fff;
+	border-radius: 8rpx;
+	padding: 32rpx;
+}
+
+.popup-title {
+	font-size: 28rpx;
+	color: #333;
+	text-align: center;
+	margin-bottom: 24rpx;
+}
+
+.popup-input {
+	width: 100%;
+	height: 72rpx;
+	border: 1rpx solid #ddd;
+	border-radius: 6rpx;
+	padding: 0 20rpx;
+	font-size: 26rpx;
+	box-sizing: border-box;
+}
+
+.popup-btns {
+	display: flex;
+	gap: 24rpx;
+	margin-top: 32rpx;
+}
+
+.popup-btn {
+	flex: 1;
+	height: 72rpx;
+	line-height: 72rpx;
+	text-align: center;
+	border: 1rpx solid #ccc;
+	border-radius: 6rpx;
+	font-size: 28rpx;
+	color: #666;
+
+	&.confirm {
+		background: linear-gradient(90deg, #3dd9cf 0%, #1ecbc3 100%);
+		border-color: #1ecbc3;
+		color: #fff;
+	}
+}
+
+.popup-mask.bottom {
+	align-items: flex-end;
+}
+
+.status-panel {
+	width: 100%;
+	background: #fff;
+	border-radius: 24rpx 24rpx 0 0;
+	padding: 32rpx;
+	padding-bottom: calc(env(safe-area-inset-bottom) + 32rpx);
+	box-sizing: border-box;
+}
+
+.panel-title {
+	font-size: 32rpx;
+	font-weight: 600;
+	color: #333;
+	text-align: center;
+	margin-bottom: 32rpx;
+}
+
+.status-option {
+	display: flex;
+	align-items: center;
+	padding: 28rpx 0;
+	border-bottom: 1rpx solid #f5f5f5;
+
+	// &.active .option-name {
+	// 	color: #1ecbc3;
+	// }
+}
+
+.option-body {
+	flex: 1;
+	min-width: 0;
+}
+
+.option-check {
+	font-size: 36rpx;
+	color: #1ecbc3;
+	font-weight: 600;
+	flex-shrink: 0;
+	margin-left: 16rpx;
+
+	image {
+		width: 50rpx;
+		height: 50rpx;
+	}
+}
+
+.option-name {
+	display: block;
+	font-size: 30rpx;
+	color: #333;
+	font-weight: 500;
+}
+
+.option-desc {
+	display: block;
+	font-size: 24rpx;
+	color: #999;
+	margin-top: 8rpx;
+	line-height: 1.5;
+}
+
+.panel-btns {
+	display: flex;
+	gap: 24rpx;
+	margin-top: 32rpx;
+}
+
+.panel-btn {
+	flex: 1;
+	height: 80rpx;
+	line-height: 80rpx;
+	text-align: center;
+	background: rgba(51, 51, 53, 0.05);
+	border-radius: 60rpx 60rpx 60rpx 60rpx;
+	font-size: 32rpx;
+	color: #1D2129;
+
+	&.confirm {
+		background: #333335;
 		border-radius: 60rpx 60rpx 60rpx 60rpx;
-		font-size: 32rpx;
-		color: #1D2129;
-
-		&.confirm {
-			background: #333335;
-			border-radius: 60rpx 60rpx 60rpx 60rpx;
-			color: #fff;
-		}
+		color: #fff;
 	}
+}
 
-	.one-line-text {
-		overflow: hidden;
-		text-overflow: ellipsis;
-		white-space: nowrap;
-	}
+.one-line-text {
+	overflow: hidden;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+}
 </style>

+ 45 - 33
src/pages/join/applyJoin.vue

@@ -20,7 +20,7 @@
                         <template slot="prefix">
                             <view class="label">
                                 <text>昵称</text>
-                                <text class="status2">{{ auditStatus }}</text>
+                                <text v-if="baseInfo.teNickNameAuditStatus==0 || baseInfo.teNickNameAuditStatus==2" :class="baseInfo.teNickNameAuditStatus==0?'status1':'status2'">{{ baseInfo.teNickNameAuditStatus==0?'审核中':'审核驳回' }}</text>
                             </view>
                         </template>
                     </u-input>
@@ -31,8 +31,18 @@
 
                 <uni-list-item title="入驻城市" :rightText="baseInfo.city" />
                 <uni-list-item showArrow title="简介" :class="{ 'hasText': baseInfo.introduceYourself }" clickable
-                    @click="introduceYourselfEdit(baseInfo.introduceYourself)"
-                    :rightText="baseInfo.introduceYourself ? baseInfo.introduceYourself : '简单的介绍您自己~'" />
+                    @click="introduceYourselfEdit(baseInfo.introduceYourself,baseInfo.teNickNameAuditStatus)"
+                    :rightText="baseInfo.introduceYourself ? baseInfo.introduceYourself : '简单的介绍您自己~'" >
+                    <!-- 自定义 body -->
+                    <template v-slot:body>
+                        <view class="slot-box slot-text">
+                            简介
+                            <view v-if="baseInfo.teNickNameAuditStatus==0 || baseInfo.teNickNameAuditStatus==2" :class="baseInfo.teNickNameAuditStatus==0?'status1':'status2'">{{ baseInfo.teNickNameAuditStatus==0?'审核中':'审核驳回' }}</view>
+                    
+                        </view>
+                    </template>
+                           
+                </uni-list-item>
             </uni-list>
         </view>
         <view class="baseInfo" style="margin-top: 16rpx;height: 80vh;">
@@ -52,9 +62,9 @@
                         <view class="slot-box slot-text">
                             形象照
                             <view
-                                :class="baseInfo.portraitPhotoList.some(item => item.auditStatus == 1) ? 'status2' : 'status1'"
-                                v-if="baseInfo.portraitPhotoList.every(item => item.auditStatus != 2)">{{
-                                    baseInfo.portraitPhotoList.some(item => item.auditStatus == 1) ? '审核中' : '审核驳回'}}
+                                :class="baseInfo.portraitPhotoList.some(item => item.auditStatus == 0) ? 'status1' : 'status2'"
+                                v-if="baseInfo.portraitPhotoList.every(item => item.auditStatus != 1)">{{
+                                    baseInfo.portraitPhotoList.some(item => item.auditStatus == 0) ? '审核中' : '审核驳回'}}
                             </view>
                         </view>
                     </template>
@@ -71,9 +81,9 @@
                     <template v-slot:body>
                         <view class="slot-box slot-text">
                             生活照
-                            <view :class="baseInfo.cImgList.some(item => item.auditStatus == 1) ? 'status2' : 'status1'"
-                                v-if="baseInfo.cImgList.every(item => item.auditStatus != 2)">{{
-                                    baseInfo.cImgList.some(item => item.auditStatus == 1) ? '审核中' : '审核驳回'}}</view>
+                            <view :class="baseInfo.cImgList.some(item => item.auditStatus == 0) ? 'status1' : 'status2'"
+                                v-if="baseInfo.cImgList.every(item => item.auditStatus != 1)">{{
+                                    baseInfo.cImgList.some(item => item.auditStatus == 0) ? '审核中' : '审核驳回'}}</view>
                         </view>
                     </template>
 
@@ -85,9 +95,9 @@
                         <view class="slot-box slot-text">
                             宣传视频
                             <view
-                                :class="baseInfo.promotionalVideo.some(item => item.auditStatus == 1) ? 'status2' : 'status1'"
-                                v-if="baseInfo.promotionalVideo.every(item => item.auditStatus != 2)">{{
-                                    baseInfo.promotionalVideo.some(item => item.auditStatus == 1) ? '审核中' : '审核驳回'}}</view>
+                                :class="baseInfo.promotionalVideo.some(item => item.auditStatus == 0) ? 'status1' : 'status2'"
+                                v-if="baseInfo.promotionalVideo.every(item => item.auditStatus != 1)">{{
+                                    baseInfo.promotionalVideo.some(item => item.auditStatus == 0) ? '审核中' : '审核驳回'}}</view>
                         </view>
                     </template>
 
@@ -99,9 +109,9 @@
                     <template v-slot:body>
                         <view class="slot-box slot-text">
                             身份证
-                            <view :class="(baseInfo.idCard || []).some(subArr => (subArr || []).some(item => item.auditStatus == 1)) ? 'status2' : 'status1'" 
-                            v-if="(baseInfo.idCard || []).every(subArr =>(subArr || []).every(item => item.auditStatus != 2))">
-                            {{(baseInfo.idCard || []).some(subArr =>(subArr || []).some(item => item.auditStatus == 1)) ? '审核中' : '审核驳回'}}</view>
+                            <view :class="(baseInfo.idCard || []).some(subArr => (subArr || []).some(item => item.auditStatus == 0)) ? 'status1' : 'status2'" 
+                            v-if="(baseInfo.idCard || []).every(subArr =>(subArr || []).every(item => item.auditStatus != 1))">
+                            {{(baseInfo.idCard || []).some(subArr =>(subArr || []).some(item => item.auditStatus == 0)) ? '审核中' : '审核驳回'}}</view>
                         </view>
                     </template>
 
@@ -115,9 +125,9 @@
                         <view class="slot-box slot-text">
                             健康证
                             <view
-                                :class="baseInfo.healthCertificate.some(item => item.auditStatus == 1) ? 'status2' : 'status1'"
-                                v-if="baseInfo.healthCertificate.every(item => item.auditStatus != 2)">{{
-                                    baseInfo.healthCertificate.some(item => item.auditStatus == 1) ? '审核中' : '审核驳回'}}
+                                :class="baseInfo.healthCertificate.some(item => item.auditStatus == 0) ? 'status1' : 'status2'"
+                                v-if="baseInfo.healthCertificate.every(item => item.auditStatus != 1)">{{
+                                    baseInfo.healthCertificate.some(item => item.auditStatus == 0) ? '审核中' : '审核驳回'}}
                             </view>
                         </view>
                     </template>
@@ -130,9 +140,9 @@
                         <view class="slot-box slot-text">
                             从业资格证
                             <view
-                                :class="baseInfo.certification.some(item => item.auditStatus == 1) ? 'status2' : 'status1'"
-                                v-if="baseInfo.certification.every(item => item.auditStatus != 2)">{{
-                                    baseInfo.certification.some(item => item.auditStatus == 1) ? '审核中' : '审核驳回'}}</view>
+                                :class="baseInfo.certification.some(item => item.auditStatus == 0) ? 'status1' : 'status2'"
+                                v-if="baseInfo.certification.every(item => item.auditStatus != 1)">{{
+                                    baseInfo.certification.some(item => item.auditStatus == 0) ? '审核中' : '审核驳回'}}</view>
                         </view>
                     </template>
 
@@ -143,9 +153,9 @@
                     <template v-slot:body>
                         <view class="slot-box slot-text">
                             无犯罪证明
-                            <view :class="baseInfo.noCrime.some(item => item.auditStatus == 1) ? 'status2' : 'status1'"
-                                v-if="baseInfo.noCrime.every(item => item.auditStatus != 2)">{{
-                                    baseInfo.noCrime.some(item => item.auditStatus == 1) ? '审核中' : '审核驳回'}}</view>
+                            <view :class="baseInfo.noCrime.some(item => item.auditStatus == 0) ? 'status1' : 'status2'"
+                                v-if="baseInfo.noCrime.every(item => item.auditStatus != 1)">{{
+                                    baseInfo.noCrime.some(item => item.auditStatus == 0) ? '审核中' : '审核驳回'}}</view>
                         </view>
                     </template>
 
@@ -158,9 +168,9 @@
                     <template v-slot:body>
                         <view class="slot-box slot-text">
                             承诺文件
-                            <view :class="(baseInfo.commitDocument || []).some(subArr => (subArr || []).some(item => item.auditStatus == 1)) ? 'status2' : 'status1'" 
-                            v-if="(baseInfo.commitDocument || []).every(subArr =>(subArr || []).every(item => item.auditStatus != 2))">
-                            {{(baseInfo.commitDocument || []).some(subArr =>(subArr || []).some(item => item.auditStatus == 1)) ? '审核中' : '审核驳回'}}</view>
+                            <view :class="(baseInfo.commitDocument || []).some(subArr => (subArr || []).some(item => item.auditStatus == 0)) ? 'status1' : 'status2'" 
+                            v-if="(baseInfo.commitDocument || []).every(subArr =>(subArr || []).every(item => item.auditStatus != 1))">
+                            {{(baseInfo.commitDocument || []).some(subArr =>(subArr || []).some(item => item.auditStatus == 0)) ? '审核中' : '审核驳回'}}</view>
                         </view>
                     </template>
 
@@ -172,7 +182,7 @@
 
 
 
-        <!-- 提交按钮 pages/join/introduceYourselfEdit-->
+        <!-- 提交按钮 -->
         <view class="submit-box">
             <u-button @click="submitForm">提交</u-button>
         </view>
@@ -194,6 +204,8 @@ export default {
                 { taskName: '222' }
             ],
             baseInfo: {
+                teNickNameAuditStatus: null,//审核状态(0-审核中,1-审核通过,2-审核驳回)
+                teBriefAuditStatus: null,
                 commitDocumentAuditStatus: 0,
                 idCardAuditStatus: 0,
                 id: '',
@@ -398,14 +410,14 @@ export default {
         commitDocmentEditFun(value) {
             let str = uni.$u.queryParams({
                 fieldName: value,
-                fieldVal: JSON.stringify(this.baseInfo[value])
+                fieldVal: JSON.stringify(this.baseInfo[value]),
             })
             uni.navigateTo({ url: `/pages/join/commitDocumentEdit${str}` })
         },
         idCardEditFun(value) {
             let str = uni.$u.queryParams({
                 fieldName: value,
-                fieldVal: JSON.stringify(this.baseInfo[value])
+                fieldVal: JSON.stringify(this.baseInfo[value]),
             })
             uni.navigateTo({ url: `/pages/join/idCardEdit${str}` })
         },
@@ -414,14 +426,14 @@ export default {
                 fieldName: value,
                 fieldVal: JSON.stringify(this.baseInfo[value]),
                 title: title,
-                maxlength: maxlength
+                maxlength: maxlength,
             })
             uni.navigateTo({ url: `/pages/join/lifePhotosEdit${str}` })
 
         },
         //简介
-        introduceYourselfEdit() {
-            uni.navigateTo({ url: '/pages/join/introduceYourselfEdit?introduceYourself=' + this.baseInfo.introduceYourself })
+        introduceYourselfEdit(introduceYourself,teNickNameAuditStatus) {
+            uni.navigateTo({ url: '/pages/join/introduceYourselfEdit?introduceYourself=' + this.baseInfo.introduceYourself + '&teNickNameAuditStatus=' + teNickNameAuditStatus })
         },
         portraitPhotoFun() {
             uni.chooseImage({

+ 147 - 133
src/pages/join/commitDocumentEdit.vue

@@ -1,12 +1,30 @@
 <template>
     <view class="commitDocument">
         <view>
+            <view v-if="auditStatus == 0 || auditStatus == 2" class="checkBox" :style="{
+                color: auditStatus === 2 ? '#F53F3F' : '#FF7D00',
+                background: auditStatus === 2 ? '#FFF5F5' : '#FFF8EC'
+            }">
+                <view style="display: flex;align-items: center;justify-content: space-between;">
+                    <view class="checkStatus">
+                        <image :src="auditStatus == 0 ? '/static/login/status1.png' : '/static/login/status2.png'"
+                            mode="" style="width: 32rpx;height: 32rpx;margin-right: 8rpx;">
+                        </image>
+                        {{ auditStatus == 2 ? '审核驳回' : '审核中' }}
+                    </view>
+                    <view class="contactCustomer" :style="{
+                        border: auditStatus === 2 ? '1px solid #F53F3F' : '1px solid #FF7D00',
+                    }">联系客服</view>
+                </view>
+
+                <view class="text">{{ auditStatus == 2 ? '审核驳回' : '审核中' }},审核结果将会在X-X个工作日通知您</view>
+            </view>
             <view class="content">
                 <view class="title">承诺书</view>
                 <view class="tip">请上传 大小不超过 2MB 格式为 jpg/jpeg/png 的文件</view>
                 <Upload :maxCount="9" @fileList="onUpload($event, 'commitment')" :fileList="commitment" :width="76"
                     :height="76">
-                    <view class="upload-block 999" slot="content">
+                    <view class="upload-block" slot="content">
                         <view class="icon-bg">
                             <image src="/static/login/cameraIcon.png" mode="widthFix"
                                 style="width: 52rpx;height: 52rpx;">
@@ -23,26 +41,37 @@
             <view class="content">
                 <view class="title">承诺录音</view>
                 <view class="tip">请上传 大小不超过 10MB 格式为 mp3/wav/wma/m4a 的文件</view>
-                <!-- <view class="recorder-buttons">
-                    <button class="record-btn" :class="{ recording: isRecording }" @click="handleRecord"
-                        :disabled="isRecording">
-                        {{ isRecording ? '录音中...' : '开始录音' }}
-                    </button>
-
-                    <button class="stop-btn" @click="handleStop" :disabled="!isRecording">
-                        停止录音
-                    </button>
-
-                    <button class="play-btn" @click="handlePlay" :disabled="!localId">
-                        播放录音
-                    </button>
+                <view class="media-area">
+                    <view v-if="formData.audioUrl">
+                        <view class="icon iconfont icon-cuo">
+                            <image src="/static/login/close2.png" mode="" style="width: 32rpx;height: 32rpx;"
+                                @tap="delectAudio">
+                            </image>
+                        </view>
+                        <audio :src="formData.audioUrl" class="audio-container" controls></audio>
+                    </view>
+                    <clUpload v-else v-model="fileList1" :action="uploadApi" :headers="headers" :count="maxCount"
+                        :listStyle="{
+                            columnGap: '20rpx',
+                            rowGap: '20rpx',
+                            width: '130rpx',
+                            radius: '12rpx',
+                        }" :imageFormData="{
+                        count: 9,
+                        size: 2,
+                    }" :audioFromData="{
+                            count: 1,
+                            size: 10,
+                        }" :maxAudio="1" :fileType="mediaType" addImg="/static/login/cameraIcon.png"
+                        deleteImg="/static/login/cameraIcon.png" @onSuccess="onSuccess"
+                        @onMediaTypeSelect="selectMediaType" @onError="onCancel">
+
+
+                    </clUpload>
                 </view>
 
-                <view v-if="audioDuration" class="audio-info">
-                    录音时长: {{ audioDuration }}秒
-                </view> -->
 
-                <Upload :maxCount="1" @fileList="onUpload($event, 'recording')" :fileList="recording">
+                <!-- <Upload :maxCount="1" @fileList="onUpload($event, 'recording')" :fileList="recording">
                     <view class="upload-block" slot="content">
                         <view class="icon-bg">
                             <image src="/static/login/cameraIcon.png" mode="widthFix"
@@ -53,7 +82,7 @@
                         </view>
 
                     </view>
-                </Upload>
+                </Upload> -->
 
             </view>
             <view class="content">
@@ -93,7 +122,7 @@
                 </view>
             </view>
 
-            <view class="footer-bar">
+            <view class="footer-bar" v-if="auditStatus != 1">
                 <u-button :customStyle="{
                     padding: '24rpx 48rpx',
                     color: '#fff',
@@ -118,17 +147,20 @@ export default {
     components: { Upload, clUpload, },
     data() {
         return {
+            auditStatus: 1,
             isRecording: false,
             localId: null,
             serverId: null,
-            audioDuration: 0,
 
             headers: {
                 Authorization: `tf: ${uni.getStorageSync('access-token')}`,
             },
             uploadApi: baseUrl + '/common/upload', // 默认使用图片上传接口
             videoUrl: '',
+            audioUrl: '',
+            audioCoverUrl: '',
             fileList: [],
+            fileList1: [],
             formData: {
                 title: '',
                 content: '',
@@ -167,10 +199,10 @@ export default {
                 this.formData.videoUrl = this.videoRecording[0].url
                 this.formData.videoCoverUrl = this.videoRecording[0].coverUrl
             }
+            let fileList = fieldVal.flat()
+            this.auditStatus = fileList.find(item => item.auditStatus == 0 || item.auditStatus == 2)?.auditStatus || 1
 
         }
-        // 初始化微信SDK(包含录音功能)
-        this.initRecorder();
     },
     onReady() {
 
@@ -181,110 +213,6 @@ export default {
         this.stopDurationTimer();
     },
     methods: {
-        async initRecorder() {
-            try {
-                await initWechatSDKWithRecorder();
-
-                // 设置录音事件监听
-                wechatRecorder.on('onStart', () => {
-                    this.isRecording = true;
-                    this.audioDuration = 0;
-                    // 计时器显示录音时长
-                    this.startDurationTimer();
-                });
-
-                wechatRecorder.on('onStop', (res) => {
-                    this.isRecording = false;
-                    this.localId = res.localId;
-                    this.stopDurationTimer();
-                });
-
-                wechatRecorder.on('onUpload', (res) => {
-                    this.serverId = res.serverId;
-                    console.log('录音上传成功:', this.serverId);
-                    // 可以在这里将serverId上传到自己的服务器
-                });
-
-                wechatRecorder.on('onError', (err) => {
-                    console.error('录音错误:', err);
-                    uni.showToast({ title: err.errMsg || '录音失败', icon: 'none' });
-                });
-
-            } catch (err) {
-                console.error('初始化录音失败:', err);
-                uni.showToast({ title: '无法使用录音功能', icon: 'none' });
-            }
-        },
-
-        handleRecord() {
-            if (this.isRecording) return;
-
-            wechatRecorder.startRecording((err, msg) => {
-                if (err) {
-                    uni.showToast({ title: err.errMsg, icon: 'none' });
-                }
-            });
-        },
-
-        handleStop() {
-            if (!this.isRecording) return;
-
-            wechatRecorder.stopRecording((err, res) => {
-                if (err) {
-                    uni.showToast({ title: err.errMsg, icon: 'none' });
-                } else {
-                    this.localId = res.localId;
-                    // 上传录音到微信服务器
-                    this.uploadAudio();
-                }
-            });
-        },
-
-        handlePlay() {
-            if (!this.localId) return;
-
-            wechatRecorder.playVoice(this.localId, (err) => {
-                if (err) {
-                    uni.showToast({ title: err.errMsg, icon: 'none' });
-                }
-            });
-        },
-
-        uploadAudio() {
-            wechatRecorder.uploadVoice(this.localId, (err, res) => {
-                if (err) {
-                    uni.showToast({ title: '上传失败', icon: 'none' });
-                } else {
-                    this.serverId = res.serverId;
-                    uni.showToast({ title: '录音上传成功', icon: 'success' });
-                    // 将serverId发送到后端保存
-                    this.saveRecording(res.serverId);
-                }
-            });
-        },
-
-        saveRecording(serverId) {
-            // 调用后端接口保存录音
-            // this.$api.saveRecording({ serverId }).then(res => {
-            //   console.log('录音保存成功');
-            // });
-        },
-
-        startDurationTimer() {
-            this.durationTimer = setInterval(() => {
-                this.audioDuration++;
-            }, 1000);
-        },
-
-        stopDurationTimer() {
-            if (this.durationTimer) {
-                clearInterval(this.durationTimer);
-                this.durationTimer = null;
-            }
-        },
-
-
-
 
         onSuccess(reslut, tempFile) {
             console.log(reslut, tempFile)
@@ -295,6 +223,11 @@ export default {
                     reslut.url.endsWith('.mov') ||
                     reslut.url.endsWith('.mkv') ||
                     reslut.url.endsWith('.wmv')
+                const isAudio =
+                    reslut.url.endsWith('.mp3') ||
+                    reslut.url.endsWith('.wav') ||
+                    reslut.url.endsWith('.aac') ||
+                    reslut.url.endsWith('.m4a')
                 if (isVideo) {
                     this.formData.videoUrl = baseUrl + reslut.url
                     this.formData.videoCoverUrl = baseUrl + reslut.coverUrl
@@ -304,6 +237,10 @@ export default {
                         size: tempFile.size,
                         coverUrl: baseUrl + reslut.coverUrl,
                     }]
+                } else if (isAudio) {
+                    this.formData.audioUrl = baseUrl + reslut.url
+                    this.fileList1.push(baseUrl + reslut.url)
+
                 } else {
                     this.fileList.push(baseUrl + reslut.url)
                 }
@@ -319,6 +256,9 @@ export default {
             } else if (type === 'video') {
                 this.uploadApi = baseUrl + '/common/uploadVi'
                 this.mediaType = 'video'
+            } else if (type === 'audio') {
+                this.uploadApi = baseUrl + '/common/uploadVi'
+                this.mediaType = 'audio'
             }
         },
         // 处理媒体类型取消事件
@@ -340,6 +280,20 @@ export default {
                 },
             })
         },
+        delectAudio() {
+            uni.showModal({
+                title: '提示',
+                content: '是否要删除此音频',
+                success: res => {
+                    if (res.confirm) {
+                        this.formData.audioUrl = ''
+                        this.fileList1 = []
+                        // 重置媒体类型
+                        this.mediaType = 'all'
+                    }
+                },
+            })
+        },
 
         // upload事件
         onUpload(e, t) {
@@ -365,13 +319,64 @@ export default {
 </script>
 
 <style scoped lang="scss">
+.audio-container {
+    width: 100%;
+    .uni-audio-default{
+        min-width: none;
+    }
+}
+
 .commitDocument {
     height: 100vh;
     background-color: #F7F8FA;
+    /* 添加以下属性修复文字模糊 */
+    -webkit-font-smoothing: antialiased;
+    -moz-osx-font-smoothing: grayscale;
+    text-rendering: optimizeLegibility;
+    backface-visibility: hidden;
+    transform-style: flat;
+
+
+    .checkBox {
+        padding: 30rpx 32rpx 24rpx 32rpx;
+        height: 134rpx;
+        border-radius: 8rpx 8rpx 8rpx 8rpx;
+
+        //color: #FF7D00;
+        .checkStatus {
+            font-weight: 500;
+            font-size: 30rpx;
+            text-align: left;
+            display: flex;
+            align-items: center;
+
+        }
+
+        .contactCustomer {
+            width: 144rpx;
+            height: 44rpx;
+            border-radius: 24rpx 24rpx 24rpx 24rpx;
+
+            font-weight: 400;
+            font-size: 26rpx;
+            text-align: center;
+
+        }
+
+        .text {
+            margin-top: 8rpx;
+            font-weight: 400;
+            font-size: 26rpx;
+            text-align: left;
+        }
+    }
+
 
     .content {
         background-color: #fff;
         padding: 32rpx;
+        margin-bottom:16rpx ;
+       
 
         .upload-block {
             width: 160rpx;
@@ -418,8 +423,13 @@ export default {
         border: none !important;
     }
 }
+
 ::v-deep .u-upload__success {
     display: none;
+}
+ ::v-deep .u-upload__wrap__preview{
+    margin: 0 16rpx 0 0;
+            
 }
 
 ::v-deep .u-upload__wrap__preview__image {
@@ -429,31 +439,35 @@ export default {
 ::v-deep .u-upload__deletable {
     border-top-right-radius: 12rpx;
     border-bottom-left-radius: 12rpx;
-    
+
 }
 
 ::v-deep .u-upload__deletable__icon {
+    // position: static !important;
+    // -webkit-transform: scale(0.8) !important;
     position: static !important;
-    -webkit-transform: scale(0.8) !important;
+    width: 80%; // 使用宽度缩放代替 transform
+    height: 80%;
 
 }
 
 .media-area {
-    margin: 20rpx 0 20rpx;
+    margin: 20rpx 0 0 0;
     justify-content: space-between;
     position: relative;
-    width: 340upx;
-    height: 240upx;
+    width: 340rpx;
 
     .icon-cuo {
+        background-color: #0000009c;
         width: 40rpx;
         height: 40rpx;
         position: absolute;
         right: 0;
         top: 0;
-        color: #ffffff !important;
+        color: #f80000 !important;
         z-index: 999;
         border-bottom-left-radius: 12rpx;
+        border-top-right-radius: 12rpx;
         display: flex;
         justify-content: center;
         align-items: center;

+ 56 - 7
src/pages/join/idCardEdit.vue

@@ -1,5 +1,23 @@
 <template>
     <view class="idCardEdit">
+        <view v-if="auditStatus == 0 || auditStatus == 2" class="checkBox" :style="{
+            color: auditStatus === 2 ? '#F53F3F' : '#FF7D00',
+            background: auditStatus === 2 ? '#FFF5F5' : '#FFF8EC'
+        }">
+            <view style="display: flex;align-items: center;justify-content: space-between;">
+                <view class="checkStatus">
+                    <image :src="auditStatus == 0 ? '/static/login/status1.png' : '/static/login/status2.png'" mode=""
+                        style="width: 32rpx;height: 32rpx;margin-right: 8rpx;">
+                    </image>
+                    {{ auditStatus == 2 ? '审核驳回' : '审核中' }}
+                </view>
+                <view class="contactCustomer" :style="{
+                    border: auditStatus === 2 ? '1px solid #F53F3F' : '1px solid #FF7D00',
+                }">联系客服</view>
+            </view>
+
+            <view class="text">{{ auditStatus == 2 ? '审核驳回' : '审核中' }},审核结果将会在X-X个工作日通知您</view>
+        </view>
         <view class="content">
             <view class="id-upload-row" style="margin-bottom: 32rpx;">
                 <view style="width: 334rpx;height: 264rpx;position: relative;">
@@ -114,7 +132,7 @@
                 </view>
             </Upload> -->
 
-            <view class="footer-bar">
+            <view class="footer-bar" v-if="auditStatus != 1 ">
                 <u-button :customStyle="{
                     padding: '24rpx 48rpx',
                     color: '#fff',
@@ -137,6 +155,7 @@ export default {
     components: { Upload },
     data() {
         return {
+            auditStatus: 1,
             fieldName: '',
             idCardFront: [],
             idCardBack: [],
@@ -149,16 +168,13 @@ export default {
         if (query.fieldName) this.fieldName = query.fieldName
         if (query.fieldVal) {
             let fieldVal = JSON.parse(query.fieldVal)
-            console.log(fieldVal, 'query')
             this.idCardFront = fieldVal[0] ? fieldVal[0] : []
             this.idCardBack = fieldVal[1] ? fieldVal[1]: []
             this.idCardHand = fieldVal[2] ? fieldVal[2] : []
+            let fileList=fieldVal.flat()
+            this.auditStatus = fileList.find(item => item.auditStatus == 0 || item.auditStatus == 2)?.auditStatus || 2
         }
-
-        // console.log(this.fileList, 'query')
-        // console.log(this.fileList, 'query')
-        // console.log(this.maxlength, 'query')
-        // console.log(this.title, 'query')
+        
     },
     onReady() {
 
@@ -203,6 +219,39 @@ export default {
 .idCardEdit {
     height: 100vh;
     background-color: #F7F8FA;
+    .checkBox {
+        padding: 30rpx 32rpx 24rpx 32rpx;
+        height: 134rpx;
+        border-radius: 8rpx 8rpx 8rpx 8rpx;
+
+        //color: #FF7D00;
+        .checkStatus {
+            font-weight: 500;
+            font-size: 30rpx;
+            text-align: left;
+            display: flex;
+            align-items: center;
+
+        }
+
+        .contactCustomer {
+            width: 144rpx;
+            height: 44rpx;
+            border-radius: 24rpx 24rpx 24rpx 24rpx;
+
+            font-weight: 400;
+            font-size: 26rpx;
+            text-align: center;
+
+        }
+
+        .text {
+            margin-top: 8rpx;
+            font-weight: 400;
+            font-size: 26rpx;
+            text-align: left;
+        }
+    }
 
     .content {
         width: 100%;

+ 55 - 1
src/pages/join/introduceYourselfEdit.vue

@@ -1,10 +1,28 @@
 <template>
     <view class="introduceYourselfEdit">
+        <view v-if="auditStatus == 0 || auditStatus == 2" class="checkBox" :style="{
+            color: auditStatus === 2 ? '#F53F3F' : '#FF7D00',
+            background: auditStatus === 2 ? '#FFF5F5' : '#FFF8EC'
+        }">
+            <view style="display: flex;align-items: center;justify-content: space-between;">
+                <view class="checkStatus">
+                    <image :src="auditStatus == 0 ? '/static/login/status1.png' : '/static/login/status2.png'" mode=""
+                        style="width: 32rpx;height: 32rpx;margin-right: 8rpx;">
+                    </image>
+                    {{ auditStatus == 2 ? '审核驳回' : '审核中' }}
+                </view>
+                <view class="contactCustomer" :style="{
+                    border: auditStatus === 2 ? '1px solid #F53F3F' : '1px solid #FF7D00',
+                }">联系客服</view>
+            </view>
+
+            <view class="text">{{ auditStatus == 2 ? '审核驳回' : '审核中' }},审核结果将会在X-X个工作日通知您</view>
+        </view>
         <view class="u-cell-group">
             <u--textarea placeholderClass="textarea-placeholder" autoHeight v-model="value" placeholder="简单的介绍您自己~"
                 class="textareaDef"></u--textarea>
         </view>
-        <view class="footer-bar">
+        <view class="footer-bar" v-if="auditStatus != 1 ">
             <u-button :customStyle="{
                 padding: '24rpx 48rpx',
                 color: '#fff',
@@ -24,6 +42,7 @@ import { onShow } from '@dcloudio/uni-app';
 export default {
     data() {
         return {
+            auditStatus: 1,
             value: '',
         }
     },
@@ -31,6 +50,7 @@ export default {
     },
     onLoad(query) {
         console.log(query, 'query')
+        this.auditStatus = query.teNickNameAuditStatus?query.teNickNameAuditStatus:1
         this.value = (query.introduceYourself === undefined || query.introduceYourself === 'undefined') ? '' : decodeURIComponent(query.introduceYourself)
     },
     onShow() {
@@ -68,6 +88,40 @@ export default {
 .introduceYourselfEdit {
     height: 100vh;
     background-color: #F7F8FA;
+    .checkBox {
+        padding: 30rpx 32rpx 24rpx 32rpx;
+        height: 134rpx;
+        border-radius: 8rpx 8rpx 8rpx 8rpx;
+
+        //color: #FF7D00;
+        .checkStatus {
+            font-weight: 500;
+            font-size: 30rpx;
+            text-align: left;
+            display: flex;
+            align-items: center;
+
+        }
+
+        .contactCustomer {
+            width: 144rpx;
+            height: 44rpx;
+            border-radius: 24rpx 24rpx 24rpx 24rpx;
+
+            font-weight: 400;
+            font-size: 26rpx;
+            text-align: center;
+
+        }
+
+        .text {
+            margin-top: 8rpx;
+            font-weight: 400;
+            font-size: 26rpx;
+            text-align: left;
+        }
+    }
+
 
     .u-cell-group {
         background: #fff;

+ 106 - 50
src/pages/join/lifePhotosEdit.vue

@@ -1,64 +1,82 @@
 <template>
     <view class="lifePhotosEdit">
+        <view v-if="auditStatus == 0 || auditStatus == 2" class="checkBox" :style="{
+            color: auditStatus == 2 ? '#F53F3F' : '#FF7D00',
+            background: auditStatus == 2 ? '#FFF5F5' : '#FFF8EC'
+        }">
+            <view style="display: flex;align-items: center;justify-content: space-between;">
+                <view class="checkStatus">
+                    <image :src="auditStatus == 0 ? '/static/login/status1.png' : '/static/login/status2.png'" mode=""
+                        style="width: 32rpx;height: 32rpx;margin-right: 8rpx;">
+                    </image>
+                    {{ auditStatus == 2 ? '审核驳回' : '审核中' }}
+                </view>
+                <view class="contactCustomer" :style="{
+                    border: auditStatus === 2 ? '1px solid #F53F3F' : '1px solid #FF7D00',
+                }">联系客服</view>
+            </view>
+
+            <view class="text">{{ auditStatus == 2 ? '审核驳回' : '审核中' }},审核结果将会在X-X个工作日通知您</view>
+        </view>
         <view class="u-cell-group">
             <!-- <Upload :maxCount="1" @fileList="onUpload($event, 'cImgList')" /> -->
-            <Upload v-if="title != '宣传视频'" :accept="title == '宣传视频' ? 'video' : 'image'" :maxCount="maxCount" :width="76" :height="76"
-                @fileList="onUpload" :fileList="fileList">
+            <Upload v-if="title != '宣传视频'" :accept="title == '宣传视频' ? 'video' : 'image'" :maxCount="maxCount"
+                :width="76" :height="76" @fileList="onUpload" :fileList="fileList">
                 <view class="upload-block" slot="content">
 
                     <view class="icon-bg">
-                        <image src="/static/login/cameraIcon.png" mode="widthFix" style="width: 52rpx;height: 52rpx;" >
+                        <image src="/static/login/cameraIcon.png" mode="widthFix" style="width: 52rpx;height: 52rpx;">
                         </image>
                         <view style="font-weight: 400;font-size: 26rpx;color: #C9CDD4;margin-top: -13rpx;">上传</view>
-                        
+
                     </view>
 
                 </view>
             </Upload>
             <view v-if="title == '宣传视频'" class="media-area">
-                    <view v-if="videoUrl">
-                        <view class="icon iconfont icon-cuo">
-                            <image src="/static/login/close2.png" mode="" style="width: 32rpx;height: 32rpx;"
-                                @tap="delectVideo">
-                            </image>
-                        </view>
-                        <video ref="myVideo" :src="videoUrl" class="video-container" controls></video>
+                <view v-if="videoUrl">
+                    <view class="icon iconfont icon-cuo">
+                        <image src="/static/login/close2.png" mode="" style="width: 32rpx;height: 32rpx;"
+                            @tap="delectVideo">
+                        </image>
                     </view>
-                    <clUpload v-else :fileList="fileList" :action="uploadApi" :headers="headers" :count="maxCount"
-                        :listStyle="{
-                            columnGap: '20rpx',
-                            rowGap: '20rpx',
-                            width: '130rpx',
-                            radius: '12rpx',
-                        }" :imageFormData="{
-                            count: 9,
-                            size: 2,
-                        }" :videoFromData="{
-                            count: 1,
-                            size: 50,
-                        }" :maxVideo="1" :fileType="mediaType" addImg="/static/login/cameraIcon.png"
-                        deleteImg="/static/login/cameraIcon.png" @onSuccess="onSuccess"
-                        @onMediaTypeSelect="selectMediaType('video')" @onError="onCancel">
-
-
-                    </clUpload>
+                    <video ref="myVideo" :src="videoUrl" class="video-container" controls></video>
                 </view>
+                <clUpload v-else :fileList="fileList" :action="uploadApi" :headers="headers" :count="maxCount"
+                    :listStyle="{
+                        columnGap: '20rpx',
+                        rowGap: '20rpx',
+                        width: '130rpx',
+                        radius: '12rpx',
+                    }" :imageFormData="{
+                        count: 9,
+                        size: 2,
+                    }" :videoFromData="{
+                        count: 1,
+                        size: 50,
+                    }" :maxVideo="1" :fileType="mediaType" addImg="/static/login/cameraIcon.png"
+                    deleteImg="/static/login/cameraIcon.png" @onSuccess="onSuccess"
+                    @onMediaTypeSelect="selectMediaType('video')" @onError="onCancel">
+
+
+                </clUpload>
+            </view>
 
             <view class="tagText" v-if="title == '生活照'">简单介绍自己的生活照,可以说说自己的基本信息,工作场景,等等;
                 或者上传自己清晰露脸半身照/全身照/工作照。最多上传{{ maxCount }}张</view>
             <view class="tagText" v-if="title == '宣传视频'">请上传 大小不超过 50MB 格式为 mp4/mov/mkv/wmv 的文件</view>
             <view class="tagText" v-if="title == '健康证' || title == '从业资格证' || title == '无犯罪证明'">请上传小于10MB的{{ title
-                }}图片,最多上传{{ maxCount }}张
+            }}图片,最多上传{{ maxCount }}张
             </view>
 
 
-            <view class="footer-bar">
+            <view class="footer-bar" v-if="auditStatus != 1 ">
                 <u-button :customStyle="{
                     padding: '24rpx 48rpx',
                     color: '#fff',
                     background: 'var(--theme-color-gradient)',
                     width: '654rpx',
-                    height: '88rpx',
+                    height: '88rpx',    
                     background: '#333335',
                     borderRadius: '60rpx 60rpx 60rpx 60rpx',
                 }" @click="onSubmit">保存</u-button>
@@ -73,10 +91,11 @@ import Upload from '@/components/upload/index.vue';
 import { baseUrl } from '@/common/config.js'
 
 export default {
-    components: { Upload,clUpload },
-    
+    components: { Upload, clUpload },
+
     data() {
         return {
+            auditStatus: 1,
             headers: {
                 Authorization: `tf: ${uni.getStorageSync('access-token')}`,
             },
@@ -101,14 +120,18 @@ export default {
         if (query.fieldName) this.fieldName = query.fieldName
         if (query.fieldVal) {
             this.fileList = JSON.parse(query.fieldVal)
-            
-            if(this.fileList.length > 0 && this.fileList[0].type) {
-                if(this.fileList[0].type.includes('video')) {
+
+            if (this.fileList.length > 0 && this.fileList[0].type) {
+                if (this.fileList[0].type.includes('video')) {
                     this.videoUrl = this.fileList[0].url
-                    this.videoCoverUrl =  this.fileList[0].coverUrl
-                } 
+                    this.videoCoverUrl = this.fileList[0].coverUrl
+                }
+                // 找到第一个1/3就返回对应数值,找不到返回默认值0
+
             }
+            this.auditStatus = this.fileList.find(item => item.auditStatus == 0 || item.auditStatus == 2)?.auditStatus || 1
         }
+        console.log(this.fileList, this.auditStatus)
         if (query.maxlength) this.maxlength = Number(query.maxlength)
         if (query.title) this.title = query.title
     },
@@ -121,8 +144,8 @@ export default {
     onShow() {
     },
     methods: {
-        onSuccess(reslut,tempFile) {
-            console.log(reslut,tempFile)
+        onSuccess(reslut, tempFile) {
+            console.log(reslut, tempFile)
             // 把服务端返回的图片地址添加到list中与组件数据同步
             if (reslut.code === 200) {
                 const isVideo =
@@ -133,11 +156,11 @@ export default {
                 if (isVideo) {
                     this.videoUrl = baseUrl + reslut.url
                     this.videoCoverUrl = baseUrl + reslut.coverUrl
-                    this.fileList=[{
-                       url: baseUrl + reslut.url,
-                       type: tempFile.tempFile.type,
-                       size: tempFile.size,
-                       coverUrl: baseUrl + reslut.coverUrl,
+                    this.fileList = [{
+                        url: baseUrl + reslut.url,
+                        type: tempFile.tempFile.type,
+                        size: tempFile.size,
+                        coverUrl: baseUrl + reslut.coverUrl,
                     }]
                 } else {
                     this.fileList.push(baseUrl + reslut.url)
@@ -179,7 +202,7 @@ export default {
 
         // upload事件
         onUpload(e) {
-            console.log(e,'6666')
+            console.log(e, '6666')
             this.fileList = e
         },
         goBack() {
@@ -223,16 +246,48 @@ export default {
         font-size: 26rpx;
         color: #86909C;
     }
+    .checkBox {
+        padding: 30rpx 32rpx 24rpx 32rpx;
+        height: 134rpx;
+        border-radius: 8rpx 8rpx 8rpx 8rpx;
 
+        //color: #FF7D00;
+        .checkStatus {
+            font-weight: 500;
+            font-size: 30rpx;
+            text-align: left;
+            display: flex;
+            align-items: center;
+
+        }
 
+        .contactCustomer {
+            width: 144rpx;
+            height: 44rpx;
+            border-radius: 24rpx 24rpx 24rpx 24rpx;
+
+            font-weight: 400;
+            font-size: 26rpx;
+            text-align: center;
+
+        }
+
+        .text {
+            margin-top: 8rpx;
+            font-weight: 400;
+            font-size: 26rpx;
+            text-align: left;
+        }
+    }
 
     ::v-deep .u-cell-group {
         padding: 32rpx;
         background-color: #fff;
-        .upload-block{
+
+        .upload-block {
             width: 160rpx;
             height: 160rpx;
-            background-color: #F7F8FA ;
+            background-color: #F7F8FA;
             display: flex;
             justify-content: center;
             align-items: center;
@@ -259,6 +314,7 @@ export default {
         }
     }
 }
+
 ::v-deep .u-upload__success {
     display: none;
 }
@@ -270,7 +326,7 @@ export default {
 ::v-deep .u-upload__deletable {
     border-top-right-radius: 12rpx;
     border-bottom-left-radius: 12rpx;
-    
+
 }
 
 ::v-deep .u-upload__deletable__icon {

+ 1 - 1
src/pages/join/staff.vue

@@ -10,7 +10,7 @@
 					color: ShopInfo.merchant.auditStatus === 3 ? '#F53F3F' : '#FF7D00',
 					background: ShopInfo.merchant.auditStatus === 3 ? '#FFF5F5' : '#FFF8EC'
 				}">
-				<view class="checkStatus">审核中</view>
+				<view class="checkStatus">{{ShopInfo.merchant.auditStatus == 3 ? '审核驳回' : '审核中'}}</view>
 				<view class="text">入驻审核中,审核结果将会在X-X个工作日通知您</view>
 			</view>
 			<view class="title">

+ 25 - 16
src/pages/my/dynamic/add_dynamic.vue

@@ -24,9 +24,9 @@
           count: 9,
           size: 2,
         }" :videoFromData="{
-            count: 1,
-            size: 50,
-          }" :maxVideo="1" :fileType="mediaType" addImg="/static/discover/ic_upload.png"
+          count: 1,
+          size: 50,
+        }" :maxVideo="1" :fileType="mediaType" addImg="/static/discover/ic_upload.png"
           deleteImg="/static/discover/ic_delete.png" @onSuccess="onSuccess" @onMediaTypeSelect="selectMediaType"
           @onError="onCancel"></clUpload>
       </view>
@@ -197,6 +197,7 @@ export default {
               this.mediaType = 'image'
               this.uploadApi = baseUrl + '/common/uploads'
               this.fileList = data.mediaList.map(item => item.mediaUrl)
+              console.log(this.fileList)
             } else if (mediaType === 2) {
               // 视频类型
               this.mediaType = 'video'
@@ -222,6 +223,7 @@ export default {
           reslut.url.endsWith('.mov') ||
           reslut.url.endsWith('.mkv') ||
           reslut.url.endsWith('.wmv')
+          console.log(isVideo,'isVideo')
         if (isVideo) {
           this.formData.videoUrl = baseUrl + reslut.url
           this.formData.videoCoverUrl = baseUrl + reslut.coverUrl
@@ -240,6 +242,9 @@ export default {
       } else if (type === 'video') {
         this.uploadApi = baseUrl + '/common/uploadVi'
         this.mediaType = 'video'
+      }else if (type === 'audio') {
+        this.uploadApi = baseUrl + '/common/uploadVi'
+        this.mediaType = 'audio'
       }
     },
     // 处理媒体类型取消事件
@@ -319,21 +324,25 @@ export default {
         longitude: data.longitude || '',
       }
       this.formData = { ...this.formData, ...resData }
+
       // 回显媒体文件
-      if (data.mediaList && data.mediaList.length > 0) {
-        const mediaType = data.mediaList[0].mediaType
-        if (mediaType === 1) {
-          // 图片类型
-          this.mediaType = 'image'
-          this.uploadApi = baseUrl + '/common/uploads'
-          this.fileList = data.mediaList.map(item => item.mediaUrl)
-        } else if (mediaType === 2) {
-          // 视频类型
-          this.mediaType = 'video'
-          this.uploadApi = baseUrl + '/common/uploadVi'
-          this.formData.videoUrl = data.mediaList[0].mediaUrl
-          this.formData.videoCoverUrl = data.coverUrl
+
+      if (data.mediaType === 1) {
+        // 图片类型
+        this.mediaType = 'image'
+        this.uploadApi = baseUrl + '/common/uploads'
+        if (data.coverUrl.includes(',')) {
+          this.fileList = data.coverUrl.split(',')
+          
+        }else{
+          this.fileList=[data.coverUrl]
         }
+      } else if (data.mediaType === 2) {
+        // 视频类型
+        this.mediaType = 'video'
+        this.uploadApi = baseUrl + '/common/uploadVi'
+        this.formData.videoUrl = data.coverUrl
+        this.formData.videoCoverUrl = data.coverUrl
       }
       this.popShow1 = false
 

+ 13 - 3
src/pages/my/dynamic/components/my_list.vue

@@ -54,6 +54,8 @@
 </template>
 
 <script>
+import { dynamicDelete } from '@/api/dynamic.js'
+
 export default {
   name: 'my-list',
   props: {
@@ -91,9 +93,17 @@ export default {
     //删除
     sure() {
       this.showModal = false
-      uni.showToast({
-        title: '动态删除成功',
-        icon: 'none'
+      dynamicDelete({
+        momentId: this.currentObj.id,
+      }).then(res => {
+        console.log(res)
+        if (res.data.code == 200) {
+          uni.showToast({
+            title: res.data.msg,
+            icon: 'none'
+          })
+          this.$emit('refreshList')
+        }
       })
 
     },

+ 1 - 1
src/pages/my/dynamic/index.vue

@@ -5,7 +5,7 @@
     }" @query="queryList">
 
       <!-- 我的动态 -->
-      <my-dynamic-list :data-list="dynamicList"></my-dynamic-list>
+      <my-dynamic-list :data-list="dynamicList" @refreshList="queryList"></my-dynamic-list>
 
 
       <template v-slot:empty>

BIN
src/static/login/status1.png


BIN
src/static/login/status2.png


BIN
src/static/workbench/logout.png


+ 177 - 41
src/workbench/city/apply.vue

@@ -17,40 +17,29 @@
 			</view>
 			<view class="reason-block">
 				<text class="label">申请原因</text>
-				<textarea
-					class="reason-input"
-					v-model="form.reason"
-					placeholder="请输入原因"
-					maxlength="500"
-					@input="onReasonInput"
-				/>
+				<textarea class="reason-input" v-model="form.reason" placeholder="请输入原因" maxlength="500"
+					@input="onReasonInput" />
 				<text class="char-count">{{ form.reason.length }}/500</text>
 			</view>
 		</view>
 
-	
+
 		<view class="footer-bar">
 			<view class="submit-btn" @click="onSubmit">申请开通</view>
 		</view>
 
 		<!-- 省 / 市 二级联动 -->
-		<u-picker
-			:show="showCityPicker"
-			:columns="cityColumns"
-			keyName="name"
-			@change="onCityColumnChange"
-			@confirm="onCityConfirm"
-			@cancel="showCityPicker = false"
-		></u-picker>
+		<u-popup :show="showCityPicker" mode="bottom" border-radius="16rpx 16rpx 0 0"
+			:style="{ height: '600rpx', zIndex: 9999, }">
+			<u-picker :key="pickerKey" :defaultIndex="defaultCityIndex" :show="showCityPicker" ref="uPicker"
+				confirmColor="#fff" title="选择城市" keyName="name" :columns="cityColumns"
+				@confirm="onSelect" @change="changeHandler" @cancel="showCityPicker = false"></u-picker>
+
+		</u-popup>
 
 		<!-- 运营中心 -->
-		<u-picker
-			:show="showCenterPicker"
-			:columns="[centerOptions]"
-			keyName="name"
-			@confirm="onCenterConfirm"
-			@cancel="showCenterPicker = false"
-		></u-picker>
+		<u-picker :show="showCenterPicker" :defaultIndex="defaultCenterIndex" title="运营中心" :columns="[centerOptions]" keyName="name"
+			@confirm="onCenterConfirm" @cancel="showCenterPicker = false" confirmColor="#fff"></u-picker>
 	</view>
 </template>
 
@@ -60,13 +49,20 @@ import {
 	getCitiesByProvince,
 	getCentersByCity,
 } from './mock.js'
+import { saveCity } from '@/api/workbench.js'
+import { provinceCityTree, regionList } from '@/api/newLogin.js'
 
 export default {
 	data() {
 		return {
+			defaultCityIndex: [0, 0],
+			defaultCenterIndex: [0],
+			pickerKey: 1,
 			form: {
 				province: '',
 				city: '',
+				provinceCode: '',
+				cityCode: '',
 				centerId: '',
 				centerName: '',
 				reason: '',
@@ -76,6 +72,7 @@ export default {
 			cityColumns: [],
 			centerOptions: [],
 			provinceIndex: 0,
+			allCityList: [],
 		}
 	},
 	computed: {
@@ -86,7 +83,7 @@ export default {
 		},
 	},
 	onLoad() {
-		this.initCityPicker()
+		this.getCity()
 	},
 	methods: {
 		initCityPicker() {
@@ -94,6 +91,51 @@ export default {
 			const cities = getCitiesByProvince(provinces[0]?.name || '').map(c => ({ name: c.name }))
 			this.cityColumns = [provinces, cities]
 		},
+		//获取城市
+		getCity() {
+			provinceCityTree().then(res => {
+				console.log(res, '获取城市')
+				this.allCityList = res.data.data
+				const provinces = res.data.data.map(p => ({ name: p.name, code: p.code }))
+				const cities = this.getCitiesByProvince(this.form.provinceName || provinces[0]?.name || '').map(c => ({ name: c.name, code: c.code }))
+				this.cityColumns = [provinces, cities]
+			});
+		},
+		//选择城市
+		onSelect(e) {
+			if (!e.value[0]) return
+			this.form.province = e.value[0]?.name || ''
+			this.form.city = e.value[1]?.name || ''
+			this.form.provinceCode = e.value[0]?.code || ''
+			this.form.cityCode = e.value[1]?.code || ''
+			this.form.centerName = ''
+			this.showCityPicker = false
+		},
+		//滚动选择器
+		changeHandler(e) {
+			console.log(e, 'e')
+			const {
+				columnIndex,
+				value,
+				values, // values为当前变化列的数组内容
+				index,
+				picker = this.$refs.uPicker
+			} = e
+			// 当第一列值发生变化时,变化第二列(后一列)对应的选项
+			if (columnIndex === 0) {
+				// picker为选择器this实例,变化第二列对应的选项
+				const provinceName = this.allCityList[index]?.name
+				const cities = this.getCitiesByProvince(provinceName).map(c => ({ name: c.name, code: c.code }))
+				picker.setColumnValues(1, cities)
+
+			}
+
+
+		},
+		getCitiesByProvince(provinceName) {
+			const province = this.allCityList.find(p => p.name === provinceName)
+			return province ? province.children : []
+		},
 		onCityColumnChange(e) {
 			const { columnIndex, index } = e
 			if (columnIndex !== 0) return
@@ -105,33 +147,34 @@ export default {
 				cities,
 			]
 		},
-		onCityConfirm(e) {
-			const province = e.value[0]?.name || ''
-			const city = e.value[1]?.name || ''
-			if (province !== this.form.province || city !== this.form.city) {
-				this.form.centerId = ''
-				this.form.centerName = ''
-				this.centerOptions = []
-			}
-			this.form.province = province
-			this.form.city = city
-			this.showCityPicker = false
-		},
-		openCenterPicker() {
+		//选择运营中心
+		async openCenterPicker() {
 			if (!this.form.province || !this.form.city) {
 				uni.showToast({ title: '请先选择城市', icon: 'none' })
 				return
 			}
-			this.centerOptions = getCentersByCity(this.form.province, this.form.city)
+			await regionList({ parentCode: this.form.provinceCode, cityCode: this.form.cityCode }).then(res => {
+				if (res.data.code == 200) {
+					this.centerOptions = res.data.data.map(c => ({ name: c.deptName, deptId: c.deptId , disabled: /^(0,)*0$/.test(c.ancestors) ? true : false }))
+				}
+			})
 			if (!this.centerOptions.length) {
 				uni.showToast({ title: '该城市暂无运营中心', icon: 'none' })
 				return
 			}
 			this.showCenterPicker = true
 		},
+		//选择运营中心确认
 		onCenterConfirm(e) {
 			const center = e.value[0]
-			this.form.centerId = center.id
+			if (center && center.disabled) {
+				uni.showToast({
+					title: '该部门不可选,请选择其他部门',
+					icon: 'none'
+				})
+				return
+			}
+			this.form.centerId = center.deptId
 			this.form.centerName = center.name
 			this.showCenterPicker = false
 		},
@@ -153,14 +196,106 @@ export default {
 				return
 			}
 			// 提交接口待对接
-			uni.showToast({ title: '已提交,待审核', icon: 'none' })
-			setTimeout(() => uni.navigateBack(), 1000)
+			let params={
+				provinceCode: this.form.provinceCode,
+				provinceName: this.form.province,
+				cityCode: this.form.cityCode,
+				cityName: this.form.city,
+				operationCenterId: this.form.centerId,
+				operationCenterName: this.form.centerName,
+				applyReason: this.form.reason,
+				merchantId: uni.getStorageSync('userId'),
+			}
+			console.log(params, 'params')
+			console.log(this.form, 'form')
+			saveCity(params).then(res => {
+				if (res.data.code == 200) {
+					uni.showToast({ title: res.data.msg, icon: 'none' })
+					setTimeout(() => uni.navigateBack(), 1000)
+				}
+			})
+			
 		},
 	},
 }
 </script>
 
 <style lang="scss" scoped>
+::v-deep .u-toolbar__title {
+	font-weight: 500;
+	font-size: 36rpx;
+	color: #1D2129;
+}
+
+::v-deep .u-picker__view__column__item {
+	font-weight: 400 !important;
+	font-size: 28rpx;
+	color: #1D2129
+}
+
+::v-deep .u-upload__success {
+	display: none;
+}
+
+::v-deep .u-picker {
+	bottom: 136rpx;
+	background-color: #ffffff;
+	position: relative;
+}
+
+::v-deep .u-toolbar__cancel__wrapper {
+	width: 30rpx;
+	height: 30rpx;
+	position: absolute;
+	right: 32rpx;
+	background-image: url('/static/login/closeIcon.png');
+	background-repeat: no-repeat;
+	background-size: 100% 100%;
+
+	.u-toolbar__wrapper__cancel {
+		width: 30rpx;
+		height: 30rpx;
+
+		span {
+			display: none;
+		}
+
+	}
+}
+
+/* 关键:穿透隐藏原生 toolbar,只留插槽内容 */
+.u-toolbar {
+	z-index: 9999 !important;
+	display: block !important;
+}
+
+::v-deep .u-toolbar__cancel__wrapper {
+	color: #666;
+}
+
+::v-deep .u-toolbar__confirm__wrapper {
+	position: fixed;
+	bottom: 0;
+	width: 100%;
+	padding: 24rpx 48rpx;
+
+	.u-toolbar__wrapper__confirm {
+		width: 654rpx;
+		height: 88rpx;
+		background: #333335;
+		border-radius: 60rpx 60rpx 60rpx 60rpx;
+
+		font-weight: 400;
+		font-size: 32rpx;
+		color: #FFFFFF;
+		text-align: center;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+}
+
+
 .apply-page {
 	min-height: 100vh;
 	background: #f5f5f5;
@@ -231,6 +366,7 @@ export default {
 	padding: 20rpx 32rpx;
 	padding-bottom: calc(env(safe-area-inset-bottom) + 20rpx);
 }
+
 .submit-btn {
 	margin: 0 auto;
 	width: 654rpx;

+ 16 - 12
src/workbench/city/index.vue

@@ -3,20 +3,20 @@
 		<view class="city-list" v-if="recordList.length">
 			<view class="city-card" v-for="item in recordList" :key="item.id">
 				<view class="card-head">
-					<text class="center-name">{{ item.centerName }}</text>
-					<text class="status-tag" :class="statusClass(item.status)">
-						{{ statusLabel(item.status) }}
+					<text class="center-name">{{ item.cityName }}-{{ item.operationCenterName }}</text>
+					<text class="status-tag" :class="item.status==0?'pending':item.status==1?'opened':'rejected'">
+						{{ item.status==0?'审核中':item.status==1?'已开通':'审核驳回' }}
 					</text>
 				</view>
 				<view class="card-divider"></view>
 				<view class="card-body">
 					<view class="meta-row">
 						<text class="meta-label">开通原因</text>
-						<text class="meta-value">{{ item.reason || '暂无' }}</text>
+						<text class="meta-value">{{ item.applyReason || '暂无' }}</text>
 					</view>
 					<view class="meta-row">
 						<text class="meta-label">开通时间</text>
-						<text class="meta-value">{{ item.openTime }}</text>
+						<text class="meta-value">{{ item.actualApprovalTime }}</text>
 					</view>
 				</view>
 			</view>
@@ -32,7 +32,7 @@
 
 <script>
 import { MOCK_CITY_RECORDS, CITY_STATUS_MAP } from './mock.js'
-
+import { getCityList } from '@/api/workbench.js'
 export default {
 	data() {
 		return {
@@ -45,13 +45,17 @@ export default {
 	methods: {
 		loadList() {
 			this.recordList = [...MOCK_CITY_RECORDS]
+			//接口就绪后替换
+			getCityList({
+				merchantId: uni.getStorageSync('userId'),
+			}).then(res => {
+				console.log(res)
+				if (res.data.code == 200) {
+					this.recordList = res.data.data
+				}
+			})
 		},
-		statusLabel(status) {
-			return CITY_STATUS_MAP[status]?.label || status
-		},
-		statusClass(status) {
-			return CITY_STATUS_MAP[status]?.class || ''
-		},
+		
 		goApply() {
 			uni.navigateTo({ url: '/workbench/city/apply' })
 		},

+ 9 - 1
src/workbench/contract/index.vue

@@ -18,6 +18,7 @@
 
 <script>
 import { MOCK_CONTRACT_LIST } from './mock.js'
+import { getContractRecords } from '@/api/workbench.js'
 
 export default {
 	data() {
@@ -31,7 +32,14 @@ export default {
 	methods: {
 		loadList() {
 			// 接口就绪后替换
-			this.contractList = [...MOCK_CONTRACT_LIST]
+			getContractRecords({
+				userId: uni.getStorageSync('userId'),
+			}).then(res => {
+				console.log(res)
+				if (res.data.code == 200) {
+					this.contractList = res.data.data
+				}
+			})
 		},
 		viewContract(item) {
 			const str = uni.$u.queryParams({

+ 31 - 2
src/workbench/fare/index.vue

@@ -121,6 +121,7 @@ const MOCK_OPENED_CATEGORIES = [
 	{ id: '1', name: '上门按摩' },
 	{ id: '3', name: '爬山' },
 ]
+import { saveFareSetting } from '@/api/workbench'
 export default {
 	data() {
 		return {
@@ -180,9 +181,37 @@ export default {
 				uni.showToast({ title: '请输入公里数', icon: 'none' })
 				return
 			}
+			let params = {
+				merchantId: uni.getStorageSync('userId'),
+				openId: uni.getStorageSync('openId'),
+				
+			}
+			if(this.settingMode === 'unified'){
+				params.mode=1
+				params.unifiedConfig= {
+					dayFreeKm: this.unifiedForm.dayKm,
+					nightFreeKm: this.unifiedForm.nightKm,
+				}
+				params.categoryConfigs=null
+			}else{
+				params.mode=2
+				params.unifiedConfig=null
+				params.categoryConfigs = this.projectForms.map(item => ({
+					categoryId: item.categoryId,
+					categoryName: item.categoryName,
+					dayFreeKm: item.dayKm,
+					nightFreeKm: item.nightKm,
+				}))
+
+			}
+			
 			// 保存接口待对接
-			uni.showToast({ title: '设置成功', icon: 'none' })
-			setTimeout(() => uni.navigateBack(), 1000)
+			saveFareSetting(params).then(res => {
+				if (res.data.code == 200) {
+					uni.showToast({ title: res.data.msg, icon: 'none' })
+					setTimeout(() => uni.navigateBack(), 1000)
+				}
+			})
 		},
 	},
 }