feat(工单管理): 新增工单编辑和详情页面及功能

添加工单编辑页面和工单详情页面,包括基础信息表单和地图功能
在工单审批页面增加新建工单按钮跳转功能
引入天地图API用于地图展示
更新页面路由配置
This commit is contained in:
liangbin 2026-01-16 11:30:52 +08:00
parent a67654d9f4
commit b55f605d6d
6 changed files with 370 additions and 5 deletions

View File

@ -5,6 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>uniapp-vue3-template</title> <title>uniapp-vue3-template</title>
<link rel="icon" href="/favicon.ico"> <link rel="icon" href="/favicon.ico">
<script type="text/javascript" src="https://api.tianditu.gov.cn/api?v=4.0&tk=627214536ffef28d296fab6a9578679e"></script>
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

View File

@ -14,6 +14,20 @@
"enablePullDownRefresh": true "enablePullDownRefresh": true
} }
}, },
{
"path": "pages/WorkOrderEdit/index",
"style": {
"navigationBarTitleText": "工单编辑",
"navigationStyle": "custom"
}
},
{
"path": "pages/WorkOrderDetails/index",
"style": {
"navigationBarTitleText": "工单详情",
"navigationStyle": "custom"
}
},
{ {
"path": "pages/ProjectList/index", "path": "pages/ProjectList/index",
"style": { "style": {

View File

@ -7,7 +7,7 @@
@update:current="TypeValue = $event"></u-select> @update:current="TypeValue = $event"></u-select>
</view> </view>
<view class="BtnBox"> <view class="BtnBox">
<u-button type="primary" text="查询">新建工单</u-button> <u-button type="primary" text="查询" @click="HandleNewAdd">新建工单</u-button>
</view> </view>
@ -22,10 +22,12 @@
</view> </view>
<view class="CodeTxt">项目编号{{ item.projectCode }}</view> <view class="CodeTxt">项目编号{{ item.projectCode }}</view>
<view class="TagBox"> <view class="TagBox">
<up-tag text="代填工作票" plain shape="circle"></up-tag> <u-tag text="代填工作票" shape="circle"></u-tag>
</view> </view>
<view class="BtnBox"> <view class="BtnList">
<up-tag text="代填工作票" plain shape="circle"></up-tag> <u-button text="修改" plain color="#2979ff" size="small"></u-button>
<u-button text="撤回" plain color="#ff9900" size="small"></u-button>
<u-button text="删除" plain color="#fa3534" size="small"></u-button>
</view> </view>
</view> </view>
</template> </template>
@ -55,6 +57,12 @@ const dataSource = ref([
{ id: 7, name: '工单7', projectCode: '123462' }, { id: 7, name: '工单7', projectCode: '123462' },
]) ])
//
const HandleNewAdd = () => {
uni.navigateTo({
url: '/pages/WorkOrderEdit/index'
})
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -67,7 +75,7 @@ const dataSource = ref([
.PageBox { .PageBox {
padding: 20rpx; padding: 20rpx;
background-color: #fff; background-color: #fff;
height: calc(100vh - 400rpx); height: calc(100vh - 170rpx);
.TopBox { .TopBox {
.SelectBox { .SelectBox {
@ -107,6 +115,7 @@ const dataSource = ref([
margin-bottom: 20rpx; margin-bottom: 20rpx;
background-color: #fff; background-color: #fff;
border-radius: 10rpx; border-radius: 10rpx;
overflow: auto;
.Title { .Title {
font-size: 32rpx; font-size: 32rpx;
font-weight: bold; font-weight: bold;
@ -124,6 +133,13 @@ const dataSource = ref([
.TagBox { .TagBox {
margin-top: 20rpx; margin-top: 20rpx;
} }
.BtnList {
margin-top: 20rpx;
display: flex;
align-items: center;
justify-content: space-between;
gap: 20rpx;
}
} }
} }

View File

@ -0,0 +1,80 @@
<!-- 工单详情 -->
<template>
<view class="PageBox">
<view class="TopBox FlexBox">
<view class="iconBox FlexBox">
<!-- 返回上一页 -->
<u-icon name="arrow-leftward" size="24"></u-icon>
</view>
<view class="Title">工单详情</view>
<view class="informBox">
<u-icon name="bell-fill" size="24"></u-icon>
<view class="MsgTxt"></view>
</view>
</view>
<view class="ContentBox">
展示内容
</view>
<view class="FootBox">
<u-button text="撤回" type="info"></u-button>
<u-button text="提交实施" color="#2979ff"></u-button>
</view>
</view>
</template>
<style lang="scss" scoped>
.FlexBox {
display: flex;
align-items: center;
justify-content: space-between;
gap: 20rpx;
}
.PageBox {
background-color: #ff9900;
height: 100vh;
overflow: hidden;
.TopBox {
height: 100rpx;
padding: 20rpx;
background-color: #fff;
.iconBox {
font-size: 32rpx;
}
.Title{
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.informBox {
.MsgTxt{
padding: 8rpx;
background-color: hsla(17, 100%, 50%, 0.849);
color: #fff;
position: absolute;
top: 16rpx;
right: 16rpx;
border-radius: 50%;
}
}
}
.ContentBox {
padding: 20rpx;
background-color: #c5d5d6;
height: calc(100vh - 200rpx);
overflow: hidden;
}
.FootBox {
height: 100rpx;
display: flex;
align-items: center;
justify-content: space-between;
gap: 20rpx;
padding: 20rpx;
background-color: #fff;
}
}
</style>

View File

@ -0,0 +1,139 @@
<!-- 工单基础信息 -->
<template>
<view class="MainBox">
<view class="FormBox">
<view class="FormItem">
<view class="FormLableBox mustBox">项目名称</view>
<view class="FormValueBox">
<u-input v-model="formData.ProjectName" placeholder="请输入项目名称"></u-input>
</view>
</view>
<view class="FormItem">
<view class="FormLableBox mustBox">作业地点</view>
<view class="MapBox" id="tianditu-map">
</view>
<view class="FormValueBox">
<u-input v-model="formData.SpecificAddress" placeholder="请输入具体楼层或区域"></u-input>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue'
//
let mapEntity = null;
//
let currentMarker = null;
//
const formData = ref({
ProjectName: '', //
Location: '', //
SpecificAddress: '', //
})
//
onMounted(() => {
// DOM
initTiandituMap();
});
//
const initTiandituMap = () => {
try {
// 1.
const container = document.getElementById('tianditu-map');
if (!container) {
console.error('地图容器未找到');
return;
}
// 2. 12
mapEntity = new T.Map('tianditu-map');
const centerPoint = new T.LngLat(116.403874, 39.914885);
mapEntity.centerAndZoom(centerPoint, 12);
// 3.
mapEntity.enableDrag();
mapEntity.enableScrollWheelZoom();
// 4. +
const vecLayer = new T.TileLayer('vec_w', { key: '你的天地图Key' });
const cvaLayer = new T.TileLayer('cva_w', { key: '你的天地图Key' });
const layerGroup = new T.LayerGroup([vecLayer, cvaLayer]);
mapEntity.addLayer(layerGroup);
// 5.
mapEntity.addEventListener('click', (e) => {
const lng = e.lnglat.getLng();
const lat = e.lnglat.getLat();
//
if (currentMarker) {
mapEntity.removeOverLay(currentMarker);
}
//
const marker = new T.Marker(new T.LngLat(lng, lat));
mapEntity.addOverLay(marker);
currentMarker = marker;
// Location
formData.value.Location = `${lng},${lat}`;
console.log('标记点位置:', lng, lat);
});
console.log('天地图初始化成功');
} catch (error) {
console.error('天地图初始化失败:', error);
}
}
</script>
<style lang="scss" scoped>
.MainBox {
padding: 20rpx;
background-color: #fff;
height: 100%;
overflow: hidden;
}
.mustBox::after {
content: '*';
color: red;
font-size: 30rpx;
margin-left: 10rpx;
}
.MapBox {
width: 100%;
height: 400rpx;
}
.FormBox {
background-color: #f5f5f5;
height: 100%;
.FormItem {
padding: 20rpx;
background-color: #fff;
.FormLableBox {
font-size: 30rpx;
font-weight: bold;
margin-bottom: 20rpx;
}
.FormValueBox {
font-size: 30rpx;
margin-top: 20rpx;
}
}
}
</style>

View File

@ -0,0 +1,115 @@
<!-- 工单编辑-外壳 -->
<template>
<view class="PageBox">
<view class="TopBox FlexBox">
<view class="iconBox FlexBox">
<!-- 返回上一页 -->
<u-icon name="arrow-leftward" size="24"></u-icon>
<!-- 返回主页 -->
<u-icon name="home" size="24"></u-icon>
</view>
<view class="Title">工单编辑</view>
<view class="informBox">
<u-icon name="bell-fill" size="24"></u-icon>
<view class="MsgTxt"></view>
</view>
</view>
<view class="ContentBox">
<BasicsInfo :ref="basicsInfoRef"></BasicsInfo>
</view>
<view class="FootBox" v-for="item in stepList" :key="item.id">
<u-button :text="item.PrevBtnName" type="info"></u-button>
<u-button :text="item.NextBtnName" color="#2979ff" @click="nextStep"></u-button>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import BasicsInfo from './compoents/BasicsInfo.vue'
const currentStep = ref(1)//
const basicsInfoRef = ref(null); //
//
const stepList = ref([
{
id: 1,
Title: '工单基础信息',
PrevBtnName: '保存草稿',
NextBtnName: '下一步(申请出入证)',
},
{
id: 2,
Title: '出入证申请',
PrevBtnName: '返回修改',
NextBtnName: '提交+下一步(填写工作票)',
},
{
id: 3,
Title: '填写工作票',
PrevBtnName: '保存草稿',
NextBtnName: '提交工单',
},
])
//
const nextStep = () => {
console.log(basicsInfoRef.value);
}
</script>
<style lang="scss" scoped>
.FlexBox {
display: flex;
align-items: center;
justify-content: space-between;
gap: 20rpx;
}
.PageBox {
background-color: #ff9900;
height: 100vh;
overflow: hidden;
.TopBox {
height: 100rpx;
padding: 20rpx;
background-color: #fff;
.iconBox {
font-size: 32rpx;
}
.Title{
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.informBox {
.MsgTxt{
padding: 8rpx;
background-color: hsla(17, 100%, 50%, 0.849);
color: #fff;
position: absolute;
top: 16rpx;
right: 16rpx;
border-radius: 50%;
}
}
}
.ContentBox {
background-color: #c5d5d6;
height: calc(100vh - 200rpx);
overflow: hidden;
}
.FootBox {
height: 100rpx;
display: flex;
align-items: center;
justify-content: space-between;
gap: 20rpx;
padding: 20rpx;
background-color: #fff;
}
}
</style>