师傅端版本研发

This commit is contained in:
yangdanqi 2022-05-06 23:47:18 +08:00
parent 496d4c46cb
commit 45fbdc18be
14 changed files with 1406 additions and 109 deletions

View File

@ -148,33 +148,41 @@ const tasks = [{
const takeCertify = true;
const areaList = [[{
id: 100,
name: '广东'
}, {
id: 101,
name: '海南'
}], [{
id: 200,
name: '广州'
}], [{
id: 300,
name: '天河'
}]]
const areaList = [
[{
id: 100,
name: '广东'
}, {
id: 101,
name: '海南'
}],
[{
id: 200,
name: '广州'
}],
[{
id: 300,
name: '天河'
}]
]
const categoryList = [[{
id: 100,
name: '电器类'
}, {
id: 101,
name: '家政类'
}], [{
id: 200,
name: '全部'
}], [{
id: 300,
name: '全部'
}]];
const categoryList = [
[{
id: 100,
name: '电器类'
}, {
id: 101,
name: '家政类'
}],
[{
id: 200,
name: '全部'
}],
[{
id: 300,
name: '全部'
}]
];
const order = {
id: 1,
@ -194,6 +202,84 @@ const order = {
comments: '上门前10分钟先电话联系'
}
const myOrders = {
summary: {
overtimeOrderNum: 336,
todayOrderNum: 1,
tomorrowOrderNum: 0,
urgentMsgOrderNum: 0,
newOrderNum: 1
},
orderList: [{
id: 1,
title: '清洗空调/挂机内机拆洗(不分匹)',
state: '',
subState: 'waitServing',
tags: [{
level: 'info',
content: '商城订单'
}, {
level: 'error',
content: '超时未预约'
}],
name: 'cc',
address: '广东省广州市天河区。。。。。。',
servTime: '2022-06-01 08:00-08:30',
doorTime: '2022-06-01 08:15:00',
comments: '备注内容。。。。。。',
phoneNum: '13233433467',
deadlineDate: '2022-06-01 08:30:00',
product: {
id: 1,
picUrl: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big20000.jpg',
name: '柜机空调清洗1',
comments: '备---------注',
salePrice: 199,
price: 250,
type: '空调/清洗',
servArea: ['天河区', '黄埔区', '荔湾区'],
pickedList: [{
id: 101,
name: '挂机内机拆洗1不分匹',
valColArr: [{
value: 3
}, {
numberBox: true,
max: 3
}]
}]
}
}]
}
const timeRangeList = [
'08:00-08:30',
'08:30-09:00',
'09:00-09:30',
'09:30-10:00',
'10:00-10:30',
'10:30-11:00',
'11:00-11:30',
'11:30-12:00',
'12:00-12:30',
'12:30-13:00',
'13:00-13:30',
'13:30-14:00',
'14:00-14:30',
'14:30-15:00',
'14:30-15:00',
'15:00-15:30',
'15:30-16:00',
'16:00-16:30',
'16:30-17:00',
'17:00-17:30',
'17:30-18:00',
'18:00-18:30',
'18:30-19:00',
'19:00-19:30',
'19:30-20:00'
]
export default {
moduleBarInfos,
myInfo,
@ -204,5 +290,7 @@ export default {
takeCertify,
categoryList,
areaList,
order
order,
myOrders,
timeRangeList
}

30
common/js/dateUtil.js Normal file
View File

@ -0,0 +1,30 @@
export default {
dateCache: null,
countDownDiffCache: null,
countDownDiff(dateStr) {
if (dateStr == this.dateCache) {
return this.countDownDiffCache;
}
let dayTimes = 24*60*60*1000;
let hourTimes = 60*60*1000;
let minTimes = 60*1000;
let secondsTimes = 1000;
let dateTimesDiff = new Date(dateStr).getTime() - new Date().getTime();
let day = Math.floor(dateTimesDiff / dayTimes);
let leftOver = dateTimesDiff % dayTimes;
let hour = Math.floor(leftOver / hourTimes);
leftOver = leftOver % hourTimes;
let min = Math.floor(leftOver / minTimes);
leftOver = leftOver % minTimes;
let seconds = Math.floor(leftOver / secondsTimes);
leftOver = leftOver % secondsTimes;
this.dateCache = dateStr;
this.countDownDiffCache = {
day: day,
hour: hour,
min: min,
seconds: seconds
}
return this.countDownDiffCache;
}
}

View File

@ -3,5 +3,8 @@ export default {
CANCEL: 'cacelCallback',
VERTICAL_NAV_GET_ITEM: 'verticalNavGetItem',
VERTICAL_NAV_SEARCH: 'verticalNavSearch',
CHOOSE_ADDRESS: 'chooseAddress'
CHOOSE_ADDRESS: 'chooseAddress',
SHOW_ARRANGE_FAIL_TIME: 'showArrangeFailTime',
HIDE_MODAL: 'hideModal',
SUBMIT_FAIL_REASON: 'submitFailReason'
}

View File

@ -0,0 +1,79 @@
<template>
<view class="flex justify-start">
<view class="cu-avatar xxl-view" :style="'background-image:url(' + product.picUrl + ');'">
</view>
<view class="margin-left-sm product-content">
<view>
<view class="text-black">{{product.name}}</view>
<view class="text-sm" v-if="ifShowComments">{{product.comments}}</view>
</view>
<view class="flex justify-between align-center">
<view class="flex justify-start align-center">
<text class="text-price text-red text-bold text-xl">{{product.salePrice}}</text>
<text class="text-del">¥{{product.price}}</text>
</view>
<view class="padding-xs">
<view class='cu-tag light bg-blue'>{{product.type}}</view>
</view>
</view>
<view v-if="ifShowServArea">
<view class="cu-capsule">
<view class='cu-tag bg-main-color sm'>
<text class='cuIcon-locationfill'></text>
</view>
<view class="cu-tag line-main-color sm">
服务区域
</view>
</view>
<text class="margin-lr-xs text-sm" v-if="ifShowServArea">{{product.servArea}}</text>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'horizontal-goods-card',
props: {
ifShowServArea: {
type: Boolean,
default: false
},
ifShowComments: {
type: Boolean,
default: true
},
product: {
type: Object,
default: {}
}
},
data() {
return {
}
}
}
</script>
<style scoped>
.xxl-view {
min-width: 230rpx;
min-height: 230rpx;
}
.product-content {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 100%;
}
.cu-list.menu-avatar>.cu-item .content .cu-tag.sm {
display: inline-block;
margin-left: 0;
height: 28rpx;
font-size: 16rpx;
line-height: 32rpx;
}
</style>

View File

@ -0,0 +1,80 @@
<template>
<view>
<view class="bg-white padding-bottom">
<horizontal-goods-card v-if="product" :ifShowServArea="true" :product="product"></horizontal-goods-card>
<view v-if="columnTitleArr.length" class="flex justify-between margin-tb-sm">
<view class="basis-df">{{columnTitleArr[0]}}</view>
<view class="flex justify-end text-center basis-sm">
<view v-for="(title, index) in columnTitleArr" v-if="index >= 1" class="basis-df">{{title}}</view>
</view>
</view>
<view class="certern-height-with-scroll">
<view class="flex justify-between margin-tb-xs align-center" v-for="(item,index) in pickedList" :key="item.id">
<view class='cu-tag padding line-main-color basis-df'>{{item.name}}</view>
<view v-if="numberBox" class="flex justify-end basis-xs">
<uni-number-box :min="0" :max="item.maxPieces" :value="item.pickedNum"
@change="changePiecesNum($event, item)">
</uni-number-box>
</view>
<view v-else-if="item.valColArr && item.valColArr.length > 0" class="flex justify-end basis-sm text-center">
<uni-number-box class="basis-df" v-for="(valCol, index0) in item.valColArr" v-if="valCol.numberBox"
:min="0" :max="valCol.max" :value="valCol.value" @change="changePiecesNum($event, item)">
</uni-number-box>
<view class="basis-df" v-else>{{valCol.value}}</view>
</view>
<view v-else class="flex justify-end basis-sm text-center">
<view class="basis-df"><text v-if="!showToServNum">×</text>{{item.pickedNum}}</view>
<view class="basis-df" v-if="showToServNum">
{{item.toServNum == undefined || item.toServNum == null ? item.secondColumnNum : item.toServNum}}
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import horizontalGoodsCard from '@/components/goods-card/horizontal-goods-card.vue';
export default {
name: "product-picked",
props: {
product: {
type: Object,
default: null
},
pickedList: {
type: Array,
default: []
},
columnTitleArr: {
type: Array,
default: []
},
showToServNum: {
type: Boolean,
default: false
},
numberBox: {
type: Boolean,
default: false
}
},
components: {
horizontalGoodsCard
},
methods: {
changePiecesNum(curNum, curItem) {
uni.$emit('changePickedNum', curNum, curItem)
}
},
}
</script>
<style scoped>
.certern-height-with-scroll {
max-height: 300rpx;
overflow: scroll;
}
</style>

View File

@ -0,0 +1,277 @@
<template>
<view class="uni-combox" :class="border ? '' : 'uni-combox__no-border'">
<view v-if="label" class="uni-combox__label" :style="labelStyle">
<text>{{label}}</text>
</view>
<view class="uni-combox__input-box">
<input class="uni-combox__input" type="text" :placeholder="placeholder"
placeholder-class="uni-combox__input-plac" v-model="inputVal.name" @input="onInput" @focus="onFocus"
@blur="onBlur" />
<uni-icons :type="showSelector? 'top' : 'bottom'" size="14" color="#999" @click="toggleSelector">
</uni-icons>
</view>
<view class="uni-combox__selector" v-if="showSelector">
<view class="uni-popper__arrow"></view>
<scroll-view scroll-y="true" class="uni-combox__selector-scroll">
<view class="uni-combox__selector-empty" v-if="filterCandidatesLength === 0">
<text>{{emptyTips}}</text>
</view>
<view class="uni-combox__selector-item" v-for="(item,index) in filterCandidates" :key="index"
@click="onSelectorClick(index)">
<text>{{item.name}}</text>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
/**
* Combox 组合输入框
* @description 组合输入框一般用于既可以输入也可以选择的场景
* @tutorial https://ext.dcloud.net.cn/plugin?id=1261
* @property {String} label 左侧文字
* @property {String} labelWidth 左侧内容宽度
* @property {String} placeholder 输入框占位符
* @property {Array} candidates 候选项列表
* @property {String} emptyTips 筛选结果为空时显示的文字
* @property {String} value 组合框的值
*/
export default {
name: 'myUniCombox',
emits: ['input', 'update:modelValue'],
props: {
border: {
type: Boolean,
default: true
},
label: {
type: String,
default: ''
},
labelWidth: {
type: String,
default: 'auto'
},
placeholder: {
type: String,
default: ''
},
candidates: {
type: Object,
default () {
return {}
}
},
emptyTips: {
type: String,
default: '无匹配项'
},
// #ifndef VUE3
value: {
type: [String, Number],
default: ''
},
// #endif
// #ifdef VUE3
modelValue: {
type: [String, Number],
default: ''
},
// #endif
},
data() {
return {
showSelector: false,
inputVal: ''
}
},
computed: {
labelStyle() {
if (this.labelWidth === 'auto') {
return ""
}
return `width: ${this.labelWidth}`
},
filterCandidates() {
return this.candidates
//
// .filter((item) => {
// return item.toString().indexOf(this.inputVal) > -1
// })
},
filterCandidatesLength() {
return this.filterCandidates.length
}
},
watch: {
// #ifndef VUE3
value: {
handler(newVal) {
this.inputVal = newVal
},
immediate: true
},
// #endif
// #ifdef VUE3
modelValue: {
handler(newVal) {
this.inputVal = newVal
},
immediate: true
},
// #endif
},
methods: {
toggleSelector() {
this.showSelector = !this.showSelector
},
onFocus() {
this.showSelector = true
},
onBlur() {
setTimeout(() => {
this.showSelector = false
}, 153)
},
onSelectorClick(index) {
this.inputVal = this.filterCandidates[index]
this.showSelector = false
this.$emit('input', this.inputVal)
this.$emit('update:modelValue', this.inputVal.name)
},
onInput() {
setTimeout(() => {
this.$emit('input', this.inputVal)
this.$emit('update:modelValue', this.inputVal)
})
}
}
}
</script>
<style lang="scss" >
.uni-combox {
font-size: 14px;
border: 1px solid #DCDFE6;
border-radius: 4px;
padding: 6px 10px;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
// height: 40px;
flex-direction: row;
align-items: center;
// border-bottom: solid 1px #DDDDDD;
}
.uni-combox__label {
font-size: 16px;
line-height: 22px;
padding-right: 10px;
color: #999999;
}
.uni-combox__input-box {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
}
.uni-combox__input {
flex: 1;
font-size: 28rpx;
height: 22px;
line-height: 22px;
}
.uni-combox__input-plac {
font-size: 28rpx;
// color: #999;
}
.uni-combox__selector {
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
position: absolute;
top: calc(100% + 12px);
left: 0;
width: 100%;
background-color: #FFFFFF;
border: 1px solid #EBEEF5;
border-radius: 6px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 2;
padding: 4px 0;
}
.uni-combox__selector-scroll {
/* #ifndef APP-NVUE */
max-height: 200px;
box-sizing: border-box;
/* #endif */
}
.uni-combox__selector-empty,
.uni-combox__selector-item {
/* #ifndef APP-NVUE */
display: flex;
cursor: pointer;
/* #endif */
line-height: 36px;
font-size: 28rpx;
text-align: center;
// border-bottom: solid 1px #DDDDDD;
padding: 0px 10px;
}
.uni-combox__selector-item:hover {
background-color: #f9f9f9;
}
.uni-combox__selector-empty:last-child,
.uni-combox__selector-item:last-child {
/* #ifndef APP-NVUE */
border-bottom: none;
/* #endif */
}
// picker
.uni-popper__arrow,
.uni-popper__arrow::after {
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 6px;
}
.uni-popper__arrow {
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
top: -6px;
left: 10%;
margin-right: 3px;
border-top-width: 0;
border-bottom-color: #EBEEF5;
}
.uni-popper__arrow::after {
content: " ";
top: 1px;
margin-left: -6px;
border-top-width: 0;
border-bottom-color: #fff;
}
.uni-combox__no-border {
border: none;
}
</style>

View File

@ -6,15 +6,14 @@ import ConfirmModal from '@/components/modal/confirm-modal.vue';
import Data from './common/js/data.js';
import globalFun from './common/js/glogalFun.js';
import validate from './common/js/validate.js';
import dateUtil from './common/js/dateUtil.js';
Vue.component('cu-custom', CuCustom)
Vue.component('confirm-modal', ConfirmModal);
const data = type => {
//模拟异步请求数据
return new Promise(resolve => {
setTimeout(() => {
resolve(Data[type]);
}, 0)
resolve(Data[type]);
})
}
Vue.prototype.$api = {
@ -22,6 +21,7 @@ Vue.prototype.$api = {
}
Vue.prototype.$globalFun = globalFun;
Vue.prototype.$validate = validate;
Vue.prototype.$dateUtil = dateUtil;
Vue.config.productionTip = false

View File

@ -1,7 +1,6 @@
{
"pages": [{
"path": "pages/index/index"
// "path": "pages/area-proxy/my-team"
}],
"subPackages": [{
"root": "pages/area-proxy/",
@ -17,6 +16,11 @@
}, {
"path": "demand-detail"
}]
}, {
"root": "pages/order-manage/",
"pages": [{
"path": "order-manage"
}]
}],
"globalStyle": {
"navigationStyle": "custom",

View File

@ -122,7 +122,7 @@
name: '查看详情',
color: 'orange',
cuIcon: 'text',
pageUrl: ''
pageUrl: '/pages/order-manage/order-manage'
}, {
id: 3,
title: '叮咚学院',

View File

@ -0,0 +1,102 @@
<template>
<view>
<view v-if="!singleServ">
<view class="solid-bottom"><product-picked :product="product" :pickedList="pickedList" :columnTitleArr="columnTitleArr"></product-picked></view>
<view class="padding-tb-sm solid-bottom flex justify-between align-center">
<text class="margin-right-sm" style="width: 150rpx;">派单价格</text>
<input class="line-input radius-input" v-model="dispatchTotalPrice" placeholder="请输入派出总额"></input>
</view>
</view>
<!-- 可指派成员 -->
<view class="bg-white padding" v-for="(member, index) in members">
<view class="flex justify-between align-center">
<view class="flex justify-start align-center">
<view class="cu-avatar round"
:style="'background-image:url(' + member.avatarUrl + ');min-width: 80rpx;min-height: 80rpx'"></view>
<view class="text-lg margin-left-sm">{{member.name}}</view>
</view>
<view>
<button class="cu-btn bg-main-color shadow-blur">指派</button>
<text v-if="singleServ" class="padding-left text-lg text-gray text-bold" data-modal="showDispatchPriceModal" @click="showModal"><text class="cuIcon-right"></text></text>
</view>
</view>
</view>
<!-- 派单金额模态框 -->
<view class="cu-modal" :class="showDispatchPriceModal?'show':''">
<view class="cu-dialog">
<view class="cu-bar bg-white justify-end solid-bottom">
<view class="content">按金额派出</view>
<view class="action" data-modal="showDispatchPriceModal" @tap="hideModal">
<text class="cuIcon-close text-red"></text>
</view>
</view>
<view class="padding-xl bg-white">
<view>请输入派单金额</view>
<view class="flex justify-center align-center margin-top-sm">
<input class="radius-input" type="digit"></input>
<text></text>
</view>
</view>
<view class="cu-bar bg-white solid-top">
<view class="action margin-0 flex-sub text-black" data-modal="showDispatchPriceModal" @tap="hideModal">取消</view>
<view class="action margin-0 flex-sub text-main-color solid-left" data-modal="showDispatchPriceModal" @tap="hideModal"
@click="">确认派单</view>
</view>
</view>
</view>
</view>
</template>
<script>
import productPicked from '@/components/goods-card/product-picked.vue';
export default {
name: 'dispatch-order',
components: {
productPicked
},
props: {
singleServ: {
type: Boolean,
default: true
},
product: {
type: Object,
default: {}
},
pickedList: {
type: Array,
default: []
},
columnTitleArr: {
type: Array,
default: {}
},
members: {
type: Array,
default: {}
},
orderNow: {
type: Boolean,
default: false
}
},
data() {
return {
dispatchTotalPrice: null,
showDispatchPriceModal: false
}
},
methods: {
showModal(e) {
this[e.currentTarget.dataset.modal] = true;
},
hideModal(e) {
this[e.currentTarget.dataset.modal] = false;
}
},
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,138 @@
<template>
<view class="cu-modal" :class="show?'show':''">
<view class="cu-dialog">
<view class="cu-bar bg-white justify-end solid-bottom">
<view class="content">上传拨打电话记录截图</view>
<view class="action" data-modal="showArrangeFailTimeModal" @click="hideModal">
<text class="cuIcon-close text-red"></text>
</view>
</view>
<view class="bg-white padding text-left">
<view>
<view class="grid col-3 grid-square flex-sub">
<view class="bg-img" v-for="(item,index) in imgList" :key="index"
@tap="viewImage($event, imgList)" :data-url="item">
<image :src="item" mode="aspectFill"></image>
<view class="cu-tag bg-red" @tap.stop="delImg($event, imgList)" :data-index="index">
<text class='cuIcon-close'></text>
</view>
</view>
<view class="solids" @tap="chooseImage" v-if="imgList.length < 1">
<text class='cuIcon-cameraadd'></text>
</view>
</view>
<view class="text-center">选填</view>
</view>
<view class="padding-tb-sm solid-bottom">多次联系客户未接通时可上传拨打截图确认无法排单客诉时你无责确认无法排单后将不计时效</view>
<view class="padding-top-sm">
<view class="flex justify-start">
<view class="margin-right">原因选择</view>
<radio-group @change="changeReasonRadio">
<label class="radio margin-right-sm">
<radio style="transform:scale(0.7)" class="main-color" value="customer"
:checked="true" />
<text>客户原因</text>
</label>
<label class="radio">
<radio style="transform:scale(0.7)" class="main-color" value="master" />
<text>师傅原因</text>
</label>
</radio-group>
</view>
<view class="margin-top uni-textarea">
<textarea class="solid padding-sm" maxlength="-1" @input="inputSpecificReason"
placeholder="具体情况(选填)" />
</view>
</view>
</view>
<view class="cu-bar bg-white solid-top">
<view class="action margin-0 flex-sub text-main-color solid-left" data-modal="showArrangeFailTimeModal"
@click="submitFailReason">确认无法排单</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'timeArrangeFail',
props: {
show: {
type: Boolean,
default: false
},
data: {
type: Object,
default: {}
}
},
data() {
return {
imgList: [],
problemPerson: '',
specificReason: ''
}
},
methods: {
hideModal(e) {
uni.$emit(this.$globalFun.HIDE_MODAL, e);
},
chooseImage(e) {
uni.chooseImage({
count: 1, //9
sizeType: ['original', 'compressed'], //
sourceType: ['album'], //
success: (res) => {
if (this.imgList.length != 0) {
this.imgList = this.imgList.concat(res.tempFilePaths)
} else {
this.imgList = res.tempFilePaths
}
}
});
},
viewImage(e, imgList) {
uni.previewImage({
urls: imgList,
current: e.currentTarget.dataset.url
});
},
delImg(e, imgList) {
uni.showModal({
title: '',
content: '确定要删除这张图片吗?',
cancelText: '取消',
confirmText: '确定',
success: res => {
if (res.confirm) {
imgList.splice(e.currentTarget.dataset.index, 1)
}
}
})
},
changeReasonRadio(e) {
this.problemPerson = e.detail.value;
},
inputSpecificReason(e) {
this.specificReason = e.detail.value;
},
submitFailReason(e) {
let reasonObj = {
imgList: this.imgList,
problemPerson: this.problemPerson,
specificReason: this.specificReason
}
uni.$emit(this.$globalFun.SUBMIT_FAIL_REASON, e, reasonObj)
}
}
}
</script>
<style scoped>
.grid.col-3.grid-square>view {
padding-bottom: calc((100% - 40rpx)/3);
height: 0;
width: calc((100% - 40rpx)/3);
margin-left: calc(100%/2 - (100% - 40rpx)/3/2);
}
</style>

View File

@ -0,0 +1,124 @@
<template>
<!-- 排单模态框 -->
<view class="cu-modal" :class="show?'show':''">
<view class="cu-dialog">
<view class="close-icon" data-modal="showTimeArrangeModal" @click="hideModal">
<text class="cuIcon-close text-red"></text>
</view>
<view class="padding bg-white text-left">
<view class="solid-bottom padding padding-bottom-sm">
<view class="flex justify-between align-center margin-bottom-xs padding-top">
<view>
<text class="text-xxl text-main-color"><text class="cuIcon-phone"></text></text>
<text class="text-bold text-lg margin-lr-xs">{{data.phoneNum}}</text>
</view>
<button class="cu-btn line-main-color">拨打</button>
</view>
<view class="text-sm">
拨打电话按与客户约定的时间填入完成排单未完成排单将导致排单超时
</view>
</view>
<view class="padding">
<view class="margin-bottom-xs">
<view class="margin-bottom-xs">选择日期</view>
<picker mode="date" :value="date" :start="curDate" @change="dateChange">
<input class="radius-input" v-model="date"></input>
</picker>
</view>
<view>
<view class="margin-bottom-xs">选择时间</view>
<picker class="inline-input" mode="time" :value="'08:00'" :start="'08:00'" :end="'20:00'"
@change="timeChange">
<input class="radius-input" v-model="time"></input>
</picker>
<text class="margin-lr-xs"></text>
<picker class="inline-input" mode="selector" :value="timeRangeIndex" :range="timeRangeList"
@change="timeRangeChange">
<input class="radius-input" v-model="timeRange"></input>
</picker>
</view>
</view>
</view>
<view class="cu-bar bg-white solid-top">
<view class="action margin-0 flex-sub text-black" @click="cannotArrangeTime">无法排单</view>
<view class="action margin-0 flex-sub text-black solid-left" data-modal="showTimeArrangeModal"
@click="arrangeTime">按原时间上门</view>
<view class="action margin-0 flex-sub text-main-color solid-left" data-modal="showTimeArrangeModal"
@click="arrangeTime">确认</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'time-arrange',
props: {
show: {
type: Boolean,
default: false
},
data: {
type: Object,
default: {}
}
},
data() {
return {
date: '',
curDate: '',
time: '',
timeRangeList: [],
timeRange: '',
timeRangeIndex: 0
}
},
onReady() {
this.loadData();
},
methods: {
async loadData() {
this.getCurDateAndTime();
this.timeRangeList = await this.$api.data('timeRangeList');
},
getCurDateAndTime() {
let date = new Date();
this.curDate = date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate() + " 00:00:00";
},
dateChange(e) {
this.date = e.detail.value
},
timeChange(e) {
this.time = e.detail.value;
},
timeRangeChange(e) {
this.timeRangeIndex = e.detail.value;
this.timeRange = this.timeRangeList[this.timeRangeIndex];
},
hideModal(e) {
uni.$emit(this.$globalFun.HIDE_MODAL, e);
},
cannotArrangeTime(e) {
uni.$emit(this.$globalFun.SHOW_ARRANGE_FAIL_TIME, e)
},
arrangeTime(e) {
this.hideModal(e);
}
}
}
</script>
<style scoped>
.inline-input {
display: inline-block;
width: calc((100% - 48rpx)/2);
vertical-align: middle;
}
.close-icon {
position: absolute;
right: 35rpx;
top: 35rpx;
z-index: 1;
}
</style>

View File

@ -0,0 +1,364 @@
<template>
<page-meta :page-style="'overflow:'+(ifShowPageMeta?'hidden':'visible')"></page-meta>
<view>
<!-- 顶部操作条 -->
<cu-custom :bgColor="'bg-main-color'" :isBack="true">
<block slot="backText">返回</block>
<block slot="content">接收的任务</block>
</cu-custom>
<view class="sticky-bar" :style="[{top: stickyTop + 'px'}]">
<!-- 条件筛选栏 -->
<view class="padding bg-white solid-bottom">
<view class="flex justify-start align-center">
<text class="margin-right-xs inline-lable">全部</text>
<!-- <my-uni-combox class="inline-combox margin-right-xs" :candidates="stateList" placeholder="请选择"
v-model="formData.state"></my-uni-combox>
<my-uni-combox class="inline-combox" :candidates="subStateList" placeholder="请选择"
v-model="formData.subState"></my-uni-combox> -->
<!-- 区域筛选picker -->
<picker class="inline-combox margin-right-xs" :mode="'multiSelector'" @change="regionChange" :value="areaMultiIndex" :range-key="'name'" :range="areaList">
<input class="radius-input" :value="formData.area ? formData.area[0].name + '-' + formData.area[1].name + '-' + formData.area[2].name : ''"
placeholder="请选择区域"></input>
</picker>
<!-- 品类筛选picker -->
<picker class="inline-combox" :mode="'multiSelector'" @change="categoryChange" :value="categoryMultiIndex" :range-key="'name'" :range="categoryList">
<input class="line-input radius-input" :value="formData.category ? formData.category[0].name + '-' + formData.category[1].name + '-' + formData.category[2].name : ''"
placeholder="请选择品类"></input>
</picker>
</view>
<view class="flex justify-between align-center margin-top-xs">
<input class="line-input radius-input margin-right-sm" v-model="formData.orderKeywords"
placeholder="请输入订单关键字"></input>
<view class="text-xl text-bold">
<text class="cuIcon-search margin-right-sm"></text>
<text class="cuIcon-refresh"></text>
</view>
</view>
</view>
<!-- 状态分类tab -->
<view class="cu-list grid no-border col-5 padding-top-sm bg-white">
<view class="cu-item" :class="stateCur === 0 ? 'bg-main-color light' : ''" :data-id="0" @tap="statusSelect">
<view class="margin-bottom-xs">超时单</view>
<view>({{myOrders.summary.overtimeOrderNum}})</view>
</view>
<view class="cu-item" :class="stateCur === 1 ? 'bg-main-color light' : ''" :data-id="1" @tap="statusSelect">
<view class="margin-bottom-xs">今日单</view>
<view>({{myOrders.summary.todayOrderNum}})</view>
</view>
<view class="cu-item" :class="stateCur === 2 ? 'bg-main-color light' : ''" :data-id="2" @tap="statusSelect">
<view class="margin-bottom-xs">明日单</view>
<view>({{myOrders.summary.tomorrowOrderNum}})</view>
</view>
<view class="cu-item" :class="stateCur === 3 ? 'bg-main-color light' : ''" :data-id="3" @tap="statusSelect">
<view class="margin-bottom-xs">急报单</view>
<view>({{myOrders.summary.urgentMsgOrderNum}})</view>
</view>
<view class="cu-item" :class="stateCur === 4 ? 'bg-main-color light' : ''" :data-id="4" @tap="statusSelect">
<view class="margin-bottom-xs">新订单</view>
<view>({{myOrders.summary.newOrderNum}})</view>
</view>
</view>
<!-- 子状态分类tab -->
<scroll-view scroll-x class="bg-white nav text-center" :scroll-with-animation="true" :scroll-left="scrollLeft">
<view class="cu-item" :class="index==tabCur?'text-main-color cur':''" v-for="(item,index) in subStateList"
:key="index" @tap="tabSelect" :data-id="index">
{{item.name}}
</view>
</scroll-view>
</view>
<!-- tab content -->
<view class="padding bg-white margin-top-sm margin-lr-sm" v-for="(order, index) in orderList">
<view class="flex justify-between">
<view class="text-lg text-bold text-cut">{{order.title}}</view>
<!-- 不同状态订单使用不同角标 -->
<view v-if="order.state === 'newOrder'" class="right-tag padding-lr-sm padding-tb-xs bg-cyan"></view>
<view v-else-if="order.subState === 'waitArrange'" class="right-tag padding-lr-sm padding-tb-xs bg-main-color"></view>
<view v-else-if="order.subState === 'waitToServ'" class="right-tag padding-lr-sm padding-tb-xs bg-yellow"></view>
<view v-else-if="order.subState === 'waitServing'" class="right-tag padding-lr-sm padding-tb-xs bg-purple"></view>
</view>
<view>
<view v-for="(tag, index1) in order.tags" v-if="tag.level === 'error'" class='cu-tag margin-right-xs radius line-red margin-top-xs'>{{tag.content}}</view>
<view v-else-if="tag.level === 'info'" class='cu-tag margin-right-xs radius line-main-color margin-top-xs'>{{tag.content}}</view>
</view>
<view class="margin-top-sm">
<text class="text-main-color text-lg margin-right-xs"><text class="cuIcon-people"></text></text>
<text>姓名{{order.name}}</text>
</view>
<view class="margin-top-sm">
<text class="text-main-color text-lg margin-right-xs"><text class="cuIcon-location"></text></text>
<text class="margin-right-xs">{{order.address}}</text>
<text class="text-lg" @tap="copyData(order.address)"><text class="cuIcon-copy"></text></text>
</view>
<view class="margin-top-sm" v-if="Boolean(order.doorTime)">
<text class="text-main-color text-lg margin-right-xs"><text class="cuIcon-time"></text></text>
<text>上门时间{{order.doorTime}}</text>
</view>
<view class="margin-top-sm" v-else-if="Boolean(order.servTime)">
<text class="text-main-color text-lg margin-right-xs"><text class="cuIcon-time"></text></text>
<text>服务时间{{order.servTime}}</text>
</view>
<view class="margin-top-sm flex justify-start align-center" v-if="order.subState === 'waitToServ'">
<text class="text-main-color text-lg margin-right-xs"><text class="cuIcon-repair"></text></text>
<text>距上门</text>
<uni-countdown :show-colon="false" :backgroundColor="'#eee'"
:day="$dateUtil.countDownDiff(order.deadlineDate).day"
:hour="$dateUtil.countDownDiff(order.deadlineDate).hour"
:minute="$dateUtil.countDownDiff(order.deadlineDate).min"
:second="$dateUtil.countDownDiff(order.deadlineDate).seconds">
</uni-countdown>
</view>
<!-- 不同状态订单支持不同操作按钮 -->
<view v-if="order.state === 'newOrder'">
<button class="cu-btn bg-main-color margin-right-xs shadow-blur margin-top-sm" data-popup="dispatchOrder" @tap="togglePopup($event, index)">派单</button>
<button class="cu-btn bg-main-color margin-right-xs shadow-blur margin-top-sm">改价</button>
<button class="cu-btn bg-main-color margin-right-xs shadow-blur margin-top-sm">转发</button>
<button class="cu-btn bg-main-color margin-right-xs shadow-blur margin-top-sm">确认接单</button>
</view>
<view v-if="order.subState === 'waitArrange'">
<button class="cu-btn bg-main-color margin-right-xs shadow-blur margin-top-sm" data-popup="dispatchOrder" @tap="togglePopup($event, index)">派单</button>
<button class="cu-btn bg-main-color margin-right-xs shadow-blur margin-top-sm" data-modal="showTimeArrangeModal" @tap="showModal($event, index)">预约时间</button>
</view>
<view v-if="order.subState === 'waitToServ'">
<button class="cu-btn bg-main-color margin-right-xs shadow-blur margin-top-sm" @click="makePhoneCall(order.phoneNum)">联系客户</button>
<button class="cu-btn bg-main-color margin-right-xs shadow-blur margin-top-sm">修改时间</button>
<button class="cu-btn bg-main-color margin-right-xs shadow-blur margin-top-sm">立即上门</button>
</view>
<view v-if="order.subState === 'waitServing'">
<button class="cu-btn bg-main-color margin-right-xs shadow-blur margin-top-sm">改价</button>
<button class="cu-btn bg-main-color margin-right-xs shadow-blur margin-top-sm" @click="makePhoneCall(order.phoneNum)">联系客户</button>
<button class="cu-btn bg-main-color margin-right-xs shadow-blur margin-top-sm">修改时间</button>
<button class="cu-btn bg-main-color margin-right-xs shadow-blur margin-top-sm">拍照回单</button>
<button class="cu-btn bg-main-color margin-right-xs shadow-blur margin-top-sm">生成付款码</button>
</view>
<view class="margin-top-sm solid-top padding-top-sm" v-if="Boolean(order.comments)">
<text class="text-main-color text-lg margin-right-xs"><text class="cuIcon-comment"></text></text>
<text>备注{{order.comments}}</text>
</view>
</view>
<!-- 模态框 -->
<time-arrange :show="showTimeArrangeModal" :data="curOrder"></time-arrange>
<time-arrange-fail :show="showArrangeFailTimeModal" :data="curOrder"></time-arrange-fail>
<!-- popup -->
<uni-popup ref="dispatchOrder" type="bottom" @change="changePopupState">
<view class="text-bold text-gray text-lg text-center left-top-sm-bar" data-popup="dispatchOrder" @click="togglePopup"><text
class="cuIcon-close"></text></view>
<view class="bg-white padding" style="padding-top: 74rpx;">
<dispatch-order :columnTitleArr="['购买机型', '待派单', '派单量']" :singleServ="curOrder && curOrder.product.pickedList.length === 1 ? true : false"
:product="curOrder.product" :pickedList="curOrder.product.pickedList" :members="myTeamMembers"></dispatch-order>
</view>
<!-- 底部占位 -->
<view class="cu-bar bg-white fixed-bottom-bar"></view>
</uni-popup>
</view>
</template>
<script>
import myUniCombox from '@/components/uni-combox/my-uni-combox.vue';
import timeArrange from '@/pages/order-manage/modal/time-arrange.vue';
import timeArrangeFail from '@/pages/order-manage/modal/time-arrange-fail.vue';
import dispatchOrder from '@/pages/order-manage/dispatch-order.vue';
export default {
components: {
myUniCombox,
timeArrange,
timeArrangeFail,
dispatchOrder
},
data() {
return {
formData: {
category: null,
area: null,
orderKeywords: ''
},
areaList: [],
areaMultiIndex: [0, 0, 0],
categoryList: [],
categoryMultiIndex: [0, 0, 0],
// stateList: [{
// code: 1,
// name: ''
// }, {
// code: 2,
// name: ''
// }, {
// code: 3,
// name: ''
// }, {
// code: 4,
// name: ''
// }, {
// code: 5,
// name: ''
// }],
subStateList: [{
code: 1,
name: '未约/未排'
}, {
code: 2,
name: '待上门'
}, {
code: 3,
name: '服务中'
}, {
code: 4,
name: '确认中'
}, {
code: 5,
name: '售后中'
}, {
code: 6,
name: '已完成'
}],
myOrders: {},
orderList: [],
curOrder: {},
myTeamMembers: [],
scrollLeft: 0,
stickyTop: this.CustomBar,
tabCur: 0,
stateCur: 0,
showTimeArrangeModal: false,
showArrangeFailTimeModal: false,
ifShowPageMeta: false
}
},
onLoad() {
this.loadData();
this.bindEvent();
},
onUnload() {
this.offBindEvent();
},
methods: {
async loadData() {
let myTeamInfo = await this.$api.data('myTeamInfo');
this.myTeamMembers = myTeamInfo.members;
this.myOrders = await this.$api.data('myOrders');
this.orderList = this.myOrders.orderList;
this.areaList = await this.$api.data('areaList');
this.categoryList = await this.$api.data('categoryList');
},
bindEvent() {
uni.$on(this.$globalFun.SHOW_ARRANGE_FAIL_TIME, this.showArrangeFailTime);
uni.$on(this.$globalFun.HIDE_MODAL, this.hideModal);
uni.$on(this.$globalFun.SUBMIT_FAIL_REASON, this.submitFailReason);
},
offBindEvent() {
uni.$off(this.$globalFun.SHOW_ARRANGE_FAIL_TIME);
uni.$off(this.$globalFun.HIDE_MODAL);
uni.$off(this.$globalFun.SUBMIT_FAIL_REASON);
},
regionChange(e) {
this.areaMultiIndex = e.detail.value;
let chosenArea = [];
for(let i = 0; i < this.areaList.length; i++) {
chosenArea.push(this.areaList[i][this.areaMultiIndex[i]]);
}
this.formData.area = chosenArea;
},
categoryChange(e) {
this.categoryMultiIndex = e.detail.value;
let chosenCategory = [];
for(let i = 0; i < this.categoryList.length; i++) {
chosenCategory.push(this.categoryList[i][this.categoryMultiIndex[i]]);
}
this.formData.category = chosenCategory;
},
input(e) {
console.log(e)
console.log(this.formData)
},
tabSelect(e) {
this.tabCur = e.currentTarget.dataset.id;
this.scrollLeft = (e.currentTarget.dataset.id - 1) * 60
this.loadData(this.stateCur, this.subStateList[this.tabCur].code);
},
statusSelect(e) {
this.stateCur = e.currentTarget.dataset.id;
this.loadData(this.stateCur, this.subStateList[this.tabCur].code);
},
setCurOrder(orderIndex) {
this.curOrder = this.orderList[orderIndex];
},
showModal(e, orderIndex) {
if (orderIndex != null && orderIndex != undefined) {
this.setCurOrder(orderIndex);
}
this[e.currentTarget.dataset.modal] = true;
},
hideModal(e) {
this.curOrder = null;
this[e.currentTarget.dataset.modal] = false;
},
copyData(data) {
uni.setClipboardData({
data: data
});
},
showArrangeFailTime(e) {
this.showTimeArrangeModal = false;
this.showArrangeFailTimeModal = true;
},
submitFailReason(e, reasonObj) {
// TODO: modalcurOrdernull
this.hideModal(e);
},
togglePopup(e, orderIndex) {
if (this.ifShowPageMeta) {
this.$refs[e.currentTarget.dataset.popup].close();
let timeout = setTimeout(() => {
this.curOrder = null;
}, 100);
} else {
if (orderIndex != null && orderIndex != undefined) {
this.setCurOrder(orderIndex);
}
this.$refs[e.currentTarget.dataset.popup].open();
}
},
changePopupState(e) {
this.ifShowPageMeta = e.show;
},
makePhoneCall(phoneNum) {
uni.makePhoneCall({
phoneNumber: phoneNum
})
},
}
}
</script>
<style scoped>
.inline-combox {
display: inline-block;
width: calc((90vw - 80rpx)/2);
}
.cu-list.grid.no-border {
padding: unset;
}
.cu-list.grid.no-border>.cu-item {
padding-top: 20rpx;
padding-bottom: 20rpx;
}
.right-tag {
position: relative;
right: -30rpx;
border-radius: 40rpx 0 0 40rpx;
}
.cu-tag+.cu-tag {
margin-left: unset;
}
.left-top-sm-bar {
position: absolute;
right: 25rpx;
top: 25rpx;
z-index: 99;
}
</style>

View File

@ -232,7 +232,7 @@
.radius-input {
border: 1rpx solid rgba(0, 0, 0, 0.1);
border-radius: 10rpx;
padding: 10rpx;
padding: 11rpx;
box-sizing: content-box;
}
@ -244,3 +244,11 @@
.big-icon {
font-size: 111rpx !important;
}
.line-input {
width: 100%;
}
.align-baseline {
align-items: baseline !important;
}