安虹睿
1 year ago
13 changed files with 692 additions and 51 deletions
@ -1,19 +1,637 @@ |
|||||
<template> |
<template> |
||||
<div>AbpIdentityMarkUsers</div> |
<div class="appMainPage" v-loading="loading"> |
||||
|
<div class="main"> |
||||
|
<div class="table-active"> |
||||
|
<div class="bttton-box"> |
||||
|
<el-button |
||||
|
type="primary" |
||||
|
icon="el-icon-plus" |
||||
|
@click="handleCreate" |
||||
|
size="mini" |
||||
|
v-permission="['AbpIdentity.Users.Create']" |
||||
|
>创建用户</el-button |
||||
|
> |
||||
|
<el-button |
||||
|
type="success" |
||||
|
icon="el-icon-refresh" |
||||
|
@click.native.prevent="Createview" |
||||
|
size="mini" |
||||
|
>刷新</el-button |
||||
|
> |
||||
|
</div> |
||||
|
<div class="query-box"> |
||||
|
<!-- 搜索 --> |
||||
|
<searchNormal |
||||
|
ref="normalSearch_UserManage" |
||||
|
@searchNormalClick="filtrate" |
||||
|
@searchNormalClear="filtrate" |
||||
|
></searchNormal> |
||||
|
</div> |
||||
|
</div> |
||||
|
<el-table |
||||
|
ref="multipleTable" |
||||
|
:data="tableData" |
||||
|
height="calc(100vh - 260px)" |
||||
|
style="width: 100%" |
||||
|
@sort-change="sortChange" |
||||
|
@selection-change="handleSelectionChange" |
||||
|
@row-click="handleRowClick" |
||||
|
:border="true" |
||||
|
> |
||||
|
<el-table-column :align="'center'" type="selection" width="55" /> |
||||
|
<el-table-column |
||||
|
prop="userName" |
||||
|
label="用户名" |
||||
|
width="180" |
||||
|
:align="'left'" |
||||
|
sortable="custom" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
prop="name" |
||||
|
label="姓名" |
||||
|
width="180" |
||||
|
:align="'left'" |
||||
|
sortable="custom" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
prop="isActive" |
||||
|
label="是否启用" |
||||
|
sortable="custom" |
||||
|
:align="'center'" |
||||
|
width="180" |
||||
|
> |
||||
|
<template slot-scope="scope"> |
||||
|
<span>{{ scope.row['isActive'] | trigger('whetherOrNot', "label") }}</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column label="操作" :align="'center'" width="230"> |
||||
|
<template slot-scope="scope"> |
||||
|
<el-button |
||||
|
type="text" |
||||
|
@click="Update(scope.row)" |
||||
|
v-permission="['AbpIdentity.Users.Update']" |
||||
|
v-if="scope.row.name == 'admin' ? false : true" |
||||
|
>编辑</el-button> |
||||
|
<el-button |
||||
|
type="text" |
||||
|
@click="deleteUser(scope.row)" |
||||
|
v-if="scope.row.name == 'admin' ? false : true" |
||||
|
v-permission="['AbpIdentity.Users.Delete']" |
||||
|
style="color:red" |
||||
|
>删除用户</el-button> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
</div> |
||||
|
<div class="Footer"> |
||||
|
<el-pagination |
||||
|
background |
||||
|
@size-change="handleSizeChange" |
||||
|
@current-change="handleCurrentChange" |
||||
|
:current-page="queryInfo.currentPage" |
||||
|
:page-sizes="[10, 15, 20]" |
||||
|
:page-size="queryInfo.pagesize" |
||||
|
layout="total, sizes, prev, pager, next, jumper" |
||||
|
:total="total" |
||||
|
> |
||||
|
</el-pagination> |
||||
|
<el-button |
||||
|
type="primary" |
||||
|
size="mini" |
||||
|
style="margin-left: 10px; background-color: #409eff" |
||||
|
>确定</el-button |
||||
|
> |
||||
|
</div> |
||||
|
<el-dialog |
||||
|
:title="formTitle" |
||||
|
:visible.sync="dialogVisible" |
||||
|
width="800px" |
||||
|
:close-on-click-modal="false" |
||||
|
:modal-append-to-body="false" |
||||
|
:append-to-body="false" |
||||
|
> |
||||
|
<el-form |
||||
|
ref="form" |
||||
|
:model="form" |
||||
|
label-width="70px" |
||||
|
:rules="rules" |
||||
|
> |
||||
|
<el-form-item label="用户名" prop="userName"> |
||||
|
<el-input |
||||
|
v-model="form.userName" |
||||
|
maxlength="20" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="姓名" prop="name"> |
||||
|
<el-input v-model="form.name" maxlength="20" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="角色" prop="roleNames"> |
||||
|
<el-select |
||||
|
:disabled="!checkPermission(['AbpIdentity.Users.ManagePermissions']) && isEdit" |
||||
|
v-model="form.roleNames" |
||||
|
multiple |
||||
|
style="width: 100%" |
||||
|
placeholder="请选择" |
||||
|
> |
||||
|
<el-option |
||||
|
v-for="item in options" |
||||
|
:key="item.id" |
||||
|
:label="item.name" |
||||
|
:value="item.name" |
||||
|
></el-option> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="是否启用" prop="IsActive"> |
||||
|
<el-select |
||||
|
v-model="form.IsActive" |
||||
|
style="width: 100%" |
||||
|
placeholder="请选择" |
||||
|
> |
||||
|
<el-option |
||||
|
v-for="item in userOptions('whetherOrNot')" |
||||
|
:key="item.value" |
||||
|
:label="item.label" |
||||
|
:value="item.value" |
||||
|
></el-option> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="密码" prop="password" v-if="!isEdit"> |
||||
|
<el-input |
||||
|
ref="password" |
||||
|
v-model="form.password" |
||||
|
maxlength="16" |
||||
|
minlength="6" |
||||
|
:type="passwordType" |
||||
|
/> |
||||
|
<span class="show-pwd" @click="showPwd"> |
||||
|
<svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" /> |
||||
|
</span> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<div slot="footer" class="dialog-footer"> |
||||
|
<el-button @click="resetform">取 消</el-button> |
||||
|
<el-button type="primary" @click="submitForm">确 定</el-button> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
</template> |
</template> |
||||
<script> |
<script> |
||||
|
import { isvalidPhone } from "@/utils/validate"; |
||||
|
import checkPermission from '@/utils/permission' |
||||
|
import { |
||||
|
getPageListUsers, |
||||
|
usersroles, |
||||
|
postCreateUser, |
||||
|
postUpdateUser, |
||||
|
postDeleteUser, |
||||
|
getusersID, |
||||
|
} from "@/api/wms-auth"; |
||||
|
import permission from "@/utils/permission/index"; |
||||
|
import searchNormal from "@/components/searchNormal/index.vue" |
||||
export default { |
export default { |
||||
|
directives: { permission }, |
||||
|
components:{ |
||||
|
searchNormal |
||||
|
}, |
||||
name:"AbpIdentityMarkUsers", |
name:"AbpIdentityMarkUsers", |
||||
data() { |
data() { |
||||
// 自定义验证 |
// 自定义验证 |
||||
|
const validPhone = (rule, value, callback) => { |
||||
|
if (!value) { |
||||
|
callback(new Error("请输入电话号码")); |
||||
|
} else if (!isvalidPhone(value)) { |
||||
|
callback(new Error("请输入正确的11位手机号码")); |
||||
|
} else { |
||||
|
callback(); |
||||
|
} |
||||
|
}; |
||||
|
const validName = (rule, value, callback) => { |
||||
|
if (!value) { |
||||
|
callback(new Error("请输入登录名称")); |
||||
|
} else if (/[\u4E00-\u9FA5]/g.test(value)) { |
||||
|
callback(new Error("登录名不能输入汉字")); |
||||
|
} else { |
||||
|
callback(); |
||||
|
} |
||||
|
}; |
||||
|
// 简单 |
||||
|
// const validpassword = (rule, value, callback) => { |
||||
|
// if (!value) { |
||||
|
// callback(new Error("请输入密码")); |
||||
|
// } else { |
||||
|
// if ( |
||||
|
// /^(?=.*\d)(?=.*[a-z]).{6,16}$/.test( |
||||
|
// value |
||||
|
// ) |
||||
|
// ) { |
||||
|
// callback(); |
||||
|
// } else { |
||||
|
// callback(new Error("密码必须包含字母,数字混合,最小长度为6位")); |
||||
|
// } |
||||
|
// } |
||||
|
// }; |
||||
|
// 中等 |
||||
|
// const validpassword = (rule, value, callback) => { |
||||
|
// if (!value) { |
||||
|
// callback(new Error("请输入密码")); |
||||
|
// } else { |
||||
|
// if ( |
||||
|
// /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,16}$/.test( |
||||
|
// value |
||||
|
// ) |
||||
|
// ) { |
||||
|
// callback(); |
||||
|
// } else { |
||||
|
// callback(new Error("密码必须包含大小写,数字混合,最小长度为6位")); |
||||
|
// } |
||||
|
// } |
||||
|
// }; |
||||
|
// 复杂 |
||||
|
const validpassword = (rule, value, callback) => { |
||||
|
if (!value) { |
||||
|
callback(new Error("请输入密码")); |
||||
|
} else { |
||||
|
if ( |
||||
|
/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[~@#$%\*-\+=:,\\?\[\]\{}]).{6,16}$/.test( |
||||
|
value |
||||
|
) |
||||
|
) { |
||||
|
callback(); |
||||
|
} else { |
||||
|
callback(new Error("密码必须包含大小写,数字与特殊字符混合,最小长度为6位")); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
const checkEmail = (rule, value, callback) => { |
||||
|
const mailReg = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/; |
||||
|
if (!value) { |
||||
|
return callback(new Error("邮箱不能为空")); |
||||
|
} |
||||
|
setTimeout(() => { |
||||
|
if (mailReg.test(value)) { |
||||
|
callback(); |
||||
|
} else { |
||||
|
callback(new Error("请输入正确的邮箱格式")); |
||||
|
} |
||||
|
}, 100); |
||||
|
}; |
||||
return { |
return { |
||||
|
loading:false, |
||||
|
//编辑弹出 |
||||
|
dialogVisible: false, |
||||
|
//密码显示 |
||||
|
isEdit: false, |
||||
|
//弹出title |
||||
|
formTitle: "", |
||||
|
//总条数 |
||||
|
total: 0, |
||||
|
//分页器 |
||||
|
queryInfo: { |
||||
|
//当前页数 |
||||
|
currentPage: 1, |
||||
|
//每页条数 |
||||
|
pagesize: 20, |
||||
|
Sorting: "", |
||||
|
}, |
||||
|
//角色组 |
||||
|
options: [], |
||||
|
//当前用户ID |
||||
|
usersId: "", |
||||
|
//编辑参数 |
||||
|
concurrencyStamp: "", |
||||
|
//新增参数 |
||||
|
form: { |
||||
|
userName: "", |
||||
|
phoneNumber: "", |
||||
|
name: "", |
||||
|
email: "", |
||||
|
roleNames: [], |
||||
|
password: "", |
||||
|
surname: "", |
||||
|
lockoutEnabled: true, |
||||
|
IsActive: true, |
||||
|
}, |
||||
|
//密码明文 |
||||
|
passwordType: "password", |
||||
|
// |
||||
|
multipleSelection: [], |
||||
|
//table渲染 |
||||
|
tableData: [], |
||||
|
rules: { |
||||
|
userName: [ |
||||
|
{ required: true, trigger: "blur", validator: validName }, |
||||
|
{ |
||||
|
min: 2, |
||||
|
max: 20, |
||||
|
message: "长度在 2 到 20 个字符", |
||||
|
trigger: "blur", |
||||
|
}, |
||||
|
], |
||||
|
name: [ |
||||
|
{ required: true, trigger: "blur", message: "请输入姓名" }, |
||||
|
{ |
||||
|
min: 2, |
||||
|
max: 20, |
||||
|
message: "长度在 2 到 20 个字符", |
||||
|
trigger: "blur", |
||||
|
}, |
||||
|
], |
||||
|
email: [{ required: true, validator: checkEmail, trigger: "blur" }], |
||||
|
phoneNumber: [ |
||||
|
{ required: true, trigger: "blur", validator: validPhone }, |
||||
|
], |
||||
|
password: [ |
||||
|
{ required: true, trigger: "blur", message: "请输入密码" }, |
||||
|
{ |
||||
|
min: 6, |
||||
|
max: 16, |
||||
|
message: "长度在 6 到 16 个字符", |
||||
|
trigger: "blur", |
||||
|
}, |
||||
|
], |
||||
|
roleNames: [ |
||||
|
{ required: true, message: "请选择角色", trigger: "change" }, |
||||
|
], |
||||
|
}, |
||||
}; |
}; |
||||
}, |
}, |
||||
|
created() { |
||||
|
//获取所有角色 |
||||
|
usersroles().then((res) => { |
||||
|
this.options = res.items; |
||||
|
}); |
||||
|
}, |
||||
mounted() { |
mounted() { |
||||
|
this.pageList(); |
||||
}, |
}, |
||||
methods: { |
methods: { |
||||
|
checkPermission, |
||||
|
// 是否下拉 |
||||
|
userOptions(val){ |
||||
|
let options = this.$staticOptions[val] |
||||
|
return options() |
||||
|
}, |
||||
|
//请求数据渲染table |
||||
|
pageList(val) { |
||||
|
this.loading = true |
||||
|
const data = { |
||||
|
Filter: val || '', |
||||
|
Sorting: this.queryInfo.Sorting, |
||||
|
SkipCount: (this.queryInfo.currentPage - 1) * this.queryInfo.pagesize, |
||||
|
MaxResultCount: this.queryInfo.pagesize, |
||||
|
}; |
||||
|
getPageListUsers(data).then((res) => { |
||||
|
this.loading = false |
||||
|
const data = res; |
||||
|
this.total = data.totalCount; |
||||
|
this.tableData = data.items; |
||||
|
}).catch(()=>{ |
||||
|
this.loading = false |
||||
|
}); |
||||
|
}, |
||||
|
//密码明文显示 |
||||
|
showPwd() { |
||||
|
if (this.passwordType === "password") { |
||||
|
this.passwordType = ""; |
||||
|
} else { |
||||
|
this.passwordType = "password"; |
||||
|
} |
||||
|
this.$nextTick(() => { |
||||
|
this.$refs.password.focus(); |
||||
|
}); |
||||
|
}, |
||||
|
//排序 |
||||
|
sortChange(data) { |
||||
|
const { prop, order } = data; |
||||
|
if (!prop || !order) { |
||||
|
this.queryInfo.Sorting = ""; |
||||
|
this.handleFilter(); |
||||
|
return; |
||||
|
} |
||||
|
this.queryInfo.Sorting = prop + " " + order; |
||||
|
this.handleFilter(); |
||||
|
}, |
||||
|
//排序触发页面更新 |
||||
|
handleFilter() { |
||||
|
this.queryInfo.currentPage = 1; |
||||
|
this.pageList(); |
||||
|
}, |
||||
|
//筛选 |
||||
|
filtrate(val) { |
||||
|
this.queryInfo.currentPage = 1; |
||||
|
this.pageList(val); |
||||
|
}, |
||||
|
//选择每页条数分页 |
||||
|
handleSizeChange(val) { |
||||
|
this.queryInfo.pagesize = val; |
||||
|
this.pageList(); |
||||
|
}, |
||||
|
//选择当前页分页 |
||||
|
handleCurrentChange(val) { |
||||
|
this.queryInfo.currentPage = val; |
||||
|
this.pageList(); |
||||
|
}, |
||||
|
//重置新建与编辑后的参数 |
||||
|
resetform() { |
||||
|
this.$refs.form.resetFields(); |
||||
|
this.dialogVisible = false; |
||||
|
this.form.userName = ""; |
||||
|
this.form.phoneNumber = ""; |
||||
|
this.form.name = ""; |
||||
|
this.form.email = ""; |
||||
|
this.form.roleNames = []; |
||||
|
this.form.password = ""; |
||||
|
this.form.surname = ""; |
||||
|
this.form.IsActive = ""; |
||||
|
this.$refs.multipleTable.clearSelection(); |
||||
|
}, |
||||
|
handleCreate() { |
||||
|
this.formTitle = "创建用户"; |
||||
|
this.dialogVisible = true; |
||||
|
this.isEdit = false; |
||||
|
this.form.phoneNumber = this.getRandomPhoneNumber() |
||||
|
this.form.email = this.getRandomEmail() |
||||
|
usersroles().then((res) => { |
||||
|
this.options = res.items |
||||
|
}) |
||||
|
|
||||
|
}, |
||||
|
//刷新 |
||||
|
Createview() { |
||||
|
this.queryInfo.currentPage = 1; |
||||
|
this.queryInfo.Sorting = ""; |
||||
|
this.$refs.normalSearch_UserManage.searchNormalClear()//清空搜索 |
||||
|
usersroles().then((res) => { |
||||
|
this.options = res.items; |
||||
|
}); |
||||
|
this.$refs.multipleTable.clearSort(); |
||||
|
}, |
||||
|
//获取当前角色 |
||||
|
usersID(data) { |
||||
|
getusersID(data).then((res) => { |
||||
|
const data = res.items; |
||||
|
this.form.roleNames = data.map((item) => { |
||||
|
return item.name; |
||||
|
}); |
||||
|
}); |
||||
|
}, |
||||
|
//编辑默认参数 |
||||
|
Update(row) { |
||||
|
if (row) { |
||||
|
this.formTitle = "编辑用户"; |
||||
|
this.usersId = row.id; |
||||
|
this.usersID(row.id); |
||||
|
this.form.userName = row.userName; |
||||
|
this.form.phoneNumber = row.phoneNumber; |
||||
|
this.form.name = row.name; |
||||
|
this.form.email = row.email; |
||||
|
this.form.surname = row.name; |
||||
|
this.form.lockoutEnabled = row.lockoutEnabled |
||||
|
this.concurrencyStamp = row.concurrencyStamp; |
||||
|
this.form.IsActive = row.isActive; |
||||
|
usersroles().then((res) => { |
||||
|
this.options = res.items; |
||||
|
}); |
||||
|
this.isEdit = true; |
||||
|
this.dialogVisible = true; |
||||
|
} |
||||
|
}, |
||||
|
//新建与编辑 |
||||
|
submitForm() { |
||||
|
this.$refs.form.validate((valid) => { |
||||
|
//新建报表组 |
||||
|
if (valid && !this.isEdit) { |
||||
|
this.form.surname = this.form.name; |
||||
|
postCreateUser(this.form) |
||||
|
.then((res) => { |
||||
|
this.resetform(); |
||||
|
this.$successMsg("创建成功!"); |
||||
|
this.pageList(); |
||||
|
}) |
||||
|
.catch((err) => { |
||||
|
this.resetform(); |
||||
|
}); |
||||
|
} else if (valid && this.isEdit) { |
||||
|
//编辑报表 |
||||
|
const data = JSON.parse(JSON.stringify(this.form)); |
||||
|
delete data.password; |
||||
|
data.concurrencyStamp = this.concurrencyStamp; |
||||
|
postUpdateUser(data, this.usersId) |
||||
|
.then((res) => { |
||||
|
this.$successMsg("编辑成功!"); |
||||
|
this.pageList(); |
||||
|
this.resetform(); |
||||
|
}) |
||||
|
.catch((err) => { |
||||
|
this.resetform(); |
||||
|
}); |
||||
|
} else { |
||||
|
this.$errorMsg("请按照提示继续输入!"); |
||||
|
return false; |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
// 删除用户 |
||||
|
deleteUser(row){ |
||||
|
this.$confirm("您确认删除 " + row.userName + " 用户吗?", "提示", { |
||||
|
confirmButtonText: "确认删除用户", |
||||
|
cancelButtonText: "取消", |
||||
|
type: "warning", |
||||
|
}) |
||||
|
.then(() => { |
||||
|
this.loading = true |
||||
|
postDeleteUser(row.id) |
||||
|
.then((res) => { |
||||
|
this.loading = false |
||||
|
this.$successMsg("删除成功!"); |
||||
|
this.pageList(); |
||||
|
}) |
||||
|
.catch((err) => { |
||||
|
this.loading = false |
||||
|
}) |
||||
|
}) |
||||
|
.catch((err) => { |
||||
|
console.log(err) |
||||
|
}) |
||||
|
}, |
||||
|
handleSelectionChange(val) { |
||||
|
this.multipleSelection = val; |
||||
|
}, |
||||
|
//点击table行选择 |
||||
|
handleRowClick(row, column, event) { |
||||
|
if ( |
||||
|
this.multipleSelection.length == 1 && |
||||
|
this.multipleSelection[0].id == row.id |
||||
|
) { |
||||
|
this.$refs.multipleTable.clearSelection(); |
||||
|
return; |
||||
|
} |
||||
|
this.$refs.multipleTable.clearSelection(); |
||||
|
this.$refs.multipleTable.toggleRowSelection(row); |
||||
|
}, |
||||
|
// 创建用户,随机生成11位电话号,去掉电话校验 |
||||
|
getRandomPhoneNumber () { |
||||
|
return '1' + Math.floor(Math.random()*9+1) + Math.floor(Math.random()*9+1) + Math.floor(Math.random()*9+1) + Math.floor(Math.random()*9+1) + Math.floor(Math.random()*9+1) + Math.floor(Math.random()*9+1) + Math.floor(Math.random()*9+1) + Math.floor(Math.random()*9+1) + Math.floor(Math.random()*9+1) + Math.floor(Math.random()*9+1) |
||||
|
}, |
||||
|
getRandomEmail () { |
||||
|
return '' + Math.floor(Math.random()*9+1) + Math.floor(Math.random()*9+1) + Math.floor(Math.random()*9+1) + Math.floor(Math.random()*9+1) + '@' + Math.floor(Math.random()*9+1) + Math.floor(Math.random()*9+1) + Math.floor(Math.random()*9+1) + '.com' |
||||
|
}, |
||||
}, |
}, |
||||
}; |
}; |
||||
</script> |
</script> |
||||
|
<style lang="scss" scoped> |
||||
|
.appMainPage { |
||||
|
.main { |
||||
|
.table-active { |
||||
|
display: flex; |
||||
|
flex-wrap: wrap; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
padding: 20px 0; |
||||
|
|
||||
|
.bttton-box { |
||||
|
display: flex; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.el-table__body-wrapper { |
||||
|
tbody { |
||||
|
span { |
||||
|
cursor: pointer; |
||||
|
|
||||
|
&:hover { |
||||
|
color: #409eff; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.Footer { |
||||
|
padding: 25px; |
||||
|
// background-color: #f2f2f2; |
||||
|
display: flex; |
||||
|
justify-content: flex-end; |
||||
|
|
||||
|
::v-deep button { |
||||
|
background-color: #fff; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
::v-deep .el-dialog { |
||||
|
.el-dialog__header { |
||||
|
button { |
||||
|
display: none; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
.el-form-item{ |
||||
|
margin-bottom: 30px; |
||||
|
} |
||||
|
.show-pwd { |
||||
|
position: absolute; |
||||
|
right: 10px; |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
|
|
||||
|
Loading…
Reference in new issue