You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
226 lines
4.7 KiB
226 lines
4.7 KiB
3 days ago
|
<template>
|
||
|
<div class="mobile-container">
|
||
|
<div>位置权限:{{ locationPermission ? '是' : '否' }}</div>
|
||
|
<div>蓝牙权限:{{ bluetoothPermission ? '是' : '否' }}</div>
|
||
|
<div>相机权限:{{ cameraPermission ? '是' : '否' }}</div>
|
||
|
<div class="mobile-header">
|
||
|
<el-input v-model="searchText" placeholder="搜索隔离点或任务名称" prefix-icon="Search" clearable class="search-input" />
|
||
|
<el-button type="primary" @click="$emit('refresh')" class="refresh-btn">刷新</el-button>
|
||
|
</div>
|
||
|
<div class="plan-list">
|
||
|
<PlanCard v-for="isolationPlan in filteredPlans" :key="isolationPlan.id" :isolation-plan="isolationPlan"
|
||
|
:expanded-plan="expandedPlans.includes(isolationPlan.id)" :expanded-points="expandedPoints"
|
||
|
:isolation-points="isolationPoints" :locks="locks" :users="users" :current-user-id="currentUserId"
|
||
|
:is-bluetooth-supported="isBluetoothSupported" :plan-id="isolationPlan[0]?.isolationPlanId"
|
||
|
@toggle-plan="togglePlan" @toggle-point="togglePoint" @bind-lock="$emit('bindLock', $event)"
|
||
|
@lock-operation="$emit('lockOperation', $event)" @verify-lock="$emit('verifyLock', $event)"
|
||
|
@unlock-verify="$emit('unlockVerify', $event)" @unlock-operation="$emit('unlockOperation', $event)" />
|
||
|
</div>
|
||
|
</div>
|
||
|
</template>
|
||
|
|
||
|
<script setup>
|
||
|
import { ref, computed, toRefs } from 'vue'
|
||
|
import { Refresh, Search } from '@element-plus/icons-vue'
|
||
|
import PlanCard from './PlanCard.vue'
|
||
|
import { useUserStore } from '@/store/modules/user'
|
||
|
|
||
|
// Props
|
||
|
const props = defineProps({
|
||
|
isolationPlanList: {
|
||
|
type: Object,
|
||
|
required: true
|
||
|
},
|
||
|
isolationPoints: {
|
||
|
type: Array,
|
||
|
default: () => []
|
||
|
},
|
||
|
locks: {
|
||
|
type: Array,
|
||
|
default: () => []
|
||
|
},
|
||
|
users: {
|
||
|
type: Array,
|
||
|
default: () => []
|
||
|
},
|
||
|
currentUserId: {
|
||
|
type: Number,
|
||
|
default: 0
|
||
|
},
|
||
|
isBluetoothSupported: {
|
||
|
type: Boolean,
|
||
|
default: false
|
||
|
}
|
||
|
})
|
||
|
|
||
|
// Emits
|
||
|
const emit = defineEmits([
|
||
|
'refresh',
|
||
|
'bindLock',
|
||
|
'lockOperation',
|
||
|
'unlockOperation',
|
||
|
'verifyLock',
|
||
|
'unlockVerify',
|
||
|
'unlockOperation'
|
||
|
])
|
||
|
|
||
|
// Reactive props
|
||
|
const { isolationPlanList, isolationPoints, locks, users, currentUserId } = toRefs(props)
|
||
|
|
||
|
// 本地状态
|
||
|
const searchText = ref('')
|
||
|
const expandedPlans = ref([])
|
||
|
const expandedPoints = ref([])
|
||
|
|
||
|
|
||
|
// 计算属性
|
||
|
const filteredPlans = computed(() => {
|
||
|
let plans = Object.values(isolationPlanList.value)
|
||
|
plans = plans.filter((plan) => {
|
||
|
return plan.some((item) =>
|
||
|
[item.operatorId, item.verifierId, item.operatorHelperId, item.verifierHelperId].some(
|
||
|
(val) => val === currentUserId.value
|
||
|
)
|
||
|
)
|
||
|
})
|
||
|
if (!searchText.value) return plans
|
||
|
return plans.filter((plan) =>
|
||
|
plan.some((item) =>
|
||
|
[item.isolationPointId, item.isolationPlanName].some((val) =>
|
||
|
val?.toString().toLowerCase().includes(searchText.value.toLowerCase())
|
||
|
)
|
||
|
)
|
||
|
)
|
||
|
})
|
||
|
const togglePlan = (planId) => {
|
||
|
const index = expandedPlans.value.indexOf(planId)
|
||
|
if (index > -1) {
|
||
|
expandedPlans.value.splice(index, 1)
|
||
|
} else {
|
||
|
expandedPlans.value.push(planId)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const togglePoint = ({ pointId, planId }) => {
|
||
|
const compositeKey = `${planId}_${pointId}`
|
||
|
const index = expandedPoints.value.indexOf(compositeKey)
|
||
|
if (index > -1) {
|
||
|
expandedPoints.value.splice(index, 1)
|
||
|
} else {
|
||
|
expandedPoints.value.push(compositeKey)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 暴露方法和数据给父组件
|
||
|
defineExpose({
|
||
|
searchText,
|
||
|
expandedPlans,
|
||
|
expandedPoints,
|
||
|
filteredPlans,
|
||
|
})
|
||
|
</script>
|
||
|
|
||
|
<style scoped>
|
||
|
.mobile-container {
|
||
|
padding: 16px;
|
||
|
background-color: #f5f5f5;
|
||
|
min-height: 100vh;
|
||
|
}
|
||
|
|
||
|
.mb-4 {
|
||
|
margin-bottom: 16px;
|
||
|
}
|
||
|
|
||
|
.mobile-header {
|
||
|
display: flex;
|
||
|
gap: 12px;
|
||
|
margin-bottom: 16px;
|
||
|
align-items: center;
|
||
|
}
|
||
|
|
||
|
.search-input {
|
||
|
flex: 1;
|
||
|
}
|
||
|
|
||
|
.refresh-btn {
|
||
|
flex-shrink: 0;
|
||
|
}
|
||
|
|
||
|
.status-summary {
|
||
|
display: flex;
|
||
|
gap: 12px;
|
||
|
margin-bottom: 16px;
|
||
|
padding: 16px;
|
||
|
background: white;
|
||
|
border-radius: 8px;
|
||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||
|
}
|
||
|
|
||
|
.summary-item {
|
||
|
flex: 1;
|
||
|
text-align: center;
|
||
|
}
|
||
|
|
||
|
.summary-value {
|
||
|
font-size: 24px;
|
||
|
font-weight: bold;
|
||
|
color: #409eff;
|
||
|
margin-bottom: 4px;
|
||
|
}
|
||
|
|
||
|
.summary-value.locked {
|
||
|
color: #67c23a;
|
||
|
}
|
||
|
|
||
|
.summary-value.unlocked {
|
||
|
color: #f56c6c;
|
||
|
}
|
||
|
|
||
|
.summary-label {
|
||
|
font-size: 14px;
|
||
|
color: #666;
|
||
|
}
|
||
|
|
||
|
.plan-list {
|
||
|
display: flex;
|
||
|
flex-direction: column;
|
||
|
gap: 12px;
|
||
|
}
|
||
|
|
||
|
@media (max-width: 480px) {
|
||
|
.mobile-container {
|
||
|
padding: 12px;
|
||
|
}
|
||
|
|
||
|
.mobile-header {
|
||
|
flex-direction: column;
|
||
|
gap: 8px;
|
||
|
}
|
||
|
|
||
|
.refresh-btn {
|
||
|
width: 100%;
|
||
|
}
|
||
|
|
||
|
.status-summary {
|
||
|
padding: 12px;
|
||
|
}
|
||
|
|
||
|
.summary-value {
|
||
|
font-size: 20px;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.mobile-container .el-tag {
|
||
|
border-radius: 12px;
|
||
|
}
|
||
|
|
||
|
.mobile-container .el-button {
|
||
|
border-radius: 6px;
|
||
|
font-size: 14px;
|
||
|
}
|
||
|
|
||
|
.mobile-container .el-input {
|
||
|
border-radius: 6px;
|
||
|
}
|
||
|
</style>
|