mirror of
https://gitee.com/bootx/dax-pay-ui.git
synced 2025-10-17 15:34:04 +00:00
feat 用户操作
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
ref="formRef"
|
ref="formRef"
|
||||||
:model="form"
|
:model="form"
|
||||||
:rules="rules"
|
:rules="rules"
|
||||||
|
validate-trigger="['blur', 'change']"
|
||||||
:label-col="labelCol"
|
:label-col="labelCol"
|
||||||
:wrapper-col="wrapperCol"
|
:wrapper-col="wrapperCol"
|
||||||
>
|
>
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
ref="formRef"
|
ref="formRef"
|
||||||
:model="form"
|
:model="form"
|
||||||
:rules="rules"
|
:rules="rules"
|
||||||
|
validate-trigger="['blur', 'change']"
|
||||||
:label-col="labelCol"
|
:label-col="labelCol"
|
||||||
:wrapper-col="wrapperCol"
|
:wrapper-col="wrapperCol"
|
||||||
>
|
>
|
||||||
|
60
src/views/baseapi/log/login/LoginLog.api.ts
Normal file
60
src/views/baseapi/log/login/LoginLog.api.ts
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import { defHttp } from '@/utils/http/axios'
|
||||||
|
import { PageResult, Result } from '#/axios'
|
||||||
|
import { BaseEntity } from '#/web'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页
|
||||||
|
*/
|
||||||
|
export const page = (params) => {
|
||||||
|
return defHttp.get<Result<PageResult<LoginLog>>>({
|
||||||
|
url: '/log/login/page',
|
||||||
|
params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取单条
|
||||||
|
*/
|
||||||
|
export const get = (id) => {
|
||||||
|
return defHttp.get<Result<LoginLog>>({
|
||||||
|
url: '/log/login/findById',
|
||||||
|
params: { id },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 清除指定天数之前的日志
|
||||||
|
*/
|
||||||
|
export const deleteByDay = (deleteDay) => {
|
||||||
|
return defHttp.delete<Result>({
|
||||||
|
url: '/log/login/deleteByDay',
|
||||||
|
params: { deleteDay },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登陆日志
|
||||||
|
*/
|
||||||
|
export interface LoginLog extends BaseEntity {
|
||||||
|
// 用户id
|
||||||
|
userId: number
|
||||||
|
// 用户名称
|
||||||
|
account: string
|
||||||
|
// 登录成功状态
|
||||||
|
login: boolean
|
||||||
|
// 终端
|
||||||
|
client: string
|
||||||
|
// 登录方式
|
||||||
|
loginType: string
|
||||||
|
// 登录IP地址
|
||||||
|
ip: string
|
||||||
|
// 登录地点
|
||||||
|
loginLocation: string
|
||||||
|
// 操作系统
|
||||||
|
os: string
|
||||||
|
// 浏览器类型
|
||||||
|
browser: string
|
||||||
|
// 提示消息
|
||||||
|
msg: string
|
||||||
|
// 访问时间
|
||||||
|
loginTime: string
|
||||||
|
}
|
68
src/views/baseapi/log/login/LoginLogInfo.vue
Normal file
68
src/views/baseapi/log/login/LoginLogInfo.vue
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<template>
|
||||||
|
<basic-modal
|
||||||
|
v-bind="$attrs"
|
||||||
|
:loading="confirmLoading"
|
||||||
|
width="50%"
|
||||||
|
title="查看"
|
||||||
|
:open="visible"
|
||||||
|
@cancel="visible = false"
|
||||||
|
>
|
||||||
|
<description :column="2" :data="data" :schema="schema" />
|
||||||
|
<template #footer>
|
||||||
|
<a-button key="cancel" @click="visible = false">取消</a-button>
|
||||||
|
</template>
|
||||||
|
</basic-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { Description, DescItem } from '@/components/Description'
|
||||||
|
import { get, LoginLog } from './LoginLog.api'
|
||||||
|
|
||||||
|
import BasicModal from '@/components/Modal/src/BasicModal.vue'
|
||||||
|
import { findOneByField } from '@/utils/dataUtil'
|
||||||
|
import { Client, findAll } from '@/views/iam/client/Client.api'
|
||||||
|
import { onMounted, ref } from 'vue'
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initClients()
|
||||||
|
})
|
||||||
|
|
||||||
|
let clients = ref<Client[]>([])
|
||||||
|
let data = ref<LoginLog>()
|
||||||
|
let visible = ref(false)
|
||||||
|
let confirmLoading = ref(false)
|
||||||
|
let schema = [
|
||||||
|
{ field: 'account', label: '登录账号' },
|
||||||
|
{ field: 'login', label: '登录成功状态', render: (curVal) => (curVal ? '成功' : '失败') },
|
||||||
|
{ field: 'client', label: '登录终端', render: (curVal) => getClient(curVal) },
|
||||||
|
{ field: 'ip', label: '登录IP地址' },
|
||||||
|
{ field: 'browser', label: '浏览器类型' },
|
||||||
|
{ field: 'os', label: '操作系统' },
|
||||||
|
{ field: 'msg', label: '提示消息' },
|
||||||
|
{ field: 'loginTime', label: '访问时间' },
|
||||||
|
] as DescItem[]
|
||||||
|
|
||||||
|
function show(id) {
|
||||||
|
visible.value = true
|
||||||
|
confirmLoading.value = true
|
||||||
|
get(id).then((res) => {
|
||||||
|
data.value = res.data
|
||||||
|
confirmLoading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function initClients() {
|
||||||
|
const { data } = await findAll()
|
||||||
|
clients.value = data
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取终端信息
|
||||||
|
function getClient(code) {
|
||||||
|
return findOneByField(clients.value, code, 'code')?.['name']
|
||||||
|
}
|
||||||
|
defineExpose({
|
||||||
|
show,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
185
src/views/baseapi/log/login/LoginLogList.vue
Normal file
185
src/views/baseapi/log/login/LoginLogList.vue
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="m-3 p-3 pt-5 bg-white">
|
||||||
|
<b-query
|
||||||
|
:query-params="model.queryParam"
|
||||||
|
:fields="fields"
|
||||||
|
@query="queryPage"
|
||||||
|
@reset="resetQueryParams"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="m-3 p-3 bg-white">
|
||||||
|
<vxe-toolbar ref="xToolbar" custom :refresh="{ queryMethod: queryPage }">
|
||||||
|
<template #buttons>
|
||||||
|
<a-space>
|
||||||
|
<a-select
|
||||||
|
style="width: 180px"
|
||||||
|
v-model:value="deleteDay"
|
||||||
|
:options="deleteDays"
|
||||||
|
allow-clear
|
||||||
|
placeholder="清除多久前的日志"
|
||||||
|
/>
|
||||||
|
<a-button v-if="deleteDay" @click="deleteLogs" type="primary">清理</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</vxe-toolbar>
|
||||||
|
<vxe-table row-id="id" ref="xTable" :data="pagination.records" :loading="loading">
|
||||||
|
<vxe-column type="seq" width="60" />
|
||||||
|
<vxe-column field="userId" title="用户id" />
|
||||||
|
<vxe-column field="account" title="用户名称" />
|
||||||
|
<vxe-column field="login" title="登录成功状态">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<a-tag v-if="row.login" color="green">成功</a-tag>
|
||||||
|
<a-tag v-else color="red">失败</a-tag>
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
|
<vxe-column field="client" title="终端">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ getClient(row.client) }}
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
|
<vxe-column field="ip" title="登录IP地址" />
|
||||||
|
<vxe-column field="os" title="操作系统" />
|
||||||
|
<vxe-column field="browser" title="浏览器类型" />
|
||||||
|
<vxe-column field="msg" title="提示消息" />
|
||||||
|
<vxe-column field="loginTime" title="访问时间" />
|
||||||
|
<vxe-column fixed="right" width="60" :showOverflow="false" title="操作">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span>
|
||||||
|
<a href="javascript:" @click="show(row)">查看</a>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
|
</vxe-table>
|
||||||
|
<vxe-pager
|
||||||
|
size="medium"
|
||||||
|
:loading="loading"
|
||||||
|
:current-page="pagination.current"
|
||||||
|
:page-size="pagination.size"
|
||||||
|
:total="pagination.total"
|
||||||
|
@page-change="handleTableChange"
|
||||||
|
/>
|
||||||
|
<LoginLogInfo :clients="clients" :login-types="loginTypes" ref="loginLogInfo" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, onMounted, ref } from 'vue'
|
||||||
|
import { deleteByDay, page } from './LoginLog.api'
|
||||||
|
import useTablePage from '@/hooks/bootx/useTablePage'
|
||||||
|
import { VxeTableInstance, VxeToolbarInstance } from 'vxe-table'
|
||||||
|
import BQuery from '/@/components/Bootx/Query/BQuery.vue'
|
||||||
|
import { useMessage } from '@/hooks/web/useMessage'
|
||||||
|
import { QueryField } from '@/components/Bootx/Query/Query'
|
||||||
|
import { Client, findAll as findClients } from '@/views/iam/client/Client.api'
|
||||||
|
import { dropdownTranslate, findOneByField } from '@/utils/dataUtil'
|
||||||
|
import LoginLogInfo from './LoginLogInfo.vue'
|
||||||
|
import { LabeledValue } from 'ant-design-vue/lib/select'
|
||||||
|
|
||||||
|
// 使用hooks
|
||||||
|
const {
|
||||||
|
handleTableChange,
|
||||||
|
pageQueryResHandel,
|
||||||
|
resetQueryParams,
|
||||||
|
pagination,
|
||||||
|
pages,
|
||||||
|
model,
|
||||||
|
loading,
|
||||||
|
} = useTablePage(queryPage)
|
||||||
|
const { notification, createMessage, createConfirm } = useMessage()
|
||||||
|
|
||||||
|
let clients = ref<Client[]>()
|
||||||
|
const deleteDay = ref<number | undefined>(undefined)
|
||||||
|
|
||||||
|
const xTable = ref<VxeTableInstance>()
|
||||||
|
const xToolbar = ref<VxeToolbarInstance>()
|
||||||
|
const loginLogInfo = ref<any>()
|
||||||
|
|
||||||
|
// 删除条件
|
||||||
|
let deleteDays = ref<LabeledValue[]>([
|
||||||
|
{ label: '3天之前', value: '3' },
|
||||||
|
{ label: '7天之前', value: '7' },
|
||||||
|
{ label: '30天之前', value: '30' },
|
||||||
|
{ label: '60天之前', value: '60' },
|
||||||
|
{ label: '90天之前', value: '90' },
|
||||||
|
{ label: '180天之前', value: '180' },
|
||||||
|
{ label: '365天之前', value: '365' },
|
||||||
|
])
|
||||||
|
// 查询条件
|
||||||
|
const fields = computed(() => {
|
||||||
|
return [
|
||||||
|
{ field: 'code', type: 'string', name: '账号', placeholder: '请输入账号名称' },
|
||||||
|
{
|
||||||
|
field: 'client',
|
||||||
|
type: 'list',
|
||||||
|
name: '终端',
|
||||||
|
placeholder: '请选择终端',
|
||||||
|
selectList: dropdownTranslate(clients, 'name', 'code'),
|
||||||
|
},
|
||||||
|
] as QueryField[]
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
vxeBind()
|
||||||
|
initClientAndLoginType()
|
||||||
|
queryPage()
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化 终端列表和登录方式列表
|
||||||
|
*/
|
||||||
|
function initClientAndLoginType() {
|
||||||
|
findClients().then(({ data }) => {
|
||||||
|
clients.value = data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function vxeBind() {
|
||||||
|
xTable.value?.connect(xToolbar.value as VxeToolbarInstance)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询
|
||||||
|
*/
|
||||||
|
function queryPage() {
|
||||||
|
loading.value = true
|
||||||
|
page({
|
||||||
|
...model.queryParam,
|
||||||
|
...pages,
|
||||||
|
}).then(({ data }) => {
|
||||||
|
pageQueryResHandel(data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 查看
|
||||||
|
*/
|
||||||
|
function show(record) {
|
||||||
|
loginLogInfo.value.show(record.id)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取终端信息
|
||||||
|
*/
|
||||||
|
function getClient(code) {
|
||||||
|
return findOneByField(clients, code, 'code')?.['name']
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 清理日志
|
||||||
|
*/
|
||||||
|
function deleteLogs() {
|
||||||
|
createConfirm({
|
||||||
|
iconType: 'warning',
|
||||||
|
title: '警告',
|
||||||
|
content: '是否清除指定日期前的日志,该操作不可撤回',
|
||||||
|
onOk: async () => {
|
||||||
|
createMessage.info('清理日志中...')
|
||||||
|
deleteByDay(deleteDay).then(() => {
|
||||||
|
createMessage.success('清理日志成功')
|
||||||
|
queryPage()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped></style>
|
67
src/views/baseapi/log/operate/OperateLog.api.ts
Normal file
67
src/views/baseapi/log/operate/OperateLog.api.ts
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import { defHttp } from '@/utils/http/axios'
|
||||||
|
import { PageResult, Result } from '#/axios'
|
||||||
|
import { BaseEntity } from '#/web'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页
|
||||||
|
*/
|
||||||
|
export const page = (params) => {
|
||||||
|
return defHttp.get<Result<PageResult<OperateLog>>>({
|
||||||
|
url: '/log/operate/page',
|
||||||
|
params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取单条
|
||||||
|
*/
|
||||||
|
export const get = (id) => {
|
||||||
|
return defHttp.get<Result<OperateLog>>({
|
||||||
|
url: '/log/operate/findById',
|
||||||
|
params: { id },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除指定天数之前的日志
|
||||||
|
*/
|
||||||
|
export const deleteByDay = (deleteDay) => {
|
||||||
|
return defHttp.delete<Result>({
|
||||||
|
url: '/log/operate/deleteByDay',
|
||||||
|
params: { deleteDay },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作日志
|
||||||
|
*/
|
||||||
|
export interface OperateLog extends BaseEntity {
|
||||||
|
// 操作模块
|
||||||
|
title?: string
|
||||||
|
// 操作人员id
|
||||||
|
operateId?: number
|
||||||
|
// 操作人员账号
|
||||||
|
username?: string
|
||||||
|
// 业务类型
|
||||||
|
businessType?: string
|
||||||
|
// 请求方法
|
||||||
|
method?: string
|
||||||
|
// 请求方式
|
||||||
|
requestMethod?: string
|
||||||
|
// 请求url
|
||||||
|
operateUrl?: string
|
||||||
|
// 操作ip
|
||||||
|
operateIp?: string
|
||||||
|
// 操作地点
|
||||||
|
operateLocation?: string
|
||||||
|
// 请求参数
|
||||||
|
operateParam?: string
|
||||||
|
// 返回参数
|
||||||
|
operateReturn?: string
|
||||||
|
// 是否成功
|
||||||
|
success?: boolean
|
||||||
|
// 错误提示
|
||||||
|
errorMsg?: string
|
||||||
|
// 操作时间
|
||||||
|
operateTime?: string
|
||||||
|
}
|
64
src/views/baseapi/log/operate/OperateLogInfo.vue
Normal file
64
src/views/baseapi/log/operate/OperateLogInfo.vue
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<template>
|
||||||
|
<basic-modal
|
||||||
|
v-bind="$attrs"
|
||||||
|
:loading="confirmLoading"
|
||||||
|
width="50%"
|
||||||
|
title="查看"
|
||||||
|
:open="visible"
|
||||||
|
@cancel="visible = false"
|
||||||
|
>
|
||||||
|
<description :column="2" :data="data" :schema="schema" />
|
||||||
|
<template #footer>
|
||||||
|
<a-space>
|
||||||
|
<a-button key="cancel" @click="visible = false">取消</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</basic-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { get, OperateLog } from './OperateLog.api'
|
||||||
|
import { BasicModal } from '@/components/Modal'
|
||||||
|
import { DescItem, Description } from '@/components/Description'
|
||||||
|
import { useDict } from '@/hooks/bootx/useDict'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
const { dictConvert } = useDict()
|
||||||
|
|
||||||
|
let data = ref<OperateLog>({})
|
||||||
|
let visible = ref(false)
|
||||||
|
let confirmLoading = ref(false)
|
||||||
|
let schema = [
|
||||||
|
{ field: 'id', label: '主键' },
|
||||||
|
{ field: 'username', label: '操作人员账号' },
|
||||||
|
{ field: 'title', label: '操作模块' },
|
||||||
|
{
|
||||||
|
field: 'client',
|
||||||
|
label: '业务类型',
|
||||||
|
render: (businessType) => dictConvert('LogBusinessType', businessType),
|
||||||
|
},
|
||||||
|
{ field: 'requestMethod', label: '请求方式' },
|
||||||
|
{ field: 'operateUrl', label: '请求url' },
|
||||||
|
{ field: 'method', label: '操作方法' },
|
||||||
|
{ field: 'success', label: '操作状态', render: (success) => (success ? '成功' : '失败') },
|
||||||
|
{ field: 'errorMsg', label: '提示消息' },
|
||||||
|
{ field: 'operateParam', label: '请求参数' },
|
||||||
|
{ field: 'operateReturn', label: '响应参数' },
|
||||||
|
{ field: 'operateTime', label: '操作时间' },
|
||||||
|
] as DescItem[]
|
||||||
|
|
||||||
|
function show(id) {
|
||||||
|
visible.value = true
|
||||||
|
confirmLoading.value = true
|
||||||
|
get(id).then((res) => {
|
||||||
|
data.value = res.data
|
||||||
|
confirmLoading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
show,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped></style>
|
158
src/views/baseapi/log/operate/OperateLogList.vue
Normal file
158
src/views/baseapi/log/operate/OperateLogList.vue
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="m-3 p-3 pt-5 bg-white">
|
||||||
|
<b-query
|
||||||
|
:query-params="model.queryParam"
|
||||||
|
:fields="fields"
|
||||||
|
@query="queryPage"
|
||||||
|
@reset="resetQueryParams"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="m-3 p-3 bg-white">
|
||||||
|
<vxe-toolbar ref="xToolbar" custom :refresh="{ queryMethod: queryPage }">
|
||||||
|
<template #buttons>
|
||||||
|
<a-space>
|
||||||
|
<a-select
|
||||||
|
style="width: 180px"
|
||||||
|
v-model:value="deleteDay"
|
||||||
|
:options="deleteDays"
|
||||||
|
allow-clear
|
||||||
|
placeholder="清除多久前的日志"
|
||||||
|
/>
|
||||||
|
<a-button v-if="deleteDay" @click="deleteLogs" type="primary">清理</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</vxe-toolbar>
|
||||||
|
<vxe-table row-id="id" ref="xTable" :data="pagination.records" :loading="loading">
|
||||||
|
<vxe-column type="seq" width="60" />
|
||||||
|
<vxe-column field="operateId" title="操作人员id" />
|
||||||
|
<vxe-column field="username" title="操作人员账号" />
|
||||||
|
<vxe-column field="title" title="操作模块" />
|
||||||
|
<vxe-column field="success" title="是否成功">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<a-tag v-if="row.success" color="green">成功</a-tag>
|
||||||
|
<a-tag v-else color="red">失败</a-tag>
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
|
<vxe-column field="businessType" title="业务类型">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ dictConvert('LogBusinessType', row.businessType) }}
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
|
<vxe-column field="operateIp" title="操作ip" />
|
||||||
|
<vxe-column field="errorMsg" title="错误提示" />
|
||||||
|
<vxe-column field="operateTime" title="操作时间" />
|
||||||
|
<vxe-column fixed="right" width="60" :showOverflow="false" title="操作">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span>
|
||||||
|
<a href="javascript:" @click="show(row)">查看</a>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
|
</vxe-table>
|
||||||
|
<vxe-pager
|
||||||
|
size="medium"
|
||||||
|
:loading="loading"
|
||||||
|
:current-page="pagination.current"
|
||||||
|
:page-size="pagination.size"
|
||||||
|
:total="pagination.total"
|
||||||
|
@page-change="handleTableChange"
|
||||||
|
/>
|
||||||
|
<OperateLogEdit ref="operateLogEdit" @ok="queryPage" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, ref } from 'vue'
|
||||||
|
import { page, deleteByDay } from './OperateLog.api'
|
||||||
|
import useTablePage from '@/hooks/bootx/useTablePage'
|
||||||
|
import OperateLogEdit from './OperateLogInfo.vue'
|
||||||
|
import { VxeTableInstance, VxeToolbarInstance } from 'vxe-table'
|
||||||
|
import BQuery from '/@/components/Bootx/Query/BQuery.vue'
|
||||||
|
import { useMessage } from '@/hooks/web/useMessage'
|
||||||
|
import { QueryField } from '@/components/Bootx/Query/Query'
|
||||||
|
import { useDict } from '@/hooks/bootx/useDict'
|
||||||
|
import { LabeledValue } from 'ant-design-vue/lib/select'
|
||||||
|
|
||||||
|
// 使用hooks
|
||||||
|
const {
|
||||||
|
handleTableChange,
|
||||||
|
pageQueryResHandel,
|
||||||
|
resetQueryParams,
|
||||||
|
pagination,
|
||||||
|
pages,
|
||||||
|
model,
|
||||||
|
loading,
|
||||||
|
} = useTablePage(queryPage)
|
||||||
|
const { createMessage, createConfirm } = useMessage()
|
||||||
|
const { dictConvert } = useDict()
|
||||||
|
|
||||||
|
const deleteDay = ref<any>(undefined)
|
||||||
|
// 删除条件
|
||||||
|
let deleteDays = ref<LabeledValue[]>([
|
||||||
|
{ label: '3天之前', value: '3' },
|
||||||
|
{ label: '7天之前', value: '7' },
|
||||||
|
{ label: '30天之前', value: '30' },
|
||||||
|
{ label: '60天之前', value: '60' },
|
||||||
|
{ label: '90天之前', value: '90' },
|
||||||
|
{ label: '180天之前', value: '180' },
|
||||||
|
{ label: '365天之前', value: '365' },
|
||||||
|
])
|
||||||
|
// 查询条件
|
||||||
|
const fields = [
|
||||||
|
{ field: 'title', type: 'string', name: '操作模块', placeholder: '请输入操作模块' },
|
||||||
|
{ field: 'username', type: 'string', name: '账号', placeholder: '请输入账号名称' },
|
||||||
|
] as QueryField[]
|
||||||
|
|
||||||
|
const xTable = ref<VxeTableInstance>()
|
||||||
|
const xToolbar = ref<VxeToolbarInstance>()
|
||||||
|
const operateLogEdit = ref<any>()
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
vxeBind()
|
||||||
|
queryPage()
|
||||||
|
})
|
||||||
|
function vxeBind() {
|
||||||
|
xTable.value?.connect(xToolbar.value as VxeToolbarInstance)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询
|
||||||
|
*/
|
||||||
|
function queryPage() {
|
||||||
|
loading.value = true
|
||||||
|
page({
|
||||||
|
...model.queryParam,
|
||||||
|
...pages,
|
||||||
|
}).then(({ data }) => {
|
||||||
|
pageQueryResHandel(data)
|
||||||
|
})
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 查看
|
||||||
|
*/
|
||||||
|
function show(record) {
|
||||||
|
operateLogEdit.value.show(record.id)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 清理日志
|
||||||
|
*/
|
||||||
|
function deleteLogs() {
|
||||||
|
createConfirm({
|
||||||
|
iconType: 'warning',
|
||||||
|
title: '警告',
|
||||||
|
content: '是否清除指定日期前的日志,该操作不可撤回',
|
||||||
|
onOk: async () => {
|
||||||
|
createMessage.info('清理日志中...')
|
||||||
|
deleteByDay(deleteDay).then(() => {
|
||||||
|
createMessage.success('清理日志成功')
|
||||||
|
queryPage()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped></style>
|
@@ -13,6 +13,7 @@
|
|||||||
ref="formRef"
|
ref="formRef"
|
||||||
:model="form"
|
:model="form"
|
||||||
:rules="rules"
|
:rules="rules"
|
||||||
|
validate-trigger="['blur', 'change']"
|
||||||
:label-col="labelCol"
|
:label-col="labelCol"
|
||||||
:wrapper-col="wrapperCol"
|
:wrapper-col="wrapperCol"
|
||||||
>
|
>
|
||||||
|
@@ -56,7 +56,7 @@ export const del = (id) => {
|
|||||||
* 查询全部
|
* 查询全部
|
||||||
*/
|
*/
|
||||||
export const findAll = () => {
|
export const findAll = () => {
|
||||||
return defHttp.get<Result<Array<Client>>>({
|
return defHttp.get<Result<Client[]>>({
|
||||||
url: '/client/findAll',
|
url: '/client/findAll',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@@ -21,7 +21,11 @@
|
|||||||
<a-input v-model:value="form.id" :disabled="showable" />
|
<a-input v-model:value="form.id" :disabled="showable" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="编码" validate-first name="code">
|
<a-form-item label="编码" validate-first name="code">
|
||||||
<a-input v-model:value="form.code" :disabled="showable" placeholder="请输入编码" />
|
<a-input
|
||||||
|
v-model:value="form.code"
|
||||||
|
:disabled="showable || form.internal"
|
||||||
|
placeholder="请输入编码"
|
||||||
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="名称" validate-first name="name">
|
<a-form-item label="名称" validate-first name="name">
|
||||||
<a-input v-model:value="form.name" :disabled="showable" placeholder="请输入名称" />
|
<a-input v-model:value="form.name" :disabled="showable" placeholder="请输入名称" />
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
class="small-from-item"
|
class="small-from-item"
|
||||||
ref="formRef"
|
ref="formRef"
|
||||||
:model="form"
|
:model="form"
|
||||||
|
validate-trigger="['blur', 'change']"
|
||||||
:rules="rules"
|
:rules="rules"
|
||||||
:label-col="labelCol"
|
:label-col="labelCol"
|
||||||
:wrapper-col="wrapperCol"
|
:wrapper-col="wrapperCol"
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
ref="formRef"
|
ref="formRef"
|
||||||
class="small-from-item"
|
class="small-from-item"
|
||||||
:model="form"
|
:model="form"
|
||||||
|
validate-trigger="['blur', 'change']"
|
||||||
:rules="rules"
|
:rules="rules"
|
||||||
:labelCol="labelCol"
|
:labelCol="labelCol"
|
||||||
:wrapperCol="wrapperCol"
|
:wrapperCol="wrapperCol"
|
||||||
|
@@ -99,7 +99,7 @@ export interface Role extends BaseEntity {
|
|||||||
// 编码
|
// 编码
|
||||||
code?: string
|
code?: string
|
||||||
// 父ID
|
// 父ID
|
||||||
pid?: number
|
pid?: string
|
||||||
// 名称
|
// 名称
|
||||||
name?: string
|
name?: string
|
||||||
// 是否系统内置
|
// 是否系统内置
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
:checkable="true"
|
:checkable="true"
|
||||||
v-model:checkedKeys="checkedKeys"
|
v-model:checkedKeys="checkedKeys"
|
||||||
v-model:expandedKeys="expandedKeys"
|
v-model:expandedKeys="expandedKeys"
|
||||||
:auto-expand-parent="autoExpandParent"
|
:auto-expand-parent="true"
|
||||||
:tree-data="treeData"
|
:tree-data="treeData"
|
||||||
@check="onCheck"
|
@check="onCheck"
|
||||||
@expand="onExpand"
|
@expand="onExpand"
|
||||||
@@ -81,7 +81,6 @@
|
|||||||
let expandedKeys = ref<string[]>([])
|
let expandedKeys = ref<string[]>([])
|
||||||
// 被选中的key
|
// 被选中的key
|
||||||
let checkedKeys = ref<string[]>([])
|
let checkedKeys = ref<string[]>([])
|
||||||
let autoExpandParent = ref(false)
|
|
||||||
//权限码树信息
|
//权限码树信息
|
||||||
let treeData = ref<Tree[]>([])
|
let treeData = ref<Tree[]>([])
|
||||||
let treeList = ref<PermCodeTree[]>([])
|
let treeList = ref<PermCodeTree[]>([])
|
||||||
@@ -182,7 +181,7 @@
|
|||||||
expandedKeys.value = treeList.value
|
expandedKeys.value = treeList.value
|
||||||
.map((node) => {
|
.map((node) => {
|
||||||
if (
|
if (
|
||||||
searchName &&
|
searchName.value &&
|
||||||
node.pid &&
|
node.pid &&
|
||||||
XEUtils.toValueString(node.name)?.toLowerCase()?.indexOf(value) > -1
|
XEUtils.toValueString(node.name)?.toLowerCase()?.indexOf(value) > -1
|
||||||
) {
|
) {
|
||||||
@@ -219,7 +218,6 @@
|
|||||||
*/
|
*/
|
||||||
function onExpand(keys) {
|
function onExpand(keys) {
|
||||||
expandedKeys.value = keys
|
expandedKeys.value = keys
|
||||||
autoExpandParent.value = false
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 点击复选框触发
|
* 点击复选框触发
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
class="small-from-item"
|
class="small-from-item"
|
||||||
:model="form"
|
:model="form"
|
||||||
ref="formRef"
|
ref="formRef"
|
||||||
|
validate-trigger="['blur', 'change']"
|
||||||
:rules="rules"
|
:rules="rules"
|
||||||
:label-col="labelCol"
|
:label-col="labelCol"
|
||||||
:wrapper-col="wrapperCol"
|
:wrapper-col="wrapperCol"
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
v-model:checkedKeys="checkedKeys"
|
v-model:checkedKeys="checkedKeys"
|
||||||
v-model:expandedKeys="expandedKeys"
|
v-model:expandedKeys="expandedKeys"
|
||||||
:checkStrictly="checkStrictly"
|
:checkStrictly="checkStrictly"
|
||||||
:auto-expand-parent="autoExpandParent"
|
:auto-expand-parent="false"
|
||||||
:tree-data="treeData"
|
:tree-data="treeData"
|
||||||
@check="onCheck"
|
@check="onCheck"
|
||||||
@expand="onExpand"
|
@expand="onExpand"
|
||||||
@@ -94,7 +94,6 @@
|
|||||||
let expandedKeys = ref<string[]>([])
|
let expandedKeys = ref<string[]>([])
|
||||||
// 被选中的key
|
// 被选中的key
|
||||||
let checkedKeys = ref<string[]>([])
|
let checkedKeys = ref<string[]>([])
|
||||||
let autoExpandParent = ref(false)
|
|
||||||
//菜单树信息
|
//菜单树信息
|
||||||
let treeData = ref<Tree[]>([])
|
let treeData = ref<Tree[]>([])
|
||||||
let treeList = ref<MenuTree[]>([])
|
let treeList = ref<MenuTree[]>([])
|
||||||
@@ -208,7 +207,7 @@
|
|||||||
expandedKeys.value = treeList.value
|
expandedKeys.value = treeList.value
|
||||||
.map((node) => {
|
.map((node) => {
|
||||||
if (
|
if (
|
||||||
searchName &&
|
searchName.value &&
|
||||||
node.pid &&
|
node.pid &&
|
||||||
XEUtils.toValueString(node.title).toLowerCase().indexOf(value) > -1
|
XEUtils.toValueString(node.title).toLowerCase().indexOf(value) > -1
|
||||||
) {
|
) {
|
||||||
@@ -245,7 +244,6 @@
|
|||||||
*/
|
*/
|
||||||
function onExpand(keys) {
|
function onExpand(keys) {
|
||||||
expandedKeys.value = keys
|
expandedKeys.value = keys
|
||||||
autoExpandParent.value = false
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 点击复选框触发
|
* 点击复选框触发
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
:checkable="true"
|
:checkable="true"
|
||||||
v-model:checkedKeys="checkedKeys"
|
v-model:checkedKeys="checkedKeys"
|
||||||
v-model:expandedKeys="expandedKeys"
|
v-model:expandedKeys="expandedKeys"
|
||||||
:auto-expand-parent="autoExpandParent"
|
:auto-expand-parent="true"
|
||||||
:tree-data="treeData"
|
:tree-data="treeData"
|
||||||
@check="onCheck"
|
@check="onCheck"
|
||||||
@expand="onExpand"
|
@expand="onExpand"
|
||||||
@@ -91,7 +91,6 @@
|
|||||||
let expandedKeys = ref<string[]>([])
|
let expandedKeys = ref<string[]>([])
|
||||||
// 被选中的key
|
// 被选中的key
|
||||||
let checkedKeys = ref<string[]>([])
|
let checkedKeys = ref<string[]>([])
|
||||||
let autoExpandParent = ref(false)
|
|
||||||
//请求路径树信息
|
//请求路径树信息
|
||||||
let treeData = ref<Tree[]>([])
|
let treeData = ref<Tree[]>([])
|
||||||
let treeList = ref<PermPathTree[]>([])
|
let treeList = ref<PermPathTree[]>([])
|
||||||
@@ -205,7 +204,7 @@
|
|||||||
expandedKeys.value = treeList.value
|
expandedKeys.value = treeList.value
|
||||||
.map((node) => {
|
.map((node) => {
|
||||||
if (
|
if (
|
||||||
searchName &&
|
searchName.value &&
|
||||||
node.pid &&
|
node.pid &&
|
||||||
XEUtils.toValueString(node.title).toLowerCase().indexOf(value) > -1
|
XEUtils.toValueString(node.title).toLowerCase().indexOf(value) > -1
|
||||||
) {
|
) {
|
||||||
@@ -213,7 +212,6 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.filter((item, i, self) => item && self.indexOf(item) === i) as string[]
|
.filter((item, i, self) => item && self.indexOf(item) === i) as string[]
|
||||||
console.log(expandedKeys.value)
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 渲染搜索项目数据开始段
|
* 渲染搜索项目数据开始段
|
||||||
@@ -243,8 +241,6 @@
|
|||||||
*/
|
*/
|
||||||
function onExpand(keys) {
|
function onExpand(keys) {
|
||||||
expandedKeys.value = keys
|
expandedKeys.value = keys
|
||||||
console.log(expandedKeys)
|
|
||||||
autoExpandParent.value = false
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 点击复选框触发
|
* 点击复选框触发
|
||||||
|
@@ -56,7 +56,7 @@ export function findAll() {
|
|||||||
export function restartPassword(userId, newPassword) {
|
export function restartPassword(userId, newPassword) {
|
||||||
return defHttp.post({
|
return defHttp.post({
|
||||||
url: '/user/admin/restartPassword',
|
url: '/user/admin/restartPassword',
|
||||||
params: { userId, newPassword },
|
data: { userId, newPassword },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,8 +66,7 @@ export function restartPassword(userId, newPassword) {
|
|||||||
export function restartPasswordBatch(userIds, newPassword) {
|
export function restartPasswordBatch(userIds, newPassword) {
|
||||||
return defHttp.post({
|
return defHttp.post({
|
||||||
url: '/user/admin/restartPasswordBatch',
|
url: '/user/admin/restartPasswordBatch',
|
||||||
data: userIds,
|
data: { userIds, newPassword },
|
||||||
params: { newPassword },
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,20 +5,20 @@ import { Role } from '@/views/iam/role/Role.api'
|
|||||||
/**
|
/**
|
||||||
* 获取用户拥有角色id集合
|
* 获取用户拥有角色id集合
|
||||||
*/
|
*/
|
||||||
export function getRoleIds(id) {
|
export function getRoleIds(userId) {
|
||||||
return defHttp.get<Result<string[]>>({
|
return defHttp.get<Result<string[]>>({
|
||||||
url: `/user/role/findRoleIdsByUser`,
|
url: `/user/role/findRoleIdsByUser`,
|
||||||
params: { id },
|
params: { userId },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户拥有角色集合
|
* 获取用户拥有角色集合
|
||||||
*/
|
*/
|
||||||
export function getRoles(id) {
|
export function getRoles(userId) {
|
||||||
return defHttp.get<Result<Role[]>>({
|
return defHttp.get<Result<Role[]>>({
|
||||||
url: `/user/role/findRolesByUser`,
|
url: `/user/role/findRolesByUser`,
|
||||||
params: { id },
|
params: { userId },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,12 +22,12 @@
|
|||||||
<a-menu-item>
|
<a-menu-item>
|
||||||
<a @click="assignRolesBatch()">角色分配</a>
|
<a @click="assignRolesBatch()">角色分配</a>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item>
|
<!-- <a-menu-item>-->
|
||||||
<a @click="lockUserConfirmBatch(true)">锁定账号</a>
|
<!-- <a @click="lockUserConfirmBatch(true)">锁定账号</a>-->
|
||||||
</a-menu-item>
|
<!-- </a-menu-item>-->
|
||||||
<a-menu-item>
|
<!-- <a-menu-item>-->
|
||||||
<a @click="lockUserConfirmBatch(false)">解锁账号</a>
|
<!-- <a @click="lockUserConfirmBatch(false)">解锁账号</a>-->
|
||||||
</a-menu-item>
|
<!-- </a-menu-item>-->
|
||||||
<a-menu-item>
|
<a-menu-item>
|
||||||
<a @click="resetPwdBatch()">重置密码</a>
|
<a @click="resetPwdBatch()">重置密码</a>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
@@ -74,12 +74,6 @@
|
|||||||
<a-menu-item>
|
<a-menu-item>
|
||||||
<a-link @click="assignRoles(row)">角色分配</a-link>
|
<a-link @click="assignRoles(row)">角色分配</a-link>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item>
|
|
||||||
<a-link @click="assignDept(row)">部门分配</a-link>
|
|
||||||
</a-menu-item>
|
|
||||||
<a-menu-item>
|
|
||||||
<a-link @click="assignDataScope(row)">数据角色分配</a-link>
|
|
||||||
</a-menu-item>
|
|
||||||
<a-menu-item>
|
<a-menu-item>
|
||||||
<a-link @click="resetPwd(row)">重置密码</a-link>
|
<a-link @click="resetPwd(row)">重置密码</a-link>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
@@ -108,6 +102,8 @@
|
|||||||
<UserAdd ref="userAdd" @ok="queryPage" />
|
<UserAdd ref="userAdd" @ok="queryPage" />
|
||||||
<UserEdit ref="userEdit" @ok="queryPage" />
|
<UserEdit ref="userEdit" @ok="queryPage" />
|
||||||
<UserShow ref="userShow" />
|
<UserShow ref="userShow" />
|
||||||
|
<UserRoleAssign ref="userRoleAssign" />
|
||||||
|
<UserResetPwd ref="userResetPwd" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -125,7 +121,9 @@
|
|||||||
import UserAdd from './UserAdd.vue'
|
import UserAdd from './UserAdd.vue'
|
||||||
import UserEdit from './UserEdit.vue'
|
import UserEdit from './UserEdit.vue'
|
||||||
import UserShow from './UserShow.vue'
|
import UserShow from './UserShow.vue'
|
||||||
import ALink from "@/components/Link/Link.vue";
|
import UserResetPwd from './UserResetPwd.vue'
|
||||||
|
import UserRoleAssign from './role/UserRoleAssign.vue'
|
||||||
|
import ALink from '@/components/Link/Link.vue'
|
||||||
|
|
||||||
// 使用hooks
|
// 使用hooks
|
||||||
const {
|
const {
|
||||||
@@ -152,13 +150,11 @@
|
|||||||
let userEdit = ref<any>()
|
let userEdit = ref<any>()
|
||||||
let userShow = ref<any>()
|
let userShow = ref<any>()
|
||||||
let userRoleAssign = ref<any>()
|
let userRoleAssign = ref<any>()
|
||||||
let userRoleAssignBatch = ref<any>()
|
|
||||||
let userDataScopeAssign = ref<any>()
|
let userDataScopeAssign = ref<any>()
|
||||||
let userDataScopeAssignBatch = ref<any>()
|
let userDataScopeAssignBatch = ref<any>()
|
||||||
let userDeptAssign = ref<any>()
|
let userDeptAssign = ref<any>()
|
||||||
let userDeptAssignBatch = ref<any>()
|
let userDeptAssignBatch = ref<any>()
|
||||||
let userResetPwd = ref<any>()
|
let userResetPwd = ref<any>()
|
||||||
let userResetPwdBatch = ref<any>()
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
vxeBind()
|
vxeBind()
|
||||||
@@ -235,30 +231,12 @@
|
|||||||
}
|
}
|
||||||
// 分配角色
|
// 分配角色
|
||||||
function assignRoles(record) {
|
function assignRoles(record) {
|
||||||
userRoleAssign.value.init(record)
|
userRoleAssign.value.init(false, record.id)
|
||||||
}
|
}
|
||||||
// 批量分配角色
|
// 批量分配角色
|
||||||
function assignRolesBatch() {
|
function assignRolesBatch() {
|
||||||
const userIds = xTable.value?.getCheckboxRecords().map((o) => o.id)
|
const userIds = xTable.value?.getCheckboxRecords().map((o) => o.id)
|
||||||
userRoleAssignBatch.value.init(userIds)
|
userRoleAssign.value.init(true, userIds)
|
||||||
}
|
|
||||||
// 分配数据权限
|
|
||||||
function assignDataScope(record) {
|
|
||||||
userDataScopeAssign.value.init(record)
|
|
||||||
}
|
|
||||||
// 批量分配数据权限
|
|
||||||
function assignDataScopeBatch() {
|
|
||||||
const userIds = xTable.value?.getCheckboxRecords().map((o) => o.id)
|
|
||||||
userDataScopeAssignBatch.value.init(userIds)
|
|
||||||
}
|
|
||||||
// 分配部门
|
|
||||||
function assignDept(record) {
|
|
||||||
userDeptAssign.value.init(record.id)
|
|
||||||
}
|
|
||||||
// 批量分配部门
|
|
||||||
function assignDeptBatch() {
|
|
||||||
const userIds = xTable.value?.getCheckboxRecords().map((o) => o.id)
|
|
||||||
userDeptAssignBatch.value.init(userIds)
|
|
||||||
}
|
}
|
||||||
function add() {
|
function add() {
|
||||||
userAdd.value.init()
|
userAdd.value.init()
|
||||||
@@ -279,14 +257,14 @@
|
|||||||
* 重置密码
|
* 重置密码
|
||||||
*/
|
*/
|
||||||
function resetPwd(record) {
|
function resetPwd(record) {
|
||||||
userResetPwd.value.init(record.id)
|
userResetPwd.value.init(false, record.id)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 重置密码
|
* 重置密码
|
||||||
*/
|
*/
|
||||||
function resetPwdBatch() {
|
function resetPwdBatch() {
|
||||||
const userIds = xTable.value?.getCheckboxRecords().map((o) => o.id)
|
const userIds = xTable.value?.getCheckboxRecords().map((o) => o.id)
|
||||||
userResetPwdBatch.value.init(userIds)
|
userResetPwd.value.init(true,userIds)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
87
src/views/iam/user/UserResetPwd.vue
Normal file
87
src/views/iam/user/UserResetPwd.vue
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<template>
|
||||||
|
<basic-modal
|
||||||
|
v-bind="$attrs"
|
||||||
|
title="重置密码"
|
||||||
|
:width="modalWidth"
|
||||||
|
:open="visible"
|
||||||
|
:confirmLoading="confirmLoading"
|
||||||
|
:maskClosable="false"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
@ok="handleOk"
|
||||||
|
>
|
||||||
|
<a-spin :spinning="confirmLoading">
|
||||||
|
<a-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="form"
|
||||||
|
:rules="rules"
|
||||||
|
:validate-trigger="['blur', 'change']"
|
||||||
|
:label-col="labelCol"
|
||||||
|
:wrapper-col="wrapperCol"
|
||||||
|
>
|
||||||
|
<a-form-item name="newPassword" label="重置密码">
|
||||||
|
<a-input-password v-model:value="form.newPassword" placeholder="请输入密码" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-spin>
|
||||||
|
</basic-modal>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import BasicModal from '@/components/Modal/src/BasicModal.vue'
|
||||||
|
import useFormEdit from '@/hooks/bootx/useFormEdit'
|
||||||
|
import { restartPassword, restartPasswordBatch } from './User.api'
|
||||||
|
import { useMessage } from '@/hooks/web/useMessage'
|
||||||
|
import { Rule } from 'ant-design-vue/lib/form'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
const { handleCancel, labelCol, wrapperCol, modalWidth, confirmLoading, visible } = useFormEdit()
|
||||||
|
const { createConfirm, createMessage } = useMessage()
|
||||||
|
|
||||||
|
// 用户id
|
||||||
|
const userId = ref('')
|
||||||
|
// 用户ids
|
||||||
|
const userIds = ref<string[]>([])
|
||||||
|
|
||||||
|
const batch = ref(false)
|
||||||
|
let form = ref<any>({
|
||||||
|
newPassword: '',
|
||||||
|
})
|
||||||
|
let formRef = ref<any>()
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
newPassword: [{ required: true, message: '重置密码不得为空' }],
|
||||||
|
} as Record<string, Rule[]>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化
|
||||||
|
*/
|
||||||
|
function init(batch: boolean, userIdOrIds: string | string[]) {
|
||||||
|
visible.value = true
|
||||||
|
if (!batch) {
|
||||||
|
userId.value = userIdOrIds as string
|
||||||
|
} else {
|
||||||
|
userIds.value = userIdOrIds as never[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleOk() {
|
||||||
|
formRef.value?.validate().then(async () => {
|
||||||
|
createConfirm({
|
||||||
|
iconType: 'info',
|
||||||
|
title: '警告',
|
||||||
|
content: '是否重置用户的密码',
|
||||||
|
onOk: async () => {
|
||||||
|
confirmLoading.value = true
|
||||||
|
if (batch.value) {
|
||||||
|
await restartPasswordBatch(userIds.value, form.value.newPassword)
|
||||||
|
} else {
|
||||||
|
await restartPassword(userId.value, form.value.newPassword)
|
||||||
|
}
|
||||||
|
createMessage.success('保存成功')
|
||||||
|
handleCancel()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
defineExpose({ init })
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less"></style>
|
269
src/views/iam/user/role/UserRoleAssign.vue
Normal file
269
src/views/iam/user/role/UserRoleAssign.vue
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
<template>
|
||||||
|
<basic-drawer
|
||||||
|
showFooter
|
||||||
|
v-bind="$attrs"
|
||||||
|
:title="modal.title"
|
||||||
|
width="40%"
|
||||||
|
:open="modal.visible"
|
||||||
|
@close="handleCancel"
|
||||||
|
>
|
||||||
|
<a-spin :spinning="modal.loading">
|
||||||
|
<a-input
|
||||||
|
style="margin-bottom: 8px"
|
||||||
|
placeholder="筛选"
|
||||||
|
allowClear
|
||||||
|
v-model:value="modal.searchName"
|
||||||
|
@change="search"
|
||||||
|
/>
|
||||||
|
<a-tree
|
||||||
|
:checkable="true"
|
||||||
|
:checkStrictly="true"
|
||||||
|
v-model:checkedKeys="modal.checkedKeys"
|
||||||
|
v-model:expandedKeys="modal.expandedKeys"
|
||||||
|
:auto-expand-parent="true"
|
||||||
|
:tree-data="modal.treeData"
|
||||||
|
@check="onCheck"
|
||||||
|
@expand="onExpand"
|
||||||
|
>
|
||||||
|
<template #title="{ title }">
|
||||||
|
<span v-if="title?.toLowerCase()?.indexOf(modal.searchName.toLowerCase()) > -1">
|
||||||
|
{{ searchRenderStart(title, modal.searchName) }}
|
||||||
|
<span style="color: #f50">
|
||||||
|
{{ searchRenderMiddle(title, modal.searchName) }}
|
||||||
|
</span>
|
||||||
|
{{ searchRenderEnd(title, modal.searchName) }}
|
||||||
|
</span>
|
||||||
|
<span v-else>{{ title }}</span>
|
||||||
|
</template>
|
||||||
|
</a-tree>
|
||||||
|
</a-spin>
|
||||||
|
<template #footer>
|
||||||
|
<a-dropdown style="margin-left: 5px" :trigger="['click']" placement="top">
|
||||||
|
<template #overlay>
|
||||||
|
<a-menu>
|
||||||
|
<a-menu-item key="1" @click="checkALL">全部勾选</a-menu-item>
|
||||||
|
<a-menu-item key="2" @click="cancelCheckALL">取消全选</a-menu-item>
|
||||||
|
<a-menu-item key="3" @click="expandAll">展开所有</a-menu-item>
|
||||||
|
<a-menu-item key="4" @click="closeAll">合并所有</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
</template>
|
||||||
|
<a-button post-icon="ant-design:up-outlined"> 操作 </a-button>
|
||||||
|
</a-dropdown>
|
||||||
|
<a-button @click="modal.visible = false" style="margin-right: 0.8rem">取消</a-button>
|
||||||
|
<a-button
|
||||||
|
@click="handleSubmit()"
|
||||||
|
type="primary"
|
||||||
|
:loading="modal.loading"
|
||||||
|
style="margin-right: 0.8rem"
|
||||||
|
>保存</a-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</basic-drawer>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { BasicDrawer } from '@/components/Drawer'
|
||||||
|
import { reactive } from 'vue'
|
||||||
|
import { Tree, treeDataTranslate } from '@/utils/dataUtil'
|
||||||
|
import XEUtils from 'xe-utils'
|
||||||
|
import { RoleTree, tree as roleTree } from '@/views/iam/role/Role.api'
|
||||||
|
import { addUserRole, addUserRoleBatch, getRoleIds } from '@/views/iam/user/UserAssign.api'
|
||||||
|
import { useMessage } from '@/hooks/web/useMessage'
|
||||||
|
|
||||||
|
const { createConfirm, createMessage } = useMessage()
|
||||||
|
const modal = reactive({
|
||||||
|
title: '角色分配',
|
||||||
|
visible: false,
|
||||||
|
batch: false,
|
||||||
|
loading: false,
|
||||||
|
searchName: '',
|
||||||
|
// 所有的key
|
||||||
|
allTreeKeys: [] as string[],
|
||||||
|
// 展开的key
|
||||||
|
expandedKeys: [] as string[],
|
||||||
|
// 被选中的key
|
||||||
|
checkedKeys: [] as string[],
|
||||||
|
// 后台获取的角色树
|
||||||
|
treeData: [] as Tree[],
|
||||||
|
// 转换后的树数据
|
||||||
|
treeList: [] as RoleTree[],
|
||||||
|
// 用户id
|
||||||
|
userId: '',
|
||||||
|
// 用户ids
|
||||||
|
userIds: [],
|
||||||
|
// 角色Ids
|
||||||
|
roleIds: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化
|
||||||
|
*/
|
||||||
|
async function init(batch: boolean, userIdOrIds: string | string[]) {
|
||||||
|
modal.visible = true
|
||||||
|
modal.batch = batch
|
||||||
|
modal.loading = true
|
||||||
|
// 初始化角色树
|
||||||
|
await initRoles()
|
||||||
|
if (!batch) {
|
||||||
|
modal.userId = userIdOrIds as string
|
||||||
|
// 初始化分配角色
|
||||||
|
await initAssign()
|
||||||
|
} else {
|
||||||
|
modal.userIds = userIdOrIds as never[]
|
||||||
|
}
|
||||||
|
modal.loading = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化菜单
|
||||||
|
*/
|
||||||
|
async function initRoles() {
|
||||||
|
modal.searchName = ''
|
||||||
|
modal.expandedKeys = []
|
||||||
|
// 角色树
|
||||||
|
await roleTree().then((res) => {
|
||||||
|
modal.treeData = treeDataTranslate(res.data, 'id', 'name')
|
||||||
|
generateTreeList(res.data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化权限码分配信息
|
||||||
|
*/
|
||||||
|
async function initAssign() {
|
||||||
|
// 当前用户已经选择的角色Id
|
||||||
|
await getRoleIds(modal.userId).then((res) => {
|
||||||
|
modal.checkedKeys = res.data
|
||||||
|
})
|
||||||
|
// 选中的的key值
|
||||||
|
modal.allTreeKeys = modal.treeList.map((item) => item.id) as string[]
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 保存
|
||||||
|
*/
|
||||||
|
function handleSubmit() {
|
||||||
|
createConfirm({
|
||||||
|
iconType: 'info',
|
||||||
|
title: '警告',
|
||||||
|
content: '是否要保存角色分配信息',
|
||||||
|
onOk: async () => {
|
||||||
|
modal.loading = true
|
||||||
|
if (modal.batch) {
|
||||||
|
await addUserRoleBatch({
|
||||||
|
userIds: modal.userIds,
|
||||||
|
roleIds: modal.checkedKeys,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
await addUserRole({
|
||||||
|
userId: modal.userId,
|
||||||
|
roleIds: modal.checkedKeys,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
createMessage.success('保存成功')
|
||||||
|
modal.loading = false
|
||||||
|
modal.visible = false
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消
|
||||||
|
*/
|
||||||
|
function handleCancel() {
|
||||||
|
modal.visible = false
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 树数据铺平
|
||||||
|
*/
|
||||||
|
function generateTreeList(treeData) {
|
||||||
|
if (!treeData) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for (let i = 0; i < treeData.length; i++) {
|
||||||
|
const node = treeData[i]
|
||||||
|
modal.treeList.push(node)
|
||||||
|
if (node.children) {
|
||||||
|
generateTreeList(node.children)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 搜索
|
||||||
|
*/
|
||||||
|
function search() {
|
||||||
|
const value = XEUtils.toValueString(modal.searchName).toLowerCase()
|
||||||
|
modal.expandedKeys = modal.treeList
|
||||||
|
.map((node) => {
|
||||||
|
if (
|
||||||
|
modal.searchName &&
|
||||||
|
node.pid &&
|
||||||
|
XEUtils.toValueString(node.name)?.toLowerCase()?.indexOf(value) > -1
|
||||||
|
) {
|
||||||
|
return node.pid
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter((item, i, self) => item && self.indexOf(item) === i) as string[]
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 渲染搜索项目数据开始段
|
||||||
|
*/
|
||||||
|
function searchRenderStart(title, searchName) {
|
||||||
|
return title.substring(0, title.toLowerCase().indexOf(searchName.toLowerCase()))
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 渲染搜索项目数据中间段
|
||||||
|
*/
|
||||||
|
function searchRenderMiddle(title, searchName) {
|
||||||
|
return title.substring(
|
||||||
|
title.toLowerCase().indexOf(searchName.toLowerCase()),
|
||||||
|
title.toLowerCase().indexOf(searchName.toLowerCase()) + searchName.length,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 渲染搜索项目数据结束段
|
||||||
|
*/
|
||||||
|
function searchRenderEnd(title, searchName) {
|
||||||
|
return title.substring(
|
||||||
|
title.toLowerCase().indexOf(searchName.toLowerCase()) + searchName.length,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 展开/收起节点时触发
|
||||||
|
*/
|
||||||
|
function onExpand(keys) {
|
||||||
|
modal.expandedKeys = keys
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 点击复选框触发
|
||||||
|
*/
|
||||||
|
function onCheck(key) {
|
||||||
|
modal.checkedKeys = key.checked
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 展开全部
|
||||||
|
*/
|
||||||
|
function expandAll() {
|
||||||
|
modal.expandedKeys = modal.allTreeKeys
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 合并全部
|
||||||
|
*/
|
||||||
|
function closeAll() {
|
||||||
|
modal.expandedKeys = []
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 全选
|
||||||
|
*/
|
||||||
|
function checkALL() {
|
||||||
|
modal.checkedKeys = modal.allTreeKeys
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 全不选
|
||||||
|
*/
|
||||||
|
function cancelCheckALL() {
|
||||||
|
modal.checkedKeys = []
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ init })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less"></style>
|
Reference in New Issue
Block a user