Merge pull request 'dev' (#2) from dev into main

Reviewed-on: #2
This commit is contained in:
yrk 2026-02-28 07:44:47 +00:00
commit d1942ac19e
6 changed files with 614 additions and 0 deletions

28
src/api/order-manage.ts Normal file
View File

@ -0,0 +1,28 @@
import { http } from '@/http/http'
/**
* @description
* @param query
* @returns
*/
export function getOrderManageListApi(query: { pageNum: number, pageSize: number }) {
return http.get<any>('/operations/statistics/getDiffOperatorOrderList', query)
}
/**
* @description
* @param data
* @returns
*/
export function changePriceApi(data: { bikeCode: string, price: number }) {
return http.post<any>('/operations/statistics/updateOrderAmount', data)
}
/**
* @description
* @param data
* @returns
*/
export function lockBikeApi(data: { bikeCode: string }) {
return http.post<any>('/operations/statistics/closeOrder', data)
}

View File

@ -81,6 +81,13 @@ export const menu_list = [
},
],
},
{
key: 'orderManagement',
name: '工单管理',
type: 'page',
path: '/pages-sub/order-manage/index',
customsrc: 'APPICON_ZHANDIANGUANLI_IMAGE',
},
],
},
{

View File

@ -0,0 +1,176 @@
<template>
<z-paging>
<template #top>
<view class="custom_navbar" :style="{ height: `${systemInfo.statusBarHeight + 44}px` }">
<view class="back_bar">
<uv-icon name="arrow-left" color="white" size="24" @click="handleBack" />
<text class="text">工单管理-修改价格</text>
</view>
</view>
</template>
<view class="container">
<view class="map_container">
<map-exhibition
:map-location="{
latitude: bikeDetails.location?.latitude,
longitude: bikeDetails.location?.longitude,
}"
/>
</view>
<uni-card>
<uv-form ref="form" label-position="left" :model="formData" :rules="rules" :label-width="90" :label-style="labelStyle">
<uv-form-item label="车辆编号:" border-bottom>
{{ routeQuery.bikeCode }}
</uv-form-item>
<uv-form-item label="订单编号:" border-bottom>
{{ routeQuery.orderId }}
</uv-form-item>
<uv-form-item label="实付金额:" border-bottom>
{{ routeQuery.actualAmount }}
</uv-form-item>
<uv-form-item label="修改金额:" prop="price" border-bottom>
<uv-input
v-model="formData.price"
type="number"
placeholder="请输入修改金额"
/>
</uv-form-item>
</uv-form>
</uni-card>
</view>
<template #bottom>
<view class="bottom-button-zaping">
<uv-button
type="primary"
:text="btnConfig.btnText"
:loading="btnConfig.btnLoading"
:loading-text="btnConfig.btnLoadingText"
:custom-style="{
backgroundImage: `linear-gradient(135deg, #1089FF 0%, #0F5BFF 100%)`,
borderRadius: '28rpx',
height: '100rpx',
}"
:custom-text-style="{
fontSize: '32rpx',
marginLeft: '8rpx',
}"
@click="submitForm"
/>
</view>
</template>
</z-paging>
</template>
<script setup lang="ts">
import { onLoad } from '@dcloudio/uni-app'
import { getEbikeDetailForWorkAPI } from '@/api/operator'
import { changePriceApi } from '@/api/order-manage'
import MapExhibition from '@/components/mapExhibition/mapExhibition.vue'
import { systemInfo } from '@/utils/systemInfo'
definePage({
style: {
navigationStyle: 'custom',
},
})
//
function handleBack() {
uni.navigateBack()
}
const formData = reactive({
bikeCode: '',
price: null,
})
const rules = {
price: {
type: 'number',
required: true,
message: '请输入修改金额',
trigger: 'blur',
},
}
const labelStyle = {
padding: '0 5px 0 0',
color: '#7c7c7c',
fontSize: '14px',
fontWeight: 'normal',
lineHeight: '32px',
}
const btnConfig = reactive({
btnText: '提交',
btnLoading: false,
btnLoadingText: '正在提交',
})
const bikeDetails = ref<any>({})
const routeQuery = ref<any>({})
onLoad(async (options) => {
const data = JSON.parse(decodeURIComponent(options.data))
routeQuery.value = data
formData.bikeCode = data.bikeCode
bikeDetails.value = await getBikeDetails(data.bikeCode)
console.log(bikeDetails.value, 'bikeDetails.value')
})
const form = ref<any>(null)
async function submitForm() {
await form.value.validate()
try {
await changePriceApi(formData)
uni.showToast({
title: '提交成功',
icon: 'success',
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
catch (e) {
uni.showToast({
title: e.message || '提交失败',
icon: 'none',
})
}
finally {
btnConfig.btnLoading = false
}
}
async function getBikeDetails(bikeCode: string) {
return await getEbikeDetailForWorkAPI(bikeCode)
}
</script>
<style lang="scss" scoped>
.custom_navbar {
width: 100%;
position: relative;
background-color: #0f74ff;
.back_bar {
display: flex;
align-items: center;
position: absolute;
bottom: 25rpx;
left: 30rpx;
.text {
font-family: SourceHanSansCN-Medium;
font-size: 34rpx;
color: white;
letter-spacing: 0;
font-weight: 500;
}
}
}
.container {
width: 100%;
.map_container {
position: relative;
width: 100%;
height: 40vh;
}
}
</style>

View File

@ -0,0 +1,247 @@
<script setup lang="ts">
import { getOrderManageListApi } from '@/api/order-manage'
import { useOperatorStore } from '@/store'
import { systemInfo } from '@/utils/systemInfo'
definePage({
style: {
navigationStyle: 'custom',
},
})
function handleBack() {
uni.navigateBack()
}
const paging = ref<any>(null)
const orderList = ref([])
const query = ref({
bikeCode: '',
})
async function queryOrderList(pageNum: number, pageSize: number) {
try {
uni.showLoading({
title: '加载中',
})
const { records } = await getOrderManageListApi({
...query.value,
pageNum,
pageSize,
})
uni.hideLoading()
paging.value.complete(records)
}
catch (e) {
uni.hideLoading()
paging.value.complete(false)
}
}
function handleSearch() {
paging.value.reload()
}
const operatorStore = useOperatorStore()
const operatorAllList = ref<any>([])
onMounted(async () => {
operatorAllList.value = await operatorStore.getOperatorList()
})
function changePrice(row) {
uni.navigateTo({
url: `/pages-sub/order-manage/change-price?data=${encodeURIComponent(JSON.stringify(row))}`,
})
}
function lockBike(row) {
uni.navigateTo({
url: `/pages-sub/order-manage/remove-locking?data=${encodeURIComponent(JSON.stringify(row))}`,
})
}
onShow(() => {
handleSearch()
})
</script>
<template>
<z-paging
ref="paging"
v-model="orderList"
bg-color="#f3f3f3"
:default-page-no="Number('1')"
:default-page-size="Number('10')"
:auto-show-back-to-top="Boolean(true)"
@query="queryOrderList"
>
<template #top>
<view class="custom_navbar" :style="{ height: `${systemInfo.statusBarHeight + 44}px` }">
<view class="back_bar">
<uv-icon name="arrow-left" color="white" size="24" @click="handleBack" />
<text class="text">工单管理</text>
</view>
</view>
<view class="search_bar">
<uv-search
v-model="query.bikeCode"
:show-action="false"
bg-color="white"
placeholder="请输入车辆编号"
@search="handleSearch"
/>
</view>
</template>
<view class="container">
<view class="list-panel">
<view
v-for="(item) in orderList"
:key="item.orderId"
>
<view class="card">
<view class="header">
<view class="title">
<view>{{ item.bikeCode }}</view>
</view>
</view>
<view class="body">
<view class="row">
<view class="text">
<view>订单编号{{ item.orderId }}</view>
</view>
</view>
<view class="row">
<view class="text">
<view>运营商{{ operatorStore.translateOperatorId(item.operatorId, operatorAllList) }}</view>
</view>
</view>
<view class="row">
<view class="text">
<view>实付金额{{ item.actualAmount }}</view>
</view>
</view>
</view>
<view class="footer">
<uv-button
type="primary"
:custom-style="{
backgroundImage: `linear-gradient(226deg, #3C9CFE 0%, #067AF2 100%)`,
borderRadius: '26rpx',
height: '70rpx',
width: '180rpx',
}"
:custom-text-style="{
fontSize: '26rpx',
marginLeft: '8rpx',
}"
text="修改价格"
@click="changePrice(item)"
/>
<uv-button
type="primary"
:custom-style="{
backgroundImage: `linear-gradient(226deg, #3C9CFE 0%, #067AF2 100%)`,
borderRadius: '26rpx',
height: '70rpx',
width: '180rpx',
}"
:custom-text-style="{
fontSize: '26rpx',
marginLeft: '8rpx',
}"
text="远程锁车"
@click="lockBike(item)"
/>
</view>
</view>
</view>
</view>
</view>
</z-paging>
</template>
<style lang="scss" scoped>
.custom_navbar {
width: 100%;
position: relative;
background-color: #0f74ff;
.back_bar {
display: flex;
align-items: center;
position: absolute;
bottom: 25rpx;
left: 30rpx;
.text {
font-family: SourceHanSansCN-Medium;
font-size: 34rpx;
color: white;
letter-spacing: 0;
font-weight: 500;
}
}
}
.container {
& .list-panel {
padding: 10px 5px 0px 0px;
width: 100%;
& .card {
padding: 10px;
margin: 10px;
border-radius: 26rpx;
background-color: #fff;
box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.04);
& .header {
margin-bottom: 30rpx;
.title {
font-family: PingFangSC-Semibold;
font-size: 30rpx;
color: #333333;
letter-spacing: 0;
font-weight: 600;
margin: 0 25rpx 0 10rpx;
}
}
& .body {
& .row {
width: 100%;
display: flex;
align-items: center;
margin-bottom: 16rpx;
.icon {
width: 46rpx;
height: 40rpx;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.text {
margin-left: 16rpx;
transform: translateY(4rpx);
font-family: PingFangSC-Regular;
font-size: 26rpx;
color: #999999;
letter-spacing: 0;
font-weight: 400;
}
}
}
& .footer {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 4px;
}
}
}
}
.search_bar {
width: calc(100% - 40rpx);
padding: 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
background-color: #0f73ff;
}
</style>

View File

@ -0,0 +1,155 @@
<template>
<z-paging>
<template #top>
<view class="custom_navbar" :style="{ height: `${systemInfo.statusBarHeight + 44}px` }">
<view class="back_bar">
<uv-icon name="arrow-left" color="white" size="24" @click="handleBack" />
<text class="text">工单管理-远程锁车</text>
</view>
</view>
</template>
<view class="container">
<view class="map_container">
<map-exhibition
:map-location="{
latitude: bikeDetails.location?.latitude,
longitude: bikeDetails.location?.longitude,
}"
/>
</view>
<uni-card>
<uv-form ref="form" label-position="left" :label-width="90" :label-style="labelStyle">
<uv-form-item label="车辆编号:" border-bottom>
{{ routeQuery.bikeCode }}
</uv-form-item>
<uv-form-item label="订单编号:" border-bottom>
{{ routeQuery.orderId }}
</uv-form-item>
</uv-form>
</uni-card>
</view>
<template #bottom>
<view class="bottom-button-zaping">
<uv-button
type="primary"
:text="btnConfig.btnText"
:loading="btnConfig.btnLoading"
:loading-text="btnConfig.btnLoadingText"
:custom-style="{
backgroundImage: `linear-gradient(135deg, #1089FF 0%, #0F5BFF 100%)`,
borderRadius: '28rpx',
height: '100rpx',
}"
:custom-text-style="{
fontSize: '32rpx',
marginLeft: '8rpx',
}"
@click="submitForm"
/>
</view>
</template>
</z-paging>
</template>
<script setup lang="ts">
import { onLoad } from '@dcloudio/uni-app'
import { getEbikeDetailForWorkAPI } from '@/api/operator'
import { lockBikeApi } from '@/api/order-manage'
import MapExhibition from '@/components/mapExhibition/mapExhibition.vue'
import { systemInfo } from '@/utils/systemInfo'
definePage({
style: {
navigationStyle: 'custom',
},
})
//
function handleBack() {
uni.navigateBack()
}
const labelStyle = {
padding: '0 5px 0 0',
color: '#7c7c7c',
fontSize: '14px',
fontWeight: 'normal',
lineHeight: '32px',
}
const btnConfig = reactive({
btnText: '确认锁车',
btnLoading: false,
btnLoadingText: '正在锁车中...',
})
const bikeDetails = ref<any>({})
const routeQuery = ref<any>({})
onLoad(async (options) => {
const data = JSON.parse(decodeURIComponent(options.data))
routeQuery.value = data
bikeDetails.value = await getBikeDetails(data.bikeCode)
console.log(bikeDetails.value, 'bikeDetails.value')
})
async function getBikeDetails(bikeCode: string) {
return await getEbikeDetailForWorkAPI(bikeCode)
}
const form = ref<any>(null)
async function submitForm() {
await form.value.validate()
try {
await lockBikeApi({
bikeCode: routeQuery.value.bikeCode,
})
uni.showToast({
title: '提交成功',
icon: 'success',
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
catch (e) {
uni.showToast({
title: e.message || '提交失败',
icon: 'none',
})
}
finally {
btnConfig.btnLoading = false
}
}
</script>
<style lang="scss" scoped>
.custom_navbar {
width: 100%;
position: relative;
background-color: #0f74ff;
.back_bar {
display: flex;
align-items: center;
position: absolute;
bottom: 25rpx;
left: 30rpx;
.text {
font-family: SourceHanSansCN-Medium;
font-size: 34rpx;
color: white;
letter-spacing: 0;
font-weight: 500;
}
}
}
.container {
width: 100%;
.map_container {
position: relative;
width: 100%;
height: 60vh;
}
}
</style>

View File

@ -27,6 +27,7 @@ function handleClickBulge() {
}
},
fail: () => {
console.log('扫码失败')
},
})
}