master
parent
ad0fd2ab96
commit
183b44c83a
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<el-config-provider :button="buttonConfig" size="default">
|
||||
<el-config-provider :button="buttonConfig" size="small">
|
||||
<router-view #="{ Component }">
|
||||
<component :is="Component"/>
|
||||
</router-view>
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ router.beforeEach((to, from) => {
|
|||
} else {
|
||||
return {
|
||||
replace: true,
|
||||
name: 'menus',
|
||||
name: 'role',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -108,6 +108,8 @@ export function reloadRouter() {
|
|||
.map((it) => it.routeName)
|
||||
|
||||
routNames.push('menus')
|
||||
routNames.push('user')
|
||||
routNames.push('role')
|
||||
|
||||
if (Colls.isEmpty(routNames)) {
|
||||
return false
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
export {}
|
||||
declare global {
|
||||
const EffectScope: typeof import('vue').EffectScope
|
||||
const ElMessage: typeof import('element-plus/es').ElMessage
|
||||
const acceptHMRUpdate: typeof import('pinia').acceptHMRUpdate
|
||||
const computed: typeof import('vue').computed
|
||||
const createApp: typeof import('vue').createApp
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
// ------
|
||||
// Generated by unplugin-vue-components
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
import { GlobalComponents } from 'vue'
|
||||
|
||||
export {}
|
||||
|
||||
|
|
@ -15,25 +14,35 @@ declare module 'vue' {
|
|||
ElAside: typeof import('element-plus/es')['ElAside']
|
||||
ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
|
||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
||||
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
||||
ElContainer: typeof import('element-plus/es')['ElContainer']
|
||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
||||
ElEmpty: typeof import('element-plus/es')['ElEmpty']
|
||||
ElForm: typeof import('element-plus/es')['ElForm']
|
||||
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||
ElHeader: typeof import('element-plus/es')['ElHeader']
|
||||
ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||
ElIconFilter: typeof import('@element-plus/icons-vue')['Filter']
|
||||
ElIconPicture: typeof import('@element-plus/icons-vue')['Picture']
|
||||
ElImage: typeof import('element-plus/es')['ElImage']
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
|
||||
ElMain: typeof import('element-plus/es')['ElMain']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||
ElTable: typeof import('element-plus/es')['ElTable']
|
||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
||||
ElTabPane: typeof import('element-plus/es')['ElTabPane']
|
||||
ElTabs: typeof import('element-plus/es')['ElTabs']
|
||||
ElTag: typeof import('element-plus/es')['ElTag']
|
||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||
ElTransfer: typeof import('element-plus/es')['ElTransfer']
|
||||
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
|
||||
ElUpload: typeof import('element-plus/es')['ElUpload']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
|
|
@ -49,25 +58,35 @@ declare global {
|
|||
const ElAside: typeof import('element-plus/es')['ElAside']
|
||||
const ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
||||
const ElButton: typeof import('element-plus/es')['ElButton']
|
||||
const ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
|
||||
const ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||
const ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
||||
const ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
||||
const ElContainer: typeof import('element-plus/es')['ElContainer']
|
||||
const ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
const ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
||||
const ElEmpty: typeof import('element-plus/es')['ElEmpty']
|
||||
const ElForm: typeof import('element-plus/es')['ElForm']
|
||||
const ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||
const ElHeader: typeof import('element-plus/es')['ElHeader']
|
||||
const ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||
const ElIconFilter: typeof import('@element-plus/icons-vue')['Filter']
|
||||
const ElIconPicture: typeof import('@element-plus/icons-vue')['Picture']
|
||||
const ElImage: typeof import('element-plus/es')['ElImage']
|
||||
const ElInput: typeof import('element-plus/es')['ElInput']
|
||||
const ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
|
||||
const ElMain: typeof import('element-plus/es')['ElMain']
|
||||
const ElOption: typeof import('element-plus/es')['ElOption']
|
||||
const ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||
const ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
const ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||
const ElTable: typeof import('element-plus/es')['ElTable']
|
||||
const ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
||||
const ElTabPane: typeof import('element-plus/es')['ElTabPane']
|
||||
const ElTabs: typeof import('element-plus/es')['ElTabs']
|
||||
const ElTag: typeof import('element-plus/es')['ElTag']
|
||||
const ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||
const ElTransfer: typeof import('element-plus/es')['ElTransfer']
|
||||
const ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
|
||||
const ElUpload: typeof import('element-plus/es')['ElUpload']
|
||||
const RouterLink: typeof import('vue-router')['RouterLink']
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ declare global {
|
|||
}
|
||||
|
||||
interface PageParam {
|
||||
current: number
|
||||
size: number
|
||||
current?: number
|
||||
size?: number
|
||||
orders?: string
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
import {
|
||||
ElButton,
|
||||
ElIcon,
|
||||
ElMenu,
|
||||
ElMenuItem,
|
||||
ElMenuItemGroup,
|
||||
ElSubMenu,
|
||||
type MenuItemRegistered,
|
||||
} from 'element-plus'
|
||||
|
||||
import { elIcons } from '@/common/element/element.ts'
|
||||
|
||||
export interface Menu extends G.TreeNode {
|
||||
// Id
|
||||
|
|
@ -72,10 +74,24 @@ export default defineComponent(
|
|||
}
|
||||
return currentNode
|
||||
}
|
||||
const isCollapse = ref(false)
|
||||
|
||||
return () => (<ElMenu>{{
|
||||
return () => (<>
|
||||
<ElMenu collapse={isCollapse.value} style={{height: '100%', overflow: 'auto', '--el-menu-base-level-padding': '10px'}} class={'menus'}>
|
||||
{{
|
||||
default: () => menus.map(renderMenu),
|
||||
}}</ElMenu>)
|
||||
}}
|
||||
</ElMenu>
|
||||
<ElButton style={{position: 'absolute', right: 0, bottom: 0, width: '32px', height: '32px'}} onClick={() => {
|
||||
isCollapse.value = !isCollapse.value
|
||||
}}>
|
||||
<ElIcon style={{cursor: 'pointer'}}>
|
||||
{
|
||||
isCollapse.value ? <elIcons.Fold/> : <elIcons.Expand/>
|
||||
}
|
||||
</ElIcon>
|
||||
</ElButton>
|
||||
</>)
|
||||
},
|
||||
{
|
||||
props: {
|
||||
|
|
|
|||
|
|
@ -102,12 +102,8 @@ onUnmounted(() => {
|
|||
|
||||
& > aside {
|
||||
height 100%;
|
||||
width 300px;
|
||||
|
||||
& > ul {
|
||||
height 100%
|
||||
overflow auto
|
||||
}
|
||||
width auto
|
||||
position relative
|
||||
}
|
||||
|
||||
& > main {
|
||||
|
|
@ -120,4 +116,10 @@ onUnmounted(() => {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
<style>
|
||||
.menus:not(.el-menu--collapse) {
|
||||
width: 230px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ const loginFormIns = ref<FormInstance>()
|
|||
const loginForm = reactive<LoginTypes.LoginForm>({
|
||||
account: '',
|
||||
secret: '',
|
||||
clientCode: 0,
|
||||
})
|
||||
const rules = reactive<FormRules<LoginTypes.LoginForm>>({
|
||||
account: [
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ declare global {
|
|||
interface LoginForm {
|
||||
account: string
|
||||
secret: string
|
||||
clientCode: 0 | 1
|
||||
}
|
||||
|
||||
interface UserSetting {
|
||||
|
|
|
|||
|
|
@ -133,10 +133,10 @@ onMounted(() => {
|
|||
width 100%
|
||||
|
||||
:deep(.table-header) {
|
||||
color black
|
||||
color #454C59
|
||||
|
||||
th {
|
||||
background-color #E1E5EB
|
||||
background-color #EDF1F7
|
||||
font-weight 500
|
||||
position relative
|
||||
|
||||
|
|
@ -151,7 +151,7 @@ onMounted(() => {
|
|||
top: 50%;
|
||||
left: 1px;
|
||||
width: 1px;
|
||||
background-color: #A6AFB5;
|
||||
background-color: #D3D7DE;
|
||||
transform: translateY(-50%);
|
||||
content: "";
|
||||
height 50%
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
import { get } from '@/common/utils/http-util.ts'
|
||||
|
||||
export default {
|
||||
list(data?: ResourceTypes.SearchResourceParam) {
|
||||
return get<ResourceTypes.SearchResourceResult[]>('/resource/list', data)
|
||||
},
|
||||
listRoleRes(roleId: string) {
|
||||
return get<ResourceTypes.SearchResourceResult[]>('/resource/list_role_res', {roleId})
|
||||
},
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
export {}
|
||||
declare global {
|
||||
namespace ResourceTypes {
|
||||
interface SearchResourceParam extends G.PageParam {
|
||||
// Id
|
||||
id?: string
|
||||
// 编号
|
||||
sn?: string
|
||||
// 表名称
|
||||
tableName?: string
|
||||
// 数据行 Id
|
||||
dataId?: string
|
||||
// 备注
|
||||
memo?: string
|
||||
keywords?: string
|
||||
}
|
||||
|
||||
interface SearchResourceResult {
|
||||
// Id
|
||||
id?: string
|
||||
// 编号
|
||||
sn?: string
|
||||
// 表名称
|
||||
tableName?: string
|
||||
// 数据行 Id
|
||||
dataId?: string
|
||||
// 备注
|
||||
memo?: string
|
||||
}
|
||||
|
||||
interface AddResourceParam {
|
||||
// Id
|
||||
id?: string
|
||||
// 编号
|
||||
sn?: string
|
||||
// 表名称
|
||||
tableName?: string
|
||||
// 数据行 Id
|
||||
dataId?: string
|
||||
// 备注
|
||||
memo?: string
|
||||
}
|
||||
|
||||
interface ModifyResourceParam {
|
||||
// Id
|
||||
id?: string
|
||||
// 编号
|
||||
sn?: string
|
||||
// 表名称
|
||||
tableName?: string
|
||||
// 数据行 Id
|
||||
dataId?: string
|
||||
// 备注
|
||||
memo?: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
<template>
|
||||
<ElDialog v-model="showDialog"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
width="900">
|
||||
<ElTransfer
|
||||
v-model="rightValue"
|
||||
:button-texts="['解绑', '绑定']"
|
||||
:data="allRes"
|
||||
:filter-method="filterMethod"
|
||||
:props="{
|
||||
key: 'id',
|
||||
label: 'roleName',
|
||||
}"
|
||||
:titles="['资源列表', '已有资源']"
|
||||
class="transfer"
|
||||
filter-placeholder="搜索"
|
||||
filterable
|
||||
>
|
||||
<template #default="{ option }">
|
||||
<ElTooltip
|
||||
:content="option.sn"
|
||||
placement="top">
|
||||
<span> {{ option.memo }} </span>
|
||||
</ElTooltip>
|
||||
</template>
|
||||
<template #left-empty>
|
||||
<el-empty :image-size="60" description="暂无数据"/>
|
||||
</template>
|
||||
<template #right-empty>
|
||||
<el-empty :image-size="60" description="暂无数据"/>
|
||||
</template>
|
||||
</ElTransfer>
|
||||
<template #footer>
|
||||
<ElButton @click="showDialog = false">取消</ElButton>
|
||||
<ElButton :disabled="rightValue.length <= 0" :loading="submiting" type="primary" @click="submitHandler">提交</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import RoleApi from '@/pages/sys/role/role-api.ts'
|
||||
import Strings from '@/common/utils/strings.ts'
|
||||
import {
|
||||
ElMessage,
|
||||
type TransferDataItem,
|
||||
} from 'element-plus'
|
||||
import ResourceApi from '@/pages/sys/resource/resource-api.ts'
|
||||
|
||||
const showDialog = ref(false)
|
||||
const submiting = ref(false)
|
||||
const hadRes = ref<ResourceTypes.SearchResourceResult[]>([])
|
||||
const allRes = ref<ResourceTypes.SearchResourceResult[]>([])
|
||||
const rightValue = ref<string[]>([])
|
||||
const currentUserId = ref<string>('')
|
||||
|
||||
function filterMethod(query: string, item: TransferDataItem) {
|
||||
return Strings.isBlank(query) || (item as ResourceTypes.SearchResourceResult).memo!.includes(query) || (item as ResourceTypes.SearchResourceResult).memo!.includes(query)
|
||||
}
|
||||
|
||||
function submitHandler() {
|
||||
submiting.value = true
|
||||
RoleApi.bindRes({
|
||||
id: currentUserId.value,
|
||||
res: rightValue.value,
|
||||
}).then(() => {
|
||||
ElMessage.success('修改成功')
|
||||
showDialog.value = false
|
||||
})
|
||||
.finally(() => {
|
||||
submiting.value = false
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open(roleId: string) {
|
||||
currentUserId.value = roleId
|
||||
showDialog.value = true
|
||||
ResourceApi.listRoleRes(roleId)
|
||||
.then(res => {
|
||||
hadRes.value = res.data ?? []
|
||||
rightValue.value = hadRes.value.map(it => it.id!)
|
||||
})
|
||||
ResourceApi.list()
|
||||
.then(res => {
|
||||
allRes.value = res.data ?? []
|
||||
})
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="stylus" scoped>
|
||||
.transfer {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
:deep(.el-transfer-panel) {
|
||||
flex 1
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import {
|
||||
get,
|
||||
post,
|
||||
} from '@/common/utils/http-util.ts'
|
||||
|
||||
export default {
|
||||
paging(data: RoleTypes.SearchRoleParam) {
|
||||
return get<G.PageResult<RoleTypes.SearchRoleResult>>('/role/paging', data)
|
||||
},
|
||||
detail(id: string) {
|
||||
return get<RoleTypes.SearchRoleResult>('/role/detail', {id})
|
||||
},
|
||||
add(data: RoleTypes.AddRoleParam) {
|
||||
return post('/role/add', data)
|
||||
},
|
||||
modify(data: RoleTypes.ModifyRoleParam) {
|
||||
return post('/role/modify', data)
|
||||
},
|
||||
del(ids: string[]) {
|
||||
return post('/role/del', ids)
|
||||
},
|
||||
listUserRole(userId: string) {
|
||||
return get<RoleTypes.SearchRoleResult[]>('/role/list_user_role', {userId})
|
||||
},
|
||||
list(data?: RoleTypes.SearchRoleParam) {
|
||||
return get<RoleTypes.SearchRoleResult[]>('/role/list', data)
|
||||
},
|
||||
bindRes(data: RoleTypes.BindResParam) {
|
||||
return post('/role/bind_res', data)
|
||||
},
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
export {}
|
||||
declare global {
|
||||
namespace RoleTypes {
|
||||
interface SearchRoleParam extends G.PageParam {
|
||||
// Id
|
||||
id?: string
|
||||
// 角色代码
|
||||
roleCode?: string
|
||||
// 角色名称
|
||||
roleName?: string
|
||||
// 备注
|
||||
memo?: string
|
||||
}
|
||||
|
||||
interface SearchRoleResult {
|
||||
// Id
|
||||
id?: string
|
||||
// 角色代码
|
||||
roleCode?: string
|
||||
// 角色名称
|
||||
roleName?: string
|
||||
// 备注
|
||||
memo?: string
|
||||
}
|
||||
|
||||
interface AddRoleParam {
|
||||
// Id
|
||||
id?: string
|
||||
// 角色代码
|
||||
roleCode?: string
|
||||
// 角色名称
|
||||
roleName?: string
|
||||
// 备注
|
||||
memo?: string
|
||||
}
|
||||
|
||||
interface ModifyRoleParam {
|
||||
// Id
|
||||
id?: string
|
||||
// 角色代码
|
||||
roleCode?: string
|
||||
// 角色名称
|
||||
roleName?: string
|
||||
// 备注
|
||||
memo?: string
|
||||
}
|
||||
|
||||
|
||||
interface BindResParam {
|
||||
id?: string
|
||||
res?: string[]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
<template>
|
||||
<ElDialog v-model="showDialog"
|
||||
:close-on-click-modal="false"
|
||||
destroy-on-close
|
||||
width="700">
|
||||
<ElTransfer
|
||||
v-model="rightValue"
|
||||
:button-texts="['解绑', '绑定']"
|
||||
:data="allRoles"
|
||||
:filter-method="filterMethod"
|
||||
:props="{
|
||||
key: 'id',
|
||||
label: 'roleName',
|
||||
}"
|
||||
:titles="['角色列表', '已有角色']"
|
||||
class="transfer"
|
||||
filter-placeholder="搜索"
|
||||
filterable
|
||||
>
|
||||
<template #default="{ option }">
|
||||
<ElTooltip
|
||||
:content="option.roleCode"
|
||||
placement="top">
|
||||
<span> {{ option.roleName }} </span>
|
||||
</ElTooltip>
|
||||
</template>
|
||||
<template #left-empty>
|
||||
<el-empty :image-size="60" description="暂无数据"/>
|
||||
</template>
|
||||
<template #right-empty>
|
||||
<el-empty :image-size="60" description="暂无数据"/>
|
||||
</template>
|
||||
</ElTransfer>
|
||||
<template #footer>
|
||||
<ElButton @click="showDialog = false">取消</ElButton>
|
||||
<ElButton :disabled="rightValue.length <= 0" :loading="submiting" type="primary" @click="submitHandler">提交</ElButton>
|
||||
</template>
|
||||
</ElDialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import RoleApi from '@/pages/sys/role/role-api.ts'
|
||||
import Strings from '@/common/utils/strings.ts'
|
||||
import {
|
||||
ElMessage,
|
||||
type TransferDataItem,
|
||||
} from 'element-plus'
|
||||
import UserApi from '@/pages/sys/user/user-api.ts'
|
||||
|
||||
const showDialog = ref(false)
|
||||
const submiting = ref(false)
|
||||
const hadRoles = ref<RoleTypes.SearchRoleResult[]>([])
|
||||
const allRoles = ref<RoleTypes.SearchRoleResult[]>([])
|
||||
const rightValue = ref<string[]>([])
|
||||
const currentUserId = ref<string>('')
|
||||
|
||||
function filterMethod(query: string, item: TransferDataItem) {
|
||||
return Strings.isBlank(query) || (item as RoleTypes.SearchRoleResult).roleCode!.includes(query) || (item as RoleTypes.SearchRoleResult).roleName!.includes(query)
|
||||
}
|
||||
|
||||
function submitHandler() {
|
||||
submiting.value = true
|
||||
UserApi.bindRole({
|
||||
id: currentUserId.value,
|
||||
roles: rightValue.value,
|
||||
}).then(() => {
|
||||
ElMessage.success('修改成功')
|
||||
showDialog.value = false
|
||||
})
|
||||
.finally(() => {
|
||||
submiting.value = false
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open(userId: string) {
|
||||
currentUserId.value = userId
|
||||
showDialog.value = true
|
||||
RoleApi.listUserRole(userId)
|
||||
.then(res => {
|
||||
hadRoles.value = res.data ?? []
|
||||
rightValue.value = hadRoles.value.map(it => it.id!)
|
||||
})
|
||||
RoleApi.list()
|
||||
.then(res => {
|
||||
allRoles.value = res.data ?? []
|
||||
})
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="stylus" scoped>
|
||||
.transfer {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -37,21 +37,49 @@
|
|||
header-row-class-name="table-header"
|
||||
row-key="id">
|
||||
<ElTableColumn label="昵称" prop="nickname"/>
|
||||
|
||||
<ElTableColumn label="头像" prop="avatar"/>
|
||||
|
||||
<ElTableColumn label="邮箱" prop="email"/>
|
||||
|
||||
<ElTableColumn label="手机号" prop="phone"/>
|
||||
<ElTableColumn label="头像" prop="avatar" width="60">
|
||||
<template #default="{row}">
|
||||
<ElImage :src="AppApi.fileUrl(row.avatar)" class="avatar">
|
||||
<template #error>
|
||||
<ElIcon>
|
||||
<ElIconPicture/>
|
||||
</ElIcon>
|
||||
</template>
|
||||
</ElImage>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="联系电话" prop="phone"/>
|
||||
<ElTableColumn label="登录手机号" prop="account.phone"/>
|
||||
<ElTableColumn label="用户名" prop="account.username"/>
|
||||
<ElTableColumn label="微信标识" prop="account.wechatOpenid"/>
|
||||
<ElTableColumn label="已授权客户端" prop="account.clientCode">
|
||||
<template #default="{row}">
|
||||
<ElCheckboxGroup v-model="row.account.clients" :disabled="row.id == '1'" @change="clientChangeHandler($event,row)">
|
||||
<ElCheckbox :value="0" label="电脑端"/>
|
||||
<ElCheckbox :value="1" label="微信小程序"/>
|
||||
</ElCheckboxGroup>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="是否禁用" prop="account.disabled">
|
||||
<template #default="{row}">
|
||||
<ElSwitch v-model="row.account.disabled" :disabled="row.id == '1'" @change="disabledUserHandler($event,row.id)"/>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
<ElTableColumn label="注册时间" prop="account.regdate" width="170"/>
|
||||
|
||||
<ElTableColumn label="操作" width="180">
|
||||
<template #default="scope">
|
||||
<ElButton text type="danger" @click="delHandler(scope)">删除</ElButton>
|
||||
<ElButton text type="primary" @click="modifyHandler(scope)">修改</ElButton>
|
||||
<!-- <ElButton text type="danger" :loading="deling" @click="delHandler(scope)">删除</ElButton> -->
|
||||
<div class="action-btn">
|
||||
<ElButton text type="primary" @click="bindRoleHandler(scope)">权限</ElButton>
|
||||
<ElButton v-if="scope.row.id != '1'" text type="primary" @click="modifyHandler(scope)">修改</ElButton>
|
||||
<ElButton v-if="scope.row.id != '1'" text type="primary" @click="resetPasswd(scope)">重置密码</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
</ElTableColumn>
|
||||
</ElTable>
|
||||
<UserForm ref="userForm"/>
|
||||
<UserForm ref="userForm" @edit-succ="paging"/>
|
||||
<BindRole ref="bindRole"/>
|
||||
</Page>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
|
|
@ -59,40 +87,117 @@ import UserApi from '@/pages/sys/user/user-api.ts'
|
|||
import Page from '@/components/page/Page.vue'
|
||||
import { elIcons } from '@/common/element/element.ts'
|
||||
import UserForm from '@/pages/sys/user/UserForm.vue'
|
||||
import {
|
||||
type CheckboxValueType,
|
||||
ElMessage,
|
||||
} from 'element-plus'
|
||||
import AppApi from '@/common/app/app-api.ts'
|
||||
import BindRole from '@/pages/sys/user/BindRole.vue'
|
||||
|
||||
const tableData = ref<UserTypes.SearchUserResult[]>([])
|
||||
const searchForm = reactive<UserTypes.SearchUserParam>({
|
||||
current: 1,
|
||||
size: 20,
|
||||
})
|
||||
const searching = ref(false)
|
||||
// const deling = ref(false)
|
||||
const showSearchForm = ref(true)
|
||||
const userFormIns = useTemplateRef<InstanceType<typeof UserForm>>('userForm')
|
||||
const bindRoleIns = useTemplateRef<InstanceType<typeof BindRole>>('bindRole')
|
||||
|
||||
function showDialog(data?: UserTypes.SearchUserResult) {
|
||||
userFormIns.value?.open(data)
|
||||
}
|
||||
function delHandler({row}: { row: UserTypes.SearchUserResult }) {
|
||||
|
||||
/* function delHandler({row}: { row: UserTypes.SearchUserResult }) {
|
||||
if (row.id == '1') {
|
||||
ElMessage.error('不能删除管理员')
|
||||
return
|
||||
}
|
||||
deling.value = true
|
||||
UserApi.del([ row.id! ])
|
||||
}
|
||||
.then(() => {
|
||||
ElMessage.success('删除成功')
|
||||
paging()
|
||||
})
|
||||
.finally(() => {
|
||||
deling.value = false
|
||||
})
|
||||
} */
|
||||
|
||||
function modifyHandler({row}: { row: UserTypes.SearchUserResult }) {
|
||||
if (row.id == '1') {
|
||||
ElMessage.error('不能修改管理员')
|
||||
return
|
||||
}
|
||||
showDialog(row)
|
||||
}
|
||||
|
||||
function resetPasswd({row}: { row: UserTypes.SearchUserResult }) {
|
||||
if (row.id == '1') {
|
||||
ElMessage.error('不能修改管理员')
|
||||
return
|
||||
}
|
||||
UserApi.resetPasswd(row.id!)
|
||||
.then((res) => {
|
||||
ElMessage.success(res.msg)
|
||||
})
|
||||
}
|
||||
|
||||
function bindRoleHandler({row}: { row: UserTypes.SearchUserResult }) {
|
||||
bindRoleIns.value?.open(row.id!)
|
||||
}
|
||||
|
||||
function addHandler() {
|
||||
showDialog()
|
||||
}
|
||||
|
||||
function reset() {
|
||||
Object.assign(searchForm, {})
|
||||
paging()
|
||||
}
|
||||
|
||||
function clientChangeHandler(clients: CheckboxValueType[], data: UserTypes.SearchUserResult) {
|
||||
if (data.id == '1') {
|
||||
ElMessage.error('不能操作管理员')
|
||||
return
|
||||
}
|
||||
searching.value = true
|
||||
UserApi.bindClient(data.id!, clients as number[])
|
||||
.then(() => {
|
||||
ElMessage.success('修改成功')
|
||||
paging()
|
||||
})
|
||||
}
|
||||
|
||||
function disabledUserHandler(val: string | number | boolean, id: string) {
|
||||
if (id == '1') {
|
||||
ElMessage.error('不能操作管理员')
|
||||
return
|
||||
}
|
||||
searching.value = true
|
||||
UserApi.disable(id, val as boolean)
|
||||
.then(() => {
|
||||
ElMessage.success(val ? '禁用成功' : '启用成功')
|
||||
paging()
|
||||
})
|
||||
}
|
||||
|
||||
function paging() {
|
||||
searching.value = true
|
||||
UserApi.paging(searchForm)
|
||||
.then(res => {
|
||||
tableData.value = res.data?.records ?? []
|
||||
tableData.value.map(it => {
|
||||
it.account.clients = UserApi.clients(it.account.clientCode!).map(it => it.val)
|
||||
return it
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
searching.value = false
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
paging()
|
||||
})
|
||||
|
|
@ -101,36 +206,64 @@ onMounted(() => {
|
|||
.table-list {
|
||||
flex 1;
|
||||
width 100%
|
||||
|
||||
:deep(.table-header) {
|
||||
color black
|
||||
color #454C59
|
||||
|
||||
th {
|
||||
background-color #E1E5EB
|
||||
background-color #EDF1F7
|
||||
font-weight 500
|
||||
position relative
|
||||
|
||||
& > div {
|
||||
display flex
|
||||
gap 5px
|
||||
align-items center
|
||||
}
|
||||
|
||||
&:not(:first-child) > div::before {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 1px;
|
||||
width: 1px;
|
||||
background-color: #A6AFB5;
|
||||
background-color: #D3D7DE;
|
||||
transform: translateY(-50%);
|
||||
content: "";
|
||||
height 50%
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.table-cell) {
|
||||
color #2F3540
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
width 100%
|
||||
display flex
|
||||
flex-wrap wrap
|
||||
|
||||
& > button {
|
||||
margin 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tool-bar {
|
||||
display flex
|
||||
justify-content space-between
|
||||
margin 0 0 20px 0
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
:deep(.el-icon) {
|
||||
font-size 25px
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -13,22 +13,35 @@
|
|||
placeholder="昵称"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="头像">
|
||||
<ElInput
|
||||
v-model="userFormData.avatar"
|
||||
<Uploader
|
||||
v-model:file="userFormData.avatar"
|
||||
:disabled="status === 'view'"
|
||||
placeholder="头像"/>
|
||||
:limit="1"
|
||||
:multiple="true"
|
||||
accept="image/*"
|
||||
class="avatar-uploader"
|
||||
list-type="picture">
|
||||
<ElButton>点击上传头像</ElButton>
|
||||
</Uploader>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="邮箱">
|
||||
<ElInput
|
||||
v-model="userFormData.email"
|
||||
:disabled="status === 'view'"
|
||||
placeholder="邮箱"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem label="手机号">
|
||||
<ElFormItem label="联系电话">
|
||||
<ElInput
|
||||
v-model="userFormData.phone"
|
||||
:disabled="status === 'view'"
|
||||
placeholder="手机号"/>
|
||||
placeholder="联系电话"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem v-if="status === 'add'" label="用户名">
|
||||
<ElInput
|
||||
v-model="userFormData.account.username"
|
||||
placeholder="用户名"/>
|
||||
</ElFormItem>
|
||||
<ElFormItem v-if="status === 'add'" label="密码">
|
||||
<ElInput
|
||||
v-model="userFormData.account.secret"
|
||||
autocomplete="new-password"
|
||||
placeholder="密码"
|
||||
show-password
|
||||
type="password"/>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<template #footer>
|
||||
|
|
@ -41,10 +54,19 @@
|
|||
import UserApi from '@/pages/sys/user/user-api.ts'
|
||||
import Strings from '@/common/utils/strings.ts'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import Uploader from '@/components/uploader/Uploader.vue'
|
||||
|
||||
const emits = defineEmits([ 'editSucc' ])
|
||||
const showDialog = ref(false)
|
||||
const submiting = ref(false)
|
||||
const status = ref<'add' | 'view' | 'modify'>('add')
|
||||
const userFormData = reactive<UserTypes.SearchUserResult>({})
|
||||
const userFormData = reactive<UserTypes.SearchUserResult>({
|
||||
account: {
|
||||
username: '',
|
||||
secret: '',
|
||||
},
|
||||
})
|
||||
|
||||
function submitHandler() {
|
||||
if (status.value === 'view') return
|
||||
submiting.value = true
|
||||
|
|
@ -52,6 +74,8 @@ function submitHandler() {
|
|||
UserApi.modify(userFormData)
|
||||
.then(() => {
|
||||
ElMessage.success('修改成功')
|
||||
emits('editSucc')
|
||||
showDialog.value = false
|
||||
})
|
||||
.finally(() => {
|
||||
submiting.value = false
|
||||
|
|
@ -60,30 +84,44 @@ function submitHandler() {
|
|||
UserApi.add(userFormData)
|
||||
.then(() => {
|
||||
ElMessage.success('添加成功')
|
||||
emits('editSucc')
|
||||
showDialog.value = false
|
||||
})
|
||||
.finally(() => {
|
||||
submiting.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open(data: UserTypes.SearchUserResult = {}) {
|
||||
open(data?: UserTypes.SearchUserResult) {
|
||||
showDialog.value = true
|
||||
if (!Strings.isBlank(data.id)) {
|
||||
if (data != null && !Strings.isBlank(data.id)) {
|
||||
status.value = 'modify'
|
||||
UserApi.detail(data.id!)
|
||||
.then(res => {
|
||||
Object.assign(userFormData, res.data)
|
||||
Object.assign(userFormData, {
|
||||
...res.data, account: {},
|
||||
})
|
||||
})
|
||||
} else {
|
||||
status.value = 'add'
|
||||
Object.assign(userFormData, {})
|
||||
}
|
||||
Object.assign(userFormData, {
|
||||
account: {
|
||||
username: '',
|
||||
secret: '',
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style lang="stylus" scoped>
|
||||
.sys_user-form {
|
||||
padding 20px
|
||||
}
|
||||
|
||||
.avatar-uploader {
|
||||
width 100%
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,21 +1,57 @@
|
|||
import {
|
||||
get,
|
||||
post
|
||||
post,
|
||||
} from '@/common/utils/http-util.ts'
|
||||
|
||||
const Clients = [ {
|
||||
txt: '电脑端',
|
||||
val: 0,
|
||||
}, {
|
||||
txt: '微信小程序',
|
||||
val: 1,
|
||||
} ]
|
||||
export default {
|
||||
paging(data: UserTypes.SearchUserParam) {
|
||||
return get<G.PageResult<UserTypes.SearchUserResult>>('/sys_user/paging', data)
|
||||
return get<G.PageResult<UserTypes.SearchUserResult>>('/user/paging', data)
|
||||
},
|
||||
detail(id: string) {
|
||||
return get<UserTypes.SearchUserResult>('/sys_user/detail', {id})
|
||||
return get<UserTypes.SearchUserResult>('/user/detail', {id})
|
||||
},
|
||||
disable(id: string, disable: boolean) {
|
||||
return get('/user/disable', {id, disable})
|
||||
},
|
||||
add(data: UserTypes.AddUserParam) {
|
||||
return post('/sys_user/add', data)
|
||||
return post('/user/add', data)
|
||||
},
|
||||
bindRole(data: UserTypes.BindRoleParam) {
|
||||
return post('/user/bind_role', data)
|
||||
},
|
||||
modify(data: UserTypes.ModifyUserParam) {
|
||||
return post('/sys_user/modify', data)
|
||||
return post('/user/modify', data)
|
||||
},
|
||||
modifyInfo(data: { nickname?: string; avatar?: string; phone?: string }) {
|
||||
return post('/user/modify_info', data)
|
||||
},
|
||||
modifyPasswd(data: { oldPasswd: string; newPasswd: string }) {
|
||||
return post('/user/modify_passwd', data)
|
||||
},
|
||||
resetPasswd(id: string) {
|
||||
return get('/user/reset_passwd', {id})
|
||||
},
|
||||
del(ids: string[]) {
|
||||
return post('/sys_user/del', ids)
|
||||
return post('/user/del', ids)
|
||||
},
|
||||
clients(clientCode: number) {
|
||||
return Clients.filter(it => {
|
||||
const mask = 1 << it.val
|
||||
return (clientCode & mask) === 0
|
||||
})
|
||||
},
|
||||
bindClient(id: string, clients: number[]) {
|
||||
let clientCode = (1 << Clients.length) - 1
|
||||
for (let client of clients) {
|
||||
clientCode = (1 << client) ^ clientCode
|
||||
}
|
||||
return get('/user/bind_client', {id, clientCode})
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,33 @@ declare global {
|
|||
// 手机号
|
||||
phone?: string
|
||||
}
|
||||
|
||||
interface SearchUserAccountResult {
|
||||
// Id
|
||||
id?: string
|
||||
// 用户 Id
|
||||
userId?: string
|
||||
// 用户名
|
||||
username?: string
|
||||
// 手机号
|
||||
phone?: string
|
||||
// 密码
|
||||
secret?: string
|
||||
// 微信 openid
|
||||
wechatOpenid?: string
|
||||
// 微信 unionid
|
||||
wechatUnionid?: string
|
||||
// 注册时间
|
||||
regdate?: string
|
||||
// 允许登录的客户端
|
||||
clientCode?: number
|
||||
clients?: number[]
|
||||
// 是否禁用
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
interface SearchUserResult {
|
||||
id?: string
|
||||
// 昵称
|
||||
nickname?: string
|
||||
// 头像
|
||||
|
|
@ -20,7 +46,10 @@ declare global {
|
|||
email?: string
|
||||
// 手机号
|
||||
phone?: string
|
||||
|
||||
account: SearchUserAccountResult
|
||||
}
|
||||
|
||||
interface AddUserParam {
|
||||
// 昵称
|
||||
nickname?: string
|
||||
|
|
@ -31,6 +60,14 @@ declare global {
|
|||
// 手机号
|
||||
phone?: string
|
||||
}
|
||||
|
||||
interface BindRoleParam {
|
||||
// 昵称
|
||||
id?: string
|
||||
// 头像
|
||||
roles?: string[]
|
||||
}
|
||||
|
||||
interface ModifyUserParam {
|
||||
// 昵称
|
||||
nickname?: string
|
||||
|
|
|
|||
Loading…
Reference in New Issue