aircraft-pilot/aircraft/server/order/add.vue
2025-08-13 09:10:53 +08:00

519 lines
17 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="order-add">
<Topnav :topLevel="1" :title="`${form.orderId?'订单详情':'新增订单'}`" defaultBackColor="#333333"
defaultNavTextColor="#333333" showBack :fixed="false" />
<view class="order-form">
<view class="order-delete" v-if="canDelete">
<u-icon name="trash" color="#333" size="46" @click="handleDelete"/>
</view>
<view class="order-field">
<u-form ref="uForm" :model="form" label-position="top"
:label-style="{fontFamily: 'PingFang SC, PingFang SC',
fontWeight: 'bold',fontSize: '32rpx',color: '#000000'}">
<u-form-item v-if="form.orderId" label="订单号:" :border-bottom="false">
<u-input disabled class="field-ninput" placeholder="订单号" v-model="form.orderNo" />
</u-form-item>
<u-form-item label="订单类型:" :border-bottom="false">
<u-input style="opacity: 0.8;" class="field-input" placeholder="请选择订单类型" v-model="form.orderTypeName" type="select" disabled/>
</u-form-item>
<u-form-item v-if="form.orderId" label="订单发起人:" :border-bottom="false">
<u-input disabled class="field-ninput" placeholder="订单发起人" v-model="form.orderInitiator" />
</u-form-item>
<u-form-item prop="customerName" required label="客户名称:" :border-bottom="false">
<u-input class="field-input" placeholder="请选择客户" v-model="form.customerName"
type="select" @click="handleSelectScenOrCus('客户')"/>
</u-form-item>
<u-form-item prop="phone" required label="手机号码:" :border-bottom="false">
<u-input class="field-input" placeholder="请选择客户" v-model.number="form.phone"
type="select" @click="handleSelectScenOrCus('客户')" />
</u-form-item>
<u-form-item prop="attractionName" label="景区:" required :border-bottom="false">
<u-input class="field-input" placeholder="请选择景区" v-model="form.attractionName"
@click="handleSelectScenOrCus('景区')" type="select"/>
</u-form-item>
<u-form-item prop="routeIds" label="路线:" required :border-bottom="false">
<!-- <u-input class="field-input" placeholder="请选择路线" v-model="form.routeIds"
type="select"/> -->
<w-select class="field-w-select" v-model="form.routeIds" multiple
:list="routes" valueName="value" keyName="key" @change="changeRoute"
placeholder="请选择路线" width="100%" bgColor="#f8f9fb">
</w-select>
</u-form-item>
<u-form-item prop="cargoWeight" required label="货物重量:" :border-bottom="false">
<u-input class="field-ninput" type="number" placeholder="请输入货物重量(最多保留两位小数)" v-model.number="form.cargoWeight" />
<view slot="right" class="field-input-right">KG</view>
</u-form-item>
<u-form-item prop="surchargeAmount" label="附加费:" :border-bottom="false">
<u-input type="number" class="field-ninput" placeholder="请输入附加费(最多保留两位小数)" v-model.number="form.surchargeAmount" />
<view slot="right" class="field-input-right">元</view>
</u-form-item>
<u-form-item prop="operatorIds" label="操作员:" required :border-bottom="false">
<w-select class="field-w-select" v-model="form.operatorIds" multiple
:list="operators" valueName="name" keyName="id"
placeholder="请选择操作员" width="100%" bgColor="#f8f9fb">
</w-select>
</u-form-item>
<u-form-item v-if="form.orderId" label="下单时间:" :border-bottom="false">
<u-input disabled class="field-ninput" placeholder="下单时间" v-model="form.orderCreateTime" />
</u-form-item>
<u-form-item v-if="form.orderId" :label="`订单确认人${ ['未进行','已取消'].includes(form.mainOrderStatus)
?'':(form.mainOrderStatus==='已完成'?'(已确认)':'(待确认)')}`" :border-bottom="false">
<u-input disabled class="field-ninput" placeholder="订单确认人" v-model="form.customerName" />
</u-form-item>
<view class="field-btns" v-if="(!form.orderInitiatorId||form.orderInitiatorId===userMessage.id)&&
(!form.mainOrderStatus||form.mainOrderStatus!=='已完成'||form.mainOrderStatus!=='已取消')">
<u-button type="warning" :custom-style="customStyle" style="width: 100%;" v-if="!isDisable"
:hair-line="false" @click="saveOrder" :loading="saveLoading">保存</u-button>
<u-button :style="{marginLeft: isDisable?'0rpx':'30rpx',width: '100%'}" type="warning"
v-if="canFinish" :custom-style="customStyle" :hair-line="false" @click="finishOrder">
完成订单
</u-button>
</view>
</u-form>
</view>
</view>
<u-picker mode="selector" v-model="showScenOrCus" :range="scenOrCusType==='景区'?scenics:customers"
:default-selector="getDefaultSelector" range-key="name" confirm-color="#f7c04d"
:title="scenOrCusType+'选择'" @confirm="handleConfirmScenOrCus"/>
<u-toast ref="uToast"></u-toast>
</view>
</template>
<script>
import Topnav from '@/components/topnav/index.vue';
import configService from '@/common/config.service.js';
import WSelect from '@/components/w-select/w-select.vue';
export default {
// #ifdef MP
options: {
styleIsolation: 'shared'
},
// #endif
components: { Topnav, WSelect },
data(){
return{
// #ifdef MP
// 微信小程序自定义导航栏参数
CustomBar: this.CustomBar || 0,
// #endif
// 订单类型
form:{
orderId: '',
orderType: 1,
orderTypeName: '载物订单',
customerName: '',
customerId: '',
phone: '',
attractionName: '',
attractionId: '',
surchargeAmount:'',
cargoWeight: '',
operatorIds: [],
routeIds: []
},
// 订单类型
orderTypes:[],
// 校验规则
rules:{
customerName: [{
required: true,
message: '请选择客户',
trigger: ['change','blur']
}],
phone: [{
required: true,
message: '请选择客户',
trigger: ['change','blur']
}],
attractionName: [{
required: true,
message: '请选择景区',
trigger: ['change','blur']
}],
cargoWeight: [{
// 自定义验证函数,见上说明
validator: (rule, value, callback) => {
return this.$u.test.amount(value);
},
message: '货物重量格式不正确',
// 触发器可以同时用blur和change
trigger: ['change','blur'],
}],
surchargeAmount: [{
validator: (rule, value, callback) => {
return value===''||/^-?\d*\.?\d+$/.test(value);
},
message: '附加费格式不正确',
trigger: ['change','blur']
}],
routeIds: [{
// 自定义验证函数,见上说明
validator: (rule, value, callback) => {
return value&&value.length>0;
},
message: '请至少选择一条路线',
// 触发器可以同时用blur和change
trigger: ['change','blur'],
}],
operatorIds: [{
// 自定义验证函数,见上说明
validator: (rule, value, callback) => {
return value&&value.length>0;
},
message: '请至少选择一位操作员',
// 触发器可以同时用blur和change
trigger: ['change','blur'],
}],
},
// 执行任务按钮样式
customStyle: {
backgroundColor: '#FEE547',
color: '#333333',
fontSize: '30rpx',
fontWeight: 'bold',
fontFamily: 'Source Han Sans SC',
padding: '20rpx 0',
borderRadius: '12rpx',
border: 'none'
},
// 景区列表
scenics: [],
// 客户列表
customers: [],
// 操作员列表
operators: [],
// 路线列表
routes: [],
// 保存加载
saveLoading: false,
// 用户信息
userMessage: this.$store.state.vuex_token === ''?{}:JSON.parse(this.$store.state.user_message),
isPilot: this.$store.state.user_type == 1,
// 景区/客户选择弹窗
showScenOrCus: false,
// 当前景区/客户选择类型
scenOrCusType: '',
// 订单状态
orderStatus: ['进行中','已完成','已取消','待确认'],
}
},
onReady() {
this.$refs.uForm.setRules(this.rules);
},
computed:{
// 获取选择器默认值
getDefaultSelector(){
const isScen = this.scenOrCusType === '景区';
const arr = isScen ? this.scenics : this.customers;
const index = this.form[isScen?'attractionId':'customerId'];
return index?[arr.findIndex(item=>item.id === index)]:[0];
},
// 判断是否可以完成订单
canFinish(){
/*
1.编辑
2.订单状态不处于已完成、已取消、未进行、飞行员-待确认
3.飞行员-订单发起人||客户-确认人
4.不存在飞行任务为未进行或进行中的状态
*/
const { orderId, mainOrderStatus, orderTaskDetailList, orderInitiatorId, customerId } = this.form;
return orderId&&(!mainOrderStatus||mainOrderStatus!=='未进行')&&
(this.isPilot&&orderInitiatorId==this.userMessage.id&&mainOrderStatus!=='待确认'||
!this.isPilot&&customerId==userMessage.id)&&(!orderTaskDetailList||
orderTaskDetailList.some(item=>item.orderItemStatus!=='未进行'&&item.orderItemStatus!=='进行中'));
},
// 判断是否可以删除
canDelete(){
const { orderId, orderInitiatorId, mainOrderStatus, orderTaskDetailList } = this.form;
return orderId&&this.isPilot&&orderInitiatorId==this.userMessage.id
&&(!mainOrderStatus||mainOrderStatus==='未进行')&&(!orderTaskDetailList||orderTaskDetailList.length===0);
},
// 判断是否禁用保存
isDisable(){
/*
1.订单状态不处于已完成、已取消
2.存在飞行任务为进行中、已完成、已取消、待确认状态
*/
const { orderTaskDetailList } = this.form;
return orderTaskDetailList&&orderTaskDetailList.length>0;
}
},
onLoad(e) {
this.form.orderId = e.id || '';
this.init();
},
methods: {
// 初始化
async init(){
// 获取客户列表
let cusRes = await this.$api.allCustomers();
if(!cusRes){
this.$refs.uToast.show({type: 'error',title: "客户获取失败!"});
}else{
this.customers = cusRes || [];
}
// 获取负责区域的景区列表
let selfRes = await this.$api.aSelfDetail(this.userMessage.id);
if(!selfRes){
this.$refs.uToast.show({type: 'error',title: "个人信息获取失败!"});
}else{
if(selfRes.areaId){
let scenRes = await this.$api.allScenicsByAreaId({areaId: selfRes.areaId});
// 获取操作员列表
let opeRes = await this.$api.allEmployees({areaId: selfRes.areaId});
this.scenics = scenRes || [];
this.operators = opeRes || [];
}
}
// 获取订单详情
if(this.form.orderId) this.getOrderDetail();
else {
const userId = this.userMessage.id;
const op = this.operators.find(item=>item.id===userId);
if(op){
this.form.operatorIds.push(op);
this.operators = this.operators.filter(item=>item.id!==userId);
}
}
},
// 获取订单详情
async getOrderDetail(){
let res = await this.$api.orderDetail(this.form.orderId);
if(res){
const { id, customerName, phone, scenicName, surchargeAmount, cargoWeight,
orderNo, orderCreateTime, orderInitiator, orderInitiatorId, mainOrderStatus,
customerId, attractionId, routeIds, operatorIds, orderTaskDetailList } = res;
this.form = {
orderId: id,
orderNo: orderNo,
orderType: 1,
orderTypeName: '载物订单',
customerName: customerName,
customerId: customerId,//
phone: phone,
attractionName: scenicName,
attractionId: attractionId,//
surchargeAmount: surchargeAmount,
cargoWeight: cargoWeight,
operatorIds: [],
routeIds: [],
orderInitiator: orderInitiator,
orderCreateTime: orderCreateTime,
orderInitiatorId: orderInitiatorId,
orderTaskDetailList: orderTaskDetailList,
mainOrderStatus: mainOrderStatus
}
let resp = await this.$api.allRoutesByScenicId(attractionId);
if(resp){
this.routes = resp || [];
this.form.routeIds = resp.filter(item=> routeIds.includes(item.key));
this.form.operatorIds = this.operators.filter(item=> operatorIds.includes(item.id));
this.operators = this.operators.filter(item=>item.id!==orderInitiatorId);
} else {
this.$refs.uToast.show({type: 'error',title: "景区路线获取失败!"});
}
} else
this.$refs.uToast.show({type: 'error',title: "订单详情获取失败!"});
},
// 删除订单
handleDelete(){
let that = this;
uni.showModal({
title: '提示',
content: '是否确认删除该订单?',
confirmColor: '#FE020E',
success: async(res) => {
if (res.confirm) {
try {
let res = await that.$api.deleteOrder(that.form.orderId);
if(res === undefined){
that.$refs.uToast.show({type: 'error',title: "订单详删除失败!"});
return;
}
uni.navigateBack({complete() {
that.$u.toast('订单删除成功!');
}})
} catch (error) {
that.$refs.uToast.show({type: 'error',title: "订单详删除失败!"});
}
}
}
})
},
// 选择路线
changeRoute(e){
},
// 点击打开景区/客户选择弹窗
handleSelectScenOrCus(type){
this.scenOrCusType = type;
this.showScenOrCus = true;
},
// 选择景区
async handleConfirmScenOrCus(index){
if(this.scenOrCusType === '景区'){
const val = this.scenics[index[0]];
this.form.attractionName = val.name;
this.form.attractionId = val.id;
this.form.routeIds = [];
let res = await this.$api.allRoutesByScenicId(val.id);
if(res){
this.routes = res || [];
this.form.routeIds = res.length>0?[res[0]]:[];
}else{
this.$refs.uToast.show({type: 'error',title: "景区路线获取失败!"});
}
}else{
const val = this.customers[index[0]];
this.form.customerId = val.id;
this.form.customerName = val.name;
this.form.phone = val.phone;
}
},
// 订单保存
saveOrder(){
try{
let that = this;
this.$refs.uForm.validate(async(valid) => {
if (valid) {
that.saveLoading = true;
const data = {...that.form,operatorIds:that.form.operatorIds.map(item=>item.id),
routeIds:that.form.routeIds.map(item=>item.key),
surchargeAmount: that.form.surchargeAmount ? that.form.surchargeAmount : 0,
orderCreateTime:that.$u.timeFormat(new Date().getTime(),'yyyy-mm-dd hh:MM:ss')}
console.log('验证通过',that.form);
let res = that.form.orderId ? await that.$api.editOrder(data) : await that.$api.addOrder(data);
console.log('res:',res);
if(res === undefined){
that.$refs.uToast.show({type: 'error',title: "订单新增失败!"});
return;
}
that.saveLoading = false;
uni.navigateBack({complete() {
that.$u.toast(`订单${that.form.orderId?'编辑':'新增'}成功!`);
}})
}else{
that.saveLoading = false;
}
});
}catch(e){
this.saveLoading = false;
this.$refs.uToast.show({type: 'error',title: "订单新增失败!"});
}
},
// 完成订单
async finishOrder(){
let that = this;
if(!this.form.orderTaskDetailList || this.form.orderTaskDetailList.length === 0){
this.$refs.uToast.show({type: 'warning',title: "该订单不存在飞行任务,无法完成!"});
return;
}
uni.showModal({
title: '订单完成',
content: '是否确认完成该订单?',
confirmColor: '#f7c04d',
success: async(res) => {
if (res.confirm) {
try {
let res = await that.$api.completeOrder(that.form.orderId);
if(res === undefined){
that.$refs.uToast.show({type: 'error',title: "订单完成操作失败!"});
return;
}
that.$refs.uToast.show({type: 'success', title: `订单完成操作成功!`});
that.init();
} catch (error) {
that.$refs.uToast.show({type: 'error', title: `订单完成操作失败!`});
}
}
}
})
},
}
}
</script>
<style scoped lang="scss">
.order-add{
display: flex;
flex-direction: column;
min-height: 100vh;
position: relative;
.order-delete{
position: absolute;
right: 50rpx;
z-index: 1;
&:active{
opacity: 0.7;
}
}
.order-form{
padding: 30rpx 32rpx 52rpx;
display: flex;
flex-direction: column;
.order-field{
&::v-deep .u-form-item--left__content--required{
font-family: PingFang SC, PingFang SC;
font-weight: bold;
font-size: 32rpx;
color: #FE020E;
margin-right: 8rpx !important;
}
&::v-deep .u-input{
padding: 12rpx 32rpx !important;
font-family: PingFang SC, PingFang SC;
font-weight: bold;
font-size: 32rpx;
line-height: 40rpx;
background: #F8F9FB;
border-radius: 4rpx;
}
.field-ninput{
&::v-deep .u-input{
padding: 12rpx 80rpx 12rpx 32rpx !important;
}
}
.field-w-select{
&::v-deep .w-select{
.select-wrap{
border: none !important;
min-height: var(--select-wrap-height);
height: inherit;
}
padding: 12rpx 32rpx !important;
background: #F8F9FB;
border-radius: 4rpx;
}
&::v-deep .select-options{
.item-active{
color: #f7c04d !important;
background-color: #f5f5f5 !important;
}
}
&::v-deep .select-content-item-default{
margin-left: 0 !important;
margin-right: 0 !important;
font-size: 28rpx;
line-height: 40rpx;
color: #c0c4cc;
}
}
.field-input-right{
font-family: Source Han Sans SC;
font-weight: bold;
font-size: 32rpx;
color: #333333;
margin-left: -80rpx;
z-index: 1;
}
.field-btns{
width: 100%;
margin-top: auto;
margin-bottom: 30rpx;
padding-top: 30rpx;
display: flex;
align-items: center;
}
}
}
}
</style>