feat:新增功能
This commit is contained in:
parent
1ca50d10ae
commit
9a22a2f872
@ -3,5 +3,5 @@
|
||||
export interface IExecuteCommand {
|
||||
ecuSn: string
|
||||
bikeCode: string
|
||||
commandCode: 'FIND_BIKE' | 'GPS' | 'OPEN_BATTERY_LOCK'
|
||||
commandCode: 'FIND_BIKE' | 'GPS' | 'OPEN_BATTERY_LOCK' | 'OPEN_HELMET' | 'UNLOCK' | 'LOCK'
|
||||
}
|
||||
|
||||
@ -5,3 +5,10 @@ export interface WorkOrdersListType {
|
||||
orderType?: string
|
||||
bikeCode?: string
|
||||
}
|
||||
|
||||
export interface createMaintainOrderType {
|
||||
bikeCode: string
|
||||
parts?: number[]
|
||||
fileUrls?: string[]
|
||||
remarks?: string
|
||||
}
|
||||
|
||||
@ -3,6 +3,8 @@ const { VITE_SERVER_BASEURL } = import.meta.env
|
||||
|
||||
// 上传远程升级文件
|
||||
export const remoteUpgradeUrl = `${VITE_SERVER_BASEURL}/operations/ebikeEcuInfo/upload`
|
||||
// 上传远程故障图片
|
||||
export const faultUrl = `${VITE_SERVER_BASEURL}/operations/ebikeBikeOrder/upload`
|
||||
|
||||
/**
|
||||
* 从图片URL数组下载并上传图片(严格模式:任一失败则整体失败)
|
||||
|
||||
@ -1,7 +1,27 @@
|
||||
import type { WorkOrdersListType } from './types/work'
|
||||
import type { createMaintainOrderType, WorkOrdersListType } from './types/work'
|
||||
import { http } from '@/http/http'
|
||||
|
||||
// 分页查询工单信息
|
||||
export function queryhWorkOrders(query: WorkOrdersListType) {
|
||||
return http.get('/operations/ebikeBikeOrder/page', query)
|
||||
}
|
||||
|
||||
// 工单详情
|
||||
export function queryWorkOrderDetailAPI(orderId: string) {
|
||||
return http.get(`/operations/ebikeBikeOrder/getInfo`, { orderId })
|
||||
}
|
||||
|
||||
// 接取工单
|
||||
export function acceptWorkOrderAPI(orderId: string) {
|
||||
return http.get(`/operations/ebikeBikeOrder/acceptOrder`, { orderId })
|
||||
}
|
||||
|
||||
// 分页查询当前员工接取的工单信息
|
||||
export function queryMyWorkOrders(query: WorkOrdersListType) {
|
||||
return http.get('/operations/ebikeBikeOrder/pageByStaff', query)
|
||||
}
|
||||
|
||||
// 生成维修工单。
|
||||
export function createMaintainOrderAPI(data: createMaintainOrderType) {
|
||||
return http.post('/operations/ebikeBikeOrder/faultOrder', data)
|
||||
}
|
||||
|
||||
131
src/components/instructTools/instructTools.vue
Normal file
131
src/components/instructTools/instructTools.vue
Normal file
@ -0,0 +1,131 @@
|
||||
<script lang="ts" setup>
|
||||
import { executeCommandAPI } from '@/api/centerControl'
|
||||
|
||||
const props = defineProps({
|
||||
bikeCode: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
|
||||
const bikecode = ref('')
|
||||
const ecucode = ref('')
|
||||
const btnConfig = reactive({
|
||||
width: '150rpx',
|
||||
heigth: '60rpx',
|
||||
})
|
||||
|
||||
// 测试项列表
|
||||
const list = reactive({
|
||||
unlocking: {
|
||||
msg: '',
|
||||
name: '开锁',
|
||||
key: 'UNLOCK',
|
||||
status: 'none',
|
||||
tip: '',
|
||||
btnText: '开锁',
|
||||
btnLoadingText: '执行',
|
||||
btnLoading: false,
|
||||
},
|
||||
Locking: {
|
||||
msg: '',
|
||||
name: '关锁',
|
||||
key: 'LOCK',
|
||||
status: 'none',
|
||||
tip: '',
|
||||
btnText: '关锁',
|
||||
btnLoadingText: '执行',
|
||||
btnLoading: false,
|
||||
},
|
||||
openLock: {
|
||||
msg: '',
|
||||
name: '开电池仓',
|
||||
key: 'OPEN_BATTERY_LOCK',
|
||||
status: 'none',
|
||||
tip: '',
|
||||
btnText: '开电池仓',
|
||||
btnLoadingText: '执行',
|
||||
btnLoading: false,
|
||||
},
|
||||
openHelmet: {
|
||||
msg: '',
|
||||
name: '开头盔锁',
|
||||
key: 'OPEN_HELMET',
|
||||
status: 'none',
|
||||
tip: '',
|
||||
btnText: '开头盔锁',
|
||||
btnLoadingText: '执行',
|
||||
btnLoading: false,
|
||||
},
|
||||
})
|
||||
|
||||
// 确定按钮点击事件
|
||||
async function handleBtnClick(value: any, key: string, index: number) {
|
||||
if (!bikecode.value) {
|
||||
return uni.showToast({
|
||||
title: '无车辆编号',
|
||||
icon: 'none',
|
||||
})
|
||||
}
|
||||
list[key].btnLoading = true
|
||||
try {
|
||||
const result: boolean = await executeCommandAPI({
|
||||
ecuSn: '',
|
||||
bikeCode: bikecode.value,
|
||||
commandCode: value.key,
|
||||
})
|
||||
if (result) {
|
||||
uni.showToast({
|
||||
title: '执行成功',
|
||||
icon: 'success',
|
||||
})
|
||||
list[key].btnLoading = false
|
||||
}
|
||||
else {
|
||||
uni.showToast({
|
||||
title: '执行失败',
|
||||
icon: 'error',
|
||||
})
|
||||
list[key].btnLoading = false
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
uni.showToast({
|
||||
title: '执行异常',
|
||||
icon: 'error',
|
||||
})
|
||||
console.error('中控测试报错------>', e)
|
||||
}
|
||||
}
|
||||
|
||||
watch(() => props.bikeCode, (val) => {
|
||||
bikecode.value = val
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="cotainer">
|
||||
<uv-button
|
||||
v-for="(value, key, index) in list"
|
||||
:key="key"
|
||||
:loading="value.btnLoading"
|
||||
:loading-text="value.btnLoadingText"
|
||||
type="primary"
|
||||
:text="value.btnText"
|
||||
:custom-text-style="{
|
||||
fontSize: '28rpx',
|
||||
}"
|
||||
:custom-style="btnConfig"
|
||||
@click="handleBtnClick(value, key, index)"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cotainer {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
132
src/components/mapOrientation/mapOrientation.vue
Normal file
132
src/components/mapOrientation/mapOrientation.vue
Normal file
@ -0,0 +1,132 @@
|
||||
<script lang="ts" setup>
|
||||
import AMapWX from '@/plugIns/amap-wx.130.js'
|
||||
import { getLoalcation, reverseGeocoder } from '@/utils/map'
|
||||
|
||||
const emits = defineEmits(['change'])
|
||||
const { VITE_AMAP_KEY } = import.meta.env
|
||||
const amapsdk = new AMapWX({
|
||||
key: VITE_AMAP_KEY,
|
||||
})
|
||||
const oMap = ref(null)
|
||||
const mapRef = ref(null)
|
||||
const formatted_address = ref('')
|
||||
|
||||
function regionchange(e: any) {
|
||||
if (e.type === 'end') {
|
||||
const { centerLocation } = e.detail
|
||||
const { longitude, latitude } = centerLocation
|
||||
console.log(e)
|
||||
reverseGeocoder({
|
||||
mapsdk: amapsdk,
|
||||
longitude,
|
||||
latitude,
|
||||
success(data: any) {
|
||||
const { regeocodeData, longitude, latitude } = data
|
||||
formatted_address.value = regeocodeData.formatted_address
|
||||
emits('change', {
|
||||
longitude,
|
||||
latitude,
|
||||
formatted_address,
|
||||
})
|
||||
},
|
||||
fail(error: any) {
|
||||
console.log(error)
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const centerLat = ref(39.904989) // 默认北京
|
||||
const centerLng = ref(116.405285)
|
||||
|
||||
onMounted(() => {
|
||||
oMap.value = uni.createMapContext('mapRef', {
|
||||
this: getCurrentInstance().proxy,
|
||||
})
|
||||
if (oMap.value) {
|
||||
getLoalcation({
|
||||
mapContext: oMap.value,
|
||||
success(res: any) {
|
||||
const { latitude, longitude } = res
|
||||
centerLat.value = latitude
|
||||
centerLng.value = longitude
|
||||
},
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="container">
|
||||
<view>
|
||||
<view class="title">
|
||||
<uv-icon name="ditu_dingwei" color="#71a2e3" custom-prefix="custom-icon" size="26" style="margin-right: 10rpx;" />
|
||||
请确定损坏车辆当前位置
|
||||
</view>
|
||||
<view class="location">
|
||||
{{ formatted_address || '--' }}
|
||||
</view>
|
||||
<view class="tips">
|
||||
拖动地图可修改位置
|
||||
</view>
|
||||
</view>
|
||||
<map
|
||||
id="mapRef"
|
||||
ref="mapRef"
|
||||
style="width: 100%; height: 660rpx;position: relative;"
|
||||
:latitude="centerLat"
|
||||
:longitude="centerLng"
|
||||
:scale="18"
|
||||
:show-location="false"
|
||||
@regionchange="regionchange"
|
||||
>
|
||||
<view class="marker">
|
||||
<uv-icon name="zuobiaodian_lixian" color="#21243e" custom-prefix="custom-icon" size="30" style="margin-right: 10rpx;" />
|
||||
</view>
|
||||
</map>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
width: 100%;
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
margin: 20rpx 0;
|
||||
}
|
||||
|
||||
.location {
|
||||
position: relative;
|
||||
left: 9%;
|
||||
font-size: 30rpx;
|
||||
width: 90%;
|
||||
color: #565656;
|
||||
margin: 10rpx 0;
|
||||
}
|
||||
|
||||
.tips {
|
||||
position: relative;
|
||||
left: 9%;
|
||||
font-size: 28rpx;
|
||||
color: #9d9d9d;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.marker {
|
||||
position: absolute;
|
||||
width: 30rpx;
|
||||
height: 40rpx;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-left: -15rpx;
|
||||
margin-top: -20rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,10 +1,12 @@
|
||||
<script lang="ts" setup>
|
||||
import { executeCommandAPI } from '@/api/centerControl'
|
||||
import bikeCodeScan from '@/components/bikeCodeScan/bikeCodeScan.vue'
|
||||
import { systemInfo } from '@/utils/systemInfo'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '换电',
|
||||
navigationBarBackgroundColor: '#1488f5',
|
||||
navigationBarTextStyle: 'white',
|
||||
},
|
||||
})
|
||||
const labelStyle = {
|
||||
@ -14,9 +16,49 @@ const labelStyle = {
|
||||
fontWeight: 'normal',
|
||||
lineHeight: '32px',
|
||||
}
|
||||
const btnConfig = reactive({
|
||||
btnText: '完成换电',
|
||||
btnLoading: false,
|
||||
btnLoadingText: '正在提交',
|
||||
})
|
||||
const testBtnConfig = reactive({
|
||||
width: '180rpx',
|
||||
heigth: '60rpx',
|
||||
})
|
||||
|
||||
// 计算 scroll-view 的高度,减去顶部导航栏和底部可能的操作栏高度
|
||||
const scrollHeight = systemInfo.screenHeight - 150
|
||||
// 测试项列表
|
||||
const list = reactive({
|
||||
findBike: {
|
||||
msg: '',
|
||||
name: '寻车铃',
|
||||
key: 'FIND_BIKE',
|
||||
status: 'none', // none,loading,success,fail
|
||||
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,
|
||||
},
|
||||
})
|
||||
|
||||
// 表单引用
|
||||
const form = ref(null)
|
||||
@ -24,6 +66,7 @@ const form = ref(null)
|
||||
// 表单校验规则
|
||||
const formData = ref({
|
||||
name: '',
|
||||
bikeCode: '',
|
||||
})
|
||||
|
||||
// 表单校验规则
|
||||
@ -33,11 +76,57 @@ const rules = {}
|
||||
function openfaultreport() {
|
||||
|
||||
}
|
||||
|
||||
function handleSubmit() {
|
||||
|
||||
}
|
||||
|
||||
// 确定按钮点击事件
|
||||
async function handleBtnClick(value: any, key: string, index: number) {
|
||||
if (!formData.value.bikeCode) {
|
||||
return uni.showToast({
|
||||
title: '无车辆编号',
|
||||
icon: 'none',
|
||||
})
|
||||
}
|
||||
list[key].btnLoading = true
|
||||
try {
|
||||
const result: boolean = await executeCommandAPI({
|
||||
ecuSn: undefined,
|
||||
bikeCode: formData.value.bikeCode,
|
||||
commandCode: value.key,
|
||||
})
|
||||
if (result) {
|
||||
uni.showToast({
|
||||
title: '执行成功',
|
||||
icon: 'success',
|
||||
})
|
||||
list[key].btnLoading = false
|
||||
}
|
||||
else {
|
||||
uni.showToast({
|
||||
title: '执行失败',
|
||||
icon: 'error',
|
||||
})
|
||||
list[key].btnLoading = false
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
uni.showToast({
|
||||
title: '执行异常',
|
||||
icon: 'error',
|
||||
})
|
||||
console.error('中控测试报错------>', e)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="b-body-gray">
|
||||
<scroll-view :scroll-y="true" :style="{ height: `${scrollHeight}px` }">
|
||||
<z-paging
|
||||
ref="paging"
|
||||
bg-color="#f3f3f3"
|
||||
>
|
||||
<view>
|
||||
<uv-form ref="form" label-position="left" :model="formData" :rules="rules" :label-width="90" :label-style="labelStyle">
|
||||
<uni-card>
|
||||
<uv-form-item label="车辆编号:" prop="name" border-bottom>
|
||||
@ -52,7 +141,7 @@ function openfaultreport() {
|
||||
<uv-form-item label="电池电量:" prop="name" border-bottom>
|
||||
{{ formData.name }}%
|
||||
</uv-form-item>
|
||||
<uv-form-item label="车辆位置:" prop="name" border-bottom>
|
||||
<!-- <uv-form-item label="车辆位置:" prop="name" border-bottom>
|
||||
<uv-cell-group>
|
||||
<uv-cell title="查看地图" is-link :title-style="labelStyle" />
|
||||
</uv-cell-group>
|
||||
@ -61,7 +150,7 @@ function openfaultreport() {
|
||||
<uv-button type="primary" size="small" text="开锁" />
|
||||
<uv-button type="primary" size="small" text="关锁" />
|
||||
</view>
|
||||
</uv-form-item>
|
||||
</uv-form-item> -->
|
||||
<uv-form-item label="新电池编号:" prop="name">
|
||||
<bikeCodeScan v-model="formData.name" placeholder="请输入或扫码" />
|
||||
</uv-form-item>
|
||||
@ -81,8 +170,27 @@ function openfaultreport() {
|
||||
</uni-card>
|
||||
</uv-form>
|
||||
|
||||
<!-- 按钮 -->
|
||||
<uni-card>
|
||||
<view class="btn_tools">
|
||||
<uv-button
|
||||
v-for="(value, key, index) in list"
|
||||
:key="key"
|
||||
:loading="value.btnLoading"
|
||||
:loading-text="value.btnLoadingText"
|
||||
type="primary"
|
||||
:text="value.btnText"
|
||||
:custom-text-style="{
|
||||
fontSize: '28rpx',
|
||||
}"
|
||||
:custom-style="testBtnConfig"
|
||||
@click="handleBtnClick(value, key, index)"
|
||||
/>
|
||||
</view>
|
||||
</uni-card>
|
||||
|
||||
<!-- 温馨提示 -->
|
||||
<view class="p-a-15">
|
||||
<view class="u-p-a-20">
|
||||
<view
|
||||
class="fz-28 text-gray"
|
||||
style="margin-bottom: 10px; font-weight: bold"
|
||||
@ -103,10 +211,29 @@ function openfaultreport() {
|
||||
量上报后会自动变成上报的电量;
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</div>
|
||||
</view>
|
||||
|
||||
<template #bottom>
|
||||
<view class="bottom-button-zaping">
|
||||
<uv-button
|
||||
type="primary"
|
||||
:text="btnConfig.btnText"
|
||||
:loading="btnConfig.btnLoading"
|
||||
:loading-text="btnConfig.btnLoadingText"
|
||||
@click="handleSubmit"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
</z-paging>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
//
|
||||
.container {
|
||||
}
|
||||
|
||||
.btn_tools {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
|
||||
344
src/pages-sub/warehouse/faultReporting/faultReporting.vue
Normal file
344
src/pages-sub/warehouse/faultReporting/faultReporting.vue
Normal file
@ -0,0 +1,344 @@
|
||||
<script lang="ts" setup>
|
||||
import { faultUrl, uploadImagesStrict } from '@/api/upload'
|
||||
import { createMaintainOrderAPI } from '@/api/work'
|
||||
import mapOrientation from '@/components/mapOrientation/mapOrientation.vue'
|
||||
import CacheManager from '@/utils/CacheManager'
|
||||
import { scanCode } from '@/utils/tools'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '故障上报',
|
||||
navigationBarBackgroundColor: '#1488f5',
|
||||
navigationBarTextStyle: 'white',
|
||||
},
|
||||
})
|
||||
|
||||
const btnConfig = reactive({
|
||||
btnLoading: false,
|
||||
btnLoadingText: '提交中...',
|
||||
})
|
||||
const partsList = ref<any>([])
|
||||
const form = ref<any>(null)
|
||||
const fileList = ref([])
|
||||
const formData = ref({
|
||||
bikeCode: '',
|
||||
parts: [],
|
||||
fileUrls: [],
|
||||
remarks: '',
|
||||
})
|
||||
|
||||
const currentLocation = reactive ({
|
||||
longitude: '',
|
||||
latitude: '',
|
||||
})
|
||||
|
||||
function scan() {
|
||||
scanCode({
|
||||
success: (res: any) => {
|
||||
formData.value.bikeCode = res.code
|
||||
},
|
||||
fail: () => {
|
||||
uni.showToast({
|
||||
title: '扫码失败',
|
||||
icon: 'none',
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
function mapChange(e: any) {
|
||||
const { longitude, latitude } = e
|
||||
currentLocation.longitude = longitude
|
||||
currentLocation.latitude = latitude
|
||||
}
|
||||
|
||||
function handlePartsClick(item: any, index: number) {
|
||||
uni.vibrateShort()
|
||||
partsList.value[index].selected = !item.selected
|
||||
}
|
||||
|
||||
function deletePic(e: any) {
|
||||
fileList.value.splice(e.index, 1)
|
||||
formData.value.fileUrls.splice(e.index, 1)
|
||||
}
|
||||
|
||||
async function afterRead(event: any) {
|
||||
const lists = [].concat(event.file)
|
||||
let fileListLen = fileList.value.length
|
||||
const token = CacheManager.get('token')
|
||||
|
||||
lists.forEach((item) => {
|
||||
fileList.value.push({
|
||||
...item,
|
||||
status: 'uploading',
|
||||
message: '上传中',
|
||||
})
|
||||
})
|
||||
|
||||
for (let i = 0; i < lists.length; i++) {
|
||||
const item = fileList.value[fileListLen]
|
||||
try {
|
||||
const result: any = await uploadImagesStrict([lists[i].url], faultUrl, {
|
||||
name: 'file',
|
||||
header: {
|
||||
'Authorization': token,
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
})
|
||||
formData.value.fileUrls.push(result[0])
|
||||
fileList.value.splice(fileListLen, 1, Object.assign(item, {
|
||||
status: 'success',
|
||||
message: '',
|
||||
url: result[0].fileUrl,
|
||||
}))
|
||||
fileListLen++
|
||||
}
|
||||
catch (err) {
|
||||
fileList.value.splice(fileListLen, 1, Object.assign(item, {
|
||||
status: 'failed',
|
||||
message: '',
|
||||
url: '',
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
const parts = partsList.value.filter(item => item.selected)
|
||||
console.log(parts)
|
||||
if (!formData.value.bikeCode) {
|
||||
uni.showToast({
|
||||
title: '请填写车牌号',
|
||||
icon: 'none',
|
||||
})
|
||||
return
|
||||
}
|
||||
if (parts.length <= 0) {
|
||||
uni.showToast({
|
||||
title: '请选择故障部件',
|
||||
icon: 'none',
|
||||
})
|
||||
return
|
||||
}
|
||||
formData.value.parts = parts.map(item => item.value)
|
||||
console.log(formData.value)
|
||||
btnConfig.btnLoading = true
|
||||
try {
|
||||
const res: any = await createMaintainOrderAPI(formData.value)
|
||||
console.log(res)
|
||||
uni.showToast({
|
||||
title: '提交成功',
|
||||
icon: 'none',
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1000)
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
finally {
|
||||
btnConfig.btnLoading = false
|
||||
}
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
const dicList: any = CacheManager.get('dictData')
|
||||
if (Array.isArray(dicList) && dicList.length > 0) {
|
||||
const list = dicList.find((item: any) => item.dicCode === 'inventory_type').values
|
||||
partsList.value = list.map((item: any) => ({
|
||||
icon: item.dicIcon || '',
|
||||
name: item.dicValueName,
|
||||
value: Number(item.dicValue),
|
||||
selected: false,
|
||||
}))
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view>
|
||||
<z-paging
|
||||
ref="paging"
|
||||
>
|
||||
<view class="content_box">
|
||||
<uv-form
|
||||
ref="form"
|
||||
label-position="left"
|
||||
label-width="80"
|
||||
:label-style="{
|
||||
fontSize: '28rpx',
|
||||
}"
|
||||
>
|
||||
<uv-form-item label="车辆编号" prop="userInfo.name" border-bottom>
|
||||
<uv-input v-model="formData.bikeCode" border="none" placeholder="请输入">
|
||||
<template #suffix>
|
||||
<uv-icon name="scan" color="#2979ff" size="28" @click="scan" />
|
||||
</template>
|
||||
</uv-input>
|
||||
</uv-form-item>
|
||||
<uv-form-item label="当前坐标" prop="userInfo.name" border-bottom>
|
||||
<view style="width: 90%;">
|
||||
{{ currentLocation.longitude || '-' }}, {{ currentLocation.latitude || '-' }}
|
||||
</view>
|
||||
</uv-form-item>
|
||||
</uv-form>
|
||||
|
||||
<!-- 地图 -->
|
||||
<view>
|
||||
<mapOrientation @change="mapChange" />
|
||||
</view>
|
||||
</view>
|
||||
</z-paging>
|
||||
</view>
|
||||
|
||||
<!-- 弹窗 -->
|
||||
<you-touchbox
|
||||
:custom-style="{
|
||||
backgroundColor: '#eff3f6',
|
||||
borderTopLeftRadius: '20px',
|
||||
borderTopRightRadius: '20px',
|
||||
boxShadow: '0 2rpx 8rpx rgba(0, 0, 0, 0.4)',
|
||||
|
||||
}"
|
||||
min-top="200"
|
||||
max-top="150"
|
||||
>
|
||||
<scroll-view
|
||||
scroll-y
|
||||
:scroll-anchoring="false"
|
||||
class="order_scroll"
|
||||
>
|
||||
<view class="order_container">
|
||||
<view class="title">
|
||||
请选择车辆<text style="color: #1488f5;">损坏部位</text>
|
||||
</view>
|
||||
<view class="list_grid">
|
||||
<view
|
||||
v-for="(item, index) in partsList"
|
||||
:key="index"
|
||||
class="fault_item"
|
||||
@click="handlePartsClick(item, index)"
|
||||
>
|
||||
<view class="icon">
|
||||
<uv-icon
|
||||
size="30"
|
||||
:name="item.icon"
|
||||
:color="item.selected ? '#1488f5' : ''"
|
||||
custom-prefix="custom-icon"
|
||||
/>
|
||||
</view>
|
||||
<view class="text" :style="{ color: item.selected ? '#1488f5' : '' }">
|
||||
{{ item.name }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="describe">
|
||||
<uv-textarea v-model="formData.remarks" placeholder="其他想说的" />
|
||||
</view>
|
||||
|
||||
<!-- 上传图片 -->
|
||||
<view class="upload-img">
|
||||
<view style="margin-bottom: 20rpx;">
|
||||
上传图片(最多五张)
|
||||
</view>
|
||||
<uv-upload
|
||||
:file-list="fileList"
|
||||
name="1"
|
||||
multiple
|
||||
:max-count="5"
|
||||
:preview-full-image="true"
|
||||
@after-read="afterRead"
|
||||
@delete="deletePic"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="btn_box">
|
||||
<uv-button
|
||||
type="primary"
|
||||
text="确定提交"
|
||||
:loading="btnConfig.btnLoading"
|
||||
:loading-text="btnConfig.btnLoadingText"
|
||||
@click="submit"
|
||||
/>
|
||||
</view>
|
||||
</you-touchbox>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content_box {
|
||||
padding: 25rpx;
|
||||
width: calc(100% - 50rpx);
|
||||
}
|
||||
|
||||
.order_scroll {
|
||||
padding: 20rpx;
|
||||
background-color: white;
|
||||
width: calc(100% - 40rpx);
|
||||
|
||||
.order_container {
|
||||
height: 1000px;
|
||||
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.list_grid {
|
||||
margin-top: 20rpx;
|
||||
padding-top: 5rpx;
|
||||
display: grid;
|
||||
overflow-y: auto;
|
||||
grid-template-columns: repeat(4, 1fr); /* 固定5列 */
|
||||
grid-template-rows: auto auto; /* 两行 */
|
||||
gap: 16px; /* 项目之间的间距 */
|
||||
}
|
||||
|
||||
.fault_item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
|
||||
.icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 0 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.text {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
text-shadow: 0 0 4px rgba(0, 0, 0, 0.1);
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
.describe {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.upload-img {
|
||||
font-size: 28rpx;
|
||||
margin-top: 50rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn_box {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
padding: 10px 20rpx 20px 20rpx;
|
||||
width: calc(100% - 40rpx);
|
||||
background-color: white;
|
||||
position: 99;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,185 @@
|
||||
<script lang="ts" setup>
|
||||
import { scanCode } from '@/utils/tools'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '领料(电池)',
|
||||
navigationBarBackgroundColor: '#1488f5',
|
||||
navigationBarTextStyle: 'white',
|
||||
},
|
||||
})
|
||||
const btnStyle = computed(() => ({
|
||||
backgroundColor: '#f1f8fd',
|
||||
color: '#64a3db',
|
||||
borderColor: '#64a3db',
|
||||
}))
|
||||
const paging = ref(null)
|
||||
const loading = ref(false)
|
||||
const tableData = ref<any>([])
|
||||
const popupRef = ref(null)
|
||||
const formData = reactive({
|
||||
batteryCode: '',
|
||||
})
|
||||
|
||||
function handleScan() {
|
||||
scanCode({
|
||||
success(res: any) {
|
||||
const { code } = res
|
||||
addCode(code)
|
||||
},
|
||||
fail(res) {
|
||||
console.log(res)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
function handleAddByCode() {
|
||||
popupRef.value.open('bottom')
|
||||
}
|
||||
|
||||
function addCode(code: string, callback = null) {
|
||||
if (!code) {
|
||||
uni.showToast({
|
||||
title: '请输入电池编号',
|
||||
icon: 'none',
|
||||
})
|
||||
return
|
||||
}
|
||||
// 判断列表中是否存在该编号
|
||||
if (tableData.value.some(item => item.batteryCode === code)) {
|
||||
uni.showToast({
|
||||
title: '该编号已存在',
|
||||
icon: 'none',
|
||||
})
|
||||
return
|
||||
}
|
||||
tableData.value.push({
|
||||
batteryCode: code,
|
||||
})
|
||||
|
||||
callback && callback()
|
||||
}
|
||||
|
||||
function handleDelete(index: number) {
|
||||
tableData.value.splice(index, 1)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view>
|
||||
<z-paging
|
||||
ref="paging"
|
||||
bg-color="#f3f3f3"
|
||||
>
|
||||
<view class="container">
|
||||
<uni-table
|
||||
ref="table"
|
||||
:loading="loading"
|
||||
stripe border
|
||||
empty-text="请扫码添加设备"
|
||||
>
|
||||
<uni-tr>
|
||||
<uni-th align="center" width="200">
|
||||
电池编号
|
||||
</uni-th>
|
||||
<uni-th align="center" width="100">
|
||||
操作
|
||||
</uni-th>
|
||||
</uni-tr>
|
||||
<uni-tr v-for="(item, index) in tableData" :key="index">
|
||||
<uni-td align="center">
|
||||
{{ item.batteryCode }}
|
||||
</uni-td>
|
||||
<uni-td>
|
||||
<view class="uni-group">
|
||||
<button class="uni-button" size="mini" type="warn" @click="handleDelete(index)">
|
||||
删除
|
||||
</button>
|
||||
</view>
|
||||
</uni-td>
|
||||
</uni-tr>
|
||||
</uni-table>
|
||||
</view>
|
||||
|
||||
<template #bottom>
|
||||
<view class="bottom-button-zaping">
|
||||
<view class="tools">
|
||||
<uv-button text="扫码新增" :custom-style="btnStyle" @click="handleScan" />
|
||||
<uv-button text="编号新增" :custom-style="btnStyle" @click="handleAddByCode" />
|
||||
</view>
|
||||
<uv-button
|
||||
type="primary"
|
||||
text="确认领取"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
</z-paging>
|
||||
<!-- 弹窗 -->
|
||||
<uv-popup ref="popupRef" round="15">
|
||||
<view class="popup-content">
|
||||
<view class="title">
|
||||
电池编号
|
||||
</view>
|
||||
<view class="input_bar">
|
||||
<uv-input v-model="formData.batteryCode" placeholder="请输入" border="surround" />
|
||||
</view>
|
||||
<view class="btn_bar">
|
||||
<uv-button
|
||||
type="primary"
|
||||
text="添加"
|
||||
@click="() => {
|
||||
addCode(
|
||||
formData.batteryCode,
|
||||
function() {
|
||||
popupRef.close()
|
||||
})
|
||||
}"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</uv-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tools {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
.container {
|
||||
padding: 20rpx 30rpx;
|
||||
width: calc(100% - 60rpx);
|
||||
}
|
||||
|
||||
.uni-group {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
padding: 20rpx;
|
||||
width: calc(100% - 40rpx);
|
||||
z-index: 9999;
|
||||
|
||||
.title {
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.input_bar {
|
||||
margin: 30rpx;
|
||||
}
|
||||
|
||||
.btn_bar {
|
||||
margin-top: 100rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
253
src/pages-sub/work/inspectionWorkOrder/inspectionWorkOrder.vue
Normal file
253
src/pages-sub/work/inspectionWorkOrder/inspectionWorkOrder.vue
Normal file
@ -0,0 +1,253 @@
|
||||
<script lang="ts" setup>
|
||||
import instructTools from '@/components/instructTools/instructTools.vue'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '故障维修',
|
||||
navigationBarBackgroundColor: '#1488f5',
|
||||
navigationBarTextStyle: 'white',
|
||||
},
|
||||
})
|
||||
|
||||
const paging = ref<any>(null)
|
||||
const popupRef = ref<any>(null)
|
||||
const fileList = ref<any>([])
|
||||
const workOrderDetail = ref<any>({
|
||||
ecuSn: '',
|
||||
bikeCode: '',
|
||||
})
|
||||
|
||||
const formData = reactive({
|
||||
type: 1,
|
||||
})
|
||||
|
||||
function findCar() {
|
||||
const params = {
|
||||
elng: 104.10,
|
||||
elat: 30.62,
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: `/pages-sub/map/findCar/findCar?params=${encodeURIComponent(JSON.stringify(params))}`,
|
||||
})
|
||||
}
|
||||
|
||||
function handleComplete() {
|
||||
popupRef.value.open('bottom')
|
||||
}
|
||||
|
||||
async function afterRead(event: any) {
|
||||
|
||||
}
|
||||
|
||||
function deletePic(e: any) {
|
||||
fileList.value.splice(e.index, 1)
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
// uni.showLoading({
|
||||
// title: '加载中...',
|
||||
// })
|
||||
// setTimeout(() => {
|
||||
// uni.hideLoading()
|
||||
// workOrderDetail.value = {
|
||||
// ecuSn: '2370171956',
|
||||
// bikeCode: '43497692725',
|
||||
// }
|
||||
// }, 1000)
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
popupRef.value.open('bottom')
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<z-paging
|
||||
ref="paging"
|
||||
bg-color="#f3f3f3"
|
||||
>
|
||||
<view class="y_card_wrapper">
|
||||
<view class="card_box">
|
||||
<!-- 车辆编号 -->
|
||||
<view class="card_row">
|
||||
<view class="card_row_key">
|
||||
车辆编号
|
||||
</view>
|
||||
<view class="card_row_value">
|
||||
101267101267
|
||||
</view>
|
||||
</view>
|
||||
<!-- 创建时间 -->
|
||||
<view class="card_row">
|
||||
<view class="card_row_key">
|
||||
创建时间
|
||||
</view>
|
||||
<view class="card_row_value">
|
||||
101267101267
|
||||
</view>
|
||||
</view>
|
||||
<!-- 电池电量 -->
|
||||
<view class="card_row">
|
||||
<view class="card_row_key">
|
||||
电池电量
|
||||
</view>
|
||||
<view class="card_row_value">
|
||||
30%
|
||||
</view>
|
||||
</view>
|
||||
<!-- 车辆位置 -->
|
||||
<view class="card_row">
|
||||
<view class="card_row_key">
|
||||
车辆位置
|
||||
</view>
|
||||
<view class="card_row_value_two" @click="findCar">
|
||||
<view>查看地图</view>
|
||||
<view class="card_row_small_text">
|
||||
110.418272,25.312344
|
||||
</view>
|
||||
</view>
|
||||
<view class="card_row_link">
|
||||
<uv-icon name="arrow-right" />
|
||||
</view>
|
||||
</view>
|
||||
<!-- 信号强度 -->
|
||||
<view class="card_row">
|
||||
<view class="card_row_key">
|
||||
信号强度
|
||||
</view>
|
||||
<view class="card_row_value">
|
||||
30%
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 指令工具栏 -->
|
||||
<view class="card_box" style="margin-top: 30rpx;">
|
||||
<instructTools :bike-code="workOrderDetail.bikeCode" />
|
||||
</view>
|
||||
</view>
|
||||
<template #bottom>
|
||||
<view class="bottom-button-zaping">
|
||||
<uv-button
|
||||
type="primary"
|
||||
text="处理完成"
|
||||
@click="handleComplete"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<!-- 弹窗 -->
|
||||
<uv-popup ref="popupRef" round="20">
|
||||
<view class="popup-content">
|
||||
<view class="popup-title">
|
||||
故障误报
|
||||
</view>
|
||||
<!-- 选择栏 -->
|
||||
<view class="popup-select-bar">
|
||||
<view
|
||||
class="select-item"
|
||||
:class="[formData.type === 1 ? `select-item-active` : ``]"
|
||||
>
|
||||
故障误报
|
||||
</view>
|
||||
<view
|
||||
class="select-item"
|
||||
:class="[formData.type === 2 ? `select-item-active` : ``]"
|
||||
style="margin-left: 30rpx;"
|
||||
>
|
||||
处理故障
|
||||
</view>
|
||||
</view>
|
||||
<!-- 描述 -->
|
||||
<view class="popup-select-row">
|
||||
<view class="row-title">
|
||||
填写处理结果
|
||||
</view>
|
||||
<view class="row-content">
|
||||
<uv-textarea placeholder="请输入处理结果" />
|
||||
</view>
|
||||
</view>
|
||||
<!-- 照片上传 -->
|
||||
<view class="popup-select-row">
|
||||
<view class="row-title">
|
||||
故障照片(最多5张)
|
||||
</view>
|
||||
<view class="row-content">
|
||||
<uv-upload
|
||||
:file-list="fileList"
|
||||
name="1"
|
||||
multiple
|
||||
:max-count="5"
|
||||
@after-read="afterRead"
|
||||
@delete="deletePic"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="popup-select-btn">
|
||||
<uv-button type="info" text="取消" style="width: 45%;" />
|
||||
<uv-button type="primary" text="提交" style="width: 45%;" />
|
||||
</view>
|
||||
</view>
|
||||
</uv-popup>
|
||||
</z-paging>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.popup-content {
|
||||
padding: 20rpx;
|
||||
width: calc(100% - 40rpx);
|
||||
height: 70vh;
|
||||
position: relative;
|
||||
|
||||
.popup-title {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
font-size: 34rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.popup-select-bar {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 30rpx;
|
||||
|
||||
.select-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 15rpx 50rpx;
|
||||
border: 2rpx solid #e9e9e9;
|
||||
border-radius: 10rpx;
|
||||
font-size: 28rpx;
|
||||
|
||||
&-active {
|
||||
background-color: #f4f8fd !important;
|
||||
color: #3d96da !important;
|
||||
border-color: #3d96da !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.popup-select-row {
|
||||
margin-top: 40rpx;
|
||||
.row-title {
|
||||
font-size: 28rpx;
|
||||
color: #a7a7a7;
|
||||
}
|
||||
|
||||
.row-content {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.popup-select-btn {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
width: calc(100% - 20px);
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,4 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { acceptWorkOrderAPI, queryWorkOrderDetailAPI } from '@/api/work'
|
||||
import { translateErrorCode } from '@/utils/tools'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '订单详情',
|
||||
@ -8,16 +11,73 @@ definePage({
|
||||
})
|
||||
|
||||
const paging = ref<any>(null)
|
||||
const workOrderDetail = ref<any>({
|
||||
ecuSn: '',
|
||||
bikeCode: '',
|
||||
createdAt: '',
|
||||
soc: 0,
|
||||
location: {
|
||||
latitude: 0,
|
||||
longitude: 0,
|
||||
},
|
||||
parts: [], // 故障类型
|
||||
orderType: -1,
|
||||
})
|
||||
|
||||
const btnConfig = reactive({
|
||||
loading: false,
|
||||
loadingText: '提交中...',
|
||||
})
|
||||
|
||||
function findCar() {
|
||||
const params = {
|
||||
elng: 104.10,
|
||||
elat: 30.62,
|
||||
elng: workOrderDetail.value.location.longitude,
|
||||
elat: workOrderDetail.value.location.latitude,
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: `/pages-sub/map/findCar/findCar?params=${encodeURIComponent(JSON.stringify(params))}`,
|
||||
})
|
||||
}
|
||||
|
||||
async function queryWorkOrderDetail(orderId: string) {
|
||||
uni.showLoading({
|
||||
title: '加载中...',
|
||||
})
|
||||
try {
|
||||
const res = await queryWorkOrderDetailAPI(orderId)
|
||||
uni.hideLoading()
|
||||
if (res) {
|
||||
workOrderDetail.value = res
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
uni.hideLoading()
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
async function acceptWorkOrder() {
|
||||
btnConfig.loading = true
|
||||
try {
|
||||
const res = await acceptWorkOrderAPI(workOrderDetail.value.orderId)
|
||||
btnConfig.loading = false
|
||||
uni.showToast({
|
||||
title: '接单成功',
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
}
|
||||
catch (e) {
|
||||
btnConfig.loading = false
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
onLoad((query) => {
|
||||
const { orderId } = query
|
||||
queryWorkOrderDetail(orderId)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -33,7 +93,7 @@ function findCar() {
|
||||
车辆编号
|
||||
</view>
|
||||
<view class="card_row_value">
|
||||
101267101267
|
||||
{{ workOrderDetail.bikeCode || '--' }}
|
||||
</view>
|
||||
</view>
|
||||
<!-- 创建时间 -->
|
||||
@ -42,7 +102,7 @@ function findCar() {
|
||||
创建时间
|
||||
</view>
|
||||
<view class="card_row_value">
|
||||
101267101267
|
||||
{{ workOrderDetail.createdAt || '--' }}
|
||||
</view>
|
||||
</view>
|
||||
<!-- 电池电量 -->
|
||||
@ -51,7 +111,7 @@ function findCar() {
|
||||
电池电量
|
||||
</view>
|
||||
<view class="card_row_value">
|
||||
30%
|
||||
{{ workOrderDetail.soc || 0 }}%
|
||||
</view>
|
||||
</view>
|
||||
<!-- 车辆位置 -->
|
||||
@ -62,7 +122,7 @@ function findCar() {
|
||||
<view class="card_row_value_two" @click="findCar">
|
||||
<view>查看地图</view>
|
||||
<view class="card_row_small_text">
|
||||
110.418272,25.312344
|
||||
{{ workOrderDetail.location.longitude || '-' }},{{ workOrderDetail.location.latitude || '-' }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="card_row_link">
|
||||
@ -70,12 +130,12 @@ function findCar() {
|
||||
</view>
|
||||
</view>
|
||||
<!-- 信号强度 -->
|
||||
<view class="card_row">
|
||||
<view v-if="workOrderDetail.orderType === 1 || workOrderDetail.orderType === 4" class="card_row">
|
||||
<view class="card_row_key">
|
||||
信号强度
|
||||
故障部位
|
||||
</view>
|
||||
<view class="card_row_value">
|
||||
30%
|
||||
{{ translateErrorCode(workOrderDetail.parts, 'inventory_type') }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -84,10 +144,15 @@ function findCar() {
|
||||
<view class="bottom-button-zaping">
|
||||
<uv-button
|
||||
type="primary"
|
||||
text="btnConfig.btnText"
|
||||
text="接单"
|
||||
:loading="btnConfig.loading"
|
||||
:loading-text="btnConfig.loadingText"
|
||||
@click="acceptWorkOrder"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<!-- 弹窗 -->
|
||||
</z-paging>
|
||||
</template>
|
||||
|
||||
|
||||
@ -32,7 +32,7 @@ const btnList = ref([
|
||||
{
|
||||
key: 'picking',
|
||||
name: '领料',
|
||||
path: '/pages-sub/warehouse/addCenterControl/addCenterControl',
|
||||
path: '/pages-sub/warehouse/materialRequisition/materialRequisition',
|
||||
customsrc: 'dianchi1',
|
||||
},
|
||||
{
|
||||
@ -44,7 +44,7 @@ const btnList = ref([
|
||||
{
|
||||
key: 'faultreport',
|
||||
name: '故障上报',
|
||||
path: '/pages/devops/faultreport/faultreport',
|
||||
path: '/pages-sub/warehouse/faultReporting/faultReporting',
|
||||
customsrc: 'guzhangshangbao',
|
||||
},
|
||||
{
|
||||
|
||||
119
src/pages/myWorkOrder/components/workLIstItem.vue
Normal file
119
src/pages/myWorkOrder/components/workLIstItem.vue
Normal file
@ -0,0 +1,119 @@
|
||||
<script lang="ts" setup>
|
||||
import { useAppStore } from '@/store'
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
const appStore = useAppStore()
|
||||
|
||||
function getIcon(value: string | number) {
|
||||
let icon = ''
|
||||
switch (value) {
|
||||
case 1:
|
||||
icon = 'xunjiandian'
|
||||
break
|
||||
case 2:
|
||||
icon = 'huandianjilu'
|
||||
break
|
||||
case 3:
|
||||
icon = 'yingjitiaodu'
|
||||
break
|
||||
case 4:
|
||||
icon = 'weixiu1'
|
||||
break
|
||||
default:
|
||||
icon = ''
|
||||
break
|
||||
}
|
||||
return icon
|
||||
}
|
||||
|
||||
function goDetail() {
|
||||
uni.navigateTo({
|
||||
url: `/pages-sub/work/inspectionWorkOrder/inspectionWorkOrder`,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="container" @click="goDetail">
|
||||
<view style="margin-right: 5rpx;" class="icon_bar">
|
||||
<uv-icon
|
||||
:name="getIcon(props.data?.orderType)"
|
||||
custom-prefix="custom-icon"
|
||||
size="20"
|
||||
color="#ffffff"
|
||||
/>
|
||||
</view>
|
||||
<!-- 信息 -->
|
||||
<view class="info">
|
||||
<view class="title">
|
||||
{{ appStore.translateDictValue(props.data?.orderType, 'orderType') || '--' }}
|
||||
</view>
|
||||
<view class="location text-ellipsis-2">
|
||||
<!-- TUDO: 地址 -->
|
||||
</view>
|
||||
<view class="info-item">
|
||||
车辆编号:
|
||||
<text style="color: #1f7ff5;"> {{ props.data.bikeCode || '--' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
创建时间:
|
||||
<text style="color: #3a3839;">{{ props.data.createdAt || '--' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view style="margin-left: 5rpx;">
|
||||
<uv-icon name="arrow-right" size="14" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
padding: 20rpx;
|
||||
width: calc(100% - 40rpx);
|
||||
background-color: white;
|
||||
border-radius: 10rpx;
|
||||
box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.1);
|
||||
margin-bottom: 30rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.icon_bar {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
border-radius: 8rpx;
|
||||
background-color: orange;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.info {
|
||||
flex: 1; /* 占据剩余空间 */
|
||||
max-width: calc(100% - 100rpx); /* 限制最大宽度 */
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.location {
|
||||
font-size: 28rpx;
|
||||
margin-bottom: 25rpx;
|
||||
color: #a4a4a4;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
font-size: 30rpx;
|
||||
margin-bottom: 10rpx;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
260
src/pages/myWorkOrder/myWorkOrder.vue
Normal file
260
src/pages/myWorkOrder/myWorkOrder.vue
Normal file
@ -0,0 +1,260 @@
|
||||
<script lang="ts" setup>
|
||||
import { queryMyWorkOrders } from '@/api/work'
|
||||
import { useAppStore } from '@/store'
|
||||
import { systemInfo } from '@/utils/systemInfo'
|
||||
import workLIstItem from './components/workLIstItem.vue'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationStyle: 'custom',
|
||||
},
|
||||
})
|
||||
|
||||
const appStore = useAppStore()
|
||||
const list = ref<any>([])
|
||||
const tabList = ref<any>([])
|
||||
const paging = ref<any>(null)
|
||||
const queryForm = ref<any>({
|
||||
bikeCode: '',
|
||||
orderType: '',
|
||||
})
|
||||
const tabConfig = ref({
|
||||
height: 44,
|
||||
})
|
||||
|
||||
const currentIndex = ref(0)
|
||||
|
||||
function subsectionChange(index: number) {
|
||||
currentIndex.value = index
|
||||
}
|
||||
|
||||
function handleTabChange(item: any) {
|
||||
const { value } = item
|
||||
queryForm.value.orderType = value || ''
|
||||
paging.value.reload()
|
||||
}
|
||||
|
||||
async function queryList(pageNum: number, pageSize: number) {
|
||||
uni.showLoading({
|
||||
title: '加载中',
|
||||
})
|
||||
try {
|
||||
const res: any = await queryMyWorkOrders({
|
||||
pageNum,
|
||||
pageSize,
|
||||
bikeCode: queryForm.value.bikeCode,
|
||||
orderType: queryForm.value.orderType ? queryForm.value.orderType : null,
|
||||
})
|
||||
const { records } = res
|
||||
uni.hideLoading()
|
||||
paging.value.complete(records)
|
||||
}
|
||||
catch (e) {
|
||||
uni.hideLoading()
|
||||
paging.value.complete(false)
|
||||
}
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
const menuButtonInfo = uni.getMenuButtonBoundingClientRect()
|
||||
tabConfig.value.height = menuButtonInfo.height + (menuButtonInfo.top - systemInfo.statusBarHeight) * 2 + systemInfo.statusBarHeight
|
||||
|
||||
tabList.value = appStore.getDictByCode('orderType').map((item: any) => ({
|
||||
name: item.dicValueName,
|
||||
value: item.dicValue,
|
||||
}))
|
||||
tabList.value.unshift({
|
||||
name: '全部',
|
||||
value: '',
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="container">
|
||||
<view
|
||||
class="header-tabs"
|
||||
:style="{
|
||||
height: `${(tabConfig.height)}px`,
|
||||
}"
|
||||
>
|
||||
<view class="tabs">
|
||||
<view
|
||||
:class="[currentIndex === 0 ? 'tabs_active' : '']"
|
||||
@click="subsectionChange(0)"
|
||||
>
|
||||
我的工单
|
||||
</view>
|
||||
<view
|
||||
:class="[currentIndex === 1 ? 'tabs_active' : '']"
|
||||
style="margin-left: 30rpx;"
|
||||
@click="subsectionChange(1)"
|
||||
>
|
||||
工单看板
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<view class="content-wrapper">
|
||||
<view
|
||||
class="content-slide"
|
||||
:style="{
|
||||
transform: `translateX(${(-currentIndex * 100) / 2}%)`,
|
||||
transition: 'transform .3s ease-in-out',
|
||||
}"
|
||||
>
|
||||
<!-- 工单列表 -->
|
||||
<view class="content-item">
|
||||
<view
|
||||
:style="{
|
||||
height: `calc(100vh - ${tabConfig.height}px - 50px - ${systemInfo.safeAreaInsets.bottom}px)`,
|
||||
}"
|
||||
class="list_bar"
|
||||
>
|
||||
<z-paging
|
||||
ref="paging"
|
||||
v-model="list"
|
||||
:fixed="false"
|
||||
:default-page-no="Number('1')"
|
||||
:default-page-size="Number('10')"
|
||||
:auto-show-back-to-top="Boolean(true)"
|
||||
bg-color="#f3f3f3"
|
||||
@query="queryList"
|
||||
>
|
||||
<template #top>
|
||||
<view class="header_bar">
|
||||
<view class="tab_bar">
|
||||
<uv-tabs
|
||||
line-color="#ffffff"
|
||||
:active-style="{
|
||||
color: '#ffffff',
|
||||
fontWeight: 'bold',
|
||||
}"
|
||||
:item-style="{
|
||||
padding: '8px 15px',
|
||||
}"
|
||||
:inactive-style="{
|
||||
color: '#ffffff',
|
||||
fontSize: '30rpx',
|
||||
}"
|
||||
:list="tabList"
|
||||
@change="handleTabChange"
|
||||
/>
|
||||
</view>
|
||||
<view class="search_bar">
|
||||
<uv-input
|
||||
v-model="queryForm.bikeCode"
|
||||
shape="circle"
|
||||
placeholder="车牌号"
|
||||
clearable
|
||||
border="none"
|
||||
:custom-style="{
|
||||
padding: '4px',
|
||||
backgroundColor: '#f5f5f5',
|
||||
}"
|
||||
@confirm="() => {
|
||||
paging.reload()
|
||||
}"
|
||||
@clear="() => {
|
||||
queryForm.bikeCode = ''
|
||||
paging.reload()
|
||||
}"
|
||||
>
|
||||
<template #prefix>
|
||||
<uv-icon name="search" color="#bfbfbf" size="24" />
|
||||
</template>
|
||||
</uv-input>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<view class="worder_list_bar">
|
||||
<workLIstItem
|
||||
v-for="(item, index) in list"
|
||||
:key="index"
|
||||
:data="item"
|
||||
/>
|
||||
</view>
|
||||
</z-paging>
|
||||
</view>
|
||||
</view>
|
||||
<view class="content-item">
|
||||
asd1
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.header-tabs {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
background-color: #1488f5;
|
||||
|
||||
.tabs {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 30rpx;
|
||||
color: white;
|
||||
bottom: 10px;
|
||||
left: 30%;
|
||||
}
|
||||
|
||||
.tabs_active {
|
||||
font-weight: bold;
|
||||
font-size: 32rpx;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
|
||||
.content-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
||||
.content-slide {
|
||||
display: flex;
|
||||
width: max-content;
|
||||
|
||||
.content-item {
|
||||
width: 100vw; /* 或者使用 100% 如果父容器固定宽度 */
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.list_bar {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.header_bar {
|
||||
width: 100%;
|
||||
background-color: #1488f5;
|
||||
|
||||
.tab_bar {
|
||||
padding: 0 10rpx;
|
||||
width: calc(100% - 20rpx);
|
||||
}
|
||||
|
||||
.search_bar {
|
||||
padding: 0 20rpx;
|
||||
width: calc(100% - 40rpx);
|
||||
margin: 24rpx 0;
|
||||
}
|
||||
}
|
||||
|
||||
.worder_list_bar {
|
||||
padding: 20rpx;
|
||||
width: calc(100% - 40rpx);
|
||||
}
|
||||
</style>
|
||||
@ -33,15 +33,15 @@ function getIcon(value: string | number) {
|
||||
return icon
|
||||
}
|
||||
|
||||
function goDetail() {
|
||||
function goDetail(orderId: string) {
|
||||
uni.navigateTo({
|
||||
url: `/pages-sub/work/workOrderDetail/workOrderDetail`,
|
||||
url: `/pages-sub/work/workOrderDetail/workOrderDetail?orderId=${orderId}`,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="container" @click="goDetail">
|
||||
<view class="container" @click="goDetail(data.orderId)">
|
||||
<view style="margin-right: 5rpx;" class="icon_bar">
|
||||
<uv-icon
|
||||
:name="getIcon(props.data?.orderType)"
|
||||
|
||||
@ -68,6 +68,10 @@ onLoad(() => {
|
||||
value: '',
|
||||
})
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
paging.value.reload()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -85,13 +89,13 @@ onLoad(() => {
|
||||
>
|
||||
工单列表
|
||||
</view>
|
||||
<view
|
||||
<!-- <view
|
||||
:class="[currentIndex === 1 ? 'tabs_active' : '']"
|
||||
style="margin-left: 30rpx;"
|
||||
@click="subsectionChange(1)"
|
||||
>
|
||||
工单看板
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@ -200,7 +204,7 @@ onLoad(() => {
|
||||
font-size: 30rpx;
|
||||
color: white;
|
||||
bottom: 10px;
|
||||
left: 30%;
|
||||
left: 40%;
|
||||
}
|
||||
|
||||
.tabs_active {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -72,12 +72,22 @@ export const customTabbarList: CustomTabBarItem[] = [
|
||||
// badge: 'dot',
|
||||
},
|
||||
{
|
||||
text: '工单',
|
||||
text: '工单大厅',
|
||||
pagePath: 'pages/workOrderList/workOrderList',
|
||||
// 注意 unocss 图标需要如下处理:(二选一)
|
||||
// 1)在fg-tabbar.vue页面上引入一下并注释掉(见tabbar/index.vue代码第2行)
|
||||
// 2)配置到 unocss.config.ts 的 safelist 中
|
||||
iconType: 'unocss',
|
||||
icon: 'i-carbon-screen',
|
||||
// badge: 'dot',
|
||||
},
|
||||
{
|
||||
text: '工单任务',
|
||||
pagePath: 'pages/myWorkOrder/myWorkOrder',
|
||||
// 注意 unocss 图标需要如下处理:(二选一)
|
||||
// 1)在fg-tabbar.vue页面上引入一下并注释掉(见tabbar/index.vue代码第2行)
|
||||
// 2)配置到 unocss.config.ts 的 safelist 中
|
||||
iconType: 'unocss',
|
||||
icon: 'i-carbon-task-tools',
|
||||
// badge: 'dot',
|
||||
},
|
||||
|
||||
22
src/uni_modules/you-touchbox/changelog.md
Normal file
22
src/uni_modules/you-touchbox/changelog.md
Normal file
@ -0,0 +1,22 @@
|
||||
## 1.1.0(2022-03-15)
|
||||
新增禁用滑动 disable 属性
|
||||
## 1.0.9(2022-03-14)
|
||||
新增get-end-detail事件,获取滑动结束时的top信息对象
|
||||
## 1.0.8(2022-03-11)
|
||||
更新了setBottom手动设置上拉框高度方法,通过this.$refs.上拉框.setBottom调用
|
||||
## 1.0.7(2022-03-09)
|
||||
对nvue做了些兼容处理,但存在transition失效问题,使用nvue时建议关闭自动复位
|
||||
## 1.0.6(2022-03-04)
|
||||
-
|
||||
## 1.0.5(2022-03-04)
|
||||
更新了适配自定义navbar、tabbar的解决方案,通过customSafeArea属性设置自定义的安全高度
|
||||
## 1.0.4(2022-03-03)
|
||||
因为组件是从项目中抽离出来的,而项目中使用的是自定义navbar,以至于这插件有极大的问题,这次更新将组件的基准改为了uniapp原生navbar,之后的更新会兼容自定义navbar的情况
|
||||
## 1.0.3(2022-03-03)
|
||||
-
|
||||
## 1.0.2(2022-03-03)
|
||||
删掉日志打印
|
||||
## 1.0.1(2022-03-03)
|
||||
修复了首次上传因粗心大意导致的bug
|
||||
## 1.0.0(2022-03-03)
|
||||
首次上传,只有最基本的功能
|
||||
@ -0,0 +1,244 @@
|
||||
<template>
|
||||
<view class="you-touchbox" :class="{touchend:isTouchEnd}" @touchstart="onTouchStart"
|
||||
@touchmove.stop.prevent="onTouchmove" @touchend="onTouchend"
|
||||
:style="{top: top + distance + 'px',zIndex,height:windowHeight+'px'}">
|
||||
<view class="you-touchbox-content" :style="customStyle" @click.stop.prevent>
|
||||
<view class="touch-line-box">
|
||||
<view class="touch-line"></view>
|
||||
</view>
|
||||
<slot></slot>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* @author youbolin @2022-3-2 18:29
|
||||
*/
|
||||
export default {
|
||||
name: "you-touchbox",
|
||||
props: {
|
||||
// 禁用滑动
|
||||
disable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
zIndex: {
|
||||
type: [Number, String],
|
||||
default: 100
|
||||
},
|
||||
// 自定义样式
|
||||
customStyle: [String, Object],
|
||||
// 自定义安全区域
|
||||
customSafeArea: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {
|
||||
h5Top: null,
|
||||
wxTop: null,
|
||||
bottom: null
|
||||
}
|
||||
}
|
||||
},
|
||||
// 最高top
|
||||
maxTop: {
|
||||
type: [Number, String],
|
||||
default: 1
|
||||
},
|
||||
// 最低top
|
||||
minTop: {
|
||||
type: [Number, String],
|
||||
default: 0.5
|
||||
},
|
||||
// 初始top
|
||||
initTop: {
|
||||
type: [Number, String],
|
||||
default: 'min'
|
||||
},
|
||||
// 自动复位
|
||||
auto: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 最高最低限制
|
||||
limit: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
windowHeight: null, // 可使用区域高度
|
||||
windowTop: null,
|
||||
touchStartY: null, // 开始滑动时的Y轴坐标
|
||||
top: null, // 上拉框top
|
||||
max: null, // maxTop
|
||||
min: null, // minTop
|
||||
distance: 0, // 滑动距离
|
||||
isTouchEnd: false, // 是否滑动结束Flag
|
||||
boundary: null, // 规定盒子复位为最大或最小状态的分界线,默认为最大最小状态的中间
|
||||
startTime: null, // 开始滑动时间
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
let {
|
||||
windowHeight, // 可使用窗口高度
|
||||
windowTop // 可使用窗口的顶部位置
|
||||
} = uni.getSystemInfoSync()
|
||||
this.windowHeight = windowHeight
|
||||
this.windowTop = windowTop
|
||||
let {
|
||||
h5Top,
|
||||
wxTop,
|
||||
bottom
|
||||
} = this.customSafeArea
|
||||
// H5自定义安全区域
|
||||
// #ifndef MP
|
||||
if (h5Top) {
|
||||
this.windowHeight -= h5Top
|
||||
windowTop += h5Top
|
||||
}
|
||||
// #endif
|
||||
if (bottom) this.windowHeight -= bottom
|
||||
// 上拉框最大高度top
|
||||
if (this.maxTop <= 1) this.max = this.windowHeight * (1 - +this.maxTop)
|
||||
else this.max = +this.maxTop
|
||||
// 上拉框最小高度top
|
||||
if (this.minTop <= 1) this.min = this.windowHeight * (1 - +this.minTop)
|
||||
else this.min = this.windowHeight - (+this.minTop)
|
||||
// 初始的上拉框top
|
||||
if (['min', 'max'].includes(this.initTop)) this.top = this.initTop === 'min' ? this.min : this.max
|
||||
else if (this.initTop <= 1) this.top = this.windowHeight * (1 - +this.initTop)
|
||||
else this.top = +this.initTop
|
||||
// 微信自定义安全区域
|
||||
// #ifdef MP
|
||||
if (wxTop) {
|
||||
this.max += wxTop === 'menuBtn' ? uni.getMenuButtonBoundingClientRect().bottom + 10 : wxTop
|
||||
this.top += wxTop
|
||||
}
|
||||
// #endif
|
||||
// H5自定义安全区域
|
||||
// #ifndef MP
|
||||
this.max += windowTop
|
||||
this.min += windowTop
|
||||
this.top += windowTop
|
||||
// #endif
|
||||
this.boundary = (this.max + this.min) / 2 // 规定盒子复位为最大或最小状态的分界线,默认为最大最小状态的中间
|
||||
},
|
||||
methods: {
|
||||
setBottom(value) {
|
||||
if (this.auto) this.isTouchEnd = true
|
||||
if (value <= 1) this.top = this.windowHeight * (1 - +value)
|
||||
else this.top = (this.windowHeight - +value)
|
||||
// #ifndef MP
|
||||
this.top += this.windowTop
|
||||
// #endif
|
||||
},
|
||||
onTouchStart(e) {
|
||||
if (this.disable) return
|
||||
this.isTouchEnd = false // 关闭滑动结束Flag,作用为是否开启上拉框的过渡效果
|
||||
// #ifndef APP-NVUE
|
||||
this.top = e.currentTarget.offsetTop // 手指触碰到上拉框时,将上拉框top设置为上拉框当前的top
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
this.touchStartY = e.touches[0].screenY // 此次滑动开始时的Y轴坐标
|
||||
// #endif
|
||||
// #ifndef APP-NVUE
|
||||
this.touchStartY = e.touches[0].clientY // 此次滑动开始时的Y轴坐标
|
||||
// #endif
|
||||
this.startTime = Date.now() // 设置滑动开始时间
|
||||
},
|
||||
onTouchmove(e) {
|
||||
if (this.disable) return
|
||||
// #ifdef APP-NVUE
|
||||
let distance = e.touches[0].screenY - this.touchStartY // 滑动的距离
|
||||
// #endif
|
||||
// #ifndef APP-NVUE
|
||||
let distance = e.touches[0].clientY - this.touchStartY // 滑动的距离
|
||||
// #endif
|
||||
if (this.limit) { // 是否开启高度限制
|
||||
let nowTop = this.top + distance // 此次滑动的上拉框top值
|
||||
if (nowTop < this.max || nowTop > this.min) {
|
||||
// 如果滑动时上拉框top小于最大高度top就让上拉框top等于最大高度top
|
||||
// 如果滑动时上拉框top大于最小高度top就让上拉框top等于最小高度top
|
||||
this.top = nowTop < this.max ? this.max : this.min
|
||||
this.distance = 0 // 滑动距离归零
|
||||
// #ifdef APP-NVUE
|
||||
this.touchStartY = e.touches[0].screenY // 此次滑动开始时的Y轴坐标
|
||||
// #endif
|
||||
// #ifndef APP-NVUE
|
||||
this.touchStartY = e.touches[0].clientY // 此次滑动开始时的Y轴坐标
|
||||
// #endif
|
||||
return
|
||||
}
|
||||
}
|
||||
this.distance = distance // 更新滑动距离
|
||||
},
|
||||
onTouchend(e) {
|
||||
if (this.disable) return
|
||||
this.top = this.top + this.distance // 更新上拉框top
|
||||
if (this.auto) { // 是否开启自动复位
|
||||
this.isTouchEnd = true // 开启滑动结束Flag
|
||||
let time = (Date.now() - this.startTime) / 1000 // 滑动时间为 滑动结束时间 - 滑动开始时间
|
||||
let speed = Math.abs(this.distance) / time // 滑动速度为 滑动距离/滑动时间
|
||||
if (speed > 800) { // 如果速度大于800px/秒
|
||||
this.top = this.distance > 0 ? this.min : this.max // 根据滑动方向设置top的值
|
||||
// return this.distance = 0 // 滑动距离归零
|
||||
} else {
|
||||
|
||||
if (this.top < this.boundary) this.top = this.max // 如果上拉框top小于分界线就让上拉框top等于最大高度top
|
||||
else this.top = this.min // 如果上拉框top大于分界线就让上拉框top等于最小高度top
|
||||
}
|
||||
}
|
||||
// 滑动结束时top信息
|
||||
this.$emit('get-end-detail', {
|
||||
minTop: this.min,
|
||||
maxTop: this.max,
|
||||
curTop: this.top
|
||||
})
|
||||
this.distance = 0 // 滑动距离归零
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.you-touchbox {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.touchend {
|
||||
transition-property: top;
|
||||
transition-duration: .6s;
|
||||
}
|
||||
|
||||
.you-touchbox-content {
|
||||
/* #ifdef APP-NVUE */
|
||||
flex: 1;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
height: 100%;
|
||||
/* #endif */
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
|
||||
.touch-line-box {
|
||||
padding: 5px 0 10px;
|
||||
/* #ifdef APP-NVUE */
|
||||
align-items: center;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.touch-line {
|
||||
/* #ifndef APP-NVUE */
|
||||
margin: 0 auto;
|
||||
/* #endif */
|
||||
width: 45px;
|
||||
height: 5px;
|
||||
border-radius: 25px;
|
||||
background: rgba(51, 51, 51, 0.2);
|
||||
}
|
||||
</style>
|
||||
83
src/uni_modules/you-touchbox/package.json
Normal file
83
src/uni_modules/you-touchbox/package.json
Normal file
@ -0,0 +1,83 @@
|
||||
{
|
||||
"id": "you-touchbox",
|
||||
"displayName": "上拉框,上下滑动框",
|
||||
"version": "1.1.0",
|
||||
"description": "上拉框,滑动框,丝滑体验,只在H5和小程序以及vue上测试过,其他未测试",
|
||||
"keywords": [
|
||||
"上拉",
|
||||
"上拉框",
|
||||
"滑动",
|
||||
"滑动框"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.1.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"category": [
|
||||
"前端组件",
|
||||
"通用组件"
|
||||
],
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "u"
|
||||
},
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "u",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "u"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "u",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "u"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "u",
|
||||
"百度": "u",
|
||||
"字节跳动": "u",
|
||||
"QQ": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
41
src/uni_modules/you-touchbox/readme.md
Normal file
41
src/uni_modules/you-touchbox/readme.md
Normal file
@ -0,0 +1,41 @@
|
||||
# you-touchbox
|
||||
|
||||
对nvue做了些兼容处理,但还不成熟,nvue下transition失效的问题无法解决,请大佬指点(现阶段不建议在nvue中使用本插件,问题多多,nvue中遇到问题可以反馈,我尽力实现需求)
|
||||
|
||||
***所有像素值参数都不要传单位**
|
||||
|
||||
***一切计算以`可使用窗口高度`为基准**,即`uni.getSystemInfoSync().windowHeight`
|
||||
|
||||
***上拉框盒子高度默认为`可使用窗口高度`**,可以通过`customStyle`属性设置
|
||||
|
||||
**属性**
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| -------------- | :----------------------- | ---------------------------------- | ------------------------------------------------------------ |
|
||||
| customStyle | 自定义样式 | String\|Object | -<br />border-radius若要兼容nvue请使用<br />border-top-left-radius,border-top-right-radius分开写 |
|
||||
| initTop | 初始top值 | Number\|String\|<br />'min'\|'max' | 默认值为'min',<br />initTop为首次加载时,上拉框显示的高度,<br />所以一般设置为与maxTop或minTop一致,<br />参数可传百分比,像素值,字符串'min''max'<br />max为与maxTop一致,<br />min为与minTop一致<br />0~1为百分比,大于1为像素值,<br />百分比以可使用窗口高度计算,<br />像素值为可使用窗口的顶部位置往下偏移 |
|
||||
| maxTop | 最高top值 | Numbe\|String | 默认为可使用窗口的顶部位置,<br />参数可传百分比和像素值,<br />0~1为百分比,大于1为像素值,<br />百分比以可使用窗口高度计算,<br />像素值为可使用窗口的顶部位置往下偏移 |
|
||||
| minTop | 最低top值 | Number\|String | 默认为可用区域50%,<br />参数可传百分比和像素值,<br />0~1为百分比,大于1为像素值,<br />百分比以可使用窗口高度计算,<br />像素值为可使用窗口的底部位置往上的偏移 |
|
||||
| auto | 是否开启自动复位 | Boolean | true,开启时松手会自动复位到最高最低状态 |
|
||||
| limit | 是否开启滑动范围限制 | Boolean | true,开启时滑动范围不可超过maxTop和minTop |
|
||||
| customSafeArea | 自定义navbar、tabbar高度 | Object | 如果使用了自定义navbar和tabbar,可以手动设置安全区域 |
|
||||
| h5Top | customSafeArea的属性 | Number | -<br />H5的自定义navbar高度 |
|
||||
| mpTop | customSafeArea的属性 | Number\|'menuBtn' | -<br />小程序的自定义navbar高度<br />特殊值字符串menuBtn的效果为微信小程序原生navbar的高度<br /> |
|
||||
| bottom | customSafeArea的属性 | Number | -<br />自定义tabbar高度<br />因为H5和小程序的navbar高度不一致才需要分开配置,而tabbar一般是一致的,所以不区分 |
|
||||
| zIndex | 上拉框z-index | Number\|String | 100 |
|
||||
| disable | 禁用滑动 | Boolean | false |
|
||||
|
||||
**事件**
|
||||
|
||||
| 事件名 | 说明 | 参数 |
|
||||
| -------------- | ------------------------------------------------------------ | -------------------------------- |
|
||||
| get-end-detail | 获取滑动结束时top信息对象<br />maxTop:最大高度top<br />minTop:最小高度top<br />curTop:当前高度top | Function({maxTop,minTop,curTop}) |
|
||||
|
||||
**方法**
|
||||
|
||||
此方法要通过ref手动改调用
|
||||
|
||||
| 方法名 | 说明 | 参数 |
|
||||
| --------- | ------------------------------------------------------------ | ----------------- |
|
||||
| setBottom | 手动设置上拉框高度,参数值传百分比和像素值(不带单位),<br />百分比以可使用窗口高度计算,<br />像素值为可使用窗口的底部位置往上的偏移 | Function(value) |
|
||||
|
||||
@ -149,3 +149,56 @@ export function getRoutePlan({
|
||||
|
||||
mapsdk.getDrivingRoute(options)
|
||||
}
|
||||
|
||||
/**
|
||||
* 逆解析地址
|
||||
* @param {object} options
|
||||
* @param {object} options.mapsdk - 地图对象
|
||||
* @param {number} options.longitude - 经度
|
||||
* @param {number} options.latitude - 纬度
|
||||
* @param {Function} options.success - 成功回调
|
||||
* @param {Function} options.fail - 失败回调
|
||||
*/
|
||||
|
||||
export function reverseGeocoder({
|
||||
mapsdk,
|
||||
longitude,
|
||||
latitude,
|
||||
success,
|
||||
fail,
|
||||
}: {
|
||||
mapsdk: any
|
||||
longitude: number
|
||||
latitude: number
|
||||
success: (data: any) => void
|
||||
fail: (error: any) => void
|
||||
}) {
|
||||
if (!mapsdk) {
|
||||
console.error('请传入地图sdk')
|
||||
fail && fail('请传入地图sdk')
|
||||
return
|
||||
}
|
||||
|
||||
if (!longitude || !latitude) {
|
||||
console.error('请传入经纬度')
|
||||
fail && fail('请传入经纬度')
|
||||
return
|
||||
}
|
||||
mapsdk.getRegeo({
|
||||
location: `${longitude},${latitude}`,
|
||||
success(res: any) {
|
||||
console.log(res)
|
||||
const { desc, regeocodeData, latitude, longitude } = res[0]
|
||||
success && success({
|
||||
desc,
|
||||
regeocodeData,
|
||||
latitude,
|
||||
longitude,
|
||||
})
|
||||
},
|
||||
fail(err: any) {
|
||||
console.log(err, '地理位置信息失败')
|
||||
fail && fail(err)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import CacheManager from './CacheManager'
|
||||
|
||||
/**
|
||||
* 扫码获取结果
|
||||
* @param {boolean} options.isBikeCode - 是否为单车码
|
||||
@ -31,3 +33,30 @@ export function scanCode({ isSN = false, success, fail }) {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 翻译数组类型数据
|
||||
* @param list
|
||||
* @param code
|
||||
*/
|
||||
export function translateErrorCode(list: any[], code: string) {
|
||||
const dicList = CacheManager.get('dictData')
|
||||
let str = ''
|
||||
if (Array.isArray(dicList) && dicList.length > 0) {
|
||||
const codeList = dicList.find(item => item.dicCode === code)
|
||||
console.log(codeList)
|
||||
|
||||
if (Array.isArray(list) && list.length > 0) {
|
||||
list.forEach((item) => {
|
||||
const codeItem = codeList.values.find(codeItem => codeItem.dicValue === item.orderPart.toString())?.dicValueName
|
||||
if (codeItem) {
|
||||
console.log(codeItem)
|
||||
str += `${codeItem} | `
|
||||
}
|
||||
})
|
||||
return str.substring(0, str.length - 2)
|
||||
}
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ export default defineConfig({
|
||||
},
|
||||
],
|
||||
// 动态图标需要在这里配置,或者写在vue页面中注释掉
|
||||
safelist: ['i-carbon-code', 'i-carbon-home', 'i-carbon-user', 'i-carbon-task-tools'],
|
||||
safelist: ['i-carbon-code', 'i-carbon-home', 'i-carbon-user', 'i-carbon-task-tools', 'i-carbon-screen'],
|
||||
rules: [
|
||||
[
|
||||
'p-safe',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user