mrr.sj.front/pages/artisan/index.vue

840 lines
19 KiB
Vue

<template>
<view class="artisan-page">
<view class="bg">
<!-- 顶部导航栏 -->
<custom-navbar
:title="artisanType == 1 ? '共享手艺人' : '商家'"
:show-back="true"
title-color="#000000"
backgroundColor="transparent"
></custom-navbar>
<!-- 头像信息区 -->
<view class="profile-section">
<view class="profile-info">
<image class="avatar"
v-if="userInfo.head_photo"
:src="userInfo.head_photo"
mode="aspectFill"></image>
<view class="info-content">
<view class="name">{{userInfo.name}}</view>
<view class="welcome">欢迎使用美融融{{artisanType == 1 ? '手艺人' : '商家'}}</view>
</view>
</view>
<view class="center-btn" @click="goRoleMy">
<view class="center-text">
{{artisanType == 1 ? '个人' : '商家'}}中心 >
</view>
</view>
</view>
</view>
<view class="switch-section">
<text class="switch-tip" @click="goMoreSetting" v-if="artisanType == 1">更多接单设置</text>
<view class="switch-box"
@click="handleSwitchChange()"
:class="{disswitch: userInfo.order_taking == 2}">
<text class="switch-text" v-if="userInfo.order_taking == 1">接单</text>
<view class="switch-yuan"></view>
<text class="switch-text" v-if="userInfo.order_taking == 2">不接单</text>
</view>
</view>
<!-- 赛事专区 -->
<!-- <view class="competition-section">
<view class="comp-left">
<image class="trophy-icon" src="/static/images/trophy.png" mode="aspectFit"></image>
<text>赛事专区</text>
</view>
<view class="comp-right" @click="goToCompetition">
<text>报名入口</text>
<image class="arrow-icon" src="/static/images/arrow-right.png" mode="aspectFit"></image>
</view>
</view> -->
<!-- 数据统计 -->
<!-- <view class="statistics-section">
<view class="stat-header">
<text class="stat-title">数据总览</text>
<view class="time-filter">
<text :class="{ active: timeRange === 'single' }" @click="switchTimeRange('single')">单笔</text>
<text :class="{ active: timeRange === '7days' }" @click="switchTimeRange('7days')">7天内</text>
<text class="date">2025-03-21</text>
</view>
</view> -->
<!-- 数据图表 -->
<!-- <view class="chart-container">
<qiun-data-charts
type="line"
:opts="chartOpts"
:chartData="chartData"
/>
</view>
</view> -->
<!-- 订单类型 -->
<view class="order-types">
<view class="order-type-item"
@click="handleOrderType(2)"
:class="{active: typeOrder == 2}"
v-if="artisanType == 1">
<text class="type-name">等待确认订单</text>
<text class="type-count"
v-if="ordernum.noconfirmnum != 0">{{ordernum.noconfirmnum}}</text>
</view>
<view class="order-type-item"
@click="handleOrderType(3)"
:class="{active: typeOrder == 3}">
<text class="type-name">待服务订单</text>
<text class="type-count"
v-if="ordernum.noservernum != 0">{{ordernum.noservernum}}</text>
</view>
<view class="order-type-item"
@click="handleOrderType(4)"
:class="{active: typeOrder == 4}">
<text class="type-name">待完成订单</text>
<text class="type-count"
v-if="ordernum.nocompletednum != 0">{{ordernum.nocompletednum}}</text>
</view>
</view>
<!-- 订单列表 -->
<view class="order-list" v-if="count != 0">
<view class="order-item"
v-for="(item,i) in orderList"
:key="item.id"
@click="goOrderDetail(item.id)">
<view class="order-header">
<text class="service-name text-overflow-1">{{item.server_title}}</text>
<image src="/static/images/arrow_right.png" class="arrow-right" mode="aspectFit"></image>
</view>
<view class="order-info">
<text class="address text-overflow-1" v-if="item.order_kind == 1 && item.reservation_address_arr">到家地址:{{item.reservation_address_arr.server_address}}</text>
<text class="service-time" v-if="item.order_kind == 1">到家时间:{{item.reservation_time}}</text>
<text class="order-number">订单编号:{{item.number}}</text>
</view>
<view class="order-actions">
<view class="action-btn cancel"
v-if="item.state == 2 || item.state == 3"
@click.stop="cancelOrder($event, item)">
<text class="action-text">取消订单</text>
</view>
<view class="action-btn verify"
v-if="item.state == 2"
@click.stop="confirmOrder($event, item)">
<text class="action-text">确认订单</text>
</view>
<view class="action-btn verify"
v-if="item.state == 3"
@click.stop="startOrder($event, item)">
<text class="action-text">开始服务</text>
</view>
<view class="action-btn verify"
v-if="item.state == 4"
@click.stop="endOrder($event, item)">
<text class="action-text">服务完成</text>
</view>
</view>
</view>
</view>
<view class="nothings-box" v-else>
<text class="nothings-text">暂无数据...</text>
</view>
<serviceCodeInput
:show="showInput"
@close="showInput = false"
@confirm="onConfirm"
/>
</view>
</template>
<script>
import request from '../../utils/request';
import { debounce } from '../../utils/debounce';
import serviceCodeInput from '../../components/service-code-input/service-code-input.vue';
export default {
components: { serviceCodeInput },
data() {
return {
artisanType: getApp().globalData.artisanType,
userInfo: {},
typeOrder: getApp().globalData.artisanType == 1 ? 2 : 3, // 2 等待确认 3 待服务 4 待完成
ordernum: {},
orderList: [],
handelOrder: {},
showInput: false,
timeRange: '7days',
count: 0,
chartOpts: {
color: ["#FF4767"],
padding: [15, 15, 0, 15],
enableScroll: false,
legend: false,
xAxis: {
gridType: "solid",
gridColor: "#F0F0F0",
fontColor: "#999999",
rotateLabel: false
},
yAxis: {
gridType: "dash",
splitNumber: 4,
gridColor: "#F0F0F0",
fontColor: "#999999",
format: "value"
},
extra: {
line: {
type: "straight",
width: 2
}
}
},
chartData: {
categories: ["03-19", "03-20", "03-21", "03-21", "03-21", "03-21"],
series: [{
name: "订单量",
data: [1.0, 0, 0, 0, 0, 0]
}]
}
}
},
onLoad() {
// 获取状态栏高度
const systemInfo = uni.getSystemInfoSync();
this.getUserInfo();
this.getOrderNumber();
this.getOrderList();
},
methods: {
getUserInfo() {
const type = this.artisanType == 1 ? 2 : this.artisanType == 2 ? 3 : 1;
request.post('/user/getuser',{type}).then(result=>{
this.userInfo = result.data;
})
},
syrorsjordertaking() {
const type = this.artisanType == 1 ? 2 : this.artisanType == 2 ? 3 : 1;
request.post('/user/syrorsjordertaking',{type: this.artisanType,order_taking: this.userInfo.order_taking}).then(result=>{
request.post('/user/getuser',{type}).then(result=>{
this.userInfo.order_taking = result.data.order_taking;
})
})
},
getOrderNumber() {
request.post('/user/ordernum',{type: this.artisanType}).then(res=>{
this.ordernum = res.data;
})
},
getOrderList() {
let state = [];
state[0] = this.typeOrder;
request.post('/user/syrandsjorders',{type: this.artisanType,state}).then(res=>{
console.log(res)
this.orderList = res.data;
this.count = res.count;
})
},
handleSwitchChange(e) {
this.orderSwitch = e;
if(this.userInfo.order_taking == 1) {
this.userInfo.order_taking = 2
}else if(this.userInfo.order_taking == 2) {
this.userInfo.order_taking = 1
}
this.syrorsjordertaking();
},
goRoleMy() {
uni.navigateTo({
url: '/pages/artisan/my'
})
},
goMoreSetting() {
uni.navigateTo({
url: '/pages/artisan/unavailable-time'
})
},
// 去订单详情
goOrderDetail(id) {
uni.navigateTo({
url: '/pages/order/artisanorder-detail?id='+id
})
},
// 报名入口
goToCompetition() {
},
switchTimeRange(range) {
this.timeRange = range
},
handleOrderType(type) {
// 处理不同类型订单的点击
this.typeOrder = type;
this.getOrderList()
},
// 取消订单
cancelOrder(e, order) {
// app阻止事件冒泡
// #ifdef APP-PLUS
e.preventDefault();
e.stopPropagation();
// #endif
if(order.state == 1) {
uni.showModal({
title: '取消订单',
content: '确定要取消该订单吗?',
success: (res) => {
if (res.confirm) {
// TODO: 取消订单
let data = {
orderNo: order.number,
amount: order.pay_money,
cancel_state: this.artisanType + 1,
cancel_id: this.userInfo.id
}
request.post('/user/cancelorder',data).then(res=>{
if(res.state == 1) {
uni.showToast({
title: '取消成功!',
icon: 'none'
})
this.getOrderNumber();
this.getOrderList();
}else {
uni.showToast({
title: res.msg,
icon: 'none'
})
}
}).catch(err=>{
console.log(err)
})
}
}
})
}else {
uni.showModal({
title: '取消订单',
content: '确定要取消该订单吗?(订单取消后,支付金额将原路退回)',
success: (res) => {
if (res.confirm) {
// TODO: 取消订单
let data = {
orderNo: order.number,
amount: order.pay_money,
cancel_state: this.artisanType + 1,
cancel_id: this.userInfo.id
}
let url = '';
if(order.pay_kind == 1) {
url = '/user/cancelbalance'
}else if(order.pay_kind == 2) {
url = '/user/wechatrefund'
}else if(order.pay_kind == 3) {
url = '/user/alirefund'
}
console.log(data,url)
request.post(url,data).then(res=>{
console.log('取消订单返回结果',res)
if(res.state == 1) {
uni.showToast({
title: '取消成功!',
icon: 'none'
})
this.getOrderNumber();
this.getOrderList();
}else {
uni.showToast({
title: res.msg,
icon: 'none'
})
}
}).catch(err=>{
console.log(err)
})
}
}
})
}
},
// 确认接单
confirmOrder(e, order) {
// app阻止事件冒泡
// #ifdef APP-PLUS
e.preventDefault();
e.stopPropagation();
// #endif
request.post('/user/ordersure',{id: order.id}).then(res=>{
uni.showToast({
title: '已接单',
icon: 'none'
})
this.getOrderNumber();
this.getOrderList();
})
},
// 开始服务
startOrder(e, order) {
// app阻止事件冒泡
// #ifdef APP-PLUS
e.preventDefault();
e.stopPropagation();
// #endif
this.showInput = true
this.handelOrder = order;
},
// 输入完成
onConfirm(code) {
this.showInput = false
request.post('/user/startserver',{id: this.handelOrder.id,server_code: code,order_shopid: this.userInfo.id}).then(res=>{
console.log(res)
if(res.state == 1) {
uni.showToast({
title: res.msg,
icon: 'none'
})
this.getOrderNumber();
this.getOrderList();
}else if(res.state == 2) {
uni.showToast({
title: res.msg,
icon: 'none'
})
}
this.handelOrder = {};
})
},
// 完成服务
// endOrder(e, order) {
// // app阻止事件冒泡
// // #ifdef APP-PLUS
// e.preventDefault();
// e.stopPropagation();
// // #endif
// request.post('/user/endserver',{id: order.id,order_shopid: this.userInfo.id}).then(res=>{
// console.log('res====================',res)
// if(res.state == 1) {
// uni.showToast({
// title: res.msg,
// icon: 'none'
// })
// this.getOrderNumber();
// this.getOrderList();
// }
// })
// },
// 完成服务
endOrder: debounce(function(e, order) {
// app阻止事件冒泡
// #ifdef APP-PLUS
e.preventDefault();
e.stopPropagation();
// #endif
request.post('/user/endserver',{id: order.id,order_shopid: this.userInfo.id}).then(res=>{
console.log('res====================',res)
if(res.state == 1) {
uni.showToast({
title: res.msg,
icon: 'none'
})
this.getOrderNumber();
this.getOrderList();
}
})
},500)
}
}
</script>
<style>
page {
background-color: #fff;
padding-bottom: 40rpx;
}
.artisan-page {
/* min-height: 100vh; */
position: relative;
}
.artisan-page::before {
content: '';
position: fixed;
top: 0;
left: 0;
right: 0;
height: 1200rpx !important;
background-image: url('/static/images/bg.png');
background-size: cover;
background-position: center top;
background-repeat: no-repeat;
z-index: 1;
}
.bg {
position: relative;
}
.bg::before {
content: '';
position: fixed;
top: 0;
left: 0;
right: 0;
height: 272rpx !important;
/* #ifdef APP-PLUS || MP-WEIXIN */
height: calc(272rpx + var(--status-bar-height)) !important;
/* #endif */
background-image: url('/static/images/bg.png');
background-size: cover;
background-position: center top;
background-repeat: no-repeat;
z-index: 999;
}
.profile-section,
.switch-section,
.order-types,
.order-list,
.nothings-box{
position: relative;
z-index: 99;
}
.profile-section {
position: fixed;
top: 88rpx;
left: 0;
right: 0;
height: 184rpx;
/* background-color: transparent; */
z-index: 999;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
padding: 0 24rpx;
}
.profile-info {
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: center;
}
.avatar {
width: 96rpx;
height: 96rpx;
border-radius: 50rpx;
margin-right: 24rpx;
background-color: #333333;
border: 4rpx solid #FFFFFF;
}
.name {
font-size: 36rpx;
font-weight: 700;
color: #000000;
}
.welcome {
font-size: 24rpx;
color: #000000;
}
.center-text {
color: #000000;
font-size: 28rpx;
}
.switch-section {
margin: 184rpx 24rpx 32rpx;
height: 80rpx;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
font-size: 28rpx;
background-color: #F7EFF2;
border-radius: 40rpx;
padding: 0 32rpx;
box-shadow: 0 4rpx 16rpx 0 rgba(210, 213, 224, 0.50);
}
.switch-box {
/* width: 126rpx; */
height: 52rpx;
line-height: 52rpx;
border-radius: 26rpx;
background-color: #31BD54;
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
padding: 0 6rpx;
}
.switch-text {
font-size: 28rpx;
color: #FFFFFF;
}
.switch-yuan {
width: 40rpx;
height: 40rpx;
border-radius: 20rpx;
background-color: #fff;
margin-left: 4rpx;
}
.switch-box.disswitch {
background-color: rgba(0, 0, 0, 0.1);
}
.switch-box.disswitch .switch-yuan {
margin-left: 0;
margin-right: 4rpx;
}
.switch-tip {
font-size: 24rpx;
color: #666666;
}
.competition-section {
margin: 24rpx;
background-color: #FFFFFF;
border-radius: 12rpx;
padding: 24rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.comp-left {
display: flex;
align-items: center;
}
.trophy-icon {
width: 48rpx;
height: 48rpx;
margin-right: 16rpx;
}
.comp-right {
display: flex;
align-items: center;
color: #999999;
font-size: 24rpx;
}
.arrow-icon {
width: 32rpx;
height: 32rpx;
margin-left: 8rpx;
}
.statistics-section {
margin: 24rpx;
background-color: #FFFFFF;
border-radius: 12rpx;
padding: 24rpx;
}
.stat-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
}
.stat-title {
font-size: 32rpx;
font-weight: 500;
}
.time-filter {
display: flex;
align-items: center;
font-size: 24rpx;
color: #999999;
}
.time-filter text {
margin-left: 24rpx;
}
.time-filter .active {
color: #FF4767;
}
.chart-container {
height: 400rpx;
margin-bottom: 24rpx;
}
.order-types {
display: flex;
justify-content: flex-start;
gap: 22rpx;
margin: 32rpx 24rpx 24rpx;
}
.order-type-item {
width: 214rpx;
height: 56rpx;
background-color: #FFFFFF;
border: 1rpx solid #FF4767;
border-radius: 8rpx;
display: flex;
justify-content: center;
align-items: center;
position: relative;
box-sizing: border-box;
}
.type-name {
font-size: 24rpx;
color: #FF4767;
}
.type-count {
display: block;
position: absolute;
top: -12rpx;
right: -12rpx;
font-size: 24rpx;
color: #fff;
font-weight: 500;
width: 32rpx;
height: 32rpx;
text-align: center;
line-height: 28rpx;
border-radius: 16rpx;
border: 2rpx solid #fff;
box-sizing: border-box;
background-color: #F53F3F;
}
.order-type-item.active {
background-color: #FF4767;
}
.order-type-item.active .type-name {
color: #FFFFFF;
font-weight: 500;
}
.order-list {
margin: 24rpx;
}
.order-item {
background-color: #FFFFFF;
border-radius: 16rpx;
padding: 32rpx;
margin-bottom: 24rpx;
box-shadow: 0 8rpx 16rpx 0 rgba(210, 213, 224, 0.50);
}
.order-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8rpx;
}
.service-name {
font-size: 28rpx;
color: #333333;
font-weight: 500;
flex: 1;
}
.order-info {
margin-bottom: 32rpx;
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: flex-start;
}
.address,
.service-time,
.order-number {
flex: 1;
font-size: 24rpx;
color: #666666;
}
.order-footer {
display: flex;
justify-content: space-between;
align-items: center;
}
.order-actions {
padding-top: 32rpx;
border-top: 1rpx solid rgba(0, 0, 0, 0.05);
display: flex;
flex-flow: row nowrap;
justify-content: flex-end;
align-items: center;
gap: 24rpx;
}
.action-btn {
/* width: 96rpx;
height: 40rpx; */
padding: 8rpx 12rpx;
display: flex;
justify-content: center;
align-items: center;
border-radius: 6rpx;
}
.action-btn.cancel,
.action-btn.confirm{
border: 1rpx solid rgba(51, 51, 51, 0.12);
box-sizing: border-box;
}
.action-btn.cancel .action-text,
.action-btn.confirm .action-text{
font-size: 28rpx;
color: #333333;
font-weight: 400;
}
.action-btn.verify {
border: 1rpx solid rgba(252, 67, 124, 0.12);
box-sizing: border-box;
}
.action-btn.verify .action-text {
font-size: 28rpx;
color: #FF4767;
}
.nothings-box {
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
padding: 280rpx 0 0;
}
.nothings-text {
font-size: 32rpx;
font-weight: 500;
color: #999999;
text-align: center;
font-style: italic;
}
/* APP适配 */
/* #ifdef APP-PLUS */
.nav-bar {
padding-top: 0;
}
.profile-section {
top: calc(var(--status-bar-height) + 88)rpx;
}
/* #endif */
/* 小程序适配 */
/* #ifdef MP-WEIXIN */
.nav-bar {
padding-top: constant(safe-area-inset-top);
padding-top: env(safe-area-inset-top);
}
.profile-section {
top: calc(var(--status-bar-height) + 88rpx);
}
/* #endif */
</style>