feat:新增功能

This commit is contained in:
5g0Wp7Zy 2025-11-27 17:00:16 +08:00
parent 1ca50d10ae
commit 9a22a2f872
25 changed files with 2181 additions and 34 deletions

View File

@ -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'
}

View File

@ -5,3 +5,10 @@ export interface WorkOrdersListType {
orderType?: string
bikeCode?: string
}
export interface createMaintainOrderType {
bikeCode: string
parts?: number[]
fileUrls?: string[]
remarks?: string
}

View File

@ -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数组下载并上传图片

View File

@ -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)
}

View 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>

View 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>

View File

@ -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>

View 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>

View File

@ -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>

View 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>

View File

@ -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>

View File

@ -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',
},
{

View 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>

View 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>

View File

@ -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)"

View File

@ -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

View File

@ -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',
},

View File

@ -0,0 +1,22 @@
## 1.1.02022-03-15
新增禁用滑动 disable 属性
## 1.0.92022-03-14
新增get-end-detail事件获取滑动结束时的top信息对象
## 1.0.82022-03-11
更新了setBottom手动设置上拉框高度方法通过this.$refs.上拉框.setBottom调用
## 1.0.72022-03-09
对nvue做了些兼容处理但存在transition失效问题使用nvue时建议关闭自动复位
## 1.0.62022-03-04
-
## 1.0.52022-03-04
更新了适配自定义navbar、tabbar的解决方案通过customSafeArea属性设置自定义的安全高度
## 1.0.42022-03-03
因为组件是从项目中抽离出来的而项目中使用的是自定义navbar以至于这插件有极大的问题这次更新将组件的基准改为了uniapp原生navbar之后的更新会兼容自定义navbar的情况
## 1.0.32022-03-03
-
## 1.0.22022-03-03
删掉日志打印
## 1.0.12022-03-03
修复了首次上传因粗心大意导致的bug
## 1.0.02022-03-03
首次上传,只有最基本的功能

View File

@ -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 // toptop
// #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) {
// toptoptoptop
// toptoptoptop
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线toptop
else this.top = this.min // top线toptop
}
}
// 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>

View 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"
}
}
}
}
}

View 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-radiusborder-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 />像素值为可使用窗口的底部位置往上的偏移 | Functionvalue |

View File

@ -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)
},
})
}

View File

@ -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
}

View File

@ -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',