按钮转换成文字类型
This commit is contained in:
@@ -58,21 +58,21 @@
|
|||||||
|
|
||||||
<!-- 按钮组 -->
|
<!-- 按钮组 -->
|
||||||
<!-- 只对默认的编辑、删除、排序按钮进行鉴权,其他按钮请通过 display 属性控制按钮是否显示 -->
|
<!-- 只对默认的编辑、删除、排序按钮进行鉴权,其他按钮请通过 display 属性控制按钮是否显示 -->
|
||||||
<div v-if="field.render == 'buttons' && field.buttons">
|
<div v-if="field.render == 'buttons' && field.buttons" class="cn-render-buttons">
|
||||||
<template v-for="(btn, idx) in field.buttons" :key="idx">
|
<template v-for="(btn, idx) in field.buttons" :key="idx">
|
||||||
|
<template v-if="!(btn.disabled && btn.disabled(row, field))">
|
||||||
<!-- 常规按钮 -->
|
<!-- 常规按钮 -->
|
||||||
<el-button
|
<el-button
|
||||||
|
link
|
||||||
v-if="btn.render == 'basicButton'"
|
v-if="btn.render == 'basicButton'"
|
||||||
@click="onButtonClick(btn)"
|
@click="onButtonClick(btn)"
|
||||||
:class="btn.class"
|
:class="btn.class"
|
||||||
class="table-operate"
|
class="table-operate"
|
||||||
:type="btn.type"
|
:type="btn.type"
|
||||||
:loading="props.row.loading || false"
|
:loading="props.row.loading || false"
|
||||||
:disabled="btn.disabled && btn.disabled(row, field)"
|
|
||||||
v-bind="btn.attr"
|
v-bind="btn.attr"
|
||||||
>
|
>
|
||||||
<Icon v-if="!props.row.loading" :name="btn.icon" />
|
<div v-if="btn.text || btn.title" class="table-operate-text">{{ btn.text || btn.title }}</div>
|
||||||
<div v-if="btn.text" class="table-operate-text">{{ btn.text }}</div>
|
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
<!-- 带提示信息的按钮 -->
|
<!-- 带提示信息的按钮 -->
|
||||||
@@ -83,15 +83,14 @@
|
|||||||
placement="top"
|
placement="top"
|
||||||
>
|
>
|
||||||
<el-button
|
<el-button
|
||||||
|
link
|
||||||
@click="onButtonClick(btn)"
|
@click="onButtonClick(btn)"
|
||||||
:class="btn.class"
|
:class="btn.class"
|
||||||
class="table-operate"
|
class="table-operate"
|
||||||
:type="btn.type"
|
:type="btn.type"
|
||||||
:disabled="btn.disabled && btn.disabled(row, field)"
|
|
||||||
v-bind="btn.attr"
|
v-bind="btn.attr"
|
||||||
>
|
>
|
||||||
<Icon :name="btn.icon" />
|
<div v-if="btn.text || btn.title" class="table-operate-text">{{ btn.text || btn.title }}</div>
|
||||||
<div v-if="btn.text" class="table-operate-text">{{ btn.text }}</div>
|
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
@@ -103,41 +102,24 @@
|
|||||||
@confirm="onButtonClick(btn)"
|
@confirm="onButtonClick(btn)"
|
||||||
>
|
>
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<div class="ml-6">
|
<div style="display: inline-block">
|
||||||
<el-tooltip :disabled="btn.title ? false : true" :content="btn.title" placement="top">
|
<el-tooltip :disabled="btn.title ? false : true" :content="btn.title" placement="top">
|
||||||
<el-button
|
<el-button
|
||||||
|
link
|
||||||
:class="btn.class"
|
:class="btn.class"
|
||||||
class="table-operate"
|
class="table-operate"
|
||||||
:type="btn.type"
|
:type="btn.type"
|
||||||
:disabled="btn.disabled && btn.disabled(row, field)"
|
|
||||||
v-bind="btn.attr"
|
v-bind="btn.attr"
|
||||||
>
|
>
|
||||||
<Icon :name="btn.icon" />
|
<div v-if="btn.text || btn.title" class="table-operate-text">
|
||||||
<div v-if="btn.text" class="table-operate-text">{{ btn.text }}</div>
|
{{ btn.text || btn.title }}
|
||||||
|
</div>
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-popconfirm>
|
</el-popconfirm>
|
||||||
|
</template>
|
||||||
<!-- 带提示的可拖拽按钮 -->
|
|
||||||
<el-tooltip
|
|
||||||
v-if="btn.render == 'moveButton' && btn.name == 'weigh-sort'"
|
|
||||||
:disabled="btn.title && !btn.disabledTip ? false : true"
|
|
||||||
:content="btn.title"
|
|
||||||
placement="top"
|
|
||||||
>
|
|
||||||
<el-button
|
|
||||||
:class="btn.class"
|
|
||||||
class="table-operate move-button"
|
|
||||||
:type="btn.type"
|
|
||||||
:disabled="btn.disabled && btn.disabled(row, field)"
|
|
||||||
v-bind="btn.attr"
|
|
||||||
>
|
|
||||||
<Icon :name="btn.icon" />
|
|
||||||
<div v-if="btn.text" class="table-operate-text">{{ btn.text }}</div>
|
|
||||||
</el-button>
|
|
||||||
</el-tooltip>
|
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -230,4 +212,9 @@ const getTagType = (value: string, custom: any): TagProps['type'] => {
|
|||||||
height: 25px;
|
height: 25px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
.cn-render-buttons {
|
||||||
|
:deep(.el-button) {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ const tableStore = new TableStore({
|
|||||||
{ title: '状态', field: 'stateName' },
|
{ title: '状态', field: 'stateName' },
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
width: '130',
|
width: '10',
|
||||||
render: 'buttons',
|
render: 'buttons',
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
@@ -42,7 +42,7 @@ const tableStore = new TableStore({
|
|||||||
title: '审核通过',
|
title: '审核通过',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-Check',
|
icon: 'el-icon-Check',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
click: row => {
|
click: row => {
|
||||||
checkUser([row.id]).then(res => {
|
checkUser([row.id]).then(res => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ const tableStore = new TableStore({
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: '130',
|
width: '180',
|
||||||
render: 'buttons',
|
render: 'buttons',
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
@@ -57,7 +57,7 @@ const tableStore = new TableStore({
|
|||||||
title: '编辑编辑',
|
title: '编辑编辑',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-EditPen',
|
icon: 'el-icon-EditPen',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
click: row => {
|
click: row => {
|
||||||
popupRef.value.open('编辑接口权限', row)
|
popupRef.value.open('编辑接口权限', row)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,32 +57,32 @@ const tableStore = new TableStore({
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: '130',
|
width: '180',
|
||||||
render: 'buttons',
|
render: 'buttons',
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
name: 'edit',
|
name: 'edit',
|
||||||
title: '新增菜单',
|
text: '新增',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-Plus',
|
icon: 'el-icon-Plus',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
click: row => {
|
click: row => {
|
||||||
popupRef.value.open('新增菜单', { pid: row.id })
|
popupRef.value.open('新增菜单', { pid: row.id })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'edit',
|
name: 'edit',
|
||||||
title: '编辑菜单',
|
text: '编辑',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-EditPen',
|
icon: 'el-icon-EditPen',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
click: row => {
|
click: row => {
|
||||||
popupRef.value.open('编辑菜单', row)
|
popupRef.value.open('编辑菜单', row)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'del',
|
name: 'del',
|
||||||
title: '删除菜单',
|
text: '删除',
|
||||||
type: 'danger',
|
type: 'danger',
|
||||||
icon: 'el-icon-Delete',
|
icon: 'el-icon-Delete',
|
||||||
render: 'confirmButton',
|
render: 'confirmButton',
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ const tableStore = new TableStore({
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: '130',
|
width: '180',
|
||||||
render: 'buttons',
|
render: 'buttons',
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
@@ -78,7 +78,7 @@ const tableStore = new TableStore({
|
|||||||
title: '编辑',
|
title: '编辑',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-EditPen',
|
icon: 'el-icon-EditPen',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
click: row => {
|
click: row => {
|
||||||
popupRef.value.open('编辑角色', row)
|
popupRef.value.open('编辑角色', row)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ const tableStore = new TableStore({
|
|||||||
title: '编辑',
|
title: '编辑',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-EditPen',
|
icon: 'el-icon-EditPen',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
disabled: row => {
|
disabled: row => {
|
||||||
return row.state !== 1
|
return row.state !== 1
|
||||||
},
|
},
|
||||||
@@ -114,7 +114,7 @@ const tableStore = new TableStore({
|
|||||||
title: '修改密码',
|
title: '修改密码',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-Lock',
|
icon: 'el-icon-Lock',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
disabled: row => {
|
disabled: row => {
|
||||||
return row.state !== 1
|
return row.state !== 1
|
||||||
},
|
},
|
||||||
@@ -135,7 +135,7 @@ const tableStore = new TableStore({
|
|||||||
title: '激活',
|
title: '激活',
|
||||||
type: 'success',
|
type: 'success',
|
||||||
icon: 'el-icon-Open',
|
icon: 'el-icon-Open',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
disabled: row => {
|
disabled: row => {
|
||||||
return row.state !== 2 && row.state !== 5 && row.state !== 0 && row.state !== 4
|
return row.state !== 2 && row.state !== 5 && row.state !== 0 && row.state !== 4
|
||||||
},
|
},
|
||||||
@@ -153,7 +153,7 @@ const tableStore = new TableStore({
|
|||||||
title: '注销',
|
title: '注销',
|
||||||
type: 'danger',
|
type: 'danger',
|
||||||
icon: 'el-icon-SwitchButton',
|
icon: 'el-icon-SwitchButton',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
disabled: row => {
|
disabled: row => {
|
||||||
return row.state !== 1 && row.state !== 3
|
return row.state !== 1 && row.state !== 3
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ const tableStore = new TableStore({
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: '130',
|
width: '180',
|
||||||
render: 'buttons',
|
render: 'buttons',
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
@@ -154,7 +154,7 @@ const tableStore = new TableStore({
|
|||||||
title: '波形分析',
|
title: '波形分析',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-DataLine',
|
icon: 'el-icon-DataLine',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
disabled: row => {
|
disabled: row => {
|
||||||
return !row.wavePath && row.evtParamTm < 20
|
return !row.wavePath && row.evtParamTm < 20
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ const tableStore = new TableStore({
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: '130',
|
width: '180',
|
||||||
render: 'buttons',
|
render: 'buttons',
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ const tableStore = new TableStore({
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: '130',
|
width: '180',
|
||||||
render: 'buttons',
|
render: 'buttons',
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
@@ -97,7 +97,7 @@ const tableStore = new TableStore({
|
|||||||
title: '编辑',
|
title: '编辑',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-EditPen',
|
icon: 'el-icon-EditPen',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
click: row => {
|
click: row => {
|
||||||
popupDictionary.value.open('编辑字典', row)
|
popupDictionary.value.open('编辑字典', row)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ const tableStore = new TableStore({
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: '130',
|
width: '180',
|
||||||
render: 'buttons',
|
render: 'buttons',
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ const tableStore = new TableStore({
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: '130',
|
width: '180',
|
||||||
render: 'buttons',
|
render: 'buttons',
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
@@ -74,7 +74,7 @@ const tableStore = new TableStore({
|
|||||||
title: '编辑',
|
title: '编辑',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-EditPen',
|
icon: 'el-icon-EditPen',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
click: row => {
|
click: row => {
|
||||||
popupVersionRef.value.open('编辑版本', row)
|
popupVersionRef.value.open('编辑版本', row)
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ const tableStore = new TableStore({
|
|||||||
title: '启用',
|
title: '启用',
|
||||||
type: 'success',
|
type: 'success',
|
||||||
icon: 'el-icon-Open',
|
icon: 'el-icon-Open',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
disabled: row => {
|
disabled: row => {
|
||||||
return row.status == 1
|
return row.status == 1
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ const tableStore = new TableStore({
|
|||||||
title: '编辑',
|
title: '编辑',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-EditPen',
|
icon: 'el-icon-EditPen',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
|
|
||||||
click: async row => {
|
click: async row => {
|
||||||
dialogFormVisible.value = true
|
dialogFormVisible.value = true
|
||||||
@@ -280,7 +280,7 @@ const tableStore = new TableStore({
|
|||||||
title: '二维码',
|
title: '二维码',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-Grid',
|
icon: 'el-icon-Grid',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
|
|
||||||
click: row => {
|
click: row => {
|
||||||
deivce.value = row
|
deivce.value = row
|
||||||
@@ -305,7 +305,7 @@ const tableStore = new TableStore({
|
|||||||
title: '删除',
|
title: '删除',
|
||||||
type: 'danger',
|
type: 'danger',
|
||||||
icon: 'el-icon-Delete',
|
icon: 'el-icon-Delete',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
|
|
||||||
click: row => {
|
click: row => {
|
||||||
ElMessageBox.confirm('确定删除该设备吗?', '提示', {
|
ElMessageBox.confirm('确定删除该设备吗?', '提示', {
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ const tableStore = new TableStore({
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: '130',
|
width: '180',
|
||||||
render: 'buttons',
|
render: 'buttons',
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
@@ -52,7 +52,7 @@ const tableStore = new TableStore({
|
|||||||
title: '编辑',
|
title: '编辑',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-EditPen',
|
icon: 'el-icon-EditPen',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
click: row => {
|
click: row => {
|
||||||
popupRef.value.open( row)
|
popupRef.value.open( row)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ const tableStore = new TableStore({
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: '130',
|
width: '180',
|
||||||
render: 'buttons',
|
render: 'buttons',
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
@@ -45,7 +45,7 @@ const tableStore = new TableStore({
|
|||||||
title: '绑定指标',
|
title: '绑定指标',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-Connection',
|
icon: 'el-icon-Connection',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
click: row => {
|
click: row => {
|
||||||
bindingRef.value.open(row.id)
|
bindingRef.value.open(row.id)
|
||||||
}
|
}
|
||||||
@@ -55,7 +55,7 @@ const tableStore = new TableStore({
|
|||||||
title: '编辑',
|
title: '编辑',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-EditPen',
|
icon: 'el-icon-EditPen',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
click: row => {
|
click: row => {
|
||||||
addRef.value.open('编辑', row)
|
addRef.value.open('编辑', row)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ const tableStore = new TableStore({
|
|||||||
title: '编辑',
|
title: '编辑',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-EditPen',
|
icon: 'el-icon-EditPen',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
click: row => {
|
click: row => {
|
||||||
popupEditRef.value.open('编辑', {
|
popupEditRef.value.open('编辑', {
|
||||||
...row,
|
...row,
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ const tableStore = new TableStore({
|
|||||||
title: '查看',
|
title: '查看',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-ZoomIn',
|
icon: 'el-icon-ZoomIn',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
click: row => {
|
click: row => {
|
||||||
detail.value = row
|
detail.value = row
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ const tableStore = new TableStore({
|
|||||||
title: '编辑',
|
title: '编辑',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-EditPen',
|
icon: 'el-icon-EditPen',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
click: row => {
|
click: row => {
|
||||||
popupEditRef.value.open('编辑字典类型', row)
|
popupEditRef.value.open('编辑字典类型', row)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ const tableStore = new TableStore({
|
|||||||
title: '新增',
|
title: '新增',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-Plus',
|
icon: 'el-icon-Plus',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
click: row => {
|
click: row => {
|
||||||
popupFormRef.value.open('新增字典类型', {
|
popupFormRef.value.open('新增字典类型', {
|
||||||
name: '',
|
name: '',
|
||||||
@@ -74,7 +74,7 @@ const tableStore = new TableStore({
|
|||||||
title: '编辑',
|
title: '编辑',
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
icon: 'el-icon-EditPen',
|
icon: 'el-icon-EditPen',
|
||||||
render: 'tipButton',
|
render: 'basicButton',
|
||||||
click: row => {
|
click: row => {
|
||||||
popupFormRef.value.open('编辑字典类型', row)
|
popupFormRef.value.open('编辑字典类型', row)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user