mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 16:00:25 +08:00
refactor: 前端代码优化
This commit is contained in:
25
mayfly_go_web/src/components/auth/auth.ts
Normal file
25
mayfly_go_web/src/components/auth/auth.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { useUserInfo } from '@/store/userInfo';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断当前用户是否拥有指定权限
|
||||||
|
* @param code 权限code
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function hasPerm(code: string) {
|
||||||
|
return useUserInfo().userInfo.permissions.some((v: any) => v === code);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断用户是否拥有权限对象里对应的code
|
||||||
|
* @param perms { save: "xxx:save"}
|
||||||
|
* @returns {"xxx:save": true} key->permission code
|
||||||
|
*/
|
||||||
|
export function hasPerms(permCodes: any[]) {
|
||||||
|
const res = {};
|
||||||
|
for (let permCode of permCodes) {
|
||||||
|
if (hasPerm(permCode)) {
|
||||||
|
res[permCode] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
@@ -86,13 +86,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-table v-bind="$attrs" max-height="700" @selection-change="handleSelectionChange" :data="props.data" border
|
<el-table v-bind="$attrs" max-height="700" @selection-change="handleSelectionChange" :data="props.data" border
|
||||||
highlight-current-row show-overflow-tooltip v-loading="loadingData">
|
highlight-current-row v-loading="loadingData">
|
||||||
|
|
||||||
<el-table-column v-if="props.showSelection" type="selection" width="40" />
|
<el-table-column v-if="props.showSelection" type="selection" width="40" />
|
||||||
|
|
||||||
<template v-for="(item, index) in columns">
|
<template v-for="(item, index) in columns">
|
||||||
<el-table-column :key="index" v-if="item.show" :prop="item.prop" :label="item.label" :fixed="item.fixed"
|
<el-table-column :key="index" v-if="item.show" :prop="item.prop" :label="item.label" :fixed="item.fixed"
|
||||||
:align="item.align" :show-overflow-tooltip="item.showOverflowTooltip || true"
|
:align="item.align" :show-overflow-tooltip="item.showOverflowTooltip"
|
||||||
:min-width="item.minWidth" :sortable="item.sortable || false" :type="item.type" :width="item.width">
|
:min-width="item.minWidth" :sortable="item.sortable || false" :type="item.type" :width="item.width">
|
||||||
|
|
||||||
<!-- 插槽:预留功能 -->
|
<!-- 插槽:预留功能 -->
|
||||||
|
|||||||
@@ -77,6 +77,11 @@ export class TableColumn {
|
|||||||
return new TableColumn(prop, label)
|
return new TableColumn(prop, label)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
noShowOverflowTooltip(): TableColumn {
|
||||||
|
this.showOverflowTooltip = false
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
setMinWidth(minWidth: number | string): TableColumn {
|
setMinWidth(minWidth: number | string): TableColumn {
|
||||||
this.minWidth = minWidth
|
this.minWidth = minWidth
|
||||||
this.autoWidth = false;
|
this.autoWidth = false;
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import type { App } from 'vue';
|
import type { App } from 'vue';
|
||||||
import { useUserInfo } from '@/store/userInfo';
|
import { useUserInfo } from '@/store/userInfo';
|
||||||
import { judementSameArr } from '@/common/utils/arrayOperation';
|
import { judementSameArr } from '@/common/utils/arrayOperation';
|
||||||
|
import { hasPerm } from '@/components/auth/auth';
|
||||||
|
|
||||||
// 用户权限指令
|
// 用户权限指令
|
||||||
export function authDirective(app: App) {
|
export function authDirective(app: App) {
|
||||||
// 单个权限验证(v-auth="xxx")
|
// 单个权限验证(v-auth="xxx")
|
||||||
app.directive('auth', {
|
app.directive('auth', {
|
||||||
mounted(el, binding) {
|
mounted(el, binding) {
|
||||||
if (!useUserInfo().userInfo.permissions.some((v: any) => v === binding.value)) {
|
if (!hasPerm(binding.value)) {
|
||||||
parseNoAuth(el, binding);
|
parseNoAuth(el, binding);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="db-list">
|
<div class="db-list">
|
||||||
<page-table ref="pageTableRef" :query="state.queryConfig" v-model:query-form="query" :show-selection="true"
|
<page-table ref="pageTableRef" :query="queryConfig" v-model:query-form="query" :show-selection="true"
|
||||||
v-model:selection-data="state.selectionData" :data="datas" :columns="state.columns" :total="total"
|
v-model:selection-data="state.selectionData" :data="datas" :columns="columns" :total="total"
|
||||||
v-model:page-size="query.pageSize" v-model:page-num="query.pageNum" @pageChange="search()">
|
v-model:page-size="query.pageSize" v-model:page-num="query.pageNum" @pageChange="search()">
|
||||||
|
|
||||||
<template #tagPathSelect>
|
<template #tagPathSelect>
|
||||||
@@ -12,8 +12,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #queryRight>
|
<template #queryRight>
|
||||||
<el-button v-auth="permissions.saveDb" type="primary" icon="plus" @click="editDb(true)">添加</el-button>
|
<el-button v-auth="perms.saveDb" type="primary" icon="plus" @click="editDb(true)">添加</el-button>
|
||||||
<el-button v-auth="permissions.delDb" :disabled="selectionData.length < 1" @click="deleteDb()" type="danger"
|
<el-button v-auth="perms.delDb" :disabled="selectionData.length < 1" @click="deleteDb()" type="danger"
|
||||||
icon="delete">删除</el-button>
|
icon="delete">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #action="{ data }">
|
<template #action="{ data }">
|
||||||
<el-button v-auth="permissions.saveDb" @click="editDb(data)" type="primary" link>编辑</el-button>
|
<el-button v-if="actionBtns[perms.saveDb]" @click="editDb(data)" type="primary" link>编辑</el-button>
|
||||||
</template>
|
</template>
|
||||||
</page-table>
|
</page-table>
|
||||||
|
|
||||||
@@ -277,15 +277,35 @@ import { dateFormat } from '@/common/utils/date';
|
|||||||
import TagInfo from '../component/TagInfo.vue';
|
import TagInfo from '../component/TagInfo.vue';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue'
|
import PageTable from '@/components/pagetable/PageTable.vue'
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn, TableQuery } from '@/components/pagetable';
|
||||||
|
import { hasPerms } from '@/components/auth/auth';
|
||||||
|
|
||||||
const DbEdit = defineAsyncComponent(() => import('./DbEdit.vue'));
|
const DbEdit = defineAsyncComponent(() => import('./DbEdit.vue'));
|
||||||
const CreateTable = defineAsyncComponent(() => import('./CreateTable.vue'));
|
const CreateTable = defineAsyncComponent(() => import('./CreateTable.vue'));
|
||||||
|
|
||||||
const permissions = {
|
const perms = {
|
||||||
saveDb: 'db:save',
|
saveDb: 'db:save',
|
||||||
delDb: 'db:del',
|
delDb: 'db:del',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const queryConfig = [
|
||||||
|
TableQuery.slot("tagPath", "标签", "tagPathSelect"),
|
||||||
|
]
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
TableColumn.new("tagPath", "标签路径").isSlot().setAddWidth(20),
|
||||||
|
TableColumn.new("name", "名称"),
|
||||||
|
TableColumn.new("host", "host:port").setFormatFunc((data: any, _prop: string) => `${data.host}:${data.port}`),
|
||||||
|
TableColumn.new("type", "类型"),
|
||||||
|
TableColumn.new("database", "数据库").isSlot().setMinWidth(70),
|
||||||
|
TableColumn.new("username", "用户名"),
|
||||||
|
TableColumn.new("remark", "备注"),
|
||||||
|
TableColumn.new("more", "更多").isSlot().setMinWidth(165).fixedRight(),
|
||||||
|
]
|
||||||
|
|
||||||
|
// 该用户拥有的的操作列按钮权限
|
||||||
|
const actionBtns = hasPerms([perms.saveDb,])
|
||||||
|
const actionColumn = TableColumn.new("action", "操作").isSlot().setMinWidth(65).fixedRight();
|
||||||
|
|
||||||
const pageTableRef: any = ref(null)
|
const pageTableRef: any = ref(null)
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
@@ -305,20 +325,6 @@ const state = reactive({
|
|||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
},
|
},
|
||||||
queryConfig: [
|
|
||||||
TableQuery.slot("tagPath", "标签", "tagPathSelect"),
|
|
||||||
],
|
|
||||||
columns: [
|
|
||||||
TableColumn.new("tagPath", "标签路径").isSlot().setAddWidth(20),
|
|
||||||
TableColumn.new("name", "名称"),
|
|
||||||
TableColumn.new("host", "host:port").setFormatFunc((data: any, _prop: string) => `${data.host}:${data.port}`),
|
|
||||||
TableColumn.new("type", "类型"),
|
|
||||||
TableColumn.new("database", "数据库").isSlot().setMinWidth(70),
|
|
||||||
TableColumn.new("username", "用户名"),
|
|
||||||
TableColumn.new("remark", "备注"),
|
|
||||||
TableColumn.new("more", "更多").isSlot().setMinWidth(165).fixedRight(),
|
|
||||||
TableColumn.new("action", "操作").isSlot().setMinWidth(65).fixedRight(),
|
|
||||||
],
|
|
||||||
datas: [],
|
datas: [],
|
||||||
total: 0,
|
total: 0,
|
||||||
infoDialog: {
|
infoDialog: {
|
||||||
@@ -422,6 +428,9 @@ const {
|
|||||||
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
if (Object.keys(actionBtns).length > 0) {
|
||||||
|
columns.push(actionColumn);
|
||||||
|
}
|
||||||
search();
|
search();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<page-table ref="pageTableRef" :query="state.queryConfig" v-model:query-form="params" :show-selection="true"
|
<page-table ref="pageTableRef" :query="queryConfig" v-model:query-form="params" :show-selection="true"
|
||||||
v-model:selection-data="state.selectionData" :data="data.list" :columns="state.columns" :total="data.total"
|
v-model:selection-data="state.selectionData" :data="data.list" :columns="columns" :total="data.total"
|
||||||
v-model:page-size="params.pageSize" v-model:page-num="params.pageNum" @pageChange="search()">
|
v-model:page-size="params.pageSize" v-model:page-num="params.pageNum" @pageChange="search()">
|
||||||
|
|
||||||
<template #tagPathSelect>
|
<template #tagPathSelect>
|
||||||
@@ -12,9 +12,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #queryRight>
|
<template #queryRight>
|
||||||
<el-button v-auth="'machine:add'" type="primary" icon="plus" @click="openFormDialog(false)" plain>添加
|
<el-button v-auth="perms.addMachine" type="primary" icon="plus" @click="openFormDialog(false)" plain>添加
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button v-auth="'machine:del'" :disabled="selectionData.length < 1" @click="deleteMachine()"
|
<el-button v-auth="perms.delMachine" :disabled="selectionData.length < 1" @click="deleteMachine()"
|
||||||
type="danger" icon="delete">删除</el-button>
|
type="danger" icon="delete">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
<el-button :disabled="data.status == -1" type="warning" @click="serviceManager(data)" link>脚本</el-button>
|
<el-button :disabled="data.status == -1" type="warning" @click="serviceManager(data)" link>脚本</el-button>
|
||||||
<el-divider direction="vertical" border-style="dashed" />
|
<el-divider direction="vertical" border-style="dashed" />
|
||||||
|
|
||||||
<el-dropdown>
|
<el-dropdown @command="handleCommand">
|
||||||
<span class="el-dropdown-link-machine-list">
|
<span class="el-dropdown-link-machine-list">
|
||||||
更多
|
更多
|
||||||
<el-icon class="el-icon--right">
|
<el-icon class="el-icon--right">
|
||||||
@@ -62,26 +62,26 @@
|
|||||||
</span>
|
</span>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item>
|
<el-dropdown-item :command="{ type: 'detail', data }">
|
||||||
<el-button @click="showInfo(data)" link>详情</el-button>
|
详情
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
|
|
||||||
<el-dropdown-item>
|
<el-dropdown-item :command="{ type: 'edit', data }" v-if="actionBtns[perms.updateMachine]">
|
||||||
<el-button v-auth="'machine:update'" @click="openFormDialog(data)" link>编辑</el-button>
|
编辑
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
|
|
||||||
<el-dropdown-item>
|
<el-dropdown-item :command="{ type: 'process', data }" :disabled="data.status == -1">
|
||||||
<el-button @click="showProcess(data)" :disabled="data.status == -1" link>进程</el-button>
|
进程
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
|
|
||||||
<el-dropdown-item v-if="data.enableRecorder == 1">
|
<el-dropdown-item :command="{ type: 'terminalRec', data }"
|
||||||
<el-button v-auth="'machine:update'" @click="showRec(data)" link>终端回放</el-button>
|
v-if="actionBtns[perms.updateMachine] && data.enableRecorder == 1">
|
||||||
|
终端回放
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
|
|
||||||
<el-dropdown-item>
|
<el-dropdown-item :command="{ type: 'closeCli', data }" v-if="actionBtns[perms.closeCli]"
|
||||||
<el-button v-auth="'machine:close-cli'" :disabled="!data.hasCli || data.status == -1"
|
:disabled="!data.hasCli || data.status == -1">
|
||||||
type="danger" @click="closeCli(data)" link>关闭连接
|
关闭连接
|
||||||
</el-button>
|
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</template>
|
</template>
|
||||||
@@ -152,6 +152,7 @@ import { dateFormat } from '@/common/utils/date';
|
|||||||
import TagInfo from '../component/TagInfo.vue';
|
import TagInfo from '../component/TagInfo.vue';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue'
|
import PageTable from '@/components/pagetable/PageTable.vue'
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn, TableQuery } from '@/components/pagetable';
|
||||||
|
import { hasPerms } from '@/components/auth/auth';
|
||||||
|
|
||||||
// 组件
|
// 组件
|
||||||
const MachineEdit = defineAsyncComponent(() => import('./MachineEdit.vue'));
|
const MachineEdit = defineAsyncComponent(() => import('./MachineEdit.vue'));
|
||||||
@@ -164,6 +165,32 @@ const ProcessList = defineAsyncComponent(() => import('./ProcessList.vue'));
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const pageTableRef: any = ref(null)
|
const pageTableRef: any = ref(null)
|
||||||
|
|
||||||
|
const perms = {
|
||||||
|
addMachine: "machine:add",
|
||||||
|
updateMachine: "machine:update",
|
||||||
|
delMachine: "machine:del",
|
||||||
|
terminal: "machine:terminal",
|
||||||
|
closeCli: "machine:close-cli",
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryConfig = [
|
||||||
|
TableQuery.slot("tagPath", "标签", "tagPathSelect"),
|
||||||
|
TableQuery.text("ip", "IP"),
|
||||||
|
TableQuery.text("name", "名称"),
|
||||||
|
]
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
TableColumn.new("tagPath", "标签路径").isSlot().setAddWidth(20),
|
||||||
|
TableColumn.new("name", "名称"),
|
||||||
|
TableColumn.new("ipPort", "ip:port").isSlot().setAddWidth(35),
|
||||||
|
TableColumn.new("username", "用户名"),
|
||||||
|
TableColumn.new("status", "状态").isSlot().setMinWidth(85),
|
||||||
|
TableColumn.new("remark", "备注"),
|
||||||
|
TableColumn.new("action", "操作").isSlot().setMinWidth(238).fixedRight(),
|
||||||
|
]
|
||||||
|
// 该用户拥有的的操作列按钮权限,使用v-if进行判断,v-auth对el-dropdown-item无效
|
||||||
|
const actionBtns = hasPerms([perms.updateMachine, perms.closeCli])
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
tags: [] as any,
|
tags: [] as any,
|
||||||
params: {
|
params: {
|
||||||
@@ -173,20 +200,6 @@ const state = reactive({
|
|||||||
name: null,
|
name: null,
|
||||||
tagPath: null,
|
tagPath: null,
|
||||||
},
|
},
|
||||||
queryConfig: [
|
|
||||||
TableQuery.slot("tagPath", "标签", "tagPathSelect"),
|
|
||||||
TableQuery.text("ip", "IP"),
|
|
||||||
TableQuery.text("name", "名称"),
|
|
||||||
],
|
|
||||||
columns: [
|
|
||||||
TableColumn.new("tagPath", "标签路径").isSlot().setAddWidth(20),
|
|
||||||
TableColumn.new("name", "名称"),
|
|
||||||
TableColumn.new("ipPort", "ip:port").isSlot().setAddWidth(35),
|
|
||||||
TableColumn.new("username", "用户名"),
|
|
||||||
TableColumn.new("status", "状态").isSlot().setMinWidth(85),
|
|
||||||
TableColumn.new("remark", "备注"),
|
|
||||||
TableColumn.new("action", "操作").isSlot().setMinWidth(235).fixedRight(),
|
|
||||||
],
|
|
||||||
// 列表数据
|
// 列表数据
|
||||||
data: {
|
data: {
|
||||||
list: [],
|
list: [],
|
||||||
@@ -248,6 +261,34 @@ onMounted(async () => {
|
|||||||
search();
|
search();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleCommand = (commond: any) => {
|
||||||
|
const data = commond.data;
|
||||||
|
const type = commond.type;
|
||||||
|
console.log(type);
|
||||||
|
switch (type) {
|
||||||
|
case "detail": {
|
||||||
|
showInfo(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case "edit": {
|
||||||
|
openFormDialog(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case "process": {
|
||||||
|
showProcess(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case "terminalRec": {
|
||||||
|
showRec(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case "closeCli": {
|
||||||
|
closeCli(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const showTerminal = (row: any) => {
|
const showTerminal = (row: any) => {
|
||||||
const { href } = router.resolve({
|
const { href } = router.resolve({
|
||||||
path: `/machine/terminal`,
|
path: `/machine/terminal`,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<page-table ref="pageTableRef" :query="state.queryConfig" v-model:query-form="query" :show-selection="true"
|
<page-table ref="pageTableRef" :query="queryConfig" v-model:query-form="query" :show-selection="true"
|
||||||
v-model:selection-data="selectionData" :data="list" :columns="state.columns" :total="total"
|
v-model:selection-data="selectionData" :data="list" :columns="columns" :total="total"
|
||||||
v-model:page-size="query.pageSize" v-model:page-num="query.pageNum" @pageChange="search()">
|
v-model:page-size="query.pageSize" v-model:page-num="query.pageNum" @pageChange="search()">
|
||||||
|
|
||||||
<template #tagPathSelect>
|
<template #tagPathSelect>
|
||||||
@@ -180,6 +180,18 @@ import { TableColumn, TableQuery } from '@/components/pagetable';
|
|||||||
|
|
||||||
const pageTableRef: any = ref(null)
|
const pageTableRef: any = ref(null)
|
||||||
|
|
||||||
|
const queryConfig = [
|
||||||
|
TableQuery.slot("tagPath", "标签", "tagPathSelect"),
|
||||||
|
]
|
||||||
|
const columns = [
|
||||||
|
TableColumn.new("tagPath", "标签路径").isSlot().setAddWidth(20),
|
||||||
|
TableColumn.new("name", "名称"),
|
||||||
|
TableColumn.new("uri", "连接uri"),
|
||||||
|
TableColumn.new("createTime", "创建时间").isTime(),
|
||||||
|
TableColumn.new("creator", "创建人"),
|
||||||
|
TableColumn.new("action", "操作").isSlot().setMinWidth(100).fixedRight(),
|
||||||
|
]
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
tags: [],
|
tags: [],
|
||||||
dbOps: {
|
dbOps: {
|
||||||
@@ -194,17 +206,6 @@ const state = reactive({
|
|||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
tagPath: null,
|
tagPath: null,
|
||||||
},
|
},
|
||||||
queryConfig: [
|
|
||||||
TableQuery.slot("tagPath", "标签", "tagPathSelect"),
|
|
||||||
],
|
|
||||||
columns: [
|
|
||||||
TableColumn.new("tagPath", "标签路径").isSlot().setAddWidth(20),
|
|
||||||
TableColumn.new("name", "名称"),
|
|
||||||
TableColumn.new("uri", "连接uri"),
|
|
||||||
TableColumn.new("createTime", "创建时间").isTime(),
|
|
||||||
TableColumn.new("creator", "创建人"),
|
|
||||||
TableColumn.new("action", "操作").isSlot().setMinWidth(100).fixedRight(),
|
|
||||||
],
|
|
||||||
mongoEditDialog: {
|
mongoEditDialog: {
|
||||||
visible: false,
|
visible: false,
|
||||||
data: null as any,
|
data: null as any,
|
||||||
|
|||||||
@@ -44,11 +44,14 @@
|
|||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button @click="searchKey()" type="success" icon="search" plain></el-button>
|
<el-button :disabled="!scanParam.id || !scanParam.db" @click="searchKey()" type="success"
|
||||||
<el-button @click="scan()" icon="bottom" plain>scan</el-button>
|
icon="search" plain></el-button>
|
||||||
<el-button @click="showNewKeyDialog" type="primary" icon="plus" plain
|
<el-button :disabled="!scanParam.id || !scanParam.db" @click="scan()" icon="bottom"
|
||||||
v-auth="'redis:data:save'"></el-button>
|
plain>scan</el-button>
|
||||||
<el-button @click="flushDb" type="danger" plain v-auth="'redis:data:save'">flush</el-button>
|
<el-button :disabled="!scanParam.id || !scanParam.db" @click="showNewKeyDialog"
|
||||||
|
type="primary" icon="plus" plain v-auth="'redis:data:save'"></el-button>
|
||||||
|
<el-button :disabled="!scanParam.id || !scanParam.db" @click="flushDb" type="danger" plain
|
||||||
|
v-auth="'redis:data:save'">flush</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<div style="float: right">
|
<div style="float: right">
|
||||||
<span>keys: {{ state.dbsize }}</span>
|
<span>keys: {{ state.dbsize }}</span>
|
||||||
@@ -149,7 +152,7 @@ const state = reactive({
|
|||||||
scanParam: {
|
scanParam: {
|
||||||
id: null as any,
|
id: null as any,
|
||||||
mode: '',
|
mode: '',
|
||||||
db: 0,
|
db: null as any,
|
||||||
match: null,
|
match: null,
|
||||||
count: 10,
|
count: 10,
|
||||||
cursor: {},
|
cursor: {},
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<page-table ref="pageTableRef" :query="state.queryConfig" v-model:query-form="query" :show-selection="true"
|
<page-table ref="pageTableRef" :query="queryConfig" v-model:query-form="query" :show-selection="true"
|
||||||
v-model:selection-data="selectionData" :data="redisTable" :columns="state.columns" :total="total"
|
v-model:selection-data="selectionData" :data="redisTable" :columns="columns" :total="total"
|
||||||
v-model:page-size="query.pageSize" v-model:page-num="query.pageNum" @pageChange="search()">
|
v-model:page-size="query.pageSize" v-model:page-num="query.pageNum" @pageChange="search()">
|
||||||
|
|
||||||
<template #tagPathSelect>
|
<template #tagPathSelect>
|
||||||
@@ -154,6 +154,19 @@ import { TableColumn, TableQuery } from '@/components/pagetable';
|
|||||||
|
|
||||||
const pageTableRef: any = ref(null)
|
const pageTableRef: any = ref(null)
|
||||||
|
|
||||||
|
const queryConfig = [
|
||||||
|
TableQuery.slot("tagPath", "标签", "tagPathSelect"),
|
||||||
|
]
|
||||||
|
const columns = [
|
||||||
|
TableColumn.new("tagPath", "标签路径").isSlot().setAddWidth(20),
|
||||||
|
TableColumn.new("name", "名称"),
|
||||||
|
TableColumn.new("host", "host:port"),
|
||||||
|
TableColumn.new("mode", "mode"),
|
||||||
|
TableColumn.new("remark", "备注"),
|
||||||
|
TableColumn.new("more", "更多").isSlot().setMinWidth(155).fixedRight(),
|
||||||
|
TableColumn.new("action", "操作").isSlot().setMinWidth(65).fixedRight(),
|
||||||
|
]
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
tags: [],
|
tags: [],
|
||||||
redisTable: [],
|
redisTable: [],
|
||||||
@@ -164,18 +177,6 @@ const state = reactive({
|
|||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
},
|
},
|
||||||
queryConfig: [
|
|
||||||
TableQuery.slot("tagPath", "标签", "tagPathSelect"),
|
|
||||||
],
|
|
||||||
columns: [
|
|
||||||
TableColumn.new("tagPath", "标签路径").isSlot().setAddWidth(20),
|
|
||||||
TableColumn.new("name", "名称"),
|
|
||||||
TableColumn.new("host", "host:port"),
|
|
||||||
TableColumn.new("mode", "mode"),
|
|
||||||
TableColumn.new("remark", "备注"),
|
|
||||||
TableColumn.new("more", "更多").isSlot().setMinWidth(155).fixedRight(),
|
|
||||||
TableColumn.new("action", "操作").isSlot().setMinWidth(65).fixedRight(),
|
|
||||||
],
|
|
||||||
detailDialog: {
|
detailDialog: {
|
||||||
visible: false,
|
visible: false,
|
||||||
data: null as any,
|
data: null as any,
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<page-table ref="pageTableRef" :query="state.queryConfig" v-model:query-form="query" :show-selection="true"
|
<page-table ref="pageTableRef" :query="queryConfig" v-model:query-form="query" :show-selection="true"
|
||||||
v-model:selection-data="selectionData" :data="datas" :columns="state.columns" :total="total"
|
v-model:selection-data="selectionData" :data="datas" :columns="columns" :total="total"
|
||||||
v-model:page-size="query.pageSize" v-model:page-num="query.pageNum" @pageChange="search()">
|
v-model:page-size="query.pageSize" v-model:page-num="query.pageNum" @pageChange="search()">
|
||||||
|
|
||||||
<template #queryRight>
|
<template #queryRight>
|
||||||
<el-button v-auth="'account:add'" type="primary" icon="plus" @click="editAccount(true)">添加</el-button>
|
<el-button v-auth="perms.addAccount" type="primary" icon="plus"
|
||||||
<el-button v-auth="'account:del'" :disabled="state.selectionData.length < 1" @click="deleteAccount()"
|
@click="editAccount(true)">添加</el-button>
|
||||||
type="danger" icon="delete">删除</el-button>
|
<el-button v-auth="perms.delAccount" :disabled="state.selectionData.length < 1"
|
||||||
|
@click="deleteAccount()" type="danger" icon="delete">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #status="{ data }">
|
<template #status="{ data }">
|
||||||
@@ -22,18 +23,21 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #action="{ data }">
|
<template #action="{ data }">
|
||||||
<el-button link v-auth="'account:add'" @click="editAccount(data)" type="primary">编辑</el-button>
|
<el-button link v-if="actionBtns[perms.addAccount]" @click="editAccount(data)"
|
||||||
|
type="primary">编辑</el-button>
|
||||||
|
|
||||||
<el-button link v-auth="'account:saveRoles'" @click="showRoleEdit(data)" type="success">角色分配</el-button>
|
<el-button link v-if="actionBtns[perms.saveAccountRole]" @click="showRoleEdit(data)"
|
||||||
|
type="success">角色分配</el-button>
|
||||||
|
|
||||||
<el-button link v-auth="'account:changeStatus'" @click="changeStatus(data)" v-if="data.status == 1"
|
<el-button link v-if="actionBtns[perms.changeAccountStatus] && data.status == 1"
|
||||||
type="danger">禁用</el-button>
|
@click="changeStatus(data)" type="danger">禁用</el-button>
|
||||||
|
|
||||||
<el-button link v-auth="'account:changeStatus'" v-if="data.status == -1" type="success"
|
<el-button link v-if="actionBtns[perms.changeAccountStatus] && data.status == -1" type="success"
|
||||||
@click="changeStatus(data)">启用</el-button>
|
@click="changeStatus(data)">启用</el-button>
|
||||||
|
|
||||||
<el-button link v-auth="'account:add'" :disabled="!data.otpSecret || data.otpSecret == '-'"
|
<el-button link v-if="actionBtns[perms.addAccount]"
|
||||||
@click="resetOtpSecret(data)" type="warning">重置OTP</el-button>
|
:disabled="!data.otpSecret || data.otpSecret == '-'" @click="resetOtpSecret(data)"
|
||||||
|
type="warning">重置OTP</el-button>
|
||||||
</template>
|
</template>
|
||||||
</page-table>
|
</page-table>
|
||||||
|
|
||||||
@@ -79,9 +83,36 @@ import { ElMessage, ElMessageBox } from 'element-plus';
|
|||||||
import { dateFormat } from '@/common/utils/date';
|
import { dateFormat } from '@/common/utils/date';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue'
|
import PageTable from '@/components/pagetable/PageTable.vue'
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn, TableQuery } from '@/components/pagetable';
|
||||||
|
import { hasPerms } from '@/components/auth/auth';
|
||||||
|
|
||||||
const pageTableRef: any = ref(null)
|
const pageTableRef: any = ref(null)
|
||||||
|
|
||||||
|
const perms = {
|
||||||
|
addAccount: "account:add",
|
||||||
|
delAccount: "account:del",
|
||||||
|
saveAccountRole: "account:saveRoles",
|
||||||
|
changeAccountStatus: "account:changeStatus",
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryConfig = [
|
||||||
|
TableQuery.text("username", "用户名"),
|
||||||
|
]
|
||||||
|
const columns = [
|
||||||
|
TableColumn.new("name", "姓名"),
|
||||||
|
TableColumn.new("username", "用户名"),
|
||||||
|
TableColumn.new("status", "状态").isSlot(),
|
||||||
|
TableColumn.new("lastLoginTime", "最后登录时间").isTime(),
|
||||||
|
TableColumn.new("showmore", "查看更多").isSlot().setMinWidth(150),
|
||||||
|
TableColumn.new("creator", "创建账号"),
|
||||||
|
TableColumn.new("createTime", "创建时间").isTime(),
|
||||||
|
TableColumn.new("modifier", "更新账号"),
|
||||||
|
TableColumn.new("updateTime", "更新时间").isTime(),
|
||||||
|
]
|
||||||
|
|
||||||
|
// 该用户拥有的的操作列按钮权限
|
||||||
|
const actionBtns = hasPerms([perms.addAccount, perms.saveAccountRole, perms.changeAccountStatus])
|
||||||
|
const actionColumn = TableColumn.new("action", "操作").isSlot().fixedRight().setMinWidth(260).noShowOverflowTooltip()
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
/**
|
/**
|
||||||
* 选中的数据
|
* 选中的数据
|
||||||
@@ -95,21 +126,6 @@ const state = reactive({
|
|||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
},
|
},
|
||||||
queryConfig: [
|
|
||||||
TableQuery.text("username", "用户名"),
|
|
||||||
],
|
|
||||||
columns: [
|
|
||||||
TableColumn.new("name", "姓名"),
|
|
||||||
TableColumn.new("username", "用户名"),
|
|
||||||
TableColumn.new("status", "状态").isSlot("status"),
|
|
||||||
TableColumn.new("lastLoginTime", "最后登录时间").isTime(),
|
|
||||||
TableColumn.new("showmore", "查看更多").isSlot("showmore").setMinWidth(150),
|
|
||||||
TableColumn.new("creator", "创建账号"),
|
|
||||||
TableColumn.new("createTime", "创建时间").isTime(),
|
|
||||||
TableColumn.new("modifier", "更新账号"),
|
|
||||||
TableColumn.new("updateTime", "更新时间").isTime(),
|
|
||||||
TableColumn.new("action", "操作").isSlot("action").fixedRight().setMinWidth(280),
|
|
||||||
],
|
|
||||||
datas: [],
|
datas: [],
|
||||||
total: 0,
|
total: 0,
|
||||||
showRoleDialog: {
|
showRoleDialog: {
|
||||||
@@ -149,6 +165,9 @@ const {
|
|||||||
} = toRefs(state)
|
} = toRefs(state)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
if (Object.keys(actionBtns).length > 0) {
|
||||||
|
columns.push(actionColumn);
|
||||||
|
}
|
||||||
search();
|
search();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<page-table :show-selection="true" v-model:selection-data="selectionData" :data="configs" :columns="state.columns"
|
<page-table :show-selection="true" v-model:selection-data="selectionData" :data="configs" :columns="columns"
|
||||||
:total="total" v-model:page-size="query.pageSize" v-model:page-num="query.pageNum" @pageChange="search()">
|
:total="total" v-model:page-size="query.pageSize" v-model:page-num="query.pageNum" @pageChange="search()">
|
||||||
|
|
||||||
<template #queryRight>
|
<template #queryRight>
|
||||||
<el-button v-auth="'config:save'" type="primary" icon="plus" @click="editConfig(false)">添加</el-button>
|
<el-button v-auth="perms.saveConfig" type="primary" icon="plus"
|
||||||
|
@click="editConfig(false)">添加</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #status="{ data }">
|
<template #status="{ data }">
|
||||||
@@ -15,7 +16,7 @@
|
|||||||
<template #action="{ data }">
|
<template #action="{ data }">
|
||||||
<el-button :disabled="data.status == -1" type="warning" @click="showSetConfigDialog(data)"
|
<el-button :disabled="data.status == -1" type="warning" @click="showSetConfigDialog(data)"
|
||||||
link>配置</el-button>
|
link>配置</el-button>
|
||||||
<el-button v-auth="'config:save'" @click="editConfig(data)" type="primary" link>编辑
|
<el-button v-if="actionBtns[perms.saveConfig]" @click="editConfig(data)" type="primary" link>编辑
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</page-table>
|
</page-table>
|
||||||
@@ -60,6 +61,21 @@ import { configApi } from '../api';
|
|||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue'
|
import PageTable from '@/components/pagetable/PageTable.vue'
|
||||||
import { TableColumn } from '@/components/pagetable';
|
import { TableColumn } from '@/components/pagetable';
|
||||||
|
import { hasPerms } from '@/components/auth/auth';
|
||||||
|
|
||||||
|
const perms = {
|
||||||
|
saveConfig: "config:save"
|
||||||
|
}
|
||||||
|
const columns = [
|
||||||
|
TableColumn.new("name", "配置项"),
|
||||||
|
TableColumn.new("key", "配置key"),
|
||||||
|
TableColumn.new("value", "配置值"),
|
||||||
|
TableColumn.new("remark", "备注"),
|
||||||
|
TableColumn.new("modifier", "更新账号"),
|
||||||
|
TableColumn.new("updateTime", "更新时间").isTime(),
|
||||||
|
]
|
||||||
|
const actionColumn = TableColumn.new("action", "操作").isSlot().fixedRight().setMinWidth(130).noShowOverflowTooltip();
|
||||||
|
const actionBtns = hasPerms([perms.saveConfig])
|
||||||
|
|
||||||
const paramsFormRef: any = ref(null)
|
const paramsFormRef: any = ref(null)
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
@@ -68,15 +84,6 @@ const state = reactive({
|
|||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
name: null,
|
name: null,
|
||||||
},
|
},
|
||||||
columns: [
|
|
||||||
TableColumn.new("name", "配置项"),
|
|
||||||
TableColumn.new("key", "配置key"),
|
|
||||||
TableColumn.new("value", "配置值"),
|
|
||||||
TableColumn.new("remark", "备注"),
|
|
||||||
TableColumn.new("modifier", "更新账号"),
|
|
||||||
TableColumn.new("updateTime", "更新时间").isTime(),
|
|
||||||
TableColumn.new("action", "操作").isSlot().fixedRight().setMinWidth(130),
|
|
||||||
],
|
|
||||||
total: 0,
|
total: 0,
|
||||||
configs: [],
|
configs: [],
|
||||||
selectionData: [],
|
selectionData: [],
|
||||||
@@ -103,6 +110,9 @@ const {
|
|||||||
} = toRefs(state)
|
} = toRefs(state)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
if (Object.keys(actionBtns).length > 0) {
|
||||||
|
columns.push(actionColumn);
|
||||||
|
}
|
||||||
search();
|
search();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<page-table ref="pageTableRef" :query="state.queryConfig" v-model:query-form="query" :show-selection="true"
|
<page-table ref="pageTableRef" :query="queryConfig" v-model:query-form="query" :show-selection="true"
|
||||||
v-model:selection-data="selectionData" :data="roles" :columns="state.columns" :total="total"
|
v-model:selection-data="selectionData" :data="roles" :columns="columns" :total="total"
|
||||||
v-model:page-size="query.pageSize" v-model:page-num="query.pageNum" @pageChange="search()">
|
v-model:page-size="query.pageSize" v-model:page-num="query.pageNum" @pageChange="search()">
|
||||||
|
|
||||||
<template #queryRight>
|
<template #queryRight>
|
||||||
<el-button v-auth="'role:add'" type="primary" icon="plus" @click="editRole(false)">添加</el-button>
|
<el-button v-auth="perms.addRole" type="primary" icon="plus" @click="editRole(false)">添加</el-button>
|
||||||
<el-button v-auth="'role:del'" :disabled="selectionData.length < 1" @click="deleteRole(selectionData)"
|
<el-button v-auth="perms.delRole" :disabled="selectionData.length < 1" @click="deleteRole(selectionData)"
|
||||||
type="danger" icon="delete">删除</el-button>
|
type="danger" icon="delete">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -20,8 +20,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #action="{ data }">
|
<template #action="{ data }">
|
||||||
<el-button v-auth="'role:update'" @click="editRole(data)" type="primary" link>编辑</el-button>
|
<el-button v-if="actionBtns[perms.updateRole]" @click="editRole(data)" type="primary" link>编辑</el-button>
|
||||||
<el-button v-auth="'role:saveResources'" @click="editResource(data)" type="success" link>权限分配</el-button>
|
<el-button v-if="actionBtns[perms.saveRoleResource]" @click="editResource(data)" type="success"
|
||||||
|
link>权限分配</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
</page-table>
|
</page-table>
|
||||||
@@ -45,30 +46,41 @@ import { roleApi, resourceApi } from '../api';
|
|||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
import PageTable from '@/components/pagetable/PageTable.vue'
|
import PageTable from '@/components/pagetable/PageTable.vue'
|
||||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
import { TableColumn, TableQuery } from '@/components/pagetable';
|
||||||
|
import { hasPerms } from '@/components/auth/auth';
|
||||||
|
|
||||||
const pageTableRef: any = ref(null)
|
const pageTableRef: any = ref(null)
|
||||||
|
|
||||||
|
const perms = {
|
||||||
|
addRole: "role:add",
|
||||||
|
delRole: "role:del",
|
||||||
|
updateRole: "role:update",
|
||||||
|
saveRoleResource: "role:saveResources",
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryConfig = [
|
||||||
|
TableQuery.text("name", "角色名"),
|
||||||
|
]
|
||||||
|
const columns = [
|
||||||
|
TableColumn.new("name", "角色名称"),
|
||||||
|
TableColumn.new("code", "角色code"),
|
||||||
|
TableColumn.new("remark", "备注"),
|
||||||
|
TableColumn.new("status", "状态").isSlot(),
|
||||||
|
TableColumn.new("creator", "创建账号"),
|
||||||
|
TableColumn.new("createTime", "创建时间").isTime(),
|
||||||
|
TableColumn.new("modifier", "更新账号"),
|
||||||
|
TableColumn.new("updateTime", "更新时间").isTime(),
|
||||||
|
TableColumn.new("showmore", "查看更多").isSlot().setMinWidth(150),
|
||||||
|
]
|
||||||
|
|
||||||
|
const actionBtns = hasPerms([perms.updateRole, perms.saveRoleResource])
|
||||||
|
const actionColumn = TableColumn.new("action", "操作").isSlot().setMinWidth(160).fixedRight()
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
query: {
|
query: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
name: null,
|
name: null,
|
||||||
},
|
},
|
||||||
queryConfig: [
|
|
||||||
TableQuery.text("name", "角色名"),
|
|
||||||
],
|
|
||||||
columns: [
|
|
||||||
TableColumn.new("name", "角色名称"),
|
|
||||||
TableColumn.new("code", "角色code"),
|
|
||||||
TableColumn.new("remark", "备注"),
|
|
||||||
TableColumn.new("status", "状态").isSlot(),
|
|
||||||
TableColumn.new("creator", "创建账号"),
|
|
||||||
TableColumn.new("createTime", "创建时间").isTime(),
|
|
||||||
TableColumn.new("modifier", "更新账号"),
|
|
||||||
TableColumn.new("updateTime", "更新时间").isTime(),
|
|
||||||
TableColumn.new("showmore", "查看更多").isSlot().setMinWidth(150),
|
|
||||||
TableColumn.new("action", "操作").isSlot().setMinWidth(160).fixedRight(),
|
|
||||||
],
|
|
||||||
total: 0,
|
total: 0,
|
||||||
roles: [],
|
roles: [],
|
||||||
selectionData: [],
|
selectionData: [],
|
||||||
@@ -101,6 +113,9 @@ const {
|
|||||||
} = toRefs(state)
|
} = toRefs(state)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
if (Object.keys(actionBtns).length > 0) {
|
||||||
|
columns.push(actionColumn);
|
||||||
|
}
|
||||||
search();
|
search();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ const state = reactive({
|
|||||||
columns: [
|
columns: [
|
||||||
TableColumn.new("creator", "操作人"),
|
TableColumn.new("creator", "操作人"),
|
||||||
TableColumn.new("createTime", "操作时间").isTime(),
|
TableColumn.new("createTime", "操作时间").isTime(),
|
||||||
TableColumn.new("type", "结果").setSlot("type"),
|
TableColumn.new("type", "结果").isSlot(),
|
||||||
TableColumn.new("description", "描述"),
|
TableColumn.new("description", "描述"),
|
||||||
TableColumn.new("reqParam", "操作信息"),
|
TableColumn.new("reqParam", "操作信息"),
|
||||||
TableColumn.new("resp", "响应信息"),
|
TableColumn.new("resp", "响应信息"),
|
||||||
|
|||||||
Reference in New Issue
Block a user