mirror of
https://codeup.aliyun.com/67762337eccfc218f6110e0e/vue/fe-manage.git
synced 2025-12-09 19:06:45 +08:00
feat:合并
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
<div class="drawerMain">
|
||||
<div class="header">
|
||||
<div v-if="edit" class="headerTitle">编辑评估</div>
|
||||
<div v-else class="headerTitle">添加评估{{assessmentName}}{{assessmentId}}</div>
|
||||
<div v-else class="headerTitle">添加评估</div>
|
||||
<img
|
||||
style="width: 29px; height: 29px; cursor: pointer"
|
||||
src="../../assets/images/basicinfo/close.png"
|
||||
@@ -192,7 +192,7 @@ export default {
|
||||
} else {
|
||||
RouterEditTask({
|
||||
chapterId: props.isactive,
|
||||
courseTaskId: state.assessmentId,
|
||||
courseId: state.assessmentId,
|
||||
name: state.assessmentName,
|
||||
routerId: props.routerId,
|
||||
routerTaskId: props.routerTaskId || 0,
|
||||
|
||||
@@ -166,6 +166,9 @@
|
||||
<button class="btn2" @click="updateTask">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="aeLoading" :style="{ display: addLoading ? 'flex' : 'none' }">
|
||||
<a-spin :spinning="addLoading" tip="" />
|
||||
</div>
|
||||
</a-drawer>
|
||||
</template>
|
||||
<script>
|
||||
@@ -256,6 +259,7 @@ export default {
|
||||
tableDataTotal: 0,
|
||||
pageSize: 10,
|
||||
choicecourse: true,
|
||||
ddLoading:false,
|
||||
});
|
||||
const ChoiceCourse = () => {
|
||||
state.choicecourse = false;
|
||||
@@ -295,7 +299,7 @@ export default {
|
||||
title: "名称",
|
||||
dataIndex: "name",
|
||||
key: "name",
|
||||
width: "40%",
|
||||
width: "30%",
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
@@ -304,20 +308,22 @@ export default {
|
||||
key: "contenttype",
|
||||
width: "15%",
|
||||
align: "center",
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: "授课教师",
|
||||
dataIndex: "teacher",
|
||||
key: "teacher",
|
||||
width: "15%",
|
||||
align: "center",
|
||||
},
|
||||
// {
|
||||
// title: "授课教师",
|
||||
// dataIndex: "teacher",
|
||||
// key: "teacher",
|
||||
// width: "15%",
|
||||
// align: "center",
|
||||
// },
|
||||
{
|
||||
title: "创建人",
|
||||
dataIndex: "sysCreateBy",
|
||||
key: "sysCreateBy",
|
||||
width: "15%x",
|
||||
align: "center",
|
||||
ellipsis: true,
|
||||
},
|
||||
// {
|
||||
// title: "创建时间",
|
||||
@@ -330,8 +336,9 @@ export default {
|
||||
title: "发布时间",
|
||||
dataIndex: "publishTime",
|
||||
key: "publishTime",
|
||||
width: "15%",
|
||||
width: "25%",
|
||||
align: "center",
|
||||
ellipsis: true,
|
||||
},
|
||||
];
|
||||
return columns;
|
||||
@@ -462,9 +469,10 @@ export default {
|
||||
});
|
||||
};
|
||||
const updateTask = () => {
|
||||
|
||||
state.addLoading =true;
|
||||
if (props.isLevel == 1) {
|
||||
if(!props.isactive){
|
||||
state.addLoading =false;
|
||||
message.destroy();
|
||||
return message.warning("请先选中关卡");
|
||||
}
|
||||
@@ -495,6 +503,7 @@ export default {
|
||||
}
|
||||
message.destroy();
|
||||
message.warning("在线课(" + tipStr + ")重复添加");
|
||||
state.addLoading =false;
|
||||
return;
|
||||
} else {
|
||||
state.addOnlineList.map((value) => {
|
||||
@@ -507,16 +516,19 @@ export default {
|
||||
routerTaskId: props.routerTaskId || 0,
|
||||
type: 1,
|
||||
})
|
||||
.then(() => {
|
||||
message.destroy();
|
||||
message.success(
|
||||
.then((res) => {
|
||||
if(res.data.code == 200){
|
||||
message.destroy();
|
||||
message.success(
|
||||
`${props.edit ? "编辑" : "新增"}关卡任务成功`
|
||||
);
|
||||
}
|
||||
ctx.emit("changeData", false);
|
||||
closeDrawer();
|
||||
state.addLoading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
state.addLoading =false;
|
||||
message.destroy();
|
||||
message.error(
|
||||
`${props.edit ? "编辑" : "新增"}关卡任务失败`
|
||||
|
||||
@@ -117,8 +117,8 @@
|
||||
:loading="tableDataTotal === -1 ? true : false"
|
||||
:pagination="false"
|
||||
/>
|
||||
<div class="tableBox">
|
||||
<div class="pa" style="display:flex;justify-content:center;padding:20px;">
|
||||
<div class="tableBox" style="margin-top:85px;">
|
||||
<div class="pa" style="display:flex;justify-content:center;">
|
||||
<a-pagination
|
||||
v-if="tableDataTotal > 10"
|
||||
:showSizeChanger="false"
|
||||
@@ -162,14 +162,16 @@ const columns1 = [
|
||||
width: "30%",
|
||||
dataIndex: "name",
|
||||
key: "name",
|
||||
ellipsis: true,
|
||||
|
||||
},
|
||||
{
|
||||
title: "内容分类",
|
||||
width: "15%",
|
||||
dataIndex: "content",
|
||||
key: "content",
|
||||
dataIndex: "category",
|
||||
key: "category",
|
||||
align: "center",
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: "授课教师",
|
||||
@@ -177,6 +179,7 @@ const columns1 = [
|
||||
dataIndex: "teacher",
|
||||
key: "teacher",
|
||||
align: "center",
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: "创建人",
|
||||
@@ -184,6 +187,7 @@ const columns1 = [
|
||||
dataIndex: "creator",
|
||||
key: "creator",
|
||||
align: "center",
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: "发布时间",
|
||||
@@ -191,6 +195,7 @@ const columns1 = [
|
||||
dataIndex: "time",
|
||||
key: "time",
|
||||
align: "center",
|
||||
ellipsis: true,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -227,6 +232,129 @@ export default {
|
||||
// time: "2022-10-31 23:12:00",
|
||||
// }
|
||||
],
|
||||
options2222: [
|
||||
{
|
||||
title: "领导力",
|
||||
value: "100",
|
||||
selectable: false,
|
||||
children: [
|
||||
{
|
||||
title: "领导业务",
|
||||
value: "1001",
|
||||
},
|
||||
{
|
||||
title: "领导团队",
|
||||
value: "1002",
|
||||
},
|
||||
{
|
||||
title: "领导自我",
|
||||
value: "1003",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "专业力",
|
||||
value: "200",
|
||||
selectable: false,
|
||||
children: [
|
||||
{
|
||||
title: "研发",
|
||||
value: "2001",
|
||||
},
|
||||
{
|
||||
title: "产品和解决方案",
|
||||
value: "2002",
|
||||
},
|
||||
{
|
||||
title: "生产技术与制造",
|
||||
value: "2003",
|
||||
},
|
||||
{
|
||||
title: "供应链",
|
||||
value: "2004",
|
||||
},
|
||||
{
|
||||
title: "营销",
|
||||
value: "2005",
|
||||
},
|
||||
{
|
||||
title: "品质",
|
||||
value: "2006",
|
||||
},
|
||||
{
|
||||
title: "战略与企划",
|
||||
value: "2007",
|
||||
},
|
||||
{
|
||||
title: "流程管理",
|
||||
value: "2008",
|
||||
},
|
||||
{
|
||||
title: "业绩管理",
|
||||
value: "2009",
|
||||
},
|
||||
{
|
||||
title: "项目管理",
|
||||
value: "20010",
|
||||
},
|
||||
{
|
||||
title: "信息技术",
|
||||
value: "20011",
|
||||
},
|
||||
{
|
||||
title: "环境与安全",
|
||||
value: "20012",
|
||||
},
|
||||
{
|
||||
title: "人力资源",
|
||||
value: "20013",
|
||||
},
|
||||
{
|
||||
title: "企业文化",
|
||||
value: "20014",
|
||||
},
|
||||
{
|
||||
title: "品牌",
|
||||
value: "20015",
|
||||
},
|
||||
{
|
||||
title: "财务",
|
||||
value: "20016",
|
||||
},
|
||||
{
|
||||
title: "法务",
|
||||
value: "20017",
|
||||
},
|
||||
{
|
||||
title: "行政",
|
||||
value: "20018",
|
||||
},
|
||||
{
|
||||
title: "医工",
|
||||
value: "20019",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "通用力",
|
||||
value: "300",
|
||||
selectable: false,
|
||||
children: [
|
||||
{
|
||||
title: "职业操守与道德",
|
||||
value: "3001",
|
||||
},
|
||||
{
|
||||
title: "职业素养与技能",
|
||||
value: "3002",
|
||||
},
|
||||
{
|
||||
title: "规章制度",
|
||||
value: "3003",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
currentPage: 1,
|
||||
tableDataTotal: null,
|
||||
pageSize: 10,
|
||||
@@ -311,6 +439,7 @@ export default {
|
||||
const getClassData = (tabledata) => {
|
||||
let data = tabledata;
|
||||
let array = [];
|
||||
let options = state.options2222;
|
||||
data.map((value) => {
|
||||
let obj = {
|
||||
key: value.offcourseId,
|
||||
@@ -320,13 +449,63 @@ export default {
|
||||
creator: value.createName || "-",
|
||||
time: value.publishTime,
|
||||
categoryId: value.categoryId,
|
||||
category:"",
|
||||
//需要判断content
|
||||
};
|
||||
console.log("obj",obj);
|
||||
var breaked = false;
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
for (let j = 0; j < options[i].children.length; j++) {
|
||||
if (
|
||||
String(options[i].children[j].value) ===
|
||||
String(obj.categoryId)
|
||||
) {
|
||||
console.log("obj.categoryId",obj.categoryId);
|
||||
obj.category = options[i].children[j].title;
|
||||
console.log("obj. obj.category ", obj.category );
|
||||
breaked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(breaked){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!obj.category ){
|
||||
obj.category ="-";
|
||||
}
|
||||
console.log("obj. obj.category22 ", obj.category );
|
||||
array.push(obj);
|
||||
});
|
||||
state.classTableData = array;
|
||||
};
|
||||
/**
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
||||
const getCategory=(id)=>{
|
||||
console.log("进来了");
|
||||
let category="";
|
||||
let options = state.options2222;
|
||||
for (let i = 0; i < options.value.length; i++) {
|
||||
for (let j = 0; j < options.value[i].children.length; j++) {
|
||||
if (
|
||||
String(options.value[i].children[j].value) ===
|
||||
String(id)
|
||||
) {
|
||||
console.log();
|
||||
category = options.value[i].children[j].title;
|
||||
|
||||
return category;
|
||||
}
|
||||
}
|
||||
}
|
||||
return category;
|
||||
}
|
||||
|
||||
|
||||
const options1 = ref([
|
||||
{
|
||||
value: 0,
|
||||
@@ -378,6 +557,7 @@ export default {
|
||||
rowSelection,
|
||||
search,
|
||||
submitCourse,
|
||||
|
||||
// change,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="btnn">
|
||||
<button class="btn1">取消</button>
|
||||
<button class="btn1" @click="closeDrawer">取消</button>
|
||||
<button class="btn2" @click="CreatSTText()">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -197,15 +197,15 @@ export default {
|
||||
className: "h",
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: "最近更新时间",
|
||||
dataIndex: "sysUpdateTime",
|
||||
key: "sysUpdateTime",
|
||||
ellipsis: true,
|
||||
width: "20%",
|
||||
align: "center",
|
||||
className: "h",
|
||||
},
|
||||
// {
|
||||
// title: "最近更新时间",
|
||||
// dataIndex: "sysUpdateTime",
|
||||
// // key: "sysUpdateTime",
|
||||
// ellipsis: true,
|
||||
// width: "20%",
|
||||
// align: "center",
|
||||
// className: "h",
|
||||
// },
|
||||
];
|
||||
return columns;
|
||||
}
|
||||
|
||||
@@ -67,6 +67,27 @@ function validateProName() {
|
||||
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.in{
|
||||
.pro{
|
||||
.ant-input-affix-wrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 99%;
|
||||
min-width: 0;
|
||||
padding: 4px 8px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
font-size: 14px;
|
||||
line-height: 1.5715;
|
||||
background-color: #fff;
|
||||
background-image: none;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s;
|
||||
display: inline-flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.in{
|
||||
.ant-input-affix-wrapper {
|
||||
position: relative;
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
</div>
|
||||
<div class="item_inp">
|
||||
<div class="i1_input">
|
||||
<NameInput placeholder="请输入课程名称" v-model:value="qdms_inputV1" v-model:validate="validate"
|
||||
<NameInput ref="inputRef" placeholder="请输入课程名称" v-model:value="qdms_inputV1" v-model:validate="validate"
|
||||
:maxlength="20" show-count :type="2" :id="offcourseId"></NameInput>
|
||||
<!-- <a-input-->
|
||||
<!-- v-model:value="qdms_inputV1"-->
|
||||
@@ -304,7 +304,7 @@
|
||||
<span style="margin-right: 14px">授课教师</span>
|
||||
</div>
|
||||
<div class="item_inp">
|
||||
<div class="i1_input">
|
||||
<div class="select" style="width:88%;">
|
||||
<ProjectManager
|
||||
v-model:value="member.value"
|
||||
v-model:name="member.name"
|
||||
|
||||
@@ -505,7 +505,7 @@ export default {
|
||||
console.log(data);
|
||||
};
|
||||
const reset = () => {
|
||||
(state.valueproj = ""),
|
||||
(state.valueproj = null),
|
||||
(state.valuecreater = null),
|
||||
(state.valuename = null),
|
||||
getList();
|
||||
|
||||
@@ -623,7 +623,7 @@ export default {
|
||||
state.tableData1 = array;
|
||||
};
|
||||
const reset = () => {
|
||||
state.valueproj = "";
|
||||
state.valueproj = null;
|
||||
state.valuecreater = null;
|
||||
state.valuename = null;
|
||||
getFaceList();
|
||||
|
||||
@@ -809,8 +809,8 @@ export default {
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
value: "已停用",
|
||||
label: "已停用",
|
||||
value: "已结束",
|
||||
label: "已结束",
|
||||
classify: -1,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -211,6 +211,14 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="name name2">
|
||||
<div class="namebox">
|
||||
<div class="inname" style="margin-top: 13px">审核意见</div>
|
||||
</div>
|
||||
<div class="description">
|
||||
{{auditDescription}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="template">
|
||||
<div class="name">
|
||||
@@ -267,6 +275,8 @@ import NameInput from "@/components/project/NameInput";
|
||||
import ProjectLevel from "@/components/project/ProjectLevel";
|
||||
import {changeOwnership, scrollLoad} from "@/api/method";
|
||||
import {storage} from "../../api/storage";
|
||||
import * as api2 from "../../api/indexAudit";
|
||||
import {validateName} from "@/api/index1";
|
||||
|
||||
export default {
|
||||
name: "projectAdd",
|
||||
@@ -297,6 +307,7 @@ export default {
|
||||
},
|
||||
classifyList5: [],
|
||||
courseSyncFlag: false,
|
||||
auditDescription:"",
|
||||
});
|
||||
|
||||
// 封面图选择
|
||||
@@ -340,6 +351,24 @@ export default {
|
||||
state.projectInfo.endTime,
|
||||
];
|
||||
state.courseSyncFlag = !!state.projectInfo.courseSyncFlag;
|
||||
if (Number(state.projectInfo.status) === -5) {
|
||||
let obj = {
|
||||
project_id: state.projectInfo.projectId,
|
||||
type: 1,
|
||||
pageNo: 1,
|
||||
pageSize: 1,
|
||||
};
|
||||
api2.auditList(obj).then((d) => {
|
||||
if (d.data.code === 200) {
|
||||
let res =d.data.data;
|
||||
if (res.rows && res.rows.length > 0) {
|
||||
let i = res.rows.length;
|
||||
state.auditDescription = res.rows[i - 1].description ? res.rows[i - 1].description : "-";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -416,16 +445,24 @@ export default {
|
||||
return true;
|
||||
}
|
||||
|
||||
const createProject = () => {
|
||||
const createProject = async() => {
|
||||
console.log("保存", state.projectInfo);
|
||||
if (!validate(state.projectInfo, errorMsgs)) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
if (!state.projectInfo.validate) {
|
||||
message.destroy();
|
||||
message.warning('项目名称重复,请修改名称!');
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
const offName = await validateName({name:state.projectInfo.name, type:1, id:state.projectInfo.projectId}).then(res => {
|
||||
return res.data.data == 1;
|
||||
});
|
||||
if(offName){
|
||||
message.destroy();
|
||||
return message.warning("项目名称重复,请重新填写");
|
||||
}
|
||||
state.projectInfo.type = 3;
|
||||
state.projectInfo.courseSyncFlag = state.courseSyncFlag ? 1 : 0;
|
||||
api.createProject(state.projectInfo).then((res) => {
|
||||
@@ -663,7 +700,10 @@ export default {
|
||||
.name2 {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
||||
.description{
|
||||
margin-top: 14px;
|
||||
margin-left: 11px;
|
||||
}
|
||||
.ant-input-textarea {
|
||||
.ant-input {
|
||||
height: 88px;
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
></a-select>
|
||||
</div>
|
||||
<div class="select addTimeBox">
|
||||
<div class="addTime">项目起止时间:</div>
|
||||
<div class="addTime">创建时间:</div>
|
||||
<a-range-picker
|
||||
v-model:value="searchParam.valueDate"
|
||||
:show-time="{
|
||||
@@ -179,7 +179,7 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="inname">项目名称:</div>
|
||||
<div class="in">
|
||||
<div class="in pro">
|
||||
<NameInput
|
||||
placeholder="请输入项目名称"
|
||||
v-model:value="projectInfo.name"
|
||||
@@ -831,6 +831,7 @@ import dayjs from "dayjs";
|
||||
import * as moment from "moment";
|
||||
import {changeOwnership} from "@/api/method";
|
||||
import NameInput from "@/components/project/NameInput";
|
||||
import {validateName} from "@/api/index1";
|
||||
|
||||
export default {
|
||||
name: "projectManage",
|
||||
@@ -958,7 +959,7 @@ export default {
|
||||
}
|
||||
|
||||
// 创建多层项目
|
||||
const createStoreyProject = () => {
|
||||
const createStoreyProject = async() => {
|
||||
// 接口需要传递的参数信息
|
||||
const errorMsgs = {
|
||||
name: "请输入项目名称",
|
||||
@@ -969,11 +970,19 @@ export default {
|
||||
if (!validate(state.projectInfo, errorMsgs)) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
if (!state.projectInfo.validate) {
|
||||
message.destroy();
|
||||
message.warning("项目名称重复,请修改名称!");
|
||||
return;
|
||||
}
|
||||
} */
|
||||
const offName = await validateName({name: state.qdms_inputV1, type:1, id:state.projectInfo.projectId}).then(res => {
|
||||
return res.data.data == 1;
|
||||
});
|
||||
if(offName){
|
||||
message.destroy();
|
||||
return message.warning("项目名称重复,请重新填写");
|
||||
}
|
||||
api.createProject(state.projectInfo).then((res) => {
|
||||
state.doublepro = false;
|
||||
message.destroy();
|
||||
@@ -1355,6 +1364,7 @@ export default {
|
||||
dayjs().isBefore(value.record.end) ? "进行中" : "已结束",
|
||||
"-1": () => "已结束",
|
||||
"-5": () => "草稿",
|
||||
|
||||
}[value.record.status + ""]() || ""
|
||||
: "-"}
|
||||
</div>
|
||||
@@ -2092,6 +2102,9 @@ export default {
|
||||
font-weight: 400;
|
||||
color: #4ea6ff;
|
||||
margin-right: -45px;
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
margin-right: 18px;
|
||||
|
||||
// line-height: 36px;
|
||||
.operation1 {
|
||||
|
||||
@@ -6,27 +6,22 @@
|
||||
* @FilePath: /fe-manage/vue.config.js
|
||||
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||
*/
|
||||
const {defineConfig} = require("@vue/cli-service");
|
||||
|
||||
const { defineConfig } = require("@vue/cli-service");
|
||||
module.exports = defineConfig({
|
||||
publicPath: "/manage",
|
||||
// transpileDependencies: true,
|
||||
// devServer: {
|
||||
// port: 8080,
|
||||
// proxy: {
|
||||
// "/manageApi": {
|
||||
// target: "http://localhost:30001/",
|
||||
// changeOrigin: true, //表示是否改变原域名
|
||||
// // secure: false,
|
||||
// // ws: false, //表示WebSocket协议
|
||||
// pathRewrite: {
|
||||
// "^/manageApi": "",
|
||||
// },
|
||||
// },
|
||||
// "/userbasic": {
|
||||
// target: "https://u-pre.boe.com",
|
||||
// changeOrigin: true,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
publicPath: "/manage",
|
||||
// transpileDependencies: true,
|
||||
devServer: {
|
||||
port: 8080,
|
||||
proxy: {
|
||||
"/manageApi": {
|
||||
target:"http://111.231.196.214:30001/",
|
||||
changeOrigin: true, //表示是否改变原域名
|
||||
// secure: false,
|
||||
// ws: false, //表示WebSocket协议
|
||||
pathRewrite: {
|
||||
"^/manageApi": "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user