'update'
This commit is contained in:
parent
41e680b55d
commit
0b5740d41c
@ -4,7 +4,7 @@
|
||||
* @Author: fzq
|
||||
* @Date: 2022-11-25 09:51:46
|
||||
* @LastEditors: fzq
|
||||
* @LastEditTime: 2023-02-07 16:19:50
|
||||
* @LastEditTime: 2023-02-09 14:40:52
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
@ -39,7 +39,8 @@
|
||||
<!-- 开发环境 -->
|
||||
<% if (process.env.VUE_APP_NODE_ENV === 'dev') { %>
|
||||
<script>
|
||||
window.SITE_CONFIG['apiURL'] = 'http://192.168.1.8';
|
||||
// window.SITE_CONFIG['apiURL'] = 'http://192.168.1.8';
|
||||
window.SITE_CONFIG['apiURL'] = 'http://india.mes.picaiba.com/';
|
||||
</script>
|
||||
<% } %>
|
||||
<!-- 集成测试环境 -->
|
||||
|
@ -1,10 +1,12 @@
|
||||
<template>
|
||||
<div class="attr-form">
|
||||
<h3>
|
||||
{{ title }} <el-button style="margin-left: 8px;" type="text" v-if="!isDetail && !showAddAttr" @click="showAddAttr = true">{{ $t('add') }}</el-button>
|
||||
<!-- <el-button style="margin-left: 8px" type="text" v-if="!isDetail && !showAddAttr" @click="showAddAttr = true">{{ $t('add') }}</el-button> 跟在{{ title }} 同行后面 -->
|
||||
{{ title }}
|
||||
</h3>
|
||||
<div v-if="!showAddAttr">
|
||||
<component
|
||||
:top-btn-config="topBtnConfig"
|
||||
key="sub-table"
|
||||
:is="require('../../base-table/index.vue').default"
|
||||
:table-head-configs="filterTableConfigs()"
|
||||
@ -12,8 +14,8 @@
|
||||
:page="pageIndex"
|
||||
:size="pageSize"
|
||||
:max-height="calcMaxHeight(8)"
|
||||
@operate-event="handleOperations"
|
||||
/>
|
||||
@clickTopBtn="clickTopBtn"
|
||||
@operate-event="handleOperations" />
|
||||
<el-pagination
|
||||
@size-change="sizeChangeHandle"
|
||||
@current-change="currentChangeHandle"
|
||||
@ -21,15 +23,14 @@
|
||||
:page-sizes="[5, 10, 20, 50]"
|
||||
:page-size="pageSize"
|
||||
:total="totalPage"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
>
|
||||
layout="total, sizes, prev, pager, next, jumper">
|
||||
</el-pagination>
|
||||
</div>
|
||||
<div v-else style="background: #eee; border-radius: 8px; padding: 12px;">
|
||||
<div v-else style="background: #eee; border-radius: 8px; padding: 12px">
|
||||
<el-row>
|
||||
<el-col>
|
||||
<el-form ref="AttrForm" :model="AttrForm" :rules="AttrFormRules" :inline="true" label-position="top">
|
||||
<el-row :gutter="20" style="padding: 0 24px;">
|
||||
<el-row :gutter="20" style="padding: 0 24px">
|
||||
<el-col :span="attrFormFields.length > 6 ? 6 : 12" v-for="field in attrFormFields" :key="field.prop + 'col'">
|
||||
<el-form-item :key="field.prop" :prop="field.prop" :label="field.name" style="width: 100%">
|
||||
<el-input v-if="field.formType === 'input' || !field.formType" v-model="AttrForm[field.prop]" :placeholder="$t('hints.input')" clearable />
|
||||
@ -43,7 +44,7 @@
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row style="text-align: right;">
|
||||
<el-row style="text-align: right">
|
||||
<el-button size="small" @click="handleCloseAttrForm">{{ $t('cancel') }}</el-button>
|
||||
<el-button type="success" size="small" @click="handleSaveAttrForm">{{ $t('save') }}</el-button>
|
||||
</el-row>
|
||||
@ -56,6 +57,12 @@ import i18n from '@/i18n'
|
||||
import BaseTable from '@/components/base-table'
|
||||
import { pick } from 'lodash/object'
|
||||
import { calcMaxHeight } from '@/utils'
|
||||
const topBtnConfig = [
|
||||
{
|
||||
type: 'add',
|
||||
btnName: i18n.t('add')
|
||||
}
|
||||
]
|
||||
export default {
|
||||
name: 'AttrForm',
|
||||
components: { BaseTable },
|
||||
@ -96,6 +103,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
calcMaxHeight,
|
||||
topBtnConfig,
|
||||
showAddAttr: false,
|
||||
dataList: [],
|
||||
pageIndex: 1,
|
||||
@ -107,9 +115,9 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
attrFormFields() {
|
||||
const _ = this.tableConfigs.filter(item => item.formField)
|
||||
const _ = this.tableConfigs.filter((item) => item.formField)
|
||||
/** 顺带配置 AttrForm */
|
||||
_.forEach(item => {
|
||||
_.forEach((item) => {
|
||||
this.$set(this.AttrForm, [item.prop], '')
|
||||
})
|
||||
|
||||
@ -126,11 +134,17 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
// 加个created,来实现不能在topBtnConfig组件直接使用的? : 判别
|
||||
created() {
|
||||
// if(!(!this.isDetail && !this.showAddAttr)) {
|
||||
// this.topBtnConfig = []
|
||||
// }
|
||||
},
|
||||
methods: {
|
||||
filterTableConfigs() {
|
||||
if (this.isDetail) {
|
||||
/** 如果是查看详情,就屏蔽操作列 */
|
||||
return this.tableConfigs.filter(opt => opt.prop !== 'operations')
|
||||
return this.tableConfigs.filter((opt) => opt.prop !== 'operations')
|
||||
}
|
||||
return this.tableConfigs
|
||||
},
|
||||
@ -182,7 +196,7 @@ export default {
|
||||
this.$nextTick(() => {
|
||||
this.$http.get(this.$http.adornUrl(`${this.url}/${id}`)).then(({ data: res }) => {
|
||||
if (res && res.code === 0 && res.data) {
|
||||
const neededFields = [...this.attrFormFields.map(item => item.prop), 'id']
|
||||
const neededFields = [...this.attrFormFields.map((item) => item.prop), 'id']
|
||||
const filtered = pick(res.data, neededFields)
|
||||
for (let field of neededFields) {
|
||||
this.AttrForm[field] = filtered[field]
|
||||
@ -231,7 +245,7 @@ export default {
|
||||
},
|
||||
|
||||
handleSaveAttrForm() {
|
||||
this.$refs['AttrForm'].validate(valid => {
|
||||
this.$refs['AttrForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.$http({
|
||||
// url: this.$http.adornUrl(`${this.url}/${!this.AttrForm.id ? '' : this.AttrForm.id}`),
|
||||
@ -271,6 +285,9 @@ export default {
|
||||
currentChangeHandle(val) {
|
||||
this.pageIndex = val
|
||||
this.getDataList()
|
||||
},
|
||||
clickTopBtn() {
|
||||
this.showAddAttr = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ const title = {
|
||||
// 或者也可以改造成自定义颜色:
|
||||
const btnType = {
|
||||
add: '#0b58ff',
|
||||
save: '#000',
|
||||
save: '#0b58ff',
|
||||
update: '#0b58ff',
|
||||
reset: ''
|
||||
// cancel: 'text'
|
||||
|
@ -1,23 +1,18 @@
|
||||
<template>
|
||||
<div class="choicepart-container">
|
||||
<!-- <div class="choicepat-navbar">
|
||||
<div class="choicepart-container">
|
||||
<!-- <div class="choicepat-navbar">
|
||||
<navbar :showhome="false" :show-title="true" />
|
||||
</div> -->
|
||||
<div class="choicepart-box">
|
||||
<div
|
||||
v-for="(item, index) in routeList"
|
||||
:key="item.path"
|
||||
class="choicepart-item"
|
||||
@click="handelClick(item, index)"
|
||||
>
|
||||
<!-- :style="{ background: colorArr.colorList[index % 9] }" -->
|
||||
<div class="choicepart-item-border">
|
||||
<img :src="require(`../../assets/img/choicepart/${item.name}.png`)" alt="">
|
||||
</div>
|
||||
<div class="choicepart-item-title" :title="item.name">{{ item.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="choicepart-box">
|
||||
<div v-for="(item, index) in routeList" :key="item.path" class="choicepart-item" @click="handelClick(item, index)">
|
||||
<!-- :style="{ background: colorArr.colorList[index % 9] }" -->
|
||||
<div class="choicepart-item-border">
|
||||
<img :src="require(`../../assets/img/choicepart/${item.name}.png`)" alt="" />
|
||||
</div>
|
||||
<div class="choicepart-item-title" :title="item.name">{{ item.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -32,212 +27,218 @@ const colorList = ['#8080ff', '#ff8080', '#b004fb', '#ff409f', '#00caca', '#8080
|
||||
const colorList1 = ['#b4b4ff', '#ffb4b4', '#c648fb', '#ff86c2', '#66f6f6', '#a2a2f3', '#ffff9a', '#ffc3a5', '#367cd4']
|
||||
|
||||
export default {
|
||||
name: 'ChoicePart',
|
||||
// components: { Navbar },
|
||||
data() {
|
||||
return {
|
||||
baseImg: require('../../assets/img/login-back.jpg'),
|
||||
coverImgUrl: localStorage.getItem('backImg') || '',
|
||||
rowNum: 1,
|
||||
colorArr: {
|
||||
colorList,
|
||||
colorList1
|
||||
},
|
||||
windowWidth: 0,
|
||||
dbConnect: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
routeList() {
|
||||
// const cangoList = []
|
||||
// const permission_routes = store.getters.permission_routes
|
||||
// console.log(permission_routes)
|
||||
// permission_routes.map(item => {
|
||||
// if (!item.hidden && item.meta) {
|
||||
// cangoList.push(item)
|
||||
// }
|
||||
// })
|
||||
// const formatList = cangoList.map((item, index) => {
|
||||
// return this.setIndex(item, index)
|
||||
// })
|
||||
// console.log(formatList)
|
||||
return window.SITE_CONFIG['menuList']
|
||||
},
|
||||
// ...mapGetters(['language', 'dictList', 'dictObj'])
|
||||
},
|
||||
created() {
|
||||
// 确保小图标点回来依然带字符
|
||||
this.$store.state.sidebarFold = false
|
||||
this.windowWidth = window.innerWidth
|
||||
console.log(this.$route)
|
||||
// this.dbConnect = db({
|
||||
// DBName: 'back_img',
|
||||
// version: '1.0',
|
||||
// params: [
|
||||
// { name: 'id', unique: true },
|
||||
// { name: 'imgUrl', unique: true }
|
||||
// ]
|
||||
// })
|
||||
// const request = this.dbConnect.openDB()
|
||||
// request.onsuccess = () => {
|
||||
// // const result = this.dbConnect.search('back_img', 'id', 1)
|
||||
// }
|
||||
},
|
||||
mounted() {
|
||||
// console.log(this.dictList, this.dictObj)
|
||||
// this.getPic()
|
||||
},
|
||||
methods: {
|
||||
// getPic() {
|
||||
// // edit here
|
||||
// downLoadBGP().then(response => {
|
||||
// if (response.data.size) {
|
||||
// blobToBase64(response.data).then(res => {
|
||||
// this.coverImgUrl = res
|
||||
// localStorage.setItem('backImg', res)
|
||||
// console.log(res)
|
||||
// // const result = this.dbConnect.search('back_img', 'id', 1)
|
||||
// // if (result.result) {
|
||||
// // this.dbConnect.update({
|
||||
// // id: 1,
|
||||
// // imgUrl: res
|
||||
// // })
|
||||
// // } else {
|
||||
// // this.dbConnect.add({
|
||||
// // id: 1,
|
||||
// // imgUrl: res
|
||||
// // })
|
||||
// // }
|
||||
// })
|
||||
// // this.coverImgUrl = response.data
|
||||
// // const temp = response.data.split('/')
|
||||
// // temp.splice(0, 2)
|
||||
// // this.coverImgUrl = 'http://zzdhg.mes.picaiba.com/' + temp.join('/')
|
||||
// }
|
||||
// })
|
||||
// },
|
||||
resize() {},
|
||||
handelClick(item, index) {
|
||||
// this.$store.dispatch('app/setChoicepart', index)
|
||||
// if (item.meta.unuse) {
|
||||
// this.$message.warning(this.$t('choisePart.module'))
|
||||
// } else {
|
||||
// this.toRouter(item)
|
||||
// }
|
||||
// console.log('item',item)
|
||||
this.toRouter(item)
|
||||
},
|
||||
toRouter(item) {
|
||||
// console.log(item.children[0].url)
|
||||
// 加个判断看是否双层children
|
||||
if ((item.children) && (item.children[0].url == "")){
|
||||
this.$router.push({name: item.children[0].children[0].url.replace(new RegExp('/','g'),'-')})
|
||||
}
|
||||
else {
|
||||
this.$router.push({name: item.children[0].url.replace(new RegExp('/','g'),'-')})
|
||||
}
|
||||
},
|
||||
setIndex(list, index) {
|
||||
list.meta.routeIndex = index
|
||||
if (list.children) {
|
||||
list.children.map(item => {
|
||||
this.setIndex(item, index)
|
||||
})
|
||||
}
|
||||
return list
|
||||
}
|
||||
}
|
||||
name: 'ChoicePart',
|
||||
// components: { Navbar },
|
||||
data() {
|
||||
return {
|
||||
baseImg: require('../../assets/img/login-back.jpg'),
|
||||
coverImgUrl: localStorage.getItem('backImg') || '',
|
||||
rowNum: 1,
|
||||
colorArr: {
|
||||
colorList,
|
||||
colorList1
|
||||
},
|
||||
windowWidth: 0,
|
||||
dbConnect: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
routeList() {
|
||||
// const cangoList = []
|
||||
// const permission_routes = store.getters.permission_routes
|
||||
// console.log(permission_routes)
|
||||
// permission_routes.map(item => {
|
||||
// if (!item.hidden && item.meta) {
|
||||
// cangoList.push(item)
|
||||
// }
|
||||
// })
|
||||
// const formatList = cangoList.map((item, index) => {
|
||||
// return this.setIndex(item, index)
|
||||
// })
|
||||
// console.log(formatList)
|
||||
return window.SITE_CONFIG['menuList']
|
||||
}
|
||||
// ...mapGetters(['language', 'dictList', 'dictObj'])
|
||||
},
|
||||
created() {
|
||||
// 确保小图标点回来依然带字符
|
||||
this.$store.state.sidebarFold = false
|
||||
this.windowWidth = window.innerWidth
|
||||
console.log(this.$route)
|
||||
// this.dbConnect = db({
|
||||
// DBName: 'back_img',
|
||||
// version: '1.0',
|
||||
// params: [
|
||||
// { name: 'id', unique: true },
|
||||
// { name: 'imgUrl', unique: true }
|
||||
// ]
|
||||
// })
|
||||
// const request = this.dbConnect.openDB()
|
||||
// request.onsuccess = () => {
|
||||
// // const result = this.dbConnect.search('back_img', 'id', 1)
|
||||
// }
|
||||
},
|
||||
mounted() {
|
||||
// console.log(this.dictList, this.dictObj)
|
||||
// this.getPic()
|
||||
},
|
||||
methods: {
|
||||
// getPic() {
|
||||
// // edit here
|
||||
// downLoadBGP().then(response => {
|
||||
// if (response.data.size) {
|
||||
// blobToBase64(response.data).then(res => {
|
||||
// this.coverImgUrl = res
|
||||
// localStorage.setItem('backImg', res)
|
||||
// console.log(res)
|
||||
// // const result = this.dbConnect.search('back_img', 'id', 1)
|
||||
// // if (result.result) {
|
||||
// // this.dbConnect.update({
|
||||
// // id: 1,
|
||||
// // imgUrl: res
|
||||
// // })
|
||||
// // } else {
|
||||
// // this.dbConnect.add({
|
||||
// // id: 1,
|
||||
// // imgUrl: res
|
||||
// // })
|
||||
// // }
|
||||
// })
|
||||
// // this.coverImgUrl = response.data
|
||||
// // const temp = response.data.split('/')
|
||||
// // temp.splice(0, 2)
|
||||
// // this.coverImgUrl = 'http://zzdhg.mes.picaiba.com/' + temp.join('/')
|
||||
// }
|
||||
// })
|
||||
// },
|
||||
resize() {},
|
||||
handelClick(item, index) {
|
||||
// this.$store.dispatch('app/setChoicepart', index)
|
||||
// if (item.meta.unuse) {
|
||||
// this.$message.warning(this.$t('choisePart.module'))
|
||||
// } else {
|
||||
// this.toRouter(item)
|
||||
// }
|
||||
// console.log('item',item)
|
||||
this.toRouter(item)
|
||||
},
|
||||
toRouter(item) {
|
||||
// console.log(item.children[0].url)
|
||||
// 加个判断看是否双层children
|
||||
if (item.children && item.children[0].url == '') {
|
||||
this.$router.push({ name: item.children[0].children[0].url.replace(new RegExp('/', 'g'), '-') })
|
||||
} else {
|
||||
this.$router.push({ name: item.children[0].url.replace(new RegExp('/', 'g'), '-') })
|
||||
}
|
||||
},
|
||||
setIndex(list, index) {
|
||||
list.meta.routeIndex = index
|
||||
if (list.children) {
|
||||
list.children.map((item) => {
|
||||
this.setIndex(item, index)
|
||||
})
|
||||
}
|
||||
return list
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.choicepart-container{
|
||||
min-width: 100%;
|
||||
min-height: 100vh;
|
||||
// background: linear-gradient(-45deg, rgb(25, 25, 200), rgb(0, 100, 200));
|
||||
background: url('../../assets/img/choicepart/choicepart-back.png') repeat;
|
||||
background-size: cover;
|
||||
overflow-x: scroll;
|
||||
.choicepart-box{
|
||||
width: 1440px;
|
||||
margin: 0 auto;
|
||||
margin: 0 auto;
|
||||
padding-top: 16vh;
|
||||
min-height: 100vh;
|
||||
.choicepart-item{
|
||||
display: inline-block;
|
||||
width: 208px;
|
||||
height: 258px;
|
||||
margin: 40px;
|
||||
background: url('../../assets/img/choicepart/choice-item-back.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
// border: 1px dashed #fff;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, .5);
|
||||
top: 0;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
img {
|
||||
width: 208px;
|
||||
height: 258px;
|
||||
}
|
||||
.choicepart-item-border{
|
||||
height: 100%;
|
||||
border-radius: 5px;
|
||||
padding: 0 5px;
|
||||
line-height: 32px;
|
||||
font-size: 28px;
|
||||
font-weight: lighter;
|
||||
color: #2C6BD8;
|
||||
overflow: hidden;
|
||||
}
|
||||
.choicepart-item-title {
|
||||
overflow:hidden;
|
||||
padding: 0 10px;
|
||||
text-overflow:ellipsis;
|
||||
white-space:nowrap;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
line-height: 48px;
|
||||
height: 48px;
|
||||
letter-spacing: 2px;
|
||||
background-color: rgba($color: #0B58FF, $alpha: 0.45);
|
||||
}
|
||||
}
|
||||
.choicepart-item:hover {
|
||||
.choicepart-item-title {
|
||||
background-color: rgba($color: #0B58FF, $alpha: 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.choicepat-navbar{
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
.choicepart-container {
|
||||
min-width: 100%;
|
||||
min-height: 100vh;
|
||||
// background: linear-gradient(-45deg, rgb(25, 25, 200), rgb(0, 100, 200));
|
||||
background: url('../../assets/img/choicepart/choicepart-back.png') repeat;
|
||||
background-size: cover;
|
||||
overflow-x: scroll;
|
||||
// flex布局
|
||||
.choicepart-box {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: center;
|
||||
width: 1440px;
|
||||
margin: 0 auto;
|
||||
margin: 0 auto;
|
||||
padding-top: 16vh;
|
||||
min-height: 100vh;
|
||||
.choicepart-item {
|
||||
display: inline-block;
|
||||
width: 208px;
|
||||
height: 258px;
|
||||
margin: 40px;
|
||||
background: url('../../assets/img/choicepart/choice-item-back.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
// border: 1px dashed #fff;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
|
||||
top: 0;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
img {
|
||||
width: 208px;
|
||||
height: 258px;
|
||||
}
|
||||
.choicepart-item-border {
|
||||
height: 100%;
|
||||
border-radius: 5px;
|
||||
padding: 0 5px;
|
||||
line-height: 32px;
|
||||
font-size: 28px;
|
||||
font-weight: lighter;
|
||||
color: #2c6bd8;
|
||||
overflow: hidden;
|
||||
}
|
||||
.choicepart-item-title {
|
||||
overflow: hidden;
|
||||
padding: 0 10px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
line-height: 48px;
|
||||
height: 48px;
|
||||
letter-spacing: 2px;
|
||||
background-color: rgba($color: #0b58ff, $alpha: 0.45);
|
||||
}
|
||||
}
|
||||
.choicepart-item:hover {
|
||||
.choicepart-item-title {
|
||||
background-color: rgba($color: #0b58ff, $alpha: 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.choicepat-navbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
::-webkit-scrollbar-track-piece { //滚动条凹槽的颜色,还可以设置边框属性
|
||||
background: rgba(255, 255, 255, .1);
|
||||
::-webkit-scrollbar-track-piece {
|
||||
//滚动条凹槽的颜色,还可以设置边框属性
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
::-webkit-scrollbar {//滚动条的宽度
|
||||
width:9px;
|
||||
height:9px;
|
||||
::-webkit-scrollbar {
|
||||
//滚动条的宽度
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {//滚动条的设置
|
||||
background-color: #dddddd;
|
||||
background-clip:padding-box;
|
||||
min-height:28px;
|
||||
border-radius: 9px;
|
||||
::-webkit-scrollbar-thumb {
|
||||
//滚动条的设置
|
||||
background-color: #dddddd;
|
||||
background-clip: padding-box;
|
||||
min-height: 28px;
|
||||
border-radius: 9px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background-color:#bbb;
|
||||
background-color: #bbb;
|
||||
}
|
||||
</style>
|
@ -21,7 +21,16 @@
|
||||
</el-form>
|
||||
|
||||
<!-- <base-table :page="pageIndex" :size="pageSize" :data="dataList" :table-head-configs="tableConfigs" :max-height="calcMaxHeight(8)" @operate-event="handleOperations" @refreshDataList="getDataList" /> -->
|
||||
<base-table :data="dataList" :table-head-configs="tableConfigs" :max-height="calcMaxHeight(8)" />
|
||||
<base-table v-if="tableConfigs.length > 3" :data="dataList" :table-head-configs="tableConfigs" :max-height="calcMaxHeight(8)" />
|
||||
<base-table v-if="tableConfigs2.length > 3" :data="dataList2" :table-head-configs="tableConfigs2" :max-height="calcMaxHeight(8)" />
|
||||
<base-table v-if="tableConfigs3.length > 3" :data="dataList3" :table-head-configs="tableConfigs3" :max-height="calcMaxHeight(8)" />
|
||||
<base-table v-if="tableConfigs4.length > 3" :data="dataList4" :table-head-configs="tableConfigs4" :max-height="calcMaxHeight(8)" />
|
||||
<base-table v-if="tableConfigs5.length > 3" :data="dataList5" :table-head-configs="tableConfigs5" :max-height="calcMaxHeight(8)" />
|
||||
<base-table v-if="tableConfigs6.length > 3" :data="dataList6" :table-head-configs="tableConfigs6" :max-height="calcMaxHeight(8)" />
|
||||
<base-table v-if="tableConfigs7.length > 3" :data="dataList7" :table-head-configs="tableConfigs7" :max-height="calcMaxHeight(8)" />
|
||||
<base-table v-if="tableConfigs8.length > 3" :data="dataList8" :table-head-configs="tableConfigs8" :max-height="calcMaxHeight(8)" />
|
||||
<base-table v-if="tableConfigs9.length > 3" :data="dataList9" :table-head-configs="tableConfigs9" :max-height="calcMaxHeight(8)" />
|
||||
<base-table v-if="tableConfigs10.length > 3" :data="dataList10" :table-head-configs="tableConfigs10" :max-height="calcMaxHeight(8)" />
|
||||
<!-- <base-table :data="dataList" :table-head-configs="tableConfigs" :max-height="calcMaxHeight(8)" /> -->
|
||||
</div>
|
||||
</template>
|
||||
@ -42,8 +51,26 @@ export default {
|
||||
equipmentName: null,
|
||||
equipmentCode: null,
|
||||
tableConfigs: [],
|
||||
tableConfigs2: [],
|
||||
tableConfigs3: [],
|
||||
tableConfigs4: [],
|
||||
tableConfigs5: [],
|
||||
tableConfigs6: [],
|
||||
tableConfigs7: [],
|
||||
tableConfigs8: [],
|
||||
tableConfigs9: [],
|
||||
tableConfigs10: [],
|
||||
dataLength: null,
|
||||
dataList: [],
|
||||
dataList2: [],
|
||||
dataList3: [],
|
||||
dataList4: [],
|
||||
dataList5: [],
|
||||
dataList6: [],
|
||||
dataList7: [],
|
||||
dataList8: [],
|
||||
dataList9: [],
|
||||
dataList10: [],
|
||||
dataListLoading: false,
|
||||
dataListSelections: []
|
||||
}
|
||||
@ -92,11 +119,135 @@ export default {
|
||||
// console.log(this.equipmentName)
|
||||
this.setTableProps(res.data[0].nameData)
|
||||
this.setTableData(res.data[0].data)
|
||||
} else {
|
||||
this.dataList = []
|
||||
}
|
||||
if (
|
||||
res &&
|
||||
res.code === 0 &&
|
||||
res.data &&
|
||||
res.data.length > 0 &&
|
||||
res.data[1].nameData &&
|
||||
res.data[1].nameData.length > 0 &&
|
||||
res.data[1].data &&
|
||||
res.data[1].data.length > 0
|
||||
) {
|
||||
// console.log(this.equipmentName)
|
||||
this.setTableProps2(res.data[1].nameData)
|
||||
this.setTableData2(res.data[1].data)
|
||||
}
|
||||
if (
|
||||
res &&
|
||||
res.code === 0 &&
|
||||
res.data &&
|
||||
res.data.length > 0 &&
|
||||
res.data[2].nameData &&
|
||||
res.data[2].nameData.length > 0 &&
|
||||
res.data[2].data &&
|
||||
res.data[2].data.length > 0
|
||||
) {
|
||||
// console.log(this.equipmentName)
|
||||
this.setTableProps3(res.data[2].nameData)
|
||||
this.setTableData3(res.data[2].data)
|
||||
}
|
||||
if (
|
||||
res &&
|
||||
res.code === 0 &&
|
||||
res.data &&
|
||||
res.data.length > 0 &&
|
||||
res.data[3].nameData &&
|
||||
res.data[3].nameData.length > 0 &&
|
||||
res.data[3].data &&
|
||||
res.data[3].data.length > 0
|
||||
) {
|
||||
// console.log(this.equipmentName)
|
||||
this.setTableProps4(res.data[3].nameData)
|
||||
this.setTableData4(res.data[3].data)
|
||||
}
|
||||
if (
|
||||
res &&
|
||||
res.code === 0 &&
|
||||
res.data &&
|
||||
res.data.length > 0 &&
|
||||
res.data[4].nameData &&
|
||||
res.data[4].nameData.length > 0 &&
|
||||
res.data[4].data &&
|
||||
res.data[4].data.length > 0
|
||||
) {
|
||||
// console.log(this.equipmentName)
|
||||
this.setTableProps5(res.data[4].nameData)
|
||||
this.setTableData5(res.data[4].data)
|
||||
}
|
||||
if (
|
||||
res &&
|
||||
res.code === 0 &&
|
||||
res.data &&
|
||||
res.data.length > 0 &&
|
||||
res.data[5].nameData &&
|
||||
res.data[5].nameData.length > 0 &&
|
||||
res.data[5].data &&
|
||||
res.data[5].data.length > 0
|
||||
) {
|
||||
// console.log(this.equipmentName)
|
||||
this.setTableProps6(res.data[5].nameData)
|
||||
this.setTableData6(res.data[5].data)
|
||||
}
|
||||
if (
|
||||
res &&
|
||||
res.code === 0 &&
|
||||
res.data &&
|
||||
res.data.length > 0 &&
|
||||
res.data[6].nameData &&
|
||||
res.data[6].nameData.length > 0 &&
|
||||
res.data[6].data &&
|
||||
res.data[6].data.length > 0
|
||||
) {
|
||||
// console.log(this.equipmentName)
|
||||
this.setTableProps7(res.data[6].nameData)
|
||||
this.setTableData7(res.data[6].data)
|
||||
}
|
||||
if (
|
||||
res &&
|
||||
res.code === 0 &&
|
||||
res.data &&
|
||||
res.data.length > 0 &&
|
||||
res.data[7].nameData &&
|
||||
res.data[7].nameData.length > 0 &&
|
||||
res.data[7].data &&
|
||||
res.data[7].data.length > 0
|
||||
) {
|
||||
// console.log(this.equipmentName)
|
||||
this.setTableProps8(res.data[7].nameData)
|
||||
this.setTableData8(res.data[7].data)
|
||||
}
|
||||
if (
|
||||
res &&
|
||||
res.code === 0 &&
|
||||
res.data &&
|
||||
res.data.length > 0 &&
|
||||
res.data[8].nameData &&
|
||||
res.data[8].nameData.length > 0 &&
|
||||
res.data[8].data &&
|
||||
res.data[8].data.length > 0
|
||||
) {
|
||||
// console.log(this.equipmentName)
|
||||
this.setTableProps9(res.data[8].nameData)
|
||||
this.setTableData9(res.data[8].data)
|
||||
}
|
||||
if (
|
||||
res &&
|
||||
res.code === 0 &&
|
||||
res.data &&
|
||||
res.data.length > 0 &&
|
||||
res.data[9].nameData &&
|
||||
res.data[9].nameData.length > 0 &&
|
||||
res.data[9].data &&
|
||||
res.data[9].data.length > 0
|
||||
) {
|
||||
// console.log(this.equipmentName)
|
||||
this.setTableProps10(res.data[9].nameData)
|
||||
this.setTableData10(res.data[9].data)
|
||||
}
|
||||
this.dataListLoading = false
|
||||
})
|
||||
}).catch(()=>{}) //---去除无效报错---
|
||||
},
|
||||
setTableProps(nameData) {
|
||||
this.tableConfigs = [
|
||||
@ -115,6 +266,176 @@ export default {
|
||||
]
|
||||
// console.log(this.tableConfigs[i]);
|
||||
},
|
||||
setTableProps2(nameData) {
|
||||
this.tableConfigs2 = [
|
||||
{
|
||||
type: 'index',
|
||||
name: i18n.t('index')
|
||||
},
|
||||
{ prop: 'time', name: this.$t('ti'), filter: timeFilter },
|
||||
{ prop: 'plcCode', name: this.$t('plcCode') },
|
||||
// { prop: 'equName', name: this.$t('equName') },
|
||||
// { prop: 'equCode', name: this.$t('equCode') },
|
||||
// ...['数值1', '数值2', '数值3'].map(name => {
|
||||
// return { prop: name, name }
|
||||
// })
|
||||
...Array.from(new Set(nameData.map((item) => item.name))).map((name) => ({ prop: name, name }))
|
||||
]
|
||||
// console.log(this.tableConfigs[i]);
|
||||
},
|
||||
setTableProps3(nameData) {
|
||||
this.tableConfigs3 = [
|
||||
{
|
||||
type: 'index',
|
||||
name: i18n.t('index')
|
||||
},
|
||||
{ prop: 'time', name: this.$t('ti'), filter: timeFilter },
|
||||
{ prop: 'plcCode', name: this.$t('plcCode') },
|
||||
// { prop: 'equName', name: this.$t('equName') },
|
||||
// { prop: 'equCode', name: this.$t('equCode') },
|
||||
// ...['数值1', '数值2', '数值3'].map(name => {
|
||||
// return { prop: name, name }
|
||||
// })
|
||||
...Array.from(new Set(nameData.map((item) => item.name))).map((name) => ({ prop: name, name }))
|
||||
]
|
||||
// console.log(this.tableConfigs[i]);
|
||||
},
|
||||
setTableProps3(nameData) {
|
||||
this.tableConfigs3 = [
|
||||
{
|
||||
type: 'index',
|
||||
name: i18n.t('index')
|
||||
},
|
||||
{ prop: 'time', name: this.$t('ti'), filter: timeFilter },
|
||||
{ prop: 'plcCode', name: this.$t('plcCode') },
|
||||
// { prop: 'equName', name: this.$t('equName') },
|
||||
// { prop: 'equCode', name: this.$t('equCode') },
|
||||
// ...['数值1', '数值2', '数值3'].map(name => {
|
||||
// return { prop: name, name }
|
||||
// })
|
||||
...Array.from(new Set(nameData.map((item) => item.name))).map((name) => ({ prop: name, name }))
|
||||
]
|
||||
// console.log(this.tableConfigs[i]);
|
||||
},
|
||||
setTableProps4(nameData) {
|
||||
this.tableConfigs4 = [
|
||||
{
|
||||
type: 'index',
|
||||
name: i18n.t('index')
|
||||
},
|
||||
{ prop: 'time', name: this.$t('ti'), filter: timeFilter },
|
||||
{ prop: 'plcCode', name: this.$t('plcCode') },
|
||||
// { prop: 'equName', name: this.$t('equName') },
|
||||
// { prop: 'equCode', name: this.$t('equCode') },
|
||||
// ...['数值1', '数值2', '数值3'].map(name => {
|
||||
// return { prop: name, name }
|
||||
// })
|
||||
...Array.from(new Set(nameData.map((item) => item.name))).map((name) => ({ prop: name, name }))
|
||||
]
|
||||
// console.log(this.tableConfigs[i]);
|
||||
},
|
||||
setTableProps5(nameData) {
|
||||
this.tableConfigs5 = [
|
||||
{
|
||||
type: 'index',
|
||||
name: i18n.t('index')
|
||||
},
|
||||
{ prop: 'time', name: this.$t('ti'), filter: timeFilter },
|
||||
{ prop: 'plcCode', name: this.$t('plcCode') },
|
||||
// { prop: 'equName', name: this.$t('equName') },
|
||||
// { prop: 'equCode', name: this.$t('equCode') },
|
||||
// ...['数值1', '数值2', '数值3'].map(name => {
|
||||
// return { prop: name, name }
|
||||
// })
|
||||
...Array.from(new Set(nameData.map((item) => item.name))).map((name) => ({ prop: name, name }))
|
||||
]
|
||||
// console.log(this.tableConfigs[i]);
|
||||
},
|
||||
setTableProps6(nameData) {
|
||||
this.tableConfigs6 = [
|
||||
{
|
||||
type: 'index',
|
||||
name: i18n.t('index')
|
||||
},
|
||||
{ prop: 'time', name: this.$t('ti'), filter: timeFilter },
|
||||
{ prop: 'plcCode', name: this.$t('plcCode') },
|
||||
// { prop: 'equName', name: this.$t('equName') },
|
||||
// { prop: 'equCode', name: this.$t('equCode') },
|
||||
// ...['数值1', '数值2', '数值3'].map(name => {
|
||||
// return { prop: name, name }
|
||||
// })
|
||||
...Array.from(new Set(nameData.map((item) => item.name))).map((name) => ({ prop: name, name }))
|
||||
]
|
||||
// console.log(this.tableConfigs[i]);
|
||||
},
|
||||
setTableProps7(nameData) {
|
||||
this.tableConfigs7 = [
|
||||
{
|
||||
type: 'index',
|
||||
name: i18n.t('index')
|
||||
},
|
||||
{ prop: 'time', name: this.$t('ti'), filter: timeFilter },
|
||||
{ prop: 'plcCode', name: this.$t('plcCode') },
|
||||
// { prop: 'equName', name: this.$t('equName') },
|
||||
// { prop: 'equCode', name: this.$t('equCode') },
|
||||
// ...['数值1', '数值2', '数值3'].map(name => {
|
||||
// return { prop: name, name }
|
||||
// })
|
||||
...Array.from(new Set(nameData.map((item) => item.name))).map((name) => ({ prop: name, name }))
|
||||
]
|
||||
// console.log(this.tableConfigs[i]);
|
||||
},
|
||||
setTableProps8(nameData) {
|
||||
this.tableConfigs8 = [
|
||||
{
|
||||
type: 'index',
|
||||
name: i18n.t('index')
|
||||
},
|
||||
{ prop: 'time', name: this.$t('ti'), filter: timeFilter },
|
||||
{ prop: 'plcCode', name: this.$t('plcCode') },
|
||||
// { prop: 'equName', name: this.$t('equName') },
|
||||
// { prop: 'equCode', name: this.$t('equCode') },
|
||||
// ...['数值1', '数值2', '数值3'].map(name => {
|
||||
// return { prop: name, name }
|
||||
// })
|
||||
...Array.from(new Set(nameData.map((item) => item.name))).map((name) => ({ prop: name, name }))
|
||||
]
|
||||
// console.log(this.tableConfigs[i]);
|
||||
},
|
||||
setTableProps9(nameData) {
|
||||
this.tableConfigs9 = [
|
||||
{
|
||||
type: 'index',
|
||||
name: i18n.t('index')
|
||||
},
|
||||
{ prop: 'time', name: this.$t('ti'), filter: timeFilter },
|
||||
{ prop: 'plcCode', name: this.$t('plcCode') },
|
||||
// { prop: 'equName', name: this.$t('equName') },
|
||||
// { prop: 'equCode', name: this.$t('equCode') },
|
||||
// ...['数值1', '数值2', '数值3'].map(name => {
|
||||
// return { prop: name, name }
|
||||
// })
|
||||
...Array.from(new Set(nameData.map((item) => item.name))).map((name) => ({ prop: name, name }))
|
||||
]
|
||||
// console.log(this.tableConfigs[i]);
|
||||
},
|
||||
setTableProps10(nameData) {
|
||||
this.tableConfigs10 = [
|
||||
{
|
||||
type: 'index',
|
||||
name: i18n.t('index')
|
||||
},
|
||||
{ prop: 'time', name: this.$t('ti'), filter: timeFilter },
|
||||
{ prop: 'plcCode', name: this.$t('plcCode') },
|
||||
// { prop: 'equName', name: this.$t('equName') },
|
||||
// { prop: 'equCode', name: this.$t('equCode') },
|
||||
// ...['数值1', '数值2', '数值3'].map(name => {
|
||||
// return { prop: name, name }
|
||||
// })
|
||||
...Array.from(new Set(nameData.map((item) => item.name))).map((name) => ({ prop: name, name }))
|
||||
]
|
||||
// console.log(this.tableConfigs[i]);
|
||||
},
|
||||
setTableData(data) {
|
||||
this.dataList = data.map((item) => {
|
||||
const rowItem = pick(item, ['time', 'plcCode', 'equName', 'equCode'])
|
||||
@ -125,6 +446,105 @@ export default {
|
||||
}
|
||||
return rowItem
|
||||
})
|
||||
},
|
||||
setTableData2(data) {
|
||||
this.dataList2 = data.map((item) => {
|
||||
const rowItem = pick(item, ['time', 'plcCode', 'equName', 'equCode'])
|
||||
if (item.data && item.data.length > 0) {
|
||||
item.data.forEach((param) => {
|
||||
rowItem[param.dynamicName] = param.dynamicValue
|
||||
})
|
||||
}
|
||||
return rowItem
|
||||
})
|
||||
},
|
||||
setTableData3(data) {
|
||||
this.dataList3 = data.map((item) => {
|
||||
const rowItem = pick(item, ['time', 'plcCode', 'equName', 'equCode'])
|
||||
if (item.data && item.data.length > 0) {
|
||||
item.data.forEach((param) => {
|
||||
rowItem[param.dynamicName] = param.dynamicValue
|
||||
})
|
||||
}
|
||||
return rowItem
|
||||
})
|
||||
},
|
||||
setTableData4(data) {
|
||||
this.dataList4 = data.map((item) => {
|
||||
const rowItem = pick(item, ['time', 'plcCode', 'equName', 'equCode'])
|
||||
if (item.data && item.data.length > 0) {
|
||||
item.data.forEach((param) => {
|
||||
rowItem[param.dynamicName] = param.dynamicValue
|
||||
})
|
||||
}
|
||||
return rowItem
|
||||
})
|
||||
},
|
||||
setTableData5(data) {
|
||||
this.dataList5 = data.map((item) => {
|
||||
const rowItem = pick(item, ['time', 'plcCode', 'equName', 'equCode'])
|
||||
if (item.data && item.data.length > 0) {
|
||||
item.data.forEach((param) => {
|
||||
rowItem[param.dynamicName] = param.dynamicValue
|
||||
})
|
||||
}
|
||||
return rowItem
|
||||
})
|
||||
},
|
||||
setTableData6(data) {
|
||||
this.dataList6 = data.map((item) => {
|
||||
const rowItem = pick(item, ['time', 'plcCode', 'equName', 'equCode'])
|
||||
if (item.data && item.data.length > 0) {
|
||||
item.data.forEach((param) => {
|
||||
rowItem[param.dynamicName] = param.dynamicValue
|
||||
})
|
||||
}
|
||||
return rowItem
|
||||
})
|
||||
},
|
||||
setTableData7(data) {
|
||||
this.dataList7 = data.map((item) => {
|
||||
const rowItem = pick(item, ['time', 'plcCode', 'equName', 'equCode'])
|
||||
if (item.data && item.data.length > 0) {
|
||||
item.data.forEach((param) => {
|
||||
rowItem[param.dynamicName] = param.dynamicValue
|
||||
})
|
||||
}
|
||||
return rowItem
|
||||
})
|
||||
},
|
||||
setTableData8(data) {
|
||||
this.dataList8 = data.map((item) => {
|
||||
const rowItem = pick(item, ['time', 'plcCode', 'equName', 'equCode'])
|
||||
if (item.data && item.data.length > 0) {
|
||||
item.data.forEach((param) => {
|
||||
rowItem[param.dynamicName] = param.dynamicValue
|
||||
})
|
||||
}
|
||||
return rowItem
|
||||
})
|
||||
},
|
||||
setTableData9(data) {
|
||||
this.dataList9 = data.map((item) => {
|
||||
const rowItem = pick(item, ['time', 'plcCode', 'equName', 'equCode'])
|
||||
if (item.data && item.data.length > 0) {
|
||||
item.data.forEach((param) => {
|
||||
rowItem[param.dynamicName] = param.dynamicValue
|
||||
})
|
||||
}
|
||||
return rowItem
|
||||
})
|
||||
},
|
||||
setTableData10(data) {
|
||||
this.dataList10 = data.map((item) => {
|
||||
const rowItem = pick(item, ['time', 'plcCode', 'equName', 'equCode'])
|
||||
if (item.data && item.data.length > 0) {
|
||||
item.data.forEach((param) => {
|
||||
rowItem[param.dynamicName] = param.dynamicValue
|
||||
})
|
||||
}
|
||||
return rowItem
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,8 @@
|
||||
:title="isDetail ? $t('ws.detail') : !dataForm.id ? $t('add') : $t('edit')"
|
||||
:visible.sync="visible"
|
||||
:close-on-click-modal="false"
|
||||
:destroy-on-close="true"
|
||||
>
|
||||
<div style="max-height: 60vh; overflow-y: scroll; overflow-x: hidden;">
|
||||
:destroy-on-close="true">
|
||||
<div style="max-height: 60vh; overflow-y: scroll; overflow-x: hidden">
|
||||
<el-form ref="dataForm" :model="dataForm" :rules="dataFormRules">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12"
|
||||
@ -49,8 +48,7 @@
|
||||
:table-head-configs="tableProps"
|
||||
:max-height="calcMaxHeight(8)"
|
||||
@operate-event="handleOperations"
|
||||
@refreshDataList="getDataList"
|
||||
/>
|
||||
@refreshDataList="getDataList" />
|
||||
<el-pagination
|
||||
@size-change="sizeChangeHandle"
|
||||
@current-change="currentChangeHandle"
|
||||
@ -58,16 +56,31 @@
|
||||
:page-sizes="[5, 10, 15, 20]"
|
||||
:page-size="limit"
|
||||
:total="eqTotal"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
/>
|
||||
layout="total, sizes, prev, pager, next, jumper" />
|
||||
</div>
|
||||
<attr-form v-else ref="AttrFrom" :workshop-section-id="dataForm.id" @close-attr-form="showAttrForm = false" @refresh-list="handleRefreshList" />
|
||||
</section>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="handleClick({ name: 'cancel' })">{{ $t('cancel') }}</el-button>
|
||||
<el-button type="primary" v-if="dataForm.id" @click="handleClick({ name: 'update' })">{{ $t('update') }}</el-button>
|
||||
<el-button type="success" v-else @click="handleClick({ name: 'save' })">{{ $t('save') }}</el-button>
|
||||
<el-button
|
||||
:style="{
|
||||
backgroundColor: '#0b58ff',
|
||||
color: '#fff'
|
||||
}"
|
||||
v-if="dataForm.id"
|
||||
@click="handleClick({ name: 'update' })"
|
||||
>{{ $t('update') }}</el-button
|
||||
>
|
||||
<el-button
|
||||
:style="{
|
||||
backgroundColor: '#0b58ff',
|
||||
color: '#fff'
|
||||
}"
|
||||
v-else
|
||||
@click="handleClick({ name: 'save' })"
|
||||
>{{ $t('save') }}</el-button
|
||||
>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@ -292,7 +305,7 @@ export default {
|
||||
}
|
||||
},
|
||||
handleCreateOrUpdate() {
|
||||
this.$refs['dataForm'].validate(valid => {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.$http({
|
||||
url: this.$http.adornUrl('/monitoring/workshopSection'),
|
||||
|
Loading…
Reference in New Issue
Block a user