feat(activity,expert): 新增发起组队活动页面与大神接单工作台,完成4位数字门票码现场核销业务闭环
这个提交包含在:
@@ -71,6 +71,24 @@
|
||||
"navigationBarTextStyle": "white",
|
||||
"backgroundColor": "#0A0F1D"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/activity/create",
|
||||
"style": {
|
||||
"navigationBarTitleText": "发起组队活动",
|
||||
"navigationBarBackgroundColor": "#0A0F1D",
|
||||
"navigationBarTextStyle": "white",
|
||||
"backgroundColor": "#0A0F1D"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/expert/workspace",
|
||||
"style": {
|
||||
"navigationBarTitleText": "大神接单工作台",
|
||||
"navigationBarBackgroundColor": "#0A0F1D",
|
||||
"navigationBarTextStyle": "white",
|
||||
"backgroundColor": "#0A0F1D"
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
|
||||
424
pwuniapp/pages/activity/create.vue
普通文件
424
pwuniapp/pages/activity/create.vue
普通文件
@@ -0,0 +1,424 @@
|
||||
<template>
|
||||
<view class="create-activity-container">
|
||||
<!-- 模式选择 Tab (AA制 / 项目制) -->
|
||||
<view class="mode-switch-wrap">
|
||||
<view
|
||||
class="mode-item btn-active"
|
||||
:class="{ active: form.payType === 'AA' }"
|
||||
@click="form.payType = 'AA'"
|
||||
>
|
||||
<image class="mode-svg" :src="ICONS.bolt" mode="aspectFit" />
|
||||
<view class="mode-text-box">
|
||||
<text class="mode-title">AA制车队</text>
|
||||
<text class="mode-desc">报名人均平摊费用</text>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
class="mode-item btn-active"
|
||||
:class="{ active: form.payType === 'PROJECT' }"
|
||||
@click="form.payType = 'PROJECT'"
|
||||
>
|
||||
<image class="mode-svg" :src="ICONS.trophy" mode="aspectFit" />
|
||||
<view class="mode-text-box">
|
||||
<text class="mode-title">项目制悬赏</text>
|
||||
<text class="mode-desc">房主全额悬赏奖金池</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 游戏品类选择 -->
|
||||
<view class="form-card">
|
||||
<view class="card-label">选择开黑游戏</view>
|
||||
<view class="game-pills">
|
||||
<view
|
||||
v-for="g in games"
|
||||
:key="g"
|
||||
class="game-pill btn-active"
|
||||
:class="{ selected: form.game === g }"
|
||||
@click="form.game = g"
|
||||
>
|
||||
{{ g }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 基础信息录入 -->
|
||||
<view class="form-card">
|
||||
<view class="input-row">
|
||||
<text class="row-label">活动标题</text>
|
||||
<input
|
||||
class="row-input"
|
||||
v-model="form.title"
|
||||
placeholder="如:今晚百星王者五排极速冲分"
|
||||
placeholder-class="ph"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="input-row">
|
||||
<text class="row-label">开黑时段</text>
|
||||
<input
|
||||
class="row-input"
|
||||
v-model="form.startTime"
|
||||
placeholder="如:今晚 20:30"
|
||||
placeholder-class="ph"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="input-row">
|
||||
<text class="row-label">语音频道</text>
|
||||
<input
|
||||
class="row-input"
|
||||
v-model="form.location"
|
||||
placeholder="如:开黑语音 1 号房间 / YY 668899"
|
||||
placeholder-class="ph"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 席位与费用配置 -->
|
||||
<view class="form-card">
|
||||
<view class="stepper-row">
|
||||
<view class="stepper-info">
|
||||
<text class="row-label">招募席位 (人)</text>
|
||||
<text class="sub-label">包含房主在内的车队总人数</text>
|
||||
</view>
|
||||
<view class="stepper-box">
|
||||
<button class="step-btn btn-active" :disabled="form.maxParticipants <= 2" @click="changeParticipants(-1)">-</button>
|
||||
<text class="step-val">{{ form.maxParticipants }} 人</text>
|
||||
<button class="step-btn btn-active" :disabled="form.maxParticipants >= 10" @click="changeParticipants(1)">+</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="input-row" v-if="form.payType === 'AA'">
|
||||
<text class="row-label">人均分摊 (元/人)</text>
|
||||
<input
|
||||
class="row-input"
|
||||
type="digit"
|
||||
v-model="form.aaFee"
|
||||
placeholder="如:30"
|
||||
placeholder-class="ph"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="input-row" v-else>
|
||||
<text class="row-label">悬赏总奖金池 (元)</text>
|
||||
<input
|
||||
class="row-input"
|
||||
type="digit"
|
||||
v-model="form.totalFee"
|
||||
placeholder="如:300"
|
||||
placeholder-class="ph"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="calc-preview">
|
||||
<text class="preview-label">预算测算:</text>
|
||||
<text class="preview-val highlight">
|
||||
{{ form.payType === 'AA' ? `总费用预估约 ¥${calcTotalFee} (人均 ¥${form.aaFee || 0})` : `参与者免费报名,全员争夺 ¥${form.totalFee || 0} 奖金池` }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部发起操作栏 (适配安全区) -->
|
||||
<view class="bottom-bar">
|
||||
<button class="btn-submit btn-active" @click="handleSubmit">
|
||||
立即发起组队活动
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { ICONS } from '@/common/icons.js';
|
||||
import { ACTIVITIES_LIST } from '@/common/mock.js';
|
||||
|
||||
const games = ['王者荣耀', '和平精英', '英雄联盟', '无畏契约'];
|
||||
|
||||
const form = ref({
|
||||
payType: 'AA',
|
||||
game: '王者荣耀',
|
||||
title: '',
|
||||
startTime: '今晚 20:30',
|
||||
location: '开黑语音 1 号频道',
|
||||
maxParticipants: 5,
|
||||
aaFee: 25,
|
||||
totalFee: 125,
|
||||
});
|
||||
|
||||
const calcTotalFee = computed(() => {
|
||||
if (form.value.payType === 'AA') {
|
||||
return (Number(form.value.aaFee) || 0) * form.value.maxParticipants;
|
||||
}
|
||||
return Number(form.value.totalFee) || 0;
|
||||
});
|
||||
|
||||
const changeParticipants = (delta) => {
|
||||
form.value.maxParticipants = Math.max(2, Math.min(10, form.value.maxParticipants + delta));
|
||||
};
|
||||
|
||||
const handleSubmit = () => {
|
||||
if (!form.value.title.trim()) {
|
||||
form.value.title = `【${form.value.game}】今晚极速开黑车队`;
|
||||
}
|
||||
|
||||
const newActivity = {
|
||||
id: `act_${Date.now()}`,
|
||||
game: form.value.game,
|
||||
title: form.value.title,
|
||||
payType: form.value.payType,
|
||||
totalFee: calcTotalFee.value,
|
||||
aaFee: Number(form.value.aaFee) || 0,
|
||||
currentParticipants: 1,
|
||||
maxParticipants: form.value.maxParticipants,
|
||||
startTime: form.value.startTime,
|
||||
location: form.value.location,
|
||||
creatorNickname: '超能电竞玩家',
|
||||
creatorAvatar: 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=150&h=150&fit=crop',
|
||||
participants: [
|
||||
{
|
||||
id: 'u_888',
|
||||
nickname: '超能电竞玩家',
|
||||
avatar: 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=150&h=150&fit=crop',
|
||||
checkedIn: true
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
ACTIVITIES_LIST.unshift(newActivity);
|
||||
|
||||
uni.showToast({
|
||||
title: '活动发起成功!车队已就绪',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1200);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.create-activity-container {
|
||||
min-height: 100vh;
|
||||
background-color: #0A0F1D;
|
||||
padding: 24rpx 32rpx calc(160rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.mode-switch-wrap {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
.mode-item {
|
||||
flex: 1;
|
||||
background: #151D30;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 20rpx;
|
||||
padding: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14rpx;
|
||||
|
||||
.mode-svg {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
|
||||
.mode-text-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.mode-title {
|
||||
font-size: 26rpx;
|
||||
font-weight: 700;
|
||||
color: #F8FAFC;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
.mode-desc {
|
||||
font-size: 18rpx;
|
||||
color: #64748B;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: linear-gradient(135deg, rgba(99, 102, 241, 0.18) 0%, rgba(139, 92, 246, 0.1) 100%);
|
||||
border-color: #6366F1;
|
||||
box-shadow: 0 0 16rpx rgba(99, 102, 241, 0.3);
|
||||
|
||||
.mode-title {
|
||||
color: #818CF8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-card {
|
||||
background: #151D30;
|
||||
border-radius: 24rpx;
|
||||
padding: 28rpx;
|
||||
margin-bottom: 24rpx;
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
|
||||
.card-label {
|
||||
font-size: 26rpx;
|
||||
font-weight: 700;
|
||||
color: #F8FAFC;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.game-pills {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 14rpx;
|
||||
|
||||
.game-pill {
|
||||
font-size: 24rpx;
|
||||
color: #94A3B8;
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
padding: 10rpx 24rpx;
|
||||
border-radius: 28rpx;
|
||||
|
||||
&.selected {
|
||||
background: rgba(99, 102, 241, 0.2);
|
||||
color: #818CF8;
|
||||
border-color: #6366F1;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.input-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.row-label {
|
||||
width: 220rpx;
|
||||
font-size: 26rpx;
|
||||
color: #CBD5E1;
|
||||
}
|
||||
|
||||
.row-input {
|
||||
flex: 1;
|
||||
font-size: 26rpx;
|
||||
color: #F8FAFC;
|
||||
}
|
||||
|
||||
.ph {
|
||||
color: #475569;
|
||||
}
|
||||
}
|
||||
|
||||
.stepper-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 20rpx;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
|
||||
|
||||
.stepper-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.row-label {
|
||||
font-size: 26rpx;
|
||||
color: #CBD5E1;
|
||||
font-weight: 600;
|
||||
}
|
||||
.sub-label {
|
||||
font-size: 20rpx;
|
||||
color: #64748B;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.stepper-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border-radius: 16rpx;
|
||||
padding: 6rpx;
|
||||
|
||||
.step-btn {
|
||||
width: 68rpx;
|
||||
height: 68rpx;
|
||||
line-height: 64rpx;
|
||||
padding: 0;
|
||||
background: #1E2942;
|
||||
color: #FFF;
|
||||
font-size: 32rpx;
|
||||
border-radius: 12rpx;
|
||||
border: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.step-val {
|
||||
font-size: 28rpx;
|
||||
color: #F8FAFC;
|
||||
font-weight: 600;
|
||||
margin: 0 20rpx;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.calc-preview {
|
||||
margin-top: 20rpx;
|
||||
padding: 16rpx 20rpx;
|
||||
background: rgba(99, 102, 241, 0.08);
|
||||
border-radius: 14rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.preview-label {
|
||||
font-size: 22rpx;
|
||||
color: #94A3B8;
|
||||
}
|
||||
.preview-val {
|
||||
font-size: 22rpx;
|
||||
color: #10B981;
|
||||
font-weight: 600;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: calc(120rpx + env(safe-area-inset-bottom));
|
||||
padding: 0 32rpx env(safe-area-inset-bottom);
|
||||
box-sizing: border-box;
|
||||
background-color: rgba(21, 29, 48, 0.95);
|
||||
backdrop-filter: blur(12px);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
z-index: 100;
|
||||
max-width: 450px;
|
||||
margin: 0 auto;
|
||||
|
||||
.btn-submit {
|
||||
flex: 1;
|
||||
background: linear-gradient(135deg, #6366F1 0%, #8B5CF6 100%);
|
||||
color: #FFF;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
border-radius: 44rpx;
|
||||
height: 84rpx;
|
||||
line-height: 84rpx;
|
||||
box-shadow: 0 4rpx 20rpx rgba(99, 102, 241, 0.4);
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -137,10 +137,8 @@ const goToDetail = (id) => {
|
||||
};
|
||||
|
||||
const createActivity = () => {
|
||||
uni.showToast({
|
||||
title: '发起组队模块已就绪(支持AA制与项目制)',
|
||||
icon: 'none',
|
||||
duration: 2500
|
||||
uni.navigateTo({
|
||||
url: '/pages/activity/create'
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
717
pwuniapp/pages/expert/workspace.vue
普通文件
717
pwuniapp/pages/expert/workspace.vue
普通文件
@@ -0,0 +1,717 @@
|
||||
<template>
|
||||
<view class="workspace-container">
|
||||
<!-- 顶部状态栏与在线接单开关 -->
|
||||
<view class="expert-status-card">
|
||||
<view class="status-left">
|
||||
<image class="expert-avatar" :src="expert.avatar" mode="aspectFill" />
|
||||
<view class="expert-info">
|
||||
<view class="name-row">
|
||||
<text class="expert-name">{{ expert.nickname }}</text>
|
||||
<text class="badge-gold">金牌导师</text>
|
||||
</view>
|
||||
<view class="status-indicator">
|
||||
<view class="dot-status" :class="{ online: isReceivingOrders }"></view>
|
||||
<text class="status-text">{{ isReceivingOrders ? '接单中 (派单池活跃)' : '已打烊休息' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="switch-wrap btn-active" @click="toggleReceivingStatus">
|
||||
<text class="switch-label">{{ isReceivingOrders ? '停止接单' : '开启接单' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 今日经营看板 -->
|
||||
<view class="stats-board">
|
||||
<view class="stat-col">
|
||||
<text class="stat-label">今日预计收益 (元)</text>
|
||||
<text class="stat-val green-val">¥{{ todayIncome }}</text>
|
||||
</view>
|
||||
<view class="stat-divider"></view>
|
||||
<view class="stat-col">
|
||||
<text class="stat-label">今日履约单数</text>
|
||||
<text class="stat-val">3 单</text>
|
||||
</view>
|
||||
<view class="stat-divider"></view>
|
||||
<view class="stat-col">
|
||||
<text class="stat-label">待签到核销</text>
|
||||
<text class="stat-val gold-val">1 人</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 核心亮点功能:4 位数字门票现场核销中心 -->
|
||||
<view class="verify-section-card">
|
||||
<view class="sec-head">
|
||||
<view class="title-wrap">
|
||||
<image class="sec-svg" :src="ICONS.ticket" mode="aspectFit" />
|
||||
<text class="sec-title">4位活动门票现场核销工具</text>
|
||||
</view>
|
||||
<text class="sec-sub">车队房主专属</text>
|
||||
</view>
|
||||
|
||||
<view class="verify-box">
|
||||
<text class="input-tips">输入参与人出示的 4 位纯数字核销码完成入队签到:</text>
|
||||
<view class="code-input-row">
|
||||
<input
|
||||
class="code-input"
|
||||
type="number"
|
||||
maxlength="4"
|
||||
v-model="inputCode"
|
||||
placeholder="输入4位数字 (如: 8392)"
|
||||
placeholder-class="ph"
|
||||
/>
|
||||
<button class="btn-verify btn-active" @click="handleVerifyCode">
|
||||
验证核销
|
||||
</button>
|
||||
</view>
|
||||
<view class="quick-demo" @click="fillDemoCode">
|
||||
<text>点击快速填入演示门票码 [8392]</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 待抢订单池 (即时匹配派单) -->
|
||||
<view class="section-card">
|
||||
<view class="sec-head">
|
||||
<view class="title-wrap">
|
||||
<image class="sec-svg" :src="ICONS.bolt" mode="aspectFit" />
|
||||
<text class="sec-title">即时抢单派单池 ({{ poolOrders.length }})</text>
|
||||
</view>
|
||||
<view class="pulse-live">
|
||||
<view class="pulse-circle"></view>
|
||||
<text class="live-text">实时派单中</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="pool-list" v-if="poolOrders.length > 0">
|
||||
<view v-for="order in poolOrders" :key="order.id" class="pool-card">
|
||||
<view class="pool-top">
|
||||
<text class="game-tag">{{ order.game }}</text>
|
||||
<text class="pool-price">¥{{ order.price }}</text>
|
||||
</view>
|
||||
<text class="pool-desc">{{ order.desc }}</text>
|
||||
<view class="pool-foot">
|
||||
<text class="pool-time">倒计时: {{ order.countdown }}s</text>
|
||||
<button class="btn-grab btn-active" @click="grabOrder(order)">立即抢单</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="empty-pool">
|
||||
<text>暂无待抢订单,保持在线有更高派单权重</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 进行中的服务履约订单 -->
|
||||
<view class="section-card">
|
||||
<view class="sec-head">
|
||||
<view class="title-wrap">
|
||||
<image class="sec-svg" :src="ICONS.orderList" mode="aspectFit" />
|
||||
<text class="sec-title">进行中履约服务 ({{ activeOrders.length }})</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="active-list">
|
||||
<view v-for="order in activeOrders" :key="order.id" class="active-order-card">
|
||||
<view class="order-buyer">
|
||||
<image class="buyer-avatar" :src="order.buyerAvatar" mode="aspectFill" />
|
||||
<view class="buyer-info">
|
||||
<text class="buyer-name">{{ order.buyerName }}</text>
|
||||
<text class="service-tag">{{ order.serviceTitle }} · {{ order.hours }}小时</text>
|
||||
</view>
|
||||
<text class="order-amount">¥{{ order.totalAmount }}</text>
|
||||
</view>
|
||||
|
||||
<view class="order-progress-row">
|
||||
<text class="prog-text">状态:{{ order.statusText }}</text>
|
||||
<view class="order-btns">
|
||||
<button class="btn-chat btn-active" @click="chatWithBuyer">联系老板</button>
|
||||
<button class="btn-complete btn-active" @click="completeOrder(order.id)">
|
||||
申请验收结算
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部切回玩家端 -->
|
||||
<view class="bottom-switch-wrap">
|
||||
<button class="btn-back-player btn-active" @click="switchBackToPlayer">
|
||||
退出工作台 · 切回玩家大厅
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { ICONS } from '@/common/icons.js';
|
||||
import { EXPERTS_LIST } from '@/common/mock.js';
|
||||
|
||||
const expert = ref(EXPERTS_LIST[0]);
|
||||
const isReceivingOrders = ref(true);
|
||||
const todayIncome = ref(175);
|
||||
const inputCode = ref('');
|
||||
|
||||
const poolOrders = ref([
|
||||
{
|
||||
id: 'pool_101',
|
||||
game: '王者荣耀',
|
||||
price: 35,
|
||||
desc: 'QQ区/星耀1晋级赛冲王者/需连麦/射手或辅助',
|
||||
countdown: 48
|
||||
},
|
||||
{
|
||||
id: 'pool_102',
|
||||
game: '和平精英',
|
||||
price: 45,
|
||||
desc: '微信区/四排海岛/刚枪上分/kd保4以上',
|
||||
countdown: 32
|
||||
}
|
||||
]);
|
||||
|
||||
const activeOrders = ref([
|
||||
{
|
||||
id: 'ord_active_1',
|
||||
buyerName: '超能电竞玩家',
|
||||
buyerAvatar: 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=150&h=150&fit=crop',
|
||||
serviceTitle: '排位包胜率',
|
||||
hours: 2,
|
||||
totalAmount: 70,
|
||||
statusText: '正在开黑连麦对局中'
|
||||
}
|
||||
]);
|
||||
|
||||
const toggleReceivingStatus = () => {
|
||||
isReceivingOrders.value = !isReceivingOrders.value;
|
||||
uni.showToast({
|
||||
title: isReceivingOrders.value ? '已开启在线接单通道!' : '已打烊停止接单',
|
||||
icon: 'none'
|
||||
});
|
||||
};
|
||||
|
||||
const fillDemoCode = () => {
|
||||
inputCode.value = '8392';
|
||||
};
|
||||
|
||||
const handleVerifyCode = () => {
|
||||
if (inputCode.value.trim() === '8392') {
|
||||
uni.showModal({
|
||||
title: '门票核销成功!',
|
||||
content: '【AA制五排王者百星车队】门票 [8392] 已核销确认!参与者已成功入队,分摊款 ¥25.00 已释放打入您的收益账户。',
|
||||
showCancel: false,
|
||||
confirmText: '完成',
|
||||
confirmColor: '#10B981',
|
||||
success: () => {
|
||||
todayIncome.value += 25;
|
||||
inputCode.value = '';
|
||||
}
|
||||
});
|
||||
} else if (inputCode.value.length === 4) {
|
||||
uni.showToast({
|
||||
title: `核销码 [${inputCode.value}] 无效或已被核销`,
|
||||
icon: 'none'
|
||||
});
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '请输入合法的 4 位纯数字门票码',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const grabOrder = (order) => {
|
||||
uni.showToast({
|
||||
title: `抢单成功!已接单 ¥${order.price}`,
|
||||
icon: 'success'
|
||||
});
|
||||
poolOrders.value = poolOrders.value.filter(o => o.id !== order.id);
|
||||
activeOrders.value.push({
|
||||
id: `ord_grabbed_${Date.now()}`,
|
||||
buyerName: '特惠预约老板',
|
||||
buyerAvatar: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=150&h=150&fit=crop',
|
||||
serviceTitle: order.game,
|
||||
hours: 1,
|
||||
totalAmount: order.price,
|
||||
statusText: '待双方进房连麦'
|
||||
});
|
||||
};
|
||||
|
||||
const chatWithBuyer = () => {
|
||||
uni.showToast({ title: '已连接买家专属密聊通道', icon: 'none' });
|
||||
};
|
||||
|
||||
const completeOrder = (id) => {
|
||||
uni.showModal({
|
||||
title: '确认提交服务验收',
|
||||
content: '服务已完成?提交后买家确认无误或 24 小时内未异议将自动解冻订单资金打入钱包。',
|
||||
confirmColor: '#10B981',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
activeOrders.value = activeOrders.value.filter(o => o.id !== id);
|
||||
uni.showToast({ title: '已申请验收结算!', icon: 'success' });
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const switchBackToPlayer = () => {
|
||||
uni.switchTab({
|
||||
url: '/pages/user/index'
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.workspace-container {
|
||||
min-height: 100vh;
|
||||
background-color: #0A0F1D;
|
||||
padding: 24rpx 32rpx calc(60rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.expert-status-card {
|
||||
background: linear-gradient(135deg, #1E1B4B 0%, #151D30 100%);
|
||||
border: 1px solid rgba(99, 102, 241, 0.3);
|
||||
border-radius: 28rpx;
|
||||
padding: 28rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24rpx;
|
||||
box-shadow: 0 8rpx 28rpx rgba(99, 102, 241, 0.25);
|
||||
|
||||
.status-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.expert-avatar {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 50rpx;
|
||||
border: 4rpx solid #6366F1;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.expert-info {
|
||||
.name-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
margin-bottom: 8rpx;
|
||||
|
||||
.expert-name {
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
.badge-gold {
|
||||
font-size: 18rpx;
|
||||
background: linear-gradient(135deg, #F59E0B, #D97706);
|
||||
color: #FFF;
|
||||
padding: 2rpx 10rpx;
|
||||
border-radius: 6rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
|
||||
.dot-status {
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
border-radius: 50%;
|
||||
background: #64748B;
|
||||
|
||||
&.online {
|
||||
background: #10B981;
|
||||
box-shadow: 0 0 10rpx #10B981;
|
||||
}
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 22rpx;
|
||||
color: #94A3B8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.switch-wrap {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
border-radius: 32rpx;
|
||||
padding: 10rpx 24rpx;
|
||||
|
||||
.switch-label {
|
||||
font-size: 22rpx;
|
||||
color: #E2E8F0;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.stats-board {
|
||||
background-color: #151D30;
|
||||
border-radius: 24rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 24rpx;
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
|
||||
.stat-col {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.stat-label {
|
||||
font-size: 20rpx;
|
||||
color: #94A3B8;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.stat-val {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #F8FAFC;
|
||||
font-variant-numeric: tabular-nums;
|
||||
|
||||
&.green-val {
|
||||
color: #10B981;
|
||||
}
|
||||
&.gold-val {
|
||||
color: #F59E0B;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.stat-divider {
|
||||
width: 1px;
|
||||
height: 60rpx;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
}
|
||||
|
||||
.verify-section-card {
|
||||
background: linear-gradient(135deg, rgba(16, 185, 129, 0.12) 0%, rgba(21, 29, 48, 1) 100%);
|
||||
border: 1px solid rgba(16, 185, 129, 0.35);
|
||||
border-radius: 24rpx;
|
||||
padding: 28rpx;
|
||||
margin-bottom: 24rpx;
|
||||
box-shadow: 0 8rpx 24rpx rgba(16, 185, 129, 0.2);
|
||||
|
||||
.sec-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.title-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
|
||||
.sec-svg {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
}
|
||||
|
||||
.sec-title {
|
||||
font-size: 26rpx;
|
||||
font-weight: 700;
|
||||
color: #10B981;
|
||||
}
|
||||
}
|
||||
|
||||
.sec-sub {
|
||||
font-size: 20rpx;
|
||||
color: #64748B;
|
||||
}
|
||||
}
|
||||
|
||||
.verify-box {
|
||||
.input-tips {
|
||||
font-size: 22rpx;
|
||||
color: #94A3B8;
|
||||
display: block;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.code-input-row {
|
||||
display: flex;
|
||||
gap: 16rpx;
|
||||
|
||||
.code-input {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
background: #0A0F1D;
|
||||
border: 2rpx solid #10B981;
|
||||
border-radius: 16rpx;
|
||||
color: #10B981;
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
letter-spacing: 6rpx;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.btn-verify {
|
||||
background: linear-gradient(135deg, #10B981 0%, #059669 100%);
|
||||
color: #FFF;
|
||||
font-size: 26rpx;
|
||||
font-weight: 700;
|
||||
border-radius: 16rpx;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
padding: 0 32rpx;
|
||||
margin: 0;
|
||||
box-shadow: 0 4rpx 16rpx rgba(16, 185, 129, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.quick-demo {
|
||||
margin-top: 14rpx;
|
||||
text-align: right;
|
||||
font-size: 20rpx;
|
||||
color: #818CF8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.section-card {
|
||||
background-color: #151D30;
|
||||
border-radius: 24rpx;
|
||||
padding: 28rpx;
|
||||
margin-bottom: 24rpx;
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
|
||||
.sec-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.title-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
|
||||
.sec-svg {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
}
|
||||
|
||||
.sec-title {
|
||||
font-size: 26rpx;
|
||||
font-weight: 700;
|
||||
color: #F8FAFC;
|
||||
}
|
||||
}
|
||||
|
||||
.pulse-live {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
|
||||
.pulse-circle {
|
||||
width: 10rpx;
|
||||
height: 10rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #10B981;
|
||||
box-shadow: 0 0 8rpx #10B981;
|
||||
}
|
||||
.live-text {
|
||||
font-size: 20rpx;
|
||||
color: #10B981;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pool-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 18rpx;
|
||||
|
||||
.pool-card {
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
border-radius: 18rpx;
|
||||
padding: 20rpx;
|
||||
|
||||
.pool-top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10rpx;
|
||||
|
||||
.game-tag {
|
||||
font-size: 20rpx;
|
||||
background: rgba(99, 102, 241, 0.2);
|
||||
color: #818CF8;
|
||||
padding: 2rpx 10rpx;
|
||||
border-radius: 6rpx;
|
||||
}
|
||||
|
||||
.pool-price {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #10B981;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
}
|
||||
|
||||
.pool-desc {
|
||||
font-size: 22rpx;
|
||||
color: #CBD5E1;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 14rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.pool-foot {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.pool-time {
|
||||
font-size: 20rpx;
|
||||
color: #EF4444;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.btn-grab {
|
||||
background: linear-gradient(135deg, #6366F1 0%, #8B5CF6 100%);
|
||||
color: #FFF;
|
||||
font-size: 22rpx;
|
||||
font-weight: 700;
|
||||
border-radius: 28rpx;
|
||||
height: 56rpx;
|
||||
line-height: 56rpx;
|
||||
padding: 0 28rpx;
|
||||
margin: 0;
|
||||
box-shadow: 0 4rpx 16rpx rgba(99, 102, 241, 0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty-pool {
|
||||
text-align: center;
|
||||
color: #64748B;
|
||||
font-size: 22rpx;
|
||||
padding: 24rpx 0;
|
||||
}
|
||||
|
||||
.active-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 18rpx;
|
||||
|
||||
.active-order-card {
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
border-radius: 18rpx;
|
||||
padding: 20rpx;
|
||||
|
||||
.order-buyer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.buyer-avatar {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 36rpx;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.buyer-info {
|
||||
flex: 1;
|
||||
|
||||
.buyer-name {
|
||||
font-size: 24rpx;
|
||||
font-weight: 700;
|
||||
color: #F8FAFC;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.service-tag {
|
||||
font-size: 20rpx;
|
||||
color: #94A3B8;
|
||||
}
|
||||
}
|
||||
|
||||
.order-amount {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #10B981;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
}
|
||||
|
||||
.order-progress-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.05);
|
||||
padding-top: 14rpx;
|
||||
|
||||
.prog-text {
|
||||
font-size: 22rpx;
|
||||
color: #64748B;
|
||||
}
|
||||
|
||||
.order-btns {
|
||||
display: flex;
|
||||
gap: 12rpx;
|
||||
|
||||
.btn-chat {
|
||||
background: rgba(99, 102, 241, 0.15);
|
||||
color: #818CF8;
|
||||
border: 1px solid rgba(99, 102, 241, 0.3);
|
||||
font-size: 20rpx;
|
||||
height: 52rpx;
|
||||
line-height: 50rpx;
|
||||
padding: 0 20rpx;
|
||||
border-radius: 26rpx;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.btn-complete {
|
||||
background: linear-gradient(135deg, #10B981 0%, #059669 100%);
|
||||
color: #FFF;
|
||||
font-size: 20rpx;
|
||||
font-weight: 600;
|
||||
height: 52rpx;
|
||||
line-height: 52rpx;
|
||||
padding: 0 22rpx;
|
||||
border-radius: 26rpx;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-switch-wrap {
|
||||
margin-top: 40rpx;
|
||||
|
||||
.btn-back-player {
|
||||
background: #151D30;
|
||||
color: #94A3B8;
|
||||
font-size: 26rpx;
|
||||
height: 84rpx;
|
||||
line-height: 84rpx;
|
||||
border-radius: 42rpx;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -59,12 +59,12 @@
|
||||
<text class="quick-title">服务订单</text>
|
||||
<text class="quick-sub">状态实时看</text>
|
||||
</view>
|
||||
<view class="quick-item btn-active" @click="navTo('/pages/user/index')">
|
||||
<view class="quick-item btn-active" @click="navTo('/pages/expert/workspace')">
|
||||
<view class="quick-icon-bg bg-orange">
|
||||
<image class="quick-svg" :src="ICONS.expertBadge" mode="aspectFit" />
|
||||
</view>
|
||||
<text class="quick-title">大神中心</text>
|
||||
<text class="quick-sub">双身份切换</text>
|
||||
<text class="quick-sub">接单工作台</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
@@ -123,16 +123,20 @@ const toggleRole = () => {
|
||||
if (currentRole.value === 'PLAYER') {
|
||||
currentRole.value = 'EXPERT';
|
||||
uni.showToast({
|
||||
title: '已无缝切换为【大神接单端】!',
|
||||
title: '正在进入【大神接单工作台】...',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
duration: 1200
|
||||
});
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/expert/workspace'
|
||||
});
|
||||
}, 600);
|
||||
} else {
|
||||
currentRole.value = 'PLAYER';
|
||||
uni.showToast({
|
||||
title: '已切换回【普通玩家端】!',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
title: '已切回【玩家端】',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -173,7 +177,9 @@ const showInvitePoster = () => {
|
||||
};
|
||||
|
||||
const applyExpert = () => {
|
||||
uni.showToast({ title: '已提交大神实名技能审核', icon: 'none' });
|
||||
uni.navigateTo({
|
||||
url: '/pages/expert/workspace'
|
||||
});
|
||||
};
|
||||
|
||||
const contactService = () => {
|
||||
|
||||
在新工单中引用
屏蔽一个用户