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,6 +29,7 @@ "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", @@ -44,6 +45,7 @@ "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", src/api/login.ts
@@ -3,22 +3,24 @@ import { LoginData, LoginResult, VerifyCodeResult, TenantInfo } from './types'; import { UserInfo } from '@/api/system/user/types'; // pc端åºå®å®¢æ·ç«¯ææid const clientId = 'e5cd7e4891bf95d1d19206ce24a7b32e'; /** * @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 @@ -60,19 +62,20 @@ timeout: 20000 }); } /** * ç¬¬ä¸æ¹ç»å½ * @param source ç¬¬ä¸æ¹ç»å½ç±»å * */ export function socialLogin(source: string, code: any, state: any): AxiosPromise<any> { const data = { code, state */ export function callback(data: LoginData): AxiosPromise<any> { const LoginData = { ...data, clientId: clientId, grantType: 'social' }; return request({ url: '/auth/social-login/' + source, method: 'get', params: data url: '/auth/social/callback', method: 'post', data: LoginData }); } src/api/system/client/index.ts
¶Ô±ÈÐÂÎļþ @@ -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 }); } src/api/system/client/types.ts
¶Ô±ÈÐÂÎļþ @@ -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; } src/api/types.ts
@@ -15,19 +15,24 @@ * ç»å½è¯·æ± */ 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; } /** src/components/RuoYiDoc/index.vue
@@ -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) src/layout/components/SocialCallback/index.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,82 @@ <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); } 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> src/layout/components/SocialLogin/index.vue
ÎļþÒÑɾ³ý src/layout/components/TagsView/ScrollPane.vue
@@ -95,7 +95,7 @@ bottom: 0px; } :deep(.el-scrollbar__wrap) { height: 39px; height: 49px; } } </style> src/permission.ts
@@ -10,7 +10,7 @@ import usePermissionStore from '@/store/modules/permission'; NProgress.configure({ showSpinner: false }); const whiteList = ['/login', '/register', '/social-login']; const whiteList = ['/login', '/register', '/social-callback']; router.beforeEach(async (to, from, next) => { NProgress.start(); src/plugins/download.ts
@@ -34,6 +34,8 @@ }, 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, @@ -50,6 +52,12 @@ } 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(); src/router/index.ts
@@ -38,9 +38,9 @@ ] }, { path: '/social-login', path: '/social-callback', hidden: true, component: () => import('@/layout/components/SocialLogin/index.vue') component: () => import('@/layout/components/SocialCallback/index.vue') }, { path: '/login', @@ -181,4 +181,5 @@ } }); export default router; src/store/modules/user.ts
@@ -23,8 +23,8 @@ 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); src/utils/auth.ts
@@ -4,6 +4,6 @@ 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); src/utils/crypto.ts
¶Ô±ÈÐÂÎļþ @@ -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(); }; src/utils/jsencrypt.ts
@@ -2,7 +2,8 @@ // å¯é¥å¯¹çæ http://web.chacuo.net/netrsakeypair const publicKey = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdH\n' + 'nzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='; 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdH\n' + 'nzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='; const privateKey = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY\n' + src/utils/request.ts
@@ -8,6 +8,8 @@ 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; // æ¯å¦æ¾ç¤ºéæ°ç»å½ @@ -29,6 +31,8 @@ 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 +67,13 @@ } } } // å½å¼å¯åæ°å å¯ 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']; src/views/index.vue
@@ -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> src/views/login.vue
@@ -72,7 +72,7 @@ const router = useRouter(); const loginForm = ref<LoginData>({ tenantId: "000000", tenantId: '000000', username: 'admin', password: 'admin123', rememberMe: false, @@ -176,6 +176,12 @@ } } } //æ£æµç§æ·éæ©æ¡çåå watch(() => loginForm.value.tenantId, (val: string) => { Cookies.set("tenantId", loginForm.value.tenantId, { expires: 30 }) }); /** * ç¬¬ä¸æ¹ç»å½ * @param type @@ -183,7 +189,8 @@ const doSocialLogin = (type: string) => { authBinding(type).then((res: any) => { if (res.code === HttpStatus.SUCCESS) { window.location.href = res.msg; // è·åææå°å跳转 window.location.href = res.data; } else { ElMessage.error(res.msg); } src/views/monitor/cache/index.vue
@@ -156,7 +156,6 @@ } ] }); const usedmemoryInstance = echarts.init(usedmemory.value, "macarons"); usedmemoryInstance.setOption({ tooltip: { @@ -180,6 +179,10 @@ } ] }) window.addEventListener("resize",()=>{ commandstatsIntance.resize() usedmemoryInstance.resize() }); } onMounted(() => { src/views/system/client/index.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,344 @@ <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> src/views/system/menu/index.vue
@@ -181,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"> src/views/system/user/profile/thirdParty.vue
@@ -80,7 +80,7 @@ const authUrl = (source: string) => { authBinding(source).then((res: any) => { if (res.code === 200) { window.location.href = res.msg; window.location.href = res.data; } else { ElMessage.error(res.msg); }