回退 'Pull Request !20 : 统一登录授权'
This commit is contained in:
		| @ -13,7 +13,7 @@ VITE_APP_CONTEXT_PATH = '/' | |||||||
| # 监控地址 | # 监控地址 | ||||||
| VITE_APP_MONITRO_ADMIN = 'http://localhost:9090/admin/applications' | VITE_APP_MONITRO_ADMIN = 'http://localhost:9090/admin/applications' | ||||||
|  |  | ||||||
| # powerjob 控制台地址 | # xxl-job 控制台地址 | ||||||
| VITE_APP_POWERJOB_ADMIN = 'http://localhost:7700/' | VITE_APP_XXL_JOB_ADMIN = 'http://localhost:9100/xxl-job-admin' | ||||||
|  |  | ||||||
| VITE_APP_PORT = 80 | VITE_APP_PORT = 80 | ||||||
|  | |||||||
| @ -10,8 +10,8 @@ VITE_APP_CONTEXT_PATH = '/' | |||||||
| # 监控地址 | # 监控地址 | ||||||
| VITE_APP_MONITRO_ADMIN = '/admin/applications' | VITE_APP_MONITRO_ADMIN = '/admin/applications' | ||||||
|  |  | ||||||
| # powerjob 控制台地址 | # 监控地址 | ||||||
| VITE_APP_POWERJOB_ADMIN = '/powerjob' | VITE_APP_XXL_JOB_ADMIN = '/xxl-job-admin' | ||||||
|  |  | ||||||
| # 生产环境 | # 生产环境 | ||||||
| VITE_APP_BASE_API = '/prod-api' | VITE_APP_BASE_API = '/prod-api' | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,5 +1,4 @@ | |||||||
| .DS_Store | .DS_Store | ||||||
| .history |  | ||||||
| node_modules/ | node_modules/ | ||||||
| dist/ | dist/ | ||||||
| npm-debug.log* | npm-debug.log* | ||||||
|  | |||||||
| @ -2,7 +2,6 @@ import request from '@/utils/request'; | |||||||
| import { AxiosPromise } from 'axios'; | import { AxiosPromise } from 'axios'; | ||||||
| import { LoginData, LoginResult, VerifyCodeResult, TenantInfo } from './types'; | import { LoginData, LoginResult, VerifyCodeResult, TenantInfo } from './types'; | ||||||
| import { UserInfo } from '@/api/system/user/types'; | import { UserInfo } from '@/api/system/user/types'; | ||||||
| import { da } from 'element-plus/es/locale'; |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * @param data {LoginData} |  * @param data {LoginData} | ||||||
| @ -10,9 +9,11 @@ import { da } from 'element-plus/es/locale'; | |||||||
|  */ |  */ | ||||||
| export function login(data: LoginData): AxiosPromise<LoginResult> { | export function login(data: LoginData): AxiosPromise<LoginResult> { | ||||||
|   const params = { |   const params = { | ||||||
|     ...data, |     tenantId: data.tenantId, | ||||||
|     clientId: data.clientId || 'e5cd7e4891bf95d1d19206ce24a7b32e', |     username: data.username.trim(), | ||||||
|     grantType: data.grantType || 'password' |     password: data.password, | ||||||
|  |     code: data.code, | ||||||
|  |     uuid: data.uuid | ||||||
|   }; |   }; | ||||||
|   return request({ |   return request({ | ||||||
|     url: '/auth/login', |     url: '/auth/login', | ||||||
| @ -59,22 +60,6 @@ export function getCodeImg(): AxiosPromise<VerifyCodeResult> { | |||||||
|     timeout: 20000 |     timeout: 20000 | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
| /** |  | ||||||
|  * 第三方登录 |  | ||||||
|  * @param source 第三方登录类型 |  | ||||||
|  * */ |  | ||||||
| export function callback(data: LoginData): AxiosPromise<any> { |  | ||||||
|   const LoginData = { |  | ||||||
|     ...data, |  | ||||||
|     clientId: 'e5cd7e4891bf95d1d19206ce24a7b32e', |  | ||||||
|     grantType: 'social' |  | ||||||
|   }; |  | ||||||
|   return request({ |  | ||||||
|     url: '/auth/social/callback', |  | ||||||
|     method: 'post', |  | ||||||
|     data: LoginData |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // 获取用户详细信息 | // 获取用户详细信息 | ||||||
| export function getInfo(): AxiosPromise<UserInfo> { | export function getInfo(): AxiosPromise<UserInfo> { | ||||||
|  | |||||||
| @ -1,80 +0,0 @@ | |||||||
| 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 |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
| @ -1,138 +0,0 @@ | |||||||
| 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; |  | ||||||
|  |  | ||||||
| } |  | ||||||
| @ -1,24 +0,0 @@ | |||||||
| 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' |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
| @ -15,24 +15,19 @@ export type RegisterForm = { | |||||||
|  * 登录请求 |  * 登录请求 | ||||||
|  */ |  */ | ||||||
| export interface LoginData { | export interface LoginData { | ||||||
|   tenantId?: string; |   tenantId: string; | ||||||
|   username?: string; |   username: string; | ||||||
|   password?: string; |   password: string; | ||||||
|   rememberMe?: boolean; |   rememberMe?: boolean; | ||||||
|   socialCode?: string, |  | ||||||
|   socialState?: string, |  | ||||||
|   source?: string, |  | ||||||
|   code?: string; |   code?: string; | ||||||
|   uuid?: string; |   uuid?: string; | ||||||
|   clientId: string; |  | ||||||
|   grantType: string; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * 登录响应 |  * 登录响应 | ||||||
|  */ |  */ | ||||||
| export interface LoginResult { | export interface LoginResult { | ||||||
|   access_token: string; |   token: string; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  | |||||||
| @ -1 +0,0 @@ | |||||||
| <?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> |  | ||||||
| Before Width: | Height: | Size: 1.2 KiB | 
| @ -1,82 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <div v-loading="loading" class="social-login"></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); |  | ||||||
|   } |  | ||||||
|   setToken(res.data.access_token); |  | ||||||
|   ElMessage.success(res.msg); |  | ||||||
|   location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index'; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const handleError = (error: any) => { |  | ||||||
|   ElMessage.error(error.message); |  | ||||||
|   location.href = import.meta.env.VITE_APP_CONTEXT_PATH + 'index'; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| 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) => { |  | ||||||
|   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> |  | ||||||
| @ -10,7 +10,7 @@ import useSettingsStore from '@/store/modules/settings'; | |||||||
| import usePermissionStore from '@/store/modules/permission'; | import usePermissionStore from '@/store/modules/permission'; | ||||||
|  |  | ||||||
| NProgress.configure({ showSpinner: false }); | NProgress.configure({ showSpinner: false }); | ||||||
| const whiteList = ['/login', '/register', '/social-login']; | const whiteList = ['/login', '/register']; | ||||||
|  |  | ||||||
| router.beforeEach(async (to, from, next) => { | router.beforeEach(async (to, from, next) => { | ||||||
|   NProgress.start(); |   NProgress.start(); | ||||||
|  | |||||||
| @ -37,11 +37,6 @@ export const constantRoutes: RouteOption[] = [ | |||||||
|       } |       } | ||||||
|     ] |     ] | ||||||
|   }, |   }, | ||||||
|   { |  | ||||||
|     path: '/social-login', |  | ||||||
|     hidden: true, |  | ||||||
|     component: () => import('@/layout/components/SocialLogin/index.vue') |  | ||||||
|   }, |  | ||||||
|   { |   { | ||||||
|     path: '/login', |     path: '/login', | ||||||
|     component: () => import('@/views/login.vue'), |     component: () => import('@/views/login.vue'), | ||||||
| @ -181,5 +176,4 @@ const router = createRouter({ | |||||||
|   } |   } | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  |  | ||||||
| export default router; | export default router; | ||||||
|  | |||||||
| @ -23,8 +23,8 @@ export const useUserStore = defineStore('user', () => { | |||||||
|     const [err, res] = await to(loginApi(userInfo)); |     const [err, res] = await to(loginApi(userInfo)); | ||||||
|     if (res) { |     if (res) { | ||||||
|       const data = res.data; |       const data = res.data; | ||||||
|       setToken(data.access_token); |       setToken(data.token); | ||||||
|       token.value = data.access_token; |       token.value = data.token; | ||||||
|       return Promise.resolve(); |       return Promise.resolve(); | ||||||
|     } |     } | ||||||
|     return Promise.reject(err); |     return Promise.reject(err); | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								src/types/env.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								src/types/env.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -65,7 +65,7 @@ interface ImportMetaEnv { | |||||||
|   VITE_APP_BASE_URL: string; |   VITE_APP_BASE_URL: string; | ||||||
|   VITE_APP_CONTEXT_PATH: string; |   VITE_APP_CONTEXT_PATH: string; | ||||||
|   VITE_APP_MONITRO_ADMIN: string; |   VITE_APP_MONITRO_ADMIN: string; | ||||||
|   VITE_APP_POWERJOB_ADMIN: string; |   VITE_APP_XXL_JOB_ADMIN: string; | ||||||
|   VITE_APP_ENV: string; |   VITE_APP_ENV: string; | ||||||
| } | } | ||||||
| interface ImportMeta { | interface ImportMeta { | ||||||
|  | |||||||
| @ -4,6 +4,6 @@ const tokenStorage = useStorage<null | string>(TokenKey, null); | |||||||
|  |  | ||||||
| export const getToken = () => tokenStorage.value; | export const getToken = () => tokenStorage.value; | ||||||
|  |  | ||||||
| export const setToken = (access_token: string) => (tokenStorage.value = access_token); | export const setToken = (token: string) => (tokenStorage.value = token); | ||||||
|  |  | ||||||
| export const removeToken = () => (tokenStorage.value = null); | export const removeToken = () => (tokenStorage.value = null); | ||||||
|  | |||||||
| @ -21,7 +21,7 @@ | |||||||
|           * 分布式锁 Lock4j 注解锁、工具锁 多种多样<br /> |           * 分布式锁 Lock4j 注解锁、工具锁 多种多样<br /> | ||||||
|           * 分布式幂等 Lock4j 基于分布式锁实现<br /> |           * 分布式幂等 Lock4j 基于分布式锁实现<br /> | ||||||
|           * 分布式链路追踪 SkyWalking 支持链路追踪、网格分析、度量聚合、可视化<br /> |           * 分布式链路追踪 SkyWalking 支持链路追踪、网格分析、度量聚合、可视化<br /> | ||||||
|           * 分布式任务调度 PowerJob 高性能 高可靠 易扩展<br /> |           * 分布式任务调度 Xxl-Job 高性能 高可靠 易扩展<br /> | ||||||
|           * 文件存储 Minio 本地存储<br /> |           * 文件存储 Minio 本地存储<br /> | ||||||
|           * 文件存储 七牛、阿里、腾讯 云存储<br /> |           * 文件存储 七牛、阿里、腾讯 云存储<br /> | ||||||
|           * 监控框架 SpringBoot-Admin 全方位服务监控<br /> |           * 监控框架 SpringBoot-Admin 全方位服务监控<br /> | ||||||
|  | |||||||
| @ -4,8 +4,7 @@ | |||||||
|       <h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3> |       <h3 class="title">RuoYi-Vue-Plus多租户管理系统</h3> | ||||||
|       <el-form-item prop="tenantId" v-if="tenantEnabled"> |       <el-form-item prop="tenantId" v-if="tenantEnabled"> | ||||||
|         <el-select v-model="loginForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%"> |         <el-select v-model="loginForm.tenantId" filterable placeholder="请选择/输入公司名称" style="width: 100%"> | ||||||
|           <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" |           <el-option v-for="item in tenantList" :key="item.tenantId" :label="item.companyName" :value="item.tenantId"> </el-option> | ||||||
|             :value="item.tenantId"></el-option> |  | ||||||
|           <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template> |           <template #prefix><svg-icon icon-class="company" class="el-input__icon input-icon" /></template> | ||||||
|         </el-select> |         </el-select> | ||||||
|       </el-form-item> |       </el-form-item> | ||||||
| @ -15,14 +14,12 @@ | |||||||
|         </el-input> |         </el-input> | ||||||
|       </el-form-item> |       </el-form-item> | ||||||
|       <el-form-item prop="password"> |       <el-form-item prop="password"> | ||||||
|         <el-input v-model="loginForm.password" type="password" size="large" auto-complete="off" placeholder="密码" |         <el-input v-model="loginForm.password" type="password" size="large" auto-complete="off" placeholder="密码" @keyup.enter="handleLogin"> | ||||||
|           @keyup.enter="handleLogin"> |  | ||||||
|           <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template> |           <template #prefix><svg-icon icon-class="password" class="el-input__icon input-icon" /></template> | ||||||
|         </el-input> |         </el-input> | ||||||
|       </el-form-item> |       </el-form-item> | ||||||
|       <el-form-item prop="code" v-if="captchaEnabled"> |       <el-form-item prop="code" v-if="captchaEnabled"> | ||||||
|         <el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%" |         <el-input v-model="loginForm.code" size="large" auto-complete="off" placeholder="验证码" style="width: 63%" @keyup.enter="handleLogin"> | ||||||
|           @keyup.enter="handleLogin"> |  | ||||||
|           <template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template> |           <template #prefix><svg-icon icon-class="validCode" class="el-input__icon input-icon" /></template> | ||||||
|         </el-input> |         </el-input> | ||||||
|         <div class="login-code"> |         <div class="login-code"> | ||||||
| @ -39,20 +36,6 @@ | |||||||
|           <router-link class="link-type" :to="'/register'">立即注册</router-link> |           <router-link class="link-type" :to="'/register'">立即注册</router-link> | ||||||
|         </div> |         </div> | ||||||
|       </el-form-item> |       </el-form-item> | ||||||
|       <div style="display: flex;justify-content: flex-end;flex-direction: row;"> |  | ||||||
|         <el-button circle> |  | ||||||
|           <svg-icon icon-class="qq" @click="doSocialLogin('qq')" /> |  | ||||||
|         </el-button> |  | ||||||
|         <el-button circle> |  | ||||||
|           <svg-icon icon-class="wechat" @click="doSocialLogin('wechat')" /> |  | ||||||
|         </el-button> |  | ||||||
|         <el-button circle> |  | ||||||
|           <svg-icon icon-class="gitee" @click="doSocialLogin('gitee')" /> |  | ||||||
|         </el-button> |  | ||||||
|         <el-button circle> |  | ||||||
|           <svg-icon icon-class="github" @click="doSocialLogin('github')" /> |  | ||||||
|         </el-button> |  | ||||||
|       </div> |  | ||||||
|     </el-form> |     </el-form> | ||||||
|     <!--  底部  --> |     <!--  底部  --> | ||||||
|     <div class="el-login-footer"> |     <div class="el-login-footer"> | ||||||
| @ -63,12 +46,11 @@ | |||||||
|  |  | ||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| import { getCodeImg, getTenantList } from '@/api/login'; | import { getCodeImg, getTenantList } from '@/api/login'; | ||||||
| import { authBinding } from '@/api/system/social/auth'; |  | ||||||
| import Cookies from 'js-cookie'; | import Cookies from 'js-cookie'; | ||||||
| import { encrypt, decrypt } from '@/utils/jsencrypt'; | import { encrypt, decrypt } from '@/utils/jsencrypt'; | ||||||
| import { useUserStore } from '@/store/modules/user'; | import { useUserStore } from '@/store/modules/user'; | ||||||
| import { LoginData, TenantVO } from '@/api/types'; | import { LoginData, TenantVO } from '@/api/types'; | ||||||
| import { ElForm, FormRules } from 'element-plus'; | import { FormRules } from 'element-plus'; | ||||||
| import { to } from 'await-to-js'; | import { to } from 'await-to-js'; | ||||||
|  |  | ||||||
| const userStore = useUserStore(); | const userStore = useUserStore(); | ||||||
| @ -106,7 +88,7 @@ const loginRef = ref(ElForm); | |||||||
| const tenantList = ref<TenantVO[]>([]); | const tenantList = ref<TenantVO[]>([]); | ||||||
|  |  | ||||||
| const handleLogin = () => { | const handleLogin = () => { | ||||||
|   loginRef.value.validate(async (valid: boolean, fields: any) => { |     loginRef.value.validate(async (valid:boolean, fields: any) => { | ||||||
|         if (valid) { |         if (valid) { | ||||||
|             loading.value = true; |             loading.value = true; | ||||||
|             // 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码 |             // 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码 | ||||||
| @ -181,27 +163,6 @@ const initTenantList = async () => { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| //检测租户选择框的变化 |  | ||||||
| watch(() => loginForm.value.tenantId, (val: string) => { |  | ||||||
|   Cookies.set("tenantId", loginForm.value.tenantId, { expires: 30 }) |  | ||||||
| }); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * 第三方登录 |  | ||||||
|  * @param type |  | ||||||
|  */ |  | ||||||
| const doSocialLogin = (type: string) => { |  | ||||||
|   authBinding(type).then((res: any) => { |  | ||||||
|     if (res.code === 200) { |  | ||||||
|       window.location.href = res.msg; |  | ||||||
|     } else { |  | ||||||
|       ElMessage.error(res.msg); |  | ||||||
|     } |  | ||||||
|   }); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| onMounted(() => { | onMounted(() => { | ||||||
|     getCode(); |     getCode(); | ||||||
|     initTenantList(); |     initTenantList(); | ||||||
| @ -218,7 +179,6 @@ onMounted(() => { | |||||||
|   background-image: url("../assets/images/login-background.jpg"); |   background-image: url("../assets/images/login-background.jpg"); | ||||||
|   background-size: cover; |   background-size: cover; | ||||||
| } | } | ||||||
|  |  | ||||||
| .title { | .title { | ||||||
|   margin: 0px auto 30px auto; |   margin: 0px auto 30px auto; | ||||||
|   text-align: center; |   text-align: center; | ||||||
| @ -230,39 +190,32 @@ onMounted(() => { | |||||||
|   background: #ffffff; |   background: #ffffff; | ||||||
|   width: 400px; |   width: 400px; | ||||||
|   padding: 25px 25px 5px 25px; |   padding: 25px 25px 5px 25px; | ||||||
|  |  | ||||||
|   .el-input { |   .el-input { | ||||||
|     height: 40px; |     height: 40px; | ||||||
|  |  | ||||||
|     input { |     input { | ||||||
|       height: 40px; |       height: 40px; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   .input-icon { |   .input-icon { | ||||||
|     height: 39px; |     height: 39px; | ||||||
|     width: 14px; |     width: 14px; | ||||||
|     margin-left: 0px; |     margin-left: 0px; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| .login-tip { | .login-tip { | ||||||
|   font-size: 13px; |   font-size: 13px; | ||||||
|   text-align: center; |   text-align: center; | ||||||
|   color: #bfbfbf; |   color: #bfbfbf; | ||||||
| } | } | ||||||
|  |  | ||||||
| .login-code { | .login-code { | ||||||
|   width: 33%; |   width: 33%; | ||||||
|   height: 40px; |   height: 40px; | ||||||
|   float: right; |   float: right; | ||||||
|  |  | ||||||
|   img { |   img { | ||||||
|     cursor: pointer; |     cursor: pointer; | ||||||
|     vertical-align: middle; |     vertical-align: middle; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| .el-login-footer { | .el-login-footer { | ||||||
|   height: 40px; |   height: 40px; | ||||||
|   line-height: 40px; |   line-height: 40px; | ||||||
| @ -271,11 +224,10 @@ onMounted(() => { | |||||||
|   width: 100%; |   width: 100%; | ||||||
|   text-align: center; |   text-align: center; | ||||||
|   color: #fff; |   color: #fff; | ||||||
|   font-family: Arial, serif; |   font-family: Arial,serif; | ||||||
|   font-size: 12px; |   font-size: 12px; | ||||||
|   letter-spacing: 1px; |   letter-spacing: 1px; | ||||||
| } | } | ||||||
|  |  | ||||||
| .login-code-img { | .login-code-img { | ||||||
|   height: 40px; |   height: 40px; | ||||||
|   padding-left: 12px; |   padding-left: 12px; | ||||||
|  | |||||||
| @ -5,5 +5,5 @@ | |||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| const url = ref(import.meta.env.VITE_APP_POWERJOB_ADMIN); | const url = ref(import.meta.env.VITE_APP_XXL_JOB_ADMIN); | ||||||
| </script> | </script> | ||||||
| @ -1,344 +0,0 @@ | |||||||
| <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 in scope.row.grantTypeList"> |  | ||||||
|                 <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'; |  | ||||||
| import { ComponentInternalInstance } from 'vue'; |  | ||||||
| import { ElForm } from 'element-plus'; |  | ||||||
|  |  | ||||||
| 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(ElForm); |  | ||||||
| const clientFormRef = ref(ElForm); |  | ||||||
|  |  | ||||||
| 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 = () => { |  | ||||||
|   dialog.visible = true; |  | ||||||
|   dialog.title = "添加客户端管理"; |  | ||||||
|   nextTick(() => { |  | ||||||
|     reset(); |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** 修改按钮操作 */ |  | ||||||
| const handleUpdate = (row?: ClientVO) => { |  | ||||||
|   loading.value = true |  | ||||||
|   dialog.visible = true; |  | ||||||
|   dialog.title = "修改客户端管理"; |  | ||||||
|   nextTick(async () => { |  | ||||||
|     reset(); |  | ||||||
|     const _id = row?.id || ids.value[0] |  | ||||||
|     const res = await getClient(_id); |  | ||||||
|     loading.value = false; |  | ||||||
|     Object.assign(form.value, res.data); |  | ||||||
|   }); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /** 提交按钮 */ |  | ||||||
| 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> |  | ||||||
| @ -180,7 +180,7 @@ | |||||||
|           </el-col> |           </el-col> | ||||||
|           <el-col :span="12" v-if="form.menuType === 'C'"> |           <el-col :span="12" v-if="form.menuType === 'C'"> | ||||||
|             <el-form-item> |             <el-form-item> | ||||||
|               <el-input v-model="form.queryParam" placeholder="请输入路由参数" maxlength="255" /> |               <el-input v-model="form.query" placeholder="请输入路由参数" maxlength="255" /> | ||||||
|               <template #label> |               <template #label> | ||||||
|                 <span> |                 <span> | ||||||
|                   <el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top"> |                   <el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top"> | ||||||
|  | |||||||
| @ -55,9 +55,6 @@ | |||||||
|             <el-tab-pane label="修改密码" name="resetPwd"> |             <el-tab-pane label="修改密码" name="resetPwd"> | ||||||
|               <resetPwd /> |               <resetPwd /> | ||||||
|             </el-tab-pane> |             </el-tab-pane> | ||||||
|             <el-tab-pane label="第三方应用" name="thirdParty"> |  | ||||||
|               <thirdParty :auths="state.auths" /> |  | ||||||
|             </el-tab-pane> |  | ||||||
|           </el-tabs> |           </el-tabs> | ||||||
|         </el-card> |         </el-card> | ||||||
|       </el-col> |       </el-col> | ||||||
| @ -69,16 +66,13 @@ | |||||||
| import userAvatar from "./userAvatar.vue"; | import userAvatar from "./userAvatar.vue"; | ||||||
| import userInfo from "./userInfo.vue"; | import userInfo from "./userInfo.vue"; | ||||||
| import resetPwd from "./resetPwd.vue"; | import resetPwd from "./resetPwd.vue"; | ||||||
| import thirdParty from "./thirdParty.vue"; |  | ||||||
| import { getAuthList } from "@/api/system/social/auth"; |  | ||||||
| import { getUserProfile } from "@/api/system/user"; | import { getUserProfile } from "@/api/system/user"; | ||||||
|  |  | ||||||
| const activeTab = ref("userinfo"); | const activeTab = ref("userinfo"); | ||||||
| const state = ref<{ user: any; roleGroup: string;  postGroup: string; auths:any[]}>({ | const state = ref<{ user: any; roleGroup: string;  postGroup: string}>({ | ||||||
|     user: {}, |     user: {}, | ||||||
|     roleGroup: '', |     roleGroup: '', | ||||||
|     postGroup: '', |     postGroup: '' | ||||||
|     auths: [], |  | ||||||
| }); | }); | ||||||
|  |  | ||||||
| const userForm = ref({}); | const userForm = ref({}); | ||||||
| @ -91,13 +85,7 @@ const getUser = async () => { | |||||||
|     state.value.postGroup = res.data.postGroup; |     state.value.postGroup = res.data.postGroup; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| const getAuths = async () => { |  | ||||||
|     const res = await getAuthList(); |  | ||||||
|     state.value.auths = res.data; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| onMounted(() => { | onMounted(() => { | ||||||
|     getUser(); |     getUser(); | ||||||
|     getAuths(); |  | ||||||
| }) | }) | ||||||
| </script> | </script> | ||||||
|  | |||||||
| @ -1,140 +0,0 @@ | |||||||
| <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('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> |  | ||||||
|  |  | ||||||
|         <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('qq');" title="使用 QQ 账号授权登录"> |  | ||||||
|           <div class="git-other-login-icon"> |  | ||||||
|             <svg-icon icon-class="qq" /> |  | ||||||
|           </div> |  | ||||||
|           <span class="app-name">QQ</span> |  | ||||||
|         </a> |  | ||||||
|       </div> |  | ||||||
|     </div> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script lang="ts" setup> |  | ||||||
| import { authUnlock, authBinding } from "@/api/system/social/auth"; |  | ||||||
| import { PropType } from "vue"; |  | ||||||
|  |  | ||||||
| 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) { |  | ||||||
|         ElMessage.success("解绑成功"); |  | ||||||
|       } else { |  | ||||||
|         ElMessage.error(res.msg); |  | ||||||
|       } |  | ||||||
|     }).catch(() => { }); |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const authUrl = (source: string) => { |  | ||||||
|   authBinding(source).then((res: any) => { |  | ||||||
|     if (res.code === 200) { |  | ||||||
|       window.location.href = res.msg; |  | ||||||
|     } else { |  | ||||||
|       ElMessage.error(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> |  | ||||||
		Reference in New Issue
	
	Block a user
	 疯狂的狮子Li
					疯狂的狮子Li