From 89e12678eb69d4f28a2916799c2db6fd45a4d973 Mon Sep 17 00:00:00 2001 From: "meilin.huang" <954537473@qq.com> Date: Mon, 13 May 2024 19:55:43 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=BC=95=E5=85=A5dayjs=E3=80=81?= =?UTF-8?q?=E6=96=B0=E5=A2=9ErefreshToken=E6=97=A0=E6=84=9F=E5=88=B7?= =?UTF-8?q?=E6=96=B0=E3=80=81=E5=9B=A2=E9=98=9F=E6=96=B0=E5=A2=9E=E6=9C=89?= =?UTF-8?q?=E6=95=88=E6=9C=9F=E3=80=81=E6=95=B0=E6=8D=AE=E5=BA=93=E7=AD=89?= =?UTF-8?q?=E9=97=AE=E9=A2=98=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mayfly_go_web/package.json | 1 + mayfly_go_web/src/common/config.ts | 2 +- mayfly_go_web/src/common/openApi.ts | 1 + mayfly_go_web/src/common/request.ts | 1 + mayfly_go_web/src/common/utils/date.ts | 31 ---- mayfly_go_web/src/common/utils/format.ts | 119 ++------------ mayfly_go_web/src/common/utils/storage.ts | 10 ++ .../src/components/pagetable/index.ts | 4 +- .../components/terminal-rdp/MachineRdp.vue | 27 +++- mayfly_go_web/src/hooks/useRequest.ts | 150 +++++++++++------- mayfly_go_web/src/store/themeConfig.ts | 4 +- .../src/views/flow/ProcinstDetail.vue | 6 +- .../views/flow/components/ProcdefTasks.vue | 4 +- mayfly_go_web/src/views/home/Home.vue | 14 +- .../views/login/component/AccountLogin.vue | 111 +++++++------ mayfly_go_web/src/views/ops/db/DbList.vue | 6 +- .../src/views/ops/db/DbRestoreList.vue | 8 +- .../src/views/ops/db/InstanceList.vue | 6 +- .../db/component/sqleditor/DbSqlEditor.vue | 45 +++--- .../db/component/sqleditor/SqlExecDialog.vue | 6 +- .../ops/db/component/table/DbTableData.vue | 25 ++- .../db/component/table/DbTableDataForm.vue | 52 +++--- .../ops/db/component/table/DbTableDataOp.vue | 11 -- .../ops/db/component/table/DbTablesOp.vue | 38 ++--- mayfly_go_web/src/views/ops/db/db.ts | 1 - .../src/views/ops/machine/MachineList.vue | 7 +- .../src/views/ops/machine/MachineOp.vue | 6 +- .../src/views/ops/machine/MachineRec.vue | 8 +- .../src/views/ops/redis/RedisList.vue | 6 +- .../src/views/ops/tag/TagTreeList.vue | 6 +- mayfly_go_web/src/views/ops/tag/TeamList.vue | 60 +++++-- .../src/views/system/account/AccountList.vue | 4 +- .../views/system/resource/ResourceList.vue | 6 +- .../src/views/system/role/ShowResource.vue | 4 +- server/config.yml.example | 8 +- server/go.mod | 2 +- server/internal/auth/api/account_login.go | 32 ++-- server/internal/auth/api/common.go | 20 +-- server/internal/auth/router/router.go | 2 + server/internal/tag/api/vo/team.go | 6 +- server/internal/tag/application/dto/team.go | 10 +- server/internal/tag/application/team.go | 7 +- server/internal/tag/domain/entity/team.go | 10 +- .../tag/infrastructure/cache/tag_tree.go | 2 +- .../persistence/tag_tree_relate.go | 14 +- server/pkg/config/app.go | 2 +- server/pkg/config/jwt.go | 9 +- server/pkg/errorx/bizerror.go | 9 +- server/pkg/model/json_time.go | 3 +- server/pkg/req/permission_handler.go | 2 +- server/pkg/req/token.go | 24 ++- server/resources/data/mayfly-go.sqlite | Bin 315392 -> 311296 bytes server/resources/script/sql/mayfly-go.sql | 4 +- server/resources/script/sql/v1.8/v1.8.4.sql | 4 + 54 files changed, 500 insertions(+), 460 deletions(-) delete mode 100644 mayfly_go_web/src/common/utils/date.ts create mode 100644 server/resources/script/sql/v1.8/v1.8.4.sql diff --git a/mayfly_go_web/package.json b/mayfly_go_web/package.json index de307484..de33f59f 100644 --- a/mayfly_go_web/package.json +++ b/mayfly_go_web/package.json @@ -15,6 +15,7 @@ "axios": "^1.6.2", "clipboard": "^2.0.11", "cropperjs": "^1.6.1", + "dayjs": "^1.11.11", "echarts": "^5.5.0", "element-plus": "^2.7.2", "js-base64": "^3.7.7", diff --git a/mayfly_go_web/src/common/config.ts b/mayfly_go_web/src/common/config.ts index 7e149d18..78856a9f 100644 --- a/mayfly_go_web/src/common/config.ts +++ b/mayfly_go_web/src/common/config.ts @@ -15,7 +15,7 @@ const config = { baseWsUrl: `${(window as any).globalConfig.BaseWsUrl || `${location.protocol == 'https:' ? 'wss:' : 'ws:'}//${getBaseApiUrl()}`}/api`, // 系统版本 - version: 'v1.8.3', + version: 'v1.8.4', }; export default config; diff --git a/mayfly_go_web/src/common/openApi.ts b/mayfly_go_web/src/common/openApi.ts index 8c7477ca..ac376b10 100644 --- a/mayfly_go_web/src/common/openApi.ts +++ b/mayfly_go_web/src/common/openApi.ts @@ -2,6 +2,7 @@ import request from './request'; export default { login: (param: any) => request.post('/auth/accounts/login', param), + refreshToken: (param: any) => request.get('/auth/accounts/refreshToken', param), otpVerify: (param: any) => request.post('/auth/accounts/otp-verify', param), getPublicKey: () => request.get('/common/public-key'), getConfigValue: (params: any) => request.get('/sys/configs/value', params), diff --git a/mayfly_go_web/src/common/request.ts b/mayfly_go_web/src/common/request.ts index bb312c58..6eadc092 100755 --- a/mayfly_go_web/src/common/request.ts +++ b/mayfly_go_web/src/common/request.ts @@ -38,6 +38,7 @@ export enum ResultEnum { PARAM_ERROR = 405, SERVER_ERROR = 500, NO_PERMISSION = 501, + ACCESS_TOKEN_INVALID = 502, // accessToken失效 } export const baseUrl: string = config.baseApiUrl; diff --git a/mayfly_go_web/src/common/utils/date.ts b/mayfly_go_web/src/common/utils/date.ts deleted file mode 100644 index 48ed6ad3..00000000 --- a/mayfly_go_web/src/common/utils/date.ts +++ /dev/null @@ -1,31 +0,0 @@ -export function dateFormat2(fmt: string, date: Date) { - let ret; - const opt = { - 'y+': date.getFullYear().toString(), // 年 - 'M+': (date.getMonth() + 1).toString(), // 月 - 'd+': date.getDate().toString(), // 日 - 'H+': date.getHours().toString(), // 时 - 'm+': date.getMinutes().toString(), // 分 - 's+': date.getSeconds().toString(), // 秒 - 'S+': date.getMilliseconds() ? date.getMilliseconds().toString() : '', // 毫秒 - // 有其他格式化字符需求可以继续添加,必须转化成字符串 - }; - for (const k in opt) { - ret = new RegExp('(' + k + ')').exec(fmt); - if (ret) { - fmt = fmt.replace(ret[1], ret[1].length == 1 ? opt[k] : opt[k].padStart(ret[1].length, '0')); - } - } - return fmt; -} - -export function dateStrFormat(fmt: string, dateStr: string) { - return dateFormat2(fmt, new Date(dateStr)); -} - -export function dateFormat(dateStr: string) { - if (!dateStr) { - return ''; - } - return dateFormat2('yyyy-MM-dd HH:mm:ss', new Date(dateStr)); -} diff --git a/mayfly_go_web/src/common/utils/format.ts b/mayfly_go_web/src/common/utils/format.ts index 2f6e34ad..563662d1 100644 --- a/mayfly_go_web/src/common/utils/format.ts +++ b/mayfly_go_web/src/common/utils/format.ts @@ -1,3 +1,18 @@ +import dayjs from 'dayjs'; + +/** + * 格式化日期 + * @param date 日期 字符串 Date 时间戳等 + * @param format 格式化格式 默认 YYYY-MM-DD HH:mm:ss + * @returns 格式化后内容 + */ +export function formatDate(date: any, format: string = 'YYYY-MM-DD HH:mm:ss') { + if (!date) { + return ''; + } + return dayjs(date).format(format); +} + /** * 格式化字节单位 * @param size byte size @@ -46,110 +61,6 @@ export function convertToBytes(sizeStr: string) { return bytes; } -/* - * 年(Y) 可用1-4个占位符 - * 月(m)、日(d)、小时(H)、分(M)、秒(S) 可用1-2个占位符 - * 星期(W) 可用1-3个占位符 - * 季度(q为阿拉伯数字,Q为中文数字)可用1或4个占位符 - * - * let date = new Date() - * formatDate(date, "YYYY-mm-dd HH:MM:SS") // 2020-02-09 14:04:23 - * formatDate(date, "YYYY-mm-dd HH:MM:SS Q") // 2020-02-09 14:09:03 一 - * formatDate(date, "YYYY-mm-dd HH:MM:SS WWW") // 2020-02-09 14:45:12 星期日 - * formatDate(date, "YYYY-mm-dd HH:MM:SS QQQQ") // 2020-02-09 14:09:36 第一季度 - * formatDate(date, "YYYY-mm-dd HH:MM:SS WWW QQQQ") // 2020-02-09 14:46:12 星期日 第一季度 - */ -export function formatDate(date: Date, format: string) { - let we = date.getDay(); // 星期 - let qut = Math.floor((date.getMonth() + 3) / 3).toString(); // 季度 - const opt: any = { - 'Y+': date.getFullYear().toString(), // 年 - 'm+': (date.getMonth() + 1).toString(), // 月(月份从0开始,要+1) - 'd+': date.getDate().toString(), // 日 - 'H+': date.getHours().toString(), // 时 - 'M+': date.getMinutes().toString(), // 分 - 'S+': date.getSeconds().toString(), // 秒 - 'q+': qut, // 季度 - }; - // 中文数字 (星期) - const week: any = { - '0': '日', - '1': '一', - '2': '二', - '3': '三', - '4': '四', - '5': '五', - '6': '六', - }; - // 中文数字(季度) - const quarter: any = { - '1': '一', - '2': '二', - '3': '三', - '4': '四', - }; - if (/(W+)/.test(format)) format = format.replace(RegExp.$1, RegExp.$1.length > 1 ? (RegExp.$1.length > 2 ? '星期' + week[we] : '周' + week[we]) : week[we]); - if (/(Q+)/.test(format)) format = format.replace(RegExp.$1, RegExp.$1.length == 4 ? '第' + quarter[qut] + '季度' : quarter[qut]); - for (let k in opt) { - let r = new RegExp('(' + k + ')').exec(format); - // 若输入的长度不为1,则前面补零 - if (r) format = format.replace(r[1], RegExp.$1.length == 1 ? opt[k] : opt[k].padStart(RegExp.$1.length, '0')); - } - return format; -} - -/** - * 10秒: 10 * 1000 - * 1分: 60 * 1000 - * 1小时: 60 * 60 * 1000 - * 24小时:60 * 60 * 24 * 1000 - * 3天: 60 * 60* 24 * 1000 * 3 - * - * let data = new Date() - * formatPast(data) // 刚刚 - * formatPast(data - 11 * 1000) // 11秒前 - * formatPast(data - 2 * 60 * 1000) // 2分钟前 - * formatPast(data - 60 * 60 * 2 * 1000) // 2小时前 - * formatPast(data - 60 * 60 * 2 * 1000) // 2小时前 - * formatPast(data - 60 * 60 * 71 * 1000) // 2天前 - * formatPast("2020-06-01") // 2020-06-01 - * formatPast("2020-06-01", "YYYY-mm-dd HH:MM:SS WWW QQQQ") // 2020-06-01 08:00:00 星期一 第二季度 - */ -export function formatPast(param: any, format: string = 'YYYY-mm-dd') { - // 传入格式处理、存储转换值 - let t: any, s: any; - // 获取js 时间戳 - let time: any = new Date().getTime(); - // 是否是对象 - typeof param === 'string' || 'object' ? (t = new Date(param).getTime()) : (t = param); - // 当前时间戳 - 传入时间戳 - time = Number.parseInt(`${time - t}`); - if (time < 10000) { - // 10秒内 - return '刚刚'; - } else if (time < 60000 && time >= 10000) { - // 超过10秒少于1分钟内 - s = Math.floor(time / 1000); - return `${s}秒前`; - } else if (time < 3600000 && time >= 60000) { - // 超过1分钟少于1小时 - s = Math.floor(time / 60000); - return `${s}分钟前`; - } else if (time < 86400000 && time >= 3600000) { - // 超过1小时少于24小时 - s = Math.floor(time / 3600000); - return `${s}小时前`; - } else if (time < 259200000 && time >= 86400000) { - // 超过1天少于3天内 - s = Math.floor(time / 86400000); - return `${s}天前`; - } else { - // 超过3天 - let date = typeof param === 'string' || 'object' ? new Date(param) : param; - return formatDate(date, format); - } -} - /** * 格式化指定时间数为人性化可阅读的内容(默认time为秒单位) * diff --git a/mayfly_go_web/src/common/utils/storage.ts b/mayfly_go_web/src/common/utils/storage.ts index f935d48b..d73d2bc3 100644 --- a/mayfly_go_web/src/common/utils/storage.ts +++ b/mayfly_go_web/src/common/utils/storage.ts @@ -1,6 +1,7 @@ import { randomUuid } from './string'; const TokenKey = 'm-token'; +const RefreshTokenKey = 'm-refresh-token'; const UserKey = 'm-user'; const TagViewsKey = 'm-tagViews'; const ClientIdKey = 'm-clientId'; @@ -15,6 +16,14 @@ export function saveToken(token: string) { setLocal(TokenKey, token); } +export function getRefreshToken(): string { + return getLocal(RefreshTokenKey); +} + +export function saveRefreshToken(refreshToken: string) { + return setLocal(RefreshTokenKey, refreshToken); +} + // 获取登录用户基础信息 export function getUser() { return getLocal(UserKey); @@ -39,6 +48,7 @@ export function getThemeConfig() { export function clearUser() { removeLocal(TokenKey); removeLocal(UserKey); + removeLocal(RefreshTokenKey); } export function getTagViews() { diff --git a/mayfly_go_web/src/components/pagetable/index.ts b/mayfly_go_web/src/components/pagetable/index.ts index c7098852..27a313d7 100644 --- a/mayfly_go_web/src/components/pagetable/index.ts +++ b/mayfly_go_web/src/components/pagetable/index.ts @@ -1,5 +1,5 @@ import EnumValue from '@/common/Enum'; -import { dateFormat } from '@/common/utils/date'; +import { formatDate } from '@/common/utils/format'; import { getValueByPath } from '@/common/utils/object'; import { getTextWidth } from '@/common/utils/string'; @@ -172,7 +172,7 @@ export class TableColumn { */ isTime(): TableColumn { this.setFormatFunc((data: any, prop: string) => { - return dateFormat(getValueByPath(data, prop)); + return formatDate(getValueByPath(data, prop)); }); return this; } diff --git a/mayfly_go_web/src/components/terminal-rdp/MachineRdp.vue b/mayfly_go_web/src/components/terminal-rdp/MachineRdp.vue index 53a9f453..cb3c02ab 100644 --- a/mayfly_go_web/src/components/terminal-rdp/MachineRdp.vue +++ b/mayfly_go_web/src/components/terminal-rdp/MachineRdp.vue @@ -24,8 +24,33 @@ + + + + - + + (api: Api, params: any = null, reqOptions: Request return { execute: async function () { - try { - await uaf.execute(true); - } catch (e: any) { - const rejectPromise = Promise.reject(e); - - if (e?.name == 'AbortError') { - console.log('请求已取消'); - return rejectPromise; - } - - const respStatus = uaf.response.value?.status; - if (respStatus == 404) { - ElMessage.error('请求接口不存在'); - return rejectPromise; - } - if (respStatus == 500) { - ElMessage.error('服务器响应异常'); - return rejectPromise; - } - - console.error(e); - ElMessage.error('网络请求错误'); - return rejectPromise; - } - - const result: Result = uaf.data.value as any; - if (!result) { - ElMessage.error('网络请求失败'); - return Promise.reject(result); - } - - // 如果返回为成功结果,则将结果的data赋值给响应式data - if (result.code === ResultEnum.SUCCESS) { - uaf.data.value = result.data; - return; - } - - // 如果提示没有权限,则跳转至无权限页面 - if (result.code === ResultEnum.NO_PERMISSION) { - router.push({ - path: URL_401, - }); - return Promise.reject(result); - } - - // 如果返回的code不为成功,则会返回对应的错误msg,则直接统一通知即可。忽略登录超时或没有权限的提示(直接跳转至401页面) - if (result.msg && result?.code != ResultEnum.NO_PERMISSION) { - ElMessage.error(result.msg); - uaf.error.value = new Error(result.msg); - } - - return Promise.reject(result); + return execUaf(uaf); }, isFetching: uaf.isFetching, data: uaf.data, abort: uaf.abort, }; } + +let refreshingToken = false; +let queue: any[] = []; + +async function execUaf(uaf: any) { + try { + await uaf.execute(true); + } catch (e: any) { + const rejectPromise = Promise.reject(e); + + if (e?.name == 'AbortError') { + console.log('请求已取消'); + return rejectPromise; + } + + const respStatus = uaf.response.value?.status; + if (respStatus == 404) { + ElMessage.error('请求接口不存在'); + return rejectPromise; + } + if (respStatus == 500) { + ElMessage.error('服务器响应异常'); + return rejectPromise; + } + + console.error(e); + ElMessage.error('网络请求错误'); + return rejectPromise; + } + + const result: Result = uaf.data.value as any; + if (!result) { + ElMessage.error('网络请求失败'); + return Promise.reject(result); + } + + const resultCode = result.code; + + // 如果返回为成功结果,则将结果的data赋值给响应式data + if (resultCode === ResultEnum.SUCCESS) { + uaf.data.value = result.data; + return; + } + + // 如果是accessToken失效,则使用refreshToken刷新token + if (resultCode == ResultEnum.ACCESS_TOKEN_INVALID) { + if (refreshingToken) { + // 请求加入队列等待, 防止并发多次请求refreshToken + return new Promise((resolve) => { + queue.push(() => { + resolve(execUaf(uaf)); + }); + }); + } + + try { + refreshingToken = true; + const res = await openApi.refreshToken({ refresh_token: getRefreshToken() }); + saveToken(res.token); + saveRefreshToken(res.refresh_token); + // 重新缓存后端用户权限code + await openApi.getPermissions(); + + // 执行accessToken失效的请求 + queue.forEach((resolve: any) => { + resolve(); + }); + } catch (e: any) { + clearUser(); + } finally { + refreshingToken = false; + queue = []; + } + + await execUaf(uaf); + return; + } + + // 如果提示没有权限,则跳转至无权限页面 + if (resultCode === ResultEnum.NO_PERMISSION) { + router.push({ + path: URL_401, + }); + return Promise.reject(result); + } + + // 如果返回的code不为成功,则会返回对应的错误msg,则直接统一通知即可。忽略登录超时或没有权限的提示(直接跳转至401页面) + if (result.msg && resultCode != ResultEnum.NO_PERMISSION) { + ElMessage.error(result.msg); + uaf.error.value = new Error(result.msg); + } + + return Promise.reject(result); +} diff --git a/mayfly_go_web/src/store/themeConfig.ts b/mayfly_go_web/src/store/themeConfig.ts index bcf3aab3..df360465 100644 --- a/mayfly_go_web/src/store/themeConfig.ts +++ b/mayfly_go_web/src/store/themeConfig.ts @@ -1,5 +1,5 @@ import { defineStore } from 'pinia'; -import { dateFormat2 } from '@/common/utils/date'; +import { formatDate } from '@/common/utils/format'; import { useUserInfo } from '@/store/userInfo'; import { getSysStyleConfig } from '@/common/sysconfig'; import { getLocal, getThemeConfig } from '@/common/utils/storage'; @@ -191,7 +191,7 @@ export const useThemeConfig = defineStore('themeConfig', { }, // 设置水印时间为当前时间 setWatermarkNowTime() { - this.themeConfig.watermarkText[1] = dateFormat2('yyyy-MM-dd HH:mm:ss', new Date()); + this.themeConfig.watermarkText[1] = formatDate(new Date()); }, // 切换暗黑模式 switchDark(isDark: boolean) { diff --git a/mayfly_go_web/src/views/flow/ProcinstDetail.vue b/mayfly_go_web/src/views/flow/ProcinstDetail.vue index 2fb747d1..22d8f28a 100755 --- a/mayfly_go_web/src/views/flow/ProcinstDetail.vue +++ b/mayfly_go_web/src/views/flow/ProcinstDetail.vue @@ -17,11 +17,11 @@ - {{ dateFormat(procinst.createTime) }} + {{ formatDate(procinst.createTime) }}
{{ formatTime(procinst.duration) }} - {{ dateFormat(procinst.endTime) }} + {{ formatDate(procinst.endTime) }}
@@ -86,11 +86,11 @@ import { procinstApi } from './api'; import { ElMessage } from 'element-plus'; import DrawerHeader from '@/components/drawer-header/DrawerHeader.vue'; import { FlowBizType, ProcinstBizStatus, ProcinstTaskStatus, ProcinstStatus } from './enums'; -import { dateFormat } from '@/common/utils/date'; import ProcdefTasks from './components/ProcdefTasks.vue'; import { formatTime } from '@/common/utils/format'; import EnumTag from '@/components/enumtag/EnumTag.vue'; import AccountInfo from '@/views/system/account/components/AccountInfo.vue'; +import { formatDate } from '@/common/utils/format'; const DbSqlExecBiz = defineAsyncComponent(() => import('./flowbiz/DbSqlExecBiz.vue')); const RedisRunWriteCmdBiz = defineAsyncComponent(() => import('./flowbiz/RedisRunWriteCmdBiz.vue')); diff --git a/mayfly_go_web/src/views/flow/components/ProcdefTasks.vue b/mayfly_go_web/src/views/flow/components/ProcdefTasks.vue index 4abe109b..4bd14367 100755 --- a/mayfly_go_web/src/views/flow/components/ProcdefTasks.vue +++ b/mayfly_go_web/src/views/flow/components/ProcdefTasks.vue @@ -3,7 +3,7 @@ @@ -14,7 +14,7 @@ import { toRefs, reactive, watch, onMounted } from 'vue'; import { accountApi } from '../../system/api'; import { ProcinstTaskStatus } from '../enums'; -import { dateFormat } from '@/common/utils/date'; +import { formatDate } from '@/common/utils/format'; import { ElSteps, ElStep } from 'element-plus'; const props = defineProps({ diff --git a/mayfly_go_web/src/views/home/Home.vue b/mayfly_go_web/src/views/home/Home.vue index ffd867d8..b528a3dc 100644 --- a/mayfly_go_web/src/views/home/Home.vue +++ b/mayfly_go_web/src/views/home/Home.vue @@ -35,7 +35,7 @@
上次登录时间:
-
{{ dateFormat(userInfo.lastLoginTime) }}
+
{{ formatDate(userInfo.lastLoginTime) }}
@@ -84,7 +84,7 @@ @@ -118,7 +118,7 @@ @@ -159,7 +159,7 @@ @@ -198,7 +198,7 @@ @@ -228,7 +228,7 @@ @@ -257,7 +257,7 @@ import { useRouter } from 'vue-router'; import { storeToRefs } from 'pinia'; import { useUserInfo } from '@/store/userInfo'; import { personApi } from '../personal/api'; -import { dateFormat } from '@/common/utils/date'; +import { formatDate } from '@/common/utils/format'; import SvgIcon from '@/components/svgIcon/index.vue'; import { TagResourceTypeEnum } from '@/common/commonEnum'; import { resourceOpLogApi } from '../ops/tag/api'; diff --git a/mayfly_go_web/src/views/login/component/AccountLogin.vue b/mayfly_go_web/src/views/login/component/AccountLogin.vue index 61776621..68c5722c 100644 --- a/mayfly_go_web/src/views/login/component/AccountLogin.vue +++ b/mayfly_go_web/src/views/login/component/AccountLogin.vue @@ -132,7 +132,7 @@ import { nextTick, onMounted, ref, toRefs, reactive, computed } from 'vue'; import { useRoute, useRouter } from 'vue-router'; import { ElMessage } from 'element-plus'; import { initRouter } from '@/router/index'; -import { saveToken, saveUser } from '@/common/utils/storage'; +import { getRefreshToken, saveRefreshToken, saveToken, saveUser } from '@/common/utils/storage'; import { formatAxis } from '@/common/utils/format'; import openApi from '@/common/openApi'; import { RsaEncrypt } from '@/common/rsa'; @@ -279,19 +279,20 @@ const login = () => { }; const otpVerify = async () => { - otpFormRef.value.validate(async (valid: boolean) => { - if (!valid) { - return false; - } - try { - state.loading.otpConfirm = true; - const accessToken = await openApi.otpVerify(state.otpDialog.form); - await signInSuccess(accessToken); - state.otpDialog.visible = false; - } finally { - state.loading.otpConfirm = false; - } - }); + try { + await otpFormRef.value.validate(); + } catch (e: any) { + return false; + } + + try { + state.loading.otpConfirm = true; + const res = await openApi.otpVerify(state.otpDialog.form); + await signInSuccess(res.token, res.refresh_token); + state.otpDialog.visible = false; + } finally { + state.loading.otpConfirm = false; + } }; // 登录 @@ -327,22 +328,23 @@ const onSignIn = async () => { }; const updateUserInfo = async () => { - baseInfoFormRef.value.validate(async (valid: boolean) => { - if (!valid) { - return false; - } - try { - state.loading.updateUserConfirm = true; - const form = state.baseInfoDialog.form; - await personApi.updateAccount.request(state.baseInfoDialog.form); - state.baseInfoDialog.visible = false; - useUserInfo().userInfo.username = form.username; - useUserInfo().userInfo.name = form.name; - await toIndex(); - } finally { - state.loading.updateUserConfirm = false; - } - }); + try { + await baseInfoFormRef.value.validate(); + } catch (e: any) { + return false; + } + + try { + state.loading.updateUserConfirm = true; + const form = state.baseInfoDialog.form; + await personApi.updateAccount.request(state.baseInfoDialog.form); + state.baseInfoDialog.visible = false; + useUserInfo().userInfo.username = form.username; + useUserInfo().userInfo.name = form.name; + await toIndex(); + } finally { + state.loading.updateUserConfirm = false; + } }; const loginResDeal = (loginRes: any) => { @@ -366,7 +368,7 @@ const loginResDeal = (loginRes: any) => { const token = loginRes.token; // 如果不需要 otp校验,则该token即为accessToken,否则为otp校验token if (loginRes.otp == -1) { - signInSuccess(token); + signInSuccess(token, loginRes.refresh_token); return; } @@ -379,12 +381,16 @@ const loginResDeal = (loginRes: any) => { }; // 登录成功后的跳转 -const signInSuccess = async (accessToken: string = '') => { +const signInSuccess = async (accessToken: string = '', refreshToken = '') => { if (!accessToken) { accessToken = getToken(); } + if (!refreshToken) { + refreshToken = getRefreshToken(); + } // 存储 token 到浏览器缓存 saveToken(accessToken); + saveRefreshToken(refreshToken); // 初始化路由 await initRouter(); @@ -415,26 +421,27 @@ const toIndex = async () => { }, 300); }; -const changePwd = () => { - changePwdFormRef.value.validate(async (valid: boolean) => { - if (!valid) { - return false; - } - try { - state.loading.changePwd = true; - const form = state.changePwdDialog.form; - const changePwdReq: any = { ...form }; - changePwdReq.oldPassword = await RsaEncrypt(form.oldPassword); - changePwdReq.newPassword = await RsaEncrypt(form.newPassword); - await openApi.changePwd(changePwdReq); - ElMessage.success('密码修改成功, 新密码已填充至登录密码框'); - state.loginForm.password = state.changePwdDialog.form.newPassword; - state.changePwdDialog.visible = false; - getCaptcha(); - } finally { - state.loading.changePwd = false; - } - }); +const changePwd = async () => { + try { + await changePwdFormRef.value.validate(); + } catch (e: any) { + return false; + } + + try { + state.loading.changePwd = true; + const form = state.changePwdDialog.form; + const changePwdReq: any = { ...form }; + changePwdReq.oldPassword = await RsaEncrypt(form.oldPassword); + changePwdReq.newPassword = await RsaEncrypt(form.newPassword); + await openApi.changePwd(changePwdReq); + ElMessage.success('密码修改成功, 新密码已填充至登录密码框'); + state.loginForm.password = state.changePwdDialog.form.newPassword; + state.changePwdDialog.visible = false; + getCaptcha(); + } finally { + state.loading.changePwd = false; + } }; const cancelChangePwd = () => { diff --git a/mayfly_go_web/src/views/ops/db/DbList.vue b/mayfly_go_web/src/views/ops/db/DbList.vue index 5d1f2674..e6aee4ee 100644 --- a/mayfly_go_web/src/views/ops/db/DbList.vue +++ b/mayfly_go_web/src/views/ops/db/DbList.vue @@ -187,10 +187,10 @@ {{ infoDialog.data?.database }} {{ infoDialog.data?.remark }} - {{ dateFormat(infoDialog.data?.createTime) }} + {{ formatDate(infoDialog.data?.createTime) }} {{ infoDialog.data?.creator }} - {{ dateFormat(infoDialog.data?.updateTime) }} + {{ formatDate(infoDialog.data?.updateTime) }} {{ infoDialog.data?.modifier }}
@@ -205,7 +205,7 @@ import { dbApi } from './api'; import config from '@/common/config'; import { joinClientParams } from '@/common/request'; import { isTrue } from '@/common/assert'; -import { dateFormat } from '@/common/utils/date'; +import { formatDate } from '@/common/utils/format'; import PageTable from '@/components/pagetable/PageTable.vue'; import { TableColumn } from '@/components/pagetable'; import { hasPerms } from '@/components/auth/auth'; diff --git a/mayfly_go_web/src/views/ops/db/DbRestoreList.vue b/mayfly_go_web/src/views/ops/db/DbRestoreList.vue index 7fe348a9..86b02652 100644 --- a/mayfly_go_web/src/views/ops/db/DbRestoreList.vue +++ b/mayfly_go_web/src/views/ops/db/DbRestoreList.vue @@ -45,14 +45,14 @@ {{ infoDialog.data.dbName }} {{ - dateFormat(infoDialog.data.pointInTime) + formatDate(infoDialog.data.pointInTime) }} {{ infoDialog.data.dbBackupHistoryName }} - {{ dateFormat(infoDialog.data.startTime) }} + {{ formatDate(infoDialog.data.startTime) }} {{ infoDialog.data.enabledDesc }} - {{ dateFormat(infoDialog.data.lastTime) }} + {{ formatDate(infoDialog.data.lastTime) }} {{ infoDialog.data.lastResult }}
@@ -66,7 +66,7 @@ import PageTable from '@/components/pagetable/PageTable.vue'; import { TableColumn } from '@/components/pagetable'; import { SearchItem } from '@/components/SearchForm'; import { ElMessage, ElMessageBox } from 'element-plus'; -import { dateFormat } from '@/common/utils/date'; +import { formatDate } from '@/common/utils/format'; const DbRestoreEdit = defineAsyncComponent(() => import('./DbRestoreEdit.vue')); const pageTableRef: Ref = ref(null); diff --git a/mayfly_go_web/src/views/ops/db/InstanceList.vue b/mayfly_go_web/src/views/ops/db/InstanceList.vue index 231003be..d5c6ecdd 100644 --- a/mayfly_go_web/src/views/ops/db/InstanceList.vue +++ b/mayfly_go_web/src/views/ops/db/InstanceList.vue @@ -53,10 +53,10 @@ {{ infoDialog.data.sshTunnelMachineId > 0 ? '是' : '否' }} - {{ dateFormat(infoDialog.data.createTime) }} + {{ formatDate(infoDialog.data.createTime) }} {{ infoDialog.data.creator }} - {{ dateFormat(infoDialog.data.updateTime) }} + {{ formatDate(infoDialog.data.updateTime) }} {{ infoDialog.data.modifier }} @@ -76,7 +76,7 @@ import { defineAsyncComponent, onMounted, reactive, ref, Ref, toRefs } from 'vue'; import { ElMessage, ElMessageBox } from 'element-plus'; import { dbApi } from './api'; -import { dateFormat } from '@/common/utils/date'; +import { formatDate } from '@/common/utils/format'; import PageTable from '@/components/pagetable/PageTable.vue'; import { TableColumn } from '@/components/pagetable'; import { hasPerms } from '@/components/auth/auth'; diff --git a/mayfly_go_web/src/views/ops/db/component/sqleditor/DbSqlEditor.vue b/mayfly_go_web/src/views/ops/db/component/sqleditor/DbSqlEditor.vue index fe08c5a4..56c8ea67 100644 --- a/mayfly_go_web/src/views/ops/db/component/sqleditor/DbSqlEditor.vue +++ b/mayfly_go_web/src/views/ops/db/component/sqleditor/DbSqlEditor.vue @@ -296,44 +296,37 @@ const onRunSql = async (newTab = false) => { notBlank(sql && sql.trim(), '请选中需要执行的sql'); // 去除字符串前的空格、换行等 sql = sql.replace(/(^\s*)/g, ''); - let execRemark = ''; - let canRun = true; // 简单截取前十个字符 const sqlPrefix = sql.slice(0, 10).toLowerCase(); - if ( + const nonQuery = sqlPrefix.startsWith('update') || sqlPrefix.startsWith('insert') || sqlPrefix.startsWith('delete') || sqlPrefix.startsWith('alert') || sqlPrefix.startsWith('drop') || - sqlPrefix.startsWith('create') - ) { - const res: any = await ElMessageBox.prompt('请输入备注', 'Tip', { - confirmButtonText: '确定', - cancelButtonText: '取消', - inputPattern: /^[\s\S]*.*[^\s][\s\S]*$/, - inputErrorMessage: '请输入执行该sql的备注信息', - }); - execRemark = res.value; - if (!execRemark) { - canRun = false; + sqlPrefix.startsWith('create'); + + // 启用工单审批 + if (nonQuery && getNowDbInst().flowProcdef) { + try { + getNowDbInst().promptExeSql(props.dbName, sql, null, () => { + ElMessage.success('工单提交成功'); + }); + } catch (e) { + ElMessage.success('工单提交失败'); } - } - if (!canRun) { return; } - // 启用工单审批 - if (execRemark && getNowDbInst().flowProcdef) { - try { - await getNowDbInst().runSql(props.dbName, sql, execRemark); - ElMessage.success('工单提交成功'); - return; - } catch (e) { - ElMessage.success('工单提交失败'); - return; - } + let execRemark; + if (nonQuery) { + const res: any = await ElMessageBox.prompt('请输入备注', 'Tip', { + confirmButtonText: '确定', + cancelButtonText: '取消', + inputErrorMessage: '输入执行该sql的备注信息', + }); + execRemark = res.value; } let execRes: ExecResTab; diff --git a/mayfly_go_web/src/views/ops/db/component/sqleditor/SqlExecDialog.vue b/mayfly_go_web/src/views/ops/db/component/sqleditor/SqlExecDialog.vue index f203a4d6..cab73478 100644 --- a/mayfly_go_web/src/views/ops/db/component/sqleditor/SqlExecDialog.vue +++ b/mayfly_go_web/src/views/ops/db/component/sqleditor/SqlExecDialog.vue @@ -66,6 +66,8 @@ const runSql = async () => { try { state.btnLoading = true; + runSuccess = true; + const res = await dbApi.sqlExec.request({ id: props.dbId, db: props.db, @@ -75,7 +77,6 @@ const runSql = async () => { // 存在流程审批 if (props.flowProcdef) { - runSuccess = false; ElMessage.success('工单提交成功'); return; } @@ -87,7 +88,6 @@ const runSql = async () => { } } - runSuccess = true; ElMessage.success('执行成功'); } catch (e) { runSuccess = false; @@ -96,9 +96,9 @@ const runSql = async () => { if (props.runSuccessCallback) { props.runSuccessCallback(); } + cancel(); } state.btnLoading = false; - cancel(); } }; diff --git a/mayfly_go_web/src/views/ops/db/component/table/DbTableData.vue b/mayfly_go_web/src/views/ops/db/component/table/DbTableData.vue index 947fee06..12b2fdce 100644 --- a/mayfly_go_web/src/views/ops/db/component/table/DbTableData.vue +++ b/mayfly_go_web/src/views/ops/db/component/table/DbTableData.vue @@ -161,7 +161,7 @@ import { DbInst } from '@/views/ops/db/db'; import { Contextmenu, ContextmenuItem } from '@/components/contextmenu'; import SvgIcon from '@/components/svgIcon/index.vue'; import { exportCsv, exportFile } from '@/common/utils/export'; -import { dateStrFormat } from '@/common/utils/date'; +import { formatDate } from '@/common/utils/format'; import { useIntervalFn, useStorage } from '@vueuse/core'; import { ColumnTypeSubscript, compatibleMysql, DataType, DbDialect, getDbDialect } from '../../dialect/index'; import ColumnFormItem from './ColumnFormItem.vue'; @@ -617,6 +617,10 @@ const onDeleteData = async () => { const db = state.db; const dbInst = getNowDbInst(); dbInst.promptExeSql(db, await dbInst.genDeleteByPrimaryKeysSql(db, state.table, deleteDatas as any), null, () => { + // 存在流程则恢复原值,需工单流程审批完后自动执行 + if (dbInst.flowProcdef) { + return; + } emits('dataDelete', deleteDatas); }); }; @@ -628,7 +632,7 @@ const onEditRowData = () => { return; } const data = selectionDatas[0]; - state.tableDataFormDialog.data = data; + state.tableDataFormDialog.data = { ...data }; state.tableDataFormDialog.title = `编辑表'${props.table}'数据`; state.tableDataFormDialog.visible = true; }; @@ -674,13 +678,13 @@ const onExportCsv = () => { columnNames.push(column.columnName); } } - exportCsv(`数据导出-${state.table}-${dateStrFormat('yyyyMMddHHmm', new Date().toString())}`, columnNames, dataList); + exportCsv(`数据导出-${state.table}-${formatDate(new Date(), 'yyyyMMddHHmm')}`, columnNames, dataList); }; const onExportSql = async () => { const selectionDatas = state.datas; exportFile( - `数据导出-${state.table}-${dateStrFormat('yyyyMMddHHmm', new Date().toString())}.sql`, + `数据导出-${state.table}-${formatDate(new Date(), 'yyyyMMddHHmm')}.sql`, await getNowDbInst().genInsertSql(state.db, state.table, selectionDatas) ); }; @@ -763,7 +767,12 @@ const submitUpdateFields = async () => { res += await dbInst.genUpdateSql(db, state.table, updateColumnValue, rowData); } - dbInst.promptExeSql(db, res, cancelUpdateFields, () => { + dbInst.promptExeSql(db, res, null, () => { + // 存在流程则恢复原值,需工单流程审批完后自动执行 + if (dbInst.flowProcdef) { + cancelUpdateFields(); + return; + } triggerRefresh(); cellUpdateMap.clear(); changeUpdatedField(); @@ -810,11 +819,11 @@ const getFormatTimeValue = (dataType: DataType, originValue: string): string => switch (dataType) { case DataType.Time: - return dateStrFormat('HH:mm:ss', originValue); + return formatDate(originValue, 'HH:mm:ss'); case DataType.Date: - return dateStrFormat('yyyy-MM-dd', originValue); + return formatDate(originValue, 'YYYY-MM-DD'); case DataType.DateTime: - return dateStrFormat('yyyy-MM-dd HH:mm:ss', originValue); + return formatDate(originValue, 'YYYY-MM-DD HH:mm:ss'); default: return originValue; } diff --git a/mayfly_go_web/src/views/ops/db/component/table/DbTableDataForm.vue b/mayfly_go_web/src/views/ops/db/component/table/DbTableDataForm.vue index d161457e..aa8bfbef 100644 --- a/mayfly_go_web/src/views/ops/db/component/table/DbTableDataForm.vue +++ b/mayfly_go_web/src/views/ops/db/component/table/DbTableDataForm.vue @@ -85,35 +85,35 @@ const closeDialog = () => { }; const confirm = async () => { - dataForm.value.validate(async (valid: boolean) => { - if (!valid) { - ElMessage.error('请正确填写数据信息'); - return false; - } + try { + await dataForm.value.validate(); + } catch (e: any) { + ElMessage.error('请正确填写数据信息'); + return false; + } - const dbInst = props.dbInst; - const data = modelValue.value; - const db = props.dbName; - const tableName = props.tableName; + const dbInst = props.dbInst; + const data = modelValue.value; + const db = props.dbName; + const tableName = props.tableName; - let sql = ''; - if (oldValue) { - const updateColumnValue = {}; - Object.keys(oldValue).forEach((key) => { - // 如果新旧值不相等,则为需要更新的字段 - if (oldValue[key] !== modelValue.value[key]) { - updateColumnValue[key] = modelValue.value[key]; - } - }); - sql = await dbInst.genUpdateSql(db, tableName, updateColumnValue, oldValue); - } else { - sql = await dbInst.genInsertSql(db, tableName, [data], true); - } - - dbInst.promptExeSql(db, sql, null, () => { - closeDialog(); - emit('submitSuccess'); + let sql = ''; + if (oldValue) { + const updateColumnValue = {}; + Object.keys(oldValue).forEach((key) => { + // 如果新旧值不相等,则为需要更新的字段 + if (oldValue[key] !== modelValue.value[key]) { + updateColumnValue[key] = modelValue.value[key]; + } }); + sql = await dbInst.genUpdateSql(db, tableName, updateColumnValue, oldValue); + } else { + sql = await dbInst.genInsertSql(db, tableName, [data], true); + } + + dbInst.promptExeSql(db, sql, null, () => { + closeDialog(); + emit('submitSuccess'); }); }; diff --git a/mayfly_go_web/src/views/ops/db/component/table/DbTableDataOp.vue b/mayfly_go_web/src/views/ops/db/component/table/DbTableDataOp.vue index e1635f34..0349d439 100644 --- a/mayfly_go_web/src/views/ops/db/component/table/DbTableDataOp.vue +++ b/mayfly_go_web/src/views/ops/db/component/table/DbTableDataOp.vue @@ -50,17 +50,6 @@ - - - - - -
- + @@ -13,16 +13,15 @@ - - - + +
- 取消 + 取消 确定
@@ -30,7 +29,9 @@ 创建表
- + + + + +