Compare commits
No commits in common. "ced191b4df7ff38d24fbfb1690d926982ef31add" and "40f426f7f5bdb4dec4eb0e420a2dbbf9a7ffcc4b" have entirely different histories.
ced191b4df
...
40f426f7f5
@ -1,8 +1,8 @@
|
|||||||
<!--
|
<!--
|
||||||
* @Author: gtz
|
* @Author: gtz
|
||||||
* @Date: 2022-03-03 09:16:10
|
* @Date: 2022-03-03 09:16:10
|
||||||
* @LastEditors: zwq
|
* @LastEditors: gtz
|
||||||
* @LastEditTime: 2022-03-17 10:56:14
|
* @LastEditTime: 2022-03-16 19:25:19
|
||||||
* @Description: file content
|
* @Description: file content
|
||||||
* @FilePath: \mt-ck-wms-ui\src\views\basicData\Warehouse\components\processStorageLink.vue
|
* @FilePath: \mt-ck-wms-ui\src\views\basicData\Warehouse\components\processStorageLink.vue
|
||||||
-->
|
-->
|
||||||
@ -11,9 +11,7 @@
|
|||||||
<el-card class="dashboard-main">
|
<el-card class="dashboard-main">
|
||||||
<el-row class="dashboard-title">
|
<el-row class="dashboard-title">
|
||||||
<div class="dashboard-header-line" />
|
<div class="dashboard-header-line" />
|
||||||
<div class="dashboard-header-title">
|
<div class="dashboard-header-title">{{ $t('module.dashboard.title') }}</div>
|
||||||
{{ $t("module.dashboard.title") }}
|
|
||||||
</div>
|
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row class="dashboard-legend">
|
<el-row class="dashboard-legend">
|
||||||
<div
|
<div
|
||||||
@ -40,28 +38,15 @@
|
|||||||
<el-button type="primary" size="mini" @click="submitLinkList">{{
|
<el-button type="primary" size="mini" @click="submitLinkList">{{
|
||||||
"btn.submit" | i18nFilter
|
"btn.submit" | i18nFilter
|
||||||
}}</el-button>
|
}}</el-button>
|
||||||
<el-button type="warning" size="mini" @click="init()">{{
|
<el-button type="warning" size="mini" @click="init()">{{ 'btn.reset' | i18nFilter }}</el-button>
|
||||||
"btn.reset" | i18nFilter
|
<el-button type="success" size="mini" @click="goback()">{{ 'btn.back' | i18nFilter }}</el-button>
|
||||||
}}</el-button>
|
|
||||||
<el-button type="success" size="mini" @click="goback()">{{
|
|
||||||
"btn.back" | i18nFilter
|
|
||||||
}}</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="dashboard-legend-search">
|
<div class="dashboard-legend-search">
|
||||||
<el-select
|
<el-select
|
||||||
v-model="current"
|
v-model="current"
|
||||||
size="mini"
|
size="mini"
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
><el-option
|
><el-option v-for="item in totalPage" :key="'select' + item" :label="$t('module.dashboard.pageHeader') + item + $t('module.dashboard.pageFooter')" :value="item" />
|
||||||
v-for="item in totalPage"
|
|
||||||
:key="'select' + item"
|
|
||||||
:label="
|
|
||||||
$t('module.dashboard.pageHeader') +
|
|
||||||
item +
|
|
||||||
$t('module.dashboard.pageFooter')
|
|
||||||
"
|
|
||||||
:value="item"
|
|
||||||
/>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -113,15 +98,9 @@
|
|||||||
].attribute === 3
|
].attribute === 3
|
||||||
? '#A2A8B5'
|
? '#A2A8B5'
|
||||||
: '',
|
: '',
|
||||||
border: selectStorageList.some(
|
border:
|
||||||
StorageItem =>
|
selectStorageList.some(StorageItem=>StorageItem.locationId===z.portVoList[(current - 1) * 80 + (item - 1) * 20 + (x - 1)].id)
|
||||||
StorageItem.locationId ===
|
? '1px solid red' : ''
|
||||||
z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].id
|
|
||||||
)
|
|
||||||
? '2px dashed red'
|
|
||||||
: ''
|
|
||||||
}"
|
}"
|
||||||
@click="
|
@click="
|
||||||
setType(
|
setType(
|
||||||
@ -131,57 +110,13 @@
|
|||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div
|
<div v-if="z.portVoList[(current - 1) * 80 + (item - 1) * 20 + (x - 1)].attribute !== 3" class="dashboard-layout-item-cricle" :style="{background: z.portVoList[(current - 1) * 80 + (item - 1) * 20 + (x - 1)].cassetteVoList[0] ? cassetteStatusObj[z.portVoList[(current - 1) * 80 + (item - 1) * 20 + (x - 1)].cassetteVoList[0].status] : ''}" />
|
||||||
v-if="
|
{{ z.portVoList[(current - 1) * 80 + (item - 1) * 20 + (x - 1)].attribute !== 3 ? z.portVoList[(current - 1) * 80 + (item - 1) * 20 + (x - 1)].name : 'XXXX' }}
|
||||||
z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].attribute !== 3
|
|
||||||
"
|
|
||||||
class="dashboard-layout-item-cricle"
|
|
||||||
:style="{
|
|
||||||
background: z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].cassetteVoList[0]
|
|
||||||
? cassetteStatusObj[
|
|
||||||
z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].cassetteVoList[0].status
|
|
||||||
]
|
|
||||||
: ''
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
:class="
|
|
||||||
StorageList.some(
|
|
||||||
StorageItem =>
|
|
||||||
StorageItem.id ===
|
|
||||||
z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].id
|
|
||||||
)
|
|
||||||
? 'dashboard-layout-item-horn'
|
|
||||||
: ''
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
{{
|
|
||||||
z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].attribute !== 3
|
|
||||||
? z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].name
|
|
||||||
: "XXXX"
|
|
||||||
}}
|
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<div class="dashboard-layout-footer">
|
<div class="dashboard-layout-footer">
|
||||||
{{
|
{{ $t(bottomIndex[index]) + '(' + ((current - 1) * 4 + item) + ')' }}
|
||||||
$t(bottomIndex[index]) +
|
|
||||||
"(" +
|
|
||||||
((current - 1) * 4 + item) +
|
|
||||||
")"
|
|
||||||
}}
|
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -190,9 +125,7 @@
|
|||||||
<el-row v-else class="dashboard-layout" :gutter="12">
|
<el-row v-else class="dashboard-layout" :gutter="12">
|
||||||
<el-col
|
<el-col
|
||||||
v-for="item in Math.ceil(
|
v-for="item in Math.ceil(
|
||||||
(shelfVoList[0].rowVoList[0].portVoList.length -
|
(shelfVoList[0].rowVoList[0].portVoList.length - (current - 1) * 80) / 20
|
||||||
(current - 1) * 80) /
|
|
||||||
20
|
|
||||||
)"
|
)"
|
||||||
:key="'shelfbox' + item"
|
:key="'shelfbox' + item"
|
||||||
class="dashboard-layout-shelf-box"
|
class="dashboard-layout-shelf-box"
|
||||||
@ -244,15 +177,9 @@
|
|||||||
].attribute === 3
|
].attribute === 3
|
||||||
? '#A2A8B5'
|
? '#A2A8B5'
|
||||||
: '',
|
: '',
|
||||||
border: selectStorageList.some(
|
border:
|
||||||
StorageItem =>
|
selectStorageList.some(StorageItem=>StorageItem.locationId===z.portVoList[(current - 1) * 80 + (item - 1) * 20 + (x - 1)].id)
|
||||||
StorageItem.locationId ===
|
? '1px solid red' : ''
|
||||||
z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].id
|
|
||||||
)
|
|
||||||
? '2px dashed red'
|
|
||||||
: ''
|
|
||||||
}"
|
}"
|
||||||
@click="
|
@click="
|
||||||
setType(
|
setType(
|
||||||
@ -262,47 +189,8 @@
|
|||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div
|
<div v-if="z.portVoList[(current - 1) * 80 + (item - 1) * 20 + (x - 1)].attribute !== 3" class="dashboard-layout-item-cricle" :style="{background: z.portVoList[(current - 1) * 80 + (item - 1) * 20 + (x - 1)].cassetteVoList[0] ? cassetteStatusObj[z.portVoList[(current - 1) * 80 + (item - 1) * 20 + (x - 1)].cassetteVoList[0].status] : ''}" />
|
||||||
v-if="
|
{{ z.portVoList[(current - 1) * 80 + (item - 1) * 20 + (x - 1)].attribute !== 3 ? z.portVoList[(current - 1) * 80 + (item - 1) * 20 + (x - 1)].name : 'XXXX' }}
|
||||||
z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].attribute !== 3
|
|
||||||
"
|
|
||||||
class="dashboard-layout-item-cricle"
|
|
||||||
:style="{
|
|
||||||
background: z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].cassetteVoList[0]
|
|
||||||
? cassetteStatusObj[
|
|
||||||
z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].cassetteVoList[0].status
|
|
||||||
]
|
|
||||||
: ''
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
:class="
|
|
||||||
StorageList.some(
|
|
||||||
StorageItem =>
|
|
||||||
StorageItem.id ===
|
|
||||||
z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].id
|
|
||||||
)
|
|
||||||
? 'dashboard-layout-item-horn'
|
|
||||||
: ''
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
{{
|
|
||||||
z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].attribute !== 3
|
|
||||||
? z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].name
|
|
||||||
: "XXXX"
|
|
||||||
}}
|
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -338,15 +226,9 @@
|
|||||||
].attribute === 3
|
].attribute === 3
|
||||||
? '#A2A8B5'
|
? '#A2A8B5'
|
||||||
: '',
|
: '',
|
||||||
border: selectStorageList.some(
|
border:
|
||||||
StorageItem =>
|
selectStorageList.some(StorageItem=>StorageItem.locationId===z.portVoList[(current - 1) * 80 + (item - 1) * 20 + (x - 1)].id)
|
||||||
StorageItem.locationId ===
|
? '1px solid red' : ''
|
||||||
z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].id
|
|
||||||
)
|
|
||||||
? '2px dashed red'
|
|
||||||
: ''
|
|
||||||
}"
|
}"
|
||||||
@click="
|
@click="
|
||||||
setType(
|
setType(
|
||||||
@ -356,57 +238,13 @@
|
|||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div
|
<div v-if="z.portVoList[(current - 1) * 80 + (item - 1) * 20 + (x - 1)].attribute !== 3" class="dashboard-layout-item-cricle" :style="{background: z.portVoList[(current - 1) * 80 + (item - 1) * 20 + (x - 1)].cassetteVoList[0] ? cassetteStatusObj[z.portVoList[(current - 1) * 80 + (item - 1) * 20 + (x - 1)].cassetteVoList[0].status] : ''}" />
|
||||||
v-if="
|
{{ z.portVoList[(current - 1) * 80 + (item - 1) * 20 + (x - 1)].attribute !== 3 ? z.portVoList[(current - 1) * 80 + (item - 1) * 20 + (x - 1)].name : 'XXXX' }}
|
||||||
z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].attribute !== 3
|
|
||||||
"
|
|
||||||
class="dashboard-layout-item-cricle"
|
|
||||||
:style="{
|
|
||||||
background: z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].cassetteVoList[0]
|
|
||||||
? cassetteStatusObj[
|
|
||||||
z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].cassetteVoList[0].status
|
|
||||||
]
|
|
||||||
: ''
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
:class="
|
|
||||||
StorageList.some(
|
|
||||||
StorageItem =>
|
|
||||||
StorageItem.id ===
|
|
||||||
z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].id
|
|
||||||
)
|
|
||||||
? 'dashboard-layout-item-horn'
|
|
||||||
: ''
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
{{
|
|
||||||
z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].attribute !== 3
|
|
||||||
? z.portVoList[
|
|
||||||
(current - 1) * 80 + (item - 1) * 20 + (x - 1)
|
|
||||||
].name
|
|
||||||
: "XXXX"
|
|
||||||
}}
|
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<div class="dashboard-layout-footer">
|
<div class="dashboard-layout-footer">
|
||||||
{{
|
{{ $t(bottomIndex[index]) + '(' + ((current - 1) * 4 + item) + ')' }}
|
||||||
$t(bottomIndex[index]) +
|
|
||||||
"(" +
|
|
||||||
((current - 1) * 4 + item) +
|
|
||||||
")"
|
|
||||||
}}
|
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -423,7 +261,6 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { getPortList } from '@/api/dashboard'
|
import { getPortList } from '@/api/dashboard'
|
||||||
import { locationByProcessList } from '@/api/basicData/Warehouse/StorageBoxInfo'
|
|
||||||
import { batchListAdd } from '@/api/basicData/Warehouse/StorageBoxInfo'
|
import { batchListAdd } from '@/api/basicData/Warehouse/StorageBoxInfo'
|
||||||
import testdata from './testdata'
|
import testdata from './testdata'
|
||||||
import processStorageType from './processStorageType'
|
import processStorageType from './processStorageType'
|
||||||
@ -436,45 +273,21 @@ export default {
|
|||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.id = this.$route.query.id
|
this.id = this.$route.query.id
|
||||||
this.totalPage = Math.ceil(
|
this.totalPage = Math.ceil(this.shelfVoList[0].rowVoList[0].portVoList.length / 80)
|
||||||
this.shelfVoList[0].rowVoList[0].portVoList.length / 80
|
|
||||||
)
|
|
||||||
this.init()
|
this.init()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
init() {
|
init() {
|
||||||
getPortList().then(res => {
|
getPortList().then(res => {
|
||||||
this.shelfVoList = res.data[0].shelfVoList
|
this.shelfVoList = res.data[0].shelfVoList
|
||||||
this.totalPage = Math.ceil(
|
this.totalPage = Math.ceil(this.shelfVoList[0].rowVoList[0].portVoList.length / 80)
|
||||||
this.shelfVoList[0].rowVoList[0].portVoList.length / 80
|
|
||||||
)
|
|
||||||
})
|
|
||||||
locationByProcessList({
|
|
||||||
current: 1,
|
|
||||||
size: 990,
|
|
||||||
workSequenId: this.id
|
|
||||||
}).then(response => {
|
|
||||||
if (response.data.records) {
|
|
||||||
this.StorageList = response.data.records
|
|
||||||
} else {
|
|
||||||
this.StorageList.splice(0, this.list.length)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
this.selectStorageList.splice(0, this.selectStorageList.length)
|
this.selectStorageList.splice(0, this.selectStorageList.length)
|
||||||
},
|
},
|
||||||
setType(item) {
|
setType(item) {
|
||||||
if (item.attribute !== 3) {
|
if (item.attribute !== 3) {
|
||||||
if (
|
if (this.selectStorageList.findIndex(StorageItem => StorageItem.locationId === item.id) + 1) {
|
||||||
this.selectStorageList.findIndex(
|
this.selectStorageList.splice(this.selectStorageList.findIndex(StorageItem => StorageItem.locationId === item.id), 1)
|
||||||
StorageItem => StorageItem.locationId === item.id
|
|
||||||
) + 1
|
|
||||||
) {
|
|
||||||
this.selectStorageList.splice(
|
|
||||||
this.selectStorageList.findIndex(
|
|
||||||
StorageItem => StorageItem.locationId === item.id
|
|
||||||
),
|
|
||||||
1
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
this.typeVisible = true
|
this.typeVisible = true
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
@ -499,34 +312,22 @@ export default {
|
|||||||
workSequenId: this.id,
|
workSequenId: this.id,
|
||||||
processLocationStorageList: this.selectStorageList
|
processLocationStorageList: this.selectStorageList
|
||||||
}
|
}
|
||||||
this.$confirm(
|
this.$confirm(`${this.$t('module.basicData.visual.TipsStorageBefore')}[${tipArr.join(',')}]?`, this.$t('module.basicData.visual.Tips'), {
|
||||||
`${this.$t(
|
confirmButtonText: this.$t('module.basicData.visual.confirmButtonText'),
|
||||||
'module.basicData.visual.TipsStorageBefore'
|
cancelButtonText: this.$t('module.basicData.visual.cancelButtonText'),
|
||||||
)}[${tipArr.join(',')}]?`,
|
type: 'warning'
|
||||||
this.$t('module.basicData.visual.Tips'),
|
}).then(() => {
|
||||||
{
|
batchListAdd(obj).then(res => {
|
||||||
confirmButtonText: this.$t(
|
this.$message({
|
||||||
'module.basicData.visual.confirmButtonText'
|
message: this.$t('module.basicData.visual.success'),
|
||||||
),
|
type: 'success',
|
||||||
cancelButtonText: this.$t(
|
duration: 1500,
|
||||||
'module.basicData.visual.cancelButtonText'
|
onClose: () => {
|
||||||
),
|
this.init()
|
||||||
type: 'warning'
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
.then(() => {
|
|
||||||
batchListAdd(obj).then(res => {
|
|
||||||
this.$message({
|
|
||||||
message: this.$t('module.basicData.visual.success'),
|
|
||||||
type: 'success',
|
|
||||||
duration: 1500,
|
|
||||||
onClose: () => {
|
|
||||||
this.init()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch(() => {})
|
}).catch(() => {})
|
||||||
} else {
|
} else {
|
||||||
this.$message({
|
this.$message({
|
||||||
message: this.$t('module.basicData.visual.PleaseAddLocationFirst'),
|
message: this.$t('module.basicData.visual.PleaseAddLocationFirst'),
|
||||||
@ -626,7 +427,6 @@ export default {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
position: relative;
|
|
||||||
.dashboard-layout-item-cricle {
|
.dashboard-layout-item-cricle {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 12px;
|
width: 12px;
|
||||||
@ -634,16 +434,6 @@ export default {
|
|||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
}
|
}
|
||||||
.dashboard-layout-item-horn {
|
|
||||||
position: absolute;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
border-style: solid;
|
|
||||||
border-width: 14px 0px 0px 14px;
|
|
||||||
border-color: #0B58FF transparent transparent transparent;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* @Author: gtz
|
* @Author: gtz
|
||||||
* @Date: 2022-03-03 15:47:47
|
* @Date: 2022-03-03 15:47:47
|
||||||
* @LastEditors: zwq
|
* @LastEditors: zwq
|
||||||
* @LastEditTime: 2022-03-17 09:05:02
|
* @LastEditTime: 2022-03-16 09:43:36
|
||||||
* @Description: file content
|
* @Description: file content
|
||||||
* @FilePath: \mt-ck-wms-ui\src\views\dashboard\testdata.js
|
* @FilePath: \mt-ck-wms-ui\src\views\dashboard\testdata.js
|
||||||
*/
|
*/
|
||||||
@ -2603,7 +2603,6 @@ export default {
|
|||||||
4: '#FFA08F'
|
4: '#FFA08F'
|
||||||
},
|
},
|
||||||
selectStorageList: [],
|
selectStorageList: [],
|
||||||
StorageList: [],
|
|
||||||
typeVisible: false,
|
typeVisible: false,
|
||||||
id: '',
|
id: '',
|
||||||
bottomIndex: ['module.dashboard.first', 'module.dashboard.second'],
|
bottomIndex: ['module.dashboard.first', 'module.dashboard.second'],
|
||||||
|
Loading…
Reference in New Issue
Block a user