bug修复
This commit is contained in:
@@ -77,11 +77,11 @@
|
|||||||
<div class="type-wrapper">
|
<div class="type-wrapper">
|
||||||
<div class="type-item">
|
<div class="type-item">
|
||||||
<span class="type-btn yellow">重大</span>
|
<span class="type-btn yellow">重大</span>
|
||||||
<span class="type-num">{{ mockData.hiddenDangerData.severityCount }}</span>
|
<span class="type-num cursor-pointer" @click="handleSeverityCountClick">{{ mockData.hiddenDangerData.severityCount }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="type-item">
|
<div class="type-item">
|
||||||
<span class="type-btn green">一般</span>
|
<span class="type-btn green">一般</span>
|
||||||
<span class="type-num">{{ mockData.hiddenDangerData.generalCount }}</span>
|
<span class="type-num cursor-pointer" @click="handleGeneralCountClick">{{ mockData.hiddenDangerData.generalCount }}</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="type-item">
|
<!-- <div class="type-item">
|
||||||
<span class="type-btn blue">较大</span>
|
<span class="type-btn blue">较大</span>
|
||||||
@@ -108,11 +108,11 @@
|
|||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
<span class="tab" :class="{ active: activeTab === '高危作业' }" @click="handleTabClick('高危作业')">高危作业</span>
|
<span class="tab" :class="{ active: activeTab === '高危作业' }" @click="handleTabClick('高危作业')">高危作业</span>
|
||||||
<span class="divider">|</span>
|
<span class="divider">|</span>
|
||||||
<span
|
<span class="tab" :class="{ active: activeTab === '安全培训考试' }"
|
||||||
class="tab" :class="{ active: activeTab === '安全培训考试' }"
|
|
||||||
@click="handleTabClick('安全培训考试')">安全培训考试</span>
|
@click="handleTabClick('安全培训考试')">安全培训考试</span>
|
||||||
<span class="divider">|</span>
|
<span class="divider">|</span>
|
||||||
<span class="tab" :class="{ active: activeTab === '应急预案及演练' }" @click="handleTabClick('应急预案及演练')">应急预案及演练</span>
|
<span class="tab" :class="{ active: activeTab === '应急预案及演练' }"
|
||||||
|
@click="handleTabClick('应急预案及演练')">应急预案及演练</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<img style="margin: 8px 0" src="@/assets/images/title_border_line.png" />
|
<img style="margin: 8px 0" src="@/assets/images/title_border_line.png" />
|
||||||
@@ -161,7 +161,8 @@ class="tab" :class="{ active: activeTab === '安全培训考试' }"
|
|||||||
<img width="50%" style="margin: 8px 0" src="@/assets/images/line_1.png" />
|
<img width="50%" style="margin: 8px 0" src="@/assets/images/line_1.png" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<AlertList maxHeight="40vh" style="margin-left: 1vw;" :table-title="trainingTableTitle" :list-data="drillList" />
|
<AlertList maxHeight="40vh" style="margin-left: 1vw;" :table-title="trainingTableTitle"
|
||||||
|
:list-data="drillList" />
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -192,11 +193,13 @@ class="tab" :class="{ active: activeTab === '安全培训考试' }"
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-item" style=" display: flex;margin-left: 2vw; align-items: center;">
|
<div class="col-item" style=" display: flex;margin-left: 2vw; align-items: center;">
|
||||||
<span>待处理</span>
|
<span>待处理</span>
|
||||||
<span style="font-size: 1.2rem; marker-start: 2vw; color: yellow;">{{ mockData.alertData.pending }}</span>
|
<span style="font-size: 1.2rem; marker-start: 2vw; color: yellow;">{{ mockData.alertData.pending
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-item" style=" display: flex;margin-left: 2vw; align-items: center;">
|
<div class="col-item" style=" display: flex;margin-left: 2vw; align-items: center;">
|
||||||
<span>处理中</span>
|
<span>处理中</span>
|
||||||
<span style="font-size: 1.2rem; marker-start: 2vw; color: yellow;">{{ mockData.alertData.processing }}</span>
|
<span style="font-size: 1.2rem; marker-start: 2vw; color: yellow;">{{ mockData.alertData.processing
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -218,7 +221,8 @@ class="tab" :class="{ active: activeTab === '安全培训考试' }"
|
|||||||
<div class="col-item">
|
<div class="col-item">
|
||||||
<img src="@/assets/images/screen/warning_img.png" width="23" />
|
<img src="@/assets/images/screen/warning_img.png" width="23" />
|
||||||
<span>超时工单数</span>
|
<span>超时工单数</span>
|
||||||
<span style="font-size: 1.2rem; marker-start: 2vw; color: red;">{{ mockData.timeoutWorkOrders.total }}</span>
|
<span style="font-size: 1.2rem; marker-start: 2vw; color: red;">{{ mockData.timeoutWorkOrders.total
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -229,14 +233,12 @@ class="tab" :class="{ active: activeTab === '安全培训考试' }"
|
|||||||
</div>
|
</div>
|
||||||
<div class="center-container">
|
<div class="center-container">
|
||||||
<!-- 中部区域 -->
|
<!-- 中部区域 -->
|
||||||
<ParkCenter
|
<ParkCenter :parkName="selectedPark" :backgroundImage="backgroundImage" @point-hover="handlePointHover"
|
||||||
:parkName="selectedPark" :backgroundImage="backgroundImage" @point-hover="handlePointHover"
|
|
||||||
@point-leave="handlePointLeave" />
|
@point-leave="handlePointLeave" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 点位信息弹窗 -->
|
<!-- 点位信息弹窗 -->
|
||||||
<PointInfoPopup
|
<PointInfoPopup v-if="showPointPopup" :visible="showPointPopup" :point-info="currentPoint"
|
||||||
v-if="showPointPopup" :visible="showPointPopup" :point-info="currentPoint"
|
|
||||||
:park-name="selectedPark || '雄安园区'" />
|
:park-name="selectedPark || '雄安园区'" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -283,6 +285,12 @@ const unfinishedCount = ref<number>(0)
|
|||||||
const inProgressCount = ref<number>(0)
|
const inProgressCount = ref<number>(0)
|
||||||
const finishedCount = ref<number>(0)
|
const finishedCount = ref<number>(0)
|
||||||
|
|
||||||
|
const handleSeverityCountClick = () => {
|
||||||
|
window.open('http://10.0.64.20/configcenter/console/device-manage', '_blank')
|
||||||
|
}
|
||||||
|
const handleGeneralCountClick = () => {
|
||||||
|
window.open('http://10.0.64.20/configcenter/console/device-manage', '_blank')
|
||||||
|
}
|
||||||
|
|
||||||
const tableTitle = [
|
const tableTitle = [
|
||||||
{
|
{
|
||||||
@@ -543,12 +551,14 @@ const initProgressChart = () => {
|
|||||||
labelLayout: function (params: any) {
|
labelLayout: function (params: any) {
|
||||||
const isLeft = params.labelRect.x < width / 2;
|
const isLeft = params.labelRect.x < width / 2;
|
||||||
const points = params.labelLinePoints;
|
const points = params.labelLinePoints;
|
||||||
|
if (points && points.length && points[2]) {
|
||||||
points[2][0] = isLeft
|
points[2][0] = isLeft
|
||||||
? params.labelRect.x
|
? params.labelRect.x
|
||||||
: params.labelRect.x + params.labelRect.width;
|
: params.labelRect.x + params.labelRect.width;
|
||||||
return {
|
return {
|
||||||
labelLinePoints: points
|
labelLinePoints: points
|
||||||
};
|
};
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -844,12 +854,14 @@ const handleHiddenDangerPannelData = (query) => {
|
|||||||
labelLayout: function (params: any) {
|
labelLayout: function (params: any) {
|
||||||
const isLeft = params.labelRect.x < width / 2;
|
const isLeft = params.labelRect.x < width / 2;
|
||||||
const points = params.labelLinePoints;
|
const points = params.labelLinePoints;
|
||||||
|
if (points && points.length && points[2]) {
|
||||||
points[2][0] = isLeft
|
points[2][0] = isLeft
|
||||||
? params.labelRect.x
|
? params.labelRect.x
|
||||||
: params.labelRect.x + params.labelRect.width;
|
: params.labelRect.x + params.labelRect.width;
|
||||||
return {
|
return {
|
||||||
labelLinePoints: points
|
labelLinePoints: points
|
||||||
};
|
};
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -1186,6 +1198,9 @@ onUnmounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
.cursor-pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
/* 响应式设计 - 自动适应不同屏幕尺寸 */
|
/* 响应式设计 - 自动适应不同屏幕尺寸 */
|
||||||
@media (width <=1200px) {
|
@media (width <=1200px) {
|
||||||
.dashboard-container {
|
.dashboard-container {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<div class="list-wrapper" ref="listWrapperRef" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
|
<div class="list-wrapper" ref="listWrapperRef" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
|
||||||
<!-- 表格模式 -->
|
<!-- 表格模式 -->
|
||||||
<template v-if="tableTitle && tableTitle.length > 0">
|
<template v-if="tableTitle && tableTitle.length > 0">
|
||||||
<div class="table-row" v-for="(item, index) in listData" :key="`table-${index}`" @mouseenter="handleMouseEnter">
|
<div @click="handleItemClick(item)" class="table-row cursor-pointer" v-for="(item, index) in listData" :key="`table-${index}`" @mouseenter="handleMouseEnter">
|
||||||
<div class="table-cell" v-for="(title, cellIndex) in tableTitle" :key="`cell-${index}-${cellIndex}`">
|
<div class="table-cell" v-for="(title, cellIndex) in tableTitle" :key="`cell-${index}-${cellIndex}`">
|
||||||
{{ item[title.key] || '-' }}
|
{{ item[title.key] || '-' }}
|
||||||
</div>
|
</div>
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
<!-- 列表模式 -->
|
<!-- 列表模式 -->
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="list-item" v-for="(item, index) in listData" :key="`list-${index}`" @mouseenter="handleMouseEnter">
|
<div @click="handleItemClick(item)" class="list-item cursor-pointer" v-for="(item, index) in listData" :key="`list-${index}`" @mouseenter="handleMouseEnter">
|
||||||
<span class="alert-text" :class="[{ error: item.alarm_level_code == 'severity' }, { warn: item.alarm_level_code == 'major' }]">
|
<span class="alert-text" :class="[{ error: item.alarm_level_code == 'severity' }, { warn: item.alarm_level_code == 'major' }]">
|
||||||
{{ (index + 1) }} {{ item.description }}
|
{{ (index + 1) }} {{ item.description }}
|
||||||
</span>
|
</span>
|
||||||
@@ -71,9 +71,14 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
const listWrapperRef = ref<HTMLElement | null>(null)
|
const listWrapperRef = ref<HTMLElement | null>(null)
|
||||||
let scrollTimer: NodeJS.Timeout | null = null
|
let scrollTimer: NodeJS.Timeout | null = null
|
||||||
let isScrolling = false
|
let isScrolling = false
|
||||||
|
let scrollDirection: 'down' | 'up' = 'down' // 滚动方向:向下或向上
|
||||||
|
|
||||||
|
const handleItemClick = (item: AlertItem) => {
|
||||||
|
window.open(`http://10.0.64.20/configcenter/console/device-manage`, '_blank')
|
||||||
|
}
|
||||||
|
|
||||||
// 自动滚动功能
|
// 自动滚动功能
|
||||||
const startAutoScroll = () => {
|
const startAutoScroll = (resetToTop: boolean = false) => {
|
||||||
if (!props.autoScroll || !listWrapperRef.value) return
|
if (!props.autoScroll || !listWrapperRef.value) return
|
||||||
|
|
||||||
const wrapper = listWrapperRef.value
|
const wrapper = listWrapperRef.value
|
||||||
@@ -83,20 +88,61 @@ const startAutoScroll = () => {
|
|||||||
// 只有当内容高度超过容器高度时才启动滚动
|
// 只有当内容高度超过容器高度时才启动滚动
|
||||||
if (scrollHeight <= clientHeight) return
|
if (scrollHeight <= clientHeight) return
|
||||||
|
|
||||||
|
// 如果是首次启动或需要重置,从顶部开始向下滚动
|
||||||
|
if (resetToTop) {
|
||||||
|
wrapper.scrollTop = 0
|
||||||
|
scrollDirection = 'down'
|
||||||
|
} else {
|
||||||
|
// 否则根据当前位置判断滚动方向
|
||||||
|
const currentScrollTop = wrapper.scrollTop
|
||||||
|
const maxScrollTop = scrollHeight - clientHeight
|
||||||
|
|
||||||
|
if (currentScrollTop >= maxScrollTop - 1) {
|
||||||
|
// 在底部,向上滚动
|
||||||
|
scrollDirection = 'up'
|
||||||
|
} else if (currentScrollTop <= 1) {
|
||||||
|
// 在顶部,向下滚动
|
||||||
|
scrollDirection = 'down'
|
||||||
|
}
|
||||||
|
// 在中间位置,保持当前方向(或默认向下)
|
||||||
|
}
|
||||||
|
|
||||||
isScrolling = true
|
isScrolling = true
|
||||||
let currentScrollTop = listWrapperRef.value.scrollTop
|
|
||||||
|
|
||||||
const scroll = () => {
|
const scroll = () => {
|
||||||
if (!isScrolling || !wrapper) return
|
if (!isScrolling || !wrapper) return
|
||||||
|
|
||||||
currentScrollTop += props.scrollSpeed
|
const currentScrollTop = wrapper.scrollTop
|
||||||
|
const maxScrollTop = scrollHeight - clientHeight
|
||||||
|
|
||||||
// 如果滚动到底部,重置到顶部
|
if (scrollDirection === 'down') {
|
||||||
if (currentScrollTop >= scrollHeight - clientHeight) {
|
// 向下滚动
|
||||||
currentScrollTop = 0
|
const nextScrollTop = currentScrollTop + props.scrollSpeed
|
||||||
wrapper.scrollTop = 0
|
|
||||||
|
if (nextScrollTop >= maxScrollTop) {
|
||||||
|
// 滚动到底部,切换方向为向上
|
||||||
|
wrapper.scrollTop = maxScrollTop
|
||||||
|
scrollDirection = 'up'
|
||||||
|
// 在底部停留一小段时间后开始向上滚动
|
||||||
|
scrollTimer = setTimeout(scroll, 500)
|
||||||
|
return
|
||||||
} else {
|
} else {
|
||||||
wrapper.scrollTop = currentScrollTop
|
wrapper.scrollTop = nextScrollTop
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 向上滚动
|
||||||
|
const nextScrollTop = currentScrollTop - props.scrollSpeed
|
||||||
|
|
||||||
|
if (nextScrollTop <= 0) {
|
||||||
|
// 滚动到顶部,切换方向为向下
|
||||||
|
wrapper.scrollTop = 0
|
||||||
|
scrollDirection = 'down'
|
||||||
|
// 在顶部停留一小段时间后开始向下滚动
|
||||||
|
scrollTimer = setTimeout(scroll, 500)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
wrapper.scrollTop = nextScrollTop
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollTimer = setTimeout(scroll, 50) // 每50ms滚动一次,实现平滑效果
|
scrollTimer = setTimeout(scroll, 50) // 每50ms滚动一次,实现平滑效果
|
||||||
@@ -121,8 +167,9 @@ const handleMouseEnter = () => {
|
|||||||
const handleMouseLeave = () => {
|
const handleMouseLeave = () => {
|
||||||
if (props.autoScroll) {
|
if (props.autoScroll) {
|
||||||
// 延迟启动滚动,避免鼠标快速进出
|
// 延迟启动滚动,避免鼠标快速进出
|
||||||
|
// 从当前位置继续,不重置
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
startAutoScroll()
|
startAutoScroll(false)
|
||||||
}, 500)
|
}, 500)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,7 +180,8 @@ watch(() => props.listData, () => {
|
|||||||
if (props.autoScroll) {
|
if (props.autoScroll) {
|
||||||
stopAutoScroll()
|
stopAutoScroll()
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
startAutoScroll()
|
// 数据更新后从顶部重新开始
|
||||||
|
startAutoScroll(true)
|
||||||
}, 1000) // 数据更新后1秒开始滚动
|
}, 1000) // 数据更新后1秒开始滚动
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -141,9 +189,9 @@ watch(() => props.listData, () => {
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (props.autoScroll) {
|
if (props.autoScroll) {
|
||||||
// 组件挂载后延迟启动滚动
|
// 组件挂载后延迟启动滚动,从顶部开始
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
startAutoScroll()
|
startAutoScroll(true)
|
||||||
}, 2000)
|
}, 2000)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -154,6 +202,9 @@ onUnmounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
.cursor-pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
.list-content {
|
.list-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 68%;
|
width: 68%;
|
||||||
|
|||||||
@@ -193,6 +193,15 @@ watch(() => props.hiddenDangerData?.progress, (newVal) => {
|
|||||||
refreshProcessCharts(newVal)
|
refreshProcessCharts(newVal)
|
||||||
}, { deep: true })
|
}, { deep: true })
|
||||||
|
|
||||||
|
// 辅助函数:安全地将值转换为数字,处理 NaN 和字符串 "NaN" 的情况
|
||||||
|
const safeNumber = (val: any): number => {
|
||||||
|
if (val === null || val === undefined || val === '' || val === 'NaN') {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
const num = Number(val)
|
||||||
|
return isNaN(num) ? 0 : num
|
||||||
|
}
|
||||||
|
|
||||||
// 更新图表数据
|
// 更新图表数据
|
||||||
const refreshProcessCharts = (process): void => {
|
const refreshProcessCharts = (process): void => {
|
||||||
if (!props.hiddenDangerData?.progress) {
|
if (!props.hiddenDangerData?.progress) {
|
||||||
@@ -200,11 +209,12 @@ const refreshProcessCharts = (process): void => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
const option = { ...progressChartOption.value }
|
const option = { ...progressChartOption.value }
|
||||||
|
// 确保所有 value 都是有效的数字,将字符串 "NaN" 或真正的 NaN 转换为 0
|
||||||
option.series[0].data = [
|
option.series[0].data = [
|
||||||
{ value: process.overdue || 0, name: '已逾期', itemStyle: { color: '#ef4444' } },
|
{ value: safeNumber(process.overdue), name: '已逾期', itemStyle: { color: '#ef4444' } },
|
||||||
{ value: process.processed || 0, name: '已处理', itemStyle: { color: '#10b981' } },
|
{ value: safeNumber(process.processed), name: '已处理', itemStyle: { color: '#10b981' } },
|
||||||
// { value: process.pending || 0, name: '待排查', itemStyle: { color: '#eab308' } },
|
// { value: safeNumber(process.pending), name: '待排查', itemStyle: { color: '#eab308' } },
|
||||||
{ value: process.processing || 0, name: '处理中', itemStyle: { color: '#3b82f6' } }
|
{ value: safeNumber(process.processing), name: '处理中', itemStyle: { color: '#3b82f6' } }
|
||||||
]
|
]
|
||||||
progressChartOption.value = option
|
progressChartOption.value = option
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<!-- 顶部标题栏 -->
|
<!-- 顶部标题栏 -->
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
<div class="header-left">
|
<div class="header-left">
|
||||||
<div class="back-button" @click="openRegionSelector"> 总部
|
<div class="back-button" @click="openRegionSelector"> 集团
|
||||||
<span>···</span>
|
<span>···</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -374,9 +374,9 @@ const loadDashboardData = async (): Promise<void> => {
|
|||||||
try {
|
try {
|
||||||
// 获取风险预警详情数据
|
// 获取风险预警详情数据
|
||||||
getTableList('risk_alert_detail', query).then(risk_alert_detail => {
|
getTableList('risk_alert_detail', query).then(risk_alert_detail => {
|
||||||
if (risk_alert_detail.records && risk_alert_detail.records.length > 0) {
|
// if (risk_alert_detail.records && risk_alert_detail.records.length > 0) {
|
||||||
dashboardData.value.alertData.details = risk_alert_detail.records
|
dashboardData.value.alertData.details = risk_alert_detail.records || []
|
||||||
}
|
// }
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
console.error('获取风险预警详情数据失败:', error)
|
console.error('获取风险预警详情数据失败:', error)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
|||||||
// 本地跨域代理. 目前注释的原因:暂时没有用途,server 端已经支持跨域
|
// 本地跨域代理. 目前注释的原因:暂时没有用途,server 端已经支持跨域
|
||||||
proxy: {
|
proxy: {
|
||||||
['/admin-api']: {
|
['/admin-api']: {
|
||||||
target: 'http://10.28.117.48:48080',
|
target: 'http://carson.wang:48080',
|
||||||
ws: false,
|
ws: false,
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path) => path.replace(new RegExp(`^/admin-api`), ''),
|
rewrite: (path) => path.replace(new RegExp(`^/admin-api`), ''),
|
||||||
|
|||||||
Reference in New Issue
Block a user