mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-02 15:30:25 +08:00
feat: 菜单权限获取方式调整、前端代码优化、数据库新增数据方式调整
This commit is contained in:
@@ -28,7 +28,7 @@ class Api {
|
||||
|
||||
/**
|
||||
* 操作该权限,即请求对应的url
|
||||
* @param {Object} param 请求该权限的参数
|
||||
* @param {Object} param 请求该api的参数
|
||||
*/
|
||||
request(param: any = null, options: any = null): Promise<any> {
|
||||
return request.send(this, param, options);
|
||||
@@ -36,7 +36,8 @@ class Api {
|
||||
|
||||
/**
|
||||
* 操作该权限,即请求对应的url
|
||||
* @param {Object} param 请求该权限的参数
|
||||
* @param {Object} param 请求该api的参数
|
||||
* @param headers headers
|
||||
*/
|
||||
requestWithHeaders(param: any, headers: any): Promise<any> {
|
||||
return request.sendWithHeaders(this, param, headers);
|
||||
@@ -50,9 +51,41 @@ class Api {
|
||||
* @param url url
|
||||
* @param method 请求方法(get,post,put,delete...)
|
||||
*/
|
||||
static create(url: string, method: string) {
|
||||
static create(url: string, method: string) :Api {
|
||||
return new Api(url, method);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建get api
|
||||
* @param url url
|
||||
*/
|
||||
static newGet(url: string): Api {
|
||||
return Api.create(url, 'get');
|
||||
}
|
||||
|
||||
/**
|
||||
* new post api
|
||||
* @param url url
|
||||
*/
|
||||
static newPost(url: string): Api {
|
||||
return Api.create(url, 'post');
|
||||
}
|
||||
|
||||
/**
|
||||
* new put api
|
||||
* @param url url
|
||||
*/
|
||||
static newPut(url: string): Api {
|
||||
return Api.create(url, 'put');
|
||||
}
|
||||
|
||||
/**
|
||||
* new delete api
|
||||
* @param url url
|
||||
*/
|
||||
static newDelete(url: string): Api {
|
||||
return Api.create(url, 'delete');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import request from './request'
|
||||
import Api from './Api'
|
||||
|
||||
export default {
|
||||
login: (param: any) => request.request('POST', '/sys/accounts/login', param),
|
||||
changePwd: (param: any) => request.request('POST', '/sys/accounts/change-pwd', param),
|
||||
getPublicKey: () => request.request('GET', '/common/public-key'),
|
||||
getConfigValue: (param: any) => request.request('GET', '/sys/configs/value', param),
|
||||
captcha: () => request.request('GET', '/sys/captcha'),
|
||||
logout: (param: any) => request.request('POST', '/sys/accounts/logout/{token}', param),
|
||||
getMenuRoute: (param: any) => request.request('Get', '/sys/resources/account', param)
|
||||
login: Api.newPost("/sys/accounts/login"),
|
||||
changePwd: Api.newPost("/sys/accounts/change-pwd"),
|
||||
getPublicKey: Api.newGet("/common/public-key"),
|
||||
getConfigValue: Api.newGet("/sys/configs/value"),
|
||||
captcha: Api.newGet("/sys/captcha"),
|
||||
logout: Api.newPost("/sys/accounts/logout/{token}"),
|
||||
getPermissions: Api.newGet("/sys/accounts/permissions")
|
||||
}
|
||||
@@ -22,7 +22,8 @@ export interface Result {
|
||||
data?: any;
|
||||
}
|
||||
|
||||
const baseUrl: string = config.baseApiUrl as string
|
||||
const baseUrl: string = config.baseApiUrl
|
||||
const baseWsUrl: string = config.baseWsUrl
|
||||
|
||||
/**
|
||||
* 通知错误消息
|
||||
@@ -115,9 +116,8 @@ function request(method: string, url: string, params: any = null, headers: any =
|
||||
query.headers = headers
|
||||
}
|
||||
|
||||
const lowMethod = method.toLowerCase();
|
||||
// post和put使用json格式传参
|
||||
if (lowMethod === 'post' || lowMethod === 'put') {
|
||||
if (method === 'post' || method === 'put') {
|
||||
query.data = params;
|
||||
} else {
|
||||
query.params = params;
|
||||
@@ -155,6 +155,7 @@ function getApiUrl(url: string) {
|
||||
return baseUrl + url + '?token=' + getSession('token');
|
||||
}
|
||||
|
||||
|
||||
export default {
|
||||
request,
|
||||
send,
|
||||
|
||||
@@ -9,7 +9,7 @@ export async function getRsaPublicKey() {
|
||||
if (publicKey) {
|
||||
return publicKey
|
||||
}
|
||||
publicKey = await openApi.getPublicKey() as string
|
||||
publicKey = await openApi.getPublicKey.request() as string
|
||||
sessionStorage.setItem('RsaPublicKey', publicKey)
|
||||
return publicKey
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ const UseWartermarkConfigKey = "UseWartermark"
|
||||
* @returns 配置值
|
||||
*/
|
||||
export async function getConfigValue(key: string) : Promise<string> {
|
||||
return await openApi.getConfigValue({key}) as string
|
||||
return await openApi.getConfigValue.request({key}) as string
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -46,8 +46,8 @@ export function initAllFun() {
|
||||
useRoutesList().setRoutesList(setFilterMenuFun(dynamicRoutes[0].children, useUserInfo().userInfo.menus))
|
||||
}
|
||||
|
||||
// 后端控制路由:模拟执行路由数据初始化
|
||||
export function initBackEndControlRoutesFun() {
|
||||
// 后端控制路由:执行路由数据初始化
|
||||
export async function initBackEndControlRoutesFun() {
|
||||
NextLoading.start(); // 界面 loading 动画开始执行
|
||||
const token = getSession('token'); // 获取浏览器缓存 token 值
|
||||
if (!token) {
|
||||
@@ -55,11 +55,8 @@ export function initBackEndControlRoutesFun() {
|
||||
return false
|
||||
}
|
||||
useUserInfo().setUserInfo({});
|
||||
let menuRoute = getSession('menus')
|
||||
if (!menuRoute) {
|
||||
menuRoute = getBackEndControlRoutes(); // 获取路由
|
||||
// const oldRoutes = res; // 获取接口原始路由(未处理component)
|
||||
}
|
||||
// 获取路由
|
||||
let menuRoute = await getBackEndControlRoutes();
|
||||
dynamicRoutes[0].children = backEndRouterConverter(menuRoute); // 处理路由(component)
|
||||
// 添加404界面
|
||||
router.addRoute(pathMatch);
|
||||
@@ -72,8 +69,16 @@ export function initBackEndControlRoutesFun() {
|
||||
}
|
||||
|
||||
// 后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
|
||||
export function getBackEndControlRoutes() {
|
||||
return openApi.getMenuRoute({});
|
||||
export async function getBackEndControlRoutes() {
|
||||
try {
|
||||
const menuAndPermission = await openApi.getPermissions.request();
|
||||
// 赋值权限码,用于控制按钮等
|
||||
useUserInfo().userInfo.permissions = menuAndPermission.permissions;
|
||||
return menuAndPermission.menus;
|
||||
} catch (e: any) {
|
||||
console.error(e);
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
// 后端控制路由,后端返回路由 转换为vue route
|
||||
@@ -124,18 +129,18 @@ export function backEndRouterConverter(routes: any, parentPath: string = "/") {
|
||||
* @returns 返回处理成函数后的 component
|
||||
*/
|
||||
export function dynamicImport(dynamicViewsModules: Record<string, Function>, component: string) {
|
||||
const keys = Object.keys(dynamicViewsModules);
|
||||
const matchKeys = keys.filter((key) => {
|
||||
const k = key.replace(/..\/views|../, '');
|
||||
return k.startsWith(`${component}`) || k.startsWith(`/${component}`);
|
||||
});
|
||||
if (matchKeys?.length === 1) {
|
||||
const matchKey = matchKeys[0];
|
||||
return dynamicViewsModules[matchKey];
|
||||
}
|
||||
if (matchKeys?.length > 1) {
|
||||
return false;
|
||||
}
|
||||
const keys = Object.keys(dynamicViewsModules);
|
||||
const matchKeys = keys.filter((key) => {
|
||||
const k = key.replace(/..\/views|../, '');
|
||||
return k.startsWith(`${component}`) || k.startsWith(`/${component}`);
|
||||
});
|
||||
if (matchKeys?.length === 1) {
|
||||
const matchKey = matchKeys[0];
|
||||
return dynamicViewsModules[matchKey];
|
||||
}
|
||||
if (matchKeys?.length > 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 多级嵌套数组处理成一维数组
|
||||
@@ -167,7 +172,6 @@ export function formatTwoStageRoutes(arr: any) {
|
||||
}
|
||||
});
|
||||
useKeepALiveNames().setCacheKeepAlive(cacheList);
|
||||
// store.dispatch('keepAliveNames/setCacheKeepAlive', cacheList);
|
||||
return newArr;
|
||||
}
|
||||
|
||||
@@ -227,21 +231,22 @@ export function resetRoute() {
|
||||
});
|
||||
}
|
||||
|
||||
// 初始化方法执行
|
||||
const { isRequestRoutes } = useThemeConfig(pinia).themeConfig;
|
||||
if (!isRequestRoutes) {
|
||||
// 未开启后端控制路由
|
||||
initAllFun();
|
||||
} else if (isRequestRoutes) {
|
||||
// 后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
|
||||
initBackEndControlRoutesFun();
|
||||
export async function initRouter() {
|
||||
// 初始化方法执行
|
||||
const { isRequestRoutes } = useThemeConfig(pinia).themeConfig;
|
||||
if (!isRequestRoutes) {
|
||||
// 未开启后端控制路由
|
||||
initAllFun();
|
||||
} else if (isRequestRoutes) {
|
||||
// 后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
|
||||
await initBackEndControlRoutesFun();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let SysWs: any;
|
||||
|
||||
// 路由加载前
|
||||
router.beforeEach((to, from, next) => {
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
NProgress.configure({ showSpinner: false });
|
||||
if (to.meta.title) NProgress.start();
|
||||
|
||||
@@ -278,7 +283,10 @@ router.beforeEach((to, from, next) => {
|
||||
if (!SysWs && to.path != '/machine/terminal') {
|
||||
SysWs = sockets.sysMsgSocket();
|
||||
}
|
||||
if (useRoutesList().routesList.length > 0) {
|
||||
if (useRoutesList().routesList.length == 0) {
|
||||
await initRouter();
|
||||
next({ path: to.path, query: to.query });
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { getSession } from '@/common/utils/storage.ts';
|
||||
import { getSession } from '@/common/utils/storage';
|
||||
|
||||
export const useUserInfo = defineStore('userInfo', {
|
||||
state: (): UserInfoState => ({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Api from '@/common/Api';
|
||||
|
||||
export const indexApi = {
|
||||
getIndexCount: Api.create("/common/index/count", 'get'),
|
||||
getIndexCount: Api.newGet("/common/index/count"),
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
import { nextTick, onMounted, ref, toRefs, reactive, computed } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { initBackEndControlRoutesFun } from '@/router/index';
|
||||
import { initRouter } from '@/router/index';
|
||||
import { setSession, setUserInfo2Session, setUseWatermark2Session } from '@/common/utils/storage';
|
||||
import { formatAxis } from '@/common/utils/format';
|
||||
import openApi from '@/common/openApi';
|
||||
@@ -71,7 +71,6 @@ import { RsaEncrypt } from '@/common/rsa';
|
||||
import { useLoginCaptcha, useWartermark } from '@/common/sysconfig';
|
||||
import { letterAvatar } from '@/common/utils/string';
|
||||
import { useUserInfo } from '@/store/userInfo';
|
||||
import { useThemeConfig } from '@/store/themeConfig';
|
||||
|
||||
const rules = {
|
||||
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
|
||||
@@ -138,7 +137,7 @@ const getCaptcha = async () => {
|
||||
if (!state.isUseLoginCaptcha) {
|
||||
return;
|
||||
}
|
||||
let res: any = await openApi.captcha();
|
||||
let res: any = await openApi.captcha.request();
|
||||
state.captchaImage = res.base64Captcha;
|
||||
state.loginForm.cid = res.cid;
|
||||
};
|
||||
@@ -167,10 +166,9 @@ const onSignIn = async () => {
|
||||
try {
|
||||
const loginReq = { ...state.loginForm };
|
||||
loginReq.password = await RsaEncrypt(originPwd);
|
||||
loginRes = await openApi.login(loginReq);
|
||||
loginRes = await openApi.login.request(loginReq);
|
||||
// 存储 token 到浏览器缓存
|
||||
setSession('token', loginRes.token);
|
||||
setSession('menus', loginRes.menus);
|
||||
} catch (e: any) {
|
||||
state.loading.signIn = false;
|
||||
state.loginForm.captcha = '';
|
||||
@@ -192,8 +190,6 @@ const onSignIn = async () => {
|
||||
// 头像
|
||||
photo: letterAvatar(state.loginForm.username),
|
||||
time: new Date().getTime(),
|
||||
// // 菜单资源code数组
|
||||
// menus: loginRes.menus,
|
||||
permissions: loginRes.permissions,
|
||||
lastLoginTime: loginRes.lastLoginTime,
|
||||
lastLoginIp: loginRes.lastLoginIp,
|
||||
@@ -202,20 +198,9 @@ const onSignIn = async () => {
|
||||
// 存储用户信息到浏览器缓存
|
||||
setUserInfo2Session(userInfos);
|
||||
// 1、请注意执行顺序(存储用户信息到vuex)
|
||||
useUserInfo().setUserInfo(userInfos)
|
||||
// store.dispatch('userInfos/setUserInfos', userInfos);
|
||||
if (!useThemeConfig().themeConfig.isRequestRoutes) {
|
||||
// 前端控制路由,2、请注意执行顺序
|
||||
// await initAllFun();
|
||||
await initBackEndControlRoutesFun();
|
||||
signInSuccess();
|
||||
} else {
|
||||
// 模拟后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
|
||||
// 添加完动态路由,再进行 router 跳转,否则可能报错 No match found for location with path "/"
|
||||
await initBackEndControlRoutesFun();
|
||||
// 执行完 initBackEndControlRoutesFun,再执行 signInSuccess
|
||||
signInSuccess();
|
||||
}
|
||||
useUserInfo().setUserInfo(userInfos);
|
||||
await initRouter();
|
||||
signInSuccess();
|
||||
};
|
||||
|
||||
// 登录成功后的跳转
|
||||
@@ -248,7 +233,7 @@ const changePwd = () => {
|
||||
const changePwdReq: any = { ...form };
|
||||
changePwdReq.oldPassword = await RsaEncrypt(form.oldPassword);
|
||||
changePwdReq.newPassword = await RsaEncrypt(form.newPassword);
|
||||
await openApi.changePwd(changePwdReq);
|
||||
await openApi.changePwd.request(changePwdReq);
|
||||
ElMessage.success('密码修改成功, 新密码已填充至登录密码框');
|
||||
state.loginForm.password = state.changePwdDialog.form.newPassword;
|
||||
state.changePwdDialog.visible = false;
|
||||
|
||||
@@ -135,7 +135,7 @@ const state = reactive({
|
||||
tabs,
|
||||
dataTabsTableHeight: '600',
|
||||
editorHeight: '600',
|
||||
tagTreeHeight: window.innerHeight - 173 + 'px',
|
||||
tagTreeHeight: window.innerHeight - 178 + 'px',
|
||||
genSqlDialog: {
|
||||
visible: false,
|
||||
sql: '',
|
||||
|
||||
@@ -2,27 +2,27 @@ import Api from '@/common/Api';
|
||||
|
||||
export const dbApi = {
|
||||
// 获取权限列表
|
||||
dbs: Api.create("/dbs", 'get'),
|
||||
saveDb: Api.create("/dbs", 'post'),
|
||||
getAllDatabase: Api.create("/dbs/databases", 'post'),
|
||||
getDbPwd: Api.create("/dbs/{id}/pwd", 'get'),
|
||||
deleteDb: Api.create("/dbs/{id}", 'delete'),
|
||||
dumpDb: Api.create("/dbs/{id}/dump", 'post'),
|
||||
tableInfos: Api.create("/dbs/{id}/t-infos", 'get'),
|
||||
tableIndex: Api.create("/dbs/{id}/t-index", 'get'),
|
||||
tableDdl: Api.create("/dbs/{id}/t-create-ddl", 'get'),
|
||||
tableMetadata: Api.create("/dbs/{id}/t-metadata", 'get'),
|
||||
columnMetadata: Api.create("/dbs/{id}/c-metadata", 'get'),
|
||||
dbs: Api.newGet("/dbs"),
|
||||
saveDb: Api.newPost("/dbs"),
|
||||
getAllDatabase: Api.newPost("/dbs/databases"),
|
||||
getDbPwd: Api.newGet("/dbs/{id}/pwd"),
|
||||
deleteDb: Api.newDelete("/dbs/{id}"),
|
||||
dumpDb: Api.newPost("/dbs/{id}/dump"),
|
||||
tableInfos: Api.newGet("/dbs/{id}/t-infos"),
|
||||
tableIndex: Api.newGet("/dbs/{id}/t-index"),
|
||||
tableDdl: Api.newGet("/dbs/{id}/t-create-ddl"),
|
||||
tableMetadata: Api.newGet("/dbs/{id}/t-metadata"),
|
||||
columnMetadata: Api.newGet("/dbs/{id}/c-metadata"),
|
||||
// 获取表即列提示
|
||||
hintTables: Api.create("/dbs/{id}/hint-tables", 'get'),
|
||||
sqlExec: Api.create("/dbs/{id}/exec-sql", 'post'),
|
||||
hintTables: Api.newGet("/dbs/{id}/hint-tables"),
|
||||
sqlExec: Api.newPost("/dbs/{id}/exec-sql"),
|
||||
// 保存sql
|
||||
saveSql: Api.create("/dbs/{id}/sql", 'post'),
|
||||
saveSql: Api.newPost("/dbs/{id}/sql"),
|
||||
// 获取保存的sql
|
||||
getSql: Api.create("/dbs/{id}/sql", 'get'),
|
||||
getSql: Api.newGet("/dbs/{id}/sql"),
|
||||
// 获取保存的sql names
|
||||
getSqlNames: Api.create("/dbs/{id}/sql-names", 'get'),
|
||||
deleteDbSql: Api.create("/dbs/{id}/sql", 'delete'),
|
||||
getSqlNames: Api.newGet("/dbs/{id}/sql-names"),
|
||||
deleteDbSql: Api.newDelete("/dbs/{id}/sql"),
|
||||
// 获取数据库sql执行记录
|
||||
getSqlExecs: Api.create("/dbs/{dbId}/sql-execs", 'get'),
|
||||
getSqlExecs: Api.newGet("/dbs/{dbId}/sql-execs"),
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
</el-link>
|
||||
<el-divider direction="vertical" border-style="dashed" />
|
||||
|
||||
<el-link @click="addRow()" type="primary" icon="plus" :underline="false"></el-link>
|
||||
<el-link @click="onShowAddDataDialog()" type="primary" icon="plus" :underline="false"></el-link>
|
||||
<el-divider direction="vertical" border-style="dashed" />
|
||||
|
||||
<el-link @click="onDeleteData()" type="danger" icon="delete" :underline="false"></el-link>
|
||||
@@ -37,8 +37,8 @@
|
||||
</el-tooltip>
|
||||
</el-col>
|
||||
<el-col :span="16">
|
||||
<el-input v-model="condition" placeholder="若需条件过滤,可选择列并点击对应的字段并输入需要过滤的内容点击查询按钮即可" clearable @clear="selectData" size="small"
|
||||
style="width: 100%">
|
||||
<el-input v-model="condition" placeholder="若需条件过滤,可选择列并点击对应的字段并输入需要过滤的内容点击查询按钮即可" clearable
|
||||
@clear="selectData" size="small" style="width: 100%">
|
||||
<template #prepend>
|
||||
<el-popover trigger="click" :width="320" placement="right">
|
||||
<template #reference>
|
||||
@@ -64,9 +64,9 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<db-table ref="dbTableRef" :db-id="state.ti.dbId" :db="state.ti.db" :data="datas"
|
||||
:table="state.table" :column-names="columnNames" :loading="loading" :height="tableHeight"
|
||||
:show-column-tip="true" :sortable="'custom'" @sort-change="(sort: any) => onTableSortChange(sort)"
|
||||
<db-table ref="dbTableRef" :db-id="state.ti.dbId" :db="state.ti.db" :data="datas" :table="state.table"
|
||||
:column-names="columnNames" :loading="loading" :height="tableHeight" :show-column-tip="true"
|
||||
:sortable="'custom'" @sort-change="(sort: any) => onTableSortChange(sort)"
|
||||
@selection-change="onDataSelectionChange" @change-updated-field="changeUpdatedField"></db-table>
|
||||
|
||||
<el-row type="flex" class="mt5" justify="center">
|
||||
@@ -99,6 +99,26 @@
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="addDataDialog.visible" :title="addDataDialog.title" :destroy-on-close="true" width="600px">
|
||||
<el-form ref="dataForm" :model="addDataDialog.data" label-width="160px">
|
||||
<el-form-item v-for="column in columns" class="w100" :prop="column.columnName" :label="column.columnName"
|
||||
:required="column.nullable != 'YES' && column.columnKey != 'PRI'">
|
||||
<el-input-number v-if="DbInst.isNumber(column.columnType)"
|
||||
v-model="addDataDialog.data[`${column.columnName}`]"
|
||||
:placeholder="`${column.columnType} ${column.columnComment}`" class="w100" />
|
||||
|
||||
<el-input v-else v-model="addDataDialog.data[`${column.columnName}`]"
|
||||
:placeholder="`${column.columnType} ${column.columnComment}`" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="closeAddDataDialog">取消</el-button>
|
||||
<el-button type="primary" @click="addRow">确定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -113,6 +133,7 @@ import { dateStrFormat } from '@/common/utils/date';
|
||||
import DbTable from '../DbTable.vue'
|
||||
|
||||
const emits = defineEmits(['genInsertSql'])
|
||||
const dataForm: any = ref(null);
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
@@ -136,7 +157,7 @@ const state = reactive({
|
||||
condition: '', // 当前条件框的条件
|
||||
loading: false, // 是否在加载数据
|
||||
columnNames: [],
|
||||
columns: [],
|
||||
columns: [] as any,
|
||||
pageNum: 1,
|
||||
count: 0,
|
||||
selectionDatas: [] as any,
|
||||
@@ -149,6 +170,12 @@ const state = reactive({
|
||||
condition: '=',
|
||||
value: null
|
||||
},
|
||||
addDataDialog: {
|
||||
data: {},
|
||||
title: '',
|
||||
placeholder: '',
|
||||
visible: false,
|
||||
},
|
||||
tableHeight: '600',
|
||||
hasUpdatedFileds: false,
|
||||
});
|
||||
@@ -163,6 +190,7 @@ const {
|
||||
count,
|
||||
hasUpdatedFileds,
|
||||
conditionDialog,
|
||||
addDataDialog,
|
||||
} = toRefs(state);
|
||||
|
||||
watch(() => props.tableHeight, (newValue: any) => {
|
||||
@@ -323,20 +351,43 @@ const cancelUpdateFields = () => {
|
||||
dbTableRef.value.cancelUpdateFields();
|
||||
}
|
||||
|
||||
const onShowAddDataDialog = async () => {
|
||||
state.addDataDialog.title = `添加'${state.table}'表数据`
|
||||
state.addDataDialog.visible = true;
|
||||
};
|
||||
|
||||
const closeAddDataDialog = () => {
|
||||
state.addDataDialog.visible = false;
|
||||
state.addDataDialog.data = {};
|
||||
}
|
||||
|
||||
// 添加新数据行
|
||||
const addRow = async () => {
|
||||
const columns = state.ti.getNowDb().getColumns(state.table);
|
||||
// key: 字段名,value: 字段名提示
|
||||
let obj: any = {};
|
||||
columns.forEach((item: any) => {
|
||||
obj[`${item.columnName}`] = `'${item.columnComment || ''} ${item.columnName}[${item.columnType}]${item.nullable == 'YES' ? '' : '[not null]'}'`;
|
||||
});
|
||||
let columnNames = Object.keys(obj).join(',');
|
||||
let values = Object.values(obj).join(',');
|
||||
let sql = `INSERT INTO ${state.table} (${columnNames}) VALUES (${values});`;
|
||||
state.ti.getNowDbInst().promptExeSql(state.ti.db, sql, null, () => {
|
||||
onRefresh();
|
||||
dataForm.value.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
const data = state.addDataDialog.data;
|
||||
// key: 字段名,value: 字段名提示
|
||||
let obj: any = {};
|
||||
for (let item of state.columns) {
|
||||
const value = data[item.columnName]
|
||||
if (!value) {
|
||||
continue
|
||||
}
|
||||
obj[`${item.columnName}`] = DbInst.wrapValueByType(value);
|
||||
}
|
||||
let columnNames = Object.keys(obj).join(',');
|
||||
let values = Object.values(obj).join(',');
|
||||
let sql = `INSERT INTO ${state.table} (${columnNames}) VALUES (${values});`;
|
||||
state.ti.getNowDbInst().promptExeSql(state.ti.db, sql, null, () => {
|
||||
closeAddDataDialog();
|
||||
onRefresh();
|
||||
});
|
||||
} else {
|
||||
ElMessage.error('请正确填写数据信息');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
@@ -274,12 +274,21 @@ export class DbInst {
|
||||
* 根据字段类型包装字段值,如为字符串等则添加‘’,数字类型则直接返回即可
|
||||
*/
|
||||
static wrapColumnValue(columnType: string, value: any) {
|
||||
if (columnType.match(/int|double|float|nubmer|decimal|byte|bit/gi)) {
|
||||
if (this.isNumber(columnType)) {
|
||||
return value;
|
||||
}
|
||||
return `'${value}'`;
|
||||
};
|
||||
|
||||
/**
|
||||
* 判断字段类型是否为数字类型
|
||||
* @param columnType 字段类型
|
||||
* @returns
|
||||
*/
|
||||
static isNumber(columnType: string) {
|
||||
return columnType.match(/int|double|float|nubmer|decimal|byte|bit/gi);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param str 字符串
|
||||
|
||||
@@ -2,45 +2,45 @@ import Api from '@/common/Api';
|
||||
|
||||
export const machineApi = {
|
||||
// 获取权限列表
|
||||
list: Api.create("/machines", 'get'),
|
||||
getMachinePwd: Api.create("/machines/{id}/pwd", 'get'),
|
||||
info: Api.create("/machines/{id}/sysinfo", 'get'),
|
||||
stats: Api.create("/machines/{id}/stats", 'get'),
|
||||
process: Api.create("/machines/{id}/process", 'get'),
|
||||
list: Api.newGet("/machines"),
|
||||
getMachinePwd: Api.newGet("/machines/{id}/pwd"),
|
||||
info: Api.newGet("/machines/{id}/sysinfo"),
|
||||
stats: Api.newGet("/machines/{id}/stats"),
|
||||
process: Api.newGet("/machines/{id}/process"),
|
||||
// 终止进程
|
||||
killProcess: Api.create("/machines/{id}/process", 'delete'),
|
||||
closeCli: Api.create("/machines/{id}/close-cli", 'delete'),
|
||||
testConn: Api.create("/machines/test-conn", 'post'),
|
||||
killProcess: Api.newDelete("/machines/{id}/process"),
|
||||
closeCli: Api.newDelete("/machines/{id}/close-cli"),
|
||||
testConn: Api.newPost("/machines/test-conn"),
|
||||
// 保存按钮
|
||||
saveMachine: Api.create("/machines", 'post'),
|
||||
saveMachine: Api.newPost("/machines"),
|
||||
// 调整状态
|
||||
changeStatus: Api.create("/machines/{id}/{status}", 'put'),
|
||||
changeStatus: Api.newPut("/machines/{id}/{status}"),
|
||||
// 删除机器
|
||||
del: Api.create("/machines/{id}", 'delete'),
|
||||
scripts: Api.create("/machines/{machineId}/scripts", 'get'),
|
||||
runScript: Api.create("/machines/{machineId}/scripts/{scriptId}/run", 'get'),
|
||||
saveScript: Api.create("/machines/{machineId}/scripts", 'post'),
|
||||
deleteScript: Api.create("/machines/{machineId}/scripts/{scriptId}", 'delete'),
|
||||
del: Api.newDelete("/machines/{id}"),
|
||||
scripts: Api.newGet("/machines/{machineId}/scripts"),
|
||||
runScript: Api.newGet("/machines/{machineId}/scripts/{scriptId}/run"),
|
||||
saveScript: Api.newPost("/machines/{machineId}/scripts"),
|
||||
deleteScript: Api.newDelete("/machines/{machineId}/scripts/{scriptId}"),
|
||||
// 获取配置文件列表
|
||||
files: Api.create("/machines/{id}/files", 'get'),
|
||||
lsFile: Api.create("/machines/{machineId}/files/{fileId}/read-dir", 'get'),
|
||||
rmFile: Api.create("/machines/{machineId}/files/{fileId}/remove", 'delete'),
|
||||
uploadFile: Api.create("/machines/{machineId}/files/{fileId}/upload?token={token}", 'post'),
|
||||
fileContent: Api.create("/machines/{machineId}/files/{fileId}/read", 'get'),
|
||||
createFile: Api.create("/machines/{machineId}/files/{id}/create-file", 'post'),
|
||||
files: Api.newGet("/machines/{id}/files"),
|
||||
lsFile: Api.newGet("/machines/{machineId}/files/{fileId}/read-dir"),
|
||||
rmFile: Api.newDelete("/machines/{machineId}/files/{fileId}/remove"),
|
||||
uploadFile: Api.newPost("/machines/{machineId}/files/{fileId}/upload?token={token}"),
|
||||
fileContent: Api.newGet("/machines/{machineId}/files/{fileId}/read"),
|
||||
createFile: Api.newPost("/machines/{machineId}/files/{id}/create-file"),
|
||||
// 修改文件内容
|
||||
updateFileContent: Api.create("/machines/{machineId}/files/{id}/write", 'post'),
|
||||
updateFileContent: Api.newPost("/machines/{machineId}/files/{id}/write"),
|
||||
// 添加文件or目录
|
||||
addConf: Api.create("/machines/{machineId}/files", 'post'),
|
||||
addConf: Api.newPost("/machines/{machineId}/files"),
|
||||
// 删除配置的文件or目录
|
||||
delConf: Api.create("/machines/{machineId}/files/{id}", 'delete'),
|
||||
terminal: Api.create("/api/machines/{id}/terminal", 'get'),
|
||||
recDirNames: Api.create("/machines/rec/names", 'get')
|
||||
delConf: Api.newDelete("/machines/{machineId}/files/{id}"),
|
||||
terminal: Api.newGet("/api/machines/{id}/terminal"),
|
||||
recDirNames: Api.newGet("/machines/rec/names")
|
||||
}
|
||||
|
||||
export const authCertApi = {
|
||||
baseList : Api.create("/sys/authcerts/base", 'get'),
|
||||
list: Api.create("/sys/authcerts", 'get'),
|
||||
save: Api.create("/sys/authcerts", 'post'),
|
||||
delete: Api.create("/sys/authcerts/{id}", 'delete'),
|
||||
baseList : Api.newGet("/sys/authcerts/base"),
|
||||
list: Api.newGet("/sys/authcerts"),
|
||||
save: Api.newPost("/sys/authcerts"),
|
||||
delete: Api.newDelete("/sys/authcerts/{id}"),
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
import Api from '@/common/Api';
|
||||
|
||||
export const mongoApi = {
|
||||
mongoList : Api.create("/mongos", 'get'),
|
||||
saveMongo : Api.create("/mongos", 'post'),
|
||||
deleteMongo : Api.create("/mongos/{id}", 'delete'),
|
||||
databases: Api.create("/mongos/{id}/databases", 'get'),
|
||||
collections: Api.create("/mongos/{id}/collections", 'get'),
|
||||
runCommand: Api.create("/mongos/{id}/run-command", 'post'),
|
||||
findCommand: Api.create("/mongos/{id}/command/find", 'post'),
|
||||
updateByIdCommand: Api.create("/mongos/{id}/command/update-by-id", 'post'),
|
||||
deleteByIdCommand: Api.create("/mongos/{id}/command/delete-by-id", 'post'),
|
||||
insertCommand: Api.create("/mongos/{id}/command/insert", 'post'),
|
||||
mongoList : Api.newGet("/mongos"),
|
||||
saveMongo : Api.newPost("/mongos"),
|
||||
deleteMongo : Api.newDelete("/mongos/{id}"),
|
||||
databases: Api.newGet("/mongos/{id}/databases"),
|
||||
collections: Api.newGet("/mongos/{id}/collections"),
|
||||
runCommand: Api.newPost("/mongos/{id}/run-command"),
|
||||
findCommand: Api.newPost("/mongos/{id}/command/find"),
|
||||
updateByIdCommand: Api.newPost("/mongos/{id}/command/update-by-id"),
|
||||
deleteByIdCommand: Api.newPost("/mongos/{id}/command/delete-by-id"),
|
||||
insertCommand: Api.newPost("/mongos/{id}/command/insert"),
|
||||
}
|
||||
@@ -1,26 +1,26 @@
|
||||
import Api from '@/common/Api';
|
||||
|
||||
export const redisApi = {
|
||||
redisList : Api.create("/redis", 'get'),
|
||||
getRedisPwd: Api.create("/redis/{id}/pwd", 'get'),
|
||||
redisInfo: Api.create("/redis/{id}/info", 'get'),
|
||||
clusterInfo: Api.create("/redis/{id}/cluster-info", 'get'),
|
||||
saveRedis: Api.create("/redis", 'post'),
|
||||
delRedis: Api.create("/redis/{id}", 'delete'),
|
||||
redisList: Api.newGet("/redis"),
|
||||
getRedisPwd: Api.newGet("/redis/{id}/pwd"),
|
||||
redisInfo: Api.newGet("/redis/{id}/info"),
|
||||
clusterInfo: Api.newGet("/redis/{id}/cluster-info"),
|
||||
saveRedis: Api.newPost("/redis"),
|
||||
delRedis: Api.newDelete("/redis/{id}"),
|
||||
// 获取权限列表
|
||||
scan: Api.create("/redis/{id}/{db}/scan", 'post'),
|
||||
getStringValue: Api.create("/redis/{id}/{db}/string-value", 'get'),
|
||||
saveStringValue: Api.create("/redis/{id}/{db}/string-value", 'post'),
|
||||
getHashValue: Api.create("/redis/{id}/{db}/hash-value", 'get'),
|
||||
hscan: Api.create("/redis/{id}/{db}/hscan", 'get'),
|
||||
hget: Api.create("/redis/{id}/{db}/hget", 'get'),
|
||||
hdel: Api.create("/redis/{id}/{db}/hdel", 'delete'),
|
||||
saveHashValue: Api.create("/redis/{id}/{db}/hash-value", 'post'),
|
||||
getSetValue: Api.create("/redis/{id}/{db}/set-value", 'get'),
|
||||
saveSetValue: Api.create("/redis/{id}/{db}/set-value", 'post'),
|
||||
del: Api.create("/redis/{id}/{db}/scan/{cursor}/{count}", 'delete'),
|
||||
delKey: Api.create("/redis/{id}/{db}/key", 'delete'),
|
||||
getListValue: Api.create("/redis/{id}/{db}/list-value", 'get'),
|
||||
saveListValue: Api.create("/redis/{id}/{db}/list-value", 'post'),
|
||||
setListValue: Api.create("/redis/{id}/{db}/list-value/lset", 'post'),
|
||||
scan: Api.newPost("/redis/{id}/{db}/scan"),
|
||||
getStringValue: Api.newGet("/redis/{id}/{db}/string-value"),
|
||||
saveStringValue: Api.newPost("/redis/{id}/{db}/string-value"),
|
||||
getHashValue: Api.newGet("/redis/{id}/{db}/hash-value"),
|
||||
hscan: Api.newGet("/redis/{id}/{db}/hscan"),
|
||||
hget: Api.newGet("/redis/{id}/{db}/hget"),
|
||||
hdel: Api.newDelete("/redis/{id}/{db}/hdel"),
|
||||
saveHashValue: Api.newPost("/redis/{id}/{db}/hash-value"),
|
||||
getSetValue: Api.newGet("/redis/{id}/{db}/set-value"),
|
||||
saveSetValue: Api.newPost("/redis/{id}/{db}/set-value"),
|
||||
del: Api.newDelete("/redis/{id}/{db}/scan/{cursor}/{count}"),
|
||||
delKey: Api.newDelete("/redis/{id}/{db}/key"),
|
||||
getListValue: Api.newGet("/redis/{id}/{db}/list-value"),
|
||||
saveListValue: Api.newPost("/redis/{id}/{db}/list-value"),
|
||||
setListValue: Api.newPost("/redis/{id}/{db}/list-value/lset"),
|
||||
}
|
||||
@@ -1,20 +1,20 @@
|
||||
import Api from '@/common/Api';
|
||||
|
||||
export const tagApi = {
|
||||
getAccountTags: Api.create("/tag-trees/account-has", 'get'),
|
||||
listByQuery: Api.create("/tag-trees/query", 'get'),
|
||||
getTagTrees: Api.create("/tag-trees", 'get'),
|
||||
saveTagTree: Api.create("/tag-trees", 'post'),
|
||||
delTagTree: Api.create("/tag-trees/{id}", 'delete'),
|
||||
getAccountTags: Api.newGet("/tag-trees/account-has"),
|
||||
listByQuery: Api.newGet("/tag-trees/query"),
|
||||
getTagTrees: Api.newGet("/tag-trees"),
|
||||
saveTagTree: Api.newPost("/tag-trees"),
|
||||
delTagTree: Api.newDelete("/tag-trees/{id}"),
|
||||
|
||||
getTeams: Api.create("/teams", 'get'),
|
||||
saveTeam: Api.create("/teams", 'post'),
|
||||
delTeam: Api.create("/teams/{id}", 'delete'),
|
||||
getTeams: Api.newGet("/teams"),
|
||||
saveTeam: Api.newPost("/teams"),
|
||||
delTeam: Api.newDelete("/teams/{id}"),
|
||||
|
||||
getTeamMem: Api.create("/teams/{teamId}/members", 'get'),
|
||||
saveTeamMem: Api.create("/teams/{teamId}/members", 'post'),
|
||||
delTeamMem: Api.create("/teams/{teamId}/members/{accountId}", 'delete'),
|
||||
getTeamMem: Api.newGet("/teams/{teamId}/members"),
|
||||
saveTeamMem: Api.newPost("/teams/{teamId}/members"),
|
||||
delTeamMem: Api.newDelete("/teams/{teamId}/members/{accountId}"),
|
||||
|
||||
getTeamTagIds: Api.create("/teams/{teamId}/tags", 'get'),
|
||||
saveTeamTags: Api.create("/teams/{teamId}/tags", 'post'),
|
||||
getTeamTagIds: Api.newGet("/teams/{teamId}/tags"),
|
||||
saveTeamTags: Api.newPost("/teams/{teamId}/tags"),
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import Api from '@/common/Api';
|
||||
|
||||
export const personApi = {
|
||||
accountInfo: Api.create("/sys/accounts/self", 'get'),
|
||||
updateAccount: Api.create("/sys/accounts/self", 'put'),
|
||||
getMsgs: Api.create("/sys/accounts/msgs", 'get'),
|
||||
accountInfo: Api.newGet("/sys/accounts/self"),
|
||||
updateAccount: Api.newPut("/sys/accounts/self"),
|
||||
getMsgs: Api.newGet("/sys/accounts/msgs"),
|
||||
}
|
||||
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
import Api from '@/common/Api';
|
||||
|
||||
export const resourceApi = {
|
||||
list: Api.create("/sys/resources", 'get'),
|
||||
detail: Api.create("/sys/resources/{id}", 'get'),
|
||||
save: Api.create("/sys/resources", 'post'),
|
||||
update: Api.create("/sys/resources/{id}", 'put'),
|
||||
del: Api.create("/sys/resources/{id}", 'delete'),
|
||||
changeStatus: Api.create("/sys/resources/{id}/{status}", 'put')
|
||||
list: Api.newGet("/sys/resources"),
|
||||
detail: Api.newGet("/sys/resources/{id}"),
|
||||
save: Api.newPost("/sys/resources"),
|
||||
update: Api.newPut("/sys/resources/{id}"),
|
||||
del: Api.newDelete("/sys/resources/{id}"),
|
||||
changeStatus: Api.newPut("/sys/resources/{id}/{status}")
|
||||
}
|
||||
|
||||
export const roleApi = {
|
||||
list: Api.create("/sys/roles", 'get'),
|
||||
save: Api.create("/sys/roles", 'post'),
|
||||
update: Api.create("/sys/roles/{id}", 'put'),
|
||||
del: Api.create("/sys/roles/{id}", 'delete'),
|
||||
list: Api.newGet("/sys/roles"),
|
||||
save: Api.newPost("/sys/roles"),
|
||||
update: Api.newPut("/sys/roles/{id}"),
|
||||
del: Api.newDelete("/sys/roles/{id}"),
|
||||
// 获取指定角色拥有的资源id
|
||||
roleResourceIds: Api.create("/sys/roles/{id}/resourceIds", 'get'),
|
||||
roleResources: Api.create("/sys/roles/{id}/resources", 'get'),
|
||||
saveResources: Api.create("/sys/roles/{id}/resources", 'post')
|
||||
roleResourceIds: Api.newGet("/sys/roles/{id}/resourceIds"),
|
||||
roleResources: Api.newGet("/sys/roles/{id}/resources"),
|
||||
saveResources: Api.newPost("/sys/roles/{id}/resources")
|
||||
}
|
||||
|
||||
export const accountApi = {
|
||||
list: Api.create("/sys/accounts", 'get'),
|
||||
save: Api.create("/sys/accounts", 'post'),
|
||||
update: Api.create("/sys/accounts/{id}", 'put'),
|
||||
del: Api.create("/sys/accounts/{id}", 'delete'),
|
||||
changeStatus: Api.create("/sys/accounts/change-status/{id}/{status}", 'put'),
|
||||
roleIds: Api.create("/sys/accounts/{id}/roleIds", 'get'),
|
||||
roles: Api.create("/sys/accounts/{id}/roles", 'get'),
|
||||
resources: Api.create("/sys/accounts/{id}/resources", 'get'),
|
||||
saveRoles: Api.create("/sys/accounts/roles", 'post')
|
||||
list: Api.newGet("/sys/accounts"),
|
||||
save: Api.newPost("/sys/accounts"),
|
||||
update: Api.newPut("/sys/accounts/{id}"),
|
||||
del: Api.newDelete("/sys/accounts/{id}"),
|
||||
changeStatus: Api.newPut("/sys/accounts/change-status/{id}/{status}"),
|
||||
roleIds: Api.newGet("/sys/accounts/{id}/roleIds"),
|
||||
roles: Api.newGet("/sys/accounts/{id}/roles"),
|
||||
resources: Api.newGet("/sys/accounts/{id}/resources"),
|
||||
saveRoles: Api.newPost("/sys/accounts/roles")
|
||||
}
|
||||
|
||||
export const configApi = {
|
||||
list: Api.create("/sys/configs", 'get'),
|
||||
save: Api.create("/sys/configs", 'post'),
|
||||
getValue: Api.create("/sys/configs/value", 'get'),
|
||||
list: Api.newGet("/sys/configs"),
|
||||
save: Api.newPost("/sys/configs"),
|
||||
getValue: Api.newGet("/sys/configs/value"),
|
||||
}
|
||||
|
||||
export const logApi = {
|
||||
list: Api.create("/syslogs", "get")
|
||||
list: Api.newGet("/syslogs")
|
||||
}
|
||||
@@ -18,8 +18,8 @@ require (
|
||||
golang.org/x/crypto v0.8.0 // ssh
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
// gorm
|
||||
gorm.io/driver/mysql v1.4.7
|
||||
gorm.io/gorm v1.24.6
|
||||
gorm.io/driver/mysql v1.5.0
|
||||
gorm.io/gorm v1.25.0
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
@@ -39,6 +39,10 @@ func (a *Account) Login(rc *req.Ctx) {
|
||||
biz.IsTrue(captcha.Verify(loginForm.Cid, loginForm.Captcha), "验证码错误")
|
||||
}
|
||||
|
||||
clientIp := rc.GinCtx.ClientIP()
|
||||
rc.ReqParam = loginForm.Username
|
||||
rc.ReqParam = fmt.Sprintf("username: %s | ip: %s", loginForm.Username, clientIp)
|
||||
|
||||
originPwd, err := utils.DefaultRsaDecrypt(loginForm.Password, true)
|
||||
biz.ErrIsNilAppendErr(err, "解密密码错误: %s")
|
||||
|
||||
@@ -50,6 +54,20 @@ func (a *Account) Login(rc *req.Ctx) {
|
||||
|
||||
// 校验密码强度是否符合
|
||||
biz.IsTrueBy(CheckPasswordLever(originPwd), biz.NewBizErrCode(401, "您的密码安全等级较低,请修改后重新登录"))
|
||||
// 保存登录消息
|
||||
go a.saveLogin(account, clientIp)
|
||||
|
||||
rc.ResData = map[string]interface{}{
|
||||
"token": req.CreateToken(account.Id, account.Username),
|
||||
"name": account.Name,
|
||||
"username": account.Username,
|
||||
"lastLoginTime": account.LastLoginTime,
|
||||
"lastLoginIp": account.LastLoginIp,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Account) GetPermissions(rc *req.Ctx) {
|
||||
account := rc.LoginAccount
|
||||
|
||||
var resources vo.AccountResourceVOList
|
||||
// 获取账号菜单资源
|
||||
@@ -66,23 +84,9 @@ func (a *Account) Login(rc *req.Ctx) {
|
||||
}
|
||||
// 保存该账号的权限codes
|
||||
req.SavePermissionCodes(account.Id, permissions)
|
||||
|
||||
clientIp := rc.GinCtx.ClientIP()
|
||||
// 保存登录消息
|
||||
go a.saveLogin(account, clientIp)
|
||||
|
||||
rc.ReqParam = fmt.Sprintf("登录ip: %s", clientIp)
|
||||
// 赋值loginAccount 主要用于记录操作日志,因为操作日志保存请求上下文没有该信息不保存日志
|
||||
rc.LoginAccount = &model.LoginAccount{Id: account.Id, Username: account.Username}
|
||||
|
||||
rc.ResData = map[string]interface{}{
|
||||
"token": req.CreateToken(account.Id, account.Username),
|
||||
"name": account.Name,
|
||||
"username": account.Username,
|
||||
"lastLoginTime": account.LastLoginTime,
|
||||
"lastLoginIp": account.LastLoginIp,
|
||||
"menus": menus.ToTrees(0),
|
||||
"permissions": permissions,
|
||||
"menus": menus.ToTrees(0),
|
||||
"permissions": permissions,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +147,7 @@ func (a *Account) saveLogin(account *entity.Account, ip string) {
|
||||
// 创建登录消息
|
||||
loginMsg := &entity.Msg{
|
||||
RecipientId: int64(account.Id),
|
||||
Msg: fmt.Sprintf("于%s登录", now.Format("2006-01-02 15:04:05")),
|
||||
Msg: fmt.Sprintf("于[%s]-[%s]登录", ip, now.Format("2006-01-02 15:04:05")),
|
||||
Type: 1,
|
||||
}
|
||||
loginMsg.CreateTime = &now
|
||||
|
||||
@@ -27,6 +27,11 @@ func InitAccountRouter(router *gin.RouterGroup) {
|
||||
Handle(a.Login)
|
||||
})
|
||||
|
||||
// 获取个人账号的权限资源信息
|
||||
account.GET("/permissions", func(c *gin.Context) {
|
||||
req.NewCtxWithGin(c).Handle(a.GetPermissions)
|
||||
})
|
||||
|
||||
changePwdLog := req.NewLogInfo("用户修改密码").WithSave(true)
|
||||
account.POST("change-pwd", func(g *gin.Context) {
|
||||
req.NewCtxWithGin(g).
|
||||
|
||||
Reference in New Issue
Block a user