Преглед на файлове

工作台及工作台下级页面

付晓文。 преди 3 часа
родител
ревизия
7e04964375

+ 24 - 0
src/api/workbench.js

@@ -1,5 +1,6 @@
 import request from "@/utils/request.js";
 
+// 商户信息
 export function getTechnician(data) {
     return request({
         method: 'get',
@@ -9,4 +10,27 @@ export function getTechnician(data) {
 		    'Authorization': `tf:${uni.getStorageSync('access-token')}`
 		}
     });
+}
+// 切换上下班
+export function switchToOffline(data) {
+    return request({
+        method: 'get',
+        url: '/technician/technician/switchToOffline',
+        data,
+		header: {
+		    'Authorization': `tf:${uni.getStorageSync('access-token')}`
+		}
+    });
+}
+
+// 查询商户技能列表
+export function getSkillList(data) {
+    return request({
+        method: 'post',
+        url: '/technician/technician/getSkillList',
+        data,
+		header: {
+		    'Authorization': `tf:${uni.getStorageSync('access-token')}`
+		}
+    });
 }

+ 1370 - 1295
src/pages/index/index.vue

@@ -7,11 +7,9 @@
 			<view class="header-section">
 				<view class="header-main" @click="goProfile">
 					<view class="avatar-wrap">
-						<image
-							class="avatar"
+						<image class="avatar"
 							:src="merchantInfo.cPortrait ? $globalData.publicUrl + merchantInfo.cPortrait : '/static/common/avatar.png'"
-							mode="aspectFill"
-						/>
+							mode="aspectFill" />
 					</view>
 					<view class="header-info">
 						<view class="nickname">
@@ -94,7 +92,7 @@
 				<view class="order-card">
 					<view class="order-title-row">
 						<text class="order-title one-line-text">{{ orderTitle }}服务项目</text>
-						 <!-- v-if="isNewCustomer" -->
+						<!-- v-if="isNewCustomer" -->
 						<text class="tag-new">新客户</text>
 					</view>
 					<view class="order-time">
@@ -110,13 +108,9 @@
 						<view class="slide-wrap" id="slideWrap">
 							<view class="slide-track">
 								<text class="slide-hint">滑动接单</text>
-								<view
-									class="slide-thumb"
-									:style="{ transform: `translateX(${slideX}px)` }"
-									@touchstart="onSlideStart"
-									@touchmove.stop.prevent="onSlideMove"
-									@touchend="onSlideEnd"
-								>
+								<view class="slide-thumb" :style="{ transform: `translateX(${slideX}px)` }"
+									@touchstart="onSlideStart" @touchmove.stop.prevent="onSlideMove"
+									@touchend="onSlideEnd">
 									<image class="slide-arrow" src="/static/workbench/move.png" mode="aspectFit" />
 								</view>
 							</view>
@@ -143,14 +137,15 @@
 				<view v-if="skillList.length === 1" class="skill-single">
 					<view class="skill-card skill-card--single">
 						<view class="skill-img">
-							<image :src="skillList[0].cCover" mode="aspectFill" />
+							<image :src="public + skillList[0].projectMasterImage" mode="aspectFill" />
 						</view>
 						<view class="skill-info">
-							<view class="skill-name one-line-text">{{ skillList[0].cTitle }}</view>
-							<view class="skill-tags" v-if="skillList[0].cTags && skillList[0].cTags.length">
-								<view class="skill-tag" v-for="(tag, tagIndex) in skillList[0].cTags" :key="tagIndex">{{ tag }}</view>
+							<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">
+									{{ tag }}</view>
 							</view>
-							<view class="skill-price">¥{{ formatMoney(skillList[0].dPrice) }}</view>
+							<view class="skill-price">¥{{ formatMoney(skillList[0].projectCurrentPrice) }}</view>
 						</view>
 					</view>
 				</view>
@@ -159,11 +154,11 @@
 					<view class="skill-list">
 						<view class="skill-card skill-card--multi" v-for="(item, index) in skillList" :key="index">
 							<view class="skill-img">
-								<image :src="item.cCover" mode="aspectFill" />
+								<image :src="public + item.projectMasterImage" mode="aspectFill" />
 							</view>
 							<view class="skill-info">
-								<view class="skill-name one-line-text">{{ item.cTitle }}</view>
-								<view class="skill-price">¥{{ formatMoney(item.dPrice) }}</view>
+								<view class="skill-name one-line-text">{{ item.projectName }}</view>
+								<view class="skill-price">¥{{ formatMoney(item.projectCurrentPrice) }}</view>
 							</view>
 						</view>
 					</view>
@@ -194,12 +189,8 @@
 					<image class="more-tip" src="/static/workbench/skillTip.png" mode="aspectFit" />
 				</view>
 				<view class="more-grid">
-					<view
-						class="more-item"
-						v-for="(item, index) in moreFeatures"
-						:key="index"
-						@click="onMoreFeature(item)"
-					>
+					<view class="more-item" v-for="(item, index) in moreFeatures" :key="index"
+						@click="onMoreFeature(item)">
 						<image class="more-icon" :src="item.icon" mode="aspectFit" />
 						<text class="more-label">{{ item.label }}</text>
 					</view>
@@ -211,12 +202,7 @@
 		<view class="popup-mask" v-if="showRejectPopup" @click="closeRejectPopup">
 			<view class="popup-box" @click.stop>
 				<view class="popup-title">请输入拒绝接单原因</view>
-				<input
-					class="popup-input"
-					v-model="rejectReason"
-					maxlength="10"
-					placeholder="请输入拒绝原因,最多10个字"
-				/>
+				<input class="popup-input" v-model="rejectReason" maxlength="10" placeholder="请输入拒绝原因,最多10个字" />
 				<view class="popup-btns">
 					<view class="popup-btn" @click="closeRejectPopup">取消</view>
 					<view class="popup-btn confirm" @click="submitReject">提交</view>
@@ -228,11 +214,7 @@
 		<view class="popup-mask bottom" v-if="showStatusPopup" @click="showStatusPopup = false">
 			<view class="status-panel" @click.stop>
 				<view class="panel-title">接单状态</view>
-				<view
-					class="status-option"
-					:class="{ active: statusDraft === 'rest' }"
-					@click="statusDraft = 'rest'"
-				>
+				<view class="status-option" :class="{ active: statusDraft === 'rest' }" @click="statusDraft = 'rest'">
 					<view class="option-body">
 						<text class="option-name">{{ !isWorking ? '休息中' : '下线休息' }}</text>
 						<text class="option-desc">{{ getStatusDesc('rest') }}</text>
@@ -241,11 +223,8 @@
 						<image src="@/static/workbench/checkCircle.png" mode=""></image>
 					</view>
 				</view>
-				<view
-					class="status-option"
-					:class="{ active: statusDraft === 'working' }"
-					@click="statusDraft = 'working'"
-				>
+				<view class="status-option" :class="{ active: statusDraft === 'working' }"
+					@click="statusDraft = 'working'">
 					<view class="option-body">
 						<text class="option-name">在线接单</text>
 						<text class="option-desc">{{ getStatusDesc('working') }}</text>
@@ -282,1328 +261,1424 @@
 </template>
 
 <script>
-import {
-	getMerchantData,
-	getInfo,
-	myIncome,
-	getStaffWorkData,
-	getWaitOrder,
-	myBank,
-	getProjectByJsId,
-	netStaffWork,
-	getJsLocation,
-} from '@/api/index';
-import { orderDeatails, takeOrder, refuseOrder } from '@/api/order.js';
-
-import { getTechnician } 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,
-			skillList: [
-				{ 
-					cTitle: '中式推拿中式推拿中式推拿中式推拿中式推拿', 
-					dPrice: 128, 
-					cCover: 'https://cdn.uviewui.com/uview/album/1.jpg' ,
-					cTags:['多人团购','热门剧本','环境干净']
+	import {
+		getMerchantData,
+		getInfo,
+		myIncome,
+		getStaffWorkData,
+		getWaitOrder,
+		myBank,
+		getProjectByJsId,
+		netStaffWork,
+		getJsLocation,
+	} from '@/api/index';
+	import {
+		orderDeatails,
+		takeOrder,
+		refuseOrder
+	} from '@/api/order.js';
+
+	import {
+		getTechnician,
+		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',
 				},
-				// { cTitle: '中式推拿', dPrice: 128, cCover: 'https://cdn.uviewui.com/uview/album/2.jpg' },
-				// { cTitle: '中式推拿', dPrice: 128, cCover: 'https://cdn.uviewui.com/uview/album/3.jpg' },
-				// { cTitle: '中式推拿', dPrice: 128, cCover: 'https://cdn.uviewui.com/uview/album/4.jpg' },
-				// { cTitle: '中式推拿', dPrice: 128, cCover: 'https://cdn.uviewui.com/uview/album/5.jpg' },
-				// { cTitle: '中式推拿', dPrice: 128, cCover: 'https://cdn.uviewui.com/uview/album/6.jpg' },
-			],
-			currentAddress: '',
-			showRejectPopup: false,
-			rejectReason: '',
-			showStatusPopup: false,
-			statusDraft: 'working',
-			slideX: 0,
-			slideStartX: 0,
-			slideMax: 0,
-			isSliding: false,
-			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/my/indent?title=编辑资料' },
-				{ label: '城市管理', icon: '/static/workbench/city.png', path: '/workbench/city/index' },
-			],
-		}
-	},
-	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() {
-		this.syncCurrentAddress()
-		this.loadPageData()
-	},
-	onLoad() {
-		setTimeout(() => {
-			console.log('666')
-			this.showModal = true
-		}, 500);
-	},
-	methods: {
-		// 我在想想:关闭弹窗
-		cancel() {
-			console.log('5555')
-			this.showModal = false
-		},
-		// 立即入驻:跳转入驻页
-		goEnter() {
-			this.showModal = false
-			uni.navigateTo({
-				url: '/pages/join/applyJoin' // 替换你的入驻页面路径
-			})
-		},
-		loadPageData() {
-			this.fetchMerchantInfo()
-			this.fetchWalletInfo()
-			this.fetchIncome()
-			this.fetchWorkData()
-			this.fetchBankCards()
-			
-			this.getWorkInfo();
-		},
-		getWorkInfo(){
-			let params = { openid: uni.getStorageSync('wx_copenid') }
-			getTechnician(params).then(res => {
-				console.log('res----',res)
-			})
-		},
-		fetchMerchantInfo() {
-			const params = { cOpenId: uni.getStorageSync('wx_copenid') }
-			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()
-			})
+				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/my/indent?title=编辑资料' },
+					{ label: '城市管理', icon: '/static/workbench/city.png', path: '/workbench/city/index' },
+				],
+			}
 		},
-		fetchWalletInfo() {
-			getInfo().then(res => {
-				if (res.data.code == 200 && res.data.data) {
-					this.cJsId = res.data.data.id;
-				}
-			})
+		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
+			},
 		},
-		fetchIncome() {
-			myIncome().then(res => {
-				if (res.data.code == 200 && res.data.data) {
-					this.myIncome = res.data.data
-				}
-			})
+		onShow() {
+			this.loadPageData()
 		},
-		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$/, '')
-				}
-			})
+		onLoad() {
+			setTimeout(() => {
+				console.log('666')
+				this.showModal = true
+			}, 500);
 		},
-		fetchBankCards() {
-			myBank().then(res => {
-				if (res.data.code == 200 && Array.isArray(res.data.data)) {
-					// this.bankCardCount = res.data.data.length
+		methods: {
+			// 我在想想:关闭弹窗
+			cancel() {
+				console.log('5555')
+				this.showModal = false
+			},
+			// 立即入驻:跳转入驻页
+			goEnter() {
+				this.showModal = false
+				uni.navigateTo({
+					url: '/pages/join/applyJoin' // 替换你的入驻页面路径
+				})
+			},
+			loadPageData() {
+				// this.fetchMerchantInfo()
+				// this.fetchWalletInfo()
+				// this.fetchIncome()
+				// this.fetchWorkData()
+				// this.fetchBankCards()
+
+				this.getWorkInfo();
+			},
+			getWorkInfo() {
+				let params = {
+					openid: uni.getStorageSync('wx_copenid')
 				}
-			})
-		},
-		fetchTodayOrders() {
-			if (!this.cJsId) return
-			getWaitOrder({ cJsId: this.cJsId }).then(res => {
-				if (res.data.code == 200) {
-					this.todayOrderCount = res.data.data || 0
+				getTechnician(params).then(res => {
+					console.log('res----', res)
+					if (res.data.code == 200) {
+						this.cJsId = res.data.result.id; //用户id
+						/**
+						 * 服务标签(1:按摩推拿 2:陪玩)
+						 */
+						this.serviceTag = res.data.result.serviceTag
+						uni.setStorageSync('serviceTag', res.data.result.serviceTag)
+						uni.setStorageSync('userId', res.data.result.id)
+						this.getSkillList();
+					}
+
+				})
+			},
+			getSkillList() {
+				let params = {
+					auditStatus: "1", //审核状态:0-待审核,1-审核通过,2-审核驳回
+					userId: this.cJsId, //商户ID
+					typeId: this.serviceTag //服务标签ID
 				}
-			})
-		},
-		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
+				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')
 				}
-			})
-		},
-		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
+				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}`
+					}
 				}
-			})
-		},
-		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}个小时`
 				}
-			}
-			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 '早起的人已经接单,勤奋的人账户常满'
 				}
-				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
-			}
-			netStaffWork({
-				id: this.cJsId,
-				nStatus2: working ? '0' : '-1',
-			}).then(res => {
-				if (res.data.code == 200) {
-					this.isWorking = working
-					const now = new Date().toISOString()
-					if (working) {
-						this.workStartTime = now
+				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'
+						})
 					} else {
-						this.restStartTime = now
+						uni.showToast({
+							title: res.data.msg || '设置失败',
+							icon: 'none'
+						})
 					}
-					uni.showToast({ title: working ? '已上线' : '已下线', icon: 'none' })
-				} else {
-					uni.showToast({ title: res.data.msg || '设置失败', icon: 'none' })
-				}
-			})
-		},
-		onRejectOrder() {
-			this.showRejectPopup = true
-			this.rejectReason = ''
-		},
-		closeRejectPopup() {
-			this.showRejectPopup = false
-			this.rejectReason = ''
-		},
-		submitReject() {
-			const reason = this.rejectReason.trim()
-			if (!reason) {
-				uni.showToast({ title: '拒绝原因不能为空', 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' })
+				})
+			},
+			onRejectOrder() {
+				this.showRejectPopup = true
+				this.rejectReason = ''
+			},
+			closeRejectPopup() {
+				this.showRejectPopup = false
+				this.rejectReason = ''
+			},
+			submitReject() {
+				const reason = this.rejectReason.trim()
+				if (!reason) {
+					uni.showToast({
+						title: '拒绝原因不能为空',
+						icon: 'none'
+					})
+					return
 				}
-			})
-		},
-		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)
+				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'
+						})
 					}
 				})
-			})
-		},
-		onSlideStart(e) {
-			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)
+						}
+					})
+				})
+			},
+			onSlideStart(e) {
+				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()
 				}
-			})
-		},
-		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' })
-		},
-		goWithdraw() {
-			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' })
-		},
-		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'),
+				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'
+						})
+					}
+				})
+			},
+			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'
+				})
+			},
+			goWithdraw() {
+				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 apiRes = await getJsLocation(params)
-				if (apiRes.data.code == 200) {
-					uni.setStorageSync('staffLocation', {
+				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,
+						})
+						this.syncCurrentAddress()
+						uni.showToast({
+							title: '地址已更新',
+							icon: 'none'
+						})
+					} else {
+						uni.showToast({
+							title: apiRes.data.msg || '更新失败',
+							icon: 'none'
+						})
+					}
+				} catch (err) {
+					if (err?.cancelled) return
+					uni.showToast({
+						title: err?.message || '获取位置失败',
+						icon: 'none'
 					})
-					this.syncCurrentAddress()
-					uni.showToast({ title: '地址已更新', icon: 'none' })
-				} else {
-					uni.showToast({ title: apiRes.data.msg || '更新失败', icon: 'none' })
 				}
-			} catch (err) {
-				if (err?.cancelled) return
-				uni.showToast({ title: err?.message || '获取位置失败', icon: 'none' })
-			}
-		},
-		onMoreFeature(item) {
-			if (!item.path) {
-				uni.showToast({ title: '功能开发中', icon: 'none' })
-				return
-			}
-			uni.navigateTo({ url: item.path })
+			},
+			onMoreFeature(item) {
+				if (!item.path) {
+					uni.showToast({
+						title: '功能开发中',
+						icon: 'none'
+					})
+					return
+				}
+				uni.navigateTo({
+					url: item.path
+				})
+			},
 		},
-	},
-}
+	}
 </script>
 
 <style lang="scss" scoped>
-// 弹窗
-.modal-wrap {
-	width: 620rpx;
-	background: #fff;
-	border-radius: 16rpx;
-	overflow: hidden;
-
-	.title {
-		font-size: 42rpx;
-		text-align: center;
-		padding: 40rpx 30rpx 20rpx;
-		font-weight: 500;
-		color: #333;
-	}
+	// 弹窗
+	.modal-wrap {
+		width: 620rpx;
+		background: #fff;
+		border-radius: 16rpx;
+		overflow: hidden;
+
+		.title {
+			font-size: 42rpx;
+			text-align: center;
+			padding: 40rpx 30rpx 20rpx;
+			font-weight: 500;
+			color: #333;
+		}
 
-	.content {
-		font-size: 36rpx;
-		color: #333;
-		padding: 0 40rpx 40rpx;
-		line-height: 1.7;
-	}
+		.content {
+			font-size: 36rpx;
+			color: #333;
+			padding: 0 40rpx 40rpx;
+			line-height: 1.7;
+		}
 
-	.btn-box {
-		display: flex;
-		border-top: 1rpx solid #eee;
-	}
+		.btn-box {
+			display: flex;
+			border-top: 1rpx solid #eee;
+		}
 
-	.btn {
-		flex: 1;
-		height: 90rpx;
-		display: flex;
-		align-items: center;
-		justify-content: center;
-		font-size: 36rpx;
-	}
+		.btn {
+			flex: 1;
+			height: 90rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			font-size: 36rpx;
+		}
 
-	.left {
-		color: #333;
-		border-right: 1rpx solid #eee;
-	}
-
-	.right {
-		color: #007aff;
-	}
-
-}
-$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;
-}
-
-.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;
-		image{
-			width: 410rpx;
-			height: 50rpx;
+		.left {
+			color: #333;
+			border-right: 1rpx solid #eee;
+		}
+
+		.right {
+			color: #007aff;
 		}
-	}
-}
-
-
-
-.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;
-		margin-bottom: 24rpx;
-	}
 
-	.section-heading-wrap {
-		display: flex;
-		align-items: flex-start;
 	}
 
-	.section-heading-box {
+	$primary: #1ecbc3;
+	$primary-dark: #0fa89e;
+	$text-main: #333333;
+	$text-sub: #999999;
+	$page-bg: #f6f7f9;
+
+	.workbench {
+		min-height: 100vh;
+		background: $page-bg;
 		position: relative;
-		display: inline-flex;
-		flex-direction: column;
+		box-sizing: border-box;
 	}
 
-	.section-heading {
+	.page-bg {
+		position: absolute;
+		top: -170rpx;
+		left: 0;
+		width: 100%;
+		z-index: 0;
+		height: 420rpx;
+	}
+
+	.page-content {
 		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%;
+		padding: 20rpx 24rpx 40rpx;
+		box-sizing: border-box;
 	}
 
-	.skill-tip {
-		width: 40rpx;
-		height: 40rpx;
-		margin-left: 8rpx;
-		margin-top: 2rpx;
-		flex-shrink: 0;
+	.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);
 	}
 
-	.section-link {
-		display: flex;
-		align-items: center;
-		font-size: 28rpx;
-		color: #86909C;
-		flex-shrink: 0;
+	.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);
 	}
 
-	.link-arrow {
-		width: 30rpx;
-		height: 30rpx;
-		margin-left: 4rpx;
+	/* 头部 */
+	.header-section {
+		padding: 16rpx 8rpx 32rpx;
 	}
-}
-
-.skill-single {
-	width: 100%;
-}
-
-.skill-scroll {
-	width: 100%;
-}
-
-.skill-list {
-	display: flex;
-	flex-direction: row;
-	flex-wrap: nowrap;
-}
 
-.skill-card {
-	display: flex;
-	align-items: center;
-	padding: 16rpx;
-	border: 1rpx solid #eeeeee;
-	border-radius: 16rpx;
-	background: #ffffff;
-	box-sizing: border-box;
-}
-
-.skill-card--single {
-	width: 100%;
-
-	.skill-img {
-		width: 160rpx;
-		height: 160rpx;
-		margin-right: 20rpx;
+	.header-main {
+		display: flex;
+		align-items: center;
 	}
-}
 
-.skill-card--multi {
-	flex-shrink: 0;
-	width: 380rpx;
-	margin-right: 20rpx;
-
-	&:last-child {
-		margin-right: 0;
+	.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);
 	}
-}
 
-.skill-img {
-	width: 88rpx;
-	height: 88rpx;
-	background: #f5f5f5;
-	border-radius: 10rpx;
-	overflow: hidden;
-	flex-shrink: 0;
-	margin-right: 14rpx;
-
-	image {
+	.avatar {
 		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;
-}
-
-.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: 20rpx;
+
+	.header-info {
+		margin-left: 24rpx;
+		flex: 1;
+		min-width: 0;
 	}
 
-	.section-heading {
-		font-size: 32rpx;
-		color: #1D2129;
+	.nickname {
+		font-size: 36rpx;
+		color: $text-main;
 		font-weight: 600;
 		line-height: 1.4;
-		padding-bottom: 10rpx;
-		background-image: url('/static/workbench/more.png');
-		background-repeat: no-repeat;
-		background-size: 80%;
 	}
 
-	.address-tip {
-		width: 40rpx;
-		height: 40rpx;
-		margin-left: 8rpx;
-		margin-top: 2rpx;
-		flex-shrink: 0;
-	}
-}
-
-.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 {
+	.status-bar {
 		display: flex;
-		align-items: flex-start;
-		margin-bottom: 20rpx;
+		align-items: center;
+		gap: 16rpx;
+		margin-top: 16rpx;
 	}
 
-	.section-heading {
-		font-size: 32rpx;
+	.status-tag {
+		display: flex;
+		align-items: center;
+		padding: 6rpx 16rpx;
+		font-size: 22rpx;
+		border-radius: 24rpx;
 		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%;
+		background: linear-gradient(263deg, #45FFD7 0%, #78FFA5 100%);
 	}
 
-	.more-tip {
-		width: 40rpx;
-		height: 40rpx;
-		margin-left: 8rpx;
-		margin-top: 2rpx;
-		flex-shrink: 0;
+	.status-tag-icon {
+		width: 24rpx;
+		height: 24rpx;
+		margin-right: 6rpx;
 	}
-}
-
-.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;
-		color: #fff;
+
+	.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);
 	}
-}
 
-.one-line-text {
-	overflow: hidden;
-	text-overflow: ellipsis;
-	white-space: nowrap;
-}
-</style>
+	.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;
+
+			image {
+				width: 410rpx;
+				height: 50rpx;
+			}
+		}
+	}
+
+
+
+	.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;
+			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%;
+	}
+
+	.skill-list {
+		display: flex;
+		flex-direction: row;
+		flex-wrap: nowrap;
+	}
+
+	.skill-card {
+		display: flex;
+		align-items: center;
+		padding: 16rpx;
+		border: 1rpx solid #eeeeee;
+		border-radius: 16rpx;
+		background: #ffffff;
+		box-sizing: border-box;
+	}
+
+	.skill-card--single {
+		width: 100%;
+
+		.skill-img {
+			width: 160rpx;
+			height: 160rpx;
+			margin-right: 20rpx;
+		}
+	}
+
+	.skill-card--multi {
+		flex-shrink: 0;
+		width: 380rpx;
+		margin-right: 20rpx;
+
+		&:last-child {
+			margin-right: 0;
+		}
+	}
+
+	.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;
+	}
+
+	.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: 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%;
+		}
+
+		.address-tip {
+			width: 40rpx;
+			height: 40rpx;
+			margin-left: 8rpx;
+			margin-top: 2rpx;
+			flex-shrink: 0;
+		}
+	}
+
+	.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;
+			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;
+	}
+
+	.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;
+			color: #fff;
+		}
+	}
+
+	.one-line-text {
+		overflow: hidden;
+		text-overflow: ellipsis;
+		white-space: nowrap;
+	}
+</style>

+ 10 - 2
src/setting/myNew/phone.vue

@@ -59,6 +59,7 @@ export default {
     },
     //登录
     loginPhoneFun() {
+		
       var _this = this;
       if (this.isBinding) return
 
@@ -87,20 +88,27 @@ export default {
       }
 
       this.isBinding = true
+	  
       clientLogin({
         //openId: uni.getStorageSync('wx_copenid'),
         userType: '2',
         phone: _this.phone,
         codeSwitch: 'false',//是否开启验证码登录 true-是 false-否
-        passWord: this.passWord
+        passWord: _this.password
       }).then(res => {
+		  console.log('-----',res);
         if (res.data.code == 200) {
           uni.showToast({
             title: '登录成功',
             icon: 'success'
           })
           uni.setStorageSync('wx_phone', _this.phone)
-          _this.isBinding = false;
+		  uni.setStorageSync('wx_copenid', res.data.result.copenid || '')
+		  uni.setStorageSync('access-token', res.data.result.token)
+		  uni.setStorageSync('phone', res.data.result.cphone)
+		  uni.setStorageSync('wx_phone', res.data.result.cphone)
+		 
+		  _this.isBinding = false;
           _this.back();
         }
       })

BIN
src/static/workbench/addSkill.png


BIN
src/static/workbench/skillTime.png


BIN
src/static/workbench/tabs.png


+ 295 - 123
src/workbench/skill/index.vue

@@ -1,19 +1,22 @@
 <template>
 	<view class="skill-page">
-		<!-- 顶栏:开通新服务 -->
-		<view class="top-bar">
-			<text class="top-link" @click="goAdd">开通新服务</text>
-		</view>
-
-		<!-- 分类 Tab -->
-		<scroll-view scroll-x class="category-tabs" :show-scrollbar="false">
+		<!-- 陪玩:分类 Tab -->
+		<scroll-view v-if="isPlaymate" scroll-x class="category-tabs" :show-scrollbar="false">
 			<view
-				v-for="cat in categories"
-				:key="cat.id"
+				v-for="tab in playmateTabs"
+				:key="tab.id"
 				class="category-tab"
-				:class="{ active: activeCategory === cat.id }"
-				@click="activeCategory = cat.id"
-			>{{ cat.name }}</view>
+				:class="{ active: activeCategory === tab.id }"
+				@click="activeCategory = tab.id"
+			>
+				<text class="category-tab__text">{{ tab.name }}</text>
+				<image
+					v-if="activeCategory === tab.id"
+					class="category-tab__indicator"
+					src="/static/workbench/tabs.png"
+					mode="widthFix"
+				/>
+			</view>
 		</scroll-view>
 
 		<!-- 状态筛选 -->
@@ -23,50 +26,65 @@
 				:key="tab.key"
 				class="status-tab"
 				:class="{ active: activeStatus === tab.key }"
-				@click="activeStatus = tab.key"
+				@click="onStatusChange(tab.key)"
 			>{{ tab.label }}</view>
 		</view>
 
 		<!-- 技能列表 -->
 		<view class="skill-list" v-if="filteredList.length">
-			<view class="skill-card" v-for="item in filteredList" :key="item.id">
-				<view class="card-main">
-					<view class="cover">
-						<image v-if="item.cover" :src="item.cover" mode="aspectFill" />
-					</view>
-					<view class="info">
-						<view class="title-row">
-							<text class="title">{{ item.title }}</text>
-							<text class="sold" v-if="item.status === 'opened' && item.soldCount">已售{{ item.soldCount }}</text>
+			<view class="skill-card" v-for="item in filteredList" :key="item.id || item.projectId">
+				<view class="card-body">
+					<view class="card-main">
+						<view class="cover">
+							<image v-if="getCover(item)" :src="getCover(item)" mode="aspectFill" />
+						</view>
+						<view class="info">
+							<view class="title-row">
+								<text class="title">{{ item.projectName }}</text>
+								<text class="sold" v-if="activeStatus === '1' && getSoldCount(item)">已售{{ getSoldCount(item) }}</text>
+							</view>
+							<text class="price">{{ formatSkillPrice(item) }}</text>
+							<view
+								class="status-bar"
+								:class="{ 'status-bar--opened': activeStatus === '1' }"
+								v-if="statusBarText(item)"
+								@click="onStatusBarClick(item)"
+							>
+								<image
+									v-if="activeStatus === '1'"
+									class="status-icon"
+									src="/static/workbench/skillTime.png"
+									mode="aspectFit"
+								/>
+								<text class="status-text">{{ statusBarText(item) }}</text>
+								<text class="chevron" v-if="activeStatus === '2'">&gt;</text>
+							</view>
 						</view>
-						<text class="price">{{ formatPrice(item) }}</text>
 					</view>
 				</view>
 
-				<!-- 状态条 -->
-				<view
-					class="status-bar"
-					v-if="statusBarText(item)"
-					@click="onStatusBarClick(item)"
-				>
-					<text class="status-text">{{ statusBarText(item) }}</text>
-					<text class="chevron" v-if="item.status === 'rejected'">&gt;</text>
-				</view>
-
 				<!-- 操作按钮 -->
-				<view class="card-actions" v-if="item.status !== 'pending'">
-					<template v-if="item.status === 'opened'">
-						<view class="btn ghost" @click="onOffShelf(item)">申请下架</view>
-						<view class="btn primary" v-if="item.canEdit" @click="goEdit(item)">编辑价格</view>
+				<view class="card-footer" v-if="activeStatus !== '0'">
+					<template v-if="activeStatus === '1'">
+						<view class="footer-btn footer-btn--ghost" @click="onOffShelf(item)">申请下架</view>
+						<view class="footer-divider"></view>
+						<view class="footer-btn footer-btn--primary" @click="goEdit(item)">编辑价格</view>
 					</template>
-					<template v-if="item.status === 'rejected'">
-						<view class="btn ghost" @click="onDelete(item)">删除</view>
-						<view class="btn primary" @click="openApplyModal([item])">重新申请</view>
+					<template v-if="activeStatus === '2'">
+						<view class="footer-btn footer-btn--ghost" @click="onDelete(item)">删除</view>
+						<view class="footer-divider"></view>
+						<view class="footer-btn footer-btn--primary" @click="openApplyModal([item])">重新申请</view>
 					</template>
 				</view>
 			</view>
 		</view>
-		<view class="empty" v-else>暂无数据</view>
+		<view class="empty" v-else-if="!loading">暂无数据</view>
+
+		<!-- 开通新服务 -->
+		<view class="fab-btn" @click="goAdd">
+			<image class="fab-icon" src="/static/workbench/addSkill.png" mode="aspectFit" />
+			<text class="fab-text">开通新服务</text>
+		</view>
 
 		<!-- 驳回详情弹窗 -->
 		<view class="modal-mask" v-if="showRejectModal" @click="showRejectModal = false">
@@ -98,21 +116,26 @@
 </template>
 
 <script>
-import {
-	SKILL_CATEGORIES,
-	MOCK_MY_SKILLS,
-	STATUS_TABS,
-	formatPrice,
-} from './mock.js'
+import { PLAYMATE_TABS } from './mock.js'
+import { getSkillList } from '@/api/workbench.js'
 
 export default {
 	data() {
 		return {
-			categories: SKILL_CATEGORIES,
-			statusTabs: STATUS_TABS,
-			skillList: [...MOCK_MY_SKILLS],
-			activeCategory: '1',
-			activeStatus: 'opened',
+			public: this.$globalData.publicUrl,
+			cJsId: '',
+			/** 服务标签(1:按摩推拿 2:陪玩) */
+			serviceTag: '',
+			playmateTabs: PLAYMATE_TABS,
+			statusTabs: [
+				{ key: '1', label: '已开通' },
+				{ key: '0', label: '申请中' },
+				{ key: '2', label: '申请驳回' },
+			],
+			skillList: [],
+			activeCategory: PLAYMATE_TABS[0]?.id || '',
+			activeStatus: '1',
+			loading: false,
 			showRejectModal: false,
 			rejectDetailText: '',
 			showApplyModal: false,
@@ -121,44 +144,130 @@ export default {
 		}
 	},
 	computed: {
+		isPlaymate() {
+			return String(this.serviceTag) === '2'
+		},
+		isMassage() {
+			return String(this.serviceTag) === '1'
+		},
 		filteredList() {
-			return this.skillList.filter(item => {
-				return item.categoryId === this.activeCategory && item.status === this.activeStatus
-			})
+			if (!this.isPlaymate) return this.skillList
+			const tab = this.playmateTabs.find(t => t.id === this.activeCategory)
+			if (!tab) return this.skillList
+			return this.skillList.filter(item => this.matchPlaymateCategory(item, tab))
 		},
 	},
+	onLoad(query) {
+		this.public = this.$globalData?.publicUrl || ''
+		this.cJsId = uni.getStorageSync('userId') || ''
+		this.serviceTag = query.serviceTag || uni.getStorageSync('serviceTag') || '1'
+	},
+	onShow() {
+		this.getSkillList()
+	},
 	methods: {
-		formatPrice,
+		onStatusChange(key) {
+			if (this.activeStatus === key) return
+			this.activeStatus = key
+			this.getSkillList()
+		},
+		getSkillList() {
+			if (!this.cJsId) {
+				this.cJsId = uni.getStorageSync('userId') || ''
+			}
+			if (!this.cJsId) return
+			this.loading = true
+			const params = {
+				auditStatus: this.activeStatus,
+				userId: this.cJsId,
+				typeId: this.serviceTag,
+			}
+			getSkillList(params).then(res => {
+				if (res.data.code == 200) {
+					this.skillList = Array.isArray(res.data.result) ? res.data.result : []
+				} else {
+					this.skillList = []
+				}
+			}).catch(() => {
+				this.skillList = []
+			}).finally(() => {
+				this.loading = false
+			})
+		},
+		matchPlaymateCategory(item, tab) {
+			const categoryId = String(item.subTypeId || item.categoryId || item.subCategoryId || '')
+			const categoryName = item.subTypeName || item.categoryName || item.subCategoryName || ''
+			return categoryId === String(tab.id) || categoryName === tab.name
+		},
+		getCover(item) {
+			const image = item.projectMasterImage || item.cover || item.projectImage || ''
+			if (!image) return ''
+			return image.startsWith('http') ? image : this.public + image
+		},
+		getSoldCount(item) {
+			return item.soldCount ?? item.saleCount ?? item.orderCount ?? item.nSaleCount ?? 0
+		},
+		formatMoney(amount) {
+			const num = parseFloat(amount)
+			if (isNaN(num)) return '0.00'
+			return num.toFixed(2)
+		},
+		formatSkillPrice(item) {
+			const unit = item.cUnit || item.unit || '次'
+			const min = item.projectMinPrice ?? item.minPrice ?? item.projectLowPrice
+			const max = item.projectMaxPrice ?? item.maxPrice ?? item.projectHighPrice
+			if (min != null && max != null) {
+				return `¥${this.formatMoney(min)}-${this.formatMoney(max)}/${unit}`
+			}
+			const price = item.projectCurrentPrice ?? item.price ?? min ?? max ?? 0
+			return `¥${this.formatMoney(price)}/${unit}`
+		},
+		formatApplyDate(timeStr) {
+			if (!timeStr) return ''
+			const str = String(timeStr)
+			const d = new Date(str.replace(/-/g, '/'))
+			if (Number.isNaN(d.getTime())) return str
+			return `${d.getFullYear()}年${d.getMonth() + 1}月${d.getDate()}日申请开通服务`
+		},
+		getRejectReason(item) {
+			return item.rejectReason || item.auditRemark || item.remark || item.auditReason || ''
+		},
 		statusBarText(item) {
-			if (item.status === 'opened' && item.applyDate) return item.applyDate
-			if (item.status === 'pending') return '申请开通服务审核中'
-			if (item.status === 'rejected') {
-				const reason = item.rejectReason || ''
+			if (this.activeStatus === '1') {
+				const time = item.createTime || item.applyTime || item.openTime || item.auditTime
+				return time ? this.formatApplyDate(time) : ''
+			}
+			if (this.activeStatus === '0') return '申请开通服务审核中'
+			if (this.activeStatus === '2') {
+				const reason = this.getRejectReason(item)
 				return reason.length > 28 ? reason.slice(0, 28) + '...' : reason
 			}
 			return ''
 		},
 		onStatusBarClick(item) {
-			if (item.status === 'rejected') {
-				this.rejectDetailText = item.rejectReason
+			if (this.activeStatus === '2') {
+				this.rejectDetailText = this.getRejectReason(item)
 				this.showRejectModal = true
 			}
 		},
 		goAdd() {
-			// type=playmate  是陪玩
-			uni.navigateTo({ url: '/workbench/skill/add?type=playmate' })
+			const type = this.isPlaymate ? 'playmate' : 'massage'
+			uni.navigateTo({ url: `/workbench/skill/add?type=${type}` })
 		},
 		goEdit(item) {
+			const categoryName = this.isPlaymate
+				? item.subTypeName || item.categoryName || item.subCategoryName || ''
+				: ''
 			const str = uni.$u.queryParams({
-				id: item.id,
-				title: item.title,
-				cover: item.cover || '',
-				categoryName: this.categories.find(c => c.id === item.categoryId)?.name || '',
-				billingType: item.billingType || '',
-				platformPrice: item.platformPrice,
-				priceRangeMin: item.priceRangeMin,
-				priceRangeMax: item.priceRangeMax,
-				myPrice: item.price,
+				id: item.id || item.projectId || '',
+				title: item.projectName || '',
+				cover: this.getCover(item),
+				categoryName,
+				billingType: item.billingType || item.chargeType || (item.nMinute ? '按分钟计费' : ''),
+				platformPrice: item.projectPlatformPrice ?? item.platformPrice ?? item.projectCurrentPrice,
+				priceRangeMin: item.projectMinPrice ?? item.minPrice ?? item.projectLowPrice,
+				priceRangeMax: item.projectMaxPrice ?? item.maxPrice ?? item.projectHighPrice,
+				myPrice: item.projectCurrentPrice ?? item.price,
 			})
 			uni.navigateTo({ url: `/workbench/skill/edit${str}` })
 		},
@@ -171,7 +280,8 @@ export default {
 				content: '确定删除该服务?',
 				success: res => {
 					if (res.confirm) {
-						this.skillList = this.skillList.filter(s => s.id !== item.id)
+						const itemId = item.id || item.projectId
+						this.skillList = this.skillList.filter(s => (s.id || s.projectId) !== itemId)
 						uni.showToast({ title: '已删除', icon: 'none' })
 					}
 				},
@@ -192,15 +302,9 @@ export default {
 				uni.showToast({ title: '请输入开通原因', icon: 'none' })
 				return
 			}
-			this.applyItems.forEach(item => {
-				const idx = this.skillList.findIndex(s => s.id === item.id)
-				if (idx > -1) {
-					this.skillList[idx].status = 'pending'
-					this.skillList[idx].rejectReason = ''
-				}
-			})
 			this.closeApplyModal()
-			this.activeStatus = 'pending'
+			this.activeStatus = '0'
+			this.getSkillList()
 			uni.showToast({ title: '已提交,待审核', icon: 'none' })
 		},
 	},
@@ -211,19 +315,7 @@ export default {
 .skill-page {
 	min-height: 100vh;
 	background: #f5f5f5;
-	padding-bottom: 40rpx;
-}
-
-.top-bar {
-	display: flex;
-	justify-content: flex-end;
-	padding: 16rpx 32rpx 0;
-	background: #fff;
-}
-
-.top-link {
-	font-size: 28rpx;
-	color: #333;
+	padding-bottom: 160rpx;
 }
 
 .category-tabs {
@@ -234,40 +326,50 @@ export default {
 }
 
 .category-tab {
-	display: inline-block;
-	padding: 16rpx 24rpx;
-	font-size: 28rpx;
-	color: #666;
-	margin-right: 8rpx;
-	border-bottom: 4rpx solid transparent;
+	display: inline-flex;
+	flex-direction: column;
+	align-items: center;
+	padding: 16rpx 28rpx 12rpx;
+	position: relative;
 
-	&.active {
+	&__text {
+		font-size: 28rpx;
+		color: #999;
+		line-height: 1.4;
+	}
+
+	&__indicator {
+		width: 48rpx;
+		height: 12rpx;
+		margin-top: -8rpx;
+	}
+
+	&.active &__text {
 		color: #333;
 		font-weight: 600;
-		border-bottom-color: #333;
 	}
 }
 
 .status-tabs {
 	display: flex;
-	gap: 16rpx;
-	padding: 24rpx 32rpx;
+	align-items: center;
+	justify-content: space-around;
+	padding: 28rpx 32rpx;
 	background: #fff;
+	border-bottom: 1rpx solid #eee;
 	margin-bottom: 16rpx;
 }
 
 .status-tab {
-	padding: 12rpx 28rpx;
-	font-size: 26rpx;
-	color: #666;
-	border: 1rpx solid #ddd;
-	border-radius: 32rpx;
-	background: #fff;
+	flex: 1;
+	text-align: center;
+	font-size: 28rpx;
+	color: #999;
+	line-height: 1.4;
 
 	&.active {
 		color: #333;
-		background: #f0f0f0;
-		border-color: #ccc;
+		font-weight: 600;
 	}
 }
 
@@ -279,8 +381,12 @@ export default {
 	background: #fff;
 	border: 1rpx solid #eee;
 	border-radius: 12rpx;
-	padding: 24rpx;
 	margin-bottom: 20rpx;
+	overflow: hidden;
+}
+
+.card-body {
+	padding: 24rpx;
 }
 
 .card-main {
@@ -323,7 +429,10 @@ export default {
 
 .sold {
 	font-size: 22rpx;
-	color: #999;
+	color: #e8a849;
+	background: #fff7ed;
+	padding: 4rpx 12rpx;
+	border-radius: 4rpx;
 	flex-shrink: 0;
 	margin-left: 12rpx;
 }
@@ -336,13 +445,28 @@ export default {
 }
 
 .status-bar {
-	display: flex;
+	display: inline-flex;
 	align-items: center;
-	justify-content: space-between;
-	margin-top: 20rpx;
-	padding: 16rpx 20rpx;
+	max-width: 100%;
+	margin-top: 12rpx;
+	padding: 8rpx 16rpx;
 	background: #f5f5f5;
 	border-radius: 8rpx;
+
+	&--opened {
+		background: #e8f9f7;
+
+		.status-text {
+			color: #20CAC2;
+		}
+	}
+}
+
+.status-icon {
+	width: 28rpx;
+	height: 28rpx;
+	margin-right: 8rpx;
+	flex-shrink: 0;
 }
 
 .status-text {
@@ -358,11 +482,33 @@ export default {
 	margin-left: 8rpx;
 }
 
-.card-actions {
+.card-footer {
 	display: flex;
-	justify-content: flex-end;
-	gap: 16rpx;
-	margin-top: 20rpx;
+	align-items: stretch;
+	border-top: 1rpx solid #eee;
+}
+
+.footer-btn {
+	flex: 1;
+	text-align: center;
+	padding: 24rpx 0;
+	font-size: 28rpx;
+	line-height: 1.4;
+
+	&--ghost {
+		color: #999;
+	}
+
+	&--primary {
+		color: #333;
+		font-weight: 500;
+	}
+}
+
+.footer-divider {
+	width: 1rpx;
+	background: #eee;
+	flex-shrink: 0;
 }
 
 .btn {
@@ -395,6 +541,32 @@ export default {
 	color: #999;
 }
 
+.fab-btn {
+	position: fixed;
+	right: 32rpx;
+	bottom: calc(48rpx + env(safe-area-inset-bottom));
+	display: flex;
+	align-items: center;
+	gap: 12rpx;
+	padding: 12rpx 32rpx 12rpx 12rpx;
+	background: #20CAC2;
+	border-radius: 48rpx;
+	box-shadow: 0 8rpx 24rpx rgba(32, 202, 194, 0.35);
+	z-index: 100;
+
+	.fab-icon {
+		width: 48rpx;
+		height: 48rpx;
+		flex-shrink: 0;
+	}
+
+	.fab-text {
+		font-size: 28rpx;
+		color: #333;
+		font-weight: 500;
+	}
+}
+
 .modal-mask {
 	position: fixed;
 	left: 0;

+ 7 - 3
src/workbench/skill/mock.js

@@ -25,25 +25,29 @@ export const SKILL_CATEGORIES = [
 	{ id: '5', name: '健身运动' },
 
 	{ id: '6', name: '读书学习' },
+	{ id: '7', name: '读书学习' },
 
 ]
 
 
 
-/** 陪玩子分类 Tab(add 页使用) */
+/** 陪玩子分类 Tab(技能管理 / 开通新服务) */
 
 export const PLAYMATE_TABS = [
 
-	{ id: 'p1', name: '羽毛球' },
+	{ id: 'p4', name: '台球' },
 
 	{ id: 'p2', name: '爬山' },
 
 	{ id: 'p3', name: '电影' },
 
-	{ id: 'p4', name: '台球' },
+	{ id: 'p1', name: '羽毛球' },
 
 	{ id: 'p5', name: '健身运动' },
 
+	{ id: 'p6', name: '读书学习' },
+	
+
 ]