553 lines
11 KiB
Vue
553 lines
11 KiB
Vue
<script lang="ts" setup>
|
||
import { executeCommandAPI } from '@/api/centerControl'
|
||
import { createChangeOrderAPI, createDispatchOrderAPI } from '@/api/operator'
|
||
import { getBatteryColor } from '@/utils/car'
|
||
|
||
const props = defineProps({
|
||
data: {
|
||
type: Object,
|
||
default: () => ({}),
|
||
},
|
||
tabType: {
|
||
type: String,
|
||
default: '',
|
||
},
|
||
})
|
||
const emits = defineEmits(['close'])
|
||
const btnType = ref('')
|
||
const carDetail = ref<any>({
|
||
bikeCode: '',
|
||
distance: '',
|
||
soc: 0,
|
||
})
|
||
const ActionSheetList = ref([
|
||
{
|
||
name: '换单工单',
|
||
key: 'hasChangeBatteryOrder',
|
||
disabled: false,
|
||
loading: false,
|
||
},
|
||
{
|
||
name: '调度工单',
|
||
key: 'hasDispatchOrder',
|
||
disabled: false,
|
||
loading: false,
|
||
},
|
||
{
|
||
name: '巡检工单',
|
||
key: 'hasInspectionOrder',
|
||
disabled: false,
|
||
loading: false,
|
||
},
|
||
])
|
||
const actionSheet = ref<any>(null)
|
||
const btnNum = ref(3)
|
||
const customStyle = computed(() => {
|
||
return {
|
||
background: '#e4f7fe',
|
||
color: '#0a84f9',
|
||
border: 'none',
|
||
height: '30px',
|
||
fontSize: '26rpx',
|
||
}
|
||
})
|
||
const btnCustomStyle = computed(() => {
|
||
return {
|
||
width: `${320 / btnNum.value}px`,
|
||
height: '35px',
|
||
border: 'none',
|
||
borderRadius: '8px',
|
||
}
|
||
})
|
||
const btnCustomStyle2 = computed(() => {
|
||
return {
|
||
width: `${320 / btnNum.value}px`,
|
||
height: '35px',
|
||
borderRadius: '8px',
|
||
border: 'none',
|
||
background: '#eeeeee',
|
||
color: '#4a4a4a',
|
||
}
|
||
})
|
||
// 测试项列表
|
||
const list = reactive({
|
||
findBike: {
|
||
msg: '',
|
||
name: '寻车铃',
|
||
key: 'FIND_BIKE',
|
||
status: 'none', // none,loading,success,fail
|
||
tip: '',
|
||
btnText: '执行',
|
||
btnLoadingText: '执行中',
|
||
btnLoading: false,
|
||
},
|
||
gps: {
|
||
msg: '',
|
||
name: 'gps测试',
|
||
key: 'GPS',
|
||
status: 'none',
|
||
tip: '',
|
||
btnText: '执行',
|
||
btnLoadingText: '执行中',
|
||
btnLoading: false,
|
||
},
|
||
openLock: {
|
||
msg: '',
|
||
name: '打开电池锁',
|
||
key: 'OPEN_BATTERY_LOCK',
|
||
status: 'none',
|
||
tip: '',
|
||
btnText: '执行',
|
||
btnLoadingText: '执行中',
|
||
btnLoading: false,
|
||
},
|
||
resetBattery: {
|
||
msg: '',
|
||
name: '复位电池仓锁',
|
||
key: 'CLOSE_BATTERY_LOCK',
|
||
status: 'none',
|
||
tip: '',
|
||
btnText: '执行',
|
||
btnLoadingText: '执行中',
|
||
btnLoading: false,
|
||
},
|
||
unlocking: {
|
||
msg: '',
|
||
name: '开锁',
|
||
key: 'UNLOCK',
|
||
status: 'none',
|
||
tip: '',
|
||
btnText: '执行',
|
||
btnLoadingText: '执行中',
|
||
btnLoading: false,
|
||
},
|
||
Locking: {
|
||
msg: '',
|
||
name: '关锁',
|
||
key: 'LOCK',
|
||
status: 'none',
|
||
tip: '',
|
||
btnText: '执行',
|
||
btnLoadingText: '执行中',
|
||
btnLoading: false,
|
||
},
|
||
openHelmet: {
|
||
msg: '',
|
||
name: '打开头盔锁',
|
||
key: 'OPEN_HELMET',
|
||
status: 'none',
|
||
tip: '',
|
||
btnText: '执行',
|
||
btnLoadingText: '执行中',
|
||
btnLoading: false,
|
||
},
|
||
offPower: {
|
||
msg: '',
|
||
name: '断电',
|
||
key: 'POWER_OFF',
|
||
status: 'none',
|
||
tip: '',
|
||
btnText: '执行',
|
||
btnLoadingText: '执行中',
|
||
btnLoading: false,
|
||
},
|
||
})
|
||
|
||
// 执行按钮点击
|
||
async function handleBtnClick(value: any, key: string) {
|
||
uni.showLoading({
|
||
title: '执行中...',
|
||
})
|
||
list[key].btnLoading = true
|
||
try {
|
||
const result: boolean = await executeCommandAPI({
|
||
bikeCode: carDetail.value.bikeCode,
|
||
commandCode: value,
|
||
})
|
||
if (result) {
|
||
uni.showToast({
|
||
title: '执行成功',
|
||
icon: 'success',
|
||
})
|
||
}
|
||
else {
|
||
uni.showToast({
|
||
title: '执行失败',
|
||
icon: 'error',
|
||
})
|
||
}
|
||
}
|
||
catch (e) {
|
||
uni.showToast({
|
||
title: '执行异常',
|
||
icon: 'error',
|
||
})
|
||
}
|
||
finally {
|
||
uni.hideLoading()
|
||
list[key].btnLoading = false
|
||
}
|
||
}
|
||
|
||
// 详情
|
||
function handleDetail() {
|
||
uni.navigateTo({
|
||
url: `/pages-sub/common/carDetail?bikeCode=${carDetail.value.bikeCode}`,
|
||
})
|
||
}
|
||
|
||
// 跳转到换电
|
||
function completeChangeBattery() {
|
||
setTimeout(() => {
|
||
uni.navigateTo({
|
||
url: `/pages-sub/changebatteries/changebatteries?bikeCode=${carDetail.value.bikeCode}`,
|
||
})
|
||
}, 100)
|
||
}
|
||
|
||
// 关闭
|
||
function handleClose() {
|
||
emits('close')
|
||
}
|
||
|
||
// 按钮
|
||
function handleBtnConfig(res: any) {
|
||
ActionSheetList.value = ActionSheetList.value.map(item => ({
|
||
...item,
|
||
disabled: res[item.key],
|
||
}))
|
||
}
|
||
|
||
// 生成工单
|
||
function generateWorkOrder() {
|
||
actionSheet.value?.open()
|
||
}
|
||
|
||
// 工单选择
|
||
async function ActionSheetSelect(e: any) {
|
||
const { key } = e
|
||
ActionSheetList.value.forEach((item) => {
|
||
if (item.key === key) {
|
||
item.loading = true
|
||
}
|
||
})
|
||
switch (key) {
|
||
case 'hasInspectionOrder':
|
||
break
|
||
case 'hasChangeBatteryOrder':
|
||
createChangeOrder(key)
|
||
break
|
||
case 'hasDispatchOrder':
|
||
createDispatchOrder(key)
|
||
break
|
||
case 'hasRepairOrder':
|
||
|
||
break
|
||
}
|
||
}
|
||
|
||
async function createChangeOrder(key: string) {
|
||
try {
|
||
const res = await createChangeOrderAPI(carDetail.value.ecuSn)
|
||
uni.showToast({
|
||
title: '工单创建成功',
|
||
icon: 'success',
|
||
})
|
||
ActionSheetList.value.forEach((item) => {
|
||
if (item.key === key) {
|
||
item.loading = false
|
||
item.disabled = false
|
||
}
|
||
})
|
||
actionSheet.value?.close()
|
||
}
|
||
catch (err) {
|
||
console.error(err)
|
||
ActionSheetList.value.forEach((item) => {
|
||
if (item.key === key) {
|
||
item.loading = false
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
async function createDispatchOrder(key: string) {
|
||
try {
|
||
const res = await createDispatchOrderAPI(carDetail.value.bikeCode)
|
||
uni.showToast({
|
||
title: '工单创建成功',
|
||
icon: 'success',
|
||
})
|
||
ActionSheetList.value.forEach((item) => {
|
||
if (item.key === key) {
|
||
item.loading = false
|
||
item.disabled = false
|
||
}
|
||
})
|
||
actionSheet.value?.close()
|
||
}
|
||
catch (err) {
|
||
console.error(err)
|
||
ActionSheetList.value.forEach((item) => {
|
||
if (item.key === key) {
|
||
item.loading = false
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
watch(() => props.data, (newVal) => {
|
||
carDetail.value = newVal
|
||
}, { deep: true })
|
||
|
||
watch(() => props.tabType, (newVal) => {
|
||
btnType.value = newVal
|
||
console.log(newVal, 'tabType')
|
||
switch (newVal) {
|
||
case 'charge':
|
||
btnNum.value = 3
|
||
break
|
||
case 'dispatch':
|
||
btnNum.value = 3
|
||
break
|
||
case 'none':
|
||
btnNum.value = 2
|
||
break
|
||
default:
|
||
btnNum.value = 3
|
||
break
|
||
}
|
||
}, { immediate: true })
|
||
|
||
defineExpose({
|
||
handleBtnConfig,
|
||
})
|
||
</script>
|
||
|
||
<template>
|
||
<view class="container">
|
||
<!-- 关闭按钮 -->
|
||
<view class="close_icon" @click="handleClose">
|
||
<uv-icon name="close" color="#ffffff" size="14" />
|
||
</view>
|
||
<!-- 车辆信息-标题 -->
|
||
<view class="car_info_title">
|
||
<view class="title">
|
||
{{ carDetail.bikeCode || '--' }}
|
||
</view>
|
||
<scroll-view
|
||
class="tags_bar"
|
||
:scroll-x="true"
|
||
:scroll-with-animation="true"
|
||
:style="{ 'white-space': 'nowrap' }"
|
||
>
|
||
<view
|
||
class="tag"
|
||
:style="{
|
||
background: carDetail.online ? '#00c854' : '#e93b40',
|
||
}"
|
||
>
|
||
{{ carDetail.online ? '在线' : '离线' }}
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
<!-- 车辆信息-电量刷新 -->
|
||
<view class="electric_time">
|
||
电量刷新时间:{{ '--' }}
|
||
</view>
|
||
<!-- 车辆信息-距离 -->
|
||
<view class="distance">
|
||
<view class="distance_left">
|
||
<view class="electric">
|
||
<uv-icon
|
||
:name="getBatteryColor({
|
||
soc: carDetail.soc,
|
||
}).icon"
|
||
custom-prefix="custom-icon"
|
||
size="18"
|
||
color="#f84a42"
|
||
/>
|
||
<text
|
||
:style="{
|
||
color: getBatteryColor({
|
||
soc: carDetail.soc,
|
||
}).color,
|
||
}"
|
||
>
|
||
{{ carDetail.soc || '--' }}%
|
||
</text>
|
||
</view>
|
||
<view class="distance">
|
||
(
|
||
<uv-icon
|
||
style="margin-left: 8rpx;"
|
||
name="zuchecheliang"
|
||
custom-prefix="custom-icon"
|
||
size="18"
|
||
color="#2eb385"
|
||
/>
|
||
<text style="margin: 0 8rpx;"> {{ carDetail.distance || '--' }}</text>
|
||
)
|
||
</view>
|
||
</view>
|
||
<view class="distance_right">
|
||
<uv-button
|
||
:custom-style="customStyle"
|
||
type="primary"
|
||
text="寻车铃"
|
||
shape="circle"
|
||
size="normal"
|
||
icon="volume"
|
||
:disabled="list.findBike.btnLoading"
|
||
icon-color="#0984fb"
|
||
@click="handleBtnClick(list.findBike.key, 'findBike')"
|
||
/>
|
||
</view>
|
||
</view>
|
||
<!-- 车辆信息-按钮区域-换电 -->
|
||
<view
|
||
v-if="btnType === 'charge'"
|
||
class="button-area"
|
||
>
|
||
<uv-button
|
||
:custom-style="btnCustomStyle2"
|
||
text="车辆详情"
|
||
@click="handleDetail"
|
||
/>
|
||
<uv-button
|
||
:custom-style="btnCustomStyle2"
|
||
text="开电池仓"
|
||
:disabled="list.openLock.btnLoading"
|
||
@click="handleBtnClick(list.openLock.key, 'openLock')"
|
||
/>
|
||
<uv-button
|
||
:custom-style="btnCustomStyle"
|
||
type="primary"
|
||
text="完成换电"
|
||
@click="completeChangeBattery"
|
||
/>
|
||
</view>
|
||
<!-- 车辆信息-按钮区域-全部 -->
|
||
<view
|
||
v-if="btnType === 'none'"
|
||
class="button-area"
|
||
>
|
||
<uv-button
|
||
:custom-style="btnCustomStyle2"
|
||
text="车辆详情"
|
||
@click="handleDetail"
|
||
/>
|
||
<uv-button
|
||
:custom-style="btnCustomStyle"
|
||
type="primary"
|
||
text="生成工单"
|
||
@click="generateWorkOrder"
|
||
/>
|
||
</view>
|
||
|
||
<!-- ActionSheet 操作菜单 -->
|
||
<uv-action-sheet
|
||
ref="actionSheet"
|
||
:actions="ActionSheetList"
|
||
title="生成工单类型"
|
||
:close-on-click-action="false"
|
||
@select="ActionSheetSelect"
|
||
/>
|
||
</view>
|
||
</template>
|
||
|
||
<style lang="scss" scoped>
|
||
.container {
|
||
position: relative;
|
||
width: calc(100% - 60rpx);
|
||
padding: 20rpx 30rpx;
|
||
background-color: white;
|
||
border-radius: 15rpx;
|
||
box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.1);
|
||
|
||
.close_icon {
|
||
position: absolute;
|
||
right: 0;
|
||
top: 0;
|
||
z-index: 1;
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
background-color: #3b3b3bca;
|
||
transform: translate(26%, -50%);
|
||
}
|
||
|
||
.car_info_title {
|
||
width: 100%;
|
||
display: flex;
|
||
margin-top: 20rpx;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
|
||
.title {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: #343434;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.tags_bar {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.tag {
|
||
display: inline-block;
|
||
padding: 6rpx 12rpx;
|
||
font-size: 24rpx;
|
||
color: #fff;
|
||
border-radius: 30rpx;
|
||
margin-right: 10rpx;
|
||
white-space: nowrap;
|
||
}
|
||
}
|
||
}
|
||
|
||
.electric_time {
|
||
font-size: 28rpx;
|
||
color: #b2b2b2;
|
||
margin: 15rpx 0;
|
||
}
|
||
|
||
.distance {
|
||
width: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
|
||
.distance_left {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.electric {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.distance {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 28rpx;
|
||
color: #2eb385;
|
||
}
|
||
}
|
||
}
|
||
|
||
.button-area {
|
||
margin-top: 35rpx;
|
||
margin-bottom: 20rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
}
|
||
</style>
|