refactor(user/index.vue): 用户界面优化

This commit is contained in:
郝先瑞
2022-01-15 23:55:14 +08:00
parent 7f5dd0f259
commit e2f24f5429
13 changed files with 362 additions and 491 deletions

View File

@@ -101,7 +101,7 @@ import '@/permission'
import Pagination from '@/components/Pagination/index.vue' import Pagination from '@/components/Pagination/index.vue'
import {getDictItemsByCode} from '@/api/system/dict' import {listDictsByCode} from '@/api/system/dict'
const app = createApp(App) const app = createApp(App)
@@ -113,7 +113,7 @@ for (let iconName in ElIconModules) {
} }
// 全局方法 // 全局方法
app.config.globalProperties.$getDictItemsByCode = getDictItemsByCode app.config.globalProperties.$listDictsByCode = listDictsByCode
app.component('Pagination', Pagination) // 全局组件 app.component('Pagination', Pagination) // 全局组件
.use(store) .use(store)
.use(router) .use(router)

View File

@@ -41,7 +41,7 @@ export const updateDept = (id:number,data: any) => {
} }
export const getDeptSelectList = ()=> { export const listDeptsForSelect = ()=> {
return request({ return request({
url: '/youlai-admin/api/v1/depts/select', url: '/youlai-admin/api/v1/depts/select',
method: 'get' method: 'get'

View File

@@ -83,7 +83,7 @@ export function listDictItemsWithPage(queryParams: object) {
* *
* @param dictCode * @param dictCode
*/ */
export function getDictItemsByCode(dictCode: string) { export function listDictsByCode(dictCode: string) {
return request({ return request({
url: '/youlai-admin/api/v2/dict/items', url: '/youlai-admin/api/v2/dict/items',
method: 'get', method: 'get',

View File

@@ -18,7 +18,7 @@ export function listRolesWithPage(queryParams: object) {
* *
* @param queryParams * @param queryParams
*/ */
export function listRoles(queryParams: object) { export function listRoles(queryParams?: object) {
return request({ return request({
url: '/youlai-admin/api/v1/roles', url: '/youlai-admin/api/v1/roles',
method: 'get', method: 'get',

View File

@@ -1,21 +1,36 @@
import request from "@/utils/request"; import request from "@/utils/request";
export const listUser = (queryParams:any)=> {
/**
* 获取用户分页列表
*
* @param queryParams
*/
export function listUsersWithPage(queryParams: any) {
return request({ return request({
url: '/youlai-admin/api/v2/users', url: '/youlai-admin/api/v1/users/page',
method: 'get', method: 'get',
params: queryParams params: queryParams
}) })
} }
export const getUser = (id ?:any) =>{ /**
* 获取用户表单详情
*
* @param userId
*/
export function getUserFormDetail(userId: any) {
return request({ return request({
url: '/youlai-admin/api/v1/users/' + id, url: '/youlai-admin/api/v1/users/' + userId + '/form',
method: 'get' method: 'get'
}) })
} }
export const addUser = (data:any) => { /**
* 添加用户
*
* @param data
*/
export function addUser(data: any) {
return request({ return request({
url: '/youlai-admin/api/v1/users', url: '/youlai-admin/api/v1/users',
method: 'post', method: 'post',
@@ -23,7 +38,13 @@ export const addUser = (data:any) => {
}) })
} }
export const updateUser = (id:number, data:any)=> { /**
* 修改用户
*
* @param id
* @param data
*/
export function updateUser(id: number, data: any) {
return request({ return request({
url: '/youlai-admin/api/v1/users/' + id, url: '/youlai-admin/api/v1/users/' + id,
method: 'put', method: 'put',
@@ -31,7 +52,13 @@ export const updateUser = (id:number, data:any)=> {
}) })
} }
export const patch = (id:number, data:any) => { /**
* 选择性修改用户
*
* @param id
* @param data
*/
export function updateUserPart(id: number, data: any) {
return request({ return request({
url: '/youlai-admin/api/v1/users/' + id, url: '/youlai-admin/api/v1/users/' + id,
method: 'patch', method: 'patch',
@@ -39,9 +66,14 @@ export const patch = (id:number, data:any) => {
}) })
} }
export const delUser =(ids:number) =>{
/**
* 删除用户
* @param ids
*/
export function deleteUsers(ids: number) {
return request({ return request({
url: '/youlai-admin/api/v1/users/'+ids, url: '/youlai-admin/api/v1/users/' + ids,
method: 'delete', method: 'delete',
}) })
} }

View File

@@ -2,7 +2,7 @@
<div class="el-tree-select"> <div class="el-tree-select">
<el-select <el-select
style="width: 100%" style="width: 100%"
v-model="valueId" v-model="modelValue"
ref="treeSelect" ref="treeSelect"
:filterable="true" :filterable="true"
:clearable="true" :clearable="true"
@@ -10,7 +10,7 @@
:filter-method="selectFilterData" :filter-method="selectFilterData"
:placeholder="placeholder" :placeholder="placeholder"
> >
<el-option :value="valueId" :label="valueTitle"> <el-option :value="modelValue" :label="valueTitle">
<el-tree <el-tree
id="tree-option" id="tree-option"
ref="selectTree" ref="selectTree"
@@ -33,7 +33,7 @@ import {ref, getCurrentInstance ,nextTick,onMounted,computed,watch} from "vue";
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance();
const state = defineProps({ const state = defineProps({
/* 配置项 */ // 配置项
props: { props: {
type: Object, type: Object,
default: () => { default: () => {
@@ -44,24 +44,24 @@ const state = defineProps({
} }
} }
}, },
/* 自动收起 */ // 自动收起
accordion: { accordion: {
type: Boolean, type: Boolean,
default: () => { default: () => {
return false return false
} }
}, },
/**当前双向数据绑定的值 */ // v-model 绑定的值
modelValue: { modelValue: {
type: [String, Number], type: Object,
default: '' default: ''
}, },
/**当前的数据 */ // 数据源
options: { options: {
type: Array, type: Array,
default: () => [] default:[]
}, },
/**输入框内部的文字 */ // 提示文字
placeholder: { placeholder: {
type: String, type: String,
default: '' default: ''
@@ -70,8 +70,9 @@ const state = defineProps({
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
const valueId = computed({ const modelValue = computed({
get: () => { get: () => {
console.log('heihei',state.modelValue)
return state.modelValue return state.modelValue
}, },
set: (val) => { set: (val) => {
@@ -83,7 +84,9 @@ const defaultExpandedKey = ref([]);
function initHandle() { function initHandle() {
nextTick(() => { nextTick(() => {
const selectedValue = valueId.value; console.log("selectedValue1",modelValue)
const selectedValue = modelValue.value;
console.log("selectedValue",modelValue.value)
if(selectedValue !== null && typeof (selectedValue) !== "undefined"){ if(selectedValue !== null && typeof (selectedValue) !== "undefined"){
const node = proxy.$refs.selectTree.getNode(selectedValue) const node = proxy.$refs.selectTree.getNode(selectedValue)
if (node) { if (node) {
@@ -98,34 +101,39 @@ function initHandle() {
} }
function handleNodeClick(node) { function handleNodeClick(node) {
valueTitle.value = node[state.props.label] valueTitle.value = node[state.props.label]
valueId.value = node[state.props.value]; modelValue.value = node[state.props.value];
defaultExpandedKey.value = []; defaultExpandedKey.value = [];
proxy.$refs.treeSelect.blur() proxy.$refs.treeSelect.blur()
selectFilterData('') selectFilterData('')
} }
function selectFilterData(val) { function selectFilterData(val) {
proxy.$refs.selectTree.filter(val) proxy.$refs.selectTree.filter(val)
} }
function filterNode(value, data) { function filterNode(value, data) {
if (!value) return true if (!value) return true
return data[state.props['label']].indexOf(value) !== -1 return data[state.props['label']].indexOf(value) !== -1
} }
function clearHandle() { function clearHandle() {
valueTitle.value = '' valueTitle.value = ''
valueId.value = '' modelValue.value = ''
defaultExpandedKey.value = []; defaultExpandedKey.value = [];
clearSelected() clearSelected()
} }
function clearSelected() { function clearSelected() {
const allNode = document.querySelectorAll('#tree-option .el-tree-node') const allNode = document.querySelectorAll('#tree-option .el-tree-node')
allNode.forEach((element) => element.classList.remove('is-current')) allNode.forEach((element) => element.classList.remove('is-current'))
} }
onMounted(() => { onMounted(() => {
console.log('hah',modelValue)
initHandle() initHandle()
}) })
watch(valueId, () => { watch(modelValue, () => {
initHandle(); initHandle();
}) })
</script> </script>

View File

@@ -15,7 +15,7 @@ import '@/permission'
import Pagination from '@/components/Pagination/index.vue' import Pagination from '@/components/Pagination/index.vue'
import {getDictItemsByCode} from '@/api/system/dict' import {listDictsByCode} from '@/api/system/dict'
const app = createApp(App) const app = createApp(App)
@@ -27,7 +27,7 @@ for (let iconName in ElIconModules) {
} }
// 全局方法 // 全局方法
app.config.globalProperties.$getDictItemsByCode = getDictItemsByCode app.config.globalProperties.$listDictsByCode = listDictsByCode
app.component('Pagination', Pagination) // 全局组件 app.component('Pagination', Pagination) // 全局组件
.use(store) .use(store)
.use(router) .use(router)

View File

@@ -156,82 +156,46 @@
<div style="padding: 6px;"> <div style="padding: 6px;">
<span tyle="font-size: 14px">郝先瑞</span> <span tyle="font-size: 14px">郝先瑞</span>
<div class="bottom clearfix" style="margin-top: 5px"> <div class="bottom clearfix" style="margin-top: 5px">
<el-tag type="primary" size="mini">后端</el-tag> <el-tag size="mini">后端</el-tag>
<el-tag type="success" style="margin-left: 5px" size="mini">前端</el-tag> <el-tag type="success" style="margin-left: 5px" size="mini">前端</el-tag>
<el-tag type="danger" style="margin-left: 5px" size="mini">运维</el-tag> <el-tag type="danger" style="margin-left: 5px" size="mini">运维</el-tag>
</div> </div>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
<el-col :span="8">
<el-card :body-style="{ padding: '0px' }" align="center">
<el-image
style="width: 60px; height: 60px"
src="https://gitee.com/haoxr/image/raw/master/20210606203219.png"
:preview-src-list="['https://gitee.com/haoxr/image/raw/master/20210606203219.png']">
</el-image>
<div style="padding: 6px;">
<span>Mr.</span>
<div class="bottom clearfix" style="margin-top: 5px">
<el-tag type="primary" size="mini">后端</el-tag>
<el-tag type="success" style="margin-left: 5px" size="mini">前端</el-tag>
<el-tag type="danger" style="margin-left: 5px" size="mini">运维</el-tag>
</div>
</div>
</el-card>
</el-col>
<el-col :span="8">
<el-card :body-style="{ padding: '0px' }" align="center">
<el-image
style="width: 60px; height: 60px"
src=" https://gitee.com/haoxr/image/raw/master/20210606203659.png"
:preview-src-list="['https://gitee.com/haoxr/image/raw/master/20210606203659.png']">
</el-image>
<div style="padding: 6px;">
<span>???</span>
<div class="bottom clearfix" style="margin-top: 5px">
<el-tag type="warning" size="mini">??</el-tag>
</div>
</div>
</el-card>
</el-col>
<el-col :span="8">
<el-card :body-style="{ padding: '0px' }" align="center">
<el-image
style="width: 60px; height: 60px"
src="https://gitee.com/haoxr/image/raw/master/huawei.jpg"
:preview-src-list="['https://gitee.com/haoxr/image/raw/master/huawei.jpg']">
</el-image>
<div style="padding: 6px;">
<span>猴子也能上天</span>
<div class="bottom clearfix" style="margin-top: 5px">
<el-tag type="primary" size="mini">后端</el-tag>
<el-tag type="success" style="margin-left: 5px" size="mini">前端</el-tag>
<el-tag type="danger" style="margin-left: 5px" size="mini">运维</el-tag>
</div>
</div>
</el-card>
</el-col>
<el-col :span="8">
<el-card :body-style="{ padding: '0px' }" align="center">
<el-image
style="width: 60px; height: 60px"
src=" https://gitee.com/haoxr/image/raw/master/DaniR.png"
:preview-src-list="['https://gitee.com/haoxr/image/raw/master/DaniR.png']">
</el-image>
<div style="padding: 6px;">
<span>DaniR</span>
<div class="bottom clearfix" style="margin-top: 5px">
<el-tag type="primary" size="mini">后端</el-tag>
<el-tag type="success" style="margin-left: 5px" size="mini">前端</el-tag>
<el-tag type="danger" style="margin-left: 5px" size="mini">运维</el-tag>
</div>
</div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="5" style="margin-top: 8px">
<el-col :span="8">
<el-card :body-style="{ padding: '0px' }" align="center">
<el-image
style="width: 60px; height: 60px"
src="https://gitee.com/haoxr/image/raw/master/20210606203219.png"
:preview-src-list="['https://gitee.com/haoxr/image/raw/master/20210606203219.png']">
</el-image>
<div style="padding: 6px;">
<span>Mr.</span>
<div class="bottom clearfix" style="margin-top: 5px">
<el-tag type="primary" size="mini">后端</el-tag>
<el-tag type="success" style="margin-left: 5px" size="mini">前端</el-tag>
<el-tag type="danger" style="margin-left: 5px" size="mini">运维</el-tag>
</div>
</div>
</el-card>
</el-col>
<el-col :span="8">
<el-card :body-style="{ padding: '0px' }" align="center">
<el-image
style="width: 60px; height: 60px"
src=" https://gitee.com/haoxr/image/raw/master/20210606203659.png"
:preview-src-list="['https://gitee.com/haoxr/image/raw/master/20210606203659.png']">
</el-image>
<div style="padding: 6px;">
<span>???</span>
<div class="bottom clearfix" style="margin-top: 5px">
<el-tag type="warning" size="mini">??</el-tag>
</div>
</div>
</el-card>
</el-col>
</el-row> </el-row>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="微信群" name="2"> <el-tab-pane label="微信群" name="2">

View File

@@ -96,7 +96,7 @@
width="700px" width="700px"
> >
<el-form <el-form
ref="dataForm" ref="dataFormRef"
:model="formData" :model="formData"
:rules="rules" :rules="rules"
label-width="100px" label-width="100px"
@@ -161,7 +161,7 @@ import {onMounted, reactive, ref, toRefs, unref} from "vue";
import {ElForm, ElMessage, ElMessageBox} from "element-plus"; import {ElForm, ElMessage, ElMessageBox} from "element-plus";
import {Search, Plus, Edit, Refresh, Delete} from '@element-plus/icons' import {Search, Plus, Edit, Refresh, Delete} from '@element-plus/icons'
const dataForm = ref(ElForm) // 属性名必须和元素的ref属性值一致 const dataFormRef = ref(ElForm) // 属性名必须和元素的ref属性值一致
const state = reactive({ const state = reactive({
loading: true, loading: true,
@@ -257,11 +257,12 @@ function handleUpdate(row: any) {
} }
function submitForm() { function submitForm() {
const form = unref(dataForm) const dataForm = unref(dataFormRef)
form.validate((valid: any) => { dataForm.validate((valid: any) => {
if (valid) { if (valid) {
if (state.formData.id) { const avertId = state.formData.id
updateAdvert(state.formData.id as any, state.formData).then(response => { if (avertId) {
updateAdvert(avertId, state.formData).then(response => {
ElMessage.success('修改成功') ElMessage.success('修改成功')
state.dialog.visible = false state.dialog.visible = false
handleQuery() handleQuery()

View File

@@ -263,7 +263,7 @@ onMounted(() => {
handleQuery() handleQuery()
// 全局字典调用 // 全局字典调用
const {proxy}: any = getCurrentInstance(); const {proxy}: any = getCurrentInstance();
proxy.$getDictItemsByCode('gender').then((response: any) => { proxy.$listDictsByCode('gender').then((response: any) => {
console.log('性别字典数据', response.data) console.log('性别字典数据', response.data)
}) })
}) })

View File

@@ -14,9 +14,7 @@
</el-button> </el-button>
</el-form-item> </el-form-item>
<el-form-item <el-form-item>
prop="name"
>
<el-input <el-input
v-model="queryParams.name" v-model="queryParams.name"
placeholder="请输入部门名称" placeholder="请输入部门名称"
@@ -24,9 +22,8 @@
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item
prop="status" <el-form-item>
>
<el-select <el-select
v-model="queryParams.status" v-model="queryParams.status"
placeholder="部门状态" placeholder="部门状态"
@@ -177,7 +174,7 @@
<script setup lang="ts"> <script setup lang="ts">
import {onMounted, reactive, unref, ref, toRefs} from 'vue' import {onMounted, reactive, unref, ref, toRefs} from 'vue'
import {Search, Plus, Edit, Refresh, Delete} from '@element-plus/icons' import {Search, Plus, Edit, Refresh, Delete} from '@element-plus/icons'
import {listDept, getDept, delDept, updateDept, addDept, getDeptSelectList} from '@/api/system/dept' import {listDept, getDept, delDept, updateDept, addDept, listDeptsForSelect} from '@/api/system/dept'
import TreeSelect from '@/components/TreeSelect/Index.vue' import TreeSelect from '@/components/TreeSelect/Index.vue'
import {ElForm, ElMessage, ElMessageBox} from 'element-plus' import {ElForm, ElMessage, ElMessageBox} from 'element-plus'
@@ -250,7 +247,6 @@ const queryForm = ref(ElForm)
const formDialog = ref(ElForm) const formDialog = ref(ElForm)
/** /**
* 删除按钮 * 删除按钮
* */ * */
@@ -295,7 +291,7 @@ function resetQuery() {
/** 查询部门下拉树结构 */ /** 查询部门下拉树结构 */
function getTreeselect() { function getTreeselect() {
getDeptSelectList().then(response => { listDeptsForSelect().then(response => {
dataMap.deptOptions = response.data dataMap.deptOptions = response.data
}) })
} }
@@ -369,6 +365,7 @@ async function handleDelete(row: any) {
function dialogshow() { function dialogshow() {
getTreeselect() getTreeselect()
} }
const { const {
ids, single, ids, single,
multiple, multiple,

View File

@@ -244,11 +244,11 @@ function handleSelectionChange(selection: any) {
* 字典数据准备 * 字典数据准备
*/ */
function loadDictData() { function loadDictData() {
proxy.$getDictItemsByCode('micro_service').then((response: any) => { proxy.$listDictsByCode('micro_service').then((response: any) => {
state.microServiceOptions = response.data state.microServiceOptions = response.data
}) })
proxy.$getDictItemsByCode('request_method').then((response: any) => { proxy.$listDictsByCode('request_method').then((response: any) => {
state.requestMethodOptions = response.data state.requestMethodOptions = response.data
}) })
} }

View File

@@ -1,49 +1,44 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-row :gutter="20"> <el-row :gutter="20">
<!--部门数据--> <!-- 部门数据 -->
<el-col <el-col
:span="3" :span="4"
:xs="24" :xs="24"
> >
<div class="head-container"> <el-input
<el-input v-model="deptName"
v-model="deptName" placeholder="部门名称"
placeholder="请输入部门名称" clearable
clearable size="small"
size="small" :prefix-icon="Search"
prefix-icon="el-icon-search" style="margin-bottom: 20px"
style="margin-bottom: 20px" />
/> <el-tree
</div> ref="treeRef"
<div class="head-container"> :data="deptOptions"
<el-tree :props="{ children: 'children',label: 'label'}"
ref="treeRef" :expand-on-click-node="false"
:data="deptOptions" :filter-node-method="filterDeptNode"
:props="defaultProps" default-expand-all
:expand-on-click-node="false" @node-click="handleDeptNodeClick"
:filter-node-method="filterNode" >
default-expand-all </el-tree>
@node-click="handleNodeClick"
/>
</div>
</el-col> </el-col>
<!--用户数据-->
<!-- 用户数据 -->
<el-col <el-col
:span="21" :span="20"
:xs="24" :xs="24"
> >
<el-form <el-form
v-show="showSearch" ref="queryFormRef"
ref="queryForm"
:model="queryParams" :model="queryParams"
:inline="true" :inline="true"
> >
<el-form-item> <el-form-item>
<el-button <el-button
type="primary" type="success"
plain
:icon="Plus" :icon="Plus"
size="mini" size="mini"
@click="handleAdd" @click="handleAdd"
@@ -51,8 +46,7 @@
新增 新增
</el-button> </el-button>
<el-button <el-button
type="success" type="primary"
plain
:icon="Edit" :icon="Edit"
size="mini" size="mini"
:disabled="single" :disabled="single"
@@ -72,10 +66,7 @@
</el-button> </el-button>
</el-form-item> </el-form-item>
<el-form-item <el-form-item>
label="关键字"
prop="keywords"
>
<el-input <el-input
v-model="queryParams.keywords" v-model="queryParams.keywords"
placeholder="用户名/昵称/手机号" placeholder="用户名/昵称/手机号"
@@ -85,23 +76,8 @@
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item
label="手机号码" <el-form-item>
prop="mobile"
>
<el-input
v-model="queryParams.mobile"
placeholder="请输入手机号码"
clearable
size="small"
style="width: 200px"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item
label="状态"
prop="status"
>
<el-select <el-select
v-model="queryParams.status" v-model="queryParams.status"
placeholder="用户状态" placeholder="用户状态"
@@ -109,14 +85,12 @@
size="small" size="small"
style="width: 200px" style="width: 200px"
> >
<el-option <el-option label="正常" value="1"/>
v-for="dict in statusOptions" <el-option label="停用" value="0"/>
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button <el-button
type="primary" type="primary"
@@ -138,7 +112,7 @@
<el-table <el-table
v-loading="loading" v-loading="loading"
:data="userList" :data="pageList"
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
> >
<el-table-column <el-table-column
@@ -147,14 +121,12 @@
align="center" align="center"
/> />
<el-table-column <el-table-column
v-if="columns[0].visible"
key="id" key="id"
label="用户编号" label="用户编号"
align="center" align="center"
prop="id" prop="id"
/> />
<el-table-column <el-table-column
v-if="columns[1].visible"
key="username" key="username"
label="用户名称" label="用户名称"
align="center" align="center"
@@ -162,7 +134,6 @@
:show-overflow-tooltip="true" :show-overflow-tooltip="true"
/> />
<el-table-column <el-table-column
v-if="columns[2].visible"
key="nickname" key="nickname"
label="用户昵称" label="用户昵称"
align="center" align="center"
@@ -170,7 +141,6 @@
:show-overflow-tooltip="true" :show-overflow-tooltip="true"
/> />
<el-table-column <el-table-column
v-if="columns[3].visible"
key="deptName" key="deptName"
label="部门" label="部门"
align="center" align="center"
@@ -178,7 +148,6 @@
:show-overflow-tooltip="true" :show-overflow-tooltip="true"
/> />
<el-table-column <el-table-column
v-if="columns[4].visible"
key="mobile" key="mobile"
label="手机号码" label="手机号码"
align="center" align="center"
@@ -187,7 +156,6 @@
/> />
<el-table-column <el-table-column
v-if="columns[5].visible"
key="status" key="status"
label="状态" label="状态"
align="center" align="center"
@@ -203,7 +171,6 @@
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
v-if="columns[6].visible"
label="创建时间" label="创建时间"
align="center" align="center"
prop="gmtCreate" prop="gmtCreate"
@@ -226,7 +193,7 @@
> >
</el-button> </el-button>
<el-button <el-button
type="success" type="danger"
size="mini" size="mini"
:icon="Delete" :icon="Delete"
circle circle
@@ -235,12 +202,12 @@
> >
</el-button> </el-button>
<el-button <el-button
type="danger" type="warning"
size="mini" size="mini"
:icon="Refresh" :icon="Lock"
circle circle
plain plain
@click="handleResetPwd(scope.row)" @click="resetPassword(scope.row)"
> >
</el-button> </el-button>
</template> </template>
@@ -252,23 +219,22 @@
:total="total" :total="total"
v-model:page="queryParams.page" v-model:page="queryParams.page"
v-model:limit="queryParams.limit" v-model:limit="queryParams.limit"
@pagination="getList" @pagination="handleQuery"
/> />
</el-col> </el-col>
</el-row> </el-row>
<!-- 添加或修改参数配置对话框 --> <!-- 添加或修改参数配置对话框 -->
<el-dialog <el-dialog
:title="title" :title="dialog.title"
v-model="open" v-model="dialog.visible"
width="600px" width="600px"
append-to-body append-to-body
@opened="showDialog"
@close="cancel" @close="cancel"
> >
<el-form <el-form
ref="addForm" ref="dataFormRef"
:model="formVal" :model="formData"
:rules="rules" :rules="rules"
label-width="80px" label-width="80px"
> >
@@ -279,7 +245,7 @@
prop="nickname" prop="nickname"
> >
<el-input <el-input
v-model="formVal.nickname" v-model="formData.nickname"
placeholder="请输入用户昵称" placeholder="请输入用户昵称"
/> />
</el-form-item> </el-form-item>
@@ -290,9 +256,10 @@
prop="deptId" prop="deptId"
> >
<tree-select <tree-select
v-model="formData.deptId"
:options="deptOptions" :options="deptOptions"
placeholder="请选择归属部门" placeholder="请选择归属部门"
v-model="formVal.deptId"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -304,7 +271,7 @@
prop="mobile" prop="mobile"
> >
<el-input <el-input
v-model="formVal.mobile" v-model="formData.mobile"
placeholder="请输入手机号码" placeholder="请输入手机号码"
maxlength="11" maxlength="11"
/> />
@@ -316,7 +283,7 @@
prop="email" prop="email"
> >
<el-input <el-input
v-model="formVal.email" v-model="formData.email"
placeholder="请输入邮箱" placeholder="请输入邮箱"
maxlength="50" maxlength="50"
/> />
@@ -326,26 +293,21 @@
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item <el-form-item
v-if="formVal.userId === undefined" v-if="formData.id === undefined"
label="用户名称" label="用户名称"
prop="userName" prop="userName"
> >
<el-input <el-input
v-model="formVal.username" v-model="formData.username"
placeholder="请输入用户名称" placeholder="请输入用户名称"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="状态"> <el-form-item label="状态">
<el-radio-group v-model="formVal.status"> <el-radio-group v-model="formData.status">
<el-radio <el-radio :label="1">正常</el-radio>
v-for="dict in statusOptions" <el-radio :label="0">禁用</el-radio>
:key="dict.dictValue"
:label="dict.dictValue"
>
{{ dict.dictLabel }}
</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -355,22 +317,19 @@
<el-col :span="12"> <el-col :span="12">
<el-form-item label="用户性别"> <el-form-item label="用户性别">
<el-select <el-select
v-model="formVal.gender" v-model="formData.gender"
placeholder="请选择" placeholder="请选择"
> >
<el-option <el-option label="未知" :value="0"/>
v-for="dict in sexOptions" <el-option label="男" :value="1"/>
:key="dict.value" <el-option label="女" :value="2"/>
:label="dict.name"
:value="dict.value"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="角色"> <el-form-item label="角色">
<el-select <el-select
v-model="formVal.roleIds" v-model="formData.roleIds"
multiple multiple
placeholder="请选择" placeholder="请选择"
> >
@@ -379,23 +338,20 @@
:key="item.id" :key="item.id"
:label="item.name" :label="item.name"
:value="item.id" :value="item.id"
:disabled="item.status === 0"
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item <el-form-item
v-if="formVal.id === undefined" v-if="formData.id === undefined"
label="用户密码" label="用户密码"
prop="password" prop="password"
> >
<el-input <el-input
v-model="formVal.password" v-model="formData.password"
placeholder="请输入用户密码" placeholder="请输入用户密码"
type="password" type="password"
/> />
@@ -425,29 +381,24 @@
</template> </template>
<script setup lang='ts'> <script setup lang='ts'>
import {listUser, getUser, delUser, addUser, updateUser, patch} from '@/api/system/user' // Vue依赖
import {reactive, ref, unref, watchEffect, onMounted, getCurrentInstance, toRefs} from 'vue'
import {getDeptSelectList} from '@/api/system/dept' // API依赖
import TreeSelect from '@/components/TreeSelect/Index.vue' import {listUsersWithPage, getUserFormDetail, deleteUsers, addUser, updateUser, updateUserPart} from '@/api/system/user'
import {listDeptsForSelect} from '@/api/system/dept'
import {listRoles} from '@/api/system/role' import {listRoles} from '@/api/system/role'
import {Search, Plus, Edit, Refresh, Delete} from '@element-plus/icons'
import {reactive, ref, unref, onMounted, watchEffect, getCurrentInstance,toRefs} from 'vue'
import {ElMessage, ElMessageBox, ElTree} from 'element-plus'
// 组件依赖
import {ElMessage, ElMessageBox, ElTree, ElForm} from 'element-plus'
import {Search, Plus, Edit, Refresh, Delete,Lock} from '@element-plus/icons'
import TreeSelect from '@/components/TreeSelect/Index.vue'
const treeRef = ref(ElTree) const treeRef = ref(ElTree)
const queryForm = ref<HTMLInputElement | null>(null) const dataFormRef = ref(ElForm)
const queryFormRef = ref(ElForm) // 变量名和绑定名ref一致
const dataMap = reactive({ const state = reactive({
props: { // 配置项(必选)
value: 'id',
label: 'label',
children: 'children'
},
addformFlag: false,
// 阻止触发switch change事件
tigger: false,
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 选中数组 // 选中数组
@@ -456,44 +407,27 @@ const dataMap = reactive({
single: true, single: true,
// 非多个禁用 // 非多个禁用
multiple: true, multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数 // 总条数
total: 0, total: 0,
originOptions: [],
// 用户表格数据 // 用户表格数据
userList: null, pageList: [],
// 弹出层标题 // 弹窗属性
title: '', dialog: {
title: '',
visible: false
},
// 部门树选项 // 部门树选项
deptOptions: [], deptOptions: [],
// 是否显示弹出层
open: false,
// 部门名称 // 部门名称
deptName: '', deptName: '',
// 默认密码
initPassword: '123456',
// 日期范围
dateRange: [],
// 状态数据字典
statusOptions: [
{
"dictValue": 0,
"dictLabel": "禁用"
},
{
"dictValue": 1,
"dictLabel": "正常"
}
],
// 性别状态字典 // 性别状态字典
sexOptions: [], genderOptions: [],
// 角色选项 // 角色选项
roleOptions: [], roleOptions: [],
// 表单参数 // 表单参数
formVal: { formData: {
id: undefined, id: undefined,
deptId: '', deptId: undefined,
username: undefined, username: undefined,
nickname: undefined, nickname: undefined,
password: '', password: '',
@@ -502,32 +436,16 @@ const dataMap = reactive({
gender: undefined, gender: undefined,
status: 1, status: 1,
remark: undefined, remark: undefined,
postIds: [],
roleIds: [] roleIds: []
}, },
defaultProps: {
children: 'children',
label: 'label'
},
// 查询参数 // 查询参数
queryParams: { queryParams: {
page: 1, page: 1,
limit: 10, limit: 10,
keywords: undefined, keywords: undefined,
mobile: undefined,
status: undefined, status: undefined,
deptId: undefined deptId: undefined
}, },
// 列信息
columns: [
{key: 0, label: '用户编号', visible: true},
{key: 1, label: '用户名称', visible: true},
{key: 2, label: '用户昵称', visible: true},
{key: 3, label: '部门', visible: true},
{key: 4, label: '手机号码', visible: true},
{key: 5, label: '状态', visible: true},
{key: 6, label: '创建时间', visible: true}
],
// 表单校验 // 表单校验
rules: { rules: {
username: [ username: [
@@ -559,124 +477,170 @@ const dataMap = reactive({
} }
}) })
/** 查询用户列表 */ const {
function getList() { loading,
dataMap.loading = true single,
dataMap.tigger = true multiple,
listUser(dataMap.queryParams).then(response => { queryParams,
const {data, total} = response pageList,
dataMap.userList = data total,
dataMap.total = total dialog,
dataMap.loading = false formData,
rules,
deptName,
deptOptions,
roleOptions
} = toRefs(state)
/**
* 加载部门数据
**/
async function loadDeptOptions() {
listDeptsForSelect().then(response => {
state.deptOptions = response.data
}) })
} }
function flatten(origin: any) { /**
let result: any = [] * 部门筛选
for (let i = 0; i < origin.length; i++) { **/
const item = origin[i] watchEffect(() => {
if (Array.isArray(item.children)) { if (state.deptName) {
result = result.concat(flatten(item.children)) const tree = unref(treeRef)
} else { tree.filter(state.deptName)
result.push(item)
}
} }
return result })
}
/** 查询部门下拉树结构 */ function filterDeptNode(value: string, data: any) {
function loadDeptOptions() {
getDeptSelectList().then(response => {
dataMap.deptOptions = response.data
dataMap.originOptions = flatten(response?.data) as any
})
}
// 筛选节点
function filterNode(value: string, data: any) {
if (!value) return true if (!value) return true
return data.label.indexOf(value) !== -1 return data.label.indexOf(value) !== -1
} }
// 节点单击事件 /**
function handleNodeClick(data: { [key: string]: any }) { * 部门点击事件
dataMap.queryParams.deptId = data.id **/
getList() function handleDeptNodeClick(data: { [key: string]: any }) {
state.queryParams.deptId = data.id
handleQuery()
} }
// 用户状态修改 /**
function handleStatusChange(row: { [key: string]: any }) { * 加载角色数据
if (dataMap.tigger) { */
const text = row.status === 1 ? '启用' : '停用' async function loadRoleOptions() {
ElMessageBox.confirm('确认要' + text + ''+ row.username + '用户吗?', '警告', { listRoles().then(response => {
confirmButtonText: '确定', state.roleOptions = response.data
cancelButtonText: '取消',
type: 'warning'
}).then( () =>{
return patch(row.id, {status: row.status})
}).then(() => {
ElMessage.success(text + '成功')
}).catch( ()=>{
row.status = row.status === 1 ? 0 : 1
})
}
}
/** 重置密码按钮操作 */
function handleResetPwd(row: { [key: string]: any }) {
ElMessageBox.prompt('请输入' + row.username + '"的新密码', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputValidator: (value) => {
if (!value || value.trim().length < 1) {
return '请填写新密码'
}
}
}).then(({value}) => {
patch(row.id, {
status: row.status,
password: value
}).then(() => {
ElMessage.success('修改成功,新密码是:' + value)
})
}).catch((err) => {
}) })
} }
/** 搜索按钮操作 */ /**
function handleQuery() { * 用户状态修改
dataMap.queryParams.page = 1 **/
getList() function handleStatusChange(row: { [key: string]: any }) {
const text = row.status === 1 ? '启用' : '停用'
ElMessageBox.confirm('确认要' + text + '' + row.username + '用户吗?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return updateUserPart(row.id, {status: row.status})
}).then(() => {
ElMessage.success(text + '成功')
}).catch(() => {
row.status = row.status === 1 ? 0 : 1
})
} }
/** 重置按钮操作 */ /**
* 密码重置
**/
function resetPassword(row: { [key: string]: any }) {
ElMessageBox.prompt('请输入"' + row.username + '"的新密码', '修改密码', {
confirmButtonText: '确定',
cancelButtonText: '取消'
}).then(({value}) => {
if(!value){
ElMessage.warning("请输入新密码")
return false
}
updateUserPart(row.id, {
password: value
}).then(() => {
ElMessage.success('修改成功,新密码是:' + value)
})
}).catch(()=>{
})
}
/**
* 用户查询
**/
function handleQuery() {
state.loading = true
listUsersWithPage(state.queryParams).then(response => {
const {data, total} = response as any
state.pageList = data
state.total = total
state.loading = false
})
}
/**
* 重置查询
*/
function resetQuery() { function resetQuery() {
(queryForm.value as any).resetFields() const queryForm = unref(queryFormRef)
queryForm.resetFields()
handleQuery() handleQuery()
} }
// 多选框选中数据 /**
* 表格行选中事件
**/
function handleSelectionChange(selection: any) { function handleSelectionChange(selection: any) {
dataMap.ids = selection.map((item: any) => item.id) state.ids = selection.map((item: any) => item.id)
dataMap.single = selection.length !== 1 state.single = selection.length !== 1
dataMap.multiple = !selection.length state.multiple = !selection.length
} }
/** 新增按钮操作 */ /**
function handleAdd() { * 添加用户
dataMap.addformFlag = true **/
dataMap.open = true async function handleAdd() {
dataMap.title = '添加用户' resetForm()
dataMap.formVal.password = "123456" await loadDeptOptions()
await loadRoleOptions()
state.dialog = {
title: '添加用户',
visible: true
}
} }
// 表单重置 /**
* 修改用户
**/
async function handleUpdate(row: { [key: string]: any }) {
const userId = row.id || state.ids
await loadDeptOptions()
await loadRoleOptions()
state.dialog = {
title: '添加用户',
visible: true
}
getUserFormDetail(userId).then((response: any) => {
state.formData = response.data
})
}
/**
* 表单重置
**/
function resetForm() { function resetForm() {
dataMap.formVal = { state.formData = {
id: undefined, id: undefined,
deptId: '', deptId: undefined,
username: undefined, username: undefined,
nickname: undefined, nickname: undefined,
password: '', password: '',
@@ -685,38 +649,30 @@ function resetForm() {
gender: undefined, gender: undefined,
status: 1, status: 1,
remark: undefined, remark: undefined,
postIds: [],
roleIds: [] roleIds: []
} }
} }
/** 修改按钮操作 */
async function handleUpdate(row: { [key: string]: any }) {
const userId = row.id || dataMap.ids
const response = await getUser(userId);
dataMap.formVal = response.data
dataMap.title = '修改用户'
dataMap.formVal.password = ''
dataMap.formVal.deptId =response.data.deptId
dataMap.open = true
}
/**
/** 提交按钮 */ * 表单提交
**/
function submitForm() { function submitForm() {
(queryForm.value as any).validate((valid: any) => { const dataForm = unref(dataFormRef)
dataForm.validate((valid: any) => {
if (valid) { if (valid) {
if (dataMap.formVal.id !== undefined) { const userId = state.formData.id
updateUser(dataMap.formVal.id, dataMap.formVal).then(() => { if (userId) {
updateUser(userId, state.formData).then(() => {
ElMessage.success('修改成功') ElMessage.success('修改成功')
dataMap.open = false state.dialog.visible = false
getList() handleQuery()
}) })
} else { } else {
addUser(dataMap.formVal).then((response: any) => { addUser(state.formData).then((response: any) => {
ElMessage.success('新增成功') ElMessage.success('新增成功')
dataMap.open = false state.dialog.visible = false
getList() handleQuery()
}) })
} }
} }
@@ -725,124 +681,37 @@ function submitForm() {
/** 删除按钮操作 */ /** 删除按钮操作 */
function handleDelete(row: { [key: string]: any }) { function handleDelete(row: { [key: string]: any }) {
const userIds = row.id || dataMap.ids.join(',') const userIds = row.id || state.ids.join(',')
ElMessageBox.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?', '警告', { ElMessageBox.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?', '警告', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(function () { }).then(function () {
return delUser(userIds) deleteUsers(userIds).then(() => {
}).then(() => { ElMessage.success('删除成功')
getList() handleQuery()
ElMessage.success('刪除成功') })
}).catch(() => }).catch(() =>
ElMessage.info('已取消删除') ElMessage.info('已取消删除')
) )
} }
// 取消按钮 /**
* 取消关闭
*/
function cancel() { function cancel() {
dataMap.tigger = true
dataMap.open = false
resetForm() resetForm()
} state.dialog.visible = false
function getDeptId(e: any) {
dataMap.formVal.deptId = e
}
watchEffect(() => {
if (dataMap.deptName) {
const tree = unref(treeRef)
tree.filter(dataMap.deptName)
}
})
async function loadRoleOptions() {
listRoles({}).then(response => {
dataMap.roleOptions = response.data
})
} }
onMounted(() => { onMounted(() => {
getList()
loadDeptOptions() loadDeptOptions()
loadRoleOptions() handleQuery()
const {proxy}: any = getCurrentInstance(); const {proxy}: any = getCurrentInstance();
proxy.$getDictItemsByCode('gender').then((response: any) => { proxy.$listDictsByCode('gender').then((response: any) => {
dataMap.sexOptions = response?.data state.genderOptions = response?.data
}) })
}) })
function showDialog() {
loadDeptOptions()
loadRoleOptions()
}
const {
props,
addformFlag,
// 阻止触发switch change事件
tigger,
// 遮罩层
loading,
// 选中数组
ids,
// 非单个禁用
single,
// 非多个禁用
multiple,
// 显示搜索条件
showSearch,
// 总条数
total,
originOptions,
// 用户表格数据
userList,
// 弹出层标题
title,
// 部门树选项
deptOptions,
// 是否显示弹出层
open,
// 部门名称
deptName,
// 默认密码
initPassword,
// 日期范围
dateRange,
// 状态数据字典
statusOptions,
// 性别状态字典
sexOptions,
// 角色选项
roleOptions,
// 表单参数
formVal,
defaultProps,
// 查询参数
queryParams,
// 列信息
columns,
// 表单校验
rules
} = toRefs(dataMap)
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.small-padding {
.cell {
padding-left: 5px;
padding-right: 5px;
}
}
.fixed-width {
.el-button--mini {
padding: 7px 10px;
width: 60px;
}
}
</style> </style>