From 387fde67cc81c89df816810783ecb91d9508e0c0 Mon Sep 17 00:00:00 2001 From: simiyu Date: Thu, 31 Oct 2024 10:03:22 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E4=B8=8A=E5=8A=A0=E5=85=A5=E8=A3=85=E9=85=8D=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E6=98=B5=E7=A7=B0=EF=BC=8C=E5=8F=AF=E4=BB=A5=E5=9C=A8?= =?UTF-8?q?=E9=9C=80=E8=A6=81=E8=BF=94=E5=9B=9E=E5=88=9B=E5=BB=BA=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E7=94=A8=E6=88=B7=E5=90=8D=E7=AD=89=E5=9C=BA=E6=99=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Helper/AssemblyDataHelper.cs | 83 +++++++++++++++++++ .../IBackUser.cs | 16 ++++ .../IServices/IUserService.cs | 16 ++++ .../Services/System/UserService.cs | 51 ++++++++++++ 4 files changed, 166 insertions(+) create mode 100644 Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/AssemblyDataHelper.cs create mode 100644 Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IBackUser.cs diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/AssemblyDataHelper.cs b/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/AssemblyDataHelper.cs new file mode 100644 index 00000000..bab823e9 --- /dev/null +++ b/Yi.Abp.Net8/framework/Yi.Framework.Core/Helper/AssemblyDataHelper.cs @@ -0,0 +1,83 @@ +using System.Collections.Specialized; + +namespace Yi.Framework.Core.Helper; + +/// +/// 数据装配帮助类 +/// +public static class AssemblyDataHelper +{ + /// + /// 装配数据 + /// + /// 数据 + /// 装配键值,键为原始数据列,值为目标列 + /// 装配的原始字典 + /// + public static async Task AssemblyData(List dataList, NameValueCollection keyValues, + Func, Task>> dataDicFunc) + { + HashSet idList = []; + var t = typeof(T); + foreach (var data in dataList) + { + foreach (var m in keyValues.AllKeys) + { + var p = t.GetProperty(m); + if (p != null) + { + var v = p.GetValue(data); + if (v is Guid guid) + { + idList.Add(guid); + } + + continue; + } + + var f = t.GetField(m); + if (f != null) + { + var v = f.GetValue(data); + if (v is Guid g) + { + idList.Add(g); + } + } + } + } + + var userDic = await dataDicFunc.Invoke(idList); + foreach (var data in dataList) + { + foreach (var m in keyValues.AllKeys) + { + var p = t.GetProperty(m); + if (p != null) + { + var v = p.GetValue(data); + if (v is Guid guid) + { + var k = t.GetProperty(keyValues[m]); + var val = userDic[guid]; + k.SetValue(data, val ?? v); + } + + continue; + } + + var f = t.GetField(m); + if (f != null) + { + var v = f.GetValue(data); + if (v is Guid guid1) + { + var k = t.GetField(keyValues[m]); + var value = userDic[guid1]; + k.SetValue(data, value ?? v); + } + } + } + } + } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IBackUser.cs b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IBackUser.cs new file mode 100644 index 00000000..a5d04497 --- /dev/null +++ b/Yi.Abp.Net8/framework/Yi.Framework.Ddd.Application.Contracts/IBackUser.cs @@ -0,0 +1,16 @@ +using Volo.Abp.Auditing; + +namespace Yi.Framework.Ddd.Application.Contracts; + +public interface IBackUser : IAuditedObject +{ + /// + /// 创建的用户名 + /// + public string CreateUserNikeName { get; set; } + + /// + /// 更新的用户名 + /// + public string UpdateUserNikeName { get; set; } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/IServices/IUserService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/IServices/IUserService.cs index 343765e4..88691bec 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/IServices/IUserService.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/IServices/IUserService.cs @@ -1,3 +1,4 @@ +using System.Collections.Specialized; using Yi.Framework.Ddd.Application.Contracts; using Yi.Framework.Rbac.Application.Contracts.Dtos.User; @@ -8,5 +9,20 @@ namespace Yi.Framework.Rbac.Application.Contracts.IServices /// public interface IUserService : IYiCrudAppService { + /// + /// 装配返回数据中的创建用户和修改用户 + /// + /// + /// 返回数据列表 + public Task AssemblyBackUser(List dataList) where T : class, IBackUser; + + /// + /// 装配用户,用来处理没有实现IBackUser接口,但需要返回用户信息 + /// 例如 AuditUserId列 对应 AuditUserNikeName这种 + /// + /// + /// + /// key为原始id列,value为填充列 + public Task AssemblyBackUser(List dataList, NameValueCollection keyValues) where T : class; } } diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/System/UserService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/System/UserService.cs index 70597f3b..e3b5308e 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/System/UserService.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/System/UserService.cs @@ -1,3 +1,4 @@ +using System.Collections.Specialized; using Microsoft.AspNetCore.Mvc; using SqlSugar; using TencentCloud.Tcr.V20190924.Models; @@ -8,7 +9,9 @@ using Volo.Abp.EventBus.Local; using Volo.Abp.Users; using Yi.Framework.Bbs.Domain.Shared.Enums; using Yi.Framework.Bbs.Domain.Shared.Etos; +using Yi.Framework.Core.Helper; using Yi.Framework.Ddd.Application; +using Yi.Framework.Ddd.Application.Contracts; using Yi.Framework.Rbac.Application.Contracts.Dtos.User; using Yi.Framework.Rbac.Application.Contracts.IServices; using Yi.Framework.Rbac.Domain.Authorization; @@ -237,5 +240,53 @@ namespace Yi.Framework.Rbac.Application.Services.System { return base.PostImportExcelAsync(input); } + + + [RemoteService(false)] + public async Task AssemblyBackUser(List dataList) where T : class, IBackUser + { + HashSet useridList = []; + foreach (var data in dataList) + { + if (data.CreatorId != null) useridList.Add(data.CreatorId.Value); + if (data.LastModifierId != null) useridList.Add(data.LastModifierId.Value); + } + + var userDic = await GetByNameKeyByIdListAsync(useridList); + foreach (var data in dataList) + { + if (data.CreatorId != null) + { + data.CreateUserNikeName = + userDic.ContainsKey(data.CreatorId.Value) ? userDic[data.CreatorId.Value] : ""; + } + + if (data.LastModifierId != null) + { + data.UpdateUserNikeName = userDic.ContainsKey(data.LastModifierId.Value) + ? userDic[data.LastModifierId.Value] + : ""; + } + } + } + + [RemoteService(false)] + public async Task AssemblyBackUser(List dataList, NameValueCollection keyValues) where T : class + { + await AssemblyDataHelper.AssemblyData(dataList, keyValues, GetByNameKeyByIdListAsync); + } + + /// + /// 用id查询用户,装备配为字典,键为id,值为Nike + /// + /// guid列表 + /// + private async Task> GetByNameKeyByIdListAsync(IEnumerable idList) + { + var users = await _repository.GetListAsync(u => idList.Contains(u.Id)); + Dictionary userDic = new(); + users.ForEach(x => userDic.Add(x.Id, x.Nick)); + return userDic; + } } } \ No newline at end of file -- Gitee From a5e12e2c50f51a31bbf8737346c517ec3be32f9d Mon Sep 17 00:00:00 2001 From: simiyu Date: Thu, 21 Nov 2024 17:45:31 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:pure-admin=20=E5=8A=A0=E5=85=A5?= =?UTF-8?q?=E5=A4=9A=E7=A7=9F=E6=88=B7=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Yi.Pure.Vue3/eslint.config.js | 340 +++++++++--------- Yi.Pure.Vue3/src/api/account.ts | 13 + Yi.Pure.Vue3/src/store/modules/user.ts | 10 +- Yi.Pure.Vue3/src/store/types.ts | 1 + Yi.Pure.Vue3/src/utils/auth.ts | 23 ++ Yi.Pure.Vue3/src/views/login/index.vue | 304 +++++++++------- .../src/views/permission/page/index.vue | 44 +-- 7 files changed, 404 insertions(+), 331 deletions(-) diff --git a/Yi.Pure.Vue3/eslint.config.js b/Yi.Pure.Vue3/eslint.config.js index b4d48fbc..844b8bd6 100644 --- a/Yi.Pure.Vue3/eslint.config.js +++ b/Yi.Pure.Vue3/eslint.config.js @@ -8,174 +8,174 @@ import * as parserTypeScript from "@typescript-eslint/parser"; import pluginTypeScript from "@typescript-eslint/eslint-plugin"; export default defineFlatConfig([ - { - ...js.configs.recommended, - ignores: [ - "**/.*", - "dist/*", - "*.d.ts", - "public/*", - "src/assets/**", - "src/**/iconfont/**" - ], - languageOptions: { - globals: { - // index.d.ts - RefType: "readonly", - EmitType: "readonly", - TargetContext: "readonly", - ComponentRef: "readonly", - ElRef: "readonly", - ForDataType: "readonly", - AnyFunction: "readonly", - PropType: "readonly", - Writable: "readonly", - Nullable: "readonly", - NonNullable: "readonly", - Recordable: "readonly", - ReadonlyRecordable: "readonly", - Indexable: "readonly", - DeepPartial: "readonly", - Without: "readonly", - Exclusive: "readonly", - TimeoutHandle: "readonly", - IntervalHandle: "readonly", - Effect: "readonly", - ChangeEvent: "readonly", - WheelEvent: "readonly", - ImportMetaEnv: "readonly", - Fn: "readonly", - PromiseFn: "readonly", - ComponentElRef: "readonly", - parseInt: "readonly", - parseFloat: "readonly" - } - }, - plugins: { - prettier: pluginPrettier - }, - rules: { - ...configPrettier.rules, - ...pluginPrettier.configs.recommended.rules, - "no-debugger": "off", - "no-unused-vars": [ - "error", - { - argsIgnorePattern: "^_", - varsIgnorePattern: "^_" - } - ], - "prettier/prettier": [ - "error", - { - endOfLine: "auto" - } - ] - } - }, - { - files: ["**/*.?([cm])ts", "**/*.?([cm])tsx"], - languageOptions: { - parser: parserTypeScript, - parserOptions: { - sourceType: "module" - } - }, - plugins: { - "@typescript-eslint": pluginTypeScript - }, - rules: { - ...pluginTypeScript.configs.strict.rules, - "@typescript-eslint/ban-types": "off", - "@typescript-eslint/no-redeclare": "error", - "@typescript-eslint/ban-ts-comment": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/prefer-as-const": "warn", - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-import-type-side-effects": "error", - "@typescript-eslint/explicit-module-boundary-types": "off", - "@typescript-eslint/consistent-type-imports": [ - "error", - { disallowTypeAnnotations: false, fixStyle: "inline-type-imports" } - ], - "@typescript-eslint/prefer-literal-enum-member": [ - "error", - { allowBitwiseExpressions: true } - ], - "@typescript-eslint/no-unused-vars": [ - "error", - { - argsIgnorePattern: "^_", - varsIgnorePattern: "^_" - } - ] - } - }, - { - files: ["**/*.d.ts"], - rules: { - "eslint-comments/no-unlimited-disable": "off", - "import/no-duplicates": "off", - "unused-imports/no-unused-vars": "off" - } - }, - { - files: ["**/*.?([cm])js"], - rules: { - "@typescript-eslint/no-require-imports": "off", - "@typescript-eslint/no-var-requires": "off" - } - }, - { - files: ["**/*.vue"], - languageOptions: { - globals: { - $: "readonly", - $$: "readonly", - $computed: "readonly", - $customRef: "readonly", - $ref: "readonly", - $shallowRef: "readonly", - $toRef: "readonly" - }, - parser: parserVue, - parserOptions: { - ecmaFeatures: { - jsx: true - }, - extraFileExtensions: [".vue"], - parser: "@typescript-eslint/parser", - sourceType: "module" - } - }, - plugins: { - vue: pluginVue - }, - processor: pluginVue.processors[".vue"], - rules: { - ...pluginVue.configs.base.rules, - ...pluginVue.configs["vue3-essential"].rules, - ...pluginVue.configs["vue3-recommended"].rules, - "no-undef": "off", - "no-unused-vars": "off", - "vue/no-v-html": "off", - "vue/require-default-prop": "off", - "vue/require-explicit-emits": "off", - "vue/multi-word-component-names": "off", - "vue/no-setup-props-reactivity-loss": "off", - "vue/html-self-closing": [ - "error", - { - html: { - void: "always", - normal: "always", - component: "always" - }, - svg: "always", - math: "always" - } - ] - } - } + // { + // ...js.configs.recommended, + // ignores: [ + // "**/.*", + // "dist/*", + // "*.d.ts", + // "public/*", + // "src/assets/**", + // "src/**/iconfont/**" + // ], + // languageOptions: { + // globals: { + // // index.d.ts + // RefType: "readonly", + // EmitType: "readonly", + // TargetContext: "readonly", + // ComponentRef: "readonly", + // ElRef: "readonly", + // ForDataType: "readonly", + // AnyFunction: "readonly", + // PropType: "readonly", + // Writable: "readonly", + // Nullable: "readonly", + // NonNullable: "readonly", + // Recordable: "readonly", + // ReadonlyRecordable: "readonly", + // Indexable: "readonly", + // DeepPartial: "readonly", + // Without: "readonly", + // Exclusive: "readonly", + // TimeoutHandle: "readonly", + // IntervalHandle: "readonly", + // Effect: "readonly", + // ChangeEvent: "readonly", + // WheelEvent: "readonly", + // ImportMetaEnv: "readonly", + // Fn: "readonly", + // PromiseFn: "readonly", + // ComponentElRef: "readonly", + // parseInt: "readonly", + // parseFloat: "readonly" + // } + // }, + // plugins: { + // prettier: pluginPrettier + // }, + // rules: { + // ...configPrettier.rules, + // ...pluginPrettier.configs.recommended.rules, + // "no-debugger": "off", + // "no-unused-vars": [ + // "error", + // { + // argsIgnorePattern: "^_", + // varsIgnorePattern: "^_" + // } + // ], + // "prettier/prettier": [ + // "error", + // { + // endOfLine: "auto" + // } + // ] + // } + // }, + // { + // files: ["**/*.?([cm])ts", "**/*.?([cm])tsx"], + // languageOptions: { + // parser: parserTypeScript, + // parserOptions: { + // sourceType: "module" + // } + // }, + // plugins: { + // "@typescript-eslint": pluginTypeScript + // }, + // rules: { + // ...pluginTypeScript.configs.strict.rules, + // "@typescript-eslint/ban-types": "off", + // "@typescript-eslint/no-redeclare": "error", + // "@typescript-eslint/ban-ts-comment": "off", + // "@typescript-eslint/no-explicit-any": "off", + // "@typescript-eslint/prefer-as-const": "warn", + // "@typescript-eslint/no-empty-function": "off", + // "@typescript-eslint/no-non-null-assertion": "off", + // "@typescript-eslint/no-import-type-side-effects": "error", + // "@typescript-eslint/explicit-module-boundary-types": "off", + // "@typescript-eslint/consistent-type-imports": [ + // "error", + // { disallowTypeAnnotations: false, fixStyle: "inline-type-imports" } + // ], + // "@typescript-eslint/prefer-literal-enum-member": [ + // "error", + // { allowBitwiseExpressions: true } + // ], + // "@typescript-eslint/no-unused-vars": [ + // "error", + // { + // argsIgnorePattern: "^_", + // varsIgnorePattern: "^_" + // } + // ] + // } + // }, + // { + // files: ["**/*.d.ts"], + // rules: { + // "eslint-comments/no-unlimited-disable": "off", + // "import/no-duplicates": "off", + // "unused-imports/no-unused-vars": "off" + // } + // }, + // { + // files: ["**/*.?([cm])js"], + // rules: { + // "@typescript-eslint/no-require-imports": "off", + // "@typescript-eslint/no-var-requires": "off" + // } + // }, + // { + // files: ["**/*.vue"], + // languageOptions: { + // globals: { + // $: "readonly", + // $$: "readonly", + // $computed: "readonly", + // $customRef: "readonly", + // $ref: "readonly", + // $shallowRef: "readonly", + // $toRef: "readonly" + // }, + // parser: parserVue, + // parserOptions: { + // ecmaFeatures: { + // jsx: true + // }, + // extraFileExtensions: [".vue"], + // parser: "@typescript-eslint/parser", + // sourceType: "module" + // } + // }, + // plugins: { + // vue: pluginVue + // }, + // processor: pluginVue.processors[".vue"], + // rules: { + // ...pluginVue.configs.base.rules, + // ...pluginVue.configs["vue3-essential"].rules, + // ...pluginVue.configs["vue3-recommended"].rules, + // "no-undef": "off", + // "no-unused-vars": "off", + // "vue/no-v-html": "off", + // "vue/require-default-prop": "off", + // "vue/require-explicit-emits": "off", + // "vue/multi-word-component-names": "off", + // "vue/no-setup-props-reactivity-loss": "off", + // "vue/html-self-closing": [ + // "error", + // { + // html: { + // void: "always", + // normal: "always", + // component: "always" + // }, + // svg: "always", + // math: "always" + // } + // ] + // } + // } ]); diff --git a/Yi.Pure.Vue3/src/api/account.ts b/Yi.Pure.Vue3/src/api/account.ts index c3afcf62..4fe8abbb 100644 --- a/Yi.Pure.Vue3/src/api/account.ts +++ b/Yi.Pure.Vue3/src/api/account.ts @@ -18,6 +18,14 @@ export type LoginResult = { }; }; +export type TenantResult = { + status: number; + data: Array<{ + id: string; + name: string; + }>; +}; + export type UserResult = { status: number; data: { @@ -69,6 +77,11 @@ export const getCodeImg = () => { return http.request("get", "/account/captcha-image"); }; +/** 获取租户信息 */ +export const getTenant = () => { + return http.request("get", "/tenant/select"); +} + /** 刷新`token` */ export const refreshTokenApi = (data?: object) => { return http.request("post", "/refresh-token", { data }); diff --git a/Yi.Pure.Vue3/src/store/modules/user.ts b/Yi.Pure.Vue3/src/store/modules/user.ts index e5f10379..1ba17c1e 100644 --- a/Yi.Pure.Vue3/src/store/modules/user.ts +++ b/Yi.Pure.Vue3/src/store/modules/user.ts @@ -15,7 +15,7 @@ import { refreshTokenApi } from "@/api/account"; import { useMultiTagsStoreHook } from "./multiTags"; -import { type DataInfo, setToken, removeToken, userKey } from "@/utils/auth"; +import {type DataInfo, setToken, removeToken, userKey, setTenantId, getTenantId} from "@/utils/auth"; export const useUserStore = defineStore({ id: "pure-user", @@ -38,7 +38,9 @@ export const useUserStore = defineStore({ // 是否勾选了登录页的免登录 isRemembered: false, // 登录页的免登录存储几天,默认7天 - loginDay: 7 + loginDay: 7, + // 租户id + tenantId: getTenantId() }), actions: { /** 存储头像 */ @@ -78,8 +80,9 @@ export const useUserStore = defineStore({ this.loginDay = Number(value); }, /** 登入 */ - async loginByUsername(data) { + async loginByUsername(data:any,tenantId:string) { return new Promise((resolve, reject) => { + setTenantId(tenantId); getLogin(data) .then(data => { if (data.status == 200) { @@ -100,6 +103,7 @@ export const useUserStore = defineStore({ } }) .catch(error => { + this.tenantId=null; reject(error); }); }); diff --git a/Yi.Pure.Vue3/src/store/types.ts b/Yi.Pure.Vue3/src/store/types.ts index d6503d9c..04b9892f 100644 --- a/Yi.Pure.Vue3/src/store/types.ts +++ b/Yi.Pure.Vue3/src/store/types.ts @@ -47,4 +47,5 @@ export type userType = { currentPage?: number; isRemembered?: boolean; loginDay?: number; + tenantId?:string; }; diff --git a/Yi.Pure.Vue3/src/utils/auth.ts b/Yi.Pure.Vue3/src/utils/auth.ts index a8a64a3e..2d036936 100644 --- a/Yi.Pure.Vue3/src/utils/auth.ts +++ b/Yi.Pure.Vue3/src/utils/auth.ts @@ -23,6 +23,7 @@ export interface DataInfo { export const userKey = "user-info"; export const TokenKey = "authorized-token"; +export const TenantIdKey = 'Tenant-Id' /** * 通过`multiple-tabs`是否在`cookie`中,判断用户是否已经登录系统, * 从而支持多标签页打开已经登录的系统后无需再登录。 @@ -138,3 +139,25 @@ export const hasPerms = (value: string | Array): boolean => { : isIncludeAllChildren(value, permissions); return isAuths ? true : false; }; + +/** + * 获取租户id + */ +export function getTenantId() { + return Cookies.get(TenantIdKey) +} + +/** + * 设置租户id + * @param tenantId 租户id + */ +export function setTenantId(tenantId: string) { + return Cookies.set(TenantIdKey, tenantId) +} + +/** + * 删除租户id + */ +export function removeTenantId() { + return Cookies.remove(TenantIdKey) +} diff --git a/Yi.Pure.Vue3/src/views/login/index.vue b/Yi.Pure.Vue3/src/views/login/index.vue index 7adcc70a..6b6cdb52 100644 --- a/Yi.Pure.Vue3/src/views/login/index.vue +++ b/Yi.Pure.Vue3/src/views/login/index.vue @@ -1,29 +1,29 @@