no message
This commit is contained in:
parent
d54b469683
commit
eee1a6cb96
@ -91,7 +91,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</EDropdownItem>
|
</EDropdownItem>
|
||||||
<EDropdownItem divided disabled>{{$L('颜色')}}</EDropdownItem>
|
<EDropdownItem divided disabled>{{$L('颜色')}}</EDropdownItem>
|
||||||
<EDropdownItem v-for="(c, k) in columnColorList" :key="k" :command="c">
|
<EDropdownItem v-for="(c, k) in $store.state.columnColorList" :key="k" :command="c">
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<i class="iconfont" :style="{color:c.color}" v-html="c.color == column.color ? '' : ''"></i>{{$L(c.name)}}
|
<i class="iconfont" :style="{color:c.color}" v-html="c.color == column.color ? '' : ''"></i>{{$L(c.name)}}
|
||||||
</div>
|
</div>
|
||||||
@ -157,7 +157,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</EDropdownItem>
|
</EDropdownItem>
|
||||||
<EDropdownItem divided disabled>{{$L('背景色')}}</EDropdownItem>
|
<EDropdownItem divided disabled>{{$L('背景色')}}</EDropdownItem>
|
||||||
<EDropdownItem v-for="(c, k) in taskColorList" :key="k" :command="c">
|
<EDropdownItem v-for="(c, k) in $store.state.taskColorList" :key="k" :command="c">
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<i class="iconfont" :style="{color:c.color||'#f9f9f9'}" v-html="c.color == item.color ? '' : ''"></i>{{$L(c.name)}}
|
<i class="iconfont" :style="{color:c.color||'#f9f9f9'}" v-html="c.color == item.color ? '' : ''"></i>{{$L(c.name)}}
|
||||||
</div>
|
</div>
|
||||||
@ -241,7 +241,7 @@
|
|||||||
<Col span="3"></Col>
|
<Col span="3"></Col>
|
||||||
<Col span="3"></Col>
|
<Col span="3"></Col>
|
||||||
</Row>
|
</Row>
|
||||||
<TaskRow :list="myList" open-key="my" :color-list="taskColorList" @command="dropTask" fast-add-task/>
|
<TaskRow :list="myList" open-key="my" @command="dropTask" fast-add-task/>
|
||||||
</div>
|
</div>
|
||||||
<!--未完成任务-->
|
<!--未完成任务-->
|
||||||
<div v-if="projectData.task_num > 0" :class="['project-table-body', !taskUndoneShow ? 'project-table-hide' : '']">
|
<div v-if="projectData.task_num > 0" :class="['project-table-body', !taskUndoneShow ? 'project-table-hide' : '']">
|
||||||
@ -256,7 +256,7 @@
|
|||||||
<Col span="3"></Col>
|
<Col span="3"></Col>
|
||||||
<Col span="3"></Col>
|
<Col span="3"></Col>
|
||||||
</Row>
|
</Row>
|
||||||
<TaskRow :list="undoneList" open-key="undone" :color-list="taskColorList" @command="dropTask"/>
|
<TaskRow :list="undoneList" open-key="undone" @command="dropTask"/>
|
||||||
</div>
|
</div>
|
||||||
<!--已完成任务-->
|
<!--已完成任务-->
|
||||||
<div v-if="projectData.task_num > 0" :class="['project-table-body', !taskCompletedShow ? 'project-table-hide' : '']">
|
<div v-if="projectData.task_num > 0" :class="['project-table-body', !taskCompletedShow ? 'project-table-hide' : '']">
|
||||||
@ -271,7 +271,7 @@
|
|||||||
<Col span="3"></Col>
|
<Col span="3"></Col>
|
||||||
<Col span="3"></Col>
|
<Col span="3"></Col>
|
||||||
</Row>
|
</Row>
|
||||||
<TaskRow :list="completedList" open-key="completed" :color-list="taskColorList" @command="dropTask"/>
|
<TaskRow :list="completedList" open-key="completed" @command="dropTask"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -385,29 +385,6 @@ export default {
|
|||||||
transferShow: false,
|
transferShow: false,
|
||||||
transferData: {},
|
transferData: {},
|
||||||
transferLoad: 0,
|
transferLoad: 0,
|
||||||
|
|
||||||
columnColorList: [
|
|
||||||
{name: '默认', color: ''},
|
|
||||||
{name: '灰色', color: '#6C6F71'},
|
|
||||||
{name: '棕色', color: '#695C56'},
|
|
||||||
{name: '橘色', color: '#9E7549'},
|
|
||||||
{name: '黄色', color: '#A0904F'},
|
|
||||||
{name: '绿色', color: '#4D7771'},
|
|
||||||
{name: '蓝色', color: '#4C7088'},
|
|
||||||
{name: '紫色', color: '#6B5C8D'},
|
|
||||||
{name: '粉色', color: '#8E5373'},
|
|
||||||
{name: '红色', color: '#9D6058'},
|
|
||||||
],
|
|
||||||
|
|
||||||
taskColorList: [
|
|
||||||
{name: '默认', color: ''},
|
|
||||||
{name: '黄色', color: '#FCF4A7'},
|
|
||||||
{name: '蓝色', color: '#BCF2FD'},
|
|
||||||
{name: '绿色', color: '#C3FDAA'},
|
|
||||||
{name: '粉色', color: '#F6C9C8'},
|
|
||||||
{name: '紫色', color: '#BAC9FB'},
|
|
||||||
{name: '灰色', color: '#EEEEEE'},
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
</EDropdownItem>
|
</EDropdownItem>
|
||||||
<template v-if="item.parent_id === 0">
|
<template v-if="item.parent_id === 0">
|
||||||
<EDropdownItem v-if="item.parent_id === 0" divided disabled>{{$L('背景色')}}</EDropdownItem>
|
<EDropdownItem v-if="item.parent_id === 0" divided disabled>{{$L('背景色')}}</EDropdownItem>
|
||||||
<EDropdownItem v-for="(c, k) in colorList" :key="k" :command="c">
|
<EDropdownItem v-for="(c, k) in $store.state.taskColorList" :key="k" :command="c">
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<i class="iconfont" :style="{color:c.color||'#f9f9f9'}" v-html="c.color == item.color ? '' : ''"></i>{{$L(c.name)}}
|
<i class="iconfont" :style="{color:c.color||'#f9f9f9'}" v-html="c.color == item.color ? '' : ''"></i>{{$L(c.name)}}
|
||||||
</div>
|
</div>
|
||||||
@ -87,7 +87,6 @@
|
|||||||
:list="subTask(item.id)"
|
:list="subTask(item.id)"
|
||||||
:parent-id="item.id"
|
:parent-id="item.id"
|
||||||
:fast-add-task="item.parent_id===0 && fastAddTask"
|
:fast-add-task="item.parent_id===0 && fastAddTask"
|
||||||
:color-list="colorList"
|
|
||||||
:open-key="openKey"
|
:open-key="openKey"
|
||||||
@command="dropTask"/>
|
@command="dropTask"/>
|
||||||
</div>
|
</div>
|
||||||
@ -110,12 +109,6 @@ export default {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
colorList: {
|
|
||||||
type: Array,
|
|
||||||
default: () => {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
parentId: {
|
parentId: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0
|
default: 0
|
||||||
|
@ -29,10 +29,51 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<div class="dashboard-title">{{title}}</div>
|
<div class="dashboard-title">{{title}}</div>
|
||||||
<ul class="dashboard-list overlay-y">
|
<ul class="dashboard-list overlay-y">
|
||||||
<li v-for="item in list" :key="item.id" @click="$store.dispatch('openTask', item.id)">
|
<li v-for="item in list" :key="item.id" :style="item.color ? {backgroundColor: item.color} : {}">
|
||||||
<i class="iconfont"></i>
|
<EDropdown
|
||||||
<div class="item-title">{{item.name}}</div>
|
trigger="click"
|
||||||
<div class="item-time"></div>
|
size="small"
|
||||||
|
placement="bottom"
|
||||||
|
@command="dropTask(item, $event)">
|
||||||
|
<div class="drop-icon">
|
||||||
|
<i class="iconfont"></i>
|
||||||
|
</div>
|
||||||
|
<EDropdownMenu slot="dropdown" class="project-list-more-dropdown-menu">
|
||||||
|
<EDropdownItem v-if="item.complete_at" command="uncomplete">
|
||||||
|
<div class="item red">
|
||||||
|
<Icon type="md-checkmark-circle-outline" />{{$L('标记未完成')}}
|
||||||
|
</div>
|
||||||
|
</EDropdownItem>
|
||||||
|
<EDropdownItem v-else command="complete">
|
||||||
|
<div class="item">
|
||||||
|
<Icon type="md-radio-button-off" />{{$L('完成')}}
|
||||||
|
</div>
|
||||||
|
</EDropdownItem>
|
||||||
|
<EDropdownItem v-if="item.parent_id === 0" command="archived">
|
||||||
|
<div class="item">
|
||||||
|
<Icon type="ios-filing" />{{$L('归档')}}
|
||||||
|
</div>
|
||||||
|
</EDropdownItem>
|
||||||
|
<EDropdownItem command="remove">
|
||||||
|
<div class="item">
|
||||||
|
<Icon type="md-trash" />{{$L('删除')}}
|
||||||
|
</div>
|
||||||
|
</EDropdownItem>
|
||||||
|
<template v-if="item.parent_id === 0">
|
||||||
|
<EDropdownItem v-if="item.parent_id === 0" divided disabled>{{$L('背景色')}}</EDropdownItem>
|
||||||
|
<EDropdownItem v-for="(c, k) in $store.state.taskColorList" :key="k" :command="c">
|
||||||
|
<div class="item">
|
||||||
|
<i class="iconfont" :style="{color:c.color||'#f9f9f9'}" v-html="c.color == item.color ? '' : ''"></i>{{$L(c.name)}}
|
||||||
|
</div>
|
||||||
|
</EDropdownItem>
|
||||||
|
</template>
|
||||||
|
</EDropdownMenu>
|
||||||
|
</EDropdown>
|
||||||
|
<div class="item-title" @click="$store.dispatch('openTask', item.id)">{{item.name}}</div>
|
||||||
|
<div :class="['item-time', item.today ? 'today' : '', item.overdue ? 'overdue' : '']">
|
||||||
|
<Icon type="ios-time-outline"/>
|
||||||
|
{{expiresFormat(item.end_at)}}
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -45,12 +86,27 @@ import {mapState} from "vuex";
|
|||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
nowTime: Math.round(new Date().getTime() / 1000),
|
||||||
|
nowInterval: null,
|
||||||
|
|
||||||
loadIng: 0,
|
loadIng: 0,
|
||||||
active: false,
|
active: false,
|
||||||
dashboard: 'today',
|
dashboard: 'today',
|
||||||
|
|
||||||
|
taskLoad: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.nowInterval = setInterval(() => {
|
||||||
|
this.nowTime = Math.round(new Date().getTime() / 1000);
|
||||||
|
}, 1000)
|
||||||
|
},
|
||||||
|
|
||||||
|
destroyed() {
|
||||||
|
clearInterval(this.nowInterval)
|
||||||
|
},
|
||||||
|
|
||||||
activated() {
|
activated() {
|
||||||
this.getTask();
|
this.getTask();
|
||||||
this.active = true;
|
this.active = true;
|
||||||
@ -81,14 +137,19 @@ export default {
|
|||||||
const todayStart = new Date($A.formatDate("Y-m-d 00:00:00")),
|
const todayStart = new Date($A.formatDate("Y-m-d 00:00:00")),
|
||||||
todayEnd = new Date($A.formatDate("Y-m-d 23:59:59"));
|
todayEnd = new Date($A.formatDate("Y-m-d 23:59:59"));
|
||||||
return tasks.filter((data) => {
|
return tasks.filter((data) => {
|
||||||
const start = new Date(data.start_at),
|
|
||||||
end = new Date(data.end_at);
|
|
||||||
if (data.parent_id > 0) {
|
if (data.parent_id > 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (data.complete_at) {
|
if (data.complete_at) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!data.end_at) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const start = new Date(data.start_at),
|
||||||
|
end = new Date(data.end_at);
|
||||||
|
data._start_time = start;
|
||||||
|
data._end_time = end;
|
||||||
switch (dashboard) {
|
switch (dashboard) {
|
||||||
case 'today':
|
case 'today':
|
||||||
return (start >= todayStart && start <= todayEnd) || (end >= todayStart && end <= todayEnd);
|
return (start >= todayStart && start <= todayEnd) || (end >= todayStart && end <= todayEnd);
|
||||||
@ -97,8 +158,26 @@ export default {
|
|||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}).sort((a, b) => {
|
||||||
|
if (a._end_time != b._end_time) {
|
||||||
|
return a._end_time - b._end_time;
|
||||||
|
}
|
||||||
|
return a.id - b.id;
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
|
||||||
|
expiresFormat() {
|
||||||
|
const {nowTime} = this;
|
||||||
|
return function (date) {
|
||||||
|
let time = Math.round(new Date(date).getTime() / 1000) - nowTime;
|
||||||
|
if (time < 86400 * 4 && time > 0 ) {
|
||||||
|
return this.formatSeconds(time);
|
||||||
|
} else if (time <= 0) {
|
||||||
|
return '-' + this.formatSeconds(time * -1);
|
||||||
|
}
|
||||||
|
return this.formatTime(date)
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
@ -140,7 +219,117 @@ export default {
|
|||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
this.loadIng--;
|
this.loadIng--;
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
|
|
||||||
|
dropTask(task, command) {
|
||||||
|
switch (command) {
|
||||||
|
case 'complete':
|
||||||
|
if (task.complete_at) return;
|
||||||
|
this.updateTask(task, {
|
||||||
|
complete_at: $A.formatDate("Y-m-d H:i:s")
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case 'uncomplete':
|
||||||
|
if (!task.complete_at) return;
|
||||||
|
this.updateTask(task, {
|
||||||
|
complete_at: false
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case 'archived':
|
||||||
|
case 'remove':
|
||||||
|
this.archivedOrRemoveTask(task, command);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (command.name) {
|
||||||
|
this.updateTask(task, {
|
||||||
|
color: command.color
|
||||||
|
})
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
updateTask(task, updata) {
|
||||||
|
if (this.taskLoad[task.id] === true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$set(this.taskLoad, task.id, true);
|
||||||
|
//
|
||||||
|
Object.keys(updata).forEach(key => this.$set(task, key, updata[key]));
|
||||||
|
//
|
||||||
|
this.$store.dispatch("taskUpdate", Object.assign(updata, {
|
||||||
|
task_id: task.id,
|
||||||
|
})).then(() => {
|
||||||
|
this.$set(this.taskLoad, task.id, false);
|
||||||
|
}).catch(({msg}) => {
|
||||||
|
$A.modalError(msg);
|
||||||
|
this.$set(this.taskLoad, task.id, false);
|
||||||
|
this.$store.dispatch("getTaskOne", task.id);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
archivedOrRemoveTask(task, type) {
|
||||||
|
let typeDispatch = type == 'remove' ? 'removeTask' : 'archivedTask';
|
||||||
|
let typeName = type == 'remove' ? '删除' : '归档';
|
||||||
|
let typeTask = task.parent_id > 0 ? '子任务' : '任务';
|
||||||
|
$A.modalConfirm({
|
||||||
|
title: typeName + typeTask,
|
||||||
|
content: '你确定要' + typeName + typeTask + '【' + task.name + '】吗?',
|
||||||
|
loading: true,
|
||||||
|
onOk: () => {
|
||||||
|
if (this.taskLoad[task.id] === true) {
|
||||||
|
this.$Modal.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$set(this.taskLoad, task.id, true);
|
||||||
|
this.$store.dispatch(typeDispatch, task.id).then(({msg}) => {
|
||||||
|
$A.messageSuccess(msg);
|
||||||
|
this.$Modal.remove();
|
||||||
|
this.$set(this.taskLoad, task.id, false);
|
||||||
|
}).catch(({msg}) => {
|
||||||
|
$A.modalError(msg, 301);
|
||||||
|
this.$Modal.remove();
|
||||||
|
this.$set(this.taskLoad, task.id, false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
formatTime(date) {
|
||||||
|
let time = Math.round(new Date(date).getTime() / 1000),
|
||||||
|
string = '';
|
||||||
|
if ($A.formatDate('Ymd') === $A.formatDate('Ymd', time)) {
|
||||||
|
string = $A.formatDate('H:i', time)
|
||||||
|
} else if ($A.formatDate('Y') === $A.formatDate('Y', time)) {
|
||||||
|
string = $A.formatDate('m-d', time)
|
||||||
|
} else {
|
||||||
|
string = $A.formatDate('Y-m-d', time)
|
||||||
|
}
|
||||||
|
return string || '';
|
||||||
|
},
|
||||||
|
|
||||||
|
formatBit(val) {
|
||||||
|
val = +val
|
||||||
|
return val > 9 ? val : '0' + val
|
||||||
|
},
|
||||||
|
|
||||||
|
formatSeconds(second) {
|
||||||
|
let duration
|
||||||
|
let days = Math.floor(second / 86400);
|
||||||
|
let hours = Math.floor((second % 86400) / 3600);
|
||||||
|
let minutes = Math.floor(((second % 86400) % 3600) / 60);
|
||||||
|
let seconds = Math.floor(((second % 86400) % 3600) % 60);
|
||||||
|
if (days > 0) {
|
||||||
|
if (hours > 0) duration = days + "d," + this.formatBit(hours) + "h";
|
||||||
|
else if (minutes > 0) duration = days + "d," + this.formatBit(minutes) + "min";
|
||||||
|
else if (seconds > 0) duration = days + "d," + this.formatBit(seconds) + "s";
|
||||||
|
else duration = days + "d";
|
||||||
|
}
|
||||||
|
else if (hours > 0) duration = this.formatBit(hours) + ":" + this.formatBit(minutes) + ":" + this.formatBit(seconds);
|
||||||
|
else if (minutes > 0) duration = this.formatBit(minutes) + ":" + this.formatBit(seconds);
|
||||||
|
else if (seconds > 0) duration = this.formatBit(seconds) + "s";
|
||||||
|
return duration;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
22
resources/assets/js/store/state.js
vendored
22
resources/assets/js/store/state.js
vendored
@ -280,6 +280,28 @@ state.taskLogs = [];
|
|||||||
state.projectId = 0;
|
state.projectId = 0;
|
||||||
state.taskId = 0;
|
state.taskId = 0;
|
||||||
|
|
||||||
|
state.columnColorList = [
|
||||||
|
{name: '默认', color: ''},
|
||||||
|
{name: '灰色', color: '#6C6F71'},
|
||||||
|
{name: '棕色', color: '#695C56'},
|
||||||
|
{name: '橘色', color: '#9E7549'},
|
||||||
|
{name: '黄色', color: '#A0904F'},
|
||||||
|
{name: '绿色', color: '#4D7771'},
|
||||||
|
{name: '蓝色', color: '#4C7088'},
|
||||||
|
{name: '紫色', color: '#6B5C8D'},
|
||||||
|
{name: '粉色', color: '#8E5373'},
|
||||||
|
{name: '红色', color: '#9D6058'},
|
||||||
|
];
|
||||||
|
state.taskColorList = [
|
||||||
|
{name: '默认', color: ''},
|
||||||
|
{name: '黄色', color: '#FCF4A7'},
|
||||||
|
{name: '蓝色', color: '#BCF2FD'},
|
||||||
|
{name: '绿色', color: '#C3FDAA'},
|
||||||
|
{name: '粉色', color: '#F6C9C8'},
|
||||||
|
{name: '紫色', color: '#BAC9FB'},
|
||||||
|
{name: '灰色', color: '#EEEEEE'},
|
||||||
|
];
|
||||||
|
|
||||||
// 会话聊天
|
// 会话聊天
|
||||||
state.dialogId = 0;
|
state.dialogId = 0;
|
||||||
state.dialogList = [];
|
state.dialogList = [];
|
||||||
|
26
resources/assets/sass/pages/page-dashboard.scss
vendored
26
resources/assets/sass/pages/page-dashboard.scss
vendored
@ -99,13 +99,15 @@
|
|||||||
&:last-child {
|
&:last-child {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
.iconfont {
|
.el-dropdown {
|
||||||
color: #bbbbbb;
|
|
||||||
font-size: 18px;
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
width: 22px;
|
width: 22px;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
line-height: 22px;
|
line-height: 22px;
|
||||||
|
.iconfont {
|
||||||
|
color: #bbbbbb;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.item-title {
|
.item-title {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@ -113,8 +115,24 @@
|
|||||||
line-height: 22px;
|
line-height: 22px;
|
||||||
}
|
}
|
||||||
.item-time {
|
.item-time {
|
||||||
padding-left: 12px;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 22px;
|
||||||
|
line-height: 22px;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-left: 12px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
color: #aaaaaa;
|
||||||
|
&.overdue {
|
||||||
|
color: #ed4014;
|
||||||
|
}
|
||||||
|
&.today {
|
||||||
|
color: #ff9900;
|
||||||
|
}
|
||||||
|
.ivu-icon {
|
||||||
|
margin-right: 3px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user