Эх сурвалжийг харах

!1947 修复标签页刷新偶现崩溃问题, 新增租户下拉选择公共组件(并替换现有租户选择) 等
Merge pull request !1947 from 夜鹰/v2

zuohuaijun 3 сар өмнө
parent
commit
05ce690148

+ 1 - 1
Admin.NET/Admin.NET.Core/Service/Tenant/SysTenantService.cs

@@ -109,7 +109,7 @@ public class SysTenantService : IDynamicApiController, ITransient
            .Where(u => u.Status == StatusEnum.Enable)
            .Select((u, a) => new
            {
-               Label = $"{u.Title}-{a.Name}",
+               Label = SqlFunc.HasValue(u.Title) ? $"{u.Title}-{a.Name}" : a.Name,
                Host = u.Host.ToLower(),
                Value = u.Id,
            }).ToListAsync();

+ 0 - 3
Web/src/layout/routerView/parent.vue

@@ -65,13 +65,10 @@ const getIframeListRoutes = async () => {
 onBeforeMount(() => {
 	state.keepAliveNameList = keepAliveNames.value;
 	mittBus.on('onTagsViewRefreshRouterView', (fullPath: string) => {
-		const cacheList = cachedViews.value;
-		if (route.meta.isKeepAlive) cachedViews.value = cachedViews.value?.filter((name: string) => route.name !== name);
 		state.keepAliveNameList = keepAliveNames.value.filter((name: string) => route.name !== name);
 		state.refreshRouterViewKey = '';
 		state.iframeRefreshKey = '';
 		nextTick(() => {
-			if (route.meta.isKeepAlive) cachedViews.value = cacheList;
 			state.keepAliveNameList = keepAliveNames.value;
 			state.refreshRouterViewKey = fullPath;
 			state.iframeRefreshKey = fullPath;

+ 1 - 3
Web/src/stores/keepAliveNames.ts

@@ -22,9 +22,7 @@ export const useKeepALiveNames = defineStore('keepALiveNames', {
 		},
 		async delCachedView(view: any) {
 			const index = this.cachedViews.indexOf(view.name);
-			setTimeout(() => {
-				index > -1 && this.cachedViews.splice(index, 1);
-			}, 20);
+			index > -1 && this.cachedViews.splice(index, 1);
 		},
 		async delOthersCachedViews(view: any) {
 			if (view.meta.isKeepAlive) this.cachedViews = [view.name];

+ 5 - 0
Web/src/theme/element.scss

@@ -352,6 +352,11 @@
 				padding: 18px !important;
                 max-height: calc(100vh - 37px);
 			}
+            .el-dialog__body:has(+ .el-dialog__footer) {
+                padding-bottom: 0 !important;
+                margin-bottom: 18px;
+                max-height: calc(100vh - 37px - 47px - 18px);
+            }
 		}
 	}
 }

+ 3 - 1
Web/src/views/error/401.vue

@@ -1,5 +1,5 @@
 <template>
-	<div class="error layout-padding">
+	<div class="error">
 		<div class="layout-padding-auto layout-padding-view">
 			<div class="error-flex">
 				<div class="left">
@@ -36,6 +36,8 @@ const onSetAuth = () => {
 <style scoped lang="scss">
 .error {
 	height: 100%;
+    width: 100%;
+    
 	.error-flex {
 		margin: auto;
 		display: flex;

+ 3 - 1
Web/src/views/error/404.vue

@@ -1,5 +1,5 @@
 <template>
-	<div class="error layout-padding">
+	<div class="error">
 		<div class="layout-padding-auto layout-padding-view">
 			<div class="error-flex">
 				<div class="left">
@@ -36,6 +36,8 @@ const onGoHome = () => {
 <style scoped lang="scss">
 .error {
 	height: 100%;
+    width: 100%;
+
 	.error-flex {
 		margin: auto;
 		display: flex;

+ 1 - 2
Web/src/views/home/widgets/components/myapp.vue

@@ -1,5 +1,5 @@
 <template>
-	<el-card shadow="hover" header="快捷入口">
+	<el-card shadow="hover" header="快捷入口" body-style="padding: 0">
 		<template #header>
 			<el-icon style="display: inline; vertical-align: middle"> <ele-Guide /> </el-icon>
 			<span> 快捷入口 </span>
@@ -139,7 +139,6 @@ const beforeClose = async () => {
 <style scoped lang="scss">
 .myMods {
 	list-style: none;
-	margin: -10px;
 }
 .myMods li {
 	display: inline-block;

+ 8 - 4
Web/src/views/login/component/register.vue

@@ -114,7 +114,7 @@ const ruleFormRef = ref();
 const accountRef = ref<InputInstance>();
 const codeRef = ref<InputInstance>();
 
-const emits = defineEmits(['reload']);
+const emits = defineEmits(['reload', 'goLogin']);
 const dragRef: any = ref(null);
 const state = reactive({
 	ruleForm: {
@@ -221,7 +221,7 @@ const onRegister = async () => {
 
 			if (err) {
 				getCaptcha(); // 重新获取验证码
-			} else if (res.data.type != 'success') {
+			} else if (res.type != 'success') {
 				getCaptcha(); // 重新获取验证码
 				ElMessage.error('message.register.注册失败!');
 			}
@@ -242,7 +242,7 @@ const openRotateVerify = () => {
 const passRotateVerify = () => {
 	state.rotateVerifyVisible = false;
 	state.isPassRotate = true;
-	onSignIn();
+	//onSignIn();
 };
 
 // 注册处理
@@ -274,7 +274,11 @@ const handleRegister = () => {
 }
 
 .login-content-form {
-	margin-top: 20px;
+	margin-top: 5px;
+
+    .el-form-item--large {
+        margin-bottom: 15px;
+    }
 
 	@for $i from 0 through 4 {
 		.login-animation#{$i} {

+ 46 - 25
Web/src/views/login/index.vue

@@ -45,12 +45,12 @@
 							<i class="iconfont" :class="state.isScan ? 'icon-diannao1' : 'icon-barcode-qr'"></i>
 							<div class="login-content-main-scan-delta"></div>
 						</div>
-						<div class="login-content-main-left" v-if="getThemeConfig.registration">
+						<div class="login-content-main-bottom" v-if="getThemeConfig.registration">
 							<template v-if="state.tabsActiveName != 'register'">
 								没有账号? 去<el-link class="login-content-main-left-register" @click="() => state.tabsActiveName = 'register'">注册账号</el-link>
 							</template>
 							<template v-else>
-								已有账户? 去<el-link class="login-content-main-left-register" @click="() => state.tabsActiveName = 'account'">登录账号</el-link>
+								已有账户? 去<el-link class="login-content-main-bottom-register" @click="() => state.tabsActiveName = 'account'">登录账号</el-link>
 							</template>
 						</div>
 					</div>
@@ -120,6 +120,9 @@ const getTenantInfo = async () => {
 	if (tenant?.value) tenantInfo.value.id = parseInt(tenant?.value);
 	return tenantInfo.value;
 }
+
+// 计算登录右侧容器高度(根据是否启用租户选择来决定高度)
+const loginRightWarpHeight = !tenantInfo.value?.id && themeConfig.value.hideTenantForLogin ? '600px' : '660px';
 </script>
 
 <style scoped lang="scss">
@@ -184,8 +187,8 @@ const getTenantInfo = async () => {
 		background-repeat: no-repeat;
 		.login-right-warp {
 			border: 1px solid var(--el-color-primary-light-3);
-			border-radius: 3px;
-			height: 600px;
+			border-radius: 6px;
+			height: v-bind(loginRightWarpHeight); // 600px;
 			position: relative;
 			overflow: hidden;
 			background-color: var(--el-color-white);
@@ -193,8 +196,8 @@ const getTenantInfo = async () => {
 			.login-right-warp-two {
 				position: absolute;
 				display: block;
-				width: inherit;
-				height: inherit;
+				width: 100%;
+				height: 100%;
 				&::before,
 				&::after {
 					content: '';
@@ -203,19 +206,19 @@ const getTenantInfo = async () => {
 				}
 			}
 			.login-right-warp-one {
-				&::before {
+				&::before {  //上
 					filter: hue-rotate(0deg);
-					top: 0px;
-					left: 0;
+					top: 0;
+                    left: -100%;
 					width: 100%;
 					height: 1px;
 					background: linear-gradient(90deg, transparent, var(--el-color-primary));
 					animation: loginLeft 3s linear infinite;
 				}
-				&::after {
+				&::after { //右
 					filter: hue-rotate(0deg);
 					top: -100%;
-					right: 2px;
+					right: 0;
 					width: 1px;
 					height: 100%;
 					background: linear-gradient(180deg, transparent, var(--el-color-primary));
@@ -224,9 +227,9 @@ const getTenantInfo = async () => {
 				}
 			}
 			.login-right-warp-two {
-				&::before {
+				&::before { //下
 					filter: hue-rotate(0deg);
-					bottom: 2px;
+					bottom: 0;
 					right: -100%;
 					width: 100%;
 					height: 1px;
@@ -234,10 +237,10 @@ const getTenantInfo = async () => {
 					animation: loginRight 3s linear infinite;
 					animation-delay: 1.4s;
 				}
-				&::after {
+				&::after { //左
 					filter: hue-rotate(0deg);
 					bottom: -100%;
-					left: 0px;
+					left: 0;
 					width: 1px;
 					height: 100%;
 					background: linear-gradient(360deg, transparent, var(--el-color-primary));
@@ -300,17 +303,15 @@ const getTenantInfo = async () => {
 							top: 0px;
 						}
 					}
-					.login-content-main-left {
+					.login-content-main-bottom {
 						position: absolute;
-						top: 10px;
-						left: 10px;
-						width: 150px;
-						height: 50px;
+                        bottom: 30px;
+						left: 50%;
+                        transform: translate(-50%);
 						overflow: hidden;
-						cursor: pointer;
 						transition: all ease 0.3s;
 						user-select: none;
-						.login-content-main-left-register {
+						.login-content-main-bottom-register {
 							top: -1.5px;
 							color: var(--el-color-primary);
 						}
@@ -361,9 +362,18 @@ const getTenantInfo = async () => {
 	}
 }
 @media screen and (max-width: 1200px) {
-	.login-right-warp {
-		width: 100%;
-	}
+    .login-right {
+        border-radius: 6px;
+
+        .login-right-warp {
+            width: 100%;
+            .login-right-warp-one,
+            .login-right-warp-two {
+                display: none !important;
+            }
+        }
+    }
+    
 	.copyright,
 	.icp {
 		left: 50%;
@@ -376,6 +386,17 @@ const getTenantInfo = async () => {
 	}
 }
 @media screen and (max-width: 580px) {
+    .login-right {
+        border-radius: 0;
+        
+        .login-right-warp {
+            width: 100%;
+            .login-right-warp-one,
+            .login-right-warp-two {
+                display: none !important;
+            }
+        }
+    }
 	.copyright,
 	.icp {
 		left: 50%;

+ 3 - 6
Web/src/views/system/file/index.vue

@@ -3,9 +3,7 @@
 		<el-card shadow="hover" :body-style="{ padding: 5 }">
 			<el-form :model="state.queryParams" ref="queryForm" :inline="true">
 				<el-form-item label="租户" v-if="userStore.userInfos.accountType == 999">
-					<el-select v-model="state.queryParams.tenantId" placeholder="租户" style="width: 100%">
-						<el-option :value="item.value" :label="`${item.label} (${item.host})`" v-for="(item, index) in state.tenantList" :key="index" />
-					</el-select>
+					<TenantSelect v-model="state.queryParams.tenantId" clearable />
 				</el-form-item>
 				<el-form-item label="文件名称" prop="fileName">
 					<el-input v-model="state.queryParams.fileName" placeholder="文件名称" clearable />
@@ -159,9 +157,10 @@ import ModifyRecord from '/@/components/table/modifyRecord.vue';
 
 import { downloadByUrl } from '/@/utils/download';
 import { getAPI } from '/@/utils/axios-utils';
-import {SysFileApi, SysTenantApi} from '/@/api-services/api';
+import { SysFileApi } from '/@/api-services/api';
 import { SysFile } from '/@/api-services/models';
 import { useUserInfo } from "/@/stores/userInfo";
+import TenantSelect from '/@/views/system/tenant/component/tenantSelect.vue';
 
 // const baseUrl = window.__env__.VITE_API_URL;
 const userStore = useUserInfo();
@@ -169,7 +168,6 @@ const uploadRef = ref<UploadInstance>();
 const editSysFileRef = ref<InstanceType<typeof EditSysFile>>();
 const state = reactive({
 	loading: false,
-	tenantList: [] as Array<any>,
 	fileData: [] as Array<SysFile>,
 	queryParams: {
 		tenantId: undefined,
@@ -200,7 +198,6 @@ const state = reactive({
 
 onMounted(async () => {
 	if (userStore.userInfos.accountType == 999) {
-		state.tenantList = await getAPI(SysTenantApi).apiSysTenantListGet().then(res => res.data.result ?? []);
 		state.queryParams.tenantId = userStore.userInfos.currentTenantId as any;
 	}
 	handleQuery();

+ 18 - 27
Web/src/views/system/ldap/index.vue

@@ -3,9 +3,7 @@
 		<el-card shadow="hover" :body-style="{ padding: 5 }">
 			<el-form :model="state.queryParams" ref="queryForm" :inline="true">
 				<el-form-item label="租户" v-if="userStore.userInfos.accountType == 999">
-					<el-select v-model="state.queryParams.tenantId" placeholder="租户" style="width: 100%">
-						<el-option :value="item.value" :label="`${item.label} (${item.host})`" v-for="(item, index) in state.tenantList" :key="index" />
-					</el-select>
+					<TenantSelect v-model="state.queryParams.tenantId" clearable />
 				</el-form-item>
 				<el-form-item label="关键字">
 					<el-input v-model="state.queryParams.keyword" clearable placeholder="请输入模糊查询关键字" />
@@ -76,16 +74,16 @@ import { onMounted, reactive, ref } from 'vue';
 import { ElMessageBox, ElMessage } from 'element-plus';
 import { auth } from '/@/utils/authFunction';
 import { getAPI } from '/@/utils/axios-utils';
-import {SysLdapApi, SysTenantApi} from '/@/api-services/api';
+import { SysLdapApi } from '/@/api-services/api';
 import ModifyRecord from '/@/components/table/modifyRecord.vue';
 import EditLdap from './component/editLdap.vue';
 import { useUserInfo } from "/@/stores/userInfo";
+import TenantSelect from '/@/views/system/tenant/component/tenantSelect.vue';
 
 const userStore = useUserInfo();
 const editLdapRef = ref<InstanceType<typeof EditLdap>>();
 const state = reactive({
 	loading: false,
-	tenantList: [] as Array<any>,
 	tableData: [] as any,
 	queryParams: {
 		tenantId: undefined,
@@ -102,7 +100,6 @@ const state = reactive({
 
 onMounted(async () => {
 	if (userStore.userInfos.accountType == 999) {
-		state.tenantList = await getAPI(SysTenantApi).apiSysTenantListGet().then(res => res.data.result ?? []);
 		state.queryParams.tenantId = userStore.userInfos.currentTenantId as any;
 	}
 	handleQuery();
@@ -143,13 +140,11 @@ const delSysLdap = (row: any) => {
 		confirmButtonText: '确定',
 		cancelButtonText: '取消',
 		type: 'warning',
-	})
-		.then(async () => {
-			await getAPI(SysLdapApi).apiSysLdapDeletePost({ id: row.id });
-			handleQuery();
-			ElMessage.success('删除成功');
-		})
-		.catch(() => {});
+	}).then(async () => {
+		await getAPI(SysLdapApi).apiSysLdapDeletePost({ id: row.id });
+		handleQuery();
+		ElMessage.success('删除成功');
+	}).catch(() => {});
 };
 
 // 改变页面容量
@@ -170,13 +165,11 @@ const syncDomainUser = (row: any) => {
 		confirmButtonText: '确定',
 		cancelButtonText: '取消',
 		type: 'warning',
-	})
-		.then(async () => {
-			await getAPI(SysLdapApi).apiSysLdapSyncUserPost({ id: row.id });
-			handleQuery();
-			ElMessage.success('删除成功');
-		})
-		.catch(() => {});
+	}).then(async () => {
+		await getAPI(SysLdapApi).apiSysLdapSyncUserPost({ id: row.id });
+		handleQuery();
+		ElMessage.success('删除成功');
+	}).catch(() => {});
 };
 
 // 同步域组织
@@ -185,12 +178,10 @@ const syncDomainOrg = (row: any) => {
 		confirmButtonText: '确定',
 		cancelButtonText: '取消',
 		type: 'warning',
-	})
-		.then(async () => {
-			await getAPI(SysLdapApi).apiSysLdapSyncOrgPost({ id: row.id });
-			handleQuery();
-			ElMessage.success('删除成功');
-		})
-		.catch(() => {});
+	}).then(async () => {
+		await getAPI(SysLdapApi).apiSysLdapSyncOrgPost({ id: row.id });
+		handleQuery();
+		ElMessage.success('删除成功');
+	}).catch(() => {});
 };
 </script>

+ 2 - 5
Web/src/views/system/log/difflog/index.vue

@@ -3,9 +3,7 @@
 		<el-card shadow="hover" :body-style="{ padding: 5 }">
 			<el-form :model="state.queryParams" ref="queryForm" :inline="true">
 				<el-form-item label="租户" v-if="userStore.userInfos.accountType == 999">
-					<el-select v-model="state.queryParams.tenantId" placeholder="租户" style="width: 100%">
-						<el-option :value="item.value" :label="`${item.label} (${item.host})`" v-for="(item, index) in state.tenantList" :key="index" />
-					</el-select>
+					<TenantSelect v-model="state.queryParams.tenantId" clearable />
 				</el-form-item>
 				<el-form-item label="开始时间">
 					<el-date-picker v-model="state.queryParams.startTime" type="datetime" placeholder="开始时间" value-format="YYYY-MM-DD HH:mm:ss" :shortcuts="shortcuts" />
@@ -91,11 +89,11 @@ import { getAPI } from '/@/utils/axios-utils';
 import { SysLogDiffApi, SysTenantApi } from '/@/api-services/api';
 import { SysLogDiff } from '/@/api-services/models';
 import { useUserInfo } from "/@/stores/userInfo";
+import TenantSelect from '/@/views/system/tenant/component/tenantSelect.vue';
 
 const userStore = useUserInfo();
 const state = reactive({
 	loading: false,
-	tenantList: [] as Array<any>,
 	queryParams: {
 		tenantId: undefined,
 		startTime: undefined,
@@ -111,7 +109,6 @@ const state = reactive({
 
 onMounted(async () => {
 	if (userStore.userInfos.accountType == 999) {
-		state.tenantList = await getAPI(SysTenantApi).apiSysTenantListGet().then(res => res.data.result ?? []);
 		state.queryParams.tenantId = userStore.userInfos.currentTenantId as any;
 	}
 	handleQuery();

+ 3 - 6
Web/src/views/system/log/oplog/index.vue

@@ -3,9 +3,7 @@
 		<el-card shadow="hover" :body-style="{ padding: 5 }">
 			<el-form :model="state.queryParams" ref="queryForm" :inline="true">
 				<el-form-item label="租户" v-if="userStore.userInfos.accountType == 999">
-					<el-select v-model="state.queryParams.tenantId" placeholder="租户" style="width: 100%">
-						<el-option :value="item.value" :label="`${item.label} (${item.host})`" v-for="(item, index) in state.tenantList" :key="index" />
-					</el-select>
+					<TenantSelect v-model="state.queryParams.tenantId" clearable />
 				</el-form-item>
 				<el-form-item label="开始时间">
 					<el-date-picker v-model="state.queryParams.startTime" type="datetime" placeholder="开始时间" value-format="YYYY-MM-DD HH:mm:ss" :shortcuts="shortcuts" />
@@ -119,13 +117,13 @@ import { downloadByData, getFileName } from '/@/utils/download';
 import { getAPI } from '/@/utils/axios-utils';
 import { SysLogOp } from '/@/api-services/models';
 import { useUserInfo } from "/@/stores/userInfo";
-import { SysLogOpApi, SysTenantApi } from '/@/api-services/api';
+import { SysLogOpApi } from '/@/api-services/api';
+import TenantSelect from '/@/views/system/tenant/component/tenantSelect.vue';
 
 const userStore = useUserInfo();
 const state = reactive({
 	loading: false,
 	loadingDetail: false,
-	tenantList: [] as Array<any>,
 	queryParams: {
 		tenantId: undefined,
 		startTime: undefined,
@@ -151,7 +149,6 @@ const state = reactive({
 
 onMounted(async () => {
 	if (userStore.userInfos.accountType == 999) {
-		state.tenantList = await getAPI(SysTenantApi).apiSysTenantListGet().then(res => res.data.result ?? []);
 		state.queryParams.tenantId = userStore.userInfos.currentTenantId as any;
 	}
 	handleQuery();

+ 2 - 5
Web/src/views/system/log/vislog/index.vue

@@ -3,9 +3,7 @@
 		<el-card shadow="hover" :body-style="{ padding: 5 }">
 			<el-form :model="state.queryParams" ref="queryForm" :inline="true">
 				<el-form-item label="租户" v-if="userStore.userInfos.accountType == 999">
-					<el-select v-model="state.queryParams.tenantId" placeholder="租户" style="width: 100%">
-						<el-option :value="item.value" :label="`${item.label} (${item.host})`" v-for="(item, index) in state.tenantList" :key="index" />
-					</el-select>
+					<TenantSelect v-model="state.queryParams.tenantId" clearable />
 				</el-form-item>
 				<el-form-item label="开始时间">
 					<el-date-picker v-model="state.queryParams.startTime" type="datetime" placeholder="开始时间" value-format="YYYY-MM-DD HH:mm:ss" :shortcuts="shortcuts" />
@@ -87,11 +85,11 @@ import { getAPI } from '/@/utils/axios-utils';
 import { SysLogVis } from '/@/api-services/models';
 import { useUserInfo } from "/@/stores/userInfo";
 import { SysLogVisApi, SysTenantApi } from '/@/api-services/api';
+import TenantSelect from '/@/views/system/tenant/component/tenantSelect.vue';
 
 const userStore = useUserInfo();
 const state = reactive({
 	loading: false,
-	tenantList: [] as Array<any>,
 	queryParams: {
 		tenantId: undefined,
 		startTime: undefined,
@@ -112,7 +110,6 @@ const state = reactive({
 
 onMounted(async () => {
 	if (userStore.userInfos.accountType == 999) {
-		state.tenantList = await getAPI(SysTenantApi).apiSysTenantListGet().then(res => res.data.result ?? []);
 		state.queryParams.tenantId = userStore.userInfos.currentTenantId as any;
 	}
 	handleQuery();

+ 4 - 9
Web/src/views/system/menu/index.vue

@@ -3,10 +3,7 @@
 		<el-card shadow="hover" :body-style="{ padding: 5 }">
 			<el-form :model="state.queryParams" ref="queryForm" :inline="true">
 				<el-form-item label="租户" v-if="userStore.userInfos.accountType == 999">
-					<el-select v-model="state.queryParams.tenantId" placeholder="租户" style="width: 100%">
-						<el-option :value="item.value" :label="`${item.label} (${item.host})`"
-							v-for="(item, index) in state.tenantList" :key="index" />
-					</el-select>
+					<TenantSelect v-model="state.queryParams.tenantId" />
 				</el-form-item>
 				<el-form-item label="菜单名称">
 					<el-input v-model="state.queryParams.title" placeholder="菜单名称" clearable />
@@ -73,8 +70,7 @@
 			</el-table>
 		</el-card>
 
-		<EditMenu ref="editMenuRef" :title="state.editMenuTitle" :menuData="state.allMenuData"
-			@handleQuery="handleQuery" />
+		<EditMenu ref="editMenuRef" :title="state.editMenuTitle" :menuData="state.allMenuData" @handleQuery="handleQuery" />
 	</div>
 </template>
 
@@ -85,15 +81,15 @@ import EditMenu from '/@/views/system/menu/component/editMenu.vue';
 import ModifyRecord from '/@/components/table/modifyRecord.vue';
 
 import { getAPI } from '/@/utils/axios-utils';
-import { SysMenuApi, SysTenantApi } from '/@/api-services/api';
+import { SysMenuApi } from '/@/api-services/api';
 import { SysMenu, UpdateMenuInput } from '/@/api-services/models';
 import { useUserInfo } from "/@/stores/userInfo";
+import TenantSelect from '/@/views/system/tenant/component/tenantSelect.vue';
 
 const userStore = useUserInfo();
 const editMenuRef = ref<InstanceType<typeof EditMenu>>();
 const state = reactive({
 	loading: false,
-	tenantList: [] as Array<any>,
 	menuData: [] as Array<SysMenu>,
 	allMenuData: [] as Array<SysMenu>,
 	queryParams: {
@@ -106,7 +102,6 @@ const state = reactive({
 
 onMounted(async () => {
 	if (userStore.userInfos.accountType == 999) {
-		state.tenantList = await getAPI(SysTenantApi).apiSysTenantListGet().then(res => res.data.result ?? []);
 		state.queryParams.tenantId = userStore.userInfos.currentTenantId as any;
 	}
 	handleQuery();

+ 5 - 12
Web/src/views/system/org/component/orgTree.vue

@@ -3,9 +3,7 @@
 		<template #header>
 			<div class="card-header">
 				<div class="tree-h-flex" v-if="!props.tenantId">
-					<el-select v-if="userStore.userInfos.accountType == 999" v-model="state.tenantId" @change="initTreeData()" placeholder="请选择租户" class="w100 mb10">
-						<el-option :value="item.value" :label="`${item.label} (${item.host})`" v-for="(item, index) in state.tenantList" :key="index" />
-					</el-select>
+					<TenantSelect v-model="state.tenantId" @change="initTreeData()" clearable class="mb10" />
 				</div>
 				<div class="tree-h-flex">
 					<div class="tree-h-left">
@@ -62,19 +60,17 @@ import type { ElTree } from 'element-plus';
 import { Search, MoreFilled } from '@element-plus/icons-vue';
 
 import { getAPI } from '/@/utils/axios-utils';
-import {SysOrgApi, SysTenantApi} from '/@/api-services/api';
-import { OrgTreeOutput, SysOrg } from '/@/api-services/models';
-import { useUserInfo } from "/@/stores/userInfo";
+import { SysOrgApi } from '/@/api-services/api';
+import { OrgTreeOutput } from '/@/api-services/models';
+import TenantSelect from '/@/views/system/tenant/component/tenantSelect.vue';
 
 const props = defineProps({
-	tenantId: Number,
+	tenantId: [Number, String],
 });
-const userStore = useUserInfo();
 const filterText = ref('');
 const treeRef = ref<InstanceType<typeof ElTree>>();
 const state = reactive({
 	loading: false,
-	tenantList: [] as Array<any>,
 	tenantId: props.tenantId as number,
 	orgData: [] as Array<OrgTreeOutput>,
 	isShowCheckbox: false,
@@ -82,9 +78,6 @@ const state = reactive({
 });
 
 onMounted( async () => {
-	if (userStore.userInfos.accountType == 999) {
-		state.tenantList = await getAPI(SysTenantApi).apiSysTenantListGet().then(res => res.data.result ?? []);
-	}
 	initTreeData();
 });
 

+ 0 - 1
Web/src/views/system/org/index.vue

@@ -175,7 +175,6 @@ const nodeClick = async (node: any) => {
     state.queryParams.code = undefined;
     state.queryParams.type = undefined;
     state.tenantId = node.tenantId;
-    console.log(node)
     handleQuery();
 };
 </script>

+ 3 - 6
Web/src/views/system/plugin/index.vue

@@ -3,9 +3,7 @@
 		<el-card shadow="hover" :body-style="{ padding: 5 }">
 			<el-form :model="state.queryParams" ref="queryForm" :inline="true">
 				<el-form-item label="租户" v-if="userStore.userInfos.accountType == 999">
-					<el-select v-model="state.queryParams.tenantId" placeholder="租户" style="width: 100%">
-						<el-option :value="item.value" :label="`${item.label} (${item.host})`" v-for="(item, index) in state.tenantList" :key="index" />
-					</el-select>
+					<TenantSelect v-model="state.queryParams.tenantId" clearable />
 				</el-form-item>
 				<el-form-item label="功能名称">
 					<el-input v-model="state.queryParams.name" placeholder="功能名称" clearable />
@@ -68,15 +66,15 @@ import { ElMessageBox, ElMessage } from 'element-plus';
 import EditPlugin from '/@/views/system/plugin/component/editPlugin.vue';
 import ModifyRecord from '/@/components/table/modifyRecord.vue';
 import { getAPI } from '/@/utils/axios-utils';
-import { SysPluginApi, SysTenantApi } from '/@/api-services/api';
+import { SysPluginApi } from '/@/api-services/api';
 import { SysPlugin } from '/@/api-services/models';
 import { useUserInfo } from "/@/stores/userInfo";
+import TenantSelect from '/@/views/system/tenant/component/tenantSelect.vue';
 
 const userStore = useUserInfo();
 const editPluginRef = ref<InstanceType<typeof EditPlugin>>();
 const state = reactive({
 	loading: false,
-	tenantList: [] as Array<any>,
 	pluginData: [] as Array<SysPlugin>,
 	queryParams: {
 		tenantId: undefined,
@@ -92,7 +90,6 @@ const state = reactive({
 
 onMounted(async () => {
 	if (userStore.userInfos.accountType == 999) {
-		state.tenantList = await getAPI(SysTenantApi).apiSysTenantListGet().then(res => res.data.result ?? []);
 		state.queryParams.tenantId = userStore.userInfos.currentTenantId as any;
 	}
 	handleQuery();

+ 4 - 6
Web/src/views/system/pos/index.vue

@@ -3,9 +3,7 @@
 		<el-card shadow="hover" :body-style="{ padding: 5 }">
 			<el-form :model="state.queryParams" ref="queryForm" :inline="true">
 				<el-form-item label="租户" v-if="userStore.userInfos.accountType == 999">
-					<el-select v-model="state.queryParams.tenantId" placeholder="租户" style="width: 100%">
-						<el-option :value="item.value" :label="`${item.label} (${item.host})`" v-for="(item, index) in state.tenantList" :key="index" />
-					</el-select>
+					<TenantSelect v-model="state.queryParams.tenantId" clearable />
 				</el-form-item>
 				<el-form-item label="职位名称">
 					<el-input v-model="state.queryParams.name" placeholder="职位名称" clearable />
@@ -81,16 +79,17 @@ import EditPos from '/@/views/system/pos/component/editPos.vue';
 import ModifyRecord from '/@/components/table/modifyRecord.vue';
 
 import { getAPI } from '/@/utils/axios-utils';
-import {SysPosApi, SysTenantApi} from '/@/api-services/api';
+import { SysPosApi } from '/@/api-services/api';
 import { SysPos, UpdatePosInput } from '/@/api-services/models';
 import { useUserInfo } from "/@/stores/userInfo";
 
+import TenantSelect from '/@/views/system/tenant/component/tenantSelect.vue';
+
 const userStore = useUserInfo();
 const editPosRef = ref<InstanceType<typeof EditPos>>();
 const state = reactive({
 	loading: false,
 	posData: [] as Array<SysPos>,
-	tenantList: [] as Array<any>,
 	queryParams: {
 		tenantId: undefined,
 		name: undefined,
@@ -101,7 +100,6 @@ const state = reactive({
 
 onMounted(async () => {
 	if (userStore.userInfos.accountType == 999) {
-		state.tenantList = await getAPI(SysTenantApi).apiSysTenantListGet().then(res => res.data.result ?? []);
 		state.queryParams.tenantId = userStore.userInfos.currentTenantId as any;
 	}
 	handleQuery();

+ 3 - 6
Web/src/views/system/print/index.vue

@@ -3,9 +3,7 @@
 		<el-card shadow="hover" :body-style="{ padding: 5 }">
 			<el-form :model="state.queryParams" ref="queryForm" :inline="true">
 				<el-form-item label="租户" v-if="userStore.userInfos.accountType == 999">
-					<el-select v-model="state.queryParams.tenantId" placeholder="租户" style="width: 100%">
-						<el-option :value="item.value" :label="`${item.label} (${item.host})`" v-for="(item, index) in state.tenantList" :key="index" />
-					</el-select>
+                    <TenantSelect v-model="state.queryParams.tenantId" clearable />
 				</el-form-item>
 				<el-form-item label="模板名称">
 					<el-input v-model="state.queryParams.name" placeholder="模板名称" clearable />
@@ -68,15 +66,15 @@ import { ElMessageBox, ElMessage } from 'element-plus';
 import EditPrint from '/@/views/system/print/component/editPrint.vue';
 import ModifyRecord from '/@/components/table/modifyRecord.vue';
 import { getAPI } from '/@/utils/axios-utils';
-import {SysPrintApi, SysTenantApi} from '/@/api-services/api';
+import { SysPrintApi } from '/@/api-services/api';
 import { SysPrint } from '/@/api-services/models';
 import { useUserInfo } from "/@/stores/userInfo";
+import TenantSelect from '/@/views/system/tenant/component/tenantSelect.vue';
 
 const userStore = useUserInfo();
 const editPrintRef = ref<InstanceType<typeof EditPrint>>();
 const state = reactive({
 	loading: false,
-	tenantList: [] as Array<any>,
 	printData: [] as Array<SysPrint>,
 	queryParams: {
 		tenantId: undefined,
@@ -92,7 +90,6 @@ const state = reactive({
 
 onMounted(async () => {
 	if (userStore.userInfos.accountType == 999) {
-		state.tenantList = await getAPI(SysTenantApi).apiSysTenantListGet().then(res => res.data.result ?? []);
 		state.queryParams.tenantId = userStore.userInfos.currentTenantId as any;
 	}
 	handleQuery();

+ 1 - 1
Web/src/views/system/role/component/grantData.vue

@@ -11,7 +11,7 @@
 				<el-row :gutter="35">
 					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl1="24" class="mb20">
 						<el-form-item label="数据范围:">
-              <g-sys-dict v-model="state.ruleForm.dataScope" code="DataScopeEnum" render-as="select" placeholder="数据范围" class="w100" />
+                            <g-sys-dict v-model="state.ruleForm.dataScope" code="DataScopeEnum" render-as="select" placeholder="数据范围" class="w100" />
 						</el-form-item>
 					</el-col>
 					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl1="24" v-show="state.ruleForm.dataScope === 5">

+ 3 - 6
Web/src/views/system/role/index.vue

@@ -3,9 +3,7 @@
 		<el-card shadow="hover" :body-style="{ padding: 5 }">
 			<el-form :model="state.queryParams" ref="queryForm" :inline="true">
 				<el-form-item label="租户" v-if="userStore.userInfos.accountType == 999">
-					<el-select v-model="state.queryParams.tenantId" placeholder="租户" style="width: 100%">
-						<el-option :value="item.value" :label="`${item.label} (${item.host})`" v-for="(item, index) in state.tenantList" :key="index" />
-					</el-select>
+					<TenantSelect v-model="state.queryParams.tenantId" clearable />
 				</el-form-item>
 				<el-form-item label="角色名称">
 					<el-input v-model="state.queryParams.name" placeholder="角色名称" clearable />
@@ -79,16 +77,16 @@ import EditRole from '/@/views/system/role/component/editRole.vue';
 import GrantData from '/@/views/system/role/component/grantData.vue';
 import ModifyRecord from '/@/components/table/modifyRecord.vue';
 import { getAPI } from '/@/utils/axios-utils';
-import { SysRoleApi, SysTenantApi } from '/@/api-services/api';
+import { SysRoleApi } from '/@/api-services/api';
 import { SysRole } from '/@/api-services/models';
 import { useUserInfo } from "/@/stores/userInfo";
+import TenantSelect from '/@/views/system/tenant/component/tenantSelect.vue';
 
 const userStore = useUserInfo();
 const editRoleRef = ref<InstanceType<typeof EditRole>>();
 const grantDataRef = ref<InstanceType<typeof GrantData>>();
 const state = reactive({
 	loading: false,
-	tenantList: [] as Array<any>,
 	roleData: [] as Array<SysRole>,
 	queryParams: {
 		tenantId: undefined,
@@ -105,7 +103,6 @@ const state = reactive({
 
 onMounted(async () => {
 	if (userStore.userInfos.accountType == 999) {
-		state.tenantList = await getAPI(SysTenantApi).apiSysTenantListGet().then(res => res.data.result ?? []);
 		state.queryParams.tenantId = userStore.userInfos.currentTenantId as any;
 	}
 	await handleQuery();

+ 1 - 1
Web/src/views/system/template/component/editTemplate.vue

@@ -57,7 +57,7 @@
 							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
 								<el-form-item label="内容" prop="content" :rules="[{ required: true, message: '内容不能为空', trigger: 'blur' }]" label-position="top">
 									<Editor v-model:get-html="state.ruleForm.content" ref="editorRef" height="200px" v-if="state.contentType == 1" />
-									<el-input v-model="state.ruleForm.content" v-else type="textarea" rows="15" show-word-limit clearable />
+									<el-input v-model="state.ruleForm.content" v-else type="textarea" :rows="15" show-word-limit clearable />
 								</el-form-item>
 							</el-col>
 							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20" style="user-select: none;">

+ 51 - 0
Web/src/views/system/tenant/component/tenantSelect.vue

@@ -0,0 +1,51 @@
+<template v-if="userStore.userInfos.accountType == 999">
+    <el-select v-bind="$attrs" v-model="tenantModelValue" placeholder="请选择租户">
+        <el-option v-for="(item, index) in state.tenantList"
+            :value="item.value" 
+            :label="item.host ? `${item.label} (${item.host})` : item.label" 
+            :key="index" 
+        />
+    </el-select>
+</template>
+
+<script lang="ts" setup name="TenantSelect">
+import { PropType, computed, reactive, onMounted } from 'vue';
+
+import { getAPI } from '/@/utils/axios-utils';
+import { useUserInfo } from "/@/stores/userInfo";
+import { SysTenantApi} from '/@/api-services/api';
+
+const emit = defineEmits(['update:modelValue']);
+
+const props = defineProps({
+	/**
+     * 绑定的值
+     * @example
+     * <tenant-select v-model="value" code="xxxx" />
+   */
+    modelValue: {
+        type: [String, Number, null] as PropType<string | number | null>,
+        default: null,
+        required: true,
+    },
+
+});
+const tenantModelValue = computed({
+    get: () => props.modelValue,
+    set: (val) => emit('update:modelValue', val),
+});
+
+const userStore = useUserInfo();
+const state = reactive({
+    tenantList: [] as Array<any>,
+});
+
+
+onMounted( async () => {
+    if (userStore.userInfos.accountType == 999) {
+        state.tenantList = await getAPI(SysTenantApi).apiSysTenantListGet().then(res => res.data.result ?? []);
+    }
+});
+</script>
+
+<style lang="scss" scoped></style>

+ 9 - 2
Web/src/views/system/user/index.vue

@@ -118,7 +118,15 @@
 							</template>
 						</el-table-column>
 					</el-table>
-					<el-pagination v-model:currentPage="state.tableParams.page" @current-change="handleCurrentChange" layout="total, sizes, prev, pager, next, jumper" />
+					<el-pagination size="small" background 
+                        v-model:currentPage="state.tableParams.page" 
+                        v-model:page-size="state.tableParams.pageSize"
+                        :total="state.tableParams.total"
+                        :page-sizes="[10, 20, 50, 100]"
+                        @size-change="handleSizeChange"
+                        @current-change="handleCurrentChange" 
+                        layout="total, sizes, prev, pager, next, jumper" 
+                    />
 				</el-card>
 			</el-splitter-panel>
 		</el-splitter>
@@ -174,7 +182,6 @@ const loadOrgData = async () => {
 	state.loading = true;
 	let res = await getAPI(SysOrgApi).apiSysOrgTreeGet(0);
 	state.orgTreeData = res.data.result ?? [];
-	console.log('🚀 → index.vue:173 → loadOrgData → state.orgTreeData:', state.orgTreeData);
 	state.loading = false;
 };
 

+ 3 - 6
Web/src/views/system/userRegWay/index.vue

@@ -3,9 +3,7 @@
 		<el-card shadow="hover" :body-style="{ padding: 5 }" v-auth="'sysUserRegWay:list'">
 			<el-form :model="state.queryParams" ref="queryForm" :inline="true">
 				<el-form-item label="租户" v-if="userStore.userInfos.accountType == 999">
-					<el-select v-model="state.queryParams.tenantId" placeholder="租户" style="width: 100%">
-						<el-option :value="item.value" :label="`${item.label} (${item.host})`" v-for="(item, index) in state.tenantList" :key="index" />
-					</el-select>
+					<TenantSelect v-model="state.queryParams.tenantId" clearable />
 				</el-form-item>
 				<el-form-item label="关键字">
 					<el-input v-model="state.queryParams.keyword" placeholder="关键字" clearable />
@@ -57,17 +55,17 @@ import { onMounted, reactive, ref } from 'vue';
 import { ElMessageBox, ElMessage } from 'element-plus';
 import { getAPI } from '/@/utils/axios-utils';
 import { UserRegWayOutput } from '/@/api-services/models';
-import { SysTenantApi, SysUserRegWayApi} from '/@/api-services/api';
+import { SysUserRegWayApi} from '/@/api-services/api';
 import { auths } from "/@/utils/authFunction";
 import { useUserInfo } from "/@/stores/userInfo";
 import EditRegWay from './component/editRegWay.vue';
 import ModifyRecord from '/@/components/table/modifyRecord.vue';
+import TenantSelect from '/@/views/system/tenant/component/tenantSelect.vue';
 
 const userStore = useUserInfo();
 const editRegWayRef = ref<InstanceType<typeof EditRegWay>>();
 const state = reactive({
 	loading: false,
-	tenantList: [] as Array<any>,
 	regWayData: [] as Array<UserRegWayOutput>,
 	queryParams: {
 		name: undefined,
@@ -79,7 +77,6 @@ const state = reactive({
 
 onMounted(async () => {
 	if (userStore.userInfos.accountType == 999) {
-		state.tenantList = await getAPI(SysTenantApi).apiSysTenantListGet().then(res => res.data.result ?? []);
 		state.queryParams.tenantId = userStore.userInfos.currentTenantId as any;
 	}
 	handleQuery();