Introducing new features. 增加令牌管理功能

This commit is contained in:
aeizzz 2023-02-10 10:59:22 +08:00
parent 8b0bb1af7e
commit 9b4a2bc5d5
9 changed files with 203 additions and 18 deletions

16
src/api/admin/token.ts Normal file
View File

@ -0,0 +1,16 @@
import request from "/@/utils/request"
export function fetchList(query: object) {
return request({
url: '/admin/token/page',
method: 'post',
data: query
})
}
export function delObj(token:string) {
return request({
url: '/admin/token/' + token,
method: 'delete'
})
}

View File

@ -1,5 +1,5 @@
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import other from "../utils/other"; import other, { deepMerge } from "../utils/other";
export interface BasicTableProps { export interface BasicTableProps {
// 是否在创建页面时,调用数据列表接口 // 是否在创建页面时,调用数据列表接口
@ -22,6 +22,10 @@ export interface BasicTableProps {
loading?: Boolean loading?: Boolean
selectObjs?: any[] selectObjs?: any[]
descs?: string[]
ascs?: string[]
} }
export interface Pagination { export interface Pagination {
@ -54,7 +58,9 @@ export function useTable(options?: BasicTableProps) {
} as Pagination, } as Pagination,
dataListSelections: [], dataListSelections: [],
loading: false, loading: false,
selectObjs: [] selectObjs: [],
descs: [],
ascs: []
} }
const mergeDefaultOptions = (options: any, props: any): BasicTableProps => { const mergeDefaultOptions = (options: any, props: any): BasicTableProps => {
@ -67,7 +73,7 @@ export function useTable(options?: BasicTableProps) {
} }
// 覆盖默认值 // 覆盖默认值
const state = mergeDefaultOptions(defaultOptions, options) const state = mergeDefaultOptions(defaultOptions,options)
const query = () => { const query = () => {
@ -77,10 +83,12 @@ export function useTable(options?: BasicTableProps) {
...state.queryForm, ...state.queryForm,
current: state.pagination?.current, current: state.pagination?.current,
size: state.pagination?.size, size: state.pagination?.size,
}).then(res => { descs: state.descs,
ascs: state.ascs
}).then((res: any) => {
state.dataList = state.isPage ? res.data.records : res.data state.dataList = state.isPage ? res.data.records : res.data
state.pagination!.total = state.isPage ? res.data.total : 0 state.pagination!.total = state.isPage ? res.data.total : 0
}).catch(err => { }).catch((err: any) => {
ElMessage.error(err.data.msg) ElMessage.error(err.data.msg)
}).finally(() => { }).finally(() => {
state.loading = false; state.loading = false;
@ -110,12 +118,22 @@ export function useTable(options?: BasicTableProps) {
const sortChangeHandle = (column: any) => { const sortChangeHandle = (column: any) => {
const prop = other.toUnderline(column.prop); const prop = other.toUnderline(column.prop);
if (column.order === 'descending') { if (column.order === 'descending') {
state.queryForm!.descs.push(prop) state.descs?.push(prop)
state.queryForm!.ascs.splice(state.queryForm!.ascs.indexOf(prop), 1) if(state.ascs!.indexOf(prop) >=0){
} state.ascs?.splice(state.ascs.indexOf(prop), 1)
if (column.order === 'ascending') { }
state.queryForm!.ascs.push(prop) }else if (column.order === 'ascending') {
state.queryForm!.descs.splice(state.queryForm!.descs.indexOf(prop), 1) state.ascs?.push(prop)
if(state.descs!.indexOf(prop) >=0){
state.descs?.splice(state.descs.indexOf(prop), 1)
}
}else{
if(state.ascs!.indexOf(prop) >=0){
state.ascs?.splice(state.ascs.indexOf(prop), 1)
}
if(state.descs!.indexOf(prop) >=0){
state.descs?.splice(state.descs.indexOf(prop), 1)
}
} }
query(); query();
} }

View File

@ -10,6 +10,8 @@ import { Local } from '/@/utils/storage';
import { verifyUrl } from '/@/utils/toolsValidate'; import { verifyUrl } from '/@/utils/toolsValidate';
import request from "/@/utils/request"; import request from "/@/utils/request";
import { useMessage } from "/@/hooks/message"; import { useMessage } from "/@/hooks/message";
import { cloneDeep } from 'lodash-es';
import { isObject } from './is';
// @ts-ignore // @ts-ignore
import * as CryptoJS from "crypto-js"; import * as CryptoJS from "crypto-js";
@ -325,7 +327,7 @@ export function handleTree(data, id, parentId, children, rootId) {
} }
/** /**
* *
* @param str 线 * @param str 线
* @returns 线 * @returns 线
*/ */
@ -333,5 +335,6 @@ export function toUnderline(str: string) {
return str.replace(/([A-Z])/g, "_$1").toLowerCase() return str.replace(/([A-Z])/g, "_$1").toLowerCase()
} }
// 统一批量导出 // 统一批量导出
export default other; export default other;

View File

@ -37,14 +37,14 @@
<el-table :data="state.dataList" v-loading="state.loading" style="width: 100%"> <el-table :data="state.dataList" v-loading="state.loading" style="width: 100%">
<el-table-column type="index" label="序号" width="50" /> <el-table-column type="index" label="序号" width="50" />
<el-table-column prop="dictType" label="类型" show-overflow-tooltip></el-table-column> <el-table-column prop="dictType" label="类型" show-overflow-tooltip></el-table-column>
<el-table-column prop="description" label="描述" show-overflow-tooltip></el-table-column> <el-table-column prop="description" label="描述" show-overflow-tooltip sortable></el-table-column>
<el-table-column prop="systemFlag" label="字典类型" show-overflow-tooltip> <el-table-column prop="systemFlag" label="字典类型" show-overflow-tooltip>
<template #default="scope"> <template #default="scope">
<dict-tag :options="dict_type" :value="scope.row.systemFlag"></dict-tag> <dict-tag :options="dict_type" :value="scope.row.systemFlag"></dict-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="remarks" label="备注信息" show-overflow-tooltip></el-table-column> <el-table-column prop="remarks" label="备注信息" show-overflow-tooltip></el-table-column>
<el-table-column prop="createTime" label="创建时间" show-overflow-tooltip></el-table-column> <el-table-column prop="createTime" label="创建时间" show-overflow-tooltip sortable></el-table-column>
<el-table-column label="操作" width="200"> <el-table-column label="操作" width="200">
<template #default="scope"> <template #default="scope">

View File

@ -90,9 +90,7 @@ const multiple = ref(true);
const state: BasicTableProps = reactive<BasicTableProps>({ const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: { queryForm: {
logType: '', logType: '',
createTime: '', createTime: ''
descs: ['create_time'],
ascs: [],
}, },
selectObjs: [], selectObjs: [],
pageList: pageList pageList: pageList

View File

@ -0,0 +1,11 @@
export default {
systoken: {
index: 'index',
userId: 'userId',
username: 'username',
clientId: 'clientId',
accessToken: 'accessToken',
expiresAt: 'expiresAt',
inputUsernameTip: 'input Username'
}
}

View File

@ -0,0 +1,12 @@
export default {
systoken: {
index: '序号',
userId: '用户ID',
username: '用户名',
clientId: '客户端',
accessToken: '令牌',
expiresAt: '过期时间',
inputUsernameTip: '请输入用户名'
},
}

View File

@ -0,0 +1,120 @@
<template>
<div class="layout-padding">
<el-card class="layout-padding-auto" shadow="hover">
<el-row v-show="showSearch" class="mb8">
<el-form :model="state.queryForm" ref="queryRef" :inline="true">
<el-form-item :label="$t('systoken.username')" prop="username">
<el-input v-model="state.queryForm.username" :placeholder="$t('systoken.inputUsernameTip')"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="getDataList">{{ $t('common.queryBtn') }}</el-button>
<el-button icon="Refresh" @click="resetQuery">{{ $t('common.resetBtn') }}</el-button>
</el-form-item>
</el-form>
</el-row>
<el-row>
<div class="mb8" style="width: 100%">
<el-button size="default" :disabled="multiple" icon="Delete" type="primary" class="ml10"
v-auth="'sys_user_del'" @click="handleDelete(undefined)">
{{ $t('common.delBtn') }}
</el-button>
<right-toolbar v-model:showSearch="showSearch" class="ml10" style="float: right;margin-right: 20px"
@queryTable="getDataList"></right-toolbar>
</div>
</el-row>
<el-table v-loading="state.loading" :data="state.dataList" style="width: 100%"
@selection-change="handleSelectionChange" @sort-change="sortChangeHandle">
<el-table-column align="center" type="selection" width="50" />
<el-table-column :label="$t('systoken.index')" type="index" width="80" />
<el-table-column :label="$t('systoken.userId')" prop="userId" show-overflow-tooltip></el-table-column>
<el-table-column :label="$t('systoken.username')" prop="username" show-overflow-tooltip></el-table-column>
<el-table-column :label="$t('systoken.clientId')" prop="clientId" show-overflow-tooltip></el-table-column>
<el-table-column :label="$t('systoken.accessToken')" prop="accessToken" show-overflow-tooltip></el-table-column>
<el-table-column :label="$t('systoken.expiresAt')" prop="expiresAt" show-overflow-tooltip></el-table-column>
<el-table-column :label="$t('common.action')" width="100">
<template #default="scope">
<el-button v-auth="'sys_user_del'" size="small" text type="primary" @click="handleDelete(scope.row)">
{{ $t('common.delBtn') }}
</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-bind="state.pagination" @size-change="sizeChangeHandle" @current-change="currentChangeHandle">
</pagination>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { BasicTableProps, useTable } from "/@/hooks/table";
import { fetchList,delObj } from "/@/api/admin/token";
import { useI18n } from 'vue-i18n'
import { useMessage, useMessageBox } from "/@/hooks/message";
const { t } = useI18n()
//
const queryRef = ref();
const showSearch = ref(true)
// rows
const selectObjs = ref([]);
//
const multiple = ref(true);
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {
username: ''
},
pageList: fetchList
});
// table hook
const {
getDataList,
currentChangeHandle,
sortChangeHandle,
sizeChangeHandle
} = useTable(state)
//
const resetQuery = () => {
queryRef.value.resetFields()
getDataList()
}
//
const handleSelectionChange = (val: any) => {
selectObjs.value = val
multiple.value = !val.length
}
//
const handleDelete = (row: any) => {
if (!row) {
selectObjs.value.forEach(val => {
handleDelete(val)
});
return
}
useMessageBox().confirm(`${t('common.delConfirmText')}${row.username} ?`).then(() => {
//
delObj(row.accessToken).then(() => {
getDataList();
useMessage().success(t('common.delSuccessText'))
}).catch(err => {
useMessage().error(err.msg)
})
})
};
</script>
<style scoped>
</style>

View File

@ -132,7 +132,14 @@ const popoverVis = (bol: boolean) => {
const popoverVisible = ref(false) const popoverVisible = ref(false)
// //
const dataRules = ref({}) const dataRules = reactive({
jobName: [{ required: true, message: '任务名称不能为空', trigger: 'blur' }],
jobGroup: [{ required: true, message: '任务组名不能为空', trigger: 'blur' }],
jobType: [{ required: true, message: '任务类型不能为空', trigger: 'blur' }],
cronExpression: [{ required: true, message: 'cron不能为空', trigger: 'blur' }],
misfirePolicy: [{ required: true, message: '策略不能为空', trigger: 'blur' }],
})
// //
const openDialog = (id: string) => { const openDialog = (id: string) => {