Merge remote-tracking branch 'origin/main'
# Conflicts: # tzipc-ui/src/views/zf/bigscreen/index.vue
This commit is contained in:
commit
d4483a22cd
Binary file not shown.
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 56 KiB |
@ -146,11 +146,12 @@ export default {
|
||||
created() {
|
||||
this.getCode();
|
||||
this.getCookie();
|
||||
|
||||
},
|
||||
methods: {
|
||||
getTitleBg() {
|
||||
const theme = localStorage.getItem("data-theme") || 'redTheme'
|
||||
const theme = localStorage.getItem("data-theme") || 'default'
|
||||
window.document.documentElement.setAttribute('data-theme', theme)
|
||||
window.document.documentElement.setAttribute('class', 'light')
|
||||
if (theme === 'default') return '/theme/default/loginTitle.png'
|
||||
if (theme === 'redTheme') return '/theme/redTheme/loginTitle.png'
|
||||
return '/theme/default/loginTitle.png'
|
||||
|
@ -1,327 +1,147 @@
|
||||
<template>
|
||||
<div class="bigscreen-outer-wrappeer">
|
||||
<div class="grid-main-wrapper">
|
||||
<div class="grid-main-wrapper" @click="$router.push('/alarm/alarmRecord')">
|
||||
<div class="grid-item-wrapper">
|
||||
<div class="card-item-wrapper">
|
||||
<div class="card-big-title">{{ title1 }}数据监控</div>
|
||||
<div
|
||||
class="card-sub-title"
|
||||
@click="jumpSensorDataLog"
|
||||
>油膜轴承振动监测</div>
|
||||
<div
|
||||
class="card-main-item-wrapper"
|
||||
id="chart1"
|
||||
style="height:calc(100% - 6.4rem);"
|
||||
></div>
|
||||
<div class="card-sub-title">油膜轴承振动监测</div>
|
||||
<div class="card-main-item-wrapper" id="chart1" style="height:calc(100% - 8.1rem);"></div>
|
||||
<div class="scroll-text-wrapper" style="height: 1.7rem;">
|
||||
<div class="scroll-inner"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="grid-item-wrapper"
|
||||
style="grid-row: span 2;grid-column: span 2;padding: 2rem;"
|
||||
@click="(e) => { e.stopPropagation() }"
|
||||
>
|
||||
<div class="device-image">
|
||||
<div @click="handleTypeChange(['rtd', 'rto'])"></div>
|
||||
<div @click="handleTypeChange(['rbd', 'rbo'])"></div>
|
||||
<div @click="handleTypeChange(['ftd', 'fto'])"></div>
|
||||
<div @click="handleTypeChange(['rbd', 'rbo'])"></div>
|
||||
<div @click="handleTypeChange(['fbd', 'fbo'])"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid-item-wrapper">
|
||||
<div class="card-item-wrapper">
|
||||
<div class="card-big-title">{{ title2 }}数据监控</div>
|
||||
<div
|
||||
class="card-sub-title"
|
||||
@click="jumpSensorDataLog"
|
||||
>油膜轴承振动监测</div>
|
||||
<div
|
||||
class="card-main-item-wrapper"
|
||||
id="chart2"
|
||||
style="height:calc(100% - 6.4rem);"
|
||||
></div>
|
||||
<div class="card-sub-title">油膜轴承振动监测</div>
|
||||
<div class="card-main-item-wrapper" id="chart2" style="height:calc(100% - 8.1rem);"></div>
|
||||
<div class="scroll-text-wrapper" style="height: 1.7rem;">
|
||||
<div class="scroll-inner"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid-item-wrapper">
|
||||
<div class="card-item-wrapper">
|
||||
<div
|
||||
class="card-sub-title"
|
||||
@click="handleViewTendency(queryParams[0], titleMap[queryParams[0]], 'pz4', '油液颗粒度特性', 'μm')"
|
||||
>油液颗粒度特性</div>
|
||||
<div
|
||||
class="card-main-item-wrapper"
|
||||
id="chart3"
|
||||
style="height:calc(100% - 2.8rem);"
|
||||
></div>
|
||||
<div class="card-sub-title">油液颗粒度特性</div>
|
||||
<div class="card-main-item-wrapper" id="chart3" style="height:calc(100% - 4.5rem);"></div>
|
||||
<div class="scroll-text-wrapper" style="height: 1.7rem;">
|
||||
<div class="scroll-inner"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid-item-wrapper">
|
||||
<div class="card-item-wrapper">
|
||||
<div
|
||||
class="card-sub-title"
|
||||
@click="handleViewTendency(queryParams[1], titleMap[queryParams[1]], 'pz4', '油液颗粒度特性', 'μm')"
|
||||
>油液颗粒度特性</div>
|
||||
<div
|
||||
class="card-main-item-wrapper"
|
||||
id="chart4"
|
||||
style="height:calc(100% - 2.8rem);"
|
||||
></div>
|
||||
<div class="card-sub-title">油液颗粒度特性</div>
|
||||
<div class="card-main-item-wrapper" id="chart4" style="height:calc(100% - 4.5rem);"></div>
|
||||
<div class="scroll-text-wrapper" style="height: 1.7rem;">
|
||||
<div class="scroll-inner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="grid-item-wrapper"
|
||||
style="grid-column: span 2;"
|
||||
>
|
||||
</div>
|
||||
<div class="grid-item-wrapper" style="grid-column: span 2;">
|
||||
<div class="card-item-wrapper">
|
||||
<div class="big-car-title-bg">油膜轴承系统油品特性</div>
|
||||
<div
|
||||
class="card-main-item-wrapper"
|
||||
style="padding: .8rem 1.2rem;height: calc(100% - 2.4rem);"
|
||||
>
|
||||
<div class="card-main-item-wrapper" style="padding: .8rem 1.2rem;height: calc(100% - 2.4rem);">
|
||||
<div class="bottom-grid-wrapper">
|
||||
<div class="bottom-grid-item">
|
||||
<div
|
||||
id="bottomL1"
|
||||
style="width: 100%;aspect-ratio: 1;"
|
||||
></div>
|
||||
<div
|
||||
style="font-family: 'BiaoTi';"
|
||||
@click="handleViewTendency(queryParams[0], titleMap[queryParams[0]], 'owc', '油水含量', '%')"
|
||||
>油水含量</div>
|
||||
<div id="bottomL1" style="width: 100%;aspect-ratio: 1;"></div>
|
||||
<div style="font-family: 'BiaoTi';">油水含量</div>
|
||||
</div>
|
||||
<div class="bottom-grid-item">
|
||||
<div
|
||||
id="bottomL2"
|
||||
style="width: 100%;aspect-ratio: 1;"
|
||||
></div>
|
||||
<div
|
||||
style="font-family: 'BiaoTi';"
|
||||
@click="handleViewTendency(queryParams[0], titleMap[queryParams[0]], 'ov', '油品粘度', 'Cp')"
|
||||
>油品粘度</div>
|
||||
<div id="bottomL2" style="width: 100%;aspect-ratio: 1;"></div>
|
||||
<div style="font-family: 'BiaoTi';">油品粘度</div>
|
||||
</div>
|
||||
<div class="bottom-grid-item">
|
||||
<div
|
||||
id="bottomL3"
|
||||
style="width: 100%;aspect-ratio: 1;"
|
||||
></div>
|
||||
<div
|
||||
style="font-family: 'BiaoTi';"
|
||||
@click="handleViewTendency(queryParams[0], titleMap[queryParams[0]], 'oip', '进油压力', 'Bar')"
|
||||
>进油压力</div>
|
||||
<div id="bottomL3" style="width: 100%;aspect-ratio: 1;"></div>
|
||||
<div style="font-family: 'BiaoTi';">进油压力</div>
|
||||
</div>
|
||||
<div class="bottom-grid-item">
|
||||
<div
|
||||
style="width: 100%;aspect-ratio: 1;"
|
||||
class="extra-bar-wrapper"
|
||||
>
|
||||
<div
|
||||
class="extra-bar-item"
|
||||
:style="`height: ${parseInt(l1 * 100)}%;background-color:#6581f0;`"
|
||||
></div>
|
||||
<div
|
||||
class="extra-bar-text"
|
||||
:style="`height: calc(100% - ${parseInt(l1 * 100)}%);`"
|
||||
>
|
||||
<div class="extra-bar-item" :style="`height: ${parseInt(l1 * 100)}%;background-color:#6581f0;`"></div>
|
||||
<div class="extra-bar-text" :style="`height: calc(100% - ${parseInt(l1 * 100)}%);`">
|
||||
{{ parseInt(l1 * 100) }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style="font-family: 'BiaoTi';"
|
||||
@click="handleViewTendency(queryParams[0], titleMap[queryParams[0]], 'rot', '回油温度', '℃')"
|
||||
>回油温度</div>
|
||||
<div style="font-family: 'BiaoTi';">回油温度</div>
|
||||
</div>
|
||||
<div class="bottom-grid-item">
|
||||
<div
|
||||
style="width: 100%;aspect-ratio: 1;"
|
||||
class="extra-bar-wrapper"
|
||||
>
|
||||
<div
|
||||
class="extra-bar-item"
|
||||
:style="`height: ${parseInt(l2 * 100)}%;background-color:#19ca88;`"
|
||||
></div>
|
||||
<div
|
||||
class="extra-bar-text"
|
||||
:style="`height: calc(100% - ${parseInt(l2 * 100)}%);`"
|
||||
>
|
||||
<div class="extra-bar-item" :style="`height: ${parseInt(l2 * 100)}%;background-color:#19ca88;`"></div>
|
||||
<div class="extra-bar-text" :style="`height: calc(100% - ${parseInt(l2 * 100)}%);`">
|
||||
{{ parseInt(l2 * 100) }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style="font-family: 'BiaoTi';"
|
||||
@click="jumpSensorDataLog"
|
||||
>轴套区温度</div>
|
||||
<div style="font-family: 'BiaoTi';">轴套区温度</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="grid-item-wrapper"
|
||||
style="grid-column: span 2;"
|
||||
>
|
||||
<div class="grid-item-wrapper" style="grid-column: span 2;">
|
||||
<div class="card-item-wrapper">
|
||||
<div class="big-car-title-bg">油膜轴承系统油品特性</div>
|
||||
<div
|
||||
class="card-main-item-wrapper"
|
||||
style="padding: .8rem 1.2rem;height: calc(100% - 2.4rem);"
|
||||
>
|
||||
<div class="card-main-item-wrapper" style="padding: .8rem 1.2rem;height: calc(100% - 2.4rem);">
|
||||
<div class="bottom-grid-wrapper">
|
||||
<div class="bottom-grid-item">
|
||||
<div
|
||||
style="width: 100%;aspect-ratio: 1;"
|
||||
class="extra-bar-wrapper"
|
||||
>
|
||||
<div
|
||||
class="extra-bar-item"
|
||||
:style="`height: ${parseInt(r1 * 100)}%;background-color:#19ca88;`"
|
||||
></div>
|
||||
<div
|
||||
class="extra-bar-text"
|
||||
:style="`height: calc(100% - ${parseInt(r1 * 100)}%);`"
|
||||
>
|
||||
<div class="extra-bar-item" :style="`height: ${parseInt(r1 * 100)}%;background-color:#19ca88;`"></div>
|
||||
<div class="extra-bar-text" :style="`height: calc(100% - ${parseInt(r1 * 100)}%);`">
|
||||
{{ parseInt(r1 * 100) }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style="font-family: 'BiaoTi';"
|
||||
@click="jumpSensorDataLog"
|
||||
>轴套区温度</div>
|
||||
<div style="font-family: 'BiaoTi';">轴套区温度</div>
|
||||
</div>
|
||||
<div class="bottom-grid-item">
|
||||
<div
|
||||
style="width: 100%;aspect-ratio: 1;"
|
||||
class="extra-bar-wrapper"
|
||||
>
|
||||
<div
|
||||
class="extra-bar-item"
|
||||
:style="`height: ${parseInt(r2 * 100)}%;background-color:#6581f0;`"
|
||||
></div>
|
||||
<div
|
||||
class="extra-bar-text"
|
||||
:style="`height: calc(100% - ${parseInt(r2 * 100)}%);`"
|
||||
>
|
||||
<div class="extra-bar-item" :style="`height: ${parseInt(r2 * 100)}%;background-color:#6581f0;`"></div>
|
||||
<div class="extra-bar-text" :style="`height: calc(100% - ${parseInt(r2 * 100)}%);`">
|
||||
{{ parseInt(r2 * 100) }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style="font-family: 'BiaoTi';"
|
||||
@click="handleViewTendency(queryParams[1], titleMap[queryParams[1]], 'rot', '回油温度', '℃')"
|
||||
>回油温度</div>
|
||||
<div style="font-family: 'BiaoTi';">回油温度</div>
|
||||
</div>
|
||||
<div class="bottom-grid-item">
|
||||
<div
|
||||
id="bottomR1"
|
||||
style="width: 100%;aspect-ratio: 1;"
|
||||
></div>
|
||||
<div
|
||||
style="font-family: 'BiaoTi';"
|
||||
@click="handleViewTendency(queryParams[1], titleMap[queryParams[1]], 'oip', '进油压力', 'Bar')"
|
||||
>进油压力</div>
|
||||
<div id="bottomR1" style="width: 100%;aspect-ratio: 1;"></div>
|
||||
<div style="font-family: 'BiaoTi';">进油压力</div>
|
||||
</div>
|
||||
<div class="bottom-grid-item">
|
||||
<div
|
||||
id="bottomR2"
|
||||
style="width: 100%;aspect-ratio: 1;"
|
||||
></div>
|
||||
<div
|
||||
style="font-family: 'BiaoTi';"
|
||||
@click="handleViewTendency(queryParams[1], titleMap[queryParams[1]], 'ov', '油品粘度', 'Cp')"
|
||||
>油品粘度</div>
|
||||
<div id="bottomR2" style="width: 100%;aspect-ratio: 1;"></div>
|
||||
<div style="font-family: 'BiaoTi';">油品粘度</div>
|
||||
</div>
|
||||
<div class="bottom-grid-item">
|
||||
<div
|
||||
id="bottomR3"
|
||||
style="width: 100%;aspect-ratio: 1;"
|
||||
></div>
|
||||
<div
|
||||
style="font-family: 'BiaoTi';"
|
||||
@click="handleViewTendency(queryParams[1], titleMap[queryParams[1]], 'owc', '油水含量', '%')"
|
||||
>油水含量</div>
|
||||
<div id="bottomR3" style="width: 100%;aspect-ratio: 1;"></div>
|
||||
<div style="font-family: 'BiaoTi';">油水含量</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 添加或修改报警记录对话框 -->
|
||||
<el-dialog
|
||||
:title="title"
|
||||
:visible.sync="open"
|
||||
width="1000px"
|
||||
append-to-body
|
||||
>
|
||||
<div>
|
||||
<el-form
|
||||
:inline="true"
|
||||
size="small"
|
||||
>
|
||||
<el-form-item
|
||||
label="油液颗粒度"
|
||||
v-if="isPz"
|
||||
>
|
||||
<el-radio
|
||||
v-model="nameKey"
|
||||
label="pz4"
|
||||
@change="getData"
|
||||
>4μm</el-radio>
|
||||
<el-radio
|
||||
v-model="nameKey"
|
||||
label="pz6"
|
||||
@change="getData"
|
||||
>6μm</el-radio>
|
||||
<el-radio
|
||||
v-model="nameKey"
|
||||
label="pz14"
|
||||
@change="getData"
|
||||
>14μm</el-radio>
|
||||
<el-radio
|
||||
v-model="nameKey"
|
||||
label="pz21"
|
||||
@change="getData"
|
||||
>21μm</el-radio>
|
||||
</el-form-item>
|
||||
<el-form-item label="时间范围">
|
||||
<el-date-picker
|
||||
@change="getData"
|
||||
class="picker"
|
||||
v-model="datetimerange"
|
||||
type="datetimerange"
|
||||
:picker-options="pickerOptions"
|
||||
range-separator="至"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
>
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-search"
|
||||
size="mini"
|
||||
@click="getData"
|
||||
>搜索</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-refresh"
|
||||
size="mini"
|
||||
@click="resetQuery"
|
||||
>重置</el-button>
|
||||
</el-form-item> -->
|
||||
</el-form>
|
||||
</div>
|
||||
<div
|
||||
v-loading="loading"
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
element-loading-background="rgba(0, 0, 0, 0.8)"
|
||||
ref="tendencyChart"
|
||||
style="height:500px;"
|
||||
></div>
|
||||
<div
|
||||
slot="footer"
|
||||
class="dialog-footer"
|
||||
>
|
||||
<el-button @click="cancel">关 闭</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@ -590,43 +410,41 @@ export default {
|
||||
const { xSensorData, vx, vy, vz } = drive;
|
||||
this.initChart2(xSensorData, vx, vy, vz);
|
||||
|
||||
const { xPlcData, pz4, pz6, pz14, pz21 } = drive;
|
||||
this.initChart4(xPlcData, pz4, pz6, pz14, pz21);
|
||||
const { xPlcData, pz4, pz6, pz14, pz21 } = drive
|
||||
this.initChart4(xPlcData, pz4, pz6, pz14, pz21)
|
||||
|
||||
const { ssat, rot, oip, ov, owc } = drive;
|
||||
const { ssat, rot, oip, ov, owc } = drive
|
||||
|
||||
this.initBottomR1(oip);
|
||||
this.initBottomR2(ov);
|
||||
this.initBottomR3(owc);
|
||||
this.initBottomR1(oip)
|
||||
this.initBottomR2(ov)
|
||||
this.initBottomR3(owc)
|
||||
|
||||
console.log("ssat", ssat);
|
||||
this.r1 = ssat;
|
||||
this.r2 = rot;
|
||||
this.r1 = ssat
|
||||
this.r2 = rot
|
||||
}
|
||||
// 处理操作侧数据
|
||||
if (operation) {
|
||||
const { xSensorData, vx, vy, vz } = operation;
|
||||
this.initChart1(xSensorData, vx, vy, vz);
|
||||
this.initChart1(xSensorData, vx, vy, vz)
|
||||
|
||||
const { xPlcData, pz4, pz6, pz14, pz21 } = operation;
|
||||
this.initChart3(xPlcData, pz4, pz6, pz14, pz21);
|
||||
|
||||
const { owc, ov, oip, rot, ssat } = operation;
|
||||
this.initBottomL1(owc);
|
||||
this.initBottomL2(ov);
|
||||
this.initBottomL3(oip);
|
||||
const { owc, ov, oip, rot, ssat } = operation
|
||||
this.initBottomL1(owc)
|
||||
this.initBottomL2(ov)
|
||||
this.initBottomL3(oip)
|
||||
|
||||
this.l1 = rot;
|
||||
this.l2 = ssat;
|
||||
this.l1 = rot
|
||||
this.l2 = ssat
|
||||
}
|
||||
});
|
||||
})
|
||||
},
|
||||
initChart1(xAxis = [], vx, vy, vz) {
|
||||
const chartIns = echarts.init(document.getElementById("chart1"));
|
||||
chartIns.setOption(
|
||||
this.generateOptions({
|
||||
chartIns.setOption(this.generateOptions({
|
||||
xAxis: {
|
||||
data: xAxis,
|
||||
data: xAxis
|
||||
},
|
||||
yAxis: { name: "单位: ㎛" },
|
||||
tooltip: {
|
||||
@ -658,20 +476,19 @@ export default {
|
||||
data: vz,
|
||||
},
|
||||
],
|
||||
}),
|
||||
true,
|
||||
true
|
||||
);
|
||||
grid: {
|
||||
bottom: "20%",
|
||||
}
|
||||
}), true, true);
|
||||
window.addEventListener("resize", () => {
|
||||
chartIns && chartIns.resize();
|
||||
});
|
||||
},
|
||||
initChart2(xAxis = [], vx, vy, vz) {
|
||||
const chartIns = echarts.init(document.getElementById("chart2"));
|
||||
chartIns.setOption(
|
||||
this.generateOptions({
|
||||
chartIns.setOption(this.generateOptions({
|
||||
xAxis: {
|
||||
data: xAxis,
|
||||
data: xAxis
|
||||
},
|
||||
yAxis: { name: "单位: ㎛" },
|
||||
tooltip: {
|
||||
@ -703,20 +520,19 @@ export default {
|
||||
data: vz,
|
||||
},
|
||||
],
|
||||
}),
|
||||
true,
|
||||
true
|
||||
);
|
||||
grid: {
|
||||
bottom: "20%",
|
||||
}
|
||||
}), true, true);
|
||||
window.addEventListener("resize", () => {
|
||||
chartIns && chartIns.resize();
|
||||
});
|
||||
},
|
||||
initChart3(xAxis = [], pz4, pz6, pz14, pz21) {
|
||||
const chartIns = echarts.init(document.getElementById("chart3"));
|
||||
chartIns.setOption(
|
||||
this.generateOptions({
|
||||
chartIns.setOption(this.generateOptions({
|
||||
xAxis: {
|
||||
data: xAxis,
|
||||
data: xAxis
|
||||
},
|
||||
yAxis: { name: "单位: ㎛" },
|
||||
tooltip: {
|
||||
@ -754,20 +570,16 @@ export default {
|
||||
data: pz21,
|
||||
},
|
||||
],
|
||||
}),
|
||||
true,
|
||||
true
|
||||
);
|
||||
}), true, true);
|
||||
window.addEventListener("resize", () => {
|
||||
chartIns && chartIns.resize();
|
||||
});
|
||||
},
|
||||
initChart4(xAxis = [], pz4, pz6, pz14, pz21) {
|
||||
const chartIns = echarts.init(document.getElementById("chart4"));
|
||||
chartIns.setOption(
|
||||
this.generateOptions({
|
||||
chartIns.setOption(this.generateOptions({
|
||||
xAxis: {
|
||||
data: xAxis,
|
||||
data: xAxis
|
||||
},
|
||||
yAxis: { name: "单位: ㎛" },
|
||||
tooltip: {
|
||||
@ -805,10 +617,7 @@ export default {
|
||||
data: pz21,
|
||||
},
|
||||
],
|
||||
}),
|
||||
true,
|
||||
true
|
||||
);
|
||||
}), true, true);
|
||||
window.addEventListener("resize", () => {
|
||||
chartIns && chartIns.resize();
|
||||
});
|
||||
@ -1279,4 +1088,25 @@ export default {
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-text-wrapper {
|
||||
border: 1px solid #ff0000b5;
|
||||
background-color: #eb16161a;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: .8rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
.scroll-inner {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
animation: scrollAnimation 10s linear infinite;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes scrollAnimation {
|
||||
0% { left: 100%; }
|
||||
100% { left: -100%; }
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user