Przeglądaj źródła

feat: 通过域名查找租户隔离登录账号

喵你个旺呀 1 rok temu
rodzic
commit
3b2adc406f

+ 5 - 0
Admin.NET/Admin.NET.Core/Const/SqlSugarConst.cs

@@ -30,4 +30,9 @@ public class SqlSugarConst
     /// 默认租户Id
     /// </summary>
     public const long DefaultTenantId = 1300000000001;
+    
+    /// <summary>
+    /// 默认租户域名
+    /// </summary>
+    public const string DefaultTenantHost = "gitee.com";
 }

+ 2 - 2
Admin.NET/Admin.NET.Core/Entity/SysTenant.cs

@@ -26,9 +26,9 @@ public partial class SysTenant : EntityBase
     public long OrgId { get; set; }
 
     /// <summary>
-    /// 主机
+    /// 域名
     /// </summary>
-    [SugarColumn(ColumnDescription = "主机", Length = 128)]
+    [SugarColumn(ColumnDescription = "域名", Length = 128)]
     [MaxLength(128)]
     public string? Host { get; set; }
 

+ 14 - 2
Admin.NET/Admin.NET.Core/Enum/ErrorCodeEnum.cs

@@ -222,6 +222,12 @@ public enum ErrorCodeEnum
     /// </summary>
     [ErrorCodeItemMetadata("开放接口绑定租户禁止删除")]
     D1031,
+    
+    /// <summary>
+    /// 手机号已存在
+    /// </summary>
+    [ErrorCodeItemMetadata("手机号已存在")]
+    D1032,
 
     /// <summary>
     /// 父机构不存在
@@ -546,6 +552,12 @@ public enum ErrorCodeEnum
     /// </summary>
     [ErrorCodeItemMetadata("租户从库配置错误")]
     D1302,
+    
+    /// <summary>
+    /// 已存在同名的租户域名
+    /// </summary>
+    [ErrorCodeItemMetadata("已存在同名的租户域名")]
+    D1303,
 
     /// <summary>
     /// 该表代码模板已经生成过
@@ -734,9 +746,9 @@ public enum ErrorCodeEnum
     Z1002,
 
     /// <summary>
-    /// 租户已禁用
+    /// 租户不存在或已禁用
     /// </summary>
-    [ErrorCodeItemMetadata("租户已禁用")]
+    [ErrorCodeItemMetadata("租户不存在或已禁用")]
     Z1003,
 
     /// <summary>

+ 1 - 1
Admin.NET/Admin.NET.Core/SeedData/SysTenantSeedData.cs

@@ -21,7 +21,7 @@ public class SysTenantSeedData : ISqlSugarEntitySeedData<SysTenant>
 
         return new[]
         {
-            new SysTenant{ Id=SqlSugarConst.DefaultTenantId, OrgId=SqlSugarConst.DefaultTenantId, UserId=1300000000111, Host="https://gitee.com", TenantType=TenantTypeEnum.Id, DbType=defaultDbConfig.DbType, Connection=defaultDbConfig.ConnectionString, ConfigId=SqlSugarConst.MainConfigId, Remark="系统默认", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
+            new SysTenant{ Id=SqlSugarConst.DefaultTenantId, OrgId=SqlSugarConst.DefaultTenantId, UserId=1300000000111, Host=SqlSugarConst.DefaultTenantHost, TenantType=TenantTypeEnum.Id, DbType=defaultDbConfig.DbType, Connection=defaultDbConfig.ConnectionString, ConfigId=SqlSugarConst.MainConfigId, Remark="系统默认", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
         };
     }
 }

+ 10 - 0
Admin.NET/Admin.NET.Core/Service/Auth/Dto/LoginInput.cs

@@ -34,6 +34,11 @@ public class LoginInput
     /// 验证码
     /// </summary>
     public string Code { get; set; }
+    
+    /// <summary>
+    /// 租户域名
+    /// </summary>
+    public string? Host { get; set; }
 }
 
 public class LoginPhoneInput
@@ -52,4 +57,9 @@ public class LoginPhoneInput
     /// <example>123456</example>
     [Required(ErrorMessage = "验证码不能为空"), MinLength(4, ErrorMessage = "验证码不能少于4个字符")]
     public string Code { get; set; }
+    
+    /// <summary>
+    /// 租户域名
+    /// </summary>
+    public string? Host { get; set; }
 }

+ 30 - 7
Admin.NET/Admin.NET.Core/Service/Auth/SysAuthService.cs

@@ -70,18 +70,20 @@ public class SysAuthService : IDynamicApiController, ITransient
             // 判断验证码
             if (!_captcha.Validate(input.CodeId.ToString(), input.Code)) throw Oops.Oh(ErrorCodeEnum.D0008);
         }
+        
+        // 获取租户
+        var tenant = await GetTenantByHost(input.Host);
 
         // 账号是否存在
-        var user = await _sysUserRep.AsQueryable().Includes(t => t.SysOrg).ClearFilter().FirstAsync(u => u.Account.Equals(input.Account));
+        var user = await _sysUserRep.AsQueryable().Includes(t => t.SysOrg).ClearFilter().FirstAsync(u => (u.TenantId == tenant.Id || u.AccountType == AccountTypeEnum.SuperAdmin) && u.Account.Equals(input.Account));
         _ = user ?? throw Oops.Oh(ErrorCodeEnum.D0009);
+        
+        // 若登录的是超级管理员,则引用当前绑定的租户,这样登陆后操作的租户数据才会与该租户关联
+        if (user.AccountType == AccountTypeEnum.SuperAdmin) user.TenantId = tenant.Id;
 
         // 账号是否被冻结
         if (user.Status == StatusEnum.Disable) throw Oops.Oh(ErrorCodeEnum.D1017);
 
-        // 租户是否被禁用
-        var tenant = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysTenant>>().GetFirstAsync(u => u.Id == user.TenantId);
-        if (tenant?.Status == StatusEnum.Disable) throw Oops.Oh(ErrorCodeEnum.Z1003);
-
         // 是否开启域登录验证
         if (await _sysConfigService.GetConfigValue<bool>(ConfigConst.SysDomainLogin))
         {
@@ -104,6 +106,23 @@ public class SysAuthService : IDynamicApiController, ITransient
 
         return await CreateToken(user);
     }
+    
+    /// <summary>
+    /// 根据绑定域名获取租户
+    /// </summary>
+    /// <param name="host"></param>
+    /// <returns></returns>
+    private async Task<SysTenant> GetTenantByHost(string host)
+    {
+        // 若租户域名为空或为本地域名,则取默认租户域名
+        if (string.IsNullOrWhiteSpace(host) || host.StartsWith("localhost")) host = SqlSugarConst.DefaultTenantHost;
+        
+        // 租户是否存在或已禁用
+        var tenant = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysTenant>>().GetFirstAsync(u => u.Host == host.ToLower());
+        if (tenant?.Status != StatusEnum.Enable) throw Oops.Oh(ErrorCodeEnum.Z1003);
+
+        return tenant;
+    }
 
     /// <summary>
     /// 验证用户密码
@@ -176,9 +195,12 @@ public class SysAuthService : IDynamicApiController, ITransient
     {
         // 校验短信验证码
         App.GetRequiredService<SysSmsService>().VerifyCode(new SmsVerifyCodeInput { Phone = input.Phone, Code = input.Code });
-
+        
+        // 获取租户
+        var tenant = await GetTenantByHost(input.Host);
+        
         // 账号是否存在
-        var user = await _sysUserRep.AsQueryable().Includes(u => u.SysOrg).ClearFilter().FirstAsync(u => u.Phone.Equals(input.Phone));
+        var user = await _sysUserRep.AsQueryable().Includes(u => u.SysOrg).ClearFilter().FirstAsync(u => (u.TenantId == tenant.Id || u.AccountType == AccountTypeEnum.SuperAdmin) && u.Phone.Equals(input.Phone));
         _ = user ?? throw Oops.Oh(ErrorCodeEnum.D0009);
 
         return await CreateToken(user);
@@ -351,6 +373,7 @@ public class SysAuthService : IDynamicApiController, ITransient
             {
                 Account = auth.UserName,
                 Password = CryptogramUtil.SM2Encrypt(auth.Password),
+                Host = SqlSugarConst.DefaultTenantHost
             });
 
             _sysCacheService.Remove($"{CacheConst.KeyConfig}{ConfigConst.SysCaptcha}");

+ 6 - 0
Admin.NET/Admin.NET.Core/Service/Tenant/Dto/TenantInput.cs

@@ -40,6 +40,12 @@ public class AddTenantInput : TenantOutput
     /// </summary>
     [Required(ErrorMessage = "租管账号不能为空"), MinLength(3, ErrorMessage = "租管账号不能少于3个字符")]
     public override string AdminAccount { get; set; }
+    
+    /// <summary>
+    /// 租户域名
+    /// </summary>
+    [Required(ErrorMessage = "域名不能为空"), MinLength(5, ErrorMessage = "域名不能少于5个字符")]
+    public new string Host { get; set; }
 }
 
 public class UpdateTenantInput : AddTenantInput

+ 11 - 2
Admin.NET/Admin.NET.Core/Service/Tenant/SysTenantService.cs

@@ -75,6 +75,7 @@ public class SysTenantService : IDynamicApiController, ITransient
                 UserId = a.Id,
                 AdminAccount = a.Account,
                 Phone = a.Phone,
+                Host = u.Host,
                 Email = a.Email,
                 TenantType = u.TenantType,
                 DbType = u.DbType,
@@ -113,8 +114,12 @@ public class SysTenantService : IDynamicApiController, ITransient
     {
         var isExist = await _sysOrgRep.IsAnyAsync(u => u.Name == input.Name);
         if (isExist) throw Oops.Oh(ErrorCodeEnum.D1300);
+        
+        input.Host = input.Host.ToLower();
+        isExist = await _sysTenantRep.IsAnyAsync(u => u.Host == input.Host);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.D1303);
 
-        isExist = await _sysUserRep.AsQueryable().ClearFilter().AnyAsync(u => u.Account == input.AdminAccount);
+        isExist = await _sysUserRep.AsQueryable().ClearFilter().AnyAsync(u => u.AccountType == AccountTypeEnum.SuperAdmin && u.Account == input.AdminAccount);
         if (isExist) throw Oops.Oh(ErrorCodeEnum.D1301);
 
         // 从库配置判断
@@ -272,8 +277,12 @@ public class SysTenantService : IDynamicApiController, ITransient
     {
         var isExist = await _sysOrgRep.IsAnyAsync(u => u.Name == input.Name && u.Id != input.OrgId);
         if (isExist) throw Oops.Oh(ErrorCodeEnum.D1300);
+
+        input.Host = input.Host.ToLower();
+        isExist = await _sysTenantRep.IsAnyAsync(u => u.Host == input.Host && u.Id != input.Id);
+        if (isExist) throw Oops.Oh(ErrorCodeEnum.D1303);
         
-        isExist = await _sysUserRep.IsAnyAsync(u => u.Account == input.AdminAccount && u.Id != input.UserId);
+        isExist = await _sysUserRep.AsQueryable().ClearFilter().AnyAsync(u => u.AccountType == AccountTypeEnum.SuperAdmin && u.Account == input.AdminAccount && u.Id != input.UserId);
         if (isExist) throw Oops.Oh(ErrorCodeEnum.D1301);
 
         // Id隔离时设置与主库一致

+ 11 - 7
Admin.NET/Admin.NET.Core/Service/User/SysUserService.cs

@@ -100,9 +100,12 @@ public class SysUserService : IDynamicApiController, ITransient
     [DisplayName("增加用户")]
     public virtual async Task<long> AddUser(AddUserInput input)
     {
-        var isExist = await _sysUserRep.AsQueryable().ClearFilter().AnyAsync(u => u.Account == input.Account);
+        var isExist = await _sysUserRep.AsQueryable().ClearFilter().AnyAsync(u => (u.TenantId == _userManager.TenantId || u.AccountType == AccountTypeEnum.SuperAdmin) && u.Account == input.Account);
         if (isExist) throw Oops.Oh(ErrorCodeEnum.D1003);
 
+        if (!string.IsNullOrWhiteSpace(input.Phone) && await _sysUserRep.AsQueryable().ClearFilter().AnyAsync(u => (u.TenantId == _userManager.TenantId || u.AccountType == AccountTypeEnum.SuperAdmin) && u.Phone == input.Phone))
+            throw Oops.Oh(ErrorCodeEnum.D1032);
+
         var password = await _sysConfigService.GetConfigValue<string>(ConfigConst.SysPassword);
 
         var user = input.Adapt<SysUser>();
@@ -132,11 +135,14 @@ public class SysUserService : IDynamicApiController, ITransient
     [DisplayName("更新用户")]
     public virtual async Task UpdateUser(UpdateUserInput input)
     {
-        if (await _sysUserRep.AsQueryable().ClearFilter().AnyAsync(u => u.Account == input.Account && u.Id != input.Id))
+        if (await _sysUserRep.AsQueryable().ClearFilter().AnyAsync(u => (u.TenantId == _userManager.TenantId || u.AccountType == AccountTypeEnum.SuperAdmin) && u.Account == input.Account && u.Id != input.Id))
             throw Oops.Oh(ErrorCodeEnum.D1003);
+        
+        if (!string.IsNullOrWhiteSpace(input.Phone) && await _sysUserRep.AsQueryable().ClearFilter().AnyAsync(u => (u.TenantId == _userManager.TenantId || u.AccountType == AccountTypeEnum.SuperAdmin) && u.Phone == input.Phone && u.Id != input.Id))
+            throw Oops.Oh(ErrorCodeEnum.D1032);
 
         await _sysUserRep.AsUpdateable(input.Adapt<SysUser>()).IgnoreColumns(true)
-            .IgnoreColumns(u => new { u.Password, u.Status }).ExecuteCommandAsync();
+            .IgnoreColumns(u => new { u.Password, u.Status, u.TenantId }).ExecuteCommandAsync();
 
         await UpdateRoleAndExtOrg(input);
 
@@ -183,13 +189,11 @@ public class SysUserService : IDynamicApiController, ITransient
 
         // 若账号为租户默认账号则禁止删除
         var isTenantUser = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysTenant>>().IsAnyAsync(u => u.UserId == input.Id);
-        if (isTenantUser)
-            throw Oops.Oh(ErrorCodeEnum.D1029);
+        if (isTenantUser) throw Oops.Oh(ErrorCodeEnum.D1029);
 
         // 若账号为开放接口绑定账号则禁止删除
         var isOpenAccessUser = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysOpenAccess>>().IsAnyAsync(u => u.BindUserId == input.Id);
-        if (isOpenAccessUser)
-            throw Oops.Oh(ErrorCodeEnum.D1030);
+        if (isOpenAccessUser) throw Oops.Oh(ErrorCodeEnum.D1030);
 
         // 强制下线
         await _sysOnlineUserService.ForceOffline(user.Id);

+ 1 - 0
Web/src/api-services/api.ts

@@ -35,6 +35,7 @@ export * from './apis/sys-message-api';
 export * from './apis/sys-notice-api';
 export * from './apis/sys-oauth-api';
 export * from './apis/sys-online-user-api';
+export * from './apis/sys-online-user-chat-api';
 export * from './apis/sys-open-access-api';
 export * from './apis/sys-org-api';
 export * from './apis/sys-plugin-api';

+ 85 - 0
Web/src/api-services/apis/sys-common-api.ts

@@ -18,6 +18,7 @@ import { Configuration } from '../configuration';
 import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } from '../base';
 import { AdminResultIActionResult } from '../models';
 import { AdminResultListApiOutput } from '../models';
+import { AdminResultObject } from '../models';
 import { AdminResultSmKeyPairOutput } from '../models';
 /**
  * SysCommonApi - axios parameter creator
@@ -116,6 +117,55 @@ export const SysCommonApiAxiosParamCreator = function (configuration?: Configura
                 options: localVarRequestOptions,
             };
         },
+        /**
+         * 
+         * @summary 加密字符串 🔖
+         * @param {string} plainText 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysCommonEncryptPlainTextPlainTextPost: async (plainText: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            // verify required parameter 'plainText' is not null or undefined
+            if (plainText === null || plainText === undefined) {
+                throw new RequiredError('plainText','Required parameter plainText was null or undefined when calling apiSysCommonEncryptPlainTextPlainTextPost.');
+            }
+            const localVarPath = `/api/sysCommon/encryptPlainText/{plainText}`
+                .replace(`{${"plainText"}}`, encodeURIComponent(String(plainText)));
+            // use dummy base URL string because the URL constructor only accepts absolute URLs.
+            const localVarUrlObj = new URL(localVarPath, 'https://example.com');
+            let baseOptions;
+            if (configuration) {
+                baseOptions = configuration.baseOptions;
+            }
+            const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
+            const localVarHeaderParameter = {} as any;
+            const localVarQueryParameter = {} as any;
+
+            // authentication Bearer required
+            // http bearer authentication required
+            if (configuration && configuration.accessToken) {
+                const accessToken = typeof configuration.accessToken === 'function'
+                    ? await configuration.accessToken()
+                    : await configuration.accessToken;
+                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
+            }
+
+            const query = new URLSearchParams(localVarUrlObj.search);
+            for (const key in localVarQueryParameter) {
+                query.set(key, localVarQueryParameter[key]);
+            }
+            for (const key in options.params) {
+                query.set(key, options.params[key]);
+            }
+            localVarUrlObj.search = (new URLSearchParams(query)).toString();
+            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+
+            return {
+                url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
+                options: localVarRequestOptions,
+            };
+        },
         /**
          * 
          * @summary 获取国密公钥私钥对 🏆
@@ -195,6 +245,20 @@ export const SysCommonApiFp = function(configuration?: Configuration) {
                 return axios.request(axiosRequestArgs);
             };
         },
+        /**
+         * 
+         * @summary 加密字符串 🔖
+         * @param {string} plainText 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysCommonEncryptPlainTextPlainTextPost(plainText: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminResultObject>>> {
+            const localVarAxiosArgs = await SysCommonApiAxiosParamCreator(configuration).apiSysCommonEncryptPlainTextPlainTextPost(plainText, options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
         /**
          * 
          * @summary 获取国密公钥私钥对 🏆
@@ -236,6 +300,16 @@ export const SysCommonApiFactory = function (configuration?: Configuration, base
         async apiSysCommonDownloadErrorExcelTempPost(fileName?: string, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultIActionResult>> {
             return SysCommonApiFp(configuration).apiSysCommonDownloadErrorExcelTempPost(fileName, options).then((request) => request(axios, basePath));
         },
+        /**
+         * 
+         * @summary 加密字符串 🔖
+         * @param {string} plainText 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysCommonEncryptPlainTextPlainTextPost(plainText: string, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultObject>> {
+            return SysCommonApiFp(configuration).apiSysCommonEncryptPlainTextPlainTextPost(plainText, options).then((request) => request(axios, basePath));
+        },
         /**
          * 
          * @summary 获取国密公钥私钥对 🏆
@@ -276,6 +350,17 @@ export class SysCommonApi extends BaseAPI {
     public async apiSysCommonDownloadErrorExcelTempPost(fileName?: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultIActionResult>> {
         return SysCommonApiFp(this.configuration).apiSysCommonDownloadErrorExcelTempPost(fileName, options).then((request) => request(this.axios, this.basePath));
     }
+    /**
+     * 
+     * @summary 加密字符串 🔖
+     * @param {string} plainText 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysCommonApi
+     */
+    public async apiSysCommonEncryptPlainTextPlainTextPost(plainText: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultObject>> {
+        return SysCommonApiFp(this.configuration).apiSysCommonEncryptPlainTextPlainTextPost(plainText, options).then((request) => request(this.axios, this.basePath));
+    }
     /**
      * 
      * @summary 获取国密公钥私钥对 🏆

+ 6 - 6
Web/src/api-services/models/add-tenant-input.ts

@@ -80,12 +80,6 @@ export interface AddTenantInput {
      * @memberof AddTenantInput
      */
     orgId?: number;
-    /**
-     * 主机
-     * @type {string}
-     * @memberof AddTenantInput
-     */
-    host?: string | null;
     /**
      * 
      * @type {TenantTypeEnum}
@@ -158,4 +152,10 @@ export interface AddTenantInput {
      * @memberof AddTenantInput
      */
     adminAccount: string;
+    /**
+     * 租户域名
+     * @type {string}
+     * @memberof AddTenantInput
+     */
+    host: string;
 }

+ 6 - 0
Web/src/api-services/models/login-input.ts

@@ -41,4 +41,10 @@ export interface LoginInput {
      * @memberof LoginInput
      */
     code?: string | null;
+    /**
+     * 租户域名
+     * @type {string}
+     * @memberof LoginInput
+     */
+    host?: string | null;
 }

+ 6 - 0
Web/src/api-services/models/login-phone-input.ts

@@ -29,4 +29,10 @@ export interface LoginPhoneInput {
      * @memberof LoginPhoneInput
      */
     code: string;
+    /**
+     * 租户域名
+     * @type {string}
+     * @memberof LoginPhoneInput
+     */
+    host?: string | null;
 }

+ 6 - 6
Web/src/api-services/models/update-tenant-input.ts

@@ -80,12 +80,6 @@ export interface UpdateTenantInput {
      * @memberof UpdateTenantInput
      */
     orgId?: number;
-    /**
-     * 主机
-     * @type {string}
-     * @memberof UpdateTenantInput
-     */
-    host?: string | null;
     /**
      * 
      * @type {TenantTypeEnum}
@@ -158,4 +152,10 @@ export interface UpdateTenantInput {
      * @memberof UpdateTenantInput
      */
     adminAccount: string;
+    /**
+     * 租户域名
+     * @type {string}
+     * @memberof UpdateTenantInput
+     */
+    host: string;
 }

+ 2 - 1
Web/src/views/login/component/account.vue

@@ -204,7 +204,8 @@ const onSignIn = async () => {
 			const publicKey = window.__env__.VITE_SM_PUBLIC_KEY;
 			const password = sm2.doEncrypt(state.ruleForm.password, publicKey, 1);
 
-			const [err, res] = await feature(getAPI(SysAuthApi).apiSysAuthLoginPost({ ...state.ruleForm, password: password }));
+      const host = route.query.host ?? location.host;
+			const [err, res] = await feature(getAPI(SysAuthApi).apiSysAuthLoginPost({ ...state.ruleForm, password: password, host: host }));
 			if (err) {
 				getCaptcha(); // 重新获取验证码
 				return;

+ 4 - 2
Web/src/views/login/component/mobile.vue

@@ -35,10 +35,11 @@
 import { reactive } from 'vue';
 import { ElMessage } from 'element-plus';
 import { verifyPhone } from '/@/utils/toolsValidate';
-
+import { useRoute } from "vue-router";
 import { getAPI } from '/@/utils/axios-utils';
 import { SysSmsApi, SysAuthApi } from '/@/api-services/api';
 
+const route = useRoute();
 const state = reactive({
 	ruleForm: {
 		phone: '',
@@ -81,7 +82,8 @@ const getSmsCode = async () => {
 
 // 登录
 const onSignIn = async () => {
-	var res = await getAPI(SysAuthApi).apiSysAuthLoginPhonePost(state.ruleForm);
+  const host = route.query.host ?? location.host;
+	var res = await getAPI(SysAuthApi).apiSysAuthLoginPhonePost({...state.ruleForm, host: host});
 	if (res.data.result?.accessToken == undefined) {
 		ElMessage.error('登录失败,请检查账号!');
 		return;

+ 4 - 4
Web/src/views/system/tenant/component/editTenant.vue

@@ -41,11 +41,11 @@
 							<el-input-number v-model="state.ruleForm.orderNo" placeholder="排序" class="w100" />
 						</el-form-item>
 					</el-col>
-					<!-- <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
-						<el-form-item label="主机">
-							<el-input v-model="ruleForm.host" placeholder="主机" clearable />
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+						<el-form-item label="绑定域名" :rules="[{ required: true, message: '绑定域名不能为空', trigger: 'blur' }]">
+							<el-input v-model="state.ruleForm.host" placeholder="例:gitee.com" clearable />
 						</el-form-item>
-					</el-col> -->
+					</el-col>
 					<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
 						<el-form-item label="数据库类型">
 							<el-select v-model="state.ruleForm.dbType" placeholder="数据库类型" clearable class="w100" :disabled="state.ruleForm.tenantType == 0 && state.ruleForm.tenantType != undefined">

+ 1 - 1
Web/src/views/system/tenant/index.vue

@@ -26,7 +26,7 @@
 				<el-table-column prop="name" label="租户名称" width="160" align="center" show-overflow-tooltip />
 				<el-table-column prop="adminAccount" label="租管账号" align="center" width="120" show-overflow-tooltip />
 				<el-table-column prop="phone" label="电话" width="120" align="center" show-overflow-tooltip />
-				<!-- <el-table-column prop="host" label="主机" show-overflow-tooltip /> -->
+				<el-table-column prop="host" label="域名" width="150" show-overflow-tooltip />
 				<!-- <el-table-column prop="email" label="邮箱" show-overflow-tooltip /> -->
 				<el-table-column prop="tenantType" label="租户类型" width="100" align="center" show-overflow-tooltip>
 					<template #default="scope">