This commit is contained in:
huangyaohui 2026-03-24 16:30:52 +08:00
parent 75494717df
commit ef72a21402
1 changed files with 556 additions and 45 deletions

View File

@ -11,16 +11,370 @@
<!-- 占位保持布局平衡 -->
</view>
</view>
<view class="ContentBox">
<!-- 项目基本信息 -->
<view class="PBasicBox">
<u-row justify="space-between">
<u-col span="4">
<view class="LabelBox">项目编号</view>
<view class="LabelBoxTxt">{{ projectInfo.code }}</view>
</u-col>
<u-col span="3">
<view class="LabelBox">作业负责人</view>
<view class="LabelBoxTxt">{{ projectInfo.leader }}</view>
</u-col>
<u-col span="5">
<view class="LabelBox">作业周期</view>
<view class="LabelBoxTxt">{{ projectInfo.period }}</view>
</u-col>
</u-row>
<u-row>
<u-col span="12">当前进度
<u-line-progress :percentage="projectInfo.percentage" activeColor="#55AAFF"></u-line-progress>
</u-col>
</u-row>
</view>
<!-- 相机切换 -->
<view class="CameraTabs">
<view
class="CameraTab"
:class="{ active: currentCamera === 1 }"
@click="currentCamera = 1"
>
相机 1
</view>
<view
class="CameraTab"
:class="{ active: currentCamera === 2 }"
@click="currentCamera = 2"
>
相机 2
</view>
<view
class="CameraTab"
:class="{ active: currentCamera === 3 }"
@click="currentCamera = 3"
>
相机 3
</view>
</view>
<!-- 绘制按钮 -->
<view class="DrawButtonBox">
<u-button style="width: 150rpx;" type="primary" @click="startDraw" size="mini" >+ 绘制电子围栏</u-button>
</view>
<!-- 监控画面 -->
<view class="MonitorBox">
<!-- 这里可以放真实的监控视频组件 -->
<view class="MonitorPlaceholder">
<text class="PlaceholderText">监控画面</text>
</view>
<!-- 围栏图形 -->
<view class="FenceOverlay">
<view class="FenceShape" v-for="(fence, index) in fenceList" :key="index" :style="getFenceStyle(index)">
<view class="FenceLabel">{{ fence.name }}</view>
</view>
</view>
</view>
<!-- 围栏列表 -->
<view class="FenceList">
<view class="FenceItem" v-for="(fence, index) in fenceList" :key="index">
<view class="FenceItemHeader">
<view class="FenceItemName">{{ fence.name }}</view>
<view class="FenceItemAction">
<u-button size="mini" type="primary" @click="editFence(index)">设置</u-button>
</view>
</view>
<view class="FenceItemContent">
<view class="FenceInfoRow">
<text class="InfoLabel">位置</text>
<text class="InfoValue">{{ fence.position }}</text>
</view>
<view class="FenceInfoRow">
<text class="InfoLabel">类型</text>
<text class="InfoValue">{{ fence.type }}</text>
</view>
<view class="FenceInfoRow">
<text class="InfoLabel">级别</text>
<text class="InfoValue">{{ fence.level }}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 底部弹窗 -->
<u-popup v-model:show="showEditPopup" mode="bottom" :round="10" :safe-area-inset-bottom="30">
<view class="EditPopup">
<view class="PopupTitle">{{ currentEditFence.name }}</view>
<view class="PopupForm">
<view class="FormItem">
<text class="FormLabel">位置</text>
<text class="FormValue">{{ currentEditFence.position }}</text>
</view>
<view class="FormItem">
<text class="FormLabel">类型</text>
<u-select
v-model="editForm.type"
:list="fenceTypeList"
@confirm="onTypeConfirm"
></u-select>
</view>
<view class="FormItem">
<text class="FormLabel">时间</text>
<u-input
v-model="editForm.time"
type="number"
:border="false"
class="TimeInput"
></u-input>
<text class="TimeUnit">分钟</text>
</view>
<view class="FormItem">
<text class="FormLabel">级别</text>
<u-select
v-model="editForm.level"
:list="fenceLevelList"
@confirm="onLevelConfirm"
></u-select>
</view>
</view>
<view class="PopupButtons">
<u-button type="primary" @click="saveFenceConfig">保存配置</u-button>
<u-button type="error" @click="deleteFence">删除围栏</u-button>
</view>
</view>
</u-popup>
</view>
</template>
<script setup>
import {ref, onMounted} from 'vue'
const projectId = ref('')
const projectInfo = ref({
code: '20230801001',
leader: '张三',
period: '2023.8.1-2023.12.31',
percentage: 30
})
//
const currentCamera = ref(1)
//
const fenceList = ref([
{
name: '图形 1',
position: '10,10',
type: '入侵检测',
level: '一级',
top: '20%',
left: '10%',
width: '30%',
height: '40%'
},
{
name: '图形 2',
position: '10,10',
type: '滞留限制',
level: '一级',
top: '50%',
left: '40%',
width: '40%',
height: '35%'
},
{
name: '图形 2',
position: '10,10',
type: '滞留限制',
level: '一级',
top: '50%',
left: '40%',
width: '40%',
height: '35%'
},
{
name: '图形 2',
position: '10,10',
type: '滞留限制',
level: '一级',
top: '50%',
left: '40%',
width: '40%',
height: '35%'
},
{
name: '图形 2',
position: '10,10',
type: '滞留限制',
level: '一级',
top: '50%',
left: '40%',
width: '40%',
height: '35%'
},
{
name: '图形 2',
position: '10,10',
type: '滞留限制',
level: '一级',
top: '50%',
left: '40%',
width: '40%',
height: '35%'
},
{
name: '图形 2',
position: '10,10',
type: '滞留限制',
level: '一级',
top: '50%',
left: '40%',
width: '40%',
height: '35%'
}
])
//
const showEditPopup = ref(false)
const currentEditIndex = ref(-1)
const currentEditFence = ref({
name: '',
position: '',
type: '',
level: '',
time: ''
})
//
const fenceTypeList = ref([
{label: '入侵检测', value: '入侵检测'},
{label: '滞留限制', value: '滞留限制'},
{label: '越界检测', value: '越界检测'},
{label: '区域警戒', value: '区域警戒'}
])
//
const fenceLevelList = ref([
{label: '一级', value: '一级'},
{label: '二级', value: '二级'},
{label: '三级', value: '三级'}
])
//
const editForm = ref({
type: '',
time: '',
level: ''
})
//
const getFenceStyle = (index) => {
const fence = fenceList.value[index]
return {
top: fence.top,
left: fence.left,
width: fence.width,
height: fence.height
}
}
//
const startDraw = () => {
uni.showToast({
title: '进入绘制模式',
icon: 'none'
})
}
//
const editFence = (index) => {
currentEditIndex.value = index
const fence = fenceList.value[index]
currentEditFence.value = {...fence, time: '30'}
editForm.value = {
type: fence.type,
time: '30',
level: fence.level
}
showEditPopup.value = true
}
//
const onTypeConfirm = (value) => {
editForm.value.type = value
}
//
const onLevelConfirm = (value) => {
editForm.value.level = value
}
//
const saveFenceConfig = () => {
if (currentEditIndex.value >= 0) {
fenceList.value[currentEditIndex.value] = {
...fenceList.value[currentEditIndex.value],
type: editForm.value.type,
level: editForm.value.level
}
}
uni.showToast({
title: '保存成功',
icon: 'success'
})
showEditPopup.value = false
}
//
const deleteFence = () => {
uni.showModal({
title: '提示',
content: '确定要删除该围栏吗?',
success: (res) => {
if (res.confirm) {
if (currentEditIndex.value >= 0) {
fenceList.value.splice(currentEditIndex.value, 1)
}
uni.showToast({
title: '删除成功',
icon: 'success'
})
showEditPopup.value = false
}
}
})
}
//
const goBack = () => {
uni.navigateBack({
delta: 1
})
}
onMounted(() => {
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]
const options = currentPage.options || {}
projectId.value = options.projectId || ''
// TODO: projectId
})
</script>
<style lang="scss" scoped>
@ -31,10 +385,26 @@ const goBack = () => {
gap: 20rpx;
}
.PBasicBox {
padding: 20rpx;
background-color: #fff;
.LabelBox {
font-size: 24rpx;
color: #666;
margin-top: 20rpx;
}
.LabelBoxTxt {
font-size: 24rpx;
color: #333;
font-weight: bold;
}
}
.PageBox {
background-color: #f5f5f5;
height: 100vh;
overflow: hidden;
height: 100%;
.TopBox {
height: 100rpx;
@ -57,72 +427,213 @@ const goBack = () => {
}
.ContentBox {
width: 100%;
height: calc(100% - 140rpx);
background-color: #f5f5f5;
height: calc(100vh - 210rpx);
overflow-y: auto;
padding: 20rpx;
padding: 0 20rpx;
display: flex;
flex-direction: column;
overflow: hidden;
.CardBox {
.CameraTabs {
display: flex;
background-color: #fff;
border-radius: 10rpx;
padding: 20rpx;
margin-bottom: 20rpx;
box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.05);
flex-shrink: 0;
.CardTitle {
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
padding-left: 10rpx;
border-left: 4rpx solid #2979ff;
.CameraTab {
flex: 1;
text-align: center;
padding: 16rpx 0;
font-size: 22rpx;
color: #666;
background-color: #fff;
border: 1rpx solid #eaeaea;
&.active {
background-color: #2979ff;
color: #fff;
font-weight: bold;
}
}
}
.FormItemBox {
.DrawButtonBox {
margin-bottom: 20rpx;
display: flex;
justify-content: center;
}
.LabelBox {
font-size: 24rpx;
color: #333;
font-weight: bold;
margin-bottom: 10rpx;
}
.small-button {
width: auto !important;
min-width: 300rpx !important;
display: inline-block;
}
.ValueBox {
font-size: 24rpx;
color: #666;
}
.MonitorBox {
position: relative;
width: 100%;
height: 400rpx;
background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
margin-bottom: 20rpx;
border-radius: 10rpx;
overflow: hidden;
flex-shrink: 0;
.CoordBox {
display: flex;
justify-content: space-between;
gap: 10rpx;
}
.RangeBox {
.MonitorPlaceholder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
gap: 20rpx;
justify-content: center;
.RangeTxt {
font-size: 24rpx;
color: #2979ff;
.PlaceholderText {
color: rgba(255, 255, 255, 0.6);
font-size: 32rpx;
font-weight: bold;
min-width: 80rpx;
}
}
.FenceOverlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
.FenceShape {
position: absolute;
border: 2rpx solid #ff9900;
background-color: rgba(255, 153, 0, 0.2);
pointer-events: none;
.FenceLabel {
position: absolute;
top: -40rpx;
left: 0;
background-color: rgba(0, 0, 0, 0.6);
color: #fff;
padding: 8rpx 16rpx;
border-radius: 4rpx;
font-size: 24rpx;
}
}
}
}
.FenceList {
flex: 1;
overflow-y: auto;
min-height: 0;
.FenceItem {
background-color: #fff;
border-radius: 10rpx;
padding: 20rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
.FenceItemHeader {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
.FenceItemName {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
}
.FenceItemContent {
display: flex;
justify-content: space-between;
.FenceInfoRow {
display: flex;
align-items: center;
gap: 10rpx;
.InfoLabel {
font-size: 24rpx;
color: #666;
font-weight: bold;
}
.InfoValue {
font-size: 24rpx;
color: #333;
}
}
}
&:last-child {
margin-bottom: 0;
}
}
}
}
}
.FootBox {
.EditPopup {
padding: 30rpx;
padding-bottom: calc(30rpx + env(safe-area-inset-bottom));
background-color: #fff;
border-radius: 20rpx 20rpx 0 0;
.PopupTitle {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 30rpx;
text-align: center;
}
.PopupForm {
.FormItem {
display: flex;
align-items: center;
justify-content: space-between;
padding: 25rpx 0;
border-bottom: 1rpx solid #f0f0f0;
.FormLabel {
font-size: 28rpx;
color: #333;
font-weight: bold;
min-width: 120rpx;
}
.FormValue {
font-size: 28rpx;
color: #666;
}
.TimeInput {
width: 300rpx;
border-bottom: 1rpx solid #eaeaea !important;
}
.TimeUnit {
font-size: 28rpx;
color: #666;
margin-left: 10rpx;
}
}
}
.PopupButtons {
display: flex;
align-items: center;
justify-content: center;
gap: 20rpx;
padding: 20rpx;
background-color: #fff;
border-top: 1rpx solid #eaeaea;
margin-top: 50rpx;
button {
flex: 1;
height: 80rpx;
line-height: 80rpx;
font-size: 28rpx;
}
}
}
</style>