日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > vue >内容正文

vue

Abp Vnext Vue3 的版本实现

發布時間:2023/12/4 vue 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Abp Vnext Vue3 的版本实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Abp Vnext Pro?的 Vue3 實現版本 開箱即用的中后臺前端/設計解決方案

開始

  • Github地址

  • 文檔地址

  • 演示地址

系統功能

  • [x] 用戶管理

  • [x] 角色管理

  • [x] 審計日志

  • [x] 后臺任務

  • [x] 集成事件

  • [x] IdentityServer4

    • [x] 客戶端管理

    • [x] Api 資源管理

    • [x] ApiScope 管理

    • [x] Identity 資源管理

  • [x] SinglaR 消息通知

  • [x] 多語言

  • [x] FreeSql

  • [x] 數據字典(UI 暫時沒有)

  • [x] 容器化部署

  • [x] 單元測試

  • [x] ES 日志

  • [x] Setting 管理

  • [x] 多租戶

  • [ ] 組織機構

項目結構

后端

. ├── Directory.Build.props nuget 版本控制 ├── frameworks # 公共模塊 │ ├── CAP # dotnetcore.cap │ └── Extensions # 自定義擴展 ├── gateways # 網關 ├── modules # 模塊 │ ├── DataDictionaryManagement # 數據字典 │ └── NotificationManagement # 通知服務 ├── services # 公共靜態資源目錄 │ ├── host # 啟動模塊 │ ├── CompanyName.ProjectName.HttpApi.Host # admin ui host │ └── CompanyName.ProjectName.IdentityServer # IdentityServer host │ ├── src # 源碼 │ └── CompanyName.ProjectName.DbMigrator # 遷移控制臺程序 │ └── test # 單元測試

前端

. ├── _nginx # docker 打包 ├── build # 打包腳本相關 │ ├── config # 配置文件 │ ├── generate # 生成器 │ ├── script # 腳本 │ └── vite # vite配置 ├── mock # mock文件夾 ├── public # 公共靜態資源目錄 ├── src # 主目錄 │ ├── api # 接口文件 │ ├── assets # 資源文件 │ │ ├── icons # icon sprite 圖標文件夾 │ │ ├── images # 項目存放圖片的文件夾 │ │ └── svg # 項目存放svg圖片的文件夾 │ ├── components # 公共組件 │ ├── design # 樣式文件 │ ├── directives # 指令 │ ├── enums # 枚舉/常量 │ ├── hooks # hook │ │ ├── component # 組件相關hook │ │ ├── core # 基礎hook │ │ ├── event # 事件相關hook │ │ ├── setting # 配置相關hook │ │ └── web # web相關hook │ ├── layouts # 布局文件 │ │ ├── default # 默認布局 │ │ ├── iframe # iframe布局 │ │ └── page # 頁面布局 │ ├── locales # 多語言 │ ├── logics # 邏輯 │ ├── main.ts # 主入口 │ ├── router # 路由配置 │ ├── services # Nswag生成的代理 │ │ ├── ServiceProxies.ts # Nswag生成的代理 │ │ ├── ServiceProxyBase.ts # Nswag生成的代理攔截器 │ ├── settings # 項目配置 │ │ ├── componentSetting.ts # 組件配置 │ │ ├── designSetting.ts # 樣式配置 │ │ ├── encryptionSetting.ts # 加密配置 │ │ ├── localeSetting.ts # 多語言配置 │ │ ├── projectSetting.ts # 項目配置 │ │ └── siteSetting.ts # 站點配置 │ ├── store # 數據倉庫 │ ├── utils # 工具類 │ └── views # 頁面 ├── test # 測試 │ └── server # 測試用到的服務 │ ├── api # 測試服務器 │ ├── upload # 測試上傳服務器 │ └── websocket # 測試ws服務器 ├── types # 類型文件 ├── vite.config.ts # vite配置文件 └── windi.config.ts # windcss配置文件

運行項目前提

  • Mysql

    docker run --name mymysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=1q2w3E* -d mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
  • Redis

    docker run --name myredis -p 6379:6379 -d redis:latest redis-server
  • RabbitMq 非必須

  • appsetting.development.json-> CAP:Enabled 設置為 false

    docker run -d --name myrabbitmq -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin -p 15672:15672 -p 5672:5672 rabbitmq:management
  • ELK 非必須

  • appsetting.development.json-> LogToElasticSearch:Enabled 設置為 false

  • 安裝 Node.js, Npm Or Yarn

獲取項目

  • 直接 clone 項目

git clone https://github.com/WangJunZzz/abp-vnext-pro.git

OR

  • 下載代碼生成器

git clone https://github.com/WangJunZzz/abp-vnext-pro-gui.git
  • 下載代碼生成生成器之后,輸入自己想要的項目名稱生成代碼即可

啟動

  • 修改 HttpApi.Host-> appsettings.development.json 的數據庫連接字符串,Redis, RabbitMq,Es 地址即可(如果沒有 es 也可以運行,只是前端 es 日志頁面無法使用而已,不影響后端項目啟動)

  • 修改 IdentityServer-> appsettings.development.json 數據庫連接字符串

  • 修改 DbMigrator-> appsettings.json 數據庫連接字符串

  • 運行 DbMigrator 生成數據庫

  • 啟動 HttpApi.Host 和 IdentityServer

  • 前端 yarn 之后,執行 npm run dev 啟動

配置說明

  • HttpApi.Host-> appsettings.development.json

{// Serilog 日志配置,生成環境修改日志級別"Serilog": {"MinimumLevel": {"Default": "Information","Override": {"Microsoft": "Information","Volo.Abp": "Information","Hangfire": "Information","DotNetCore.CAP": "Information","Serilog.AspNetCore": "Information"}}},// 跨域設置"App": {"CorsOrigins": "https://*.ProjectName.com,http://localhost:4200,http://localhost:3100"},// 數據庫連接字符串,修改為你本地的mysql地址"ConnectionStrings": {"Default": "Data Source=localhost;Database=CompanyNameProjectNameDB;uid=root;pwd=1q2w3E*;charset=utf8mb4;Allow User Variables=true;AllowLoadLocalInfile=true"},// Redis緩存"Cache": {"Redis": {"ConnectionString": "localhost","Password": "mypassword","DatabaseId": 0}},// Jwt配置"Jwt": {"Audience": "CompanyNameProjectName",//客戶端標識"SecurityKey": "dzehzRz9a8asdfasfdadfasdfasdfafsdadfasbasdf=","Issuer": "CompanyNameProjectName",//簽發者"ExpirationTime": 24//過期時間 hour},// 使用了Dotnetcore.cap的rabbitmq,false的情況基于內存"Cap": {"Enabled": "false","RabbitMq": {"HostName": "localhost","UserName": "admin","Password": "admin"}},// es日志地址配置"LogToElasticSearch": {"Enabled": "true","ElasticSearch": {"Url": "http://es.cn","IndexFormat": "companyname.projectname.development","UserName": "elastic","Password": "aVVhjQ95RP7nbwNy","DashboardIndex": "companyname.projectname"}},// identityserver地址"HttpClient": {"Sts": {"Url": "http://localhost:44354"}},// Consul 服務發現和治理"Consul": {"Enabled": false,"Host": "http://localhost:8500","Service": "Project-Service"} }
  • IdentityServer-> appsettings.development.json

{"App": {"SelfUrl": "https://localhost:44354","ClientUrl": "http://localhost:4200","CorsOrigins": "https://*.ProjectName.com,http://localhost:4200,https://localhost:44307,https://localhost:44315","RedirectAllowedUrls": "http://localhost:4200,https://localhost:44307"},// mysql連接字符串"ConnectionStrings": {"Default": "Data Source=localhost;Database=CompanyNameProjectNameDB;uid=root;pwd=1q2w3E*;charset=utf8mb4;Allow User Variables=true;AllowLoadLocalInfile=true"},// Redis"Redis": {"Configuration": "localhost,password=mypassword"} }
  • DbMigrator-> appsettings.json

// 遷移數據庫"ConnectionStrings": {"Default": "Data Source=localhost;Database=CompanyNameProjectNameDB;uid=root;pwd=1q2w3E*;charset=utf8mb4;Allow User Variables=true;AllowLoadLocalInfile=true"}

前端

  • 前端采用 TypeScript,所有的類型動態生成?NSwag

  • 后端 api 統一使用 Post

  • 定義 api 格式

// 一定要打Tags,因為前端會根據這個生成代理類 // 建議參數都封裝為一個Input [SwaggerOperation(summary: "登錄", Tags = new[] {"Account"})] public Task<LoginOutput> LoginAsync(LoginInput input) {return _loginAppService.LoginAsync(input); }
  • 在前端目錄下配置代理的地址

    • nswag->nswag.json

"documentGenerator": {"fromDocument": {"url": "http://localhost:44315/swagger/v1/swagger.json", // 代理地址,只有生成的時候用,不區分環境}}
  • 如果接口參數或者返回值有改變,需要重新生成代理,執行:

npm run nswag
  • 前端多環境,.env.development 和.env.production

    • 接口地址配置 VITE_API_URL

    • IdentityServer 地址配置 VITE_AUTH_URL

  • 權限配置

  • 菜單權限

    • src/router/routes

      policy 字段匹配后端的權限名稱

    • 按鈕權限

      v-auth="'AbpIdentity.Users.Delete'"

健康檢查

模塊

用戶管理

  • 提供原始登錄和第三方登錄(IdentityServer4),默認用戶名密碼:admin 1q2w3*

角色管理

  • 權限定義(Application.Contracts 層)

  • Abp 會自動掃描繼承 PermissionDefinitionProvider

  • 文檔 Abp 官方

  • 在 Http.Api 的 Controller 打上 Authorize

設置管理

  • 集成Abp.SettingUi

消息通知

  • 消息類型,發送給指定人和廣播消息

  • 發送消息到前端,通過集成事件和 RabbitMq

  • 注入 NotificationManager 發送消息,

/// <summary> /// 發送普通文本消息 /// </summary> /// <returns></returns> /// <exception cref="NotificationManagementDomainException"></exception> public async Task<Notification> SendCommonTextAsync(string title, string content, List<Guid> receiveIds) {if (receiveIds is {Count: 0}){throw new NotificationManagementDomainException("消息接收人不能為空");var senderId = Guid.Empty;if (_currentUser?.Id != null){senderId = _currentUser.Id.Value;var entity = new Notification(GuidGenerator.Create(), title, content, MessageType.Text, senderId);foreach (var item in receiveIds){entity.AddNotificationSubscription(GuidGenerator.Create(), item);var notificationEto = ObjectMapper.Map<Notification, NotificationEto>(entity);// 發送集成事件entity.AddCreatedNotificationDistributedEvent(new CreatedNotificationDistributedEvent(notificationEto));return entity = await _notificationRepository.InsertAsync(entity); }
  • Handler 當前事件:NotificationCreatedDistributedEventHandler

/// <summary> /// 發送消息 /// </summary> public async Task SendMessageAsync(string title, string content, MessageType messageType, List<string> users) {switch (messageType){case MessageType.Text:await SendMessageToClientByUserIdAsync(new SendNotificationDto(title, content, messageType), users);break;case MessageType.BroadCast:await SendMessageToAllClientAsync(new SendNotificationDto(title, content, messageType));break;default:throw new UserFriendlyException("未知的消息類型");} }
  • 前端接受 SignalR 消息

// src/hooks/web/useSignalR.js import * as signalR from "@microsoft/signalr"; import { useMessage } from "/@/hooks/web/useMessage"; import { useUserStoreWithOut } from "/@/store/modules/user"; export function useSignalR() {/*** 開始連接SignalR*/function startConnect(): void {let connection = connectionsignalR();//接收普通文本消息connection.on("ReceiveTextMessageAsync", ReceiveTextMessageHandlerAsync);//接收廣播消息connection.on("ReceiveBroadCastMessageAsync", ReceiveBroadCastMessageHandlerAsync);//開始連接connection.start();}/*** 連接signalr*/function connectionsignalR(): signalR.HubConnection {const userStore = useUserStoreWithOut();const token = userStore.getToken;const url = (import.meta.env.VITE_WEBSOCKE_URL as string) + "/ws/signalr/notification";const connection = new signalR.HubConnectionBuilder().withUrl(url, {accessTokenFactory: () => token,skipNegotiation: true,transport: signalR.HttpTransportType.WebSockets,}).withAutomaticReconnect({nextRetryDelayInMilliseconds: (retryContext) => {//重連規則:重連次數<300:間隔1s;重試次數<3000:間隔3s;重試次數>3000:間隔30slet count = retryContext.previousRetryCount / 300;if (count < 1) {//重試次數<300,間隔1sreturn 1000;} else if (count < 10) {//重試次數>300:間隔5sreturn 1000 * 5;} //重試次數>3000:間隔30selse {return 1000 * 30;}},}).configureLogging(signalR.LogLevel.Debug).build();return connection;}/*** 接收文本消息* @param message 消息體*/function ReceiveTextMessageHandlerAsync(message: any) {console.log(message);const { notification } = useMessage();notification.open({message: message.title,description: message.content,});}/*** 接收廣播消息* @param message 消息體*/function ReceiveBroadCastMessageHandlerAsync(message: any) {const { notification } = useMessage();notification.open({message: message.title,description: message.content,});}return { startConnect }; }

審計日志

  • 參考 Abp 官方文檔即可

ES 日志

  • 在 appsetting.development.json 設置是否開啟

"LogToElasticSearch": {"Enabled": "false", // 如果為fasel,日志也會寫入到本地,安裝ELK,參考上面的docker-compose"ElasticSearch": {"Url": "http://es.cn","IndexFormat": "companyname.projectname.development","UserName": "elastic","Password": "aVVhjQ95RP7nbwNy","DashboardIndex": "companyname.projectname"}},

后臺任務

  • 定時任務

public override void OnPostApplicationInitialization(ApplicationInitializationContext context) {context.CreateRecurringJob();base.OnPostApplicationInitialization(context); }
  • 延遲任務:?官方文檔

集成事件

  • 集成?dotnetcore.CAP

  • 在 appsetting.development.json 設置是否開啟

"Cap": {"Enabled": "false", //如果為false 默認使用內存級別的隊列,否則請安裝rabbitmq"RabbitMq": {"HostName": "localhost","UserName": "admin","Password": "admin"}},private void ConfigurationCap(ServiceConfigurationContext context) {var configuration = context.Services.GetConfiguration();var enabled = configuration.GetValue<bool>("Cap:Enabled", false);if (enabled){context.AddAbpCap(capOptions =>{capOptions.UseEntityFramework<ProjectNameDbContext>();capOptions.UseRabbitMQ(option =>{option.HostName = configuration.GetValue<string>("Cap:RabbitMq:HostName");option.UserName = configuration.GetValue<string>("Cap:RabbitMq:UserName");option.Password = configuration.GetValue<string>("Cap:RabbitMq:Password");});var hostingEnvironment = context.Services.GetHostingEnvironment();bool auth = !hostingEnvironment.IsDevelopment();capOptions.UseDashboard(options => { options.UseAuth = auth; });});}else{context.AddAbpCap(capOptions =>{capOptions.UseInMemoryStorage();capOptions.UseInMemoryMessageQueue();var hostingEnvironment = context.Services.GetHostingEnvironment();bool auth = !hostingEnvironment.IsDevelopment();capOptions.UseDashboard(options => { options.UseAuth = auth; });});} }
  • 發布事件

    • 可參考通知模塊

// 發送集成事件 entity.AddCreatedNotificationDistributedEvent(new CreatedNotificationDistributedEvent(notificationEto));
  • 訂閱事件

    • 可參考通知模塊

/// <summary> /// 創建消息事件處理 /// </summary> public classCreatedNotificationDistributedEventHandler : IDistributedEventHandler<CreatedNotificationDistributedEvent>,ITransientDependency {private readonly INotificationAppService _hubAppService;public CreatedNotificationDistributedEventHandler(INotificationAppService hubAppService){_hubAppService = hubAppService;}public Task HandleEventAsync(CreatedNotificationDistributedEvent eventData){return _hubAppService.SendMessageAsync(eventData.NotificationEto.Title,eventData.NotificationEto.Content,eventData.NotificationEto.MessageType,eventData.NotificationEto.NotificationSubscriptions.Select(e => e.ReceiveId.ToString()).ToList());} }

身份認證中心

  • IdentityServer4

  • 可重寫登錄界面 UI

租戶管理

  • 提供租戶登錄和 IdentityServer4 租戶登錄方式

Ocelot 網關(可選)

  • 集成 Ocelot 和 Consul

部署

Docker 方式

HttpApi.Host

  • 發布 HttpApi.Host 到和 Dockerfile 同級目錄

    -- publish -- Dockerfile
  • Dockerfile

FROM mcr.microsoft.com/dotnet/aspnet:5.0# 創建目錄 RUN mkdir /appCOPY publish /app# 設置工作目錄 WORKDIR /app# 暴露80端口 EXPOSE 80# 設置環境變量 ENV ASPNETCORE_ENVIRONMENT=ProductionENTRYPOINT ["dotnet", "CompanyName.ProjectName.HttpApi.Host.dll"]
  • 生成 Docker 鏡像

docker build -t abp-vnext-pro-admin .
  • 運行容器

docker run -itd --name abp-vnext-pro-admin -p 8011:80 abp-vnext-pro-admin

IdentityServer.Host

  • 步驟同上

前端

  • 打包

npm run build
  • Dockerfile

FROM nginx:1.17.3-alpine as base EXPOSE 80 COPY /_nginx/nginx.conf /etc/nginx/nginx.conf COPY /_nginx/env.js /etc/nginx/env.js COPY /_nginx/default.conf /etc/nginx/conf.d/default.conf COPY /dist/ /usr/share/nginx/html CMD ["nginx", "-g", "daemon off;"]
  • 生成 Docker 鏡像

docker build -t abp-vnext-pro-ui .
  • 運行容器

docker run -itd --name abp-vnext-pro-ui -p 8012:80 abp-vnext-pro-ui

常見問題

VS 編譯項目字符串超過 256 個字符

  • 把項目拷貝到磁盤根目錄 OR 使用 Rider 開發

Hangfire 和 Cap 界面加載不出來

  • 這 2 個界面開啟了權限認證,由于前端路由的異步加載,導致路由在渲染的時候 access_token 沒有加載出來,Ctrl+F5 刷新即可

總結

以上是生活随笔為你收集整理的Abp Vnext Vue3 的版本实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。