Merge branch 'ts' into future/flowable
This commit is contained in:
commit
375a21a300
@ -13,7 +13,13 @@ VITE_APP_CONTEXT_PATH = '/'
|
||||
# 监控地址
|
||||
VITE_APP_MONITRO_ADMIN = 'http://localhost:9090/admin/applications'
|
||||
|
||||
# xxl-job 控制台地址
|
||||
VITE_APP_XXL_JOB_ADMIN = 'http://localhost:9100/xxl-job-admin'
|
||||
# powerjob 控制台地址
|
||||
VITE_APP_POWERJOB_ADMIN = 'http://localhost:7700/'
|
||||
|
||||
VITE_APP_PORT = 80
|
||||
|
||||
# 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
|
||||
VITE_APP_RSA_PUBLIC_KEY = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
|
||||
|
||||
# 客户端id
|
||||
VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
|
||||
|
@ -10,8 +10,8 @@ VITE_APP_CONTEXT_PATH = '/'
|
||||
# 监控地址
|
||||
VITE_APP_MONITRO_ADMIN = '/admin/applications'
|
||||
|
||||
# 监控地址
|
||||
VITE_APP_XXL_JOB_ADMIN = '/xxl-job-admin'
|
||||
# powerjob 控制台地址
|
||||
VITE_APP_POWERJOB_ADMIN = '/powerjob'
|
||||
|
||||
# 生产环境
|
||||
VITE_APP_BASE_API = '/prod-api'
|
||||
@ -20,3 +20,9 @@ VITE_APP_BASE_API = '/prod-api'
|
||||
VITE_BUILD_COMPRESS = gzip
|
||||
|
||||
VITE_APP_PORT = 80
|
||||
|
||||
# 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
|
||||
VITE_APP_RSA_PUBLIC_KEY = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
|
||||
|
||||
# 客户端id
|
||||
VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
|
||||
|
@ -1,5 +1,36 @@
|
||||
{
|
||||
"globals": {
|
||||
"ComponentInternalInstance": true,
|
||||
"TransferKey": true,
|
||||
"ElFormRules": true,
|
||||
"CheckboxValueType": true,
|
||||
"PropType": true,
|
||||
"DateModelType": true,
|
||||
"UploadFile": true,
|
||||
"ElFormInstance": true,
|
||||
"ElTableInstance": true,
|
||||
"ElTreeInstance": true,
|
||||
"ElTreeSelectInstance": true,
|
||||
"ElSelectInstance": true,
|
||||
"ElUploadInstance": true,
|
||||
"ElCardInstance": true,
|
||||
"ElDialogInstance": true,
|
||||
"ElInputInstance": true,
|
||||
"ElInputNumberInstance": true,
|
||||
"ElRadioInstance": true,
|
||||
"ElRadioGroupInstance": true,
|
||||
"ElRadioButtonInstance": true,
|
||||
"ElCheckboxInstance": true,
|
||||
"ElCheckboxGroupInstance": true,
|
||||
"ElSwitchInstance": true,
|
||||
"ElDatePickerInstance": true,
|
||||
"ElTimePickerInstance": true,
|
||||
"ElTimeSelectInstance": true,
|
||||
"ElScrollbarInstance": true,
|
||||
"ElCascaderInstance": true,
|
||||
"ElColorPickerInstance": true,
|
||||
"ElRateInstance": true,
|
||||
"ElSliderInstance": true,
|
||||
"useRouter": true,
|
||||
"useRoute": true,
|
||||
"EffectScope": true,
|
||||
|
@ -29,7 +29,8 @@ module.exports = {
|
||||
// 关闭空类型检查 {}
|
||||
extendDefaults: true,
|
||||
types: {
|
||||
'{}': false
|
||||
'{}': false,
|
||||
'Function': false
|
||||
}
|
||||
}
|
||||
]
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
.DS_Store
|
||||
.history
|
||||
node_modules/
|
||||
dist/
|
||||
npm-debug.log*
|
||||
|
10
package.json
10
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ruoyi-vue-plus",
|
||||
"version": "5.0.0",
|
||||
"version": "5.1.0",
|
||||
"description": "RuoYi-Vue-Plus多租户管理系统",
|
||||
"author": "LionLi",
|
||||
"license": "MIT",
|
||||
@ -29,19 +29,23 @@
|
||||
"fuse.js": "6.6.2",
|
||||
"js-cookie": "3.0.1",
|
||||
"jsencrypt": "3.3.1",
|
||||
"crypto-js": "^4.1.1",
|
||||
"nprogress": "0.2.0",
|
||||
"path-browserify": "1.0.1",
|
||||
"path-to-regexp": "6.2.0",
|
||||
"pinia": "2.0.22",
|
||||
"screenfull": "6.0.0",
|
||||
"vform3-builds": "3.0.8",
|
||||
"vue": "3.2.45",
|
||||
"vue-cropper": "1.0.3",
|
||||
"vue-i18n": "9.2.2",
|
||||
"vue-router": "4.1.4"
|
||||
"vue-router": "4.1.4",
|
||||
"vue-types": "^5.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify/json": "^2.2.40",
|
||||
"@intlify/unplugin-vue-i18n": "0.8.2",
|
||||
"@types/crypto-js": "^4.1.1",
|
||||
"@types/file-saver": "2.0.5",
|
||||
"@types/js-cookie": "3.0.3",
|
||||
"@types/node": "18.14.2",
|
||||
@ -69,11 +73,11 @@
|
||||
"unplugin-auto-import": "0.13.0",
|
||||
"unplugin-icons": "0.15.1",
|
||||
"unplugin-vue-components": "0.23.0",
|
||||
"vite": "4.3.1",
|
||||
"vite-plugin-compression": "0.5.1",
|
||||
"vite-plugin-svg-icons": "2.0.1",
|
||||
"vite-plugin-vue-setup-extend": "^0.4.0",
|
||||
"vitest": "^0.29.7",
|
||||
"vite": "4.3.1",
|
||||
"vue-eslint-parser": "9.1.0",
|
||||
"vue-tsc": "0.35.0"
|
||||
}
|
||||
|
@ -3,22 +3,24 @@ import { AxiosPromise } from 'axios';
|
||||
import { LoginData, LoginResult, VerifyCodeResult, TenantInfo } from './types';
|
||||
import { UserInfo } from '@/api/system/user/types';
|
||||
|
||||
// pc端固定客户端授权id
|
||||
const clientId = import.meta.env.VITE_APP_CLIENT_ID;
|
||||
|
||||
/**
|
||||
* @param data {LoginData}
|
||||
* @returns
|
||||
*/
|
||||
export function login(data: LoginData): AxiosPromise<LoginResult> {
|
||||
const params = {
|
||||
tenantId: data.tenantId,
|
||||
username: data.username.trim(),
|
||||
password: data.password,
|
||||
code: data.code,
|
||||
uuid: data.uuid
|
||||
...data,
|
||||
clientId: data.clientId || clientId,
|
||||
grantType: data.grantType || 'password'
|
||||
};
|
||||
return request({
|
||||
url: '/auth/login',
|
||||
headers: {
|
||||
isToken: false
|
||||
isToken: false,
|
||||
isEncrypt: true
|
||||
},
|
||||
method: 'post',
|
||||
data: params
|
||||
@ -52,7 +54,7 @@ export function logout() {
|
||||
*/
|
||||
export function getCodeImg(): AxiosPromise<VerifyCodeResult> {
|
||||
return request({
|
||||
url: '/code',
|
||||
url: '/auth/code',
|
||||
headers: {
|
||||
isToken: false
|
||||
},
|
||||
@ -61,6 +63,22 @@ export function getCodeImg(): AxiosPromise<VerifyCodeResult> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 第三方登录
|
||||
*/
|
||||
export function callback(data: LoginData): AxiosPromise<any> {
|
||||
const LoginData = {
|
||||
...data,
|
||||
clientId: clientId,
|
||||
grantType: 'social'
|
||||
};
|
||||
return request({
|
||||
url: '/auth/social/callback',
|
||||
method: 'post',
|
||||
data: LoginData
|
||||
});
|
||||
}
|
||||
|
||||
// 获取用户详细信息
|
||||
export function getInfo(): AxiosPromise<UserInfo> {
|
||||
return request({
|
||||
|
80
src/api/system/client/index.ts
Normal file
80
src/api/system/client/index.ts
Normal file
@ -0,0 +1,80 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { ClientVO, ClientForm, ClientQuery } from '@/api/system/client/types';
|
||||
|
||||
/**
|
||||
* 查询客户端管理列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const listClient = (query?: ClientQuery): AxiosPromise<ClientVO[]> => {
|
||||
return request({
|
||||
url: '/system/client/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询客户端管理详细
|
||||
* @param id
|
||||
*/
|
||||
export const getClient = (id: string | number): AxiosPromise<ClientVO> => {
|
||||
return request({
|
||||
url: '/system/client/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 新增客户端管理
|
||||
* @param data
|
||||
*/
|
||||
export const addClient = (data: ClientForm) => {
|
||||
return request({
|
||||
url: '/system/client',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改客户端管理
|
||||
* @param data
|
||||
*/
|
||||
export const updateClient = (data: ClientForm) => {
|
||||
return request({
|
||||
url: '/system/client',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除客户端管理
|
||||
* @param id
|
||||
*/
|
||||
export const delClient = (id: string | number | Array<string | number>) => {
|
||||
return request({
|
||||
url: '/system/client/' + id,
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 状态修改
|
||||
* @param id ID
|
||||
* @param status 状态
|
||||
*/
|
||||
export function changeStatus(id: number | string, status: string) {
|
||||
const data = {
|
||||
id,
|
||||
status
|
||||
};
|
||||
return request({
|
||||
url: '/system/client/changeStatus',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
}
|
138
src/api/system/client/types.ts
Normal file
138
src/api/system/client/types.ts
Normal file
@ -0,0 +1,138 @@
|
||||
export interface ClientVO {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 客户端id
|
||||
*/
|
||||
clientId: string | number;
|
||||
|
||||
/**
|
||||
* 客户端key
|
||||
*/
|
||||
clientKey: string;
|
||||
|
||||
/**
|
||||
* 客户端秘钥
|
||||
*/
|
||||
clientSecret: string;
|
||||
|
||||
/**
|
||||
* 授权类型
|
||||
*/
|
||||
grantTypeList: string[];
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
deviceType: string;
|
||||
|
||||
/**
|
||||
* token活跃超时时间
|
||||
*/
|
||||
activeTimeout: number;
|
||||
|
||||
/**
|
||||
* token固定超时
|
||||
*/
|
||||
timeout: number;
|
||||
|
||||
/**
|
||||
* 状态(0正常 1停用)
|
||||
*/
|
||||
status: string;
|
||||
|
||||
}
|
||||
|
||||
export interface ClientForm extends BaseEntity {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 客户端id
|
||||
*/
|
||||
clientId?: string | number;
|
||||
|
||||
/**
|
||||
* 客户端key
|
||||
*/
|
||||
clientKey?: string;
|
||||
|
||||
/**
|
||||
* 客户端秘钥
|
||||
*/
|
||||
clientSecret?: string;
|
||||
|
||||
/**
|
||||
* 授权类型
|
||||
*/
|
||||
grantTypeList?: string[];
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
deviceType?: string;
|
||||
|
||||
/**
|
||||
* token活跃超时时间
|
||||
*/
|
||||
activeTimeout?: number;
|
||||
|
||||
/**
|
||||
* token固定超时
|
||||
*/
|
||||
timeout?: number;
|
||||
|
||||
/**
|
||||
* 状态(0正常 1停用)
|
||||
*/
|
||||
status?: string;
|
||||
|
||||
}
|
||||
|
||||
export interface ClientQuery extends PageQuery {
|
||||
/**
|
||||
* 客户端id
|
||||
*/
|
||||
clientId?: string | number;
|
||||
|
||||
/**
|
||||
* 客户端key
|
||||
*/
|
||||
clientKey?: string;
|
||||
|
||||
/**
|
||||
* 客户端秘钥
|
||||
*/
|
||||
clientSecret?: string;
|
||||
|
||||
/**
|
||||
* 授权类型
|
||||
*/
|
||||
grantType?: string;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
deviceType?: string;
|
||||
|
||||
/**
|
||||
* token活跃超时时间
|
||||
*/
|
||||
activeTimeout?: number;
|
||||
|
||||
/**
|
||||
* token固定超时
|
||||
*/
|
||||
timeout?: number;
|
||||
|
||||
/**
|
||||
* 状态(0正常 1停用)
|
||||
*/
|
||||
status?: string;
|
||||
|
||||
}
|
24
src/api/system/social/auth.ts
Normal file
24
src/api/system/social/auth.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import request from '@/utils/request';
|
||||
|
||||
// 绑定账号
|
||||
export function authBinding(source: string) {
|
||||
return request({
|
||||
url: '/auth/binding/' + source,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 解绑账号
|
||||
export function authUnlock(authId: string) {
|
||||
return request({
|
||||
url: '/auth/unlock/' + authId,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
//获取授权列表
|
||||
export function getAuthList() {
|
||||
return request({
|
||||
url: '/system/social/list',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
@ -9,64 +9,64 @@ import { parseStrEmpty } from '@/utils/ruoyi';
|
||||
* 查询用户列表
|
||||
* @param query
|
||||
*/
|
||||
export function listUser(query: UserQuery): AxiosPromise<UserVO[]> {
|
||||
export const listUser = (query: UserQuery): AxiosPromise<UserVO[]> => {
|
||||
return request({
|
||||
url: '/system/user/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取用户详情
|
||||
* @param userId
|
||||
*/
|
||||
export function getUser(userId?: string | number): AxiosPromise<UserInfoVO> {
|
||||
export const getUser = (userId?: string | number): AxiosPromise<UserInfoVO> => {
|
||||
return request({
|
||||
url: '/system/user/' + parseStrEmpty(userId),
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 新增用户
|
||||
*/
|
||||
export function addUser(data: UserForm) {
|
||||
export const addUser = (data: UserForm) => {
|
||||
return request({
|
||||
url: '/system/user',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改用户
|
||||
*/
|
||||
export function updateUser(data: UserForm) {
|
||||
export const updateUser = (data: UserForm) => {
|
||||
return request({
|
||||
url: '/system/user',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
export function delUser(userId: Array<string | number> | string | number) {
|
||||
export const delUser = (userId: Array<string | number> | string | number) => {
|
||||
return request({
|
||||
url: '/system/user/' + userId,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 用户密码重置
|
||||
* @param userId 用户ID
|
||||
* @param password 密码
|
||||
*/
|
||||
export function resetUserPwd(userId: string | number, password: string) {
|
||||
export const resetUserPwd = (userId: string | number, password: string) => {
|
||||
const data = {
|
||||
userId,
|
||||
password
|
||||
@ -76,14 +76,14 @@ export function resetUserPwd(userId: string | number, password: string) {
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 用户状态修改
|
||||
* @param userId 用户ID
|
||||
* @param status 用户状态
|
||||
*/
|
||||
export function changeUserStatus(userId: number | string, status: string) {
|
||||
export const changeUserStatus = (userId: number | string, status: string) => {
|
||||
const data = {
|
||||
userId,
|
||||
status
|
||||
@ -93,36 +93,36 @@ export function changeUserStatus(userId: number | string, status: string) {
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询用户个人信息
|
||||
*/
|
||||
export function getUserProfile(): AxiosPromise<UserInfoVO> {
|
||||
export const getUserProfile = (): AxiosPromise<UserInfoVO> => {
|
||||
return request({
|
||||
url: '/system/user/profile',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改用户个人信息
|
||||
* @param data 用户信息
|
||||
*/
|
||||
export function updateUserProfile(data: UserForm) {
|
||||
export const updateUserProfile = (data: UserForm) => {
|
||||
return request({
|
||||
url: '/system/user/profile',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 用户密码重置
|
||||
* @param oldPassword 旧密码
|
||||
* @param newPassword 新密码
|
||||
*/
|
||||
export function updateUserPwd(oldPassword: string, newPassword: string) {
|
||||
export const updateUserPwd = (oldPassword: string, newPassword: string) => {
|
||||
const data = {
|
||||
oldPassword,
|
||||
newPassword
|
||||
@ -132,49 +132,66 @@ export function updateUserPwd(oldPassword: string, newPassword: string) {
|
||||
method: 'put',
|
||||
params: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 用户头像上传
|
||||
* @param data 头像文件
|
||||
*/
|
||||
export function uploadAvatar(data: FormData) {
|
||||
export const uploadAvatar = (data: FormData) => {
|
||||
return request({
|
||||
url: '/system/user/profile/avatar',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询授权角色
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
export function getAuthRole(userId: string | number): AxiosPromise<{ user: UserVO; roles: RoleVO[] }> {
|
||||
export const getAuthRole = (userId: string | number): AxiosPromise<{ user: UserVO; roles: RoleVO[] }> => {
|
||||
return request({
|
||||
url: '/system/user/authRole/' + userId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 保存授权角色
|
||||
* @param data 用户ID
|
||||
*/
|
||||
export function updateAuthRole(data: { userId: string; roleIds: string }) {
|
||||
export const updateAuthRole = (data: { userId: string; roleIds: string }) => {
|
||||
return request({
|
||||
url: '/system/user/authRole',
|
||||
method: 'put',
|
||||
params: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询部门下拉树结构
|
||||
*/
|
||||
export function deptTreeSelect(): AxiosPromise<DeptVO[]> {
|
||||
export const deptTreeSelect = (): AxiosPromise<DeptVO[]> => {
|
||||
return request({
|
||||
url: '/system/user/deptTree',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
listUser,
|
||||
getUser,
|
||||
addUser,
|
||||
updateUser,
|
||||
delUser,
|
||||
resetUserPwd,
|
||||
changeUserStatus,
|
||||
getUserProfile,
|
||||
updateUserProfile,
|
||||
updateUserPwd,
|
||||
uploadAvatar,
|
||||
getAuthRole,
|
||||
updateAuthRole,
|
||||
deptTreeSelect
|
||||
};
|
||||
|
@ -15,19 +15,24 @@ export type RegisterForm = {
|
||||
* 登录请求
|
||||
*/
|
||||
export interface LoginData {
|
||||
tenantId: string;
|
||||
username: string;
|
||||
password: string;
|
||||
tenantId?: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
rememberMe?: boolean;
|
||||
socialCode?: string;
|
||||
socialState?: string;
|
||||
source?: string;
|
||||
code?: string;
|
||||
uuid?: string;
|
||||
clientId: string;
|
||||
grantType: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录响应
|
||||
*/
|
||||
export interface LoginResult {
|
||||
token: string;
|
||||
access_token: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
1
src/assets/icons/svg/gitee.svg
Normal file
1
src/assets/icons/svg/gitee.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1686919908144" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2521" width="200" height="200" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M512 992C246.895625 992 32 777.104375 32 512S246.895625 32 512 32s480 214.895625 480 480-214.895625 480-480 480z m242.9521875-533.3278125h-272.56875a23.7121875 23.7121875 0 0 0-23.71125 23.7121875l-0.024375 59.255625c0 13.08 10.6078125 23.7121875 23.6878125 23.7121875h165.96c13.104375 0 23.7121875 10.6078125 23.7121875 23.6878125v11.855625a71.1121875 71.1121875 0 0 1-71.1121875 71.1121875h-225.215625a23.7121875 23.7121875 0 0 1-23.6878125-23.7121875V423.1278125a71.1121875 71.1121875 0 0 1 71.0878125-71.1121875h331.824375a23.7121875 23.7121875 0 0 0 23.6878125-23.71125l0.0721875-59.2565625a23.7121875 23.7121875 0 0 0-23.68875-23.7121875H423.08a177.76875 177.76875 0 0 0-177.76875 177.7921875V754.953125c0 13.1034375 10.60875 23.7121875 23.713125 23.7121875h349.63125a159.984375 159.984375 0 0 0 159.984375-159.984375V482.36a23.7121875 23.7121875 0 0 0-23.7121875-23.6878125z" fill="#515151" p-id="2522"></path></svg>
|
After Width: | Height: | Size: 1.2 KiB |
3
src/assets/icons/svg/maxkey.svg
Normal file
3
src/assets/icons/svg/maxkey.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 9.3 KiB |
@ -26,6 +26,10 @@ html {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html.dark .svg-icon, html.dark svg {
|
||||
fill: var(--el-text-color-regular);
|
||||
}
|
||||
|
||||
#app {
|
||||
height: 100%;
|
||||
}
|
||||
@ -137,6 +141,7 @@ aside {
|
||||
border: 1px solid var(--el-border-color-light);
|
||||
background-color: var(--el-bg-color-overlay);
|
||||
padding: 0.75rem;
|
||||
transition: all ease 0.3s;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 2px 12px #0000001a;
|
||||
|
@ -90,8 +90,8 @@ h6 {
|
||||
.el-table__fixed-header-wrapper {
|
||||
th {
|
||||
word-break: break-word;
|
||||
background-color: #f8f8f9 !important;
|
||||
color: #515a6e;
|
||||
background-color: $table-header-bg !important;
|
||||
color: $table-header-text-color;
|
||||
height: 40px !important;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
@ -84,7 +84,7 @@
|
||||
.sub-menu-title-noDropdown,
|
||||
.el-sub-menu__title {
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.06) !important;
|
||||
background-color: $base-sub-menu-title-hover !important;
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,7 +211,7 @@
|
||||
.el-menu-item {
|
||||
&:hover {
|
||||
// you can use $sub-menuHover
|
||||
background-color: rgba(0, 0, 0, 0.06) !important;
|
||||
background-color: $base-menu-hover !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,40 @@
|
||||
// 全局SCSS变量
|
||||
:root {
|
||||
--menuBg: #304156;
|
||||
--menuColor: #bfcbd9;
|
||||
--menuActiveText: #f4f4f5;
|
||||
--menuHover: #263445;
|
||||
|
||||
--subMenuBg: #1f2d3d;
|
||||
--subMenuActiveText: #f4f4f5;
|
||||
--subMenuHover: #001528;
|
||||
--subMenuTitleHover: #293444;
|
||||
|
||||
--fixedHeaderBg: #ffffff;
|
||||
--tableHeaderBg: #f8f8f9;
|
||||
--tableHeaderTextColor: #515a6e;
|
||||
}
|
||||
html.dark {
|
||||
--menuBg: #1d1e1f;
|
||||
--menuColor: #bfcbd9;
|
||||
--menuActiveText: #f4f4f5;
|
||||
--menuHover: #171819;
|
||||
|
||||
--subMenuBg: #1d1e1f;
|
||||
--subMenuActiveText: #1d1e1f;
|
||||
--subMenuHover: #171819;
|
||||
--subMenuTitleHover: #171819;
|
||||
|
||||
--fixedHeaderBg: #171819;
|
||||
--tableHeaderBg: var(--el-bg-color);
|
||||
--tableHeaderTextColor: var(--el-text-color);
|
||||
|
||||
// 覆盖ele 高亮当前行的标准暗色
|
||||
.el-tree-node__content {
|
||||
--el-color-primary-light-9: #262727;
|
||||
}
|
||||
}
|
||||
|
||||
// base color
|
||||
$blue: #324157;
|
||||
$light-blue: #3a71a8;
|
||||
@ -9,32 +46,23 @@ $yellow: #fec171;
|
||||
$panGreen: #30b08f;
|
||||
|
||||
// 默认菜单主题风格
|
||||
$base-menu-color: #bfcbd9;
|
||||
$base-menu-color-active: #f4f4f5;
|
||||
$base-menu-background: #304156;
|
||||
$base-menu-color: var(--menuColor);
|
||||
$base-menu-hover: var(--menuHover);
|
||||
$base-menu-color-active: var(--menuActiveText);
|
||||
$base-menu-background: var(--menuBg);
|
||||
$base-logo-title-color: #ffffff;
|
||||
|
||||
$base-menu-light-color: rgba(0, 0, 0, 0.7);
|
||||
$base-menu-light-background: #ffffff;
|
||||
$base-logo-light-title-color: #001529;
|
||||
|
||||
$base-sub-menu-background: #1f2d3d;
|
||||
$base-sub-menu-hover: #001528;
|
||||
|
||||
// 自定义暗色菜单风格
|
||||
/**
|
||||
$base-menu-color:hsla(0,0%,100%,.65);
|
||||
$base-menu-color-active:#fff;
|
||||
$base-menu-background:#001529;
|
||||
$base-logo-title-color: #ffffff;
|
||||
|
||||
$base-menu-light-color:rgba(0,0,0,.70);
|
||||
$base-menu-light-background:#ffffff;
|
||||
$base-logo-light-title-color: #001529;
|
||||
|
||||
$base-sub-menu-background:#000c17;
|
||||
$base-sub-menu-hover:#001528;
|
||||
*/
|
||||
$base-sub-menu-background: var(--subMenuBg);
|
||||
$base-sub-menu-hover: var(--subMenuHover);
|
||||
$base-sub-menu-title-hover: var(--subMenuTitleHover);
|
||||
// 表单头背景色和标题颜色
|
||||
$fixed-header-bg: var(--fixedHeaderBg);
|
||||
$table-header-bg: var(--tableHeaderBg);
|
||||
$table-header-text-color: var(--tableHeaderTextColor);
|
||||
|
||||
$--color-primary: #409eff;
|
||||
$--color-success: #67c23a;
|
||||
|
64
src/components/BuildCode/index.vue
Normal file
64
src/components/BuildCode/index.vue
Normal file
@ -0,0 +1,64 @@
|
||||
<!-- 代码构建 -->
|
||||
<script setup lang="ts">
|
||||
|
||||
const props = defineProps({
|
||||
showBtn: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
formJson: {
|
||||
type: Object,
|
||||
default: undefined
|
||||
}
|
||||
})
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const buildRef = ref();
|
||||
const emits = defineEmits(['reJson', 'saveDesign']);
|
||||
|
||||
|
||||
|
||||
//获取表单json
|
||||
const getJson = () => {
|
||||
const formJson = JSON.stringify(buildRef.value.getFormJson())
|
||||
const fieldJson = JSON.stringify(buildRef.value.getFieldWidgets())
|
||||
let data = {
|
||||
formJson, fieldJson
|
||||
}
|
||||
emits("saveDesign", data)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (props.formJson) {
|
||||
buildRef.value.setFormJson(props.formJson)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<v-form-designer
|
||||
class="build"
|
||||
ref="buildRef"
|
||||
:designer-config="{ importJsonButton: true, exportJsonButton: true, exportCodeButton: true, generateSFCButton: true, formTemplates: true }"
|
||||
>
|
||||
<template #customToolButtons v-if="showBtn">
|
||||
<el-button link type="primary" icon="Select" @click="getJson">保存</el-button>
|
||||
</template>
|
||||
</v-form-designer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.build {
|
||||
margin: 0 !important;
|
||||
overflow-y: auto !important;
|
||||
|
||||
& header.main-header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
& .right-toolbar-con {
|
||||
text-align: right !important;
|
||||
}
|
||||
}
|
||||
</style>
|
62
src/components/BuildCode/render.vue
Normal file
62
src/components/BuildCode/render.vue
Normal file
@ -0,0 +1,62 @@
|
||||
<!-- 动态表单渲染 -->
|
||||
<script setup name="Render">
|
||||
|
||||
const props = defineProps({
|
||||
formJson: {
|
||||
type: [String, Object],
|
||||
default: {}
|
||||
},
|
||||
formData: {
|
||||
type: [String, Object],
|
||||
default: {}
|
||||
},
|
||||
isView: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const vFormRef = ref(null)
|
||||
// 获取表单数据-异步
|
||||
const getFormData = () => {
|
||||
return vFormRef.value.getFormData()
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置表单内容
|
||||
* @param {表单配置} formConf
|
||||
* formConfig:{ formTemplate:表单模板,formData:表单数据,hiddenField:需要隐藏的字段字符串集合,disabledField:需要禁用的自读字符串集合}
|
||||
*/
|
||||
const initForm = (formConf) => {
|
||||
const { formTemplate, formData, hiddenField, disabledField } = toRaw(formConf)
|
||||
if (formTemplate) {
|
||||
vFormRef.value.setFormJson(formTemplate)
|
||||
if (formData) {
|
||||
vFormRef.value.setFormData(formData)
|
||||
}
|
||||
if (disabledField && disabledField.length > 0) {
|
||||
setTimeout(() => {
|
||||
vFormRef.value.disableWidgets(disabledField)
|
||||
}, 200)
|
||||
}
|
||||
if (hiddenField && hiddenField.length > 0) {
|
||||
setTimeout(() => {
|
||||
vFormRef.value.hideWidgets(hiddenField)
|
||||
}, 200)
|
||||
}
|
||||
if (props.isView) {
|
||||
console.log(props.isView)
|
||||
setTimeout(() => {
|
||||
vFormRef.value.disableForm()
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
defineExpose({ getFormData, initForm })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="">
|
||||
<v-form-render ref="vFormRef" :form-json="formJson" :form-data="formData" />
|
||||
</div>
|
||||
</template>
|
@ -24,7 +24,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { PropType } from 'vue';
|
||||
import { propTypes } from '@/utils/propTypes';
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
@ -36,10 +36,7 @@ const props = defineProps({
|
||||
// 当前的值
|
||||
value: [Number, String, Array] as PropType<number | string | Array<number | string>>,
|
||||
// 当未找到匹配的数据时,显示value
|
||||
showValue: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: true,
|
||||
},
|
||||
showValue: propTypes.bool.def(true),
|
||||
});
|
||||
|
||||
const values = computed(() => {
|
||||
|
@ -29,45 +29,28 @@
|
||||
<script setup lang="ts">
|
||||
import { QuillEditor, Quill } from '@vueup/vue-quill';
|
||||
import '@vueup/vue-quill/dist/vue-quill.snow.css';
|
||||
import { getToken } from "@/utils/auth";
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
import { propTypes } from '@/utils/propTypes';
|
||||
import { globalHeaders } from "@/utils/request";
|
||||
|
||||
const props = defineProps({
|
||||
/* 编辑器的内容 */
|
||||
modelValue: {
|
||||
type: String,
|
||||
},
|
||||
modelValue: propTypes.string,
|
||||
/* 高度 */
|
||||
height: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
height: propTypes.number.def(400),
|
||||
/* 最小高度 */
|
||||
minHeight: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
minHeight: propTypes.number.def(400),
|
||||
/* 只读 */
|
||||
readOnly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
readOnly: propTypes.bool.def(false),
|
||||
/* 上传文件大小限制(MB) */
|
||||
fileSize: {
|
||||
type: Number,
|
||||
default: 5,
|
||||
},
|
||||
fileSize: propTypes.number.def(5),
|
||||
/* 类型(base64格式、url格式) */
|
||||
type: {
|
||||
type: String,
|
||||
default: "url",
|
||||
}
|
||||
type: propTypes.string.def('url')
|
||||
});
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
const upload = reactive<UploadOption>({
|
||||
headers: { Authorization: "Bearer " + getToken() },
|
||||
headers: globalHeaders,
|
||||
url: import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload'
|
||||
})
|
||||
const myQuillEditor = ref();
|
||||
@ -166,16 +149,20 @@ const handleUploadError = (err: any) => {
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.editor, .ql-toolbar {
|
||||
.editor,
|
||||
.ql-toolbar {
|
||||
white-space: pre-wrap !important;
|
||||
line-height: normal !important;
|
||||
}
|
||||
|
||||
.quill-img {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ql-snow .ql-tooltip[data-mode="link"]::before {
|
||||
content: "请输入链接地址:";
|
||||
}
|
||||
|
||||
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
|
||||
border-right: 0;
|
||||
content: "保存";
|
||||
@ -190,14 +177,17 @@ const handleUploadError = (err: any) => {
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
|
||||
content: "14px";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
|
||||
content: "10px";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
|
||||
content: "18px";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
|
||||
content: "32px";
|
||||
@ -207,26 +197,32 @@ const handleUploadError = (err: any) => {
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
|
||||
content: "文本";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
|
||||
content: "标题1";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
|
||||
content: "标题2";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
|
||||
content: "标题3";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
|
||||
content: "标题4";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
|
||||
content: "标题5";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
|
||||
content: "标题6";
|
||||
@ -236,10 +232,12 @@ const handleUploadError = (err: any) => {
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
|
||||
content: "标准字体";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
|
||||
content: "衬线字体";
|
||||
}
|
||||
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
|
||||
content: "等宽字体";
|
||||
|
@ -43,33 +43,20 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getToken } from "@/utils/auth";
|
||||
import { listByIds, delOss } from "@/api/system/oss";
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
import { ElUpload, UploadFile } from "element-plus";
|
||||
import { propTypes } from '@/utils/propTypes';
|
||||
import { globalHeaders } from "@/utils/request";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: [String, Object, Array],
|
||||
// 数量限制
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 5,
|
||||
},
|
||||
limit: propTypes.number.def(5),
|
||||
// 大小限制(MB)
|
||||
fileSize: {
|
||||
type: Number,
|
||||
default: 5,
|
||||
},
|
||||
fileSize: propTypes.number.def(5),
|
||||
// 文件类型, 例如['png', 'jpg', 'jpeg']
|
||||
fileType: {
|
||||
type: Array,
|
||||
default: () => ["doc", "xls", "ppt", "txt", "pdf"],
|
||||
},
|
||||
fileType: propTypes.array.def(["doc", "xls", "ppt", "txt", "pdf"]),
|
||||
// 是否显示提示
|
||||
isShowTip: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
isShowTip: propTypes.bool.def(true),
|
||||
});
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
@ -79,14 +66,14 @@ const uploadList = ref<any[]>([]);
|
||||
|
||||
const baseUrl = import.meta.env.VITE_APP_BASE_API;
|
||||
const uploadFileUrl = ref(baseUrl + "/resource/oss/upload"); // 上传文件服务器地址
|
||||
const headers = ref({ Authorization: "Bearer " + getToken() });
|
||||
const headers = ref(globalHeaders);
|
||||
|
||||
const fileList = ref<any[]>([]);
|
||||
const showTip = computed(
|
||||
() => props.isShowTip && (props.fileType || props.fileSize)
|
||||
);
|
||||
|
||||
const fileUploadRef = ref(ElUpload);
|
||||
const fileUploadRef = ref<ElUploadInstance>();
|
||||
|
||||
watch(() => props.modelValue, async val => {
|
||||
if (val) {
|
||||
@ -158,7 +145,7 @@ const handleUploadSuccess = (res:any, file: UploadFile) => {
|
||||
number.value--;
|
||||
proxy?.$modal.closeLoading();
|
||||
proxy?.$modal.msgError(res.msg);
|
||||
fileUploadRef.value.handleRemove(file);
|
||||
fileUploadRef.value?.handleRemove(file);
|
||||
uploadedSuccessfully();
|
||||
}
|
||||
}
|
||||
@ -209,18 +196,21 @@ const listToString = (list: any[], separator?: string) => {
|
||||
.upload-file-uploader {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.upload-file-list .el-upload-list__item {
|
||||
border: 1px solid #e4e7ed;
|
||||
line-height: 2;
|
||||
margin-bottom: 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.upload-file-list .ele-upload-list__item-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.ele-upload-list__item-content-action .el-link {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
@ -9,11 +9,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { propTypes } from '@/utils/propTypes';
|
||||
|
||||
defineProps({
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
isActive: propTypes.bool.def(false)
|
||||
})
|
||||
|
||||
const emit = defineEmits(['toggleClick'])
|
||||
|
@ -17,12 +17,12 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Fuse from 'fuse.js'
|
||||
import { getNormalPath } from '@/utils/ruoyi'
|
||||
import { isHttp } from '@/utils/validate'
|
||||
import usePermissionStore from '@/store/modules/permission'
|
||||
import { RouteOption } from 'vue-router'
|
||||
<script setup lang="ts" name="HeaderSearch">
|
||||
import Fuse from 'fuse.js';
|
||||
import { getNormalPath } from '@/utils/ruoyi';
|
||||
import { isHttp } from '@/utils/validate';
|
||||
import usePermissionStore from '@/store/modules/permission';
|
||||
import { RouteOption } from 'vue-router';
|
||||
|
||||
type Router = Array<{
|
||||
path: string;
|
||||
@ -34,7 +34,7 @@ const options = ref<any>([]);
|
||||
const searchPool = ref<Router>([]);
|
||||
const show = ref(false);
|
||||
const fuse = ref();
|
||||
const headerSearchSelectRef = ref(ElSelect);
|
||||
const headerSearchSelectRef = ref<ElSelectInstance>();
|
||||
const router = useRouter();
|
||||
const routes = computed(() => usePermissionStore().routes);
|
||||
|
||||
@ -123,9 +123,9 @@ onMounted(() => {
|
||||
searchPool.value = generateRoutes(routes.value);
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
searchPool.value = generateRoutes(routes.value)
|
||||
})
|
||||
// watchEffect(() => {
|
||||
// searchPool.value = generateRoutes(routes.value)
|
||||
// })
|
||||
|
||||
watch(show, (value) => {
|
||||
if (value) {
|
||||
|
@ -31,17 +31,11 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import icons from '@/components/IconSelect/requireIcons';
|
||||
import { propTypes } from '@/utils/propTypes';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
require: true
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
require: false,
|
||||
default: '400px'
|
||||
}
|
||||
modelValue: propTypes.string.isRequired,
|
||||
width: propTypes.string.def('400px')
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
|
@ -9,11 +9,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { propTypes } from '@/utils/propTypes';
|
||||
|
||||
const props = defineProps({
|
||||
src: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
src: propTypes.string.def(''),
|
||||
width: {
|
||||
type: [Number, String],
|
||||
default: ""
|
||||
@ -58,13 +57,16 @@ const realHeight = computed(() =>
|
||||
border-radius: 5px;
|
||||
background-color: #ebeef5;
|
||||
box-shadow: 0 0 5px 1px #ccc;
|
||||
|
||||
:deep(.el-image__inner) {
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.image-slot) {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
@ -17,7 +17,9 @@
|
||||
:on-preview="handlePictureCardPreview"
|
||||
:class="{ hide: fileList.length >= limit }"
|
||||
>
|
||||
<el-icon class="avatar-uploader-icon"><plus /></el-icon>
|
||||
<el-icon class="avatar-uploader-icon">
|
||||
<plus />
|
||||
</el-icon>
|
||||
</el-upload>
|
||||
<!-- 上传提示 -->
|
||||
<div class="el-upload__tip" v-if="showTip">
|
||||
@ -38,29 +40,20 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getToken } from "@/utils/auth";
|
||||
import { listByIds, delOss } from "@/api/system/oss";
|
||||
import { ComponentInternalInstance, PropType } from "vue";
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
import { OssVO } from "@/api/system/oss/types";
|
||||
import { ElUpload, UploadFile } from "element-plus";
|
||||
import { propTypes } from '@/utils/propTypes';
|
||||
import {globalHeaders} from "@/utils/request";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: [String, Object, Array],
|
||||
// 图片数量限制
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 5,
|
||||
},
|
||||
limit: propTypes.number.def(5),
|
||||
// 大小限制(MB)
|
||||
fileSize: {
|
||||
type: Number,
|
||||
default: 5,
|
||||
},
|
||||
fileSize: propTypes.number.def(5),
|
||||
// 文件类型, 例如['png', 'jpg', 'jpeg']
|
||||
fileType: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => ["png", "jpg", "jpeg"],
|
||||
},
|
||||
fileType: propTypes.array.def(["png", "jpg", "jpeg"]),
|
||||
// 是否显示提示
|
||||
isShowTip: {
|
||||
type: Boolean,
|
||||
@ -77,14 +70,14 @@ const dialogVisible = ref(false);
|
||||
|
||||
const baseUrl = import.meta.env.VITE_APP_BASE_API;
|
||||
const uploadImgUrl = ref(baseUrl + "/resource/oss/upload"); // 上传的图片服务器地址
|
||||
const headers = ref({ Authorization: "Bearer " + getToken() });
|
||||
const headers = ref(globalHeaders);
|
||||
|
||||
const fileList = ref<any[]>([]);
|
||||
const showTip = computed(
|
||||
() => props.isShowTip && (props.fileType || props.fileSize)
|
||||
);
|
||||
|
||||
const imageUploadRef = ref(ElUpload);
|
||||
const imageUploadRef = ref<ElUploadInstance>();
|
||||
|
||||
watch(() => props.modelValue, async val => {
|
||||
if (val) {
|
||||
@ -122,7 +115,7 @@ const handleBeforeUpload = (file: any) => {
|
||||
if (file.name.lastIndexOf(".") > -1) {
|
||||
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
|
||||
}
|
||||
isImg = props.fileType.some((type) => {
|
||||
isImg = props.fileType.some((type: any) => {
|
||||
if (file.type.indexOf(type) > -1) return true;
|
||||
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
|
||||
return false;
|
||||
@ -161,7 +154,7 @@ const handleUploadSuccess = (res: any, file: UploadFile) => {
|
||||
number.value--;
|
||||
proxy?.$modal.closeLoading();
|
||||
proxy?.$modal.msgError(res.msg);
|
||||
imageUploadRef.value.handleRemove(file);
|
||||
imageUploadRef.value?.handleRemove(file);
|
||||
uploadedSuccessfully();
|
||||
}
|
||||
}
|
||||
|
@ -22,52 +22,23 @@ export default {
|
||||
|
||||
<script setup lang="ts">
|
||||
import { scrollTo } from '@/utils/scroll-to'
|
||||
import { PropType } from "vue";
|
||||
import { propTypes } from "@/utils/propTypes";
|
||||
|
||||
const props = defineProps({
|
||||
total: {
|
||||
required: true,
|
||||
type: Number
|
||||
},
|
||||
page: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 20
|
||||
},
|
||||
total: propTypes.number,
|
||||
page: propTypes.number.def(1),
|
||||
limit: propTypes.number.def(20),
|
||||
pageSizes: {
|
||||
type: Array as PropType<number[]>,
|
||||
default() {
|
||||
return [10, 20, 30, 50]
|
||||
}
|
||||
default: () => [10, 20, 30, 50]
|
||||
},
|
||||
// 移动端页码按钮的数量端默认值5
|
||||
pagerCount: {
|
||||
type: Number,
|
||||
default: document.body.clientWidth < 992 ? 5 : 7
|
||||
},
|
||||
layout: {
|
||||
type: String,
|
||||
default: 'total, sizes, prev, pager, next, jumper'
|
||||
},
|
||||
background: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
autoScroll: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
hidden: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
float: {
|
||||
type: String,
|
||||
default: 'right'
|
||||
}
|
||||
pagerCount: propTypes.number.def(document.body.clientWidth < 992 ? 5 : 7),
|
||||
layout: propTypes.string.def('total, sizes, prev, pager, next, jumper'),
|
||||
background: propTypes.bool.def(true),
|
||||
autoScroll: propTypes.bool.def(true),
|
||||
hidden: propTypes.bool.def(false),
|
||||
float: propTypes.string.def('right')
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:page', 'update:limit', 'pagination']);
|
||||
@ -106,7 +77,6 @@ function handleCurrentChange(val: number) {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.pagination-container {
|
||||
background: #fff;
|
||||
padding: 32px 16px;
|
||||
.el-pagination{
|
||||
float: v-bind(float);
|
||||
|
@ -18,25 +18,15 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { TransferKey } from "element-plus";
|
||||
import { PropType } from "vue";
|
||||
import { propTypes } from '@/utils/propTypes';
|
||||
|
||||
const props = defineProps({
|
||||
showSearch: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
showSearch: propTypes.bool.def(true),
|
||||
columns: {
|
||||
type: Array as PropType<FieldOption[]>,
|
||||
},
|
||||
search: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
gutter: {
|
||||
type: Number,
|
||||
default: 10,
|
||||
},
|
||||
search: propTypes.bool.def(true),
|
||||
gutter: propTypes.number.def(10),
|
||||
})
|
||||
|
||||
const emits = defineEmits(['update:showSearch', 'queryTable']);
|
||||
|
@ -5,7 +5,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const url = ref('https://javalionli.gitee.io/plus-doc');
|
||||
const url = ref('https://plus-doc.dromara.org/');
|
||||
|
||||
function goto() {
|
||||
window.open(url.value)
|
||||
|
@ -5,19 +5,12 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { propTypes } from '@/utils/propTypes';
|
||||
|
||||
const props = defineProps({
|
||||
iconClass: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
className: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
iconClass: propTypes.string.isRequired,
|
||||
className: propTypes.string.def(''),
|
||||
color: propTypes.string.def(''),
|
||||
})
|
||||
const iconName = computed(() => `#icon-${props.iconClass}`);
|
||||
const svgClass = computed(() => {
|
||||
|
@ -29,7 +29,6 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ElTreeSelect } from 'element-plus'
|
||||
|
||||
const props = defineProps({
|
||||
/* 配置项 */
|
||||
@ -68,7 +67,7 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
|
||||
const selectTree = ref(ElTreeSelect);
|
||||
const selectTree = ref<ElTreeSelectInstance>();
|
||||
|
||||
const emit = defineEmits(['update:value']);
|
||||
|
||||
@ -81,14 +80,14 @@ const valueId = computed({
|
||||
const valueTitle = ref('');
|
||||
const defaultExpandedKey = ref<any[]>([]);
|
||||
|
||||
function initHandle() {
|
||||
const initHandle = () => {
|
||||
nextTick(() => {
|
||||
const selectedValue = valueId.value;
|
||||
if (selectedValue !== null && typeof (selectedValue) !== 'undefined') {
|
||||
const node = selectTree.value.getNode(selectedValue)
|
||||
const node = selectTree.value?.getNode(selectedValue)
|
||||
if (node) {
|
||||
valueTitle.value = node.data[props.objMap.label]
|
||||
selectTree.value.setCurrentKey(selectedValue) // 设置默认选中
|
||||
selectTree.value?.setCurrentKey(selectedValue) // 设置默认选中
|
||||
defaultExpandedKey.value = [selectedValue] // 设置默认展开
|
||||
}
|
||||
} else {
|
||||
@ -96,27 +95,27 @@ function initHandle() {
|
||||
}
|
||||
})
|
||||
}
|
||||
function handleNodeClick(node: any) {
|
||||
const handleNodeClick = (node: any) => {
|
||||
valueTitle.value = node[props.objMap.label]
|
||||
valueId.value = node[props.objMap.value];
|
||||
defaultExpandedKey.value = [];
|
||||
selectTree.value.blur()
|
||||
selectTree.value?.blur()
|
||||
selectFilterData('')
|
||||
}
|
||||
function selectFilterData(val: any) {
|
||||
selectTree.value.filter(val)
|
||||
const selectFilterData = (val: any) => {
|
||||
selectTree.value?.filter(val)
|
||||
}
|
||||
function filterNode(value: any, data: any) {
|
||||
const filterNode = (value: any, data: any) => {
|
||||
if (!value) return true
|
||||
return data[props.objMap['label']].indexOf(value) !== -1
|
||||
}
|
||||
function clearHandle() {
|
||||
const clearHandle = () => {
|
||||
valueTitle.value = ''
|
||||
valueId.value = ''
|
||||
defaultExpandedKey.value = [];
|
||||
clearSelected()
|
||||
}
|
||||
function clearSelected() {
|
||||
const clearSelected = () => {
|
||||
const allNode = document.querySelectorAll('#tree-option .el-tree-node')
|
||||
allNode.forEach((element) => element.classList.remove('is-current'))
|
||||
}
|
||||
@ -132,6 +131,7 @@ watch(valueId, () => {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/assets/styles/variables.module.scss";
|
||||
|
||||
.el-scrollbar .el-scrollbar__view .el-select-dropdown__item {
|
||||
padding: 0;
|
||||
background-color: #fff;
|
||||
|
@ -5,11 +5,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { propTypes } from '@/utils/propTypes';
|
||||
|
||||
const props = defineProps({
|
||||
src: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
src: propTypes.string.isRequired
|
||||
})
|
||||
|
||||
const height = ref(document.documentElement.clientHeight - 94.5 + "px;")
|
||||
|
@ -20,8 +20,13 @@
|
||||
<template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template>
|
||||
</el-select>
|
||||
|
||||
<header-search id="header-search" class="right-menu-item" />
|
||||
|
||||
<!-- <header-search id="header-search" class="right-menu-item" /> -->
|
||||
<search-menu ref="searchMenuRef" />
|
||||
<el-tooltip content="搜索" effect="dark" placement="bottom">
|
||||
<div class="right-menu-item hover-effect" @click="openSearchMenu">
|
||||
<svg-icon class-name="search-icon" icon-class="search" />
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="Github" effect="dark" placement="bottom">
|
||||
<ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
|
||||
</el-tooltip>
|
||||
@ -68,17 +73,18 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import useAppStore from '@/store/modules/app'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import useSettingsStore from '@/store/modules/settings'
|
||||
import SearchMenu from './topBar/search.vue';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import useUserStore from '@/store/modules/user';
|
||||
import useSettingsStore from '@/store/modules/settings';
|
||||
import { getTenantList } from "@/api/login";
|
||||
import { dynamicClear, dynamicTenant } from "@/api/system/tenant";
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
import { TenantVO } from "@/api/types";
|
||||
|
||||
const appStore = useAppStore()
|
||||
const userStore = useUserStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
const appStore = useAppStore();
|
||||
const userStore = useUserStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
@ -89,6 +95,12 @@ const tenantList = ref<TenantVO[]>([]);
|
||||
const dynamic = ref(false);
|
||||
// 租户开关
|
||||
const tenantEnabled = ref(true);
|
||||
// 搜索菜单
|
||||
const searchMenuRef = ref<InstanceType<typeof SearchMenu>>();
|
||||
|
||||
const openSearchMenu = () => {
|
||||
searchMenuRef.value?.openSearch();
|
||||
}
|
||||
|
||||
// 动态切换
|
||||
const dynamicTenantEvent = async (tenantId: string) => {
|
||||
@ -104,7 +116,7 @@ const dynamicClearEvent = async () => {
|
||||
await dynamicClear();
|
||||
dynamic.value = false;
|
||||
proxy?.$tab.closeAllPage();
|
||||
proxy?.$router.push('/')
|
||||
proxy?.$router.push('/');
|
||||
}
|
||||
|
||||
/** 租户列表 */
|
||||
@ -121,7 +133,7 @@ defineExpose({
|
||||
})
|
||||
|
||||
const toggleSideBar = () => {
|
||||
appStore.toggleSideBar(false)
|
||||
appStore.toggleSideBar(false);
|
||||
}
|
||||
|
||||
const logout = async () => {
|
||||
@ -169,7 +181,7 @@ const handleCommand = (command: string) => {
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
//background: #fff;
|
||||
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||
|
||||
.hamburger-container {
|
||||
|
@ -1,8 +1,7 @@
|
||||
<template>
|
||||
<el-drawer v-model="showSettings" :withHeader="false" direction="rtl" size="300px" close-on-click-modal>
|
||||
<div class="setting-drawer-title">
|
||||
<h3 class="drawer-title">主题风格设置</h3>
|
||||
</div>
|
||||
|
||||
<div class="setting-drawer-block-checbox">
|
||||
<div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-dark')">
|
||||
<img src="@/assets/images/dark.svg" alt="dark" />
|
||||
@ -35,6 +34,13 @@
|
||||
<el-color-picker v-model="theme" :predefine="predefineColors" @change="themeChange" />
|
||||
</span>
|
||||
</div>
|
||||
<div class="drawer-item">
|
||||
<span>深色模式</span>
|
||||
<span class="comp-style">
|
||||
<el-switch v-model="isDark" @change="toggleDark" class="drawer-switch" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<el-divider />
|
||||
|
||||
<h3 class="drawer-title">系统布局配置</h3>
|
||||
@ -102,7 +108,15 @@ const sideTheme = ref(settingsStore.sideTheme);
|
||||
const storeSettings = computed(() => settingsStore);
|
||||
const predefineColors = ref(["#409EFF", "#ff4500", "#ff8c00", "#ffd700", "#90ee90", "#00ced1", "#1e90ff", "#c71585"]);
|
||||
|
||||
/** 是否需要topnav */
|
||||
// 是否暗黑模式
|
||||
const isDark = useDark({
|
||||
storageKey: 'useDarkKey',
|
||||
valueDark: 'dark',
|
||||
valueLight: 'light',
|
||||
});
|
||||
const toggleDark = () => useToggle(isDark);
|
||||
|
||||
/** 是否需要topNav */
|
||||
const topNav = computed({
|
||||
get: () => storeSettings.value.topNav,
|
||||
set: (val) => {
|
||||
@ -234,7 +248,6 @@ defineExpose({
|
||||
}
|
||||
|
||||
.drawer-item {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
padding: 12px 0;
|
||||
font-size: 14px;
|
||||
|
||||
|
89
src/layout/components/SocialCallback/index.vue
Normal file
89
src/layout/components/SocialCallback/index.vue
Normal file
@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<div v-loading="loading" class="social-callback"></div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { login, callback } from '@/api/login';
|
||||
import { setToken } from '@/utils/auth';
|
||||
import Cookies from 'js-cookie';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { LoginData } from '@/api/types';
|
||||
|
||||
const route = useRoute();
|
||||
const loading = ref(true);
|
||||
|
||||
|
||||
/**
|
||||
* 接收Route传递的参数
|
||||
* @param {Object} route.query.
|
||||
*/
|
||||
const code = route.query.code as string;
|
||||
const state = route.query.state as string;
|
||||
const source = route.query.source as string;
|
||||
const tenantId = Cookies.get("tenantId") ? Cookies.get("tenantId") as string : '000000';
|
||||
|
||||
|
||||
const processResponse = async (res: any) => {
|
||||
if (res.code !== 200) {
|
||||
throw new Error(res.msg);
|
||||
}
|
||||
if (res.data !== null) {
|
||||
setToken(res.data.access_token);
|
||||
}
|
||||
ElMessage.success(res.msg);
|
||||
setTimeout(() => {
|
||||
location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index';
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
const handleError = (error: any) => {
|
||||
ElMessage.error(error.message);
|
||||
setTimeout(() => {
|
||||
location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index';
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
const callbackByCode = async (data: LoginData) => {
|
||||
try {
|
||||
const res = await callback(data);
|
||||
await processResponse(res);
|
||||
loading.value = false;
|
||||
} catch (error) {
|
||||
handleError(error);
|
||||
}
|
||||
};
|
||||
|
||||
const loginByCode = async (data: LoginData) => {
|
||||
console.log(2)
|
||||
try {
|
||||
const res = await login(data);
|
||||
await processResponse(res);
|
||||
loading.value = false;
|
||||
} catch (error) {
|
||||
handleError(error);
|
||||
}
|
||||
};
|
||||
|
||||
const init = async () => {
|
||||
const data: LoginData = {
|
||||
socialCode: code,
|
||||
socialState: state,
|
||||
tenantId: tenantId,
|
||||
source: source,
|
||||
clientId: 'e5cd7e4891bf95d1d19206ce24a7b32e',
|
||||
grantType: 'social'
|
||||
};
|
||||
|
||||
if (!getToken()) {
|
||||
await loginByCode(data);
|
||||
} else {
|
||||
await callbackByCode(data);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
init();
|
||||
});
|
||||
});
|
||||
</script>
|
@ -6,18 +6,17 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import useTagsViewStore from '@/store/modules/tagsView'
|
||||
import { ElScrollbar } from 'element-plus';
|
||||
import { TagView } from 'vue-router'
|
||||
const tagAndTagSpacing = ref(4);
|
||||
|
||||
const scrollContainerRef = ref(ElScrollbar)
|
||||
const scrollWrapper = computed(() => scrollContainerRef.value.$refs.wrapRef);
|
||||
const scrollContainerRef = ref<ElScrollbarInstance>()
|
||||
const scrollWrapper = computed(() => scrollContainerRef.value?.$refs.wrapRef as any);
|
||||
|
||||
onMounted(() => {
|
||||
scrollWrapper.value.addEventListener('scroll', emitScroll, true)
|
||||
scrollWrapper.value?.addEventListener('scroll', emitScroll, true)
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
scrollWrapper.value.removeEventListener('scroll', emitScroll)
|
||||
scrollWrapper.value?.removeEventListener('scroll', emitScroll)
|
||||
})
|
||||
|
||||
const handleScroll = (e: WheelEvent) => {
|
||||
@ -34,7 +33,7 @@ const tagsViewStore = useTagsViewStore()
|
||||
const visitedViews = computed(() => tagsViewStore.visitedViews);
|
||||
|
||||
const moveToTarget = (currentTag: TagView) => {
|
||||
const $container = scrollContainerRef.value.$el
|
||||
const $container = scrollContainerRef.value?.$el
|
||||
const $containerWidth = $container.offsetWidth
|
||||
const $scrollWrapper = scrollWrapper.value;
|
||||
|
||||
@ -96,7 +95,7 @@ defineExpose({
|
||||
bottom: 0px;
|
||||
}
|
||||
:deep(.el-scrollbar__wrap) {
|
||||
height: 39px;
|
||||
height: 49px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -125,6 +125,9 @@ const initTags = () => {
|
||||
}
|
||||
const addTags = () => {
|
||||
const { name } = route;
|
||||
if(route.query.title) {
|
||||
route.meta.title = route.query.title;
|
||||
}
|
||||
if (name) {
|
||||
useTagsViewStore().addView(route);
|
||||
if (route.meta.link) {
|
||||
@ -237,8 +240,8 @@ onMounted(() => {
|
||||
.tags-view-container {
|
||||
height: 34px;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid #d8dce5;
|
||||
background-color: var(--el-bg-color);
|
||||
border: 1px solid var(--el-border-color-light);
|
||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);
|
||||
.tags-view-wrapper {
|
||||
.tags-view-item {
|
||||
@ -247,13 +250,16 @@ onMounted(() => {
|
||||
cursor: pointer;
|
||||
height: 26px;
|
||||
line-height: 23px;
|
||||
border: 1px solid #d8dce5;
|
||||
background-color: var(--el-bg-color);
|
||||
border: 1px solid var(--el-border-color-light);
|
||||
color: #495060;
|
||||
background: #fff;
|
||||
padding: 0 8px;
|
||||
font-size: 12px;
|
||||
margin-left: 5px;
|
||||
margin-top: 4px;
|
||||
&:hover {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
&:first-of-type {
|
||||
margin-left: 15px;
|
||||
}
|
||||
@ -279,7 +285,7 @@ onMounted(() => {
|
||||
}
|
||||
.contextmenu {
|
||||
margin: 0;
|
||||
background: #fff;
|
||||
background: var(--el-bg-color);
|
||||
z-index: 3000;
|
||||
position: absolute;
|
||||
list-style-type: none;
|
||||
@ -287,7 +293,6 @@ onMounted(() => {
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: #333;
|
||||
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
|
||||
li {
|
||||
margin: 0;
|
||||
|
158
src/layout/components/topBar/search.vue
Normal file
158
src/layout/components/topBar/search.vue
Normal file
@ -0,0 +1,158 @@
|
||||
<template>
|
||||
<div class="layout-search-dialog">
|
||||
<el-dialog v-model="state.isShowSearch" destroy-on-close :show-close="false">
|
||||
<template #footer>
|
||||
<el-autocomplete
|
||||
v-model="state.menuQuery"
|
||||
:fetch-suggestions="menuSearch"
|
||||
placeholder="搜索"
|
||||
ref="layoutMenuAutocompleteRef"
|
||||
@select="onHandleSelect"
|
||||
:fit-input-width="true"
|
||||
>
|
||||
<template #prefix>
|
||||
<svg-icon class-name="search-icon" icon-class="search" />
|
||||
</template>
|
||||
<template #default="{ item }">
|
||||
<div>
|
||||
<svg-icon :icon-class="item.icon" class="mr5" />
|
||||
{{ item.title }}
|
||||
</div>
|
||||
</template>
|
||||
</el-autocomplete>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="layoutBreadcrumbSearch">
|
||||
import { getNormalPath } from '@/utils/ruoyi';
|
||||
import { isHttp } from '@/utils/validate';
|
||||
import usePermissionStore from '@/store/modules/permission';
|
||||
import { RouteOption } from 'vue-router';
|
||||
type Router = Array<{
|
||||
path: string;
|
||||
icon: string;
|
||||
title: string[];
|
||||
}>
|
||||
type SearchState<T = any> = {
|
||||
isShowSearch: boolean;
|
||||
menuQuery: string;
|
||||
menuList: T[];
|
||||
};
|
||||
// 定义变量内容
|
||||
const layoutMenuAutocompleteRef = ref();
|
||||
const router = useRouter();
|
||||
const routes = computed(() => usePermissionStore().routes);
|
||||
const state = reactive<SearchState>({
|
||||
isShowSearch: false,
|
||||
menuQuery: '',
|
||||
menuList: [],
|
||||
});
|
||||
|
||||
// 搜索弹窗打开
|
||||
const openSearch = () => {
|
||||
state.menuQuery = '';
|
||||
state.isShowSearch = true;
|
||||
state.menuList = generateRoutes(routes.value);
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
layoutMenuAutocompleteRef.value.focus();
|
||||
});
|
||||
});
|
||||
};
|
||||
// 搜索弹窗关闭
|
||||
const closeSearch = () => {
|
||||
state.isShowSearch = false;
|
||||
};
|
||||
// 菜单搜索数据过滤
|
||||
const menuSearch = (queryString: string, cb: Function) => {
|
||||
let options = state.menuList.filter((item) => {
|
||||
return item.title.indexOf(queryString) > -1;
|
||||
});
|
||||
cb(options);
|
||||
};
|
||||
|
||||
// Filter out the routes that can be displayed in the sidebar
|
||||
// And generate the internationalized title
|
||||
const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: string[] = []) => {
|
||||
let res: Router = []
|
||||
routes.forEach(r => {
|
||||
// skip hidden router
|
||||
if (!r.hidden) {
|
||||
const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path;
|
||||
const data: any = {
|
||||
path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path,
|
||||
icon: r.meta?.icon,
|
||||
title: [...prefixTitle]
|
||||
}
|
||||
if (r.meta && r.meta.title) {
|
||||
data.title = [...data.title, r.meta.title];
|
||||
if (r.redirect !== 'noRedirect') {
|
||||
// only push the routes with title
|
||||
// special case: need to exclude parent router without redirect
|
||||
res.push(data);
|
||||
}
|
||||
}
|
||||
// recursive child routes
|
||||
if (r.children) {
|
||||
const tempRoutes = generateRoutes(r.children, data.path, data.title);
|
||||
if (tempRoutes.length >= 1) {
|
||||
res = [...res, ...tempRoutes];
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
res.forEach((item: any) => {
|
||||
if (item.title instanceof Array) {
|
||||
item.title = item.title.join('/');
|
||||
}
|
||||
});
|
||||
return res;
|
||||
}
|
||||
// 当前菜单选中时
|
||||
const onHandleSelect = (val: any) => {
|
||||
const paths = val.path;
|
||||
if (isHttp(paths)) {
|
||||
// http(s):// 路径新窗口打开
|
||||
const pindex = paths.indexOf("http");
|
||||
window.open(paths.substring(pindex, paths.length), "_blank");
|
||||
} else {
|
||||
router.push(paths);
|
||||
}
|
||||
state.menuQuery = ''
|
||||
closeSearch();
|
||||
|
||||
};
|
||||
|
||||
// 暴露变量
|
||||
defineExpose({
|
||||
openSearch
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.layout-search-dialog {
|
||||
position: relative;
|
||||
:deep(.el-dialog) {
|
||||
.el-dialog__header,
|
||||
.el-dialog__body {
|
||||
display: none;
|
||||
}
|
||||
.el-dialog__footer {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
top: -53vh;
|
||||
}
|
||||
}
|
||||
:deep(.el-autocomplete) {
|
||||
width: 560px;
|
||||
position: absolute;
|
||||
top: 150px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
</style>
|
@ -107,6 +107,7 @@ const setLayout = () => {
|
||||
z-index: 9;
|
||||
width: calc(100% - #{$base-sidebar-width});
|
||||
transition: width 0.28s;
|
||||
background: $fixed-header-bg;
|
||||
}
|
||||
|
||||
.hideSidebar .fixed-header {
|
||||
|
@ -10,7 +10,7 @@ import useSettingsStore from '@/store/modules/settings';
|
||||
import usePermissionStore from '@/store/modules/permission';
|
||||
|
||||
NProgress.configure({ showSpinner: false });
|
||||
const whiteList = ['/login', '/register'];
|
||||
const whiteList = ['/login', '/register', '/social-callback'];
|
||||
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
NProgress.start();
|
||||
|
@ -1,9 +1,9 @@
|
||||
import axios from 'axios';
|
||||
import FileSaver from 'file-saver';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import errorCode from '@/utils/errorCode';
|
||||
import { blobValidate } from '@/utils/ruoyi';
|
||||
import { LoadingInstance } from 'element-plus/es/components/loading/src/loading';
|
||||
import { globalHeaders } from "@/utils/request";
|
||||
|
||||
const baseURL = import.meta.env.VITE_APP_BASE_API;
|
||||
let downloadLoadingInstance: LoadingInstance;
|
||||
@ -16,7 +16,7 @@ export default {
|
||||
method: 'get',
|
||||
url: url,
|
||||
responseType: 'blob',
|
||||
headers: { Authorization: 'Bearer ' + getToken() }
|
||||
headers: globalHeaders,
|
||||
});
|
||||
const isBlob = blobValidate(res.data);
|
||||
if (isBlob) {
|
||||
@ -34,14 +34,13 @@ export default {
|
||||
},
|
||||
async zip(url: string, name: string) {
|
||||
url = baseURL + url;
|
||||
downloadLoadingInstance = ElLoading.service({ text: '正在下载数据,请稍候', background: 'rgba(0, 0, 0, 0.7)' });
|
||||
try {
|
||||
const res = await axios({
|
||||
method: 'get',
|
||||
url: url,
|
||||
responseType: 'blob',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + getToken(),
|
||||
datasource: localStorage.getItem('dataName')
|
||||
}
|
||||
headers: globalHeaders,
|
||||
});
|
||||
const isBlob = blobValidate(res.data);
|
||||
if (isBlob) {
|
||||
@ -50,6 +49,12 @@ export default {
|
||||
} else {
|
||||
this.printErrMsg(res.data);
|
||||
}
|
||||
downloadLoadingInstance.close();
|
||||
} catch (r) {
|
||||
console.error(r);
|
||||
ElMessage.error('下载文件出现错误,请联系管理员!');
|
||||
downloadLoadingInstance.close();
|
||||
}
|
||||
},
|
||||
async printErrMsg(data: any) {
|
||||
const resText = await data.text();
|
||||
|
@ -1,57 +1,57 @@
|
||||
import { ElMessage, ElMessageBox, ElNotification, ElLoading, MessageBoxData } from 'element-plus';
|
||||
import { MessageBoxData } from 'element-plus';
|
||||
import { LoadingInstance } from 'element-plus/es/components/loading/src/loading';
|
||||
let loadingInstance: LoadingInstance;
|
||||
export default {
|
||||
// 消息提示
|
||||
msg(content: string) {
|
||||
msg(content: any) {
|
||||
ElMessage.info(content);
|
||||
},
|
||||
// 错误消息
|
||||
msgError(content: string) {
|
||||
msgError(content: any) {
|
||||
ElMessage.error(content);
|
||||
},
|
||||
// 成功消息
|
||||
msgSuccess(content: string) {
|
||||
msgSuccess(content: any) {
|
||||
ElMessage.success(content);
|
||||
},
|
||||
// 警告消息
|
||||
msgWarning(content: string) {
|
||||
msgWarning(content: any) {
|
||||
ElMessage.warning(content);
|
||||
},
|
||||
// 弹出提示
|
||||
alert(content: string) {
|
||||
alert(content: any) {
|
||||
ElMessageBox.alert(content, '系统提示');
|
||||
},
|
||||
// 错误提示
|
||||
alertError(content: string) {
|
||||
alertError(content: any) {
|
||||
ElMessageBox.alert(content, '系统提示', { type: 'error' });
|
||||
},
|
||||
// 成功提示
|
||||
alertSuccess(content: string, s: string, p: { dangerouslyUseHTMLString: boolean }) {
|
||||
alertSuccess(content: any) {
|
||||
ElMessageBox.alert(content, '系统提示', { type: 'success' });
|
||||
},
|
||||
// 警告提示
|
||||
alertWarning(content: string) {
|
||||
alertWarning(content: any) {
|
||||
ElMessageBox.alert(content, '系统提示', { type: 'warning' });
|
||||
},
|
||||
// 通知提示
|
||||
notify(content: string) {
|
||||
notify(content: any) {
|
||||
ElNotification.info(content);
|
||||
},
|
||||
// 错误通知
|
||||
notifyError(content: string) {
|
||||
notifyError(content: any) {
|
||||
ElNotification.error(content);
|
||||
},
|
||||
// 成功通知
|
||||
notifySuccess(content: string) {
|
||||
notifySuccess(content: any) {
|
||||
ElNotification.success(content);
|
||||
},
|
||||
// 警告通知
|
||||
notifyWarning(content: string) {
|
||||
notifyWarning(content: any) {
|
||||
ElNotification.warning(content);
|
||||
},
|
||||
// 确认窗体
|
||||
confirm(content: string): Promise<MessageBoxData> {
|
||||
confirm(content: any): Promise<MessageBoxData> {
|
||||
return ElMessageBox.confirm(content, '系统提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
@ -59,7 +59,7 @@ export default {
|
||||
});
|
||||
},
|
||||
// 提交内容
|
||||
prompt(content: string) {
|
||||
prompt(content: any) {
|
||||
return ElMessageBox.prompt(content, '系统提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
|
@ -3,8 +3,11 @@ import router from '@/router';
|
||||
import { TagView, RouteLocationRaw } from 'vue-router';
|
||||
|
||||
export default {
|
||||
// 刷新当前tab页签
|
||||
async refreshPage(obj: TagView): Promise<void> {
|
||||
/**
|
||||
* 刷新当前tab页签
|
||||
* @param obj 标签对象
|
||||
*/
|
||||
async refreshPage(obj?: TagView): Promise<void> {
|
||||
const { path, query, matched } = router.currentRoute.value;
|
||||
if (obj === undefined) {
|
||||
matched.forEach((m) => {
|
||||
@ -15,11 +18,16 @@ export default {
|
||||
}
|
||||
});
|
||||
}
|
||||
// prettier-ignore
|
||||
await useTagsViewStore().delCachedView(obj)
|
||||
router.replace({
|
||||
path: '/redirect' + obj.path,
|
||||
query: obj.query
|
||||
let query1: undefined | {} = {};
|
||||
let path1: undefined | string = '';
|
||||
if (obj) {
|
||||
query1 = obj.query;
|
||||
path1 = obj.path;
|
||||
}
|
||||
await useTagsViewStore().delCachedView(obj);
|
||||
await router.replace({
|
||||
path: '/redirect' + path1,
|
||||
query: query1
|
||||
});
|
||||
},
|
||||
// 关闭当前tab页签,打开新页签
|
||||
@ -34,9 +42,9 @@ export default {
|
||||
if (obj === undefined) {
|
||||
// prettier-ignore
|
||||
const { visitedViews } = await useTagsViewStore().delView(router.currentRoute.value) as any
|
||||
const latestView = visitedViews.slice(-1)[0]
|
||||
const latestView = visitedViews.slice(-1)[0];
|
||||
if (latestView) {
|
||||
return router.push(latestView.fullPath)
|
||||
return router.push(latestView.fullPath);
|
||||
}
|
||||
return router.push('/');
|
||||
}
|
||||
@ -47,22 +55,31 @@ export default {
|
||||
return useTagsViewStore().delAllViews();
|
||||
},
|
||||
// 关闭左侧tab页签
|
||||
closeLeftPage(obj: TagView) {
|
||||
closeLeftPage(obj?: TagView) {
|
||||
return useTagsViewStore().delLeftTags(obj || router.currentRoute.value);
|
||||
},
|
||||
// 关闭右侧tab页签
|
||||
closeRightPage(obj: TagView) {
|
||||
closeRightPage(obj?: TagView) {
|
||||
return useTagsViewStore().delRightTags(obj || router.currentRoute.value);
|
||||
},
|
||||
// 关闭其他tab页签
|
||||
closeOtherPage(obj: TagView) {
|
||||
closeOtherPage(obj?: TagView) {
|
||||
return useTagsViewStore().delOthersViews(obj || router.currentRoute.value);
|
||||
},
|
||||
// 打开tab页签
|
||||
openPage(url: RouteLocationRaw) {
|
||||
return router.push(url);
|
||||
/**
|
||||
* 打开tab页签
|
||||
* @param url 路由地址
|
||||
* @param title 标题
|
||||
* @param query 参数
|
||||
*/
|
||||
openPage(url: string, title?: string, query?: any) {
|
||||
const obj = { path: url, query: { ...query, title } };
|
||||
return router.push(obj);
|
||||
},
|
||||
// 修改tab页签
|
||||
/**
|
||||
* 修改tab页签
|
||||
* @param obj 标签对象
|
||||
*/
|
||||
updatePage(obj: TagView) {
|
||||
return useTagsViewStore().updateVisitedView(obj);
|
||||
}
|
||||
|
@ -37,6 +37,11 @@ export const constantRoutes: RouteOption[] = [
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/social-callback',
|
||||
hidden: true,
|
||||
component: () => import('@/layout/components/SocialCallback/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
component: () => import('@/views/login.vue'),
|
||||
@ -176,4 +181,5 @@ const router = createRouter({
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export default router;
|
||||
|
@ -54,8 +54,11 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
||||
resolve([...visitedViews.value]);
|
||||
});
|
||||
};
|
||||
const delCachedView = (view: TagView): Promise<string[]> => {
|
||||
const viewName = view.name as string;
|
||||
const delCachedView = (view?: TagView): Promise<string[]> => {
|
||||
let viewName = '';
|
||||
if (view) {
|
||||
viewName = view.name as string;
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
const index = cachedViews.value.indexOf(viewName);
|
||||
index > -1 && cachedViews.value.splice(index, 1);
|
||||
@ -167,6 +170,7 @@ export const useTagsViewStore = defineStore('tagsView', () => {
|
||||
|
||||
const addCachedView = (view: TagView): void => {
|
||||
const viewName = view.name as string;
|
||||
if (!viewName) return;
|
||||
if (cachedViews.value.includes(viewName)) return;
|
||||
if (!view.meta?.noCache) {
|
||||
cachedViews.value.push(viewName);
|
||||
|
@ -23,8 +23,8 @@ export const useUserStore = defineStore('user', () => {
|
||||
const [err, res] = await to(loginApi(userInfo));
|
||||
if (res) {
|
||||
const data = res.data;
|
||||
setToken(data.token);
|
||||
token.value = data.token;
|
||||
setToken(data.access_token);
|
||||
token.value = data.access_token;
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject(err);
|
||||
|
34
src/types/element.d.ts
vendored
34
src/types/element.d.ts
vendored
@ -1 +1,35 @@
|
||||
import type * as ep from 'element-plus';
|
||||
declare global {
|
||||
declare type ElTagType = '' | 'success' | 'warning' | 'info' | 'danger' | 'default' | 'primary';
|
||||
declare type ElFormInstance = InstanceType<typeof ep.ElForm>;
|
||||
declare type ElTableInstance = InstanceType<typeof ep.ElTable>;
|
||||
declare type ElTreeInstance = InstanceType<typeof ep.ElTree>;
|
||||
declare type ElTreeSelectInstance = InstanceType<typeof ep.ElTreeSelect>;
|
||||
declare type ElSelectInstance = InstanceType<typeof ep.ElSelect>;
|
||||
declare type ElUploadInstance = InstanceType<typeof ep.ElUpload>;
|
||||
declare type ElCardInstance = InstanceType<typeof ep.ElCard>;
|
||||
declare type ElDialogInstance = InstanceType<typeof ep.ElDialog>;
|
||||
declare type ElInputInstance = InstanceType<typeof ep.ElInput>;
|
||||
declare type ElInputNumberInstance = InstanceType<typeof ep.ElInputNumber>;
|
||||
declare type ElRadioInstance = InstanceType<typeof ep.ElRadio>;
|
||||
declare type ElRadioGroupInstance = InstanceType<typeof ep.ElRadioGroup>;
|
||||
declare type ElRadioButtonInstance = InstanceType<typeof ep.ElRadioButton>;
|
||||
declare type ElCheckboxInstance = InstanceType<typeof ep.ElCheckbox>;
|
||||
declare type ElCheckboxGroupInstance = InstanceType<typeof ep.ElCheckboxGroup>;
|
||||
declare type ElSwitchInstance = InstanceType<typeof ep.ElSwitch>;
|
||||
declare type ElDatePickerInstance = InstanceType<typeof ep.ElDatePicker>;
|
||||
declare type ElTimePickerInstance = InstanceType<typeof ep.ElTimePicker>;
|
||||
declare type ElTimeSelectInstance = InstanceType<typeof ep.ElTimeSelect>;
|
||||
declare type ElCascaderInstance = InstanceType<typeof ep.ElCascader>;
|
||||
declare type ElColorPickerInstance = InstanceType<typeof ep.ElColorPicker>;
|
||||
declare type ElRateInstance = InstanceType<typeof ep.ElRate>;
|
||||
declare type ElSliderInstance = InstanceType<typeof ep.ElSlider>;
|
||||
declare type ElUploadInstance = InstanceType<typeof ep.ElUpload>;
|
||||
declare type ElScrollbarInstance = InstanceType<typeof ep.ElScrollbar>;
|
||||
|
||||
declare type TransferKey = ep.TransferKey;
|
||||
declare type CheckboxValueType = ep.CheckboxValueType;
|
||||
declare type ElFormRules = ep.FormRules;
|
||||
declare type DateModelType = ep.DateModelType;
|
||||
declare type UploadFile = typeof ep.UploadFile;
|
||||
}
|
||||
|
4
src/types/env.d.ts
vendored
4
src/types/env.d.ts
vendored
@ -65,8 +65,10 @@ interface ImportMetaEnv {
|
||||
VITE_APP_BASE_URL: string;
|
||||
VITE_APP_CONTEXT_PATH: string;
|
||||
VITE_APP_MONITRO_ADMIN: string;
|
||||
VITE_APP_XXL_JOB_ADMIN: string;
|
||||
VITE_APP_POWERJOB_ADMIN: string;
|
||||
VITE_APP_ENV: string;
|
||||
VITE_APP_RSA_PUBLIC_KEY: string;
|
||||
VITE_APP_CLIENT_ID: string;
|
||||
}
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
|
26
src/types/global.d.ts
vendored
26
src/types/global.d.ts
vendored
@ -1,9 +1,15 @@
|
||||
import { FormRules } from 'element-plus';
|
||||
import type { ComponentInternalInstance as ComponentInstance, PropType as VuePropType } from 'vue';
|
||||
|
||||
declare global {
|
||||
/** vue Instance */
|
||||
declare type ComponentInternalInstance = ComponentInstance;
|
||||
/**vue */
|
||||
declare type PropType<T> = VuePropType<T>;
|
||||
|
||||
/**
|
||||
* 界面字段隐藏属性
|
||||
*/
|
||||
interface FieldOption {
|
||||
declare interface FieldOption {
|
||||
key: number;
|
||||
label: string;
|
||||
visible: boolean;
|
||||
@ -12,7 +18,7 @@ declare global {
|
||||
/**
|
||||
* 弹窗属性
|
||||
*/
|
||||
interface DialogOption {
|
||||
declare interface DialogOption {
|
||||
/**
|
||||
* 弹窗标题
|
||||
*/
|
||||
@ -23,7 +29,7 @@ declare global {
|
||||
visible: boolean;
|
||||
}
|
||||
|
||||
interface UploadOption {
|
||||
declare interface UploadOption {
|
||||
/** 设置上传的请求头部 */
|
||||
headers: { [key: string]: any };
|
||||
|
||||
@ -34,7 +40,7 @@ declare global {
|
||||
/**
|
||||
* 导入属性
|
||||
*/
|
||||
interface ImportOption extends UploadOption {
|
||||
declare interface ImportOption extends UploadOption {
|
||||
/** 是否显示弹出层 */
|
||||
open: boolean;
|
||||
/** 弹出层标题 */
|
||||
@ -48,14 +54,14 @@ declare global {
|
||||
/**
|
||||
* 字典数据 数据配置
|
||||
*/
|
||||
interface DictDataOption {
|
||||
declare interface DictDataOption {
|
||||
label: string;
|
||||
value: string;
|
||||
elTagType?: ElTagType;
|
||||
elTagClass?: string;
|
||||
}
|
||||
|
||||
interface BaseEntity {
|
||||
declare interface BaseEntity {
|
||||
createBy?: any;
|
||||
createDept?: any;
|
||||
createTime?: string;
|
||||
@ -68,15 +74,15 @@ declare global {
|
||||
* T : 表单数据
|
||||
* D : 查询参数
|
||||
*/
|
||||
interface PageData<T, D> {
|
||||
declare interface PageData<T, D> {
|
||||
form: T;
|
||||
queryParams: D;
|
||||
rules: FormRules;
|
||||
rules: ElFormRules;
|
||||
}
|
||||
/**
|
||||
* 分页查询参数
|
||||
*/
|
||||
interface PageQuery {
|
||||
declare interface PageQuery {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
26
src/types/module.d.ts
vendored
26
src/types/module.d.ts
vendored
@ -1,23 +1,27 @@
|
||||
import modal from '@/plugins/modal';
|
||||
import tab from '@/plugins/tab';
|
||||
import { useDict } from '@/utils/dict';
|
||||
import { addDateRange, handleTree, selectDictLabel, selectDictLabels, parseTime } from '@/utils/ruoyi';
|
||||
import { getConfigKey, updateConfigByKey } from '@/api/system/config';
|
||||
import { download as download1 } from '@/utils/request';
|
||||
import download from '@/plugins/download';
|
||||
import animate from '@/animate';
|
||||
import type modal from '@/plugins/modal';
|
||||
import type tab from '@/plugins/tab';
|
||||
import type download from '@/plugins/download';
|
||||
import type auth from '@/plugins/auth';
|
||||
import type cache from '@/plugins/cache';
|
||||
import type animate from '@/animate';
|
||||
import type { useDict } from '@/utils/dict';
|
||||
import type { addDateRange, handleTree, selectDictLabel, selectDictLabels, parseTime } from '@/utils/ruoyi';
|
||||
import type { getConfigKey, updateConfigByKey } from '@/api/system/config';
|
||||
import type { download as rd } from '@/utils/request';
|
||||
|
||||
declare module 'vue' {
|
||||
export interface ComponentCustomProperties {
|
||||
declare module '@vue/runtime-core' {
|
||||
interface ComponentCustomProperties {
|
||||
// 全局方法声明
|
||||
$modal: typeof modal;
|
||||
$tab: typeof tab;
|
||||
$download: typeof download;
|
||||
$auth: typeof auth;
|
||||
$cache: typeof cache;
|
||||
animate: typeof animate;
|
||||
|
||||
useDict: typeof useDict;
|
||||
addDateRange: typeof addDateRange;
|
||||
download: typeof download1;
|
||||
download: typeof rd;
|
||||
handleTree: typeof handleTree;
|
||||
getConfigKey: typeof getConfigKey;
|
||||
updateConfigByKey: typeof updateConfigByKey;
|
||||
|
8
src/types/router.d.ts
vendored
8
src/types/router.d.ts
vendored
@ -1,7 +1,7 @@
|
||||
import { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
declare module 'vue-router' {
|
||||
type RouteOption = {
|
||||
declare type RouteOption = {
|
||||
hidden?: boolean;
|
||||
permissions?: string[];
|
||||
roles?: string[];
|
||||
@ -16,15 +16,15 @@ declare module 'vue-router' {
|
||||
query?: string;
|
||||
} & RouteRecordRaw;
|
||||
|
||||
interface _RouteLocationBase {
|
||||
declare interface _RouteLocationBase {
|
||||
children?: RouteOption[];
|
||||
}
|
||||
|
||||
interface RouteLocationOptions {
|
||||
declare interface RouteLocationOptions {
|
||||
fullPath?: string;
|
||||
}
|
||||
|
||||
interface TagView extends Partial<_RouteLocationBase> {
|
||||
declare interface TagView extends Partial<_RouteLocationBase> {
|
||||
title?: string;
|
||||
meta?: {
|
||||
link?: string;
|
||||
|
4
src/types/vform3-builds.d.ts
vendored
Normal file
4
src/types/vform3-builds.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
declare module 'vform3-builds' {
|
||||
const content: any;
|
||||
export = content;
|
||||
}
|
@ -4,6 +4,6 @@ const tokenStorage = useStorage<null | string>(TokenKey, null);
|
||||
|
||||
export const getToken = () => tokenStorage.value;
|
||||
|
||||
export const setToken = (token: string) => (tokenStorage.value = token);
|
||||
export const setToken = (access_token: string) => (tokenStorage.value = access_token);
|
||||
|
||||
export const removeToken = () => (tokenStorage.value = null);
|
||||
|
45
src/utils/crypto.ts
Normal file
45
src/utils/crypto.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import CryptoJS from 'crypto-js';
|
||||
|
||||
/**
|
||||
* 随机生成32位的字符串
|
||||
* @returns {string}
|
||||
*/
|
||||
const generateRandomString = () => {
|
||||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
let result = '';
|
||||
const charactersLength = characters.length;
|
||||
for (let i = 0; i < 32; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* 随机生成aes 密钥
|
||||
* @returns {string}
|
||||
*/
|
||||
export const generateAesKey = () => {
|
||||
return CryptoJS.enc.Utf8.parse(generateRandomString());
|
||||
};
|
||||
|
||||
/**
|
||||
* 加密base64
|
||||
* @returns {string}
|
||||
*/
|
||||
export const encryptBase64 = (str: CryptoJS.lib.WordArray) => {
|
||||
return CryptoJS.enc.Base64.stringify(str);
|
||||
};
|
||||
|
||||
/**
|
||||
* 使用密钥对数据进行加密
|
||||
* @param message
|
||||
* @param aesKey
|
||||
* @returns {string}
|
||||
*/
|
||||
export const encryptWithAes = (message: string, aesKey: CryptoJS.lib.WordArray) => {
|
||||
const encrypted = CryptoJS.AES.encrypt(message, aesKey, {
|
||||
mode: CryptoJS.mode.ECB,
|
||||
padding: CryptoJS.pad.Pkcs7
|
||||
});
|
||||
return encrypted.toString();
|
||||
};
|
@ -1,18 +1,10 @@
|
||||
import JSEncrypt from 'jsencrypt';
|
||||
// 密钥对生成 http://web.chacuo.net/netrsakeypair
|
||||
|
||||
const publicKey =
|
||||
'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdH\n' + 'nzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==';
|
||||
const publicKey = import.meta.env.VITE_APP_RSA_PUBLIC_KEY;
|
||||
|
||||
const privateKey =
|
||||
'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY\n' +
|
||||
'7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKN\n' +
|
||||
'PuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gA\n' +
|
||||
'kM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWow\n' +
|
||||
'cSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99Ecv\n' +
|
||||
'DQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthh\n' +
|
||||
'YhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3\n' +
|
||||
'UP8iWi1Qw0Y=';
|
||||
// 前端不建议存放私钥 不建议解密数据 因为都是透明的意义不大
|
||||
const privateKey = '**********';
|
||||
|
||||
// 加密
|
||||
export const encrypt = (txt: string) => {
|
||||
|
25
src/utils/propTypes.ts
Normal file
25
src/utils/propTypes.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { CSSProperties } from 'vue';
|
||||
import VueTypes, { createTypes, toValidableType, VueTypeValidableDef, VueTypesInterface } from 'vue-types';
|
||||
|
||||
type PropTypes = VueTypesInterface & {
|
||||
readonly style: VueTypeValidableDef<CSSProperties>;
|
||||
};
|
||||
|
||||
const propTypes = createTypes({
|
||||
func: undefined,
|
||||
bool: undefined,
|
||||
string: undefined,
|
||||
number: undefined,
|
||||
object: undefined,
|
||||
integer: undefined
|
||||
}) as PropTypes;
|
||||
|
||||
export default class ProjectTypes extends VueTypes {
|
||||
static get style() {
|
||||
return toValidableType('style', {
|
||||
type: [String, Object],
|
||||
default: undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
export { propTypes };
|
@ -8,12 +8,19 @@ import { errorCode } from '@/utils/errorCode';
|
||||
import { LoadingInstance } from 'element-plus/es/components/loading/src/loading';
|
||||
import FileSaver from 'file-saver';
|
||||
import { getLanguage } from '@/lang';
|
||||
import { encryptBase64, encryptWithAes, generateAesKey } from '@/utils/crypto';
|
||||
import { encrypt } from '@/utils/jsencrypt';
|
||||
|
||||
let downloadLoadingInstance: LoadingInstance;
|
||||
// 是否显示重新登录
|
||||
export const isRelogin = { show: false };
|
||||
export const globalHeaders = {
|
||||
Authorization: "Bearer " + getToken(),
|
||||
clientid: import.meta.env.VITE_APP_CLIENT_ID
|
||||
}
|
||||
|
||||
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8';
|
||||
axios.defaults.headers['clientid'] = import.meta.env.VITE_APP_CLIENT_ID;
|
||||
// 创建 axios 实例
|
||||
const service = axios.create({
|
||||
baseURL: import.meta.env.VITE_APP_BASE_API,
|
||||
@ -29,6 +36,8 @@ service.interceptors.request.use(
|
||||
const isToken = (config.headers || {}).isToken === false;
|
||||
// 是否需要防止数据重复提交
|
||||
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false;
|
||||
// 是否需要加密
|
||||
const isEncrypt = (config.headers || {}).isEncrypt === 'true';
|
||||
if (getToken() && !isToken) {
|
||||
config.headers['Authorization'] = 'Bearer ' + getToken(); // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
@ -63,6 +72,13 @@ service.interceptors.request.use(
|
||||
}
|
||||
}
|
||||
}
|
||||
// 当开启参数加密
|
||||
if (isEncrypt && (config.method === 'post' || config.method === 'put')) {
|
||||
// 生成一个 AES 密钥
|
||||
const aesKey = generateAesKey();
|
||||
config.headers['encrypt-key'] = encrypt(encryptBase64(aesKey));
|
||||
config.data = typeof config.data === 'object' ? encryptWithAes(JSON.stringify(config.data), aesKey) : encryptWithAes(config.data, aesKey);
|
||||
}
|
||||
// FormData数据去请求头Content-Type
|
||||
if (config.data instanceof FormData) {
|
||||
delete config.headers['Content-Type'];
|
||||
|
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div class="search" v-show="showSearch">
|
||||
<div class="mb-[10px]" v-show="showSearch">
|
||||
<el-card shadow="hover">
|
||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
||||
<el-form-item label="部门id" prop="deptId">
|
||||
<el-input v-model="queryParams.deptId" placeholder="请输入部门id" clearable @keyup.enter="handleQuery" />
|
||||
@ -23,10 +24,11 @@
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
@ -36,7 +38,9 @@
|
||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['demo:demo:edit']">修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['demo:demo:remove']">删除</el-button>
|
||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['demo:demo:remove']"
|
||||
>删除</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['demo:demo:export']">导出</el-button>
|
||||
@ -65,13 +69,7 @@
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||
</el-card>
|
||||
<!-- 添加或修改测试单对话框 -->
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||
@ -105,8 +103,6 @@
|
||||
<script setup name="Demo" lang="ts">
|
||||
import { listDemo, getDemo, delDemo, addDemo, updateDemo } from '@/api/demo/demo';
|
||||
import { DemoVO, DemoQuery, DemoForm } from '@/api/demo/demo/types';
|
||||
import { ComponentInternalInstance } from 'vue';
|
||||
import { ElForm } from 'element-plus';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
@ -119,8 +115,8 @@ const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
const demoFormRef = ref(ElForm);
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const demoFormRef = ref<ElFormInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
@ -188,7 +184,7 @@ const cancel = () => {
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
demoFormRef.value.resetFields();
|
||||
demoFormRef.value?.resetFields();
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
@ -199,7 +195,7 @@ const handleQuery = () => {
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
@ -212,30 +208,24 @@ const handleSelectionChange = (selection: DemoVO[]) => {
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加测试单";
|
||||
nextTick(() => {
|
||||
reset();
|
||||
});
|
||||
}
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = (row?: DemoVO) => {
|
||||
loading.value = true
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改测试单";
|
||||
nextTick(async () => {
|
||||
const handleUpdate = async (row?: DemoVO) => {
|
||||
reset();
|
||||
const _id = row?.id || ids.value[0]
|
||||
const res = await getDemo(_id);
|
||||
loading.value = false;
|
||||
Object.assign(form.value, res.data);
|
||||
});
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改测试单";
|
||||
}
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
demoFormRef.value.validate(async (valid: boolean) => {
|
||||
demoFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
if (form.value.id) {
|
||||
|
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div class="search" v-show="showSearch">
|
||||
<div class="mb-[10px]" v-show="showSearch">
|
||||
<el-card shadow="hover">
|
||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
||||
<el-form-item label="树节点名" prop="treeName">
|
||||
<el-input v-model="queryParams.treeName" placeholder="请输入树节点名" clearable @keyup.enter="handleQuery" />
|
||||
@ -11,10 +12,11 @@
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
@ -89,8 +91,6 @@
|
||||
<script setup name="Tree" lang="ts">
|
||||
import { listTree, getTree, delTree, addTree, updateTree } from "@/api/demo/tree";
|
||||
import { TreeVO, TreeQuery, TreeForm } from '@/api/demo/tree/types';
|
||||
import { ComponentInternalInstance } from 'vue';
|
||||
import { ElForm, ElTable } from 'element-plus';
|
||||
|
||||
|
||||
type TreeOption = {
|
||||
@ -109,9 +109,9 @@ const showSearch = ref(true);
|
||||
const isExpandAll = ref(true);
|
||||
const loading = ref(false);
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
const treeFormRef = ref(ElForm);
|
||||
const treeTableRef = ref(ElTable)
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const treeFormRef = ref<ElFormInstance>();
|
||||
const treeTableRef = ref<ElTableInstance>()
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
@ -185,7 +185,7 @@ const cancel = () => {
|
||||
// 表单重置
|
||||
const reset = () => {
|
||||
form.value = {...initFormData}
|
||||
treeFormRef.value.resetFields();
|
||||
treeFormRef.value?.resetFields();
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
@ -195,23 +195,21 @@ const handleQuery = () => {
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = (row?: TreeVO) => {
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加测试树";
|
||||
nextTick(() => {
|
||||
reset();
|
||||
getTreeselect();
|
||||
if (row != null && row.id) {
|
||||
if (row && row.id) {
|
||||
form.value.parentId = row.id;
|
||||
} else {
|
||||
form.value.parentId = 0;
|
||||
}
|
||||
});
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加测试树";
|
||||
}
|
||||
|
||||
/** 展开/折叠操作 */
|
||||
@ -223,31 +221,27 @@ const handleToggleExpandAll = () => {
|
||||
/** 展开/折叠操作 */
|
||||
const toggleExpandAll = (data: TreeVO[], status: boolean) => {
|
||||
data.forEach((item) => {
|
||||
treeTableRef.value.toggleRowExpansion(item, status)
|
||||
treeTableRef.value?.toggleRowExpansion(item, status)
|
||||
if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
|
||||
})
|
||||
}
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = (row: TreeVO) => {
|
||||
loading.value = true;
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改测试树";
|
||||
nextTick(async () => {
|
||||
const handleUpdate = async (row: TreeVO) => {
|
||||
reset();
|
||||
await getTreeselect();
|
||||
if (row != null) {
|
||||
if (row) {
|
||||
form.value.parentId = row.id;
|
||||
}
|
||||
const res = await getTree(row.id);
|
||||
loading.value = false;
|
||||
Object.assign(form.value, res.data);
|
||||
});
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改测试树";
|
||||
}
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
treeFormRef.value.validate(async (valid: boolean) => {
|
||||
treeFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
if (form.value.id) {
|
||||
@ -257,7 +251,7 @@ const submitForm = () => {
|
||||
}
|
||||
proxy?.$modal.msgSuccess("操作成功");
|
||||
dialog.visible = false;
|
||||
getList();
|
||||
await getList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -21,7 +21,6 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import errImage from '@/assets/401_images/401.gif';
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
|
||||
let { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
* 分布式锁 Lock4j 注解锁、工具锁 多种多样<br />
|
||||
* 分布式幂等 Lock4j 基于分布式锁实现<br />
|
||||
* 分布式链路追踪 SkyWalking 支持链路追踪、网格分析、度量聚合、可视化<br />
|
||||
* 分布式任务调度 Xxl-Job 高性能 高可靠 易扩展<br />
|
||||
* 分布式任务调度 PowerJob 高性能 高可靠 易扩展<br />
|
||||
* 文件存储 Minio 本地存储<br />
|
||||
* 文件存储 七牛、阿里、腾讯 云存储<br />
|
||||
* 监控框架 SpringBoot-Admin 全方位服务监控<br />
|
||||
@ -33,14 +33,14 @@
|
||||
* 部署方式 Docker 容器编排 一键部署业务集群<br />
|
||||
* 国际化 SpringMessage Spring标准国际化方案<br />
|
||||
</p>
|
||||
<p><b>当前版本:</b> <span>v5.0.0</span></p>
|
||||
<p><b>当前版本:</b> <span>v5.1.0</span></p>
|
||||
<p>
|
||||
<el-tag type="danger">¥免费开源</el-tag>
|
||||
</p>
|
||||
<p>
|
||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://gitee.com/dromara/RuoYi-Vue-Plus')">访问码云</el-button>
|
||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://github.com/dromara/RuoYi-Vue-Plus')">访问GitHub</el-button>
|
||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://javalionli.gitee.io/plus-doc/#/ruoyi-vue-plus/changlog')"
|
||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://plus-doc.dromara.org/#/ruoyi-vue-plus/changlog')"
|
||||
>更新日志</el-button
|
||||
>
|
||||
</p>
|
||||
@ -78,14 +78,14 @@
|
||||
* 分布式监控 Prometheus、Grafana 全方位性能监控<br />
|
||||
* 其余与 Vue 版本一致<br />
|
||||
</p>
|
||||
<p><b>当前版本:</b> <span>v2.0.0</span></p>
|
||||
<p><b>当前版本:</b> <span>v2.1.0</span></p>
|
||||
<p>
|
||||
<el-tag type="danger">¥免费开源</el-tag>
|
||||
</p>
|
||||
<p>
|
||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://gitee.com/dromara/RuoYi-Cloud-Plus')">访问码云</el-button>
|
||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://github.com/dromara/RuoYi-Cloud-Plus')">访问GitHub</el-button>
|
||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://javalionli.gitee.io/plus-doc/#/ruoyi-cloud-plus/changlog')"
|
||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://plus-doc.dromara.org/#/ruoyi-cloud-plus/changlog')"
|
||||
>更新日志</el-button
|
||||
>
|
||||
</p>
|
||||
|
@ -27,6 +27,20 @@
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
|
||||
<el-form-item style="float: right;">
|
||||
<el-button circle title="微信登录" @click="doSocialLogin('wechat')">
|
||||
<svg-icon icon-class="wechat" />
|
||||
</el-button>
|
||||
<el-button circle title="MaxKey登录" @click="doSocialLogin('maxkey')">
|
||||
<svg-icon icon-class="maxkey" />
|
||||
</el-button>
|
||||
<el-button circle title="Gitee登录" @click="doSocialLogin('gitee')">
|
||||
<svg-icon icon-class="gitee" />
|
||||
</el-button>
|
||||
<el-button circle title="Github登录" @click="doSocialLogin('github')">
|
||||
<svg-icon icon-class="github" />
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item style="width:100%;">
|
||||
<el-button :loading="loading" size="large" type="primary" style="width:100%;" @click.prevent="handleLogin">
|
||||
<span v-if="!loading">登 录</span>
|
||||
@ -46,26 +60,26 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getCodeImg, getTenantList } from '@/api/login';
|
||||
import { authBinding } from '@/api/system/social/auth';
|
||||
import Cookies from 'js-cookie';
|
||||
import { encrypt, decrypt } from '@/utils/jsencrypt';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { LoginData, TenantVO } from '@/api/types';
|
||||
import { FormRules } from 'element-plus';
|
||||
import { to } from 'await-to-js';
|
||||
import { HttpStatus } from "@/enums/RespEnum";
|
||||
|
||||
const userStore = useUserStore();
|
||||
const router = useRouter();
|
||||
|
||||
const loginForm = ref<LoginData>({
|
||||
tenantId: "000000",
|
||||
tenantId: '000000',
|
||||
username: 'admin',
|
||||
password: 'admin123',
|
||||
rememberMe: false,
|
||||
code: '',
|
||||
uuid: ''
|
||||
});
|
||||
} as LoginData);
|
||||
|
||||
const loginRules: FormRules = {
|
||||
const loginRules: ElFormRules = {
|
||||
tenantId: [{ required: true, trigger: "blur", message: "请输入您的租户编号" }],
|
||||
username: [{ required: true, trigger: 'blur', message: '请输入您的账号' }],
|
||||
password: [{ required: true, trigger: 'blur', message: '请输入您的密码' }],
|
||||
@ -83,19 +97,19 @@ const tenantEnabled = ref(true);
|
||||
// 注册开关
|
||||
const register = ref(false);
|
||||
const redirect = ref(undefined);
|
||||
const loginRef = ref(ElForm);
|
||||
const loginRef = ref<ElFormInstance>();
|
||||
// 租户列表
|
||||
const tenantList = ref<TenantVO[]>([]);
|
||||
|
||||
const handleLogin = () => {
|
||||
loginRef.value.validate(async (valid:boolean, fields: any) => {
|
||||
loginRef.value?.validate(async (valid: boolean, fields: any) => {
|
||||
if (valid) {
|
||||
loading.value = true;
|
||||
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
|
||||
if (loginForm.value.rememberMe) {
|
||||
Cookies.set("tenantId", loginForm.value.tenantId, { expires: 30 });
|
||||
Cookies.set('username', loginForm.value.username, { expires: 30 });
|
||||
Cookies.set('password', String(encrypt(loginForm.value.password)), { expires: 30 });
|
||||
Cookies.set("tenantId", String(loginForm.value.tenantId), { expires: 30 });
|
||||
Cookies.set('username', String(loginForm.value.username), { expires: 30 });
|
||||
Cookies.set('password', String(loginForm.value.password), { expires: 30 });
|
||||
Cookies.set('rememberMe', String(loginForm.value.rememberMe), { expires: 30 });
|
||||
} else {
|
||||
// 否则移除
|
||||
@ -105,7 +119,6 @@ const handleLogin = () => {
|
||||
Cookies.remove('rememberMe');
|
||||
}
|
||||
// 调用action的登录方法
|
||||
// prittier-ignore
|
||||
const [err] = await to(userStore.login(loginForm.value));
|
||||
if (!err) {
|
||||
await router.push({ path: redirect.value || '/' });
|
||||
@ -141,11 +154,11 @@ const getCookie = () => {
|
||||
const password = Cookies.get('password');
|
||||
const rememberMe = Cookies.get('rememberMe');
|
||||
loginForm.value = {
|
||||
tenantId: tenantId === undefined ? loginForm.value.tenantId : tenantId,
|
||||
username: username === undefined ? loginForm.value.username : username,
|
||||
password: password === undefined ? loginForm.value.password : (decrypt(password) as string),
|
||||
tenantId: tenantId === undefined ? String(loginForm.value.tenantId) : tenantId,
|
||||
username: username === undefined ? String(loginForm.value.username) : username,
|
||||
password: password === undefined ? String(loginForm.value.password) : String(password),
|
||||
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
|
||||
};
|
||||
} as LoginData;
|
||||
}
|
||||
|
||||
|
||||
@ -163,6 +176,28 @@ const initTenantList = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
//检测租户选择框的变化
|
||||
watch(() => loginForm.value.tenantId, () => {
|
||||
Cookies.set("tenantId", String(loginForm.value.tenantId), { expires: 30 })
|
||||
});
|
||||
|
||||
/**
|
||||
* 第三方登录
|
||||
* @param type
|
||||
*/
|
||||
const doSocialLogin = (type: string) => {
|
||||
authBinding(type).then((res: any) => {
|
||||
if (res.code === HttpStatus.SUCCESS) {
|
||||
// 获取授权地址跳转
|
||||
window.location.href = res.data;
|
||||
} else {
|
||||
ElMessage.error(res.msg);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
getCode();
|
||||
initTenantList();
|
||||
@ -179,6 +214,7 @@ onMounted(() => {
|
||||
background-image: url("../assets/images/login-background.jpg");
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 0px auto 30px auto;
|
||||
text-align: center;
|
||||
@ -190,32 +226,39 @@ onMounted(() => {
|
||||
background: #ffffff;
|
||||
width: 400px;
|
||||
padding: 25px 25px 5px 25px;
|
||||
|
||||
.el-input {
|
||||
height: 40px;
|
||||
|
||||
input {
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.input-icon {
|
||||
height: 39px;
|
||||
width: 14px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-tip {
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
color: #bfbfbf;
|
||||
}
|
||||
|
||||
.login-code {
|
||||
width: 33%;
|
||||
height: 40px;
|
||||
float: right;
|
||||
|
||||
img {
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.el-login-footer {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
@ -228,6 +271,7 @@ onMounted(() => {
|
||||
font-size: 12px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.login-code-img {
|
||||
height: 40px;
|
||||
padding-left: 12px;
|
||||
|
12
src/views/monitor/cache/index.vue
vendored
12
src/views/monitor/cache/index.vue
vendored
@ -2,7 +2,7 @@
|
||||
<div class="p-2">
|
||||
<el-row>
|
||||
<el-col :span="24" class="card-box">
|
||||
<el-card>
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<Monitor style="width: 1em; height: 1em; vertical-align: middle;" />
|
||||
<span style="vertical-align: middle;">基本信息</span>
|
||||
@ -98,7 +98,7 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="card-box">
|
||||
<el-card>
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<PieChart style="width: 1em; height: 1em; vertical-align: middle;" />
|
||||
<span style="vertical-align: middle;">命令统计</span>
|
||||
@ -110,7 +110,7 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="card-box">
|
||||
<el-card>
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<Odometer style="width: 1em; height: 1em; vertical-align: middle;" /> <span style="vertical-align: middle;">内存信息</span>
|
||||
</template>
|
||||
@ -126,7 +126,6 @@
|
||||
<script setup name="Cache" lang="ts">
|
||||
import { getCache } from '@/api/monitor/cache';
|
||||
import * as echarts from 'echarts';
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
|
||||
const cache = ref<any>({});
|
||||
const commandstats = ref();
|
||||
@ -157,7 +156,6 @@ const getList = async () => {
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const usedmemoryInstance = echarts.init(usedmemory.value, "macarons");
|
||||
usedmemoryInstance.setOption({
|
||||
tooltip: {
|
||||
@ -181,6 +179,10 @@ const getList = async () => {
|
||||
}
|
||||
]
|
||||
})
|
||||
window.addEventListener("resize",()=>{
|
||||
commandstatsIntance.resize()
|
||||
usedmemoryInstance.resize()
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div class="search" v-show="showSearch">
|
||||
<div class="mb-[10px]" v-show="showSearch">
|
||||
<el-card shadow="hover">
|
||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
||||
<el-form-item label="登录地址" prop="ipaddr">
|
||||
<el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable style="width: 240px;" @keyup.enter="handleQuery" />
|
||||
@ -30,10 +31,11 @@
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
@ -98,9 +100,7 @@
|
||||
|
||||
<script setup name="Logininfor" lang="ts">
|
||||
import { list, delLoginInfo, cleanLoginInfo, unlockLoginInfo } from "@/api/monitor/loginInfo";
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
import { LoginInfoQuery, LoginInfoVO } from "@/api/monitor/loginInfo/types";
|
||||
import { DateModelType } from 'element-plus';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { sys_common_status } = toRefs<any>(proxy?.useDict("sys_common_status"));
|
||||
@ -116,8 +116,8 @@ const total = ref(0);
|
||||
const dateRange = ref<[DateModelType,DateModelType]>(['', '']);
|
||||
const defaultSort = ref<any>({ prop: "loginTime", order: "descending" });
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
const loginInfoTableRef = ref(ElTable);
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const loginInfoTableRef = ref<ElTableInstance>();
|
||||
// 查询参数
|
||||
const queryParams = ref<LoginInfoQuery>({
|
||||
pageNum: 1,
|
||||
@ -145,9 +145,9 @@ const handleQuery = () => {
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
dateRange.value = ['', ''];
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
queryParams.value.pageNum = 1;
|
||||
loginInfoTableRef.value.sort(defaultSort.value.prop, defaultSort.value.order);
|
||||
loginInfoTableRef.value?.sort(defaultSort.value.prop, defaultSort.value.order);
|
||||
}
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: LoginInfoVO[]) => {
|
||||
@ -167,14 +167,14 @@ const handleDelete = async (row?: LoginInfoVO) => {
|
||||
const infoIds = row?.infoId || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?');
|
||||
await delLoginInfo(infoIds);
|
||||
getList();
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess("删除成功");
|
||||
}
|
||||
/** 清空按钮操作 */
|
||||
const handleClean = async () => {
|
||||
await proxy?.$modal.confirm("是否确认清空所有登录日志数据项?");
|
||||
await cleanLoginInfo();
|
||||
getList();
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess("清空成功");
|
||||
}
|
||||
/** 解锁按钮操作 */
|
||||
|
@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<div class="search">
|
||||
<div class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true">
|
||||
<el-form-item label="登录地址" prop="ipaddr">
|
||||
<el-input v-model="queryParams.ipaddr" placeholder="请输入登录地址" clearable style="width: 200px" @keyup.enter="handleQuery" />
|
||||
@ -13,8 +14,9 @@
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<el-card shadow="hover">
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="onlineList.slice((queryParams.pageNum - 1) * queryParams.pageSize, queryParams.pageNum * queryParams.pageSize)"
|
||||
@ -48,13 +50,12 @@
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" />
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Online" lang="ts">
|
||||
import { forceLogout, list as initData } from "@/api/monitor/online";
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
import { OnlineQuery, OnlineVO } from "@/api/monitor/online/types";
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
@ -63,7 +64,7 @@ const onlineList = ref<OnlineVO[]>([]);
|
||||
const loading = ref(true);
|
||||
const total = ref(0);
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
|
||||
const queryParams = ref<OnlineQuery>({
|
||||
pageNum: 1,
|
||||
@ -87,14 +88,14 @@ const handleQuery = () => {
|
||||
}
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
/** 强退按钮操作 */
|
||||
const handleForceLogout = async (row: OnlineVO) => {
|
||||
await proxy?.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?');
|
||||
await forceLogout(row.tokenId);
|
||||
getList();
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess("删除成功");
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div class="search" v-show="showSearch">
|
||||
<div class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
||||
<el-form-item label="系统模块" prop="title">
|
||||
<el-input v-model="queryParams.title" placeholder="请输入系统模块" clearable style="width: 240px;" @keyup.enter="handleQuery" />
|
||||
@ -35,10 +36,11 @@
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
@ -165,9 +167,7 @@
|
||||
|
||||
<script setup name="Operlog" lang="ts">
|
||||
import { list, delOperlog, cleanOperlog } from '@/api/monitor/operlog';
|
||||
import { ComponentInternalInstance } from 'vue';
|
||||
import { OperLogForm, OperLogQuery, OperLogVO } from '@/api/monitor/operlog/types';
|
||||
import { DateModelType } from 'element-plus';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { sys_oper_type, sys_common_status } = toRefs<any>(proxy?.useDict("sys_oper_type", "sys_common_status"));
|
||||
@ -181,8 +181,8 @@ const total = ref(0);
|
||||
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
||||
const defaultSort = ref<any>({ prop: "operTime", order: "descending" });
|
||||
|
||||
const operLogTableRef = ref(ElTable);
|
||||
const queryFormRef = ref(ElForm);
|
||||
const operLogTableRef = ref<ElTableInstance>();
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
@ -247,9 +247,9 @@ const handleQuery = () => {
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
dateRange.value = ['', ''];
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
queryParams.value.pageNum = 1;
|
||||
operLogTableRef.value.sort(defaultSort.value.prop, defaultSort.value.order);
|
||||
operLogTableRef.value?.sort(defaultSort.value.prop, defaultSort.value.order);
|
||||
}
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: OperLogVO[]) => {
|
||||
@ -272,7 +272,7 @@ const handleDelete = async (row?: OperLogVO) => {
|
||||
const operIds = row?.operId || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除日志编号为"' + operIds + '"的数据项?');
|
||||
await delOperlog(operIds);
|
||||
getList();
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess("删除成功");
|
||||
}
|
||||
|
||||
@ -280,7 +280,7 @@ const handleDelete = async (row?: OperLogVO) => {
|
||||
const handleClean = async () => {
|
||||
await proxy?.$modal.confirm("是否确认清空所有操作日志数据项?");
|
||||
await cleanOperlog();
|
||||
getList();
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess("清空成功");
|
||||
}
|
||||
|
||||
|
@ -5,5 +5,5 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const url = ref(import.meta.env.VITE_APP_XXL_JOB_ADMIN);
|
||||
const url = ref(import.meta.env.VITE_APP_POWERJOB_ADMIN);
|
||||
</script>
|
@ -58,7 +58,6 @@
|
||||
<script setup lang="ts">
|
||||
import { getCodeImg, register, getTenantList } from '@/api/login';
|
||||
import { RegisterForm, TenantVO } from '@/api/types';
|
||||
import { FormRules } from 'element-plus';
|
||||
import { to } from 'await-to-js';
|
||||
|
||||
const router = useRouter();
|
||||
@ -85,7 +84,7 @@ const equalToPassword = (rule: any, value: string, callback: any) => {
|
||||
}
|
||||
};
|
||||
|
||||
const registerRules: FormRules = {
|
||||
const registerRules: ElFormRules = {
|
||||
tenantId: [
|
||||
{ required: true, trigger: "blur", message: "请输入您的租户编号" }
|
||||
],
|
||||
|
328
src/views/system/client/index.vue
Normal file
328
src/views/system/client/index.vue
Normal file
@ -0,0 +1,328 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div class="search" v-show="showSearch">
|
||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="100px">
|
||||
<el-form-item label="客户端key" prop="clientKey">
|
||||
<el-input v-model="queryParams.clientKey" placeholder="请输入客户端key" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="客户端秘钥" prop="clientSecret">
|
||||
<el-input v-model="queryParams.clientSecret" placeholder="请输入客户端秘钥" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="状态" clearable>
|
||||
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:client:add']">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:client:edit']">
|
||||
修改
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:client:remove']">
|
||||
删除
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:client:export']">导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table v-loading="loading" :data="clientList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="id" align="center" prop="id" v-if="true" />
|
||||
<el-table-column label="客户端id" align="center" prop="clientId" />
|
||||
<el-table-column label="客户端key" align="center" prop="clientKey" />
|
||||
<el-table-column label="客户端秘钥" align="center" prop="clientSecret" />
|
||||
<el-table-column label="授权类型" align="center">
|
||||
<template #default="scope">
|
||||
<div>
|
||||
<template v-for="(type, index) in scope.row.grantTypeList" :key="index">
|
||||
<dict-tag class="el-check-tag" :options="sys_grant_type" :value="type" />
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="设备类型" align="center">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_device_type" :value="scope.row.deviceType" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="Token活跃超时时间" align="center" prop="activeTimeout" />
|
||||
<el-table-column label="Token固定超时时间" align="center" prop="timeout" />
|
||||
<el-table-column label="状态" align="center" key="status">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-tooltip content="修改" placement="top">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:client:edit']"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="删除" placement="top">
|
||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:client:remove']"></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total>0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||
</el-card>
|
||||
<!-- 添加或修改客户端管理对话框 -->
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||
<el-form ref="clientFormRef" :model="form" :rules="rules" label-width="100px">
|
||||
<el-form-item label="客户端key" prop="clientKey">
|
||||
<el-input v-model="form.clientKey" :disabled="form.id != null" placeholder="请输入客户端key" />
|
||||
</el-form-item>
|
||||
<el-form-item label="客户端秘钥" prop="clientSecret">
|
||||
<el-input v-model="form.clientSecret" :disabled="form.id != null" placeholder="请输入客户端秘钥" />
|
||||
</el-form-item>
|
||||
<el-form-item label="授权类型" prop="grantTypeList">
|
||||
<el-select v-model="form.grantTypeList" multiple placeholder="请输入授权类型">
|
||||
<el-option v-for="dict in sys_grant_type" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="设备类型" prop="deviceType">
|
||||
<el-select v-model="form.deviceType" placeholder="请输入设备类型">
|
||||
<el-option v-for="dict in sys_device_type" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item prop="activeTimeout" label-width="auto">
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="指定时间无操作则过期(单位:秒),默认30分钟(1800秒)" placement="top">
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
Token活跃超时时间
|
||||
</span>
|
||||
</template>
|
||||
<el-input v-model="form.activeTimeout" placeholder="请输入Token活跃超时时间" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="timeout" label-width="auto">
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="指定时间必定过期(单位:秒),默认七天(604800秒)" placement="top">
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
Token固定超时时间
|
||||
</span>
|
||||
</template>
|
||||
<el-input v-model="form.timeout" placeholder="请输入Token固定超时时间" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.value">
|
||||
{{ dict.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Client" lang="ts">
|
||||
import { listClient, getClient, delClient, addClient, updateClient, changeStatus } from '@/api/system/client';
|
||||
import { ClientVO, ClientQuery, ClientForm } from '@/api/system/client/types';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"));
|
||||
const { sys_grant_type } = toRefs<any>(proxy?.useDict("sys_grant_type"));
|
||||
const { sys_device_type } = toRefs<any>(proxy?.useDict("sys_device_type"));
|
||||
|
||||
const clientList = ref<ClientVO[]>([]);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const ids = ref<Array<string | number>>([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const clientFormRef = ref<ElFormInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
const initFormData: ClientForm = {
|
||||
id: undefined,
|
||||
clientId: undefined,
|
||||
clientKey: undefined,
|
||||
clientSecret: undefined,
|
||||
grantTypeList: undefined,
|
||||
deviceType: undefined,
|
||||
activeTimeout: undefined,
|
||||
timeout: undefined,
|
||||
status: undefined,
|
||||
}
|
||||
const data = reactive<PageData<ClientForm, ClientQuery>>({
|
||||
form: {...initFormData},
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
clientId: undefined,
|
||||
clientKey: undefined,
|
||||
clientSecret: undefined,
|
||||
grantType: undefined,
|
||||
deviceType: undefined,
|
||||
activeTimeout: undefined,
|
||||
timeout: undefined,
|
||||
status: undefined,
|
||||
},
|
||||
rules: {
|
||||
id: [
|
||||
{ required: true, message: "id不能为空", trigger: "blur" }
|
||||
],
|
||||
clientId: [
|
||||
{ required: true, message: "客户端id不能为空", trigger: "blur" }
|
||||
],
|
||||
clientKey: [
|
||||
{ required: true, message: "客户端key不能为空", trigger: "blur" }
|
||||
],
|
||||
clientSecret: [
|
||||
{ required: true, message: "客户端秘钥不能为空", trigger: "blur" }
|
||||
],
|
||||
grantTypeList: [
|
||||
{ required: true, message: "授权类型不能为空", trigger: "change" }
|
||||
],
|
||||
deviceType: [
|
||||
{ required: true, message: "设备类型不能为空", trigger: "change" }
|
||||
],
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
/** 查询客户端管理列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
const res = await listClient(queryParams.value);
|
||||
clientList.value = res.rows;
|
||||
total.value = res.total;
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
/** 取消按钮 */
|
||||
const cancel = () => {
|
||||
reset();
|
||||
dialog.visible = false;
|
||||
}
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = {...initFormData};
|
||||
clientFormRef.value?.resetFields();
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
}
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: ClientVO[]) => {
|
||||
ids.value = selection.map(item => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
}
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加客户端管理";
|
||||
}
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row?: ClientVO) => {
|
||||
reset();
|
||||
const _id = row?.id || ids.value[0]
|
||||
const res = await getClient(_id);
|
||||
Object.assign(form.value, res.data);
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改客户端管理";
|
||||
}
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
clientFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
if (form.value.id) {
|
||||
await updateClient(form.value).finally(() => buttonLoading.value = false);
|
||||
} else {
|
||||
await addClient(form.value).finally(() => buttonLoading.value = false);
|
||||
}
|
||||
proxy?.$modal.msgSuccess("修改成功");
|
||||
dialog.visible = false;
|
||||
await getList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: ClientVO) => {
|
||||
const _ids = row?.id || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除客户端管理编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
|
||||
await delClient(_ids);
|
||||
proxy?.$modal.msgSuccess("删除成功");
|
||||
await getList();
|
||||
}
|
||||
|
||||
/** 导出按钮操作 */
|
||||
const handleExport = () => {
|
||||
proxy?.download('system/client/export', {
|
||||
...queryParams.value
|
||||
}, `client_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
|
||||
/** 状态修改 */
|
||||
const handleStatusChange = async (row: ClientVO) => {
|
||||
let text = row.status === "0" ? "启用" : "停用"
|
||||
try {
|
||||
await proxy?.$modal.confirm('确认要"' + text + '"吗?');
|
||||
await changeStatus(row.id, row.status);
|
||||
proxy?.$modal.msgSuccess(text + "成功");
|
||||
} catch (err) {
|
||||
row.status = row.status === "0" ? "1" : "0";
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div class="search" v-show="showSearch">
|
||||
<div class="mb-[10px]" v-show="showSearch">
|
||||
<el-card shadow="hover">
|
||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
||||
<el-form-item label="参数名称" prop="configName">
|
||||
<el-input v-model="queryParams.configName" placeholder="请输入参数名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||
@ -30,9 +31,10 @@
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
<el-card shadow="never">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
@ -123,8 +125,6 @@
|
||||
<script setup name="Config" lang="ts">
|
||||
import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache } from "@/api/system/config";
|
||||
import { ConfigForm, ConfigQuery, ConfigVO } from "@/api/system/config/types";
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
import { DateModelType } from 'element-plus';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { sys_yes_no } = toRefs<any>(proxy?.useDict("sys_yes_no"));
|
||||
@ -138,8 +138,8 @@ const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
const configFormRef = ref(ElForm);
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const configFormRef = ref<ElFormInstance>();
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
@ -186,7 +186,7 @@ const cancel = () => {
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
configFormRef.value.resetFields();
|
||||
configFormRef.value?.resetFields();
|
||||
}
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
@ -196,7 +196,7 @@ const handleQuery = () => {
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
dateRange.value = ['', ''];
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
/** 多选框选中数据 */
|
||||
@ -207,31 +207,27 @@ const handleSelectionChange = (selection: ConfigVO[]) => {
|
||||
}
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加参数";
|
||||
nextTick(() => {
|
||||
reset();
|
||||
})
|
||||
}
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = (row?: ConfigVO) => {
|
||||
const handleUpdate = async (row?: ConfigVO) => {
|
||||
reset();
|
||||
const configId = row?.configId || ids.value[0];
|
||||
const res = await getConfig(configId);
|
||||
Object.assign(form.value, res.data);
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改参数";
|
||||
const configId = row?.configId || ids.value[0];
|
||||
nextTick(async () => {
|
||||
reset();
|
||||
const res = await getConfig(configId);
|
||||
form.value = res.data;
|
||||
})
|
||||
}
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
configFormRef.value.validate(async (valid: boolean) => {
|
||||
configFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
form.value.configId ? await updateConfig(form.value) : await addConfig(form.value);
|
||||
proxy?.$modal.msgSuccess("操作成功");
|
||||
dialog.visible = false;
|
||||
getList();
|
||||
await getList();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -240,7 +236,7 @@ const handleDelete = async (row?: ConfigVO) => {
|
||||
const configIds = row?.configId || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?');
|
||||
await delConfig(configIds);
|
||||
getList();
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess("删除成功");
|
||||
}
|
||||
/** 导出按钮操作 */
|
||||
|
@ -1,9 +1,10 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div class="search" v-show="showSearch">
|
||||
<div class="mb-[10px]" v-show="showSearch">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||
<el-form-item label="菜单名称" prop="menuName">
|
||||
<el-form-item label="部门名称" prop="deptName">
|
||||
<el-input v-model="queryParams.deptName" placeholder="请输入部门名称" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
@ -16,10 +17,11 @@
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="1.5">
|
||||
@ -130,7 +132,6 @@
|
||||
|
||||
<script setup name="Dept" lang="ts">
|
||||
import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from "@/api/system/dept"
|
||||
import { ComponentInternalInstance } from 'vue';
|
||||
import { DeptForm, DeptQuery, DeptVO } from "@/api/system/dept/types";
|
||||
|
||||
interface DeptOptionsType {
|
||||
@ -155,9 +156,9 @@ const dialog = reactive<DialogOption>({
|
||||
title: ''
|
||||
});
|
||||
|
||||
const deptTableRef = ref(ElTable);
|
||||
const queryFormRef = ref(ElForm);
|
||||
const deptFormRef = ref(ElForm);
|
||||
const deptTableRef = ref<ElTableInstance>();
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const deptFormRef = ref<ElFormInstance>();
|
||||
|
||||
const initFormData: DeptForm = {
|
||||
deptId: undefined,
|
||||
@ -206,7 +207,7 @@ const cancel = () => {
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
deptFormRef.value.resetFields();
|
||||
deptFormRef.value?.resetFields();
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
@ -215,26 +216,10 @@ const handleQuery = () => {
|
||||
}
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery()
|
||||
}
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = (row?: DeptVO) => {
|
||||
listDept().then(res => {
|
||||
const data = proxy?.handleTree<DeptOptionsType>(res.data, "deptId");
|
||||
if (data) {
|
||||
deptOptions.value = data
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加部门";
|
||||
nextTick(() => {
|
||||
reset();
|
||||
if (row && row.deptId) {
|
||||
form.value.parentId = row?.deptId;
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** 展开/折叠操作 */
|
||||
const handleToggleExpandAll = () => {
|
||||
isExpandAll.value = !isExpandAll.value;
|
||||
@ -243,38 +228,55 @@ const handleToggleExpandAll = () => {
|
||||
/** 展开/折叠所有 */
|
||||
const toggleExpandAll = (data: DeptVO[], status: boolean) => {
|
||||
data.forEach((item) => {
|
||||
deptTableRef.value.toggleRowExpansion(item, status)
|
||||
deptTableRef.value?.toggleRowExpansion(item, status)
|
||||
if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
|
||||
})
|
||||
}
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = async (row?: DeptVO) => {
|
||||
reset();
|
||||
const res = await listDept();
|
||||
const data = proxy?.handleTree<DeptOptionsType>(res.data, "deptId");
|
||||
if (data) {
|
||||
deptOptions.value = data
|
||||
if (row && row.deptId) {
|
||||
form.value.parentId = row?.deptId;
|
||||
}
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加部门";
|
||||
}
|
||||
}
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row: DeptVO) => {
|
||||
const res = await getDept(row.deptId);
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改部门";
|
||||
nextTick(async () => {
|
||||
reset();
|
||||
const res = await getDept(row.deptId);
|
||||
form.value = res.data
|
||||
const response = await listDeptExcludeChild(row.deptId);
|
||||
const data = proxy?.handleTree<DeptOptionsType>(response.data, "deptId")
|
||||
if (data) {
|
||||
deptOptions.value = data;
|
||||
if (data.length === 0) {
|
||||
const noResultsOptions: DeptOptionsType = { deptId: res.data.parentId, deptName: res.data.parentName, children: [] };
|
||||
const noResultsOptions: DeptOptionsType = {
|
||||
deptId: res.data.parentId,
|
||||
deptName: res.data.parentName,
|
||||
children: []
|
||||
};
|
||||
deptOptions.value.push(noResultsOptions);
|
||||
}
|
||||
}
|
||||
})
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改部门";
|
||||
}
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
deptFormRef.value.validate(async (valid: boolean) => {
|
||||
deptFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
form.value.deptId ? await updateDept(form.value) : await addDept(form.value);
|
||||
proxy?.$modal.msgSuccess("操作成功");
|
||||
dialog.visible = false;
|
||||
getList();
|
||||
await getList();
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -282,7 +284,7 @@ const submitForm = () => {
|
||||
const handleDelete = async (row: DeptVO) => {
|
||||
await proxy?.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?');
|
||||
await delDept(row.deptId);
|
||||
getList();
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess("删除成功");
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div class="search" v-show="showSearch">
|
||||
<div class="mb-[10px]" v-show="showSearch">
|
||||
<el-card shadow="hover">
|
||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
||||
<el-form-item label="字典名称" prop="dictType">
|
||||
<el-select v-model="queryParams.dictType" style="width: 200px">
|
||||
@ -21,9 +22,10 @@
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
<el-card shadow="never">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
@ -136,9 +138,7 @@ import useDictStore from '@/store/modules/dict'
|
||||
import { optionselect as getDictOptionselect, getType } from "@/api/system/dict/type";
|
||||
import { listData, getData, delData, addData, updateData } from "@/api/system/dict/data";
|
||||
import { DictTypeVO } from '@/api/system/dict/type/types';
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
import { DictDataForm, DictDataQuery, DictDataVO } from "@/api/system/dict/data/types";
|
||||
import { ElForm } from 'element-plus';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance
|
||||
const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"));
|
||||
@ -154,8 +154,8 @@ const total = ref(0);
|
||||
const defaultDictType = ref("");
|
||||
const typeOptions = ref<DictTypeVO[]>([]);
|
||||
|
||||
const dataFormRef = ref(ElForm);
|
||||
const queryFormRef = ref(ElForm);
|
||||
const dataFormRef = ref<ElFormInstance>();
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
@ -231,7 +231,7 @@ const cancel = () => {
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
dataFormRef.value.resetFields();
|
||||
dataFormRef.value?.resetFields();
|
||||
}
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
@ -245,18 +245,16 @@ const handleClose = () => {
|
||||
}
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
queryParams.value.dictType = defaultDictType.value;
|
||||
handleQuery();
|
||||
}
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加字典数据";
|
||||
nextTick(() => {
|
||||
reset();
|
||||
form.value.dictType = queryParams.value.dictType;
|
||||
})
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加字典数据";
|
||||
}
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: DictDataVO[]) => {
|
||||
@ -265,25 +263,23 @@ const handleSelectionChange = (selection: DictDataVO[]) => {
|
||||
multiple.value = !selection.length;
|
||||
}
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = (row?: DictDataVO) => {
|
||||
const handleUpdate = async (row?: DictDataVO) => {
|
||||
reset();
|
||||
const dictCode = row?.dictCode || ids.value[0];
|
||||
const res = await getData(dictCode);
|
||||
Object.assign(form.value, res.data);
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改字典数据";
|
||||
nextTick(async () => {
|
||||
const res = await getData(dictCode);
|
||||
reset();
|
||||
form.value = res.data;
|
||||
})
|
||||
}
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
dataFormRef.value.validate(async (valid: boolean) => {
|
||||
dataFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
form.value.dictCode ? await updateData(form.value) : await addData(form.value);
|
||||
useDictStore().removeDict(queryParams.value.dictType);
|
||||
proxy?.$modal.msgSuccess("操作成功");
|
||||
dialog.visible = false;
|
||||
getList();
|
||||
await getList();
|
||||
|
||||
}
|
||||
});
|
||||
@ -293,7 +289,7 @@ const handleDelete = async (row?: DictDataVO) => {
|
||||
const dictCodes = row?.dictCode || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?');
|
||||
await delData(dictCodes);
|
||||
getList();
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess("删除成功");
|
||||
useDictStore().removeDict(queryParams.value.dictType);
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div class="search" v-show="showSearch">
|
||||
<div class="mb-[10px]" v-show="showSearch">
|
||||
<el-card shadow="hover">
|
||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
||||
<el-form-item label="字典名称" prop="dictName">
|
||||
<el-input v-model="queryParams.dictName" placeholder="请输入字典名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||
@ -30,9 +31,10 @@
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
<el-card shadow="never">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
@ -123,9 +125,7 @@
|
||||
<script setup name="Dict" lang="ts">
|
||||
import useDictStore from '@/store/modules/dict'
|
||||
import { listType, getType, delType, addType, updateType, refreshCache } from "@/api/system/dict/type";
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
import { DictTypeForm, DictTypeQuery, DictTypeVO } from "@/api/system/dict/type/types";
|
||||
import { DateModelType } from 'element-plus';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"))
|
||||
@ -139,8 +139,8 @@ const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
||||
|
||||
const dictFormRef = ref(ElForm);
|
||||
const queryFormRef = ref(ElForm);
|
||||
const dictFormRef = ref<ElFormInstance>();
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
@ -189,7 +189,7 @@ const cancel = () => {
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
dictFormRef.value.resetFields();
|
||||
dictFormRef.value?.resetFields();
|
||||
}
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
@ -199,16 +199,14 @@ const handleQuery = () => {
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
dateRange.value = ['', ''];
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加字典类型";
|
||||
nextTick(() => {
|
||||
reset();
|
||||
})
|
||||
}
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: DictTypeVO[]) => {
|
||||
@ -217,20 +215,17 @@ const handleSelectionChange = (selection: DictTypeVO[]) => {
|
||||
multiple.value = !selection.length;
|
||||
}
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = (row?: DictTypeVO) => {
|
||||
const handleUpdate = async (row?: DictTypeVO) => {
|
||||
reset();
|
||||
const dictId = row?.dictId || ids.value[0];
|
||||
const res = await getType(dictId);
|
||||
Object.assign(form.value, res.data);
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改字典类型";
|
||||
const dictId = row?.dictId || ids.value[0];
|
||||
nextTick(async () => {
|
||||
reset();
|
||||
const res = await getType(dictId);
|
||||
form.value = res.data;
|
||||
})
|
||||
|
||||
}
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
dictFormRef.value.validate(async (valid: boolean) => {
|
||||
dictFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
form.value.dictId ? await updateType(form.value) : await addType(form.value);
|
||||
proxy?.$modal.msgSuccess("操作成功");
|
||||
|
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div class="search" v-show="showSearch">
|
||||
<div class="mb-[10px]" v-show="showSearch">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||
<el-form-item label="菜单名称" prop="menuName">
|
||||
<el-input v-model="queryParams.menuName" placeholder="请输入菜单名称" clearable @keyup.enter="handleQuery" />
|
||||
@ -16,10 +17,11 @@
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="1.5">
|
||||
@ -37,7 +39,6 @@
|
||||
:data="menuList"
|
||||
row-key="menuId"
|
||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||
border
|
||||
ref="menuTableRef"
|
||||
:default-expand-all="isExpandAll"
|
||||
>
|
||||
@ -180,7 +181,7 @@
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="form.menuType === 'C'">
|
||||
<el-form-item>
|
||||
<el-input v-model="form.query" placeholder="请输入路由参数" maxlength="255" />
|
||||
<el-input v-model="form.queryParam" placeholder="请输入路由参数" maxlength="255" />
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top">
|
||||
@ -262,9 +263,7 @@
|
||||
<script setup name="Menu" lang="ts">
|
||||
import { addMenu, delMenu, getMenu, listMenu, updateMenu } from '@/api/system/menu';
|
||||
import { MenuForm, MenuQuery, MenuVO } from '@/api/system/menu/types';
|
||||
import { ComponentInternalInstance } from 'vue';
|
||||
import { MenuTypeEnum } from '@/enums/MenuTypeEnum';
|
||||
import { ElTable, ElForm } from 'element-plus';
|
||||
|
||||
interface MenuOptionsType {
|
||||
menuId: number;
|
||||
@ -286,8 +285,8 @@ const dialog = reactive<DialogOption>({
|
||||
title: ''
|
||||
});
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
const menuFormRef = ref(ElForm);
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const menuFormRef = ref<ElFormInstance>();
|
||||
const initFormData = {
|
||||
path: '',
|
||||
menuId: undefined,
|
||||
@ -314,7 +313,7 @@ const data = reactive<PageData<MenuForm, MenuQuery>>({
|
||||
},
|
||||
})
|
||||
|
||||
const menuTableRef = ref(ElTable);
|
||||
const menuTableRef = ref<ElTableInstance>();
|
||||
|
||||
const { queryParams, form, rules } = toRefs<PageData<MenuForm, MenuQuery>>(data)
|
||||
/** 查询菜单列表 */
|
||||
@ -343,7 +342,7 @@ const cancel = () => {
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
menuFormRef.value.resetFields();
|
||||
menuFormRef.value?.resetFields();
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
@ -352,19 +351,16 @@ const handleQuery = () => {
|
||||
}
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = (row?: MenuVO) => {
|
||||
reset();
|
||||
getTreeselect();
|
||||
row && row.menuId ? form.value.parentId = row.menuId : form.value.parentId = 0;
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加菜单";
|
||||
getTreeselect();
|
||||
nextTick(() => {
|
||||
reset();
|
||||
row && row.menuId ? form.value.parentId = row.menuId : form.value.parentId = 0;
|
||||
})
|
||||
|
||||
}
|
||||
/** 展开/折叠操作 */
|
||||
const handleToggleExpandAll = () => {
|
||||
@ -374,32 +370,29 @@ const handleToggleExpandAll = () => {
|
||||
/** 展开/折叠所有 */
|
||||
const toggleExpandAll = (data: MenuVO[], status: boolean) => {
|
||||
data.forEach((item: MenuVO) => {
|
||||
menuTableRef.value.toggleRowExpansion(item, status)
|
||||
menuTableRef.value?.toggleRowExpansion(item, status)
|
||||
if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
|
||||
})
|
||||
}
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row: MenuVO) => {
|
||||
reset();
|
||||
await getTreeselect();
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改菜单";
|
||||
await nextTick(async () => {
|
||||
if (row.menuId) {
|
||||
const { data } = await getMenu(row.menuId);
|
||||
reset();
|
||||
form.value = data;
|
||||
}
|
||||
})
|
||||
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改菜单";
|
||||
}
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
menuFormRef.value.validate(async (valid: boolean) => {
|
||||
menuFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
form.value.menuId ? await updateMenu(form.value) : await addMenu(form.value);
|
||||
proxy?.$modal.msgSuccess("操作成功");
|
||||
dialog.visible = false;
|
||||
getList();
|
||||
await getList();
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -407,7 +400,7 @@ const submitForm = () => {
|
||||
const handleDelete = async (row: MenuVO) => {
|
||||
await proxy?.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?');
|
||||
await delMenu(row.menuId);
|
||||
getList();
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess("删除成功");
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div class="search" v-show="showSearch">
|
||||
<div class="mb-[10px]" v-show="showSearch">
|
||||
<el-card shadow="hover">
|
||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
||||
<el-form-item label="公告标题" prop="noticeTitle">
|
||||
<el-input v-model="queryParams.noticeTitle" placeholder="请输入公告标题" clearable style="width: 200px" @keyup.enter="handleQuery" />
|
||||
@ -19,10 +20,11 @@
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
@ -119,9 +121,7 @@
|
||||
|
||||
<script setup name="Notice" lang="ts">
|
||||
import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice";
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
import { NoticeForm, NoticeQuery, NoticeVO } from "@/api/system/notice/types";
|
||||
import { ElForm } from 'element-plus';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { sys_notice_status, sys_notice_type } = toRefs<any>(proxy?.useDict("sys_notice_status", "sys_notice_type"));
|
||||
@ -134,8 +134,8 @@ const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
const noticeFormRef = ref(ElForm);
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const noticeFormRef = ref<ElFormInstance>();
|
||||
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
@ -186,7 +186,7 @@ const cancel = () => {
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
noticeFormRef.value.resetFields();
|
||||
noticeFormRef.value?.resetFields();
|
||||
}
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
@ -195,7 +195,7 @@ const handleQuery = () => {
|
||||
}
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
/** 多选框选中数据 */
|
||||
@ -206,31 +206,27 @@ const handleSelectionChange = (selection: NoticeVO[]) => {
|
||||
}
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加公告";
|
||||
nextTick(() => {
|
||||
reset();
|
||||
})
|
||||
}
|
||||
/**修改按钮操作 */
|
||||
const handleUpdate = (row?: NoticeVO) => {
|
||||
const handleUpdate = async (row?: NoticeVO) => {
|
||||
reset();
|
||||
const noticeId = row?.noticeId || ids.value[0];
|
||||
const { data } = await getNotice(noticeId);
|
||||
Object.assign(form.value, data);
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改公告";
|
||||
nextTick(async () => {
|
||||
const noticeId = row?.noticeId || ids.value[0];
|
||||
reset();
|
||||
const { data } = await getNotice(noticeId);
|
||||
form.value = data;
|
||||
})
|
||||
}
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
noticeFormRef.value.validate(async (valid: boolean) => {
|
||||
noticeFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
form.value.noticeId ? await updateNotice(form.value) : await addNotice(form.value);
|
||||
proxy?.$modal.msgSuccess("修改成功");
|
||||
dialog.visible = false;
|
||||
getList();
|
||||
await getList();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -239,7 +235,7 @@ const handleDelete = async (row?: NoticeVO) => {
|
||||
const noticeIds = row?.noticeId || ids.value
|
||||
await proxy?.$modal.confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?');
|
||||
await delNotice(noticeIds);
|
||||
getList();
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess("删除成功");
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div class="search" v-show="showSearch">
|
||||
<div class="mb-[10px]" v-show="showSearch">
|
||||
<el-card shadow="hover">
|
||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
||||
<el-form-item label="配置key" prop="configKey">
|
||||
<el-input v-model="queryParams.configKey" placeholder="配置key" clearable style="width: 200px" @keyup.enter="handleQuery" />
|
||||
@ -20,10 +21,11 @@
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
@ -62,7 +64,7 @@
|
||||
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="150" class-name="small-padding fixed-width">
|
||||
<el-table-column label="操作" fixed="right" align="center" width="150" class-name="small-padding">
|
||||
<template #default="scope">
|
||||
<el-tooltip content="修改" placement="top">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:oss:edit']"></el-button>
|
||||
@ -138,9 +140,7 @@ import {
|
||||
updateOssConfig,
|
||||
changeOssConfigStatus
|
||||
} from "@/api/system/ossConfig";
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
import { OssConfigForm, OssConfigQuery, OssConfigVO } from "@/api/system/ossConfig/types";
|
||||
import { ElForm } from 'element-plus';
|
||||
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance
|
||||
@ -155,8 +155,8 @@ const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
const ossConfigFormRef = ref(ElForm);
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const ossConfigFormRef = ref<ElFormInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
@ -262,7 +262,7 @@ const cancel = () => {
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
ossConfigFormRef.value.resetFields();
|
||||
ossConfigFormRef.value?.resetFields();
|
||||
}
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
@ -271,7 +271,7 @@ const handleQuery = () => {
|
||||
}
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
/** 选择条数 */
|
||||
@ -282,28 +282,22 @@ const handleSelectionChange = (selection: OssConfigVO[]) => {
|
||||
}
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加对象存储配置";
|
||||
nextTick(() => {
|
||||
reset();
|
||||
})
|
||||
}
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = (row?: OssConfigVO) => {
|
||||
loading.value = true;
|
||||
const handleUpdate = async (row?: OssConfigVO) => {
|
||||
reset();
|
||||
const ossConfigId = row?.ossConfigId || ids.value[0];
|
||||
const res = await getOssConfig(ossConfigId);
|
||||
Object.assign(form.value, res.data);
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改对象存储配置";
|
||||
const ossConfigId = row?.ossConfigId || ids.value[0];
|
||||
nextTick(async () => {
|
||||
reset();
|
||||
const res = await getOssConfig(ossConfigId);
|
||||
loading.value = false;
|
||||
form.value = res.data;
|
||||
})
|
||||
}
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
ossConfigFormRef.value.validate(async (valid: boolean) => {
|
||||
ossConfigFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
if (form.value.ossConfigId) {
|
||||
@ -313,7 +307,7 @@ const submitForm = () => {
|
||||
}
|
||||
proxy?.$modal.msgSuccess("新增成功");
|
||||
dialog.visible = false;
|
||||
getList();
|
||||
await getList();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -323,7 +317,7 @@ const handleStatusChange = async (row: OssConfigVO) => {
|
||||
try {
|
||||
await proxy?.$modal.confirm('确认要"' + text + '""' + row.configKey + '"配置吗?');
|
||||
await changeOssConfigStatus(row.ossConfigId, row.status, row.configKey);
|
||||
getList()
|
||||
await getList()
|
||||
proxy?.$modal.msgSuccess(text + "成功");
|
||||
} catch { return } finally {
|
||||
row.status = row.status === "0" ? "1" : "0";
|
||||
@ -336,7 +330,7 @@ const handleDelete = async (row?: OssConfigVO) => {
|
||||
await proxy?.$modal.confirm('是否确认删除OSS配置编号为"' + ossConfigIds + '"的数据项?');
|
||||
loading.value = true;
|
||||
await delOssConfig(ossConfigIds).finally(() => loading.value = false);
|
||||
getList();
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess("删除成功");
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div class="search" v-show="showSearch">
|
||||
<div class="mb-[10px]" v-show="showSearch">
|
||||
<el-card shadow="hover">
|
||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
||||
<el-form-item label="文件名" prop="fileName">
|
||||
<el-input v-model="queryParams.fileName" placeholder="请输入文件名" clearable style="width: 200px" @keyup.enter="handleQuery" />
|
||||
@ -14,7 +15,7 @@
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<el-date-picker
|
||||
v-model="daterangeCreateTime"
|
||||
v-model="dateRangeCreateTime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
type="daterange"
|
||||
range-separator="-"
|
||||
@ -31,10 +32,11 @@
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
@ -133,9 +135,7 @@
|
||||
<script setup name="Oss" lang="ts">
|
||||
import { listOss, delOss } from "@/api/system/oss";
|
||||
import ImagePreview from "@/components/ImagePreview/index.vue";
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
import { OssForm, OssQuery, OssVO } from "@/api/system/oss/types";
|
||||
import { DateModelType } from 'element-plus';
|
||||
|
||||
const router = useRouter();
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
@ -151,7 +151,7 @@ const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
const type = ref(0);
|
||||
const previewListResource = ref(true);
|
||||
const daterangeCreateTime = ref<[DateModelType, DateModelType]>(['', '']);
|
||||
const dateRangeCreateTime = ref<[DateModelType, DateModelType]>(['', '']);
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
@ -161,8 +161,8 @@ const dialog = reactive<DialogOption>({
|
||||
// 默认排序
|
||||
const defaultSort = ref({ prop: 'createTime', order: 'ascending' });
|
||||
|
||||
const ossFormRef = ref(ElForm);
|
||||
const queryFormRef = ref(ElForm);
|
||||
const ossFormRef = ref<ElFormInstance>();
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
|
||||
const initFormData = {
|
||||
file: undefined,
|
||||
@ -195,7 +195,7 @@ const getList = async () => {
|
||||
loading.value = true;
|
||||
const res = await proxy?.getConfigKey("sys.oss.previewListResource");
|
||||
previewListResource.value = res?.msg === undefined ? true : res.msg === 'true';
|
||||
const response = await listOss(proxy?.addDateRange(queryParams.value, daterangeCreateTime.value, "CreateTime"));
|
||||
const response = await listOss(proxy?.addDateRange(queryParams.value, dateRangeCreateTime.value, "CreateTime"));
|
||||
ossList.value = response.rows;
|
||||
total.value = response.total;
|
||||
loading.value = false;
|
||||
@ -215,7 +215,7 @@ function cancel() {
|
||||
/** 表单重置 */
|
||||
function reset() {
|
||||
form.value = { ...initFormData };
|
||||
ossFormRef.value.resetFields();
|
||||
ossFormRef.value?.resetFields();
|
||||
}
|
||||
/** 搜索按钮操作 */
|
||||
function handleQuery() {
|
||||
@ -225,8 +225,8 @@ function handleQuery() {
|
||||
/** 重置按钮操作 */
|
||||
function resetQuery() {
|
||||
showTable.value = false;
|
||||
daterangeCreateTime.value = ['', ''];
|
||||
queryFormRef.value.resetFields();
|
||||
dateRangeCreateTime.value = ['', ''];
|
||||
queryFormRef.value?.resetFields();
|
||||
queryParams.value.orderByColumn = defaultSort.value.prop;
|
||||
queryParams.value.isAsc = defaultSort.value.order;
|
||||
handleQuery();
|
||||
@ -288,21 +288,17 @@ const handleOssConfig = () => {
|
||||
}
|
||||
/** 文件按钮操作 */
|
||||
const handleFile = () => {
|
||||
dialog.visible = true;
|
||||
dialog.title = "上传文件";
|
||||
nextTick(() => {
|
||||
reset();
|
||||
type.value = 0;
|
||||
})
|
||||
dialog.visible = true;
|
||||
dialog.title = "上传文件";
|
||||
}
|
||||
/** 图片按钮操作 */
|
||||
const handleImage = () => {
|
||||
dialog.visible = true;
|
||||
dialog.title = "上传图片";
|
||||
nextTick(() => {
|
||||
reset();
|
||||
type.value = 1;
|
||||
})
|
||||
dialog.visible = true;
|
||||
dialog.title = "上传图片";
|
||||
}
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
@ -319,7 +315,7 @@ const handlePreviewListResource = async (preview: boolean) => {
|
||||
try {
|
||||
await proxy?.$modal.confirm('确认要"' + text + '""预览列表图片"配置吗?');
|
||||
await proxy?.updateConfigByKey("sys.oss.previewListResource", preview);
|
||||
getList()
|
||||
await getList()
|
||||
proxy?.$modal.msgSuccess(text + "成功");
|
||||
} catch { return }
|
||||
}
|
||||
@ -329,7 +325,7 @@ const handleDelete = async (row?: OssVO) => {
|
||||
await proxy?.$modal.confirm('是否确认删除OSS对象存储编号为"' + ossIds + '"的数据项?');
|
||||
loading.value = true;
|
||||
await delOss(ossIds).finally(() => loading.value = false);
|
||||
getList();
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess("删除成功");
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div class="search" v-show="showSearch">
|
||||
<div class="mb-[10px]" v-show="showSearch">
|
||||
<el-card shadow="hover">
|
||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="70">
|
||||
<el-form-item label="岗位编码" prop="postCode">
|
||||
<el-input v-model="queryParams.postCode" placeholder="请输入岗位编码" clearable style="width: 200px" @keyup.enter="handleQuery" />
|
||||
@ -19,9 +20,10 @@
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
<el-card shadow="never">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
@ -107,7 +109,6 @@
|
||||
<script setup name="Post" lang="ts">
|
||||
import { listPost, addPost, delPost, getPost, updatePost } from "@/api/system/post";
|
||||
import { PostForm, PostQuery, PostVO } from "@/api/system/post/types";
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { sys_normal_disable } = toRefs<any>(proxy?.useDict("sys_normal_disable"));
|
||||
@ -120,8 +121,8 @@ const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
|
||||
const postFormRef = ref(ElForm);
|
||||
const queryFormRef = ref(ElForm);
|
||||
const postFormRef = ref<ElFormInstance>();
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
@ -171,7 +172,7 @@ const cancel = () => {
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
postFormRef.value.resetFields();
|
||||
postFormRef.value?.resetFields();
|
||||
}
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
@ -180,7 +181,7 @@ const handleQuery = () => {
|
||||
}
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
/** 多选框选中数据 */
|
||||
@ -191,31 +192,27 @@ const handleSelectionChange = (selection: PostVO[]) => {
|
||||
}
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加岗位";
|
||||
nextTick(() => {
|
||||
reset();
|
||||
})
|
||||
}
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = (row?: PostVO) => {
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改岗位";
|
||||
nextTick(async () => {
|
||||
const handleUpdate = async (row?: PostVO) => {
|
||||
reset();
|
||||
const postId = row?.postId || ids.value[0];
|
||||
const res = await getPost(postId);
|
||||
form.value = res.data;
|
||||
})
|
||||
Object.assign(form.value, res.data);
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改岗位";
|
||||
}
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
postFormRef.value.validate(async (valid: boolean) => {
|
||||
postFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
form.value.postId ? await updatePost(form.value) : await addPost(form.value);
|
||||
proxy?.$modal.msgSuccess("操作成功");
|
||||
dialog.visible = false;
|
||||
getList();
|
||||
await getList();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -224,7 +221,7 @@ const handleDelete = async (row?: PostVO) => {
|
||||
const postIds = row?.postId || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?');
|
||||
await delPost(postIds);
|
||||
getList();
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess("删除成功");
|
||||
}
|
||||
/** 导出按钮操作 */
|
||||
|
@ -58,13 +58,7 @@
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||
<select-user ref="selectRef" :roleId="queryParams.roleId" @ok="handleQuery" />
|
||||
</el-card>
|
||||
</div>
|
||||
@ -73,10 +67,8 @@
|
||||
<script setup name="AuthUser" lang="ts">
|
||||
import { allocatedUserList, authUserCancel, authUserCancelAll } from "@/api/system/role";
|
||||
import { UserQuery } from "@/api/system/user/types";
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
import { UserVO } from "@/api/system/user/types";
|
||||
import SelectUser from "./selectUser.vue";
|
||||
// import { ElForm, ElSelect} from 'element-plus';
|
||||
|
||||
|
||||
const route = useRoute();
|
||||
@ -90,8 +82,8 @@ const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
const userIds = ref<Array<string | number>>([]);
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
const selectRef = ref(SelectUser);
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const selectRef = ref<InstanceType<typeof SelectUser>>();
|
||||
|
||||
const queryParams = reactive<UserQuery>({
|
||||
pageNum: 1,
|
||||
@ -121,7 +113,7 @@ const handleQuery=() => {
|
||||
}
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
// 多选框选中数据
|
||||
@ -131,13 +123,13 @@ const handleSelectionChange = (selection: UserVO[]) =>{
|
||||
}
|
||||
/** 打开授权用户表弹窗 */
|
||||
const openSelectUser = () => {
|
||||
selectRef.value.show();
|
||||
selectRef.value?.show();
|
||||
}
|
||||
/** 取消授权按钮操作 */
|
||||
const cancelAuthUser = async (row: UserVO) => {
|
||||
await proxy?.$modal.confirm('确认要取消该用户"' + row.userName + '"角色吗?');
|
||||
await authUserCancel({ userId: row.userId, roleId: queryParams.roleId });
|
||||
getList();
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess("取消授权成功");
|
||||
}
|
||||
/** 批量取消授权按钮操作 */
|
||||
@ -146,7 +138,7 @@ const cancelAuthUserAll = async () => {
|
||||
const uIds = userIds.value.join(",");
|
||||
await proxy?.$modal.confirm("是否取消选中用户授权数据项?");
|
||||
await authUserCancelAll({ roleId: roleId, userIds: uIds });
|
||||
getList();
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess("取消授权成功");
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div class="search" v-show="showSearch">
|
||||
<div class="mb-[10px]" v-show="showSearch">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||
<el-form-item label="角色名称" prop="roleName">
|
||||
<el-input v-model="queryParams.roleName" placeholder="请输入角色名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||
@ -31,10 +32,11 @@
|
||||
<el-button @click="resetQuery" icon="Refresh">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="1.5">
|
||||
@ -196,8 +198,6 @@ import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updat
|
||||
import { roleMenuTreeselect, treeselect as menuTreeselect } from '@/api/system/menu/index';
|
||||
import { RoleVO, RoleForm, RoleQuery, DeptTreeOption } from '@/api/system/role/types';
|
||||
import { MenuTreeOption, RoleMenuTree } from '@/api/system/menu/types';
|
||||
import { ComponentInternalInstance } from 'vue';
|
||||
import { ElTree, ElForm, DateModelType } from 'element-plus';
|
||||
|
||||
const router = useRouter();
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
@ -228,11 +228,11 @@ const dataScopeOptions = ref([
|
||||
{ value: "5", label: "仅本人数据权限" }
|
||||
])
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
const roleFormRef = ref(ElForm);
|
||||
const dataScopeRef = ref(ElForm);
|
||||
const menuRef = ref(ElTree);
|
||||
const deptRef = ref(ElTree);
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const roleFormRef = ref<ElFormInstance>();
|
||||
const dataScopeRef = ref<ElFormInstance>();
|
||||
const menuRef = ref<ElTreeInstance>();
|
||||
const deptRef = ref<ElTreeInstance>();
|
||||
|
||||
const initForm: RoleForm = {
|
||||
roleId: undefined,
|
||||
@ -265,13 +265,11 @@ const data = reactive<PageData<RoleForm, RoleQuery>>({
|
||||
})
|
||||
const { form, queryParams, rules } = toRefs(data)
|
||||
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* 查询角色列表
|
||||
*/
|
||||
@ -295,7 +293,7 @@ const handleQuery = () => {
|
||||
/** 重置 */
|
||||
const resetQuery = () => {
|
||||
dateRange.value = ['', '']
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
/**删除按钮操作 */
|
||||
@ -343,56 +341,51 @@ const getMenuTreeselect = async () => {
|
||||
menuOptions.value = res.data;
|
||||
}
|
||||
/** 所有部门节点数据 */
|
||||
const getDeptAllCheckedKeys = () => {
|
||||
const getDeptAllCheckedKeys = (): any => {
|
||||
// 目前被选中的部门节点
|
||||
let checkedKeys = deptRef.value.getCheckedKeys();
|
||||
let checkedKeys = deptRef.value?.getCheckedKeys();
|
||||
// 半选中的部门节点
|
||||
let halfCheckedKeys = deptRef.value.getHalfCheckedKeys();
|
||||
checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
|
||||
let halfCheckedKeys = deptRef.value?.getHalfCheckedKeys();
|
||||
if (halfCheckedKeys) {
|
||||
checkedKeys?.unshift.apply(checkedKeys, halfCheckedKeys);
|
||||
}
|
||||
return checkedKeys
|
||||
}
|
||||
/** 重置新增的表单以及其他数据 */
|
||||
const reset = () => {
|
||||
menuRef.value.setCheckedKeys([]);
|
||||
menuRef.value?.setCheckedKeys([]);
|
||||
menuExpand.value = false
|
||||
menuNodeAll.value = false
|
||||
deptExpand.value = true
|
||||
deptNodeAll.value = false
|
||||
form.value = { ...initForm };
|
||||
roleFormRef.value.resetFields();
|
||||
roleFormRef.value?.resetFields();
|
||||
|
||||
}
|
||||
|
||||
/** 添加角色 */
|
||||
const handleAdd = () => {
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加角色";
|
||||
nextTick(() => {
|
||||
reset();
|
||||
getMenuTreeselect();
|
||||
})
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加角色";
|
||||
}
|
||||
/** 修改角色 */
|
||||
const handleUpdate = async (row?: RoleVO) => {
|
||||
const roleId = row?.roleId || ids.value[0]
|
||||
const roleMenu = getRoleMenuTreeselect(roleId)
|
||||
const { data } = await getRole(roleId);
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改角色";
|
||||
nextTick(() => {
|
||||
reset();
|
||||
const roleId = row?.roleId || ids.value[0]
|
||||
const { data } = await getRole(roleId);
|
||||
Object.assign(form.value, data);
|
||||
form.value.roleSort = Number(form.value.roleSort);
|
||||
nextTick(async () => {
|
||||
const res = await roleMenu;
|
||||
let checkedKeys = res.checkedKeys;
|
||||
checkedKeys.forEach((v) => {
|
||||
const res = await getRoleMenuTreeselect(roleId);
|
||||
dialog.title = "修改角色";
|
||||
dialog.visible = true;
|
||||
res.checkedKeys.forEach((v) => {
|
||||
nextTick(() => {
|
||||
menuRef.value.setChecked(v, true, false);
|
||||
})
|
||||
})
|
||||
menuRef.value?.setChecked(v, true, false);
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
/** 根据角色ID查询菜单树结构 */
|
||||
const getRoleMenuTreeselect = (roleId: string | number) => {
|
||||
@ -408,25 +401,29 @@ const getRoleDeptTreeSelect = async (roleId: string | number) => {
|
||||
return res.data;
|
||||
}
|
||||
/** 树权限(展开/折叠)*/
|
||||
const handleCheckedTreeExpand = (value: any, type: string) => {
|
||||
const handleCheckedTreeExpand = (value: boolean, type: string) => {
|
||||
if (type == "menu") {
|
||||
let treeList = menuOptions.value;
|
||||
for (let i = 0; i < treeList.length; i++) {
|
||||
if (menuRef.value) {
|
||||
menuRef.value.store.nodesMap[treeList[i].id].expanded = value;
|
||||
}
|
||||
}
|
||||
} else if (type == "dept") {
|
||||
let treeList = deptOptions.value;
|
||||
for (let i = 0; i < treeList.length; i++) {
|
||||
if (deptRef.value) {
|
||||
deptRef.value.store.nodesMap[treeList[i].id].expanded = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 树权限(全选/全不选) */
|
||||
const handleCheckedTreeNodeAll = (value: any, type: string) => {
|
||||
if (type == "menu") {
|
||||
menuRef.value.setCheckedNodes(value ? menuOptions.value : []);
|
||||
menuRef.value?.setCheckedNodes(value ? menuOptions.value as any : []);
|
||||
} else if (type == "dept") {
|
||||
deptRef.value.setCheckedNodes(value ? deptOptions.value : []);
|
||||
deptRef.value?.setCheckedNodes(value ? deptOptions.value as any : []);
|
||||
}
|
||||
}
|
||||
/** 树权限(父子联动) */
|
||||
@ -438,17 +435,19 @@ const handleCheckedTreeConnect = (value: any, type: string) => {
|
||||
}
|
||||
}
|
||||
/** 所有菜单节点数据 */
|
||||
const getMenuAllCheckedKeys = () => {
|
||||
const getMenuAllCheckedKeys = (): any => {
|
||||
// 目前被选中的菜单节点
|
||||
let checkedKeys = menuRef.value.getCheckedKeys();
|
||||
let checkedKeys = menuRef.value?.getCheckedKeys();
|
||||
// 半选中的菜单节点
|
||||
let halfCheckedKeys = menuRef.value.getHalfCheckedKeys();
|
||||
checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
|
||||
let halfCheckedKeys = menuRef.value?.getHalfCheckedKeys();
|
||||
if (halfCheckedKeys) {
|
||||
checkedKeys?.unshift.apply(checkedKeys, halfCheckedKeys);
|
||||
}
|
||||
return checkedKeys;
|
||||
}
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
roleFormRef.value.validate(async (valid: boolean) => {
|
||||
roleFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
form.value.menuIds = getMenuAllCheckedKeys()
|
||||
form.value.roleId ? await updateRole(form.value) : await addRole(form.value);
|
||||
@ -466,23 +465,18 @@ const cancel = () => {
|
||||
/** 选择角色权限范围触发 */
|
||||
const dataScopeSelectChange = (value: string) => {
|
||||
if (value !== "2") {
|
||||
deptRef.value.setCheckedKeys([])
|
||||
deptRef.value?.setCheckedKeys([])
|
||||
}
|
||||
}
|
||||
/** 分配数据权限操作 */
|
||||
const handleDataScope = async (row: RoleVO) => {
|
||||
const roleDeptTreeselect = getRoleDeptTreeSelect(row.roleId);
|
||||
const response = await getRole(row.roleId);
|
||||
Object.assign(form.value, response.data);
|
||||
const res = await getRoleDeptTreeSelect(row.roleId);
|
||||
openDataScope.value = true;
|
||||
dialog.title = "分配数据权限";
|
||||
nextTick(async () => {
|
||||
const res = await roleDeptTreeselect;
|
||||
nextTick(() => {
|
||||
if (deptRef.value) {
|
||||
deptRef.value.setCheckedKeys(res.checkedKeys);
|
||||
}
|
||||
})
|
||||
await nextTick(() => {
|
||||
deptRef.value?.setCheckedKeys(res.checkedKeys);
|
||||
})
|
||||
}
|
||||
/** 提交按钮(数据权限) */
|
||||
@ -497,7 +491,7 @@ const submitDataScope = async () => {
|
||||
}
|
||||
/** 取消按钮(数据权限)*/
|
||||
const cancelDataScope = () => {
|
||||
dataScopeRef.value.resetFields();
|
||||
dataScopeRef.value?.resetFields();
|
||||
form.value = { ...initForm };
|
||||
openDataScope.value = false;
|
||||
}
|
||||
|
@ -47,8 +47,6 @@
|
||||
import { authUserSelectAll, unallocatedUserList } from "@/api/system/role";
|
||||
import { UserVO } from '@/api/system/user/types';
|
||||
import { UserQuery } from '@/api/system/user/types';
|
||||
import { ComponentInternalInstance } from 'vue';
|
||||
import { ElForm, ElTable } from 'element-plus';
|
||||
|
||||
|
||||
const props = defineProps({
|
||||
@ -73,8 +71,8 @@ const queryParams = reactive<UserQuery>({
|
||||
phonenumber: undefined
|
||||
})
|
||||
|
||||
const tableRef = ref(ElTable);
|
||||
const queryFormRef = ref(ElForm);
|
||||
const tableRef = ref<ElTableInstance>();
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
|
||||
const show = () => {
|
||||
queryParams.roleId = props.roleId;
|
||||
@ -86,7 +84,8 @@ const show = () => {
|
||||
* 选择行
|
||||
*/
|
||||
const clickRow = (row: any) => {
|
||||
tableRef.value.toggleRowSelection(row);
|
||||
// ele的bug
|
||||
tableRef.value?.toggleRowSelection(row, false);
|
||||
}
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: UserVO[]) => {
|
||||
@ -106,7 +105,7 @@ const handleQuery = () => {
|
||||
}
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
getList();
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div class="search" v-show="showSearch">
|
||||
<div class="mb-[10px]" v-show="showSearch">
|
||||
<el-card shadow="hover">
|
||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
||||
<el-form-item label="租户编号" prop="tenantId">
|
||||
<el-input v-model="queryParams.tenantId" placeholder="请输入租户编号" clearable @keyup.enter="handleQuery" />
|
||||
@ -20,10 +21,11 @@
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
@ -64,7 +66,7 @@
|
||||
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<el-table-column width="150" label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-tooltip content="修改" placement="top">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:tenant:edit']"></el-button>
|
||||
@ -143,8 +145,6 @@ import { listTenant, getTenant, delTenant, addTenant, updateTenant, changeTenant
|
||||
import { selectTenantPackage } from '@/api/system/tenantPackage';
|
||||
import { TenantForm, TenantQuery, TenantVO } from '@/api/system/tenant/types';
|
||||
import { TenantPkgVO } from '@/api/system/tenantPackage/types';
|
||||
import { ComponentInternalInstance } from 'vue';
|
||||
import { ElForm } from 'element-plus';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
@ -158,8 +158,8 @@ const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
const tenantFormRef = ref(ElForm);
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const tenantFormRef = ref<ElFormInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
@ -251,7 +251,7 @@ const cancel = () => {
|
||||
// 表单重置
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
tenantFormRef.value.resetFields();
|
||||
tenantFormRef.value?.resetFields();
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
@ -262,7 +262,7 @@ const handleQuery = () => {
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
@ -275,32 +275,26 @@ const handleSelectionChange = (selection: TenantVO[]) => {
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加租户";
|
||||
nextTick(() => {
|
||||
reset();
|
||||
getTenantPackage();
|
||||
})
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加租户";
|
||||
}
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = (row?: TenantVO) => {
|
||||
loading.value = true;
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改租户";
|
||||
nextTick(async () => {
|
||||
const handleUpdate = async (row?: TenantVO) => {
|
||||
reset();
|
||||
getTenantPackage();
|
||||
await getTenantPackage();
|
||||
const _id = row?.id || ids.value[0];
|
||||
const res = await getTenant(_id);
|
||||
loading.value = false;
|
||||
Object.assign(form.value, res.data)
|
||||
})
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改租户";
|
||||
}
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
tenantFormRef.value.validate(async (valid: boolean) => {
|
||||
tenantFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
if (form.value.id) {
|
||||
@ -310,7 +304,7 @@ const submitForm = () => {
|
||||
}
|
||||
proxy?.$modal.msgSuccess("操作成功");
|
||||
dialog.visible = false;
|
||||
getList();
|
||||
await getList();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -321,7 +315,7 @@ const handleDelete = async (row?: TenantVO) => {
|
||||
await proxy?.$modal.confirm('是否确认删除租户编号为"' + _ids + '"的数据项?')
|
||||
loading.value = true;
|
||||
await delTenant(_ids).finally(() => loading.value = false);
|
||||
getList();
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess("删除成功");
|
||||
|
||||
|
||||
@ -333,7 +327,7 @@ const handleSyncTenantPackage = async (row: TenantVO) => {
|
||||
await proxy?.$modal.confirm('是否确认同步租户套餐租户编号为"' + row.tenantId + '"的数据项?');
|
||||
loading.value = true;
|
||||
await syncTenantPackage(row.tenantId, row.packageId);
|
||||
getList();
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess("同步成功");
|
||||
} catch { return } finally {
|
||||
loading.value = false;
|
||||
|
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div class="search" v-show="showSearch">
|
||||
<div class="mb-[10px]" v-show="showSearch">
|
||||
<el-card shadow="hover">
|
||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
||||
<el-form-item label="套餐名称" prop="packageName">
|
||||
<el-input v-model="queryParams.packageName" placeholder="请输入套餐名称" clearable @keyup.enter="handleQuery" />
|
||||
@ -11,24 +12,25 @@
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:tenantPackage:add']"> 新增 </el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:tenantPackage:edit']"
|
||||
>修改</el-button
|
||||
>
|
||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:tenantPackage:edit']">
|
||||
修改
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:tenantPackage:remove']"
|
||||
>删除</el-button
|
||||
>
|
||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:tenantPackage:remove']">
|
||||
删除
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:tenantPackage:export']">导出 </el-button>
|
||||
@ -98,12 +100,17 @@
|
||||
</template>
|
||||
|
||||
<script setup name="TenantPackage" lang="ts">
|
||||
import { listTenantPackage, getTenantPackage, delTenantPackage, addTenantPackage, updateTenantPackage, changePackageStatus } from "@/api/system/tenantPackage";
|
||||
import {
|
||||
listTenantPackage,
|
||||
getTenantPackage,
|
||||
delTenantPackage,
|
||||
addTenantPackage,
|
||||
updateTenantPackage,
|
||||
changePackageStatus
|
||||
} from "@/api/system/tenantPackage";
|
||||
import { treeselect as menuTreeselect, tenantPackageMenuTreeselect } from "@/api/system/menu";
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
import { TenantPkgForm, TenantPkgQuery, TenantPkgVO } from "@/api/system/tenantPackage/types";
|
||||
import { MenuTreeOption } from "@/api/system/menu/types";
|
||||
import { CheckboxValueType, ElTree, ElForm } from 'element-plus';
|
||||
import to from "await-to-js";
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
@ -120,21 +127,21 @@ const menuExpand = ref(false);
|
||||
const menuNodeAll = ref(false);
|
||||
const menuOptions = ref<MenuTreeOption[]>([]);
|
||||
|
||||
const menuTreeRef = ref(ElTree);
|
||||
const queryFormRef = ref(ElForm);
|
||||
const tenantPackageFormRef = ref(ElForm);
|
||||
const menuTreeRef = ref<ElTreeInstance>();
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const tenantPackageFormRef = ref<ElFormInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
title: ""
|
||||
});
|
||||
|
||||
|
||||
const initFormData: TenantPkgForm = {
|
||||
packageId: undefined,
|
||||
packageName: '',
|
||||
menuIds: '',
|
||||
remark: '',
|
||||
packageName: "",
|
||||
menuIds: "",
|
||||
remark: "",
|
||||
menuCheckStrictly: true
|
||||
};
|
||||
const data = reactive<PageData<TenantPkgForm, TenantPkgQuery>>({
|
||||
@ -142,7 +149,7 @@ const data = reactive<PageData<TenantPkgForm, TenantPkgQuery>>({
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
packageName: ''
|
||||
packageName: ""
|
||||
},
|
||||
rules: {
|
||||
packageId: [{ required: true, message: "租户套餐id不能为空", trigger: "blur" }],
|
||||
@ -156,24 +163,26 @@ const { queryParams, form, rules } = toRefs(data);
|
||||
const getMenuTreeselect = async () => {
|
||||
const { data } = await menuTreeselect();
|
||||
menuOptions.value = data;
|
||||
}
|
||||
};
|
||||
|
||||
// 所有菜单节点数据
|
||||
const getMenuAllCheckedKeys = () => {
|
||||
const getMenuAllCheckedKeys = (): any => {
|
||||
// 目前被选中的菜单节点
|
||||
let checkedKeys = menuTreeRef.value.getCheckedKeys();
|
||||
let checkedKeys = menuTreeRef.value?.getCheckedKeys();
|
||||
// 半选中的菜单节点
|
||||
let halfCheckedKeys = menuTreeRef.value.getHalfCheckedKeys();
|
||||
checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
|
||||
return checkedKeys;
|
||||
let halfCheckedKeys = menuTreeRef.value?.getHalfCheckedKeys();
|
||||
if (halfCheckedKeys) {
|
||||
checkedKeys?.unshift.apply(checkedKeys, halfCheckedKeys);
|
||||
}
|
||||
return checkedKeys;
|
||||
};
|
||||
|
||||
/** 根据租户套餐ID查询菜单树结构 */
|
||||
const getPackageMenuTreeselect = async (packageId: string | number) => {
|
||||
const res = await tenantPackageMenuTreeselect(packageId);
|
||||
menuOptions.value = res.data.menus;
|
||||
return Promise.resolve(res);
|
||||
}
|
||||
};
|
||||
|
||||
/** 查询租户套餐列表 */
|
||||
const getList = async () => {
|
||||
@ -182,115 +191,107 @@ const getList = async () => {
|
||||
tenantPackageList.value = res.rows;
|
||||
total.value = res.total;
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 租户套餐状态修改
|
||||
const handleStatusChange = async (row: TenantPkgVO) => {
|
||||
let text = row.status === "0" ? "启用" : "停用";
|
||||
const [err] = await to(proxy?.$modal.confirm('确认要"' + text + '""' + row.packageName + '"套餐吗?') as Promise<any>)
|
||||
const [err] = await to(proxy?.$modal.confirm("确认要\"" + text + "\"\"" + row.packageName + "\"套餐吗?") as Promise<any>);
|
||||
if (err) {
|
||||
row.status = row.status === "0" ? "1" : "0";
|
||||
} else {
|
||||
await changePackageStatus(row.packageId, row.status);
|
||||
proxy?.$modal.msgSuccess(text + "成功");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 取消按钮
|
||||
const cancel = () => {
|
||||
reset();
|
||||
dialog.visible = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 表单重置
|
||||
const reset = () => {
|
||||
menuTreeRef.value.setCheckedKeys([]);
|
||||
menuTreeRef.value?.setCheckedKeys([]);
|
||||
menuExpand.value = false;
|
||||
menuNodeAll.value = false;
|
||||
form.value = { ...initFormData };
|
||||
tenantPackageFormRef.value.resetFields();
|
||||
}
|
||||
tenantPackageFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
}
|
||||
};
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
};
|
||||
|
||||
// 多选框选中数据
|
||||
const handleSelectionChange = (selection: TenantPkgVO[]) => {
|
||||
ids.value = selection.map(item => item.packageId);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
}
|
||||
};
|
||||
|
||||
// 树权限(展开/折叠)
|
||||
const handleCheckedTreeExpand = (value: CheckboxValueType, type: string) => {
|
||||
if (type == 'menu') {
|
||||
if (type == "menu") {
|
||||
let treeList = menuOptions.value;
|
||||
for (let i = 0; i < treeList.length; i++) {
|
||||
menuTreeRef.value.store.nodesMap[treeList[i].id].expanded = value;
|
||||
if (menuTreeRef.value) {
|
||||
menuTreeRef.value.store.nodesMap[treeList[i].id].expanded = value as boolean;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 树权限(全选/全不选)
|
||||
const handleCheckedTreeNodeAll = (value: CheckboxValueType, type: string) => {
|
||||
if (type == 'menu') {
|
||||
menuTreeRef.value.setCheckedNodes(value ? menuOptions.value: []);
|
||||
}
|
||||
if (type == "menu") {
|
||||
menuTreeRef.value?.setCheckedNodes(value ? menuOptions.value as any : []);
|
||||
}
|
||||
};
|
||||
|
||||
// 树权限(父子联动)
|
||||
const handleCheckedTreeConnect = (value: CheckboxValueType, type: string) => {
|
||||
if (type == 'menu') {
|
||||
if (type == "menu") {
|
||||
form.value.menuCheckStrictly = value as boolean;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加租户套餐";
|
||||
nextTick(() => {
|
||||
reset();
|
||||
getMenuTreeselect();
|
||||
})
|
||||
}
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加租户套餐";
|
||||
};
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = (row?: TenantPkgVO) => {
|
||||
loading.value = true
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改租户套餐";
|
||||
nextTick(async () => {
|
||||
const handleUpdate = async (row?: TenantPkgVO) => {
|
||||
reset();
|
||||
const _packageId = row?.packageId || ids.value[0];
|
||||
const packageMenu = getPackageMenuTreeselect(_packageId);
|
||||
const response = await getTenantPackage(_packageId);
|
||||
loading.value = false;
|
||||
form.value = response.data;
|
||||
nextTick(async () => {
|
||||
const res = await packageMenu;
|
||||
let checkedKeys = res.data.checkedKeys
|
||||
checkedKeys.forEach((v) => {
|
||||
const res = await getPackageMenuTreeselect(_packageId);
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改租户套餐";
|
||||
res.data.checkedKeys.forEach((v) => {
|
||||
nextTick(() => {
|
||||
menuTreeRef.value.setChecked(v, true ,false);
|
||||
})
|
||||
})
|
||||
menuTreeRef.value?.setChecked(v, true, false);
|
||||
});
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
tenantPackageFormRef.value.validate(async (valid: boolean) => {
|
||||
tenantPackageFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
form.value.menuIds = getMenuAllCheckedKeys();
|
||||
@ -301,31 +302,31 @@ const submitForm = () => {
|
||||
}
|
||||
proxy?.$modal.msgSuccess("操作成功");
|
||||
dialog.visible = false;
|
||||
getList();
|
||||
await getList();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: TenantPkgVO) => {
|
||||
const _packageIds = row?.packageId || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除租户套餐编号为"' + _packageIds + '"的数据项?').finally(() => {
|
||||
await proxy?.$modal.confirm("是否确认删除租户套餐编号为\"" + _packageIds + "\"的数据项?").finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
await delTenantPackage(_packageIds);
|
||||
loading.value = true;
|
||||
getList();
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess("删除成功");
|
||||
}
|
||||
};
|
||||
|
||||
/** 导出按钮操作 */
|
||||
const handleExport = () => {
|
||||
proxy?.download('system/tenantPackage/export', {
|
||||
proxy?.download("system/tenantPackage/export", {
|
||||
...queryParams.value
|
||||
}, `tenantPackage_${new Date().getTime()}.xlsx`)
|
||||
}
|
||||
}, `tenantPackage_${new Date().getTime()}.xlsx`);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
@ -55,11 +55,10 @@
|
||||
</template>
|
||||
|
||||
<script setup name="AuthRole" lang="ts">
|
||||
import { RoleVO } from '@/api/system/role/types';
|
||||
import { getAuthRole, updateAuthRole } from '@/api/system/user';
|
||||
import { UserForm } from '@/api/system/user/types';
|
||||
import { ElTable } from "element-plus";
|
||||
import { ComponentInternalInstance } from 'vue';
|
||||
import { RoleVO } from "@/api/system/role/types";
|
||||
import { getAuthRole, updateAuthRole } from "@/api/system/user";
|
||||
import { UserForm } from "@/api/system/user/types";
|
||||
|
||||
const route = useRoute();
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
@ -71,15 +70,16 @@ const roleIds = ref<Array<string | number>>([]);
|
||||
const roles = ref<RoleVO[]>([]);
|
||||
const form = ref<Partial<UserForm>>({
|
||||
nickName: undefined,
|
||||
userName: '',
|
||||
userName: "",
|
||||
userId: undefined
|
||||
});
|
||||
|
||||
const tableRef = ref(ElTable)
|
||||
const tableRef = ref<ElTableInstance>();
|
||||
|
||||
/** 单击选中行数据 */
|
||||
const clickRow = (row: RoleVO) => {
|
||||
tableRef.value.toggleRowSelection(row);
|
||||
// ele的方法有问题,selected应该为可选参数
|
||||
tableRef.value?.toggleRowSelection(row, false);
|
||||
};
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: RoleVO[]) => {
|
||||
@ -98,7 +98,7 @@ const close = () => {
|
||||
const submitForm = async () => {
|
||||
const userId = form.value.userId;
|
||||
const rIds = roleIds.value.join(",");
|
||||
await updateAuthRole({ userId: userId as string, roleIds: rIds })
|
||||
await updateAuthRole({ userId: userId as string, roleIds: rIds });
|
||||
proxy?.$modal.msgSuccess("授权成功");
|
||||
close();
|
||||
};
|
||||
@ -108,20 +108,20 @@ const getList = async() => {
|
||||
if (userId) {
|
||||
loading.value = true;
|
||||
const res = await getAuthRole(userId as string);
|
||||
Object.assign(form.value, res.data.user)
|
||||
Object.assign(roles.value, res.data.roles)
|
||||
Object.assign(form.value, res.data.user);
|
||||
Object.assign(roles.value, res.data.roles);
|
||||
total.value = roles.value.length;
|
||||
await nextTick(() => {
|
||||
roles.value.forEach(row => {
|
||||
if (row?.flag) {
|
||||
tableRef.value.toggleRowSelection(row);
|
||||
tableRef.value?.toggleRowSelection(row, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
getList();
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
@ -16,18 +16,25 @@
|
||||
highlight-current
|
||||
default-expand-all
|
||||
@node-click="handleNodeClick"
|
||||
></el-tree>
|
||||
/>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :lg="20" :xs="24">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div class="search" v-show="showSearch">
|
||||
<div class="mb-[10px]" v-show="showSearch">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="68px">
|
||||
<el-form-item label="用户名称" prop="userName">
|
||||
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号码" prop="phonenumber">
|
||||
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter="handleQuery" />
|
||||
<el-input
|
||||
v-model="queryParams.phonenumber"
|
||||
placeholder="请输入手机号码"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="状态" prop="status">
|
||||
@ -50,6 +57,7 @@
|
||||
<el-button @click="resetQuery" icon="Refresh">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
@ -146,7 +154,7 @@
|
||||
</el-row>
|
||||
|
||||
<!-- 添加或修改用户配置对话框 -->
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="600px" append-to-body @close="closeDialog">
|
||||
<el-dialog ref="formDialogRef" :title="dialog.title" v-model="dialog.visible" width="600px" append-to-body @close="closeDialog">
|
||||
<el-form :model="form" :rules="rules" ref="userFormRef" label-width="80px">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
@ -289,30 +297,20 @@
|
||||
</template>
|
||||
|
||||
<script setup name="User" lang="ts">
|
||||
import {
|
||||
changeUserStatus,
|
||||
listUser,
|
||||
resetUserPwd,
|
||||
delUser,
|
||||
getUser,
|
||||
updateUser,
|
||||
addUser,
|
||||
deptTreeSelect
|
||||
} from "@/api/system/user"
|
||||
import api from "@/api/system/user"
|
||||
import { UserForm, UserQuery, UserVO } from '@/api/system/user/types';
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
import { getToken } from "@/utils/auth";
|
||||
import { treeselect } from "@/api/system/dept";
|
||||
import { DeptVO } from "@/api/system/dept/types";
|
||||
import { RoleVO } from "@/api/system/role/types";
|
||||
import { PostVO } from "@/api/system/post/types";
|
||||
import { DateModelType, ElTree, ElUpload, UploadFile, ElForm } from 'element-plus';
|
||||
import { to } from "await-to-js";
|
||||
import { globalHeaders } from "@/utils/request";
|
||||
|
||||
const router = useRouter();
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance
|
||||
const { sys_normal_disable, sys_user_sex } = toRefs<any>(proxy?.useDict('sys_normal_disable', 'sys_user_sex'));
|
||||
|
||||
|
||||
const userList = ref<UserVO[]>();
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true)
|
||||
@ -337,7 +335,7 @@ const upload = reactive<ImportOption>({
|
||||
// 是否更新已经存在的用户数据
|
||||
updateSupport: 0,
|
||||
// 设置上传的请求头部
|
||||
headers: { Authorization: "Bearer " + getToken() },
|
||||
headers: globalHeaders,
|
||||
// 上传的地址
|
||||
url: import.meta.env.VITE_APP_BASE_API + "/system/user/importData"
|
||||
})
|
||||
@ -353,10 +351,11 @@ const columns = ref<FieldOption[]>([
|
||||
])
|
||||
|
||||
|
||||
const deptTreeRef = ref(ElTree);
|
||||
const queryFormRef = ref(ElForm);
|
||||
const userFormRef = ref(ElForm);
|
||||
const uploadRef = ref(ElUpload);
|
||||
const deptTreeRef = ref<ElTreeInstance>();
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const userFormRef = ref<ElFormInstance>();
|
||||
const uploadRef = ref<ElUploadInstance>();
|
||||
const formDialogRef = ref<ElDialogInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
@ -405,7 +404,7 @@ const filterNode = (value: string, data: any) => {
|
||||
}
|
||||
/** 根据名称筛选部门树 */
|
||||
watchEffect(
|
||||
() => {deptTreeRef.value.filter(deptName.value);},
|
||||
() => { deptTreeRef.value?.filter(deptName.value); },
|
||||
{
|
||||
flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发,此属性控制在DOM元素更新后运行
|
||||
}
|
||||
@ -413,14 +412,14 @@ watchEffect(
|
||||
|
||||
/** 查询部门下拉树结构 */
|
||||
const getTreeSelect = async () => {
|
||||
const res = await deptTreeSelect();
|
||||
const res = await api.deptTreeSelect();
|
||||
deptOptions.value = res.data;
|
||||
};
|
||||
|
||||
/** 查询用户列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
const res = await listUser(proxy?.addDateRange(queryParams.value, dateRange.value));
|
||||
const res = await api.listUser(proxy?.addDateRange(queryParams.value, dateRange.value));
|
||||
loading.value = false;
|
||||
userList.value = res.rows;
|
||||
total.value = res.total;
|
||||
@ -441,10 +440,10 @@ const handleQuery = () => {
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
dateRange.value = ['', '']
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
queryParams.value.pageNum = 1;
|
||||
queryParams.value.deptId = undefined;
|
||||
deptTreeRef.value.setCurrentKey(null);
|
||||
deptTreeRef.value?.setCurrentKey(undefined);
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
@ -453,7 +452,7 @@ const handleDelete = async (row?: UserVO) => {
|
||||
const userIds = row?.userId || ids.value;
|
||||
const [err] = await to(proxy?.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?') as any);
|
||||
if (!err) {
|
||||
await delUser(userIds);
|
||||
await api.delUser(userIds);
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess("删除成功");
|
||||
}
|
||||
@ -464,7 +463,7 @@ const handleStatusChange = async (row: UserVO) => {
|
||||
let text = row.status === "0" ? "启用" : "停用"
|
||||
try {
|
||||
await proxy?.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?');
|
||||
await changeUserStatus(row.userId, row.status);
|
||||
await api.changeUserStatus(row.userId, row.status);
|
||||
proxy?.$modal.msgSuccess(text + "成功");
|
||||
} catch (err) {
|
||||
row.status = row.status === "0" ? "1" : "0";
|
||||
@ -486,7 +485,7 @@ const handleResetPwd = async (row: UserVO) => {
|
||||
inputErrorMessage: "用户密码长度必须介于 5 和 20 之间",
|
||||
}))
|
||||
if (!err) {
|
||||
await resetUserPwd(row.userId, res.value);
|
||||
await api.resetUserPwd(row.userId, res.value);
|
||||
proxy?.$modal.msgSuccess("修改成功,新密码是:" + res.value);
|
||||
}
|
||||
}
|
||||
@ -523,14 +522,14 @@ const handleFileUploadProgress = () => {
|
||||
const handleFileSuccess = (response: any, file: UploadFile) => {
|
||||
upload.open = false;
|
||||
upload.isUploading = false;
|
||||
uploadRef.value.handleRemove(file);
|
||||
uploadRef.value?.handleRemove(file);
|
||||
ElMessageBox.alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true });
|
||||
getList();
|
||||
}
|
||||
|
||||
/** 提交上传文件 */
|
||||
function submitFileForm() {
|
||||
uploadRef.value.submit();
|
||||
uploadRef.value?.submit();
|
||||
}
|
||||
|
||||
/** 初始化部门数据 */
|
||||
@ -546,51 +545,46 @@ const initTreeData = async () => {
|
||||
/** 重置操作表单 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
userFormRef.value.resetFields();
|
||||
userFormRef.value?.resetFields();
|
||||
}
|
||||
/** 取消按钮 */
|
||||
const cancel = () => {
|
||||
reset();
|
||||
dialog.visible = false;
|
||||
reset();
|
||||
}
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
const handleAdd = async () => {
|
||||
reset();
|
||||
const { data } = await api.getUser();
|
||||
dialog.visible = true;
|
||||
dialog.title = "新增用户";
|
||||
nextTick(async () => {
|
||||
reset();
|
||||
await initTreeData();
|
||||
const { data } = await getUser();
|
||||
postOptions.value = data.posts;
|
||||
roleOptions.value = data.roles;
|
||||
form.value.password = initPassword.value;
|
||||
})
|
||||
}
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = (row?: UserForm) => {
|
||||
const handleUpdate = async (row?: UserForm) => {
|
||||
reset();
|
||||
const userId = row?.userId || ids.value[0]
|
||||
const { data } = await api.getUser(userId)
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改用户";
|
||||
nextTick(async () => {
|
||||
reset();
|
||||
await initTreeData();
|
||||
const userId = row?.userId || ids.value[0]
|
||||
const { data } = await getUser(userId)
|
||||
Object.assign(form.value, data.user);
|
||||
postOptions.value = data.posts;
|
||||
roleOptions.value = data.roles;
|
||||
form.value.postIds = data.postIds;
|
||||
form.value.roleIds = data.roleIds;
|
||||
form.value.password = "";
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
userFormRef.value.validate(async (valid: boolean) => {
|
||||
userFormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
form.value.userId ? await updateUser(form.value) : await addUser(form.value);
|
||||
form.value.userId ? await api.updateUser(form.value) : await api.addUser(form.value);
|
||||
proxy?.$modal.msgSuccess("操作成功");
|
||||
dialog.visible = false;
|
||||
await getList();
|
||||
@ -611,8 +605,8 @@ const closeDialog = () => {
|
||||
* 重置表单
|
||||
*/
|
||||
const resetForm = () => {
|
||||
userFormRef.value.resetFields();
|
||||
userFormRef.value.clearValidate();
|
||||
userFormRef.value?.resetFields();
|
||||
userFormRef.value?.clearValidate();
|
||||
|
||||
form.value.id = undefined;
|
||||
form.value.status = '1';
|
||||
|
@ -55,6 +55,9 @@
|
||||
<el-tab-pane label="修改密码" name="resetPwd">
|
||||
<resetPwd />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="第三方应用" name="thirdParty">
|
||||
<thirdParty :auths="state.auths" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
</el-col>
|
||||
@ -66,13 +69,16 @@
|
||||
import userAvatar from "./userAvatar.vue";
|
||||
import userInfo from "./userInfo.vue";
|
||||
import resetPwd from "./resetPwd.vue";
|
||||
import thirdParty from "./thirdParty.vue";
|
||||
import { getAuthList } from "@/api/system/social/auth";
|
||||
import { getUserProfile } from "@/api/system/user";
|
||||
|
||||
const activeTab = ref("userinfo");
|
||||
const state = ref<{ user: any; roleGroup: string; postGroup: string}>({
|
||||
const state = ref<Record<string, any>>({
|
||||
user: {},
|
||||
roleGroup: '',
|
||||
postGroup: ''
|
||||
postGroup: '',
|
||||
auths: []
|
||||
});
|
||||
|
||||
const userForm = ref({});
|
||||
@ -85,7 +91,13 @@ const getUser = async () => {
|
||||
state.value.postGroup = res.data.postGroup;
|
||||
};
|
||||
|
||||
const getAuths = async () => {
|
||||
const res = await getAuthList();
|
||||
state.value.auths = res.data;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getUser();
|
||||
getAuths();
|
||||
})
|
||||
</script>
|
||||
|
@ -17,20 +17,15 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { updateUserPwd } from '@/api/system/user';
|
||||
import { ComponentInternalInstance } from 'vue';
|
||||
import { ResetPwdForm } from '@/api/system/user/types'
|
||||
import { ElForm } from 'element-plus';
|
||||
import { updateUserPwd } from "@/api/system/user";
|
||||
import type { ResetPwdForm } from "@/api/system/user/types";
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
|
||||
const pwdRef = ref(ElForm);
|
||||
|
||||
const pwdRef = ref<ElFormInstance>();
|
||||
const user = ref<ResetPwdForm>({
|
||||
oldPassword: '',
|
||||
newPassword: '',
|
||||
confirmPassword: ''
|
||||
oldPassword: "",
|
||||
newPassword: "",
|
||||
confirmPassword: ""
|
||||
});
|
||||
|
||||
const equalToPassword = (rule: any, value: string, callback: any) => {
|
||||
@ -42,15 +37,24 @@ const equalToPassword = (rule: any, value: string, callback: any) => {
|
||||
};
|
||||
const rules = ref({
|
||||
oldPassword: [{ required: true, message: "旧密码不能为空", trigger: "blur" }],
|
||||
newPassword: [{ required: true, message: "新密码不能为空", trigger: "blur" }, { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" }],
|
||||
confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, { required: true, validator: equalToPassword, trigger: "blur" }]
|
||||
newPassword: [{ required: true, message: "新密码不能为空", trigger: "blur" }, {
|
||||
min: 6,
|
||||
max: 20,
|
||||
message: "长度在 6 到 20 个字符",
|
||||
trigger: "blur"
|
||||
}],
|
||||
confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, {
|
||||
required: true,
|
||||
validator: equalToPassword,
|
||||
trigger: "blur"
|
||||
}]
|
||||
});
|
||||
|
||||
/** 提交按钮 */
|
||||
const submit = () => {
|
||||
pwdRef.value.validate(async (valid: boolean) => {
|
||||
pwdRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
await updateUserPwd(user.value.oldPassword, user.value.newPassword)
|
||||
await updateUserPwd(user.value.oldPassword, user.value.newPassword);
|
||||
proxy?.$modal.msgSuccess("修改成功");
|
||||
}
|
||||
});
|
||||
|
140
src/views/system/user/profile/thirdParty.vue
Normal file
140
src/views/system/user/profile/thirdParty.vue
Normal file
@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-table :data="auths" style="width: 100%; height: 100%; font-size: 10px">
|
||||
<el-table-column label="序号" width="50" type="index"></el-table-column>
|
||||
<el-table-column label="绑定账号平台" width="140" align="center" prop="source" show-overflow-tooltip />
|
||||
<el-table-column label="头像" width="120" align="center" prop="avatar">
|
||||
<template v-slot="scope">
|
||||
<img :src="scope.row.avatar" style="width: 45px; height: 45px" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="系统账号" width="180" align="center" prop="userName" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="绑定时间" width="180" align="center" prop="createTime" />
|
||||
<el-table-column label="操作" width="80" align="center" class-name="small-padding fixed-width">
|
||||
<template v-slot="scope">
|
||||
<el-button size="small" type="text" @click="unlockAuth(scope.row)">解绑</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div id="git-user-binding">
|
||||
<h4 class="provider-desc">你可以绑定以下第三方帐号</h4>
|
||||
<div id="authlist" class="user-bind">
|
||||
<a class="third-app" href="#" @click="authUrl('wechar');" title="使用 微信 账号授权登录">
|
||||
<div class="git-other-login-icon">
|
||||
<svg-icon icon-class="wechat" />
|
||||
</div>
|
||||
<span class="app-name">WeiXin</span>
|
||||
</a>
|
||||
<a class="third-app" href="#" @click="authUrl('maxkey');" title="使用 MaxKey 账号授权登录">
|
||||
<div class="git-other-login-icon">
|
||||
<svg-icon icon-class="maxkey" />
|
||||
</div>
|
||||
<span class="app-name">MaxKey</span>
|
||||
</a>
|
||||
<a class="third-app" href="#" @click="authUrl('gitee');" title="使用 Gitee 账号授权登录">
|
||||
<div class="git-other-login-icon">
|
||||
<svg-icon icon-class="gitee" />
|
||||
</div>
|
||||
<span class="app-name">Gitee</span>
|
||||
</a>
|
||||
<a class="third-app" href="#" @click="authUrl('github');" title="使用 GitHub 账号授权登录">
|
||||
<div class="git-other-login-icon">
|
||||
<svg-icon icon-class="github" />
|
||||
</div>
|
||||
<span class="app-name">Github</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { authUnlock, authBinding } from "@/api/system/social/auth";
|
||||
import { PropType } from "vue";
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
const props = defineProps({
|
||||
auths: {
|
||||
type: Object as PropType<any>,
|
||||
}
|
||||
});
|
||||
const auths = computed(() => props.auths);
|
||||
|
||||
|
||||
const unlockAuth = (row: any) => {
|
||||
ElMessageBox.confirm('您确定要解除"' + row.source + '"的账号绑定吗?')
|
||||
.then(() => {
|
||||
return authUnlock(row.id);
|
||||
}).then((res: any) => {
|
||||
if (res.code === 200) {
|
||||
proxy?.$modal.msgSuccess("解绑成功");
|
||||
proxy?.$tab.refreshPage();
|
||||
} else {
|
||||
proxy?.$modal.msgError(res.msg);
|
||||
}
|
||||
}).catch(() => { });
|
||||
};
|
||||
|
||||
const authUrl = (source: string) => {
|
||||
authBinding(source).then((res: any) => {
|
||||
if (res.code === 200) {
|
||||
window.location.href = res.data;
|
||||
} else {
|
||||
proxy?.$modal.msgError(res.msg);
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style type="text/css">
|
||||
.user-bind .third-app {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
min-width: 80px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.user-bind {
|
||||
font-size: 1rem;
|
||||
text-align: start;
|
||||
height: 50px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.git-other-login-icon>img {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
color: #005980;
|
||||
}
|
||||
|
||||
.provider-desc {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial,
|
||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Liberation Sans",
|
||||
"PingFang SC", "Microsoft YaHei", "Hiragino Sans GB", "Wenquanyi Micro Hei",
|
||||
"WenQuanYi Zen Hei", "ST Heiti", SimHei, SimSun, "WenQuanYi Zen Hei Sharp",
|
||||
sans-serif;
|
||||
font-size: 1.071rem;
|
||||
}
|
||||
|
||||
td>img {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
display: inline-block;
|
||||
border-radius: 50%;
|
||||
margin-right: 5px;
|
||||
}
|
||||
</style>
|
@ -29,7 +29,9 @@
|
||||
<el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
|
||||
<el-button>
|
||||
选择
|
||||
<el-icon class="el-icon--right"><Upload /></el-icon>
|
||||
<el-icon class="el-icon--right">
|
||||
<Upload />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</el-upload>
|
||||
</el-col>
|
||||
@ -58,18 +60,17 @@ import "vue-cropper/dist/index.css";
|
||||
import { VueCropper } from "vue-cropper";
|
||||
import { uploadAvatar } from "@/api/system/user";
|
||||
import useUserStore from "@/store/modules/user";
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
|
||||
interface Options {
|
||||
img: string | ArrayBuffer | null // 裁剪图片的地址
|
||||
autoCrop: boolean // 是否默认生成截图框
|
||||
autoCropWidth: number // 默认生成截图框宽度
|
||||
autoCropHeight: number // 默认生成截图框高度
|
||||
fixedBox: boolean // 固定截图框大小 不允许改变
|
||||
fileName: string
|
||||
previews: any // 预览数据
|
||||
outputType: string
|
||||
visible: boolean
|
||||
img: string | ArrayBuffer | null; // 裁剪图片的地址
|
||||
autoCrop: boolean; // 是否默认生成截图框
|
||||
autoCropWidth: number; // 默认生成截图框宽度
|
||||
autoCropHeight: number; // 默认生成截图框高度
|
||||
fixedBox: boolean; // 固定截图框大小 不允许改变
|
||||
fileName: string;
|
||||
previews: any; // 预览数据
|
||||
outputType: string;
|
||||
visible: boolean;
|
||||
}
|
||||
|
||||
|
||||
@ -89,7 +90,7 @@ const options = reactive<Options>({
|
||||
autoCropHeight: 200,
|
||||
fixedBox: true,
|
||||
outputType: "png",
|
||||
fileName: '',
|
||||
fileName: "",
|
||||
previews: {},
|
||||
visible: false
|
||||
});
|
||||
@ -97,26 +98,27 @@ const options = reactive<Options>({
|
||||
/** 编辑头像 */
|
||||
const editCropper = () => {
|
||||
open.value = true;
|
||||
}
|
||||
};
|
||||
/** 打开弹出层结束时的回调 */
|
||||
const modalOpened = () => {
|
||||
visible.value = true;
|
||||
}
|
||||
};
|
||||
/** 覆盖默认上传行为 */
|
||||
const requestUpload = (): any => {}
|
||||
const requestUpload = (): any => {
|
||||
};
|
||||
/** 向左旋转 */
|
||||
const rotateLeft = () => {
|
||||
cropper.value.rotateLeft();
|
||||
}
|
||||
};
|
||||
/** 向右旋转 */
|
||||
const rotateRight = () => {
|
||||
cropper.value.rotateRight();
|
||||
}
|
||||
};
|
||||
/** 图片缩放 */
|
||||
const changeScale = (num: number) => {
|
||||
num = num || 1;
|
||||
cropper.value.changeScale(num);
|
||||
}
|
||||
};
|
||||
/** 上传预处理 */
|
||||
const beforeUpload = (file: any) => {
|
||||
if (file.type.indexOf("image/") == -1) {
|
||||
@ -129,7 +131,7 @@ const beforeUpload = (file: any) => {
|
||||
options.fileName = file.name;
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
/** 上传图片 */
|
||||
const uploadImg = async () => {
|
||||
cropper.value.getCropBlob(async (data: any) => {
|
||||
@ -138,20 +140,20 @@ const uploadImg = async () => {
|
||||
const res = await uploadAvatar(formData);
|
||||
open.value = false;
|
||||
options.img = res.data.imgUrl;
|
||||
userStore.avatar = options.img as string;
|
||||
userStore.avatar = options.img as string
|
||||
proxy?.$modal.msgSuccess("修改成功");
|
||||
visible.value = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
/** 实时预览 */
|
||||
const realTime = (data: any) => {
|
||||
options.previews = data;
|
||||
}
|
||||
};
|
||||
/** 关闭窗口 */
|
||||
const closeDialog = () => {
|
||||
options.img = userStore.avatar;
|
||||
options.visible = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -24,34 +24,36 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { updateUserProfile } from "@/api/system/user";
|
||||
import { FormRules } from "element-plus";
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
import { PropType } from "vue";
|
||||
import { ElForm } from "element-plus";
|
||||
|
||||
const props = defineProps({
|
||||
user: {
|
||||
type: Object as PropType<any>,
|
||||
required: true
|
||||
}
|
||||
});
|
||||
const userForm = computed(() => props.user);
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
const userRef = ref(ElForm);
|
||||
|
||||
const rules = ref<FormRules>({
|
||||
const userRef = ref<ElFormInstance>();
|
||||
const rules = ref<ElFormRules>({
|
||||
nickName: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
|
||||
email: [{ required: true, message: "邮箱地址不能为空", trigger: "blur" }, { type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
|
||||
phonenumber: [{ required: true, message: "手机号码不能为空", trigger: "blur" }, { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }],
|
||||
email: [{ required: true, message: "邮箱地址不能为空", trigger: "blur" }, {
|
||||
type: "email",
|
||||
message: "请输入正确的邮箱地址",
|
||||
trigger: ["blur", "change"]
|
||||
}],
|
||||
phonenumber: [{
|
||||
required: true,
|
||||
message: "手机号码不能为空",
|
||||
trigger: "blur"
|
||||
}, { pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }]
|
||||
});
|
||||
|
||||
|
||||
/** 提交按钮 */
|
||||
const submit = () => {
|
||||
userRef.value.validate(async (valid: boolean) => {
|
||||
userRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
await updateUserProfile(props.user)
|
||||
await updateUserProfile(props.user);
|
||||
proxy?.$modal.msgSuccess("修改成功");
|
||||
}
|
||||
});
|
||||
|
@ -31,15 +31,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { PropType } from 'vue';
|
||||
import { propTypes } from "@/utils/propTypes";
|
||||
|
||||
const prop = defineProps({
|
||||
info: {
|
||||
type: Object as PropType<any>,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
info: propTypes.any.def({})
|
||||
});
|
||||
|
||||
const infoForm = computed(() => prop.info)
|
||||
|
@ -117,9 +117,8 @@ import { getGenTable, updateGenTable } from '@/api/tool/gen';
|
||||
import { DbColumnVO, DbTableVO } from '@/api/tool/gen/types';
|
||||
import { optionselect as getDictOptionselect } from '@/api/system/dict/type';
|
||||
import { DictTypeVO } from '@/api/system/dict/type/types';
|
||||
import basicInfoForm from './basicInfoForm.vue';
|
||||
import genInfoForm from "./genInfoForm.vue";
|
||||
import { ComponentInternalInstance } from "vue";
|
||||
import BasicInfoForm from './basicInfoForm.vue';
|
||||
import GenInfoForm from "./genInfoForm.vue";
|
||||
|
||||
const route = useRoute();
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
@ -131,13 +130,13 @@ const columns = ref<DbColumnVO[]>([]);
|
||||
const dictOptions = ref<DictTypeVO[]>([]);
|
||||
const info = ref<Partial<DbTableVO>>({});
|
||||
|
||||
const basicInfo = ref(basicInfoForm);
|
||||
const genInfo = ref(genInfoForm);
|
||||
const basicInfo = ref<InstanceType<typeof BasicInfoForm>>();
|
||||
const genInfo = ref<InstanceType<typeof GenInfoForm>>();
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
const basicForm = basicInfo.value.$refs.basicInfoForm;
|
||||
const genForm = genInfo.value.$refs.genInfoForm;
|
||||
const basicForm = basicInfo.value?.$refs.basicInfoForm;
|
||||
const genForm = genInfo.value?.$refs.genInfoForm;
|
||||
|
||||
Promise.all([basicForm, genForm].map(getFormPromise)).then(async res => {
|
||||
const validateResult = res.every(item => !!item);
|
||||
|
@ -223,7 +223,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { listMenu } from '@/api/system/menu';
|
||||
import { ComponentInternalInstance, PropType } from 'vue';
|
||||
import { propTypes } from "@/utils/propTypes";
|
||||
|
||||
interface MenuOptionsType {
|
||||
menuId: number | string;
|
||||
@ -236,14 +236,8 @@ const menuOptions = ref<Array<MenuOptionsType>>([]);
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
const props = defineProps({
|
||||
info: {
|
||||
type: Object as PropType<any>,
|
||||
default: null
|
||||
},
|
||||
tables: {
|
||||
type: Array as PropType<any[]>,
|
||||
default: null
|
||||
}
|
||||
info: propTypes.any.def(null),
|
||||
tables: propTypes.any.def(null)
|
||||
});
|
||||
|
||||
const infoForm = computed(() => props.info);
|
||||
@ -268,7 +262,7 @@ const tplSelectChange = (value: string) => {
|
||||
}
|
||||
}
|
||||
const setSubTableColumns = (value: string) => {
|
||||
table.value.forEach(item => {
|
||||
table.value.forEach((item: any) => {
|
||||
const name = item.tableName;
|
||||
if (value === name) {
|
||||
subColumns.value = item.columns;
|
||||
|
@ -40,8 +40,6 @@
|
||||
<script setup lang="ts">
|
||||
import { listDbTable, importTable, getDataNames } from '@/api/tool/gen';
|
||||
import { DbTableQuery, DbTableVO } from '@/api/tool/gen/types';
|
||||
import { ComponentInternalInstance } from 'vue';
|
||||
import { ElTable, ElForm } from 'element-plus';
|
||||
|
||||
const total = ref(0);
|
||||
const visible = ref(false);
|
||||
@ -49,8 +47,8 @@ const tables = ref<Array<string>>([]);
|
||||
const dbTableList = ref<Array<DbTableVO>>([]);
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
const tableRef = ref(ElTable);
|
||||
const queryFormRef = ref(ElForm);
|
||||
const tableRef = ref<ElTableInstance>();
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
|
||||
const queryParams = reactive<DbTableQuery>({
|
||||
pageNum: 1,
|
||||
@ -76,7 +74,8 @@ const show = (dataName: string) => {
|
||||
}
|
||||
/** 单击选择行 */
|
||||
const clickRow = (row: DbTableVO) => {
|
||||
tableRef.value.toggleRowSelection(row);
|
||||
// ele bug
|
||||
tableRef.value?.toggleRowSelection(row, false);
|
||||
}
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: DbTableVO[]) => {
|
||||
@ -95,7 +94,7 @@ const handleQuery = () => {
|
||||
}
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
/** 导入按钮操作 */
|
||||
|
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div class="search" v-show="showSearch">
|
||||
<div class="mb-[10px]" v-show="showSearch">
|
||||
<el-card shadow="hover">
|
||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
||||
<el-form-item label="数据源" prop="dataName">
|
||||
<el-select v-model="queryParams.dataName" filterable clearable placeholder="请选择/输入数据源名称" style="width: 200px">
|
||||
@ -30,10 +31,11 @@
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
@ -99,9 +101,9 @@
|
||||
:name="(key as any).substring((key as any).lastIndexOf('/') + 1, (key as any).indexOf('.vm'))"
|
||||
:key="value"
|
||||
>
|
||||
<el-link :underline="false" icon="DocumentCopy" v-copyText="value" v-copyText:callback="copyTextSuccess" style="float:right"
|
||||
> 复制</el-link
|
||||
>
|
||||
<el-link :underline="false" icon="DocumentCopy" v-copyText="value" v-copyText:callback="copyTextSuccess" style="float:right">
|
||||
复制
|
||||
</el-link>
|
||||
<pre>{{ value }}</pre>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
@ -114,9 +116,7 @@
|
||||
import { listTable, previewTable, delTable, genCode, synchDb, getDataNames } from '@/api/tool/gen';
|
||||
import { TableQuery, TableVO } from '@/api/tool/gen/types';
|
||||
import router from '@/router';
|
||||
import importTable from './importTable.vue';
|
||||
import { ComponentInternalInstance } from 'vue';
|
||||
import { ElForm, DateModelType } from 'element-plus';
|
||||
import ImportTable from './importTable.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
@ -132,8 +132,8 @@ const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
||||
const uniqueId = ref("");
|
||||
const dataNameList = ref<Array<string>>([]);
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
const importRef = ref(importTable);
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const importRef = ref<InstanceType<typeof ImportTable>>();
|
||||
|
||||
const queryParams = ref<TableQuery>({
|
||||
pageNum: 1,
|
||||
@ -158,7 +158,7 @@ onActivated(() => {
|
||||
uniqueId.value = time as string;
|
||||
queryParams.value.pageNum = Number(route.query.pageNum);
|
||||
dateRange.value = ['', ''];
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
getList();
|
||||
}
|
||||
})
|
||||
@ -205,12 +205,12 @@ const handleSynchDb = async (row: TableVO) => {
|
||||
}
|
||||
/** 打开导入表弹窗 */
|
||||
const openImportTable = () => {
|
||||
importRef.value.show(queryParams.value.dataName);
|
||||
importRef.value?.show(queryParams.value.dataName);
|
||||
}
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
dateRange.value = ['', ''];
|
||||
queryFormRef.value.resetFields();
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
/** 预览按钮 */
|
||||
@ -240,7 +240,7 @@ const handleDelete = async (row?: TableVO) => {
|
||||
const tableIds = row?.tableId || ids.value;
|
||||
await proxy?.$modal.confirm('是否确认删除表编号为"' + tableIds + '"的数据项?');
|
||||
await delTable(tableIds);
|
||||
getList();
|
||||
await getList();
|
||||
proxy?.$modal.msgSuccess('删除成功');
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user