Compare commits

..

13 Commits

114 changed files with 7511 additions and 1604 deletions

View File

@ -1,10 +1,9 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
// This code was generated by a tool.
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
@ -14,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("IMTest")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+2ecaa28091b41de707825db3628d380b62fa727f")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+f7772a9c5a6c1a00fd55a667dd7644fe3debe9d7")]
[assembly: System.Reflection.AssemblyProductAttribute("IMTest")]
[assembly: System.Reflection.AssemblyTitleAttribute("IMTest")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

View File

@ -1 +1 @@
ed4980dfc7aff253176b260ed9015f9a80b52e92cbf3095eff3ed06865ea6e0d
c6e01bb72d85599aa024524b725bc3ddb7e3c1cc42c37b8b46561df20748cbf5

View File

@ -1,40 +1,33 @@
{
"format": 1,
"restore": {
"C:\\Users\\nanxun\\Documents\\IM\\backend\\IMTest\\IMTest.csproj": {}
"/home/nanxun/Documents/Project/IM/backend/IMTest/IMTest.csproj": {}
},
"projects": {
"C:\\Users\\nanxun\\Documents\\IM\\backend\\IMTest\\IMTest.csproj": {
"/home/nanxun/Documents/Project/IM/backend/IMTest/IMTest.csproj": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IMTest\\IMTest.csproj",
"projectUniqueName": "/home/nanxun/Documents/Project/IM/backend/IMTest/IMTest.csproj",
"projectName": "IMTest",
"projectPath": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IMTest\\IMTest.csproj",
"packagesPath": "C:\\Users\\nanxun\\.nuget\\packages\\",
"outputPath": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IMTest\\obj\\",
"projectPath": "/home/nanxun/Documents/Project/IM/backend/IMTest/IMTest.csproj",
"packagesPath": "/home/nanxun/.nuget/packages/",
"outputPath": "/home/nanxun/Documents/Project/IM/backend/IMTest/obj/",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
],
"configFilePaths": [
"C:\\Users\\nanxun\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
"/home/nanxun/.nuget/NuGet/NuGet.Config"
],
"originalTargetFrameworks": [
"net8.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"C:\\Program Files\\dotnet\\library-packs": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net8.0": {
"targetAlias": "net8.0",
"projectReferences": {
"C:\\Users\\nanxun\\Documents\\IM\\backend\\IM_API\\IM_API.csproj": {
"projectPath": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IM_API\\IM_API.csproj"
"/home/nanxun/Documents/Project/IM/backend/IM_API/IM_API.csproj": {
"projectPath": "/home/nanxun/Documents/Project/IM/backend/IM_API/IM_API.csproj"
}
}
}
@ -49,7 +42,7 @@
"auditLevel": "low",
"auditMode": "direct"
},
"SdkAnalysisLevel": "9.0.300"
"SdkAnalysisLevel": "10.0.200"
},
"frameworks": {
"net8.0": {
@ -96,33 +89,26 @@
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.311/PortableRuntimeIdentifierGraph.json"
"runtimeIdentifierGraphPath": "/home/nanxun/dotnet/sdk/10.0.201/PortableRuntimeIdentifierGraph.json"
}
}
},
"C:\\Users\\nanxun\\Documents\\IM\\backend\\IM_API\\IM_API.csproj": {
"/home/nanxun/Documents/Project/IM/backend/IM_API/IM_API.csproj": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IM_API\\IM_API.csproj",
"projectUniqueName": "/home/nanxun/Documents/Project/IM/backend/IM_API/IM_API.csproj",
"projectName": "IM_API",
"projectPath": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IM_API\\IM_API.csproj",
"packagesPath": "C:\\Users\\nanxun\\.nuget\\packages\\",
"outputPath": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IM_API\\obj\\",
"projectPath": "/home/nanxun/Documents/Project/IM/backend/IM_API/IM_API.csproj",
"packagesPath": "/home/nanxun/.nuget/packages/",
"outputPath": "/home/nanxun/Documents/Project/IM/backend/IM_API/obj/",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
],
"configFilePaths": [
"C:\\Users\\nanxun\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
"/home/nanxun/.nuget/NuGet/NuGet.Config"
],
"originalTargetFrameworks": [
"net8.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"C:\\Program Files\\dotnet\\library-packs": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
@ -141,7 +127,7 @@
"auditLevel": "low",
"auditMode": "direct"
},
"SdkAnalysisLevel": "9.0.300"
"SdkAnalysisLevel": "10.0.200"
},
"frameworks": {
"net8.0": {
@ -235,7 +221,7 @@
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.311/PortableRuntimeIdentifierGraph.json"
"runtimeIdentifierGraphPath": "/home/nanxun/dotnet/sdk/10.0.201/PortableRuntimeIdentifierGraph.json"
}
}
}

View File

@ -4,26 +4,25 @@
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">C:\Users\nanxun\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages</NuGetPackageFolders>
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">/home/nanxun/.nuget/packages/</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">/home/nanxun/.nuget/packages/</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.14.2</NuGetToolVersion>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">7.0.0</NuGetToolVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="C:\Users\nanxun\.nuget\packages\" />
<SourceRoot Include="C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages\" />
<SourceRoot Include="/home/nanxun/.nuget/packages/" />
</ItemGroup>
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)xunit.runner.visualstudio\2.5.3\build\net6.0\xunit.runner.visualstudio.props" Condition="Exists('$(NuGetPackageRoot)xunit.runner.visualstudio\2.5.3\build\net6.0\xunit.runner.visualstudio.props')" />
<Import Project="$(NuGetPackageRoot)xunit.core\2.5.3\build\xunit.core.props" Condition="Exists('$(NuGetPackageRoot)xunit.core\2.5.3\build\xunit.core.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore\8.0.22\buildTransitive\net8.0\Microsoft.EntityFrameworkCore.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore\8.0.22\buildTransitive\net8.0\Microsoft.EntityFrameworkCore.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.testplatform.testhost\17.8.0\build\netcoreapp3.1\Microsoft.TestPlatform.TestHost.props" Condition="Exists('$(NuGetPackageRoot)microsoft.testplatform.testhost\17.8.0\build\netcoreapp3.1\Microsoft.TestPlatform.TestHost.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.codecoverage\17.8.0\build\netstandard2.0\Microsoft.CodeCoverage.props" Condition="Exists('$(NuGetPackageRoot)microsoft.codecoverage\17.8.0\build\netstandard2.0\Microsoft.CodeCoverage.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.net.test.sdk\17.8.0\build\netcoreapp3.1\Microsoft.NET.Test.Sdk.props" Condition="Exists('$(NuGetPackageRoot)microsoft.net.test.sdk\17.8.0\build\netcoreapp3.1\Microsoft.NET.Test.Sdk.props')" />
<Import Project="$(NuGetPackageRoot)xunit.runner.visualstudio/2.5.3/build/net6.0/xunit.runner.visualstudio.props" Condition="Exists('$(NuGetPackageRoot)xunit.runner.visualstudio/2.5.3/build/net6.0/xunit.runner.visualstudio.props')" />
<Import Project="$(NuGetPackageRoot)xunit.core/2.5.3/build/xunit.core.props" Condition="Exists('$(NuGetPackageRoot)xunit.core/2.5.3/build/xunit.core.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore/8.0.22/buildTransitive/net8.0/Microsoft.EntityFrameworkCore.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore/8.0.22/buildTransitive/net8.0/Microsoft.EntityFrameworkCore.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.testplatform.testhost/17.8.0/build/netcoreapp3.1/Microsoft.TestPlatform.TestHost.props" Condition="Exists('$(NuGetPackageRoot)microsoft.testplatform.testhost/17.8.0/build/netcoreapp3.1/Microsoft.TestPlatform.TestHost.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.codecoverage/17.8.0/build/netstandard2.0/Microsoft.CodeCoverage.props" Condition="Exists('$(NuGetPackageRoot)microsoft.codecoverage/17.8.0/build/netstandard2.0/Microsoft.CodeCoverage.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.net.test.sdk/17.8.0/build/netcoreapp3.1/Microsoft.NET.Test.Sdk.props" Condition="Exists('$(NuGetPackageRoot)microsoft.net.test.sdk/17.8.0/build/netcoreapp3.1/Microsoft.NET.Test.Sdk.props')" />
</ImportGroup>
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Pkgxunit_analyzers Condition=" '$(Pkgxunit_analyzers)' == '' ">C:\Users\nanxun\.nuget\packages\xunit.analyzers\1.4.0</Pkgxunit_analyzers>
<PkgMicrosoft_Extensions_ApiDescription_Server Condition=" '$(PkgMicrosoft_Extensions_ApiDescription_Server)' == '' ">C:\Users\nanxun\.nuget\packages\microsoft.extensions.apidescription.server\6.0.5</PkgMicrosoft_Extensions_ApiDescription_Server>
<PkgMicrosoft_VisualStudio_Azure_Containers_Tools_Targets Condition=" '$(PkgMicrosoft_VisualStudio_Azure_Containers_Tools_Targets)' == '' ">C:\Users\nanxun\.nuget\packages\microsoft.visualstudio.azure.containers.tools.targets\1.22.1</PkgMicrosoft_VisualStudio_Azure_Containers_Tools_Targets>
<Pkgxunit_analyzers Condition=" '$(Pkgxunit_analyzers)' == '' ">/home/nanxun/.nuget/packages/xunit.analyzers/1.4.0</Pkgxunit_analyzers>
<PkgMicrosoft_Extensions_ApiDescription_Server Condition=" '$(PkgMicrosoft_Extensions_ApiDescription_Server)' == '' ">/home/nanxun/.nuget/packages/microsoft.extensions.apidescription.server/6.0.5</PkgMicrosoft_Extensions_ApiDescription_Server>
<PkgMicrosoft_VisualStudio_Azure_Containers_Tools_Targets Condition=" '$(PkgMicrosoft_VisualStudio_Azure_Containers_Tools_Targets)' == '' ">/home/nanxun/.nuget/packages/microsoft.visualstudio.azure.containers.tools.targets/1.22.1</PkgMicrosoft_VisualStudio_Azure_Containers_Tools_Targets>
</PropertyGroup>
</Project>

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)xunit.core\2.5.3\build\xunit.core.targets" Condition="Exists('$(NuGetPackageRoot)xunit.core\2.5.3\build\xunit.core.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\10.0.2\buildTransitive\net8.0\Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\10.0.2\buildTransitive\net8.0\Microsoft.Extensions.Logging.Abstractions.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.options\10.0.2\buildTransitive\net8.0\Microsoft.Extensions.Options.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.options\10.0.2\buildTransitive\net8.0\Microsoft.Extensions.Options.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.codecoverage\17.8.0\build\netstandard2.0\Microsoft.CodeCoverage.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.codecoverage\17.8.0\build\netstandard2.0\Microsoft.CodeCoverage.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.net.test.sdk\17.8.0\build\netcoreapp3.1\Microsoft.NET.Test.Sdk.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.net.test.sdk\17.8.0\build\netcoreapp3.1\Microsoft.NET.Test.Sdk.targets')" />
<Import Project="$(NuGetPackageRoot)coverlet.collector\6.0.0\build\netstandard1.0\coverlet.collector.targets" Condition="Exists('$(NuGetPackageRoot)coverlet.collector\6.0.0\build\netstandard1.0\coverlet.collector.targets')" />
<Import Project="$(NuGetPackageRoot)xunit.core/2.5.3/build/xunit.core.targets" Condition="Exists('$(NuGetPackageRoot)xunit.core/2.5.3/build/xunit.core.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.logging.abstractions/10.0.2/buildTransitive/net8.0/Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.logging.abstractions/10.0.2/buildTransitive/net8.0/Microsoft.Extensions.Logging.Abstractions.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.options/10.0.2/buildTransitive/net8.0/Microsoft.Extensions.Options.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.options/10.0.2/buildTransitive/net8.0/Microsoft.Extensions.Options.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.codecoverage/17.8.0/build/netstandard2.0/Microsoft.CodeCoverage.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.codecoverage/17.8.0/build/netstandard2.0/Microsoft.CodeCoverage.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.net.test.sdk/17.8.0/build/netcoreapp3.1/Microsoft.NET.Test.Sdk.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.net.test.sdk/17.8.0/build/netcoreapp3.1/Microsoft.NET.Test.Sdk.targets')" />
<Import Project="$(NuGetPackageRoot)coverlet.collector/6.0.0/build/netstandard1.0/coverlet.collector.targets" Condition="Exists('$(NuGetPackageRoot)coverlet.collector/6.0.0/build/netstandard1.0/coverlet.collector.targets')" />
</ImportGroup>
</Project>

View File

@ -8900,40 +8900,32 @@
]
},
"packageFolders": {
"C:\\Users\\nanxun\\.nuget\\packages\\": {},
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {}
"/home/nanxun/.nuget/packages/": {}
},
"project": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IMTest\\IMTest.csproj",
"projectUniqueName": "/home/nanxun/Documents/Project/IM/backend/IMTest/IMTest.csproj",
"projectName": "IMTest",
"projectPath": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IMTest\\IMTest.csproj",
"packagesPath": "C:\\Users\\nanxun\\.nuget\\packages\\",
"outputPath": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IMTest\\obj\\",
"projectPath": "/home/nanxun/Documents/Project/IM/backend/IMTest/IMTest.csproj",
"packagesPath": "/home/nanxun/.nuget/packages/",
"outputPath": "/home/nanxun/Documents/Project/IM/backend/IMTest/obj/",
"projectStyle": "PackageReference",
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
],
"configFilePaths": [
"C:\\Users\\nanxun\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
"/home/nanxun/.nuget/NuGet/NuGet.Config"
],
"originalTargetFrameworks": [
"net8.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"C:\\Program Files\\dotnet\\library-packs": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net8.0": {
"targetAlias": "net8.0",
"projectReferences": {
"C:\\Users\\nanxun\\Documents\\IM\\backend\\IM_API\\IM_API.csproj": {
"projectPath": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IM_API\\IM_API.csproj"
"/home/nanxun/Documents/Project/IM/backend/IM_API/IM_API.csproj": {
"projectPath": "/home/nanxun/Documents/Project/IM/backend/IM_API/IM_API.csproj"
}
}
}
@ -8948,7 +8940,7 @@
"auditLevel": "low",
"auditMode": "direct"
},
"SdkAnalysisLevel": "9.0.300"
"SdkAnalysisLevel": "10.0.200"
},
"frameworks": {
"net8.0": {
@ -8995,7 +8987,7 @@
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.311/PortableRuntimeIdentifierGraph.json"
"runtimeIdentifierGraphPath": "/home/nanxun/dotnet/sdk/10.0.201/PortableRuntimeIdentifierGraph.json"
}
}
}

View File

@ -1,177 +1,177 @@
{
"version": 2,
"dgSpecHash": "E2DnflEnEuk=",
"dgSpecHash": "0Nf/3kBX/3U=",
"success": true,
"projectFilePath": "C:\\Users\\nanxun\\Documents\\IM\\backend\\IMTest\\IMTest.csproj",
"projectFilePath": "/home/nanxun/Documents/Project/IM/backend/IMTest/IMTest.csproj",
"expectedPackageFiles": [
"C:\\Users\\nanxun\\.nuget\\packages\\automapper\\12.0.1\\automapper.12.0.1.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\automapper.extensions.microsoft.dependencyinjection\\12.0.0\\automapper.extensions.microsoft.dependencyinjection.12.0.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\castle.core\\5.1.1\\castle.core.5.1.1.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\coverlet.collector\\6.0.0\\coverlet.collector.6.0.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\masstransit\\8.5.5\\masstransit.8.5.5.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\masstransit.abstractions\\8.5.5\\masstransit.abstractions.8.5.5.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\masstransit.rabbitmq\\8.5.5\\masstransit.rabbitmq.8.5.5.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.authentication.abstractions\\2.3.0\\microsoft.aspnetcore.authentication.abstractions.2.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.authentication.jwtbearer\\8.0.21\\microsoft.aspnetcore.authentication.jwtbearer.8.0.21.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.authorization\\2.3.0\\microsoft.aspnetcore.authorization.2.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.authorization.policy\\2.3.0\\microsoft.aspnetcore.authorization.policy.2.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.connections.abstractions\\2.3.0\\microsoft.aspnetcore.connections.abstractions.2.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.hosting.abstractions\\2.3.0\\microsoft.aspnetcore.hosting.abstractions.2.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.hosting.server.abstractions\\2.3.0\\microsoft.aspnetcore.hosting.server.abstractions.2.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.http\\2.3.0\\microsoft.aspnetcore.http.2.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.http.abstractions\\2.3.0\\microsoft.aspnetcore.http.abstractions.2.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.http.connections\\1.2.0\\microsoft.aspnetcore.http.connections.1.2.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.http.connections.common\\1.2.0\\microsoft.aspnetcore.http.connections.common.1.2.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.http.extensions\\2.3.0\\microsoft.aspnetcore.http.extensions.2.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.http.features\\2.3.0\\microsoft.aspnetcore.http.features.2.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.routing\\2.3.0\\microsoft.aspnetcore.routing.2.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.routing.abstractions\\2.3.0\\microsoft.aspnetcore.routing.abstractions.2.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.signalr\\1.2.0\\microsoft.aspnetcore.signalr.1.2.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.signalr.common\\1.2.0\\microsoft.aspnetcore.signalr.common.1.2.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.signalr.core\\1.2.0\\microsoft.aspnetcore.signalr.core.1.2.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.signalr.protocols.json\\1.2.0\\microsoft.aspnetcore.signalr.protocols.json.1.2.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.websockets\\2.3.0\\microsoft.aspnetcore.websockets.2.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.aspnetcore.webutilities\\2.3.0\\microsoft.aspnetcore.webutilities.2.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.bcl.asyncinterfaces\\1.1.0\\microsoft.bcl.asyncinterfaces.1.1.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.codecoverage\\17.8.0\\microsoft.codecoverage.17.8.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.csharp\\4.7.0\\microsoft.csharp.4.7.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.entityframeworkcore\\8.0.22\\microsoft.entityframeworkcore.8.0.22.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.entityframeworkcore.abstractions\\8.0.22\\microsoft.entityframeworkcore.abstractions.8.0.22.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.entityframeworkcore.analyzers\\8.0.22\\microsoft.entityframeworkcore.analyzers.8.0.22.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.entityframeworkcore.inmemory\\8.0.22\\microsoft.entityframeworkcore.inmemory.8.0.22.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.entityframeworkcore.relational\\8.0.13\\microsoft.entityframeworkcore.relational.8.0.13.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.extensions.apidescription.server\\6.0.5\\microsoft.extensions.apidescription.server.6.0.5.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.extensions.caching.abstractions\\10.0.2\\microsoft.extensions.caching.abstractions.10.0.2.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.extensions.caching.memory\\8.0.1\\microsoft.extensions.caching.memory.8.0.1.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.extensions.caching.stackexchangeredis\\10.0.2\\microsoft.extensions.caching.stackexchangeredis.10.0.2.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.extensions.configuration.abstractions\\8.0.0\\microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.extensions.dependencyinjection\\8.0.1\\microsoft.extensions.dependencyinjection.8.0.1.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.extensions.dependencyinjection.abstractions\\10.0.2\\microsoft.extensions.dependencyinjection.abstractions.10.0.2.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.extensions.diagnostics.abstractions\\8.0.1\\microsoft.extensions.diagnostics.abstractions.8.0.1.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.extensions.diagnostics.healthchecks\\8.0.0\\microsoft.extensions.diagnostics.healthchecks.8.0.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.extensions.diagnostics.healthchecks.abstractions\\8.0.0\\microsoft.extensions.diagnostics.healthchecks.abstractions.8.0.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.extensions.fileproviders.abstractions\\8.0.0\\microsoft.extensions.fileproviders.abstractions.8.0.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.extensions.hosting.abstractions\\8.0.1\\microsoft.extensions.hosting.abstractions.8.0.1.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.extensions.logging\\8.0.1\\microsoft.extensions.logging.8.0.1.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.extensions.logging.abstractions\\10.0.2\\microsoft.extensions.logging.abstractions.10.0.2.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.extensions.objectpool\\8.0.11\\microsoft.extensions.objectpool.8.0.11.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.extensions.options\\10.0.2\\microsoft.extensions.options.10.0.2.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.extensions.primitives\\10.0.2\\microsoft.extensions.primitives.10.0.2.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.identitymodel.abstractions\\8.14.0\\microsoft.identitymodel.abstractions.8.14.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.identitymodel.jsonwebtokens\\8.14.0\\microsoft.identitymodel.jsonwebtokens.8.14.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.identitymodel.logging\\8.14.0\\microsoft.identitymodel.logging.8.14.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.identitymodel.protocols\\7.1.2\\microsoft.identitymodel.protocols.7.1.2.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.identitymodel.protocols.openidconnect\\7.1.2\\microsoft.identitymodel.protocols.openidconnect.7.1.2.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.identitymodel.tokens\\8.14.0\\microsoft.identitymodel.tokens.8.14.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.net.http.headers\\2.3.0\\microsoft.net.http.headers.2.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.net.test.sdk\\17.8.0\\microsoft.net.test.sdk.17.8.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.netcore.platforms\\1.1.0\\microsoft.netcore.platforms.1.1.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.netcore.targets\\1.1.0\\microsoft.netcore.targets.1.1.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.openapi\\1.6.14\\microsoft.openapi.1.6.14.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.testplatform.objectmodel\\17.8.0\\microsoft.testplatform.objectmodel.17.8.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.testplatform.testhost\\17.8.0\\microsoft.testplatform.testhost.17.8.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.visualstudio.azure.containers.tools.targets\\1.22.1\\microsoft.visualstudio.azure.containers.tools.targets.1.22.1.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\microsoft.win32.primitives\\4.3.0\\microsoft.win32.primitives.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\moq\\4.20.72\\moq.4.20.72.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\mysqlconnector\\2.3.5\\mysqlconnector.2.3.5.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\netstandard.library\\1.6.1\\netstandard.library.1.6.1.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\newtonsoft.json\\13.0.4\\newtonsoft.json.13.0.4.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\nuget.frameworks\\6.5.0\\nuget.frameworks.6.5.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\pipelines.sockets.unofficial\\2.2.8\\pipelines.sockets.unofficial.2.2.8.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\pomelo.entityframeworkcore.mysql\\8.0.3\\pomelo.entityframeworkcore.mysql.8.0.3.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\rabbitmq.client\\7.1.2\\rabbitmq.client.7.1.2.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\redlock.net\\2.3.2\\redlock.net.2.3.2.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\runtime.debian.8-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.debian.8-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\runtime.fedora.23-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.fedora.23-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\runtime.fedora.24-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.fedora.24-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\runtime.native.system\\4.3.0\\runtime.native.system.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\runtime.native.system.io.compression\\4.3.0\\runtime.native.system.io.compression.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\runtime.native.system.net.http\\4.3.0\\runtime.native.system.net.http.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\runtime.native.system.security.cryptography.apple\\4.3.0\\runtime.native.system.security.cryptography.apple.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\runtime.opensuse.13.2-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.opensuse.13.2-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\runtime.opensuse.42.1-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.opensuse.42.1-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\runtime.osx.10.10-x64.runtime.native.system.security.cryptography.apple\\4.3.0\\runtime.osx.10.10-x64.runtime.native.system.security.cryptography.apple.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\runtime.osx.10.10-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.osx.10.10-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\runtime.rhel.7-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.rhel.7-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\runtime.ubuntu.14.04-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.ubuntu.14.04-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\runtime.ubuntu.16.04-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.ubuntu.16.04-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\runtime.ubuntu.16.10-x64.runtime.native.system.security.cryptography.openssl\\4.3.0\\runtime.ubuntu.16.10-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\sixlabors.imagesharp\\3.1.12\\sixlabors.imagesharp.3.1.12.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\stackexchange.redis\\2.9.32\\stackexchange.redis.2.9.32.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\swashbuckle.aspnetcore\\6.6.2\\swashbuckle.aspnetcore.6.6.2.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\swashbuckle.aspnetcore.swagger\\6.6.2\\swashbuckle.aspnetcore.swagger.6.6.2.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\swashbuckle.aspnetcore.swaggergen\\6.6.2\\swashbuckle.aspnetcore.swaggergen.6.6.2.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\swashbuckle.aspnetcore.swaggerui\\6.6.2\\swashbuckle.aspnetcore.swaggerui.6.6.2.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.appcontext\\4.3.0\\system.appcontext.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.buffers\\4.6.0\\system.buffers.4.6.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.collections\\4.3.0\\system.collections.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.collections.concurrent\\4.3.0\\system.collections.concurrent.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.console\\4.3.0\\system.console.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.diagnostics.debug\\4.3.0\\system.diagnostics.debug.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.diagnostics.diagnosticsource\\10.0.2\\system.diagnostics.diagnosticsource.10.0.2.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.diagnostics.eventlog\\6.0.0\\system.diagnostics.eventlog.6.0.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.diagnostics.tools\\4.3.0\\system.diagnostics.tools.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.diagnostics.tracing\\4.3.0\\system.diagnostics.tracing.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.globalization\\4.3.0\\system.globalization.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.globalization.calendars\\4.3.0\\system.globalization.calendars.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.globalization.extensions\\4.3.0\\system.globalization.extensions.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.identitymodel.tokens.jwt\\8.14.0\\system.identitymodel.tokens.jwt.8.14.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.io\\4.3.0\\system.io.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.io.compression\\4.3.0\\system.io.compression.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.io.compression.zipfile\\4.3.0\\system.io.compression.zipfile.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.io.filesystem\\4.3.0\\system.io.filesystem.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.io.filesystem.primitives\\4.3.0\\system.io.filesystem.primitives.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.io.pipelines\\8.0.0\\system.io.pipelines.8.0.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.linq\\4.3.0\\system.linq.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.linq.expressions\\4.3.0\\system.linq.expressions.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.net.http\\4.3.0\\system.net.http.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.net.primitives\\4.3.0\\system.net.primitives.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.net.sockets\\4.3.0\\system.net.sockets.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.net.websockets.websocketprotocol\\5.1.0\\system.net.websockets.websocketprotocol.5.1.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.objectmodel\\4.3.0\\system.objectmodel.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.reflection\\4.3.0\\system.reflection.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.reflection.emit\\4.7.0\\system.reflection.emit.4.7.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.reflection.emit.ilgeneration\\4.3.0\\system.reflection.emit.ilgeneration.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.reflection.emit.lightweight\\4.3.0\\system.reflection.emit.lightweight.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.reflection.extensions\\4.3.0\\system.reflection.extensions.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.reflection.metadata\\1.6.0\\system.reflection.metadata.1.6.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.reflection.primitives\\4.3.0\\system.reflection.primitives.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.reflection.typeextensions\\4.3.0\\system.reflection.typeextensions.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.resources.resourcemanager\\4.3.0\\system.resources.resourcemanager.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.runtime\\4.3.0\\system.runtime.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.runtime.extensions\\4.3.0\\system.runtime.extensions.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.runtime.handles\\4.3.0\\system.runtime.handles.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.runtime.interopservices\\4.3.0\\system.runtime.interopservices.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.runtime.interopservices.runtimeinformation\\4.3.0\\system.runtime.interopservices.runtimeinformation.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.runtime.numerics\\4.3.0\\system.runtime.numerics.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.security.cryptography.algorithms\\4.3.0\\system.security.cryptography.algorithms.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.security.cryptography.cng\\4.3.0\\system.security.cryptography.cng.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.security.cryptography.csp\\4.3.0\\system.security.cryptography.csp.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.security.cryptography.encoding\\4.3.0\\system.security.cryptography.encoding.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.security.cryptography.openssl\\4.3.0\\system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.security.cryptography.primitives\\4.3.0\\system.security.cryptography.primitives.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.security.cryptography.x509certificates\\4.3.0\\system.security.cryptography.x509certificates.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.text.encoding\\4.3.0\\system.text.encoding.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.text.encoding.extensions\\4.3.0\\system.text.encoding.extensions.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.text.encodings.web\\8.0.0\\system.text.encodings.web.8.0.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.text.regularexpressions\\4.3.0\\system.text.regularexpressions.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.threading\\4.3.0\\system.threading.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.threading.channels\\8.0.0\\system.threading.channels.8.0.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.threading.ratelimiting\\8.0.0\\system.threading.ratelimiting.8.0.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.threading.tasks\\4.3.0\\system.threading.tasks.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.threading.tasks.extensions\\4.3.0\\system.threading.tasks.extensions.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.threading.timer\\4.3.0\\system.threading.timer.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.xml.readerwriter\\4.3.0\\system.xml.readerwriter.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\system.xml.xdocument\\4.3.0\\system.xml.xdocument.4.3.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\xunit\\2.5.3\\xunit.2.5.3.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\xunit.abstractions\\2.0.3\\xunit.abstractions.2.0.3.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\xunit.analyzers\\1.4.0\\xunit.analyzers.1.4.0.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\xunit.assert\\2.5.3\\xunit.assert.2.5.3.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\xunit.core\\2.5.3\\xunit.core.2.5.3.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\xunit.extensibility.core\\2.5.3\\xunit.extensibility.core.2.5.3.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\xunit.extensibility.execution\\2.5.3\\xunit.extensibility.execution.2.5.3.nupkg.sha512",
"C:\\Users\\nanxun\\.nuget\\packages\\xunit.runner.visualstudio\\2.5.3\\xunit.runner.visualstudio.2.5.3.nupkg.sha512"
"/home/nanxun/.nuget/packages/automapper/12.0.1/automapper.12.0.1.nupkg.sha512",
"/home/nanxun/.nuget/packages/automapper.extensions.microsoft.dependencyinjection/12.0.0/automapper.extensions.microsoft.dependencyinjection.12.0.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/castle.core/5.1.1/castle.core.5.1.1.nupkg.sha512",
"/home/nanxun/.nuget/packages/coverlet.collector/6.0.0/coverlet.collector.6.0.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/masstransit/8.5.5/masstransit.8.5.5.nupkg.sha512",
"/home/nanxun/.nuget/packages/masstransit.abstractions/8.5.5/masstransit.abstractions.8.5.5.nupkg.sha512",
"/home/nanxun/.nuget/packages/masstransit.rabbitmq/8.5.5/masstransit.rabbitmq.8.5.5.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.authentication.abstractions/2.3.0/microsoft.aspnetcore.authentication.abstractions.2.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.authentication.jwtbearer/8.0.21/microsoft.aspnetcore.authentication.jwtbearer.8.0.21.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.authorization/2.3.0/microsoft.aspnetcore.authorization.2.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.authorization.policy/2.3.0/microsoft.aspnetcore.authorization.policy.2.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.connections.abstractions/2.3.0/microsoft.aspnetcore.connections.abstractions.2.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.hosting.abstractions/2.3.0/microsoft.aspnetcore.hosting.abstractions.2.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.hosting.server.abstractions/2.3.0/microsoft.aspnetcore.hosting.server.abstractions.2.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.http/2.3.0/microsoft.aspnetcore.http.2.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.http.abstractions/2.3.0/microsoft.aspnetcore.http.abstractions.2.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.http.connections/1.2.0/microsoft.aspnetcore.http.connections.1.2.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.http.connections.common/1.2.0/microsoft.aspnetcore.http.connections.common.1.2.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.http.extensions/2.3.0/microsoft.aspnetcore.http.extensions.2.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.http.features/2.3.0/microsoft.aspnetcore.http.features.2.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.routing/2.3.0/microsoft.aspnetcore.routing.2.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.routing.abstractions/2.3.0/microsoft.aspnetcore.routing.abstractions.2.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.signalr/1.2.0/microsoft.aspnetcore.signalr.1.2.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.signalr.common/1.2.0/microsoft.aspnetcore.signalr.common.1.2.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.signalr.core/1.2.0/microsoft.aspnetcore.signalr.core.1.2.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.signalr.protocols.json/1.2.0/microsoft.aspnetcore.signalr.protocols.json.1.2.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.websockets/2.3.0/microsoft.aspnetcore.websockets.2.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.aspnetcore.webutilities/2.3.0/microsoft.aspnetcore.webutilities.2.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.bcl.asyncinterfaces/1.1.0/microsoft.bcl.asyncinterfaces.1.1.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.codecoverage/17.8.0/microsoft.codecoverage.17.8.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.csharp/4.7.0/microsoft.csharp.4.7.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.entityframeworkcore/8.0.22/microsoft.entityframeworkcore.8.0.22.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.entityframeworkcore.abstractions/8.0.22/microsoft.entityframeworkcore.abstractions.8.0.22.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.entityframeworkcore.analyzers/8.0.22/microsoft.entityframeworkcore.analyzers.8.0.22.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.entityframeworkcore.inmemory/8.0.22/microsoft.entityframeworkcore.inmemory.8.0.22.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.entityframeworkcore.relational/8.0.13/microsoft.entityframeworkcore.relational.8.0.13.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.extensions.apidescription.server/6.0.5/microsoft.extensions.apidescription.server.6.0.5.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.extensions.caching.abstractions/10.0.2/microsoft.extensions.caching.abstractions.10.0.2.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.extensions.caching.memory/8.0.1/microsoft.extensions.caching.memory.8.0.1.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.extensions.caching.stackexchangeredis/10.0.2/microsoft.extensions.caching.stackexchangeredis.10.0.2.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.extensions.configuration.abstractions/8.0.0/microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.extensions.dependencyinjection/8.0.1/microsoft.extensions.dependencyinjection.8.0.1.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.extensions.dependencyinjection.abstractions/10.0.2/microsoft.extensions.dependencyinjection.abstractions.10.0.2.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.extensions.diagnostics.abstractions/8.0.1/microsoft.extensions.diagnostics.abstractions.8.0.1.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.extensions.diagnostics.healthchecks/8.0.0/microsoft.extensions.diagnostics.healthchecks.8.0.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.extensions.diagnostics.healthchecks.abstractions/8.0.0/microsoft.extensions.diagnostics.healthchecks.abstractions.8.0.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.extensions.fileproviders.abstractions/8.0.0/microsoft.extensions.fileproviders.abstractions.8.0.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.extensions.hosting.abstractions/8.0.1/microsoft.extensions.hosting.abstractions.8.0.1.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.extensions.logging/8.0.1/microsoft.extensions.logging.8.0.1.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.extensions.logging.abstractions/10.0.2/microsoft.extensions.logging.abstractions.10.0.2.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.extensions.objectpool/8.0.11/microsoft.extensions.objectpool.8.0.11.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.extensions.options/10.0.2/microsoft.extensions.options.10.0.2.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.extensions.primitives/10.0.2/microsoft.extensions.primitives.10.0.2.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.identitymodel.abstractions/8.14.0/microsoft.identitymodel.abstractions.8.14.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.identitymodel.jsonwebtokens/8.14.0/microsoft.identitymodel.jsonwebtokens.8.14.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.identitymodel.logging/8.14.0/microsoft.identitymodel.logging.8.14.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.identitymodel.protocols/7.1.2/microsoft.identitymodel.protocols.7.1.2.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.identitymodel.protocols.openidconnect/7.1.2/microsoft.identitymodel.protocols.openidconnect.7.1.2.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.identitymodel.tokens/8.14.0/microsoft.identitymodel.tokens.8.14.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.net.http.headers/2.3.0/microsoft.net.http.headers.2.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.net.test.sdk/17.8.0/microsoft.net.test.sdk.17.8.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.netcore.platforms/1.1.0/microsoft.netcore.platforms.1.1.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.netcore.targets/1.1.0/microsoft.netcore.targets.1.1.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.openapi/1.6.14/microsoft.openapi.1.6.14.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.testplatform.objectmodel/17.8.0/microsoft.testplatform.objectmodel.17.8.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.testplatform.testhost/17.8.0/microsoft.testplatform.testhost.17.8.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.visualstudio.azure.containers.tools.targets/1.22.1/microsoft.visualstudio.azure.containers.tools.targets.1.22.1.nupkg.sha512",
"/home/nanxun/.nuget/packages/microsoft.win32.primitives/4.3.0/microsoft.win32.primitives.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/moq/4.20.72/moq.4.20.72.nupkg.sha512",
"/home/nanxun/.nuget/packages/mysqlconnector/2.3.5/mysqlconnector.2.3.5.nupkg.sha512",
"/home/nanxun/.nuget/packages/netstandard.library/1.6.1/netstandard.library.1.6.1.nupkg.sha512",
"/home/nanxun/.nuget/packages/newtonsoft.json/13.0.4/newtonsoft.json.13.0.4.nupkg.sha512",
"/home/nanxun/.nuget/packages/nuget.frameworks/6.5.0/nuget.frameworks.6.5.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/pipelines.sockets.unofficial/2.2.8/pipelines.sockets.unofficial.2.2.8.nupkg.sha512",
"/home/nanxun/.nuget/packages/pomelo.entityframeworkcore.mysql/8.0.3/pomelo.entityframeworkcore.mysql.8.0.3.nupkg.sha512",
"/home/nanxun/.nuget/packages/rabbitmq.client/7.1.2/rabbitmq.client.7.1.2.nupkg.sha512",
"/home/nanxun/.nuget/packages/redlock.net/2.3.2/redlock.net.2.3.2.nupkg.sha512",
"/home/nanxun/.nuget/packages/runtime.debian.8-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.debian.8-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/runtime.fedora.23-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.fedora.23-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/runtime.fedora.24-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.fedora.24-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/runtime.native.system/4.3.0/runtime.native.system.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/runtime.native.system.io.compression/4.3.0/runtime.native.system.io.compression.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/runtime.native.system.net.http/4.3.0/runtime.native.system.net.http.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/runtime.native.system.security.cryptography.apple/4.3.0/runtime.native.system.security.cryptography.apple.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/runtime.native.system.security.cryptography.openssl/4.3.0/runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/runtime.opensuse.13.2-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.opensuse.13.2-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/runtime.opensuse.42.1-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.opensuse.42.1-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/runtime.osx.10.10-x64.runtime.native.system.security.cryptography.apple/4.3.0/runtime.osx.10.10-x64.runtime.native.system.security.cryptography.apple.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/runtime.osx.10.10-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.osx.10.10-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/runtime.rhel.7-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.rhel.7-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/runtime.ubuntu.14.04-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.ubuntu.14.04-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/runtime.ubuntu.16.04-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.ubuntu.16.04-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/runtime.ubuntu.16.10-x64.runtime.native.system.security.cryptography.openssl/4.3.0/runtime.ubuntu.16.10-x64.runtime.native.system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/sixlabors.imagesharp/3.1.12/sixlabors.imagesharp.3.1.12.nupkg.sha512",
"/home/nanxun/.nuget/packages/stackexchange.redis/2.9.32/stackexchange.redis.2.9.32.nupkg.sha512",
"/home/nanxun/.nuget/packages/swashbuckle.aspnetcore/6.6.2/swashbuckle.aspnetcore.6.6.2.nupkg.sha512",
"/home/nanxun/.nuget/packages/swashbuckle.aspnetcore.swagger/6.6.2/swashbuckle.aspnetcore.swagger.6.6.2.nupkg.sha512",
"/home/nanxun/.nuget/packages/swashbuckle.aspnetcore.swaggergen/6.6.2/swashbuckle.aspnetcore.swaggergen.6.6.2.nupkg.sha512",
"/home/nanxun/.nuget/packages/swashbuckle.aspnetcore.swaggerui/6.6.2/swashbuckle.aspnetcore.swaggerui.6.6.2.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.appcontext/4.3.0/system.appcontext.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.buffers/4.6.0/system.buffers.4.6.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.collections/4.3.0/system.collections.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.collections.concurrent/4.3.0/system.collections.concurrent.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.console/4.3.0/system.console.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.diagnostics.debug/4.3.0/system.diagnostics.debug.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.diagnostics.diagnosticsource/10.0.2/system.diagnostics.diagnosticsource.10.0.2.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.diagnostics.eventlog/6.0.0/system.diagnostics.eventlog.6.0.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.diagnostics.tools/4.3.0/system.diagnostics.tools.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.diagnostics.tracing/4.3.0/system.diagnostics.tracing.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.globalization/4.3.0/system.globalization.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.globalization.calendars/4.3.0/system.globalization.calendars.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.globalization.extensions/4.3.0/system.globalization.extensions.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.identitymodel.tokens.jwt/8.14.0/system.identitymodel.tokens.jwt.8.14.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.io/4.3.0/system.io.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.io.compression/4.3.0/system.io.compression.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.io.compression.zipfile/4.3.0/system.io.compression.zipfile.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.io.filesystem/4.3.0/system.io.filesystem.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.io.filesystem.primitives/4.3.0/system.io.filesystem.primitives.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.io.pipelines/8.0.0/system.io.pipelines.8.0.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.linq/4.3.0/system.linq.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.linq.expressions/4.3.0/system.linq.expressions.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.net.http/4.3.0/system.net.http.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.net.primitives/4.3.0/system.net.primitives.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.net.sockets/4.3.0/system.net.sockets.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.net.websockets.websocketprotocol/5.1.0/system.net.websockets.websocketprotocol.5.1.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.objectmodel/4.3.0/system.objectmodel.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.reflection/4.3.0/system.reflection.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.reflection.emit/4.7.0/system.reflection.emit.4.7.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.reflection.emit.ilgeneration/4.3.0/system.reflection.emit.ilgeneration.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.reflection.emit.lightweight/4.3.0/system.reflection.emit.lightweight.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.reflection.extensions/4.3.0/system.reflection.extensions.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.reflection.metadata/1.6.0/system.reflection.metadata.1.6.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.reflection.primitives/4.3.0/system.reflection.primitives.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.reflection.typeextensions/4.3.0/system.reflection.typeextensions.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.resources.resourcemanager/4.3.0/system.resources.resourcemanager.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.runtime/4.3.0/system.runtime.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.runtime.extensions/4.3.0/system.runtime.extensions.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.runtime.handles/4.3.0/system.runtime.handles.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.runtime.interopservices/4.3.0/system.runtime.interopservices.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.runtime.interopservices.runtimeinformation/4.3.0/system.runtime.interopservices.runtimeinformation.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.runtime.numerics/4.3.0/system.runtime.numerics.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.security.cryptography.algorithms/4.3.0/system.security.cryptography.algorithms.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.security.cryptography.cng/4.3.0/system.security.cryptography.cng.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.security.cryptography.csp/4.3.0/system.security.cryptography.csp.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.security.cryptography.encoding/4.3.0/system.security.cryptography.encoding.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.security.cryptography.openssl/4.3.0/system.security.cryptography.openssl.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.security.cryptography.primitives/4.3.0/system.security.cryptography.primitives.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.security.cryptography.x509certificates/4.3.0/system.security.cryptography.x509certificates.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.text.encoding/4.3.0/system.text.encoding.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.text.encoding.extensions/4.3.0/system.text.encoding.extensions.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.text.encodings.web/8.0.0/system.text.encodings.web.8.0.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.text.regularexpressions/4.3.0/system.text.regularexpressions.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.threading/4.3.0/system.threading.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.threading.channels/8.0.0/system.threading.channels.8.0.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.threading.ratelimiting/8.0.0/system.threading.ratelimiting.8.0.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.threading.tasks/4.3.0/system.threading.tasks.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.threading.tasks.extensions/4.3.0/system.threading.tasks.extensions.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.threading.timer/4.3.0/system.threading.timer.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.xml.readerwriter/4.3.0/system.xml.readerwriter.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/system.xml.xdocument/4.3.0/system.xml.xdocument.4.3.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/xunit/2.5.3/xunit.2.5.3.nupkg.sha512",
"/home/nanxun/.nuget/packages/xunit.abstractions/2.0.3/xunit.abstractions.2.0.3.nupkg.sha512",
"/home/nanxun/.nuget/packages/xunit.analyzers/1.4.0/xunit.analyzers.1.4.0.nupkg.sha512",
"/home/nanxun/.nuget/packages/xunit.assert/2.5.3/xunit.assert.2.5.3.nupkg.sha512",
"/home/nanxun/.nuget/packages/xunit.core/2.5.3/xunit.core.2.5.3.nupkg.sha512",
"/home/nanxun/.nuget/packages/xunit.extensibility.core/2.5.3/xunit.extensibility.core.2.5.3.nupkg.sha512",
"/home/nanxun/.nuget/packages/xunit.extensibility.execution/2.5.3/xunit.extensibility.execution.2.5.3.nupkg.sha512",
"/home/nanxun/.nuget/packages/xunit.runner.visualstudio/2.5.3/xunit.runner.visualstudio.2.5.3.nupkg.sha512"
],
"logs": []
}

View File

@ -0,0 +1,15 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/modules.xml
/projectSettingsUpdater.xml
/.idea.IM_API.iml
/contentModel.xml
# Ignored default folder with query files
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
</component>
</project>

View File

@ -22,7 +22,7 @@ namespace IM_API.Application.EventHandlers.FriendAddHandler
var usersList = new List<string> {
@event.RequestUserId.ToString(), @event.ResponseUserId.ToString()
};
var res = new HubResponse<MessageBaseDto>("Event", new MessageBaseDto()
var res = new HubResponse<MessageBaseDto>(HubResponseType.FriendAccepted, new MessageBaseDto()
{
ChatType = ChatType.PRIVATE,
Content = "您有新的好友关系已添加",

View File

@ -15,7 +15,7 @@ namespace IM_API.Application.EventHandlers.GroupInviteActionUpdateHandler
public async Task Consume(ConsumeContext<GroupInviteActionUpdateEvent> context)
{
var @event = context.Message;
if(@event.Action == Models.GroupInviteState.Passed)
if(@event.Action == Models.GroupRequestState.TargetPassed)
{
await _groupService.MakeGroupRequestAsync(@event.UserId, @event.InviteUserId,@event.GroupId);
}

View File

@ -29,6 +29,7 @@ namespace IM_API.Configs
CreateMap<RegisterRequestDto, User>()
.ForMember(dest => dest.Username,opt => opt.MapFrom(src => src.Username))
.ForMember(dest => dest.Password,opt => opt.MapFrom(src => src.Password))
.ForMember(dest => dest.Email, opt => opt.MapFrom(src => src.Email))
.ForMember(dest => dest.Avatar,opt => opt.MapFrom(src => "https://ts1.tc.mm.bing.net/th/id/OIP-C.dl0WpkTP6E2J4FnhDC_jHwAAAA?rs=1&pid=ImgDetMain&o=7&rm=3"))
.ForMember(dest => dest.StatusEnum,opt => opt.MapFrom(src => UserStatus.Normal))
.ForMember(dest => dest.OnlineStatusEnum,opt => opt.MapFrom(src => UserOnlineStatus.Offline))
@ -215,6 +216,34 @@ namespace IM_API.Configs
CreateMap<GroupMember, GroupMemberVo>()
.ForMember(dest => dest.Created, opt => opt.MapFrom(src => src.Created))
.ForMember(dest => dest.Role, opt => opt.MapFrom(src => src.RoleEnum));
//群更新模型
CreateMap<GroupUpdateDto, Group>()
.ForMember(dest => dest.Avatar, opt => opt.MapFrom(src => src.Avatar))
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.GroupName))
.ForMember(dest => dest.Announcement, opt => opt.MapFrom(src => src.Description))
.ForAllMembers(dest => dest.Ignore());
CreateMap<Group, GroupInfoVo>()
.ForMember(dest => dest.Auhority, opt => opt.MapFrom(src => src.AuhorityEnum))
.ForMember(dest => dest.AllMembersBanned, opt => opt.MapFrom(src => src.AllMembersBannedEnum))
.ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.StatusEnum))
;
//群通知模型转换
CreateMap<GroupRequest, GroupNotificationVo>()
.ForMember(dest => dest.UserId, opt => opt.MapFrom(src => src.UserId))
.ForMember(dest => dest.GroupId, opt => opt.MapFrom(src => src.GroupId))
.ForMember(dest => dest.InviteUser, opt => opt.MapFrom(src => src.InviteUserId))
.ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.StateEnum))
.ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.Description))
.ForMember(dest => dest.RequestId, opt => opt.MapFrom(src => src.Id))
//.ForAllMembers(opt => opt.Ignore())
;
}
}
}

View File

@ -77,5 +77,33 @@ namespace IM_API.Controllers
var members = await _groupService.GetGroupMembers(int.Parse(useridStr), groupId);
return Ok(new BaseResponse<List<GroupMemberVo>>(members));
}
[HttpPost]
[ProducesResponseType(typeof(BaseResponse<GroupInfoVo>), StatusCodes.Status200OK)]
public async Task<IActionResult> UpdateGroup([FromQuery]int groupId, [FromBody]GroupUpdateDto dto)
{
var useridStr = User.FindFirstValue(ClaimTypes.NameIdentifier);
var groupinfo = await _groupService.UpdateGroupInfoAsync(int.Parse(useridStr), groupId, dto);
return Ok(new BaseResponse<GroupInfoVo>(groupinfo));
}
[HttpGet]
[ProducesResponseType(typeof(BaseResponse<GroupInfoVo>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetGroupInfo([FromQuery]int groupId)
{
var group = await _groupService.GetGroupInfoAsync(groupId);
return Ok(new BaseResponse<GroupInfoVo>(group));
}
[HttpGet]
[ProducesResponseType(typeof(BaseResponse<List<GroupNotificationVo>>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetGroupNotification([FromQuery]int groupId)
{
string userIdStr = User.FindFirstValue(ClaimTypes.NameIdentifier)!;
var data = await _groupService.GetGroupNotificationAsync(int.Parse(userIdStr));
return Ok(new BaseResponse<List<GroupNotificationVo>>(data));
}
}
}

View File

@ -9,6 +9,6 @@ namespace IM_API.Domain.Events
public int InviteUserId { get; set; }
public int InviteId { get; set; }
public int GroupId { get; set; }
public GroupInviteState Action { get; set; }
public GroupRequestState Action { get; set; }
}
}

View File

@ -4,6 +4,8 @@ namespace IM_API.Dtos.Auth
{
public class RegisterRequestDto
{
[EmailAddress(ErrorMessage = "邮箱格式错误")]
public string Email { get; set; }
[Required(ErrorMessage = "用户名不能为空")]
[MaxLength(20, ErrorMessage = "用户名不能超过20字符")]
[RegularExpression(@"^[A-Za-z0-9]+$", ErrorMessage = "")]

View File

@ -0,0 +1,10 @@
namespace IM_API.Dtos.Group
{
public class GroupUpdateDto
{
public string? GroupName { get; set; }
public string? Description { get; set; }
public string? Avatar { get; set; }
}
}

View File

@ -5,6 +5,6 @@ namespace IM_API.Dtos.Group
public class HandleGroupInviteDto
{
public int InviteId { get; set; }
public GroupInviteState Action { get; set; }
public GroupRequestState Action { get; set; }
}
}

View File

@ -39,11 +39,44 @@ namespace IM_API.Dtos
Message = codeDefine.Message;
Data = data;
}
public HubResponse(HubResponseType type, T? data)
{
Code = CodeDefine.SUCCESS.Code;
Method = "Event";
Type = type;
Data = data;
}
}
public enum HubResponseType
{
ChatMsg = 1, // 聊天内容
SystemNotice = 2, // 系统通知(如:申请好友成功)
ActionStatus = 3 // 状态变更(如:对方正在输入、已读回执)
// --- 基础聊天 (10-19) ---
ChatMsg = 1, // 普通消息
// --- 系统与通知 (20-29) ---
SystemNotice = 2, // 通用系统通知
FriendRequest = 21, // 好友申请消息
FriendAccepted = 22, // 好友通过通知
UserInLine = 23, // 好友上线/下线通知
// --- 状态变更与交互 (30-39) ---
ActionStatus = 3, // 通用状态(正在输入等)
MsgReadReceipt = 31, // 已读回执
MsgRevoke = 32, // 消息撤回
MsgEdit = 33, // 消息二次编辑更新
// --- 群组管理 (40-49) ---
GroupInvited = 41, // 被邀请入群
GroupMemberUpdate = 42, // 群成员变动(进群/退群)
GroupAnnouncement = 43, // 群公告更新
GroupDismissed = 44, // 群组解散
// --- 实时通信控制 (50-59) ---
RTC_CallRequest = 51, // 音视频通话邀请
RTC_CallHandled = 52, // 音视频接听/挂断/取消状态
// --- 异常与安全 (90-99) ---
ErrorInternal = 91, // 服务器内部错误
TokenExpired = 92, // 登录过期,强制下线
KickedOut = 93 // 被挤下线(异地登录)
}
}

View File

@ -0,0 +1,4 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/Environment/Hierarchy/Build/BuildTool/RecentDotNetCliExePaths/=_002Fhome_002Fnanxun_002Fdotnet_002Fdotnet/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/Environment/Hierarchy/Build/BuildTool/DotNetCliExePath/@EntryValue">/home/nanxun/dotnet/dotnet</s:String>
<s:String x:Key="/Default/Environment/Hierarchy/Build/BuildTool/CustomBuildToolPath/@EntryValue">/home/nanxun/dotnet/sdk/10.0.201/MSBuild.dll</s:String></wpf:ResourceDictionary>

View File

@ -53,5 +53,15 @@ namespace IM_API.Interface.Services
Task MakeGroupRequestAsync(int userId,int? adminUserId,int groupId);
Task MakeGroupMemberAsync(int userId, int groupId, GroupMemberRole? role);
Task<List<GroupMemberVo>> GetGroupMembers(int userId, int groupId);
Task<GroupInfoVo> UpdateGroupInfoAsync(int userId, int groupId, GroupUpdateDto updateDto);
Task<GroupInfoVo> GetGroupInfoAsync(int groupId);
/// <summary>
/// 获取群聊通知
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
Task<List<GroupNotificationVo>> GetGroupNotificationAsync(int userId);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace IM_API.Migrations
{
/// <inheritdoc />
public partial class updategroupannouncement : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.UpdateData(
table: "groups",
keyColumn: "Announcement",
keyValue: null,
column: "Announcement",
value: "");
migrationBuilder.AlterColumn<string>(
name: "Announcement",
table: "groups",
type: "text",
nullable: false,
comment: "群公告",
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "text",
oldNullable: true,
oldComment: "群公告")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("Relational:Collation", "utf8mb4_general_ci");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "Announcement",
table: "groups",
type: "text",
nullable: true,
comment: "群公告",
collation: "utf8mb4_general_ci",
oldClrType: typeof(string),
oldType: "text",
oldComment: "群公告")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("Relational:Collation", "utf8mb4_general_ci");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,87 @@
using System;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace IM_API.Migrations
{
/// <inheritdoc />
public partial class groupinviterequestmerge : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "group_invite");
migrationBuilder.AddColumn<int>(
name: "InviteUserId",
table: "group_request",
type: "int",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "InviteUserId",
table: "group_request");
migrationBuilder.RenameIndex(
name: "GroupId",
table: "group_request",
newName: "GroupId1");
migrationBuilder.CreateTable(
name: "group_invite",
columns: table => new
{
ID = table.Column<int>(type: "int(11)", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
GroupId = table.Column<int>(type: "int(11)", nullable: false, comment: "群聊编号"),
InvitedUser = table.Column<int>(type: "int(11)", nullable: true, comment: "被邀请用户"),
InviteUser = table.Column<int>(type: "int(11)", nullable: true, comment: "邀请用户"),
Created = table.Column<DateTimeOffset>(type: "datetime", nullable: true, comment: "创建时间"),
State = table.Column<sbyte>(type: "tinyint(4)", nullable: true, comment: "当前状态(0:待被邀请人同意\r\n1:被邀请人已同意)")
},
constraints: table =>
{
table.PrimaryKey("PRIMARY", x => x.ID);
table.ForeignKey(
name: "group_invite_ibfk_1",
column: x => x.InviteUser,
principalTable: "users",
principalColumn: "ID");
table.ForeignKey(
name: "group_invite_ibfk_2",
column: x => x.GroupId,
principalTable: "groups",
principalColumn: "ID");
table.ForeignKey(
name: "group_invite_ibfk_3",
column: x => x.InvitedUser,
principalTable: "users",
principalColumn: "ID");
})
.Annotation("MySql:CharSet", "utf8mb4")
.Annotation("Relational:Collation", "utf8mb4_general_ci");
migrationBuilder.CreateIndex(
name: "GroupId",
table: "group_invite",
column: "GroupId");
migrationBuilder.CreateIndex(
name: "InvitedUser",
table: "group_invite",
column: "InvitedUser");
migrationBuilder.CreateIndex(
name: "InviteUser",
table: "group_invite",
column: "InviteUser");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace IM_API.Migrations
{
/// <inheritdoc />
public partial class updateuser : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Description",
table: "users",
type: "longtext",
nullable: true,
collation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AddColumn<string>(
name: "Email",
table: "users",
type: "longtext",
nullable: true,
collation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AddColumn<string>(
name: "Region",
table: "users",
type: "longtext",
nullable: true,
collation: "utf8mb4_general_ci")
.Annotation("MySql:CharSet", "utf8mb4");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Description",
table: "users");
migrationBuilder.DropColumn(
name: "Email",
table: "users");
migrationBuilder.DropColumn(
name: "Region",
table: "users");
}
}
}

View File

@ -333,6 +333,7 @@ namespace IM_API.Migrations
.HasComment("全员禁言0允许发言2全员禁言");
b.Property<string>("Announcement")
.IsRequired()
.HasColumnType("text")
.HasComment("群公告");
@ -392,50 +393,6 @@ namespace IM_API.Migrations
MySqlEntityTypeBuilderExtensions.UseCollation(b, "utf8mb4_general_ci");
});
modelBuilder.Entity("IM_API.Models.GroupInvite", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int(11)")
.HasColumnName("ID");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
b.Property<DateTimeOffset?>("Created")
.HasColumnType("datetime")
.HasComment("创建时间");
b.Property<int>("GroupId")
.HasColumnType("int(11)")
.HasComment("群聊编号");
b.Property<int?>("InviteUser")
.HasColumnType("int(11)")
.HasComment("邀请用户");
b.Property<int?>("InvitedUser")
.HasColumnType("int(11)")
.HasComment("被邀请用户");
b.Property<sbyte?>("State")
.HasColumnType("tinyint(4)")
.HasComment("当前状态(0:待被邀请人同意\r\n1:被邀请人已同意)");
b.HasKey("Id")
.HasName("PRIMARY");
b.HasIndex(new[] { "GroupId" }, "GroupId");
b.HasIndex(new[] { "InviteUser" }, "InviteUser");
b.HasIndex(new[] { "InvitedUser" }, "InvitedUser");
b.ToTable("group_invite", (string)null);
MySqlEntityTypeBuilderExtensions.HasCharSet(b, "utf8mb4");
MySqlEntityTypeBuilderExtensions.UseCollation(b, "utf8mb4_general_ci");
});
modelBuilder.Entity("IM_API.Models.GroupMember", b =>
{
b.Property<int>("Id")
@ -502,6 +459,9 @@ namespace IM_API.Migrations
.HasColumnType("int(11)")
.HasComment("群聊编号\r\n");
b.Property<int?>("InviteUserId")
.HasColumnType("int");
b.Property<sbyte>("State")
.HasColumnType("tinyint(4)")
.HasComment("申请状态0:待管理员同意,1:已拒绝,2已同意");
@ -515,8 +475,7 @@ namespace IM_API.Migrations
b.HasIndex("UserId");
b.HasIndex(new[] { "GroupId" }, "GroupId")
.HasDatabaseName("GroupId1");
b.HasIndex(new[] { "GroupId" }, "GroupId");
b.ToTable("group_request", (string)null);
@ -844,6 +803,12 @@ namespace IM_API.Migrations
.HasDefaultValueSql("'1970-01-01 00:00:00'")
.HasComment("创建时间");
b.Property<string>("Description")
.HasColumnType("longtext");
b.Property<string>("Email")
.HasColumnType("longtext");
b.Property<sbyte>("IsDeleted")
.HasColumnType("tinyint(4)")
.HasComment("软删除标识\r\n0账号正常\r\n1账号已删除");
@ -863,6 +828,9 @@ namespace IM_API.Migrations
.HasColumnType("varchar(50)")
.HasComment("密码");
b.Property<string>("Region")
.HasColumnType("longtext");
b.Property<sbyte>("Status")
.ValueGeneratedOnAdd()
.HasColumnType("tinyint(4)")
@ -991,31 +959,6 @@ namespace IM_API.Migrations
b.Navigation("GroupMasterNavigation");
});
modelBuilder.Entity("IM_API.Models.GroupInvite", b =>
{
b.HasOne("IM_API.Models.Group", "Group")
.WithMany("GroupInvites")
.HasForeignKey("GroupId")
.IsRequired()
.HasConstraintName("group_invite_ibfk_2");
b.HasOne("IM_API.Models.User", "InviteUserNavigation")
.WithMany("GroupInviteInviteUserNavigations")
.HasForeignKey("InviteUser")
.HasConstraintName("group_invite_ibfk_1");
b.HasOne("IM_API.Models.User", "InvitedUserNavigation")
.WithMany("GroupInviteInvitedUserNavigations")
.HasForeignKey("InvitedUser")
.HasConstraintName("group_invite_ibfk_3");
b.Navigation("Group");
b.Navigation("InviteUserNavigation");
b.Navigation("InvitedUserNavigation");
});
modelBuilder.Entity("IM_API.Models.GroupMember", b =>
{
b.HasOne("IM_API.Models.Group", "Group")
@ -1108,8 +1051,6 @@ namespace IM_API.Migrations
modelBuilder.Entity("IM_API.Models.Group", b =>
{
b.Navigation("GroupInvites");
b.Navigation("GroupMembers");
b.Navigation("GroupRequests");
@ -1148,10 +1089,6 @@ namespace IM_API.Migrations
b.Navigation("FriendUsers");
b.Navigation("GroupInviteInviteUserNavigations");
b.Navigation("GroupInviteInvitedUserNavigations");
b.Navigation("GroupMembers");
b.Navigation("GroupRequests");

View File

@ -38,7 +38,7 @@ public partial class Group
/// <summary>
/// 群公告
/// </summary>
public string? Announcement { get; set; }
public string Announcement { get; set; } = "暂无群公告,点击编辑添加。";
/// <summary>
/// 群聊创建时间
@ -56,7 +56,6 @@ public partial class Group
public DateTimeOffset LastUpdateTime { get; set; } = DateTime.UtcNow;
public virtual ICollection<GroupInvite> GroupInvites { get; set; } = new List<GroupInvite>();
public virtual User GroupMasterNavigation { get; set; } = null!;

View File

@ -1,11 +0,0 @@
namespace IM_API.Models
{
public partial class GroupInvite
{
public GroupInviteState StateEnum
{
get => (GroupInviteState)State;
set => State = (sbyte)value;
}
}
}

View File

@ -1,17 +0,0 @@
namespace IM_API.Models
{
/// <summary>
/// 群邀请状态
/// </summary>
public enum GroupInviteState
{
/// <summary>
/// 待处理
/// </summary>
Pending = 0,
/// <summary>
/// 已同意
/// </summary>
Passed = 1
}
}

View File

@ -7,12 +7,24 @@
/// </summary>
Pending = 0,
/// <summary>
/// 已拒绝
/// 管理员已拒绝
/// </summary>
Declined = 1,
/// <summary>
/// 已同意
/// 管理员已同意
/// </summary>
Passed = 2
Passed = 2,
/// <summary>
/// 待对方同意
/// </summary>
TargetPending = 3,
/// <summary>
/// 对方拒绝
/// </summary>
TargetDeclined = 4,
/// <summary>
/// 对方同意
/// </summary>
TargetPassed = 5
}
}

View File

@ -1,41 +0,0 @@
using System;
using System.Collections.Generic;
namespace IM_API.Models;
public partial class GroupInvite
{
public int Id { get; set; }
/// <summary>
/// 群聊编号
/// </summary>
public int GroupId { get; set; }
/// <summary>
/// 被邀请用户
/// </summary>
public int? InvitedUser { get; set; }
/// <summary>
/// 邀请用户
/// </summary>
public int? InviteUser { get; set; }
/// <summary>
/// 当前状态(0:待被邀请人同意
/// 1:被邀请人已同意)
/// </summary>
public sbyte? State { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTimeOffset? Created { get; set; }
public virtual Group Group { get; set; } = null!;
public virtual User? InviteUserNavigation { get; set; }
public virtual User? InvitedUserNavigation { get; set; }
}

View File

@ -19,8 +19,10 @@ public partial class GroupRequest
/// </summary>
public int UserId { get; set; }
public int? InviteUserId { get; set; }
/// <summary>
/// 申请状态0:待管理员同意,1:已拒绝,2已同意
/// 申请状态0:待管理员同意,1:管理员已拒绝,2管理员已同意,3待对方同意,4对方拒绝
/// </summary>
public sbyte State { get; set; }

View File

@ -49,11 +49,6 @@ namespace IM_API.Models
entity.Ignore(e => e.AuhorityEnum);
});
modelBuilder.Entity<GroupInvite>(entity =>
{
entity.Ignore(e => e.StateEnum);
});
modelBuilder.Entity<GroupMember>(entity =>
{
entity.Ignore(e => e.RoleEnum);

View File

@ -27,7 +27,6 @@ public partial class ImContext : DbContext
public virtual DbSet<Group> Groups { get; set; }
public virtual DbSet<GroupInvite> GroupInvites { get; set; }
public virtual DbSet<GroupMember> GroupMembers { get; set; }
@ -362,53 +361,6 @@ public partial class ImContext : DbContext
.HasConstraintName("groups_ibfk_1");
});
modelBuilder.Entity<GroupInvite>(entity =>
{
entity.HasKey(e => e.Id).HasName("PRIMARY");
entity
.ToTable("group_invite")
.HasCharSet("utf8mb4")
.UseCollation("utf8mb4_general_ci");
entity.HasIndex(e => e.GroupId, "GroupId");
entity.HasIndex(e => e.InviteUser, "InviteUser");
entity.HasIndex(e => e.InvitedUser, "InvitedUser");
entity.Property(e => e.Id)
.HasColumnType("int(11)")
.HasColumnName("ID");
entity.Property(e => e.Created)
.HasComment("创建时间")
.HasColumnType("datetime");
entity.Property(e => e.GroupId)
.HasComment("群聊编号")
.HasColumnType("int(11)");
entity.Property(e => e.InviteUser)
.HasComment("邀请用户")
.HasColumnType("int(11)");
entity.Property(e => e.InvitedUser)
.HasComment("被邀请用户")
.HasColumnType("int(11)");
entity.Property(e => e.State)
.HasComment("当前状态(0:待被邀请人同意\r\n1:被邀请人已同意)")
.HasColumnType("tinyint(4)");
entity.HasOne(d => d.Group).WithMany(p => p.GroupInvites)
.HasForeignKey(d => d.GroupId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("group_invite_ibfk_2");
entity.HasOne(d => d.InviteUserNavigation).WithMany(p => p.GroupInviteInviteUserNavigations)
.HasForeignKey(d => d.InviteUser)
.HasConstraintName("group_invite_ibfk_1");
entity.HasOne(d => d.InvitedUserNavigation).WithMany(p => p.GroupInviteInvitedUserNavigations)
.HasForeignKey(d => d.InvitedUser)
.HasConstraintName("group_invite_ibfk_3");
});
modelBuilder.Entity<GroupMember>(entity =>
{

View File

@ -23,6 +23,18 @@ public partial class User
/// 用户昵称
/// </summary>
public string? NickName { get; set; }
/// <summary>
/// 用户邮箱
/// </summary>
public string? Email { get; set; }
/// <summary>
/// 用户签名
/// </summary>
public string? Description { get; set; } = "";
/// <summary>
/// 地区
/// </summary>
public string? Region { get; set; } = "未知地区";
/// <summary>
/// 用户在线状态
@ -73,10 +85,6 @@ public partial class User
[JsonIgnore]
public virtual ICollection<Friend> FriendUsers { get; set; } = new List<Friend>();
[JsonIgnore]
public virtual ICollection<GroupInvite> GroupInviteInviteUserNavigations { get; set; } = new List<GroupInvite>();
[JsonIgnore]
public virtual ICollection<GroupInvite> GroupInviteInvitedUserNavigations { get; set; } = new List<GroupInvite>();
[JsonIgnore]
public virtual ICollection<GroupMember> GroupMembers { get; set; } = new List<GroupMember>();
[JsonIgnore]
public virtual ICollection<GroupRequest> GroupRequests { get; set; } = new List<GroupRequest>();

View File

@ -146,7 +146,8 @@ namespace IM_API.Services
public async Task MakeConversationAsync(int userAId, int userBId, ChatType chatType)
{
var userAcExist = await _context.Conversations.AnyAsync(x => x.UserId == userAId && x.TargetId == userBId);
var userAcExist = await _context.Conversations.AnyAsync(
x => x.UserId == userAId && x.TargetId == userBId && x.ChatType == chatType);
if (userAcExist) return;
var streamKey = chatType == ChatType.PRIVATE ?
StreamKeyBuilder.Private(userAId, userBId) : StreamKeyBuilder.Group(userBId);

View File

@ -79,6 +79,7 @@ namespace IM_API.Services
}
}
public Task DeleteGroupAsync(int userId, int groupId)
{
throw new NotImplementedException();
@ -90,15 +91,15 @@ namespace IM_API.Services
x => x.Id == groupId) ?? throw new BaseException(CodeDefine.GROUP_NOT_FOUND);
//过滤非好友
var groupInviteIds = await validFriendshipAsync(userId, userIds);
var inviteList = groupInviteIds.Select(id => new GroupInvite
var inviteList = groupInviteIds.Select(id => new GroupRequest
{
Created = DateTime.UtcNow,
GroupId = group.Id,
InviteUser = userId,
InvitedUser = id,
StateEnum = GroupInviteState.Pending
UserId = id,
InviteUserId = userId,
StateEnum = GroupRequestState.TargetPending
}).ToList();
_context.GroupInvites.AddRange(inviteList);
_context.GroupRequests.AddRange(inviteList);
await _context.SaveChangesAsync();
await _endPoint.Publish(new GroupInviteEvent
{
@ -132,7 +133,7 @@ namespace IM_API.Services
throw new NotImplementedException();
}
public async Task<List<GroupInfoDto>> GetGroupListAsync(int userId, int page, int limit, bool desc)
public async Task<List<GroupInfoDto>> GetGroupListAsync(int userId, int page = 1, int limit = 50, bool desc = false)
{
var query = _context.GroupMembers
.Where(x => x.UserId == userId)
@ -159,14 +160,18 @@ namespace IM_API.Services
_context.Groups.Update(group);
await _context.SaveChangesAsync();
}
public async Task HandleGroupInviteAsync(int userid, HandleGroupInviteDto dto)
{
var user = _userService.GetUserInfoAsync(userid);
var inviteInfo = await _context.GroupInvites.FirstOrDefaultAsync(x => x.Id == dto.InviteId)
var inviteInfo = await _context.GroupRequests
.FirstOrDefaultAsync(x => x.UserId == userid && x.StateEnum == GroupRequestState.TargetPending)
?? throw new BaseException(CodeDefine.INVALID_ACTION);
if (inviteInfo.InvitedUser != userid) throw new BaseException(CodeDefine.AUTH_FAILED);
if (!(dto.Action == GroupRequestState.TargetPassed ||
dto.Action == GroupRequestState.TargetDeclined))
return;
inviteInfo.StateEnum = dto.Action;
_context.GroupInvites.Update(inviteInfo);
_context.GroupRequests.Update(inviteInfo);
await _context.SaveChangesAsync();
await _endPoint.Publish(new GroupInviteActionUpdateEvent
{
@ -176,12 +181,13 @@ namespace IM_API.Services
EventId = Guid.NewGuid(),
GroupId = inviteInfo.GroupId,
InviteId = inviteInfo.Id,
InviteUserId = inviteInfo.InviteUser.Value,
InviteUserId = inviteInfo.InviteUserId!.Value,
OperatorId = userid,
UserId = userid
});
}
public async Task HandleGroupRequestAsync(int userid, HandleGroupRequestDto dto)
{
var user = _userService.GetUserInfoAsync(userid);
@ -266,5 +272,104 @@ namespace IM_API.Services
return user;
}).ToList();
}
public async Task<GroupInfoVo> UpdateGroupInfoAsync(int userId, int groupId, GroupUpdateDto updateDto)
{
//判断群存在
var groupInfo = await _context.Groups.FirstOrDefaultAsync(x => x.Id == groupId);
if (groupInfo is null)
throw new BaseException(CodeDefine.GROUP_NOT_FOUND);
//判断操作者权限
var memberInfo = await _context.GroupMembers
.FirstOrDefaultAsync(x => x.UserId == userId && x.GroupId == groupId);
if (memberInfo is null || memberInfo.RoleEnum == GroupMemberRole.Normal)
throw new BaseException(CodeDefine.NO_GROUP_PERMISSION);
groupInfo.Name = updateDto.GroupName ?? groupInfo.Name;
groupInfo.Avatar = updateDto.Avatar ?? groupInfo.Avatar;
groupInfo.Announcement = updateDto.Description ?? groupInfo.Announcement;
_context.Groups.Update(groupInfo);
await _context.SaveChangesAsync();
return _mapper.Map<GroupInfoVo>(groupInfo);
}
public async Task<GroupInfoVo> GetGroupInfoAsync(int groupId)
{
var groupInfo = await _context.Groups.FirstOrDefaultAsync(x => x.Id == groupId);
if (groupInfo is null)
throw new BaseException(CodeDefine.GROUP_NOT_FOUND);
return _mapper.Map<GroupInfoVo>(groupInfo);
}
public async Task<List<GroupNotificationVo>> GetGroupNotificationAsync(int userId)
{
// 1. 查询群请求记录
var groupList = await _context.GroupMembers
.Where(x => x.UserId == userId &&
(x.Role == (sbyte)GroupMemberRole.Master || x.Role == (sbyte)GroupMemberRole.Administrator))
.Select(s => s.GroupId)
.ToListAsync();
var groupRequest = await _context.GroupRequests
.Where(x => groupList.Contains(x.GroupId) || x.UserId == userId || x.InviteUserId == userId)
.OrderByDescending(o => o.Id)
.ToListAsync();
if (!groupRequest.Any()) return new List<GroupNotificationVo>();
// 2. 收集所有需要的 ID 并去重
var userIds = groupRequest.Select(s => s.UserId).Distinct().ToList();
var inviteUserIds = groupRequest.Where(x => x.InviteUserId != null).Select(s => s.InviteUserId.Value).Distinct().ToList();
var groupIds = groupRequest.Select(s => s.GroupId).Distinct().ToList();
var userList = await _userService.GetUserInfoListAsync(userIds);
var inviteUserList = await _userService.GetUserInfoListAsync(inviteUserIds);
var groupInfoList = await _context.Groups
.Where(x => groupIds.Contains(x.Id))
.ToListAsync();
// 2. 转换为字典
var userDict = userList.ToDictionary(u => u.Id);
var inviteUserDict = inviteUserList.ToDictionary(u => u.Id);
var groupDict = groupInfoList.ToDictionary(g => g.Id);
// 3. 组装数据 (Select 逻辑不变)
return groupRequest.Select(g =>
{
var gnv = _mapper.Map<GroupNotificationVo>(g);
// 匹配用户信息
if (userDict.TryGetValue(g.UserId, out var u))
{
gnv.UserAvatar = u.Avatar;
gnv.NickName = u.NickName;
}
// 匹配邀请人信息
if (g.InviteUserId.HasValue && inviteUserDict.TryGetValue(g.InviteUserId.Value, out var i))
{
gnv.InviteUserAvatar = i.Avatar;
gnv.InviteUserNickname = i.NickName;
}
// 匹配群信息
if (groupDict.TryGetValue(g.GroupId, out var gi))
{
gnv.GroupAvatar = gi.Avatar;
gnv.GroupName = gi.Name;
}
return gnv;
}).ToList();
}
}
}

View File

@ -0,0 +1,8 @@
using IM_API.Dtos.Group;
namespace IM_API.VOs.Group
{
public class GroupInfoVo:GroupInfoDto
{
}
}

View File

@ -8,6 +8,6 @@ namespace IM_API.VOs.Group
public int InviteUserId { get; set; }
public int InvitedUserId { get; set; }
public int InviteId { get; set; }
public GroupInviteState Action { get; set; }
public GroupRequestState Action { get; set; }
}
}

View File

@ -0,0 +1,21 @@
using IM_API.Models;
namespace IM_API.VOs.Group
{
public class GroupNotificationVo
{
public int RequestId { get; set; }
public int? UserId { get; set; }
public string? NickName { get; set; }
public string? UserAvatar { get; set; }
public int GroupId { get; set; }
public string? GroupAvatar { get; set; }
public string? GroupName { get; set; }
public GroupRequestState Status { get; set; }
public string Description { get; set; }
public int? InviteUser { get; set; }
public string? InviteUserNickname { get; set; }
public string? InviteUserAvatar { get; set; }
}
}

View File

@ -10,6 +10,9 @@ pluginManagement {
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
// 👇 添加这一行,用于下载 Flutter 插件相关的依赖
maven { url = uri("https://storage.flutter-io.cn/download.flutter.io") }
maven { url = uri("https://maven.aliyun.com/repository/google") }
maven { url = uri("https://maven.aliyun.com/repository/public") }
gradlePluginPortal()
@ -21,6 +24,9 @@ pluginManagement {
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
repositories {
// 👇 添加这一行,这是解决你报错的核心!强制项目从这里下载 Flutter 引擎
maven { url = uri("https://storage.flutter-io.cn/download.flutter.io") }
maven { url = uri("https://maven.aliyun.com/repository/google") }
maven { url = uri("https://maven.aliyun.com/repository/public") }
gradlePluginPortal()
@ -31,8 +37,10 @@ dependencyResolutionManagement {
plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.1.1" apply false
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
// 👇 升级到 8.2.1 修复 Java 21 兼容性 bug
id("com.android.application") version "8.2.1" apply false
// 👇 顺便把 Kotlin 版本也稍微升一下,避免后续出现旧版本警告
id("org.jetbrains.kotlin.android") version "1.9.22" apply false
}
include(":app")

View File

@ -0,0 +1,9 @@
import 'package:dio/dio.dart';
class AuthInterceptor extends Interceptor{
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
// TODO: implement onRequest
super.onRequest(options, handler);
}
}

View File

@ -0,0 +1,21 @@
import 'package:app/core/network/auth_interceptor.dart';
import 'package:dio/dio.dart';
class Request {
static final Request _instance = Request._internal();
factory Request() => _instance;
late Dio dio;
Request._internal(){
BaseOptions options = BaseOptions(
baseUrl: "",
responseType: ResponseType.json,
contentType: 'application/json; charset=utf-8',
);
dio = Dio(options);
dio.interceptors.addAll([
AuthInterceptor()
]);
}
}

View File

@ -1,6 +1,7 @@
import 'package:app/features/auth/pages/login_page.dart';
import 'package:app/features/auth/pages/register_page.dart';
import 'package:app/features/home/pages/index_page.dart';
import 'package:go_router/go_router.dart';
@ -10,6 +11,7 @@ final appRouter = GoRouter(
initialLocation: '/auth/login',
routes: [
GoRoute(path: '/auth/login', builder: (context, state) => const LoginPage()),
GoRoute(path: '/auth/register', builder: (context, state) => const RegisterPage()),
ShellRoute(
builder: (context, state, child) {
return MainPage(child: child);

View File

@ -1,6 +1,7 @@
import 'package:app/core/constants/app_colors.dart';
import 'package:app/features/auth/pages/login_page.dart';
import 'package:flutter/material.dart';
import 'package:app/core/router/app_router.dart';
class LoginPageState extends State<LoginPage> {
@override
@ -11,10 +12,10 @@ class LoginPageState extends State<LoginPage> {
backgroundColor: Colors.transparent,
elevation: 0,
actions: [
TextButton(
onPressed: () {},
child: const Text("找回密码", style: TextStyle(color: Colors.grey)),
),
// TextButton(
// onPressed: () {},
// child: const Text("找回密码", style: TextStyle(color: Colors.grey)),
// ),
],
),
body: SingleChildScrollView(
@ -24,23 +25,9 @@ class LoginPageState extends State<LoginPage> {
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 20),
// 1. Logo/
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: AppColors.primaryColor.withOpacity(0.1),
shape: BoxShape.circle,
),
child: const Icon(
Icons.person_rounded,
size: 60,
color: AppColors.primaryColor,
),
),
const SizedBox(height: 24),
const Text(
"录您的聊天账号",
"登陆账号",
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
@ -109,7 +96,9 @@ class LoginPageState extends State<LoginPage> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: () {},
onPressed: () {
appRouter.push("/auth/register");
},
child: const Text(
"注册账号",
style: TextStyle(color: Color(0xFF576B95)),
@ -126,6 +115,13 @@ class LoginPageState extends State<LoginPage> {
style: TextStyle(color: Color(0xFF576B95)),
),
),
TextButton(
onPressed: () {},
child: const Text(
"找回密码",
style: TextStyle(color: Color(0xFF576B95)),
),
),
],
),

View File

@ -0,0 +1,156 @@
import 'package:app/features/auth/pages/register_page.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../../../core/constants/app_colors.dart';
class RegisterPageState extends State<RegisterPage> {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
actions: [
// TextButton(
// onPressed: () {},
// child: const Text("找回密码", style: TextStyle(color: Colors.grey)),
// ),
],
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 40),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 20),
const SizedBox(height: 24),
const Text(
"注册账号",
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
const SizedBox(height: 60),
// 2. (线)
TextField(
decoration: InputDecoration(
labelText: "用户名",
labelStyle: const TextStyle(color: Colors.grey, fontSize: 14),
floatingLabelStyle: const TextStyle(color: AppColors.primaryColor),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.grey.shade300),
),
focusedBorder: const UnderlineInputBorder(
borderSide: BorderSide(color: AppColors.primaryColor, width: 2),
),
),
),
const SizedBox(height: 25),
// 3.
TextField(
obscureText: true,
decoration: InputDecoration(
labelText: "请输入密码",
labelStyle: const TextStyle(color: Colors.grey, fontSize: 14),
floatingLabelStyle: const TextStyle(color: AppColors.primaryColor),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.grey.shade300),
),
focusedBorder: const UnderlineInputBorder(
borderSide: BorderSide(color: AppColors.primaryColor, width: 2),
),
),
),
const SizedBox(height: 60),
// 4. ()
SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primaryColor,
foregroundColor: Colors.white,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
child: const Text(
"注 册",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
),
),
),
const SizedBox(height: 20),
// 5. /
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: () {},
child: const Text(
"已有账号?点我登录",
style: TextStyle(color: Color(0xFF576B95)),
), //
),
const SizedBox(
height: 20,
child: VerticalDivider(color: Colors.grey),
),
TextButton(
onPressed: () {},
child: const Text(
"找回密码",
style: TextStyle(color: Color(0xFF576B95)),
),
),
],
),
const SizedBox(height: 80),
// 6. (App必有)
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Checkbox(
value: true,
activeColor: AppColors.primaryColor,
onChanged: (v) {},
),
const Text(
"我已阅读并同意",
style: TextStyle(color: Colors.grey, fontSize: 12),
),
const Text(
"《用户协议》",
style: TextStyle(color: Color(0xFF576B95), fontSize: 12),
),
const Text(
"",
style: TextStyle(color: Colors.grey, fontSize: 12),
),
const Text(
"《隐私政策》",
style: TextStyle(color: Color(0xFF576B95), fontSize: 12),
),
],
),
],
),
),
),
);
}
}

View File

@ -0,0 +1,12 @@
import 'package:app/features/auth/bloc/register_page_state.dart';
import 'package:flutter/cupertino.dart';
class RegisterPage extends StatefulWidget {
const RegisterPage({super.key});
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return RegisterPageState();
}
}

View File

@ -5,16 +5,16 @@ packages:
dependency: transitive
description:
name: async
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
url: "https://pub.dev"
sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.13.0"
version: "2.13.1"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.2"
characters:
@ -22,7 +22,7 @@ packages:
description:
name: characters
sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.4.1"
clock:
@ -30,7 +30,7 @@ packages:
description:
name: clock
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.2"
collection:
@ -38,23 +38,39 @@ packages:
description:
name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.19.1"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
url: "https://pub.dev"
sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.8"
version: "1.0.9"
dio:
dependency: "direct main"
description:
name: dio
sha256: aff32c08f92787a557dd5c0145ac91536481831a01b4648136373cddb0e64f8c
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.9.2"
dio_web_adapter:
dependency: transitive
description:
name: dio_web_adapter
sha256: "2f9e64323a7c3c7ef69567d5c800424a11f8337b8b228bad02524c9fb3c1f340"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.2"
fake_async:
dependency: transitive
description:
name: fake_async
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.3.3"
flutter:
@ -67,7 +83,7 @@ packages:
description:
name: flutter_lints
sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "6.0.0"
flutter_test:
@ -85,15 +101,23 @@ packages:
description:
name: go_router
sha256: "7974313e217a7771557add6ff2238acb63f635317c35fa590d348fb238f00896"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "17.1.0"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.1.2"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "11.0.2"
leak_tracker_flutter_testing:
@ -101,7 +125,7 @@ packages:
description:
name: leak_tracker_flutter_testing
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.10"
leak_tracker_testing:
@ -109,7 +133,7 @@ packages:
description:
name: leak_tracker_testing
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.2"
lints:
@ -117,7 +141,7 @@ packages:
description:
name: lints
sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "6.1.0"
logging:
@ -125,7 +149,7 @@ packages:
description:
name: logging
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.3.0"
matcher:
@ -133,7 +157,7 @@ packages:
description:
name: matcher
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.12.18"
material_color_utilities:
@ -141,7 +165,7 @@ packages:
description:
name: material_color_utilities
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.13.0"
meta:
@ -149,15 +173,23 @@ packages:
description:
name: meta
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.17.0"
mime:
dependency: transitive
description:
name: mime
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
path:
dependency: transitive
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.9.1"
sky_engine:
@ -170,7 +202,7 @@ packages:
description:
name: source_span
sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.10.2"
stack_trace:
@ -178,7 +210,7 @@ packages:
description:
name: stack_trace
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.12.1"
stream_channel:
@ -186,7 +218,7 @@ packages:
description:
name: stream_channel
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.4"
string_scanner:
@ -194,7 +226,7 @@ packages:
description:
name: string_scanner
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.4.1"
term_glyph:
@ -202,7 +234,7 @@ packages:
description:
name: term_glyph
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.2"
test_api:
@ -210,15 +242,23 @@ packages:
description:
name: test_api
sha256: "19a78f63e83d3a61f00826d09bc2f60e191bf3504183c001262be6ac75589fb8"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.7.8"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.4.0"
vector_math:
dependency: transitive
description:
name: vector_math
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.2.0"
vm_service:
@ -226,9 +266,17 @@ packages:
description:
name: vm_service
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
url: "https://pub.dev"
url: "https://pub.flutter-io.cn"
source: hosted
version: "15.0.2"
web:
dependency: transitive
description:
name: web
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.1"
sdks:
dart: ">=3.10.4 <4.0.0"
flutter: ">=3.35.0"

View File

@ -38,6 +38,7 @@ dependencies:
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
go_router: ^17.0.1
dio: ^5.9.2
dev_dependencies:
flutter_test:

View File

@ -11,6 +11,7 @@
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite.cmd"
},
"runtimeArgs": ["--sourcemap"],
"console": "integratedTerminal",
"env": {
"REMOTE_DEBUGGING_PORT": "9222"
}

View File

@ -3,7 +3,7 @@
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
"editor.defaultFormatter": "vscode.typescript-language-features"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"

View File

@ -1,16 +1,20 @@
import { resolve } from 'path'
import { defineConfig } from 'electron-vite'
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'
export default defineConfig({
main: {},
preload: {},
renderer: {
server: {
host: true
},
resolve: {
alias: {
'@': resolve('src/renderer/src')
}
},
plugins: [vue()]
plugins: [vue(), vueDevTools()]
}
})

View File

@ -16,6 +16,7 @@
"@vuelidate/core": "^2.0.3",
"@vuelidate/validators": "^2.0.4",
"axios": "^1.13.2",
"crypto": "^1.0.1",
"electron-updater": "^6.3.9",
"feather-icons": "^4.29.2",
"hevue-img-preview": "^7.1.3",
@ -38,6 +39,7 @@
"eslint-plugin-vue": "^10.6.2",
"prettier": "^3.7.4",
"vite": "^7.2.6",
"vite-plugin-vue-devtools": "^8.0.7",
"vue": "^3.5.25",
"vue-eslint-parser": "^10.2.0"
}
@ -115,6 +117,19 @@
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-annotate-as-pure": {
"version": "7.27.3",
"resolved": "https://registry.npmmirror.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz",
"integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.27.3"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-compilation-targets": {
"version": "7.28.6",
"resolved": "https://registry.npmmirror.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
@ -132,6 +147,28 @@
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-create-class-features-plugin": {
"version": "7.28.6",
"resolved": "https://registry.npmmirror.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz",
"integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.27.3",
"@babel/helper-member-expression-to-functions": "^7.28.5",
"@babel/helper-optimise-call-expression": "^7.27.1",
"@babel/helper-replace-supers": "^7.28.6",
"@babel/helper-skip-transparent-expression-wrappers": "^7.27.1",
"@babel/traverse": "^7.28.6",
"semver": "^6.3.1"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0"
}
},
"node_modules/@babel/helper-globals": {
"version": "7.28.0",
"resolved": "https://registry.npmmirror.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
@ -142,6 +179,20 @@
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-member-expression-to-functions": {
"version": "7.28.5",
"resolved": "https://registry.npmmirror.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz",
"integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/traverse": "^7.28.5",
"@babel/types": "^7.28.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-imports": {
"version": "7.28.6",
"resolved": "https://registry.npmmirror.com/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
@ -174,6 +225,19 @@
"@babel/core": "^7.0.0"
}
},
"node_modules/@babel/helper-optimise-call-expression": {
"version": "7.27.1",
"resolved": "https://registry.npmmirror.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz",
"integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/types": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-plugin-utils": {
"version": "7.28.6",
"resolved": "https://registry.npmmirror.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
@ -184,6 +248,38 @@
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-replace-supers": {
"version": "7.28.6",
"resolved": "https://registry.npmmirror.com/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz",
"integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-member-expression-to-functions": "^7.28.5",
"@babel/helper-optimise-call-expression": "^7.27.1",
"@babel/traverse": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0"
}
},
"node_modules/@babel/helper-skip-transparent-expression-wrappers": {
"version": "7.27.1",
"resolved": "https://registry.npmmirror.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz",
"integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/traverse": "^7.27.1",
"@babel/types": "^7.27.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-string-parser": {
"version": "7.27.1",
"resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
@ -241,6 +337,101 @@
"node": ">=6.0.0"
}
},
"node_modules/@babel/plugin-proposal-decorators": {
"version": "7.29.0",
"resolved": "https://registry.npmmirror.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.29.0.tgz",
"integrity": "sha512-CVBVv3VY/XRMxRYq5dwr2DS7/MvqPm23cOCjbwNnVrfOqcWlnefua1uUs0sjdKOGjvPUG633o07uWzJq4oI6dA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-create-class-features-plugin": "^7.28.6",
"@babel/helper-plugin-utils": "^7.28.6",
"@babel/plugin-syntax-decorators": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/plugin-syntax-decorators": {
"version": "7.28.6",
"resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.28.6.tgz",
"integrity": "sha512-71EYI0ONURHJBL4rSFXnITXqXrrY8q4P0q006DPfN+Rk+ASM+++IBXem/ruokgBZR8YNEWZ8R6B+rCb8VcUTqA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/plugin-syntax-import-attributes": {
"version": "7.28.6",
"resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz",
"integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/plugin-syntax-import-meta": {
"version": "7.10.4",
"resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
"integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.10.4"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/plugin-syntax-jsx": {
"version": "7.28.6",
"resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz",
"integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/plugin-syntax-typescript": {
"version": "7.28.6",
"resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz",
"integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-plugin-utils": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/plugin-transform-arrow-functions": {
"version": "7.27.1",
"resolved": "https://registry.npmmirror.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz",
@ -257,6 +448,26 @@
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/plugin-transform-typescript": {
"version": "7.28.6",
"resolved": "https://registry.npmmirror.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz",
"integrity": "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.27.3",
"@babel/helper-create-class-features-plugin": "^7.28.6",
"@babel/helper-plugin-utils": "^7.28.6",
"@babel/helper-skip-transparent-expression-wrappers": "^7.27.1",
"@babel/plugin-syntax-typescript": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/template": {
"version": "7.28.6",
"resolved": "https://registry.npmmirror.com/@babel/template/-/template-7.28.6.tgz",
@ -1863,6 +2074,13 @@
"url": "https://opencollective.com/pkgr"
}
},
"node_modules/@polka/url": {
"version": "1.0.0-next.29",
"resolved": "https://registry.npmmirror.com/@polka/url/-/url-1.0.0-next.29.tgz",
"integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
"dev": true,
"license": "MIT"
},
"node_modules/@rolldown/pluginutils": {
"version": "1.0.0-rc.2",
"resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz",
@ -2377,6 +2595,59 @@
"vue": "^3.2.25"
}
},
"node_modules/@vue/babel-helper-vue-transform-on": {
"version": "1.5.0",
"resolved": "https://registry.npmmirror.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.5.0.tgz",
"integrity": "sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==",
"dev": true,
"license": "MIT"
},
"node_modules/@vue/babel-plugin-jsx": {
"version": "1.5.0",
"resolved": "https://registry.npmmirror.com/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.5.0.tgz",
"integrity": "sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.27.1",
"@babel/helper-plugin-utils": "^7.27.1",
"@babel/plugin-syntax-jsx": "^7.27.1",
"@babel/template": "^7.27.2",
"@babel/traverse": "^7.28.0",
"@babel/types": "^7.28.2",
"@vue/babel-helper-vue-transform-on": "1.5.0",
"@vue/babel-plugin-resolve-type": "1.5.0",
"@vue/shared": "^3.5.18"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
},
"peerDependenciesMeta": {
"@babel/core": {
"optional": true
}
}
},
"node_modules/@vue/babel-plugin-resolve-type": {
"version": "1.5.0",
"resolved": "https://registry.npmmirror.com/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.5.0.tgz",
"integrity": "sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/helper-module-imports": "^7.27.1",
"@babel/helper-plugin-utils": "^7.27.1",
"@babel/parser": "^7.28.0",
"@vue/compiler-sfc": "^3.5.18"
},
"funding": {
"url": "https://github.com/sponsors/sxzz"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@vue/compiler-core": {
"version": "3.5.28",
"resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.28.tgz",
@ -2436,6 +2707,47 @@
"@vue/devtools-kit": "^7.7.9"
}
},
"node_modules/@vue/devtools-core": {
"version": "8.0.7",
"resolved": "https://registry.npmmirror.com/@vue/devtools-core/-/devtools-core-8.0.7.tgz",
"integrity": "sha512-PmpiPxvg3Of80ODHVvyckxwEW1Z02VIAvARIZS1xegINn3VuNQLm9iHUmKD+o6cLkMNWV8OG8x7zo0kgydZgdg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vue/devtools-kit": "^8.0.7",
"@vue/devtools-shared": "^8.0.7"
},
"peerDependencies": {
"vue": "^3.0.0"
}
},
"node_modules/@vue/devtools-core/node_modules/@vue/devtools-kit": {
"version": "8.0.7",
"resolved": "https://registry.npmmirror.com/@vue/devtools-kit/-/devtools-kit-8.0.7.tgz",
"integrity": "sha512-H6esJGHGl5q0E9iV3m2EoBQHJ+V83WMW83A0/+Fn95eZ2iIvdsq4+UCS6yT/Fdd4cGZSchx/MdWDreM3WqMsDw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vue/devtools-shared": "^8.0.7",
"birpc": "^2.6.1",
"hookable": "^5.5.3",
"perfect-debounce": "^2.0.0"
}
},
"node_modules/@vue/devtools-core/node_modules/@vue/devtools-shared": {
"version": "8.0.7",
"resolved": "https://registry.npmmirror.com/@vue/devtools-shared/-/devtools-shared-8.0.7.tgz",
"integrity": "sha512-CgAb9oJH5NUmbQRdYDj/1zMiaICYSLtm+B1kxcP72LBrifGAjUmt8bx52dDH1gWRPlQgxGPqpAMKavzVirAEhA==",
"dev": true,
"license": "MIT"
},
"node_modules/@vue/devtools-core/node_modules/perfect-debounce": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/perfect-debounce/-/perfect-debounce-2.1.0.tgz",
"integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==",
"dev": true,
"license": "MIT"
},
"node_modules/@vue/devtools-kit": {
"version": "7.7.9",
"resolved": "https://registry.npmmirror.com/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz",
@ -2723,6 +3035,16 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/ansis": {
"version": "4.2.0",
"resolved": "https://registry.npmmirror.com/ansis/-/ansis-4.2.0.tgz",
"integrity": "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=14"
}
},
"node_modules/app-builder-bin": {
"version": "5.0.0-alpha.12",
"resolved": "https://registry.npmmirror.com/app-builder-bin/-/app-builder-bin-5.0.0-alpha.12.tgz",
@ -3212,6 +3534,22 @@
"node": ">= 10.0.0"
}
},
"node_modules/bundle-name": {
"version": "4.1.0",
"resolved": "https://registry.npmmirror.com/bundle-name/-/bundle-name-4.1.0.tgz",
"integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"run-applescript": "^7.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/cac": {
"version": "6.7.14",
"resolved": "https://registry.npmmirror.com/cac/-/cac-6.7.14.tgz",
@ -3656,6 +3994,13 @@
"node": ">= 8"
}
},
"node_modules/crypto": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/crypto/-/crypto-1.0.1.tgz",
"integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==",
"deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in.",
"license": "ISC"
},
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/cssesc/-/cssesc-3.0.0.tgz",
@ -3739,6 +4084,36 @@
"dev": true,
"license": "MIT"
},
"node_modules/default-browser": {
"version": "5.5.0",
"resolved": "https://registry.npmmirror.com/default-browser/-/default-browser-5.5.0.tgz",
"integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==",
"dev": true,
"license": "MIT",
"dependencies": {
"bundle-name": "^4.1.0",
"default-browser-id": "^5.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/default-browser-id": {
"version": "5.0.1",
"resolved": "https://registry.npmmirror.com/default-browser-id/-/default-browser-id-5.0.1.tgz",
"integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/defaults": {
"version": "1.0.4",
"resolved": "https://registry.npmmirror.com/defaults/-/defaults-1.0.4.tgz",
@ -3779,6 +4154,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/define-lazy-prop": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
"integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/define-properties": {
"version": "1.2.1",
"resolved": "https://registry.npmmirror.com/define-properties/-/define-properties-1.2.1.tgz",
@ -4355,6 +4743,16 @@
"dev": true,
"license": "MIT"
},
"node_modules/error-stack-parser-es": {
"version": "1.0.5",
"resolved": "https://registry.npmmirror.com/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz",
"integrity": "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz",
@ -5671,6 +6069,22 @@
"node": ">= 12"
}
},
"node_modules/is-docker": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/is-docker/-/is-docker-3.0.0.tgz",
"integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
"dev": true,
"license": "MIT",
"bin": {
"is-docker": "cli.js"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz",
@ -5704,6 +6118,25 @@
"node": ">=0.10.0"
}
},
"node_modules/is-inside-container": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/is-inside-container/-/is-inside-container-1.0.0.tgz",
"integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-docker": "^3.0.0"
},
"bin": {
"is-inside-container": "cli.js"
},
"engines": {
"node": ">=14.16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/is-interactive": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/is-interactive/-/is-interactive-1.0.0.tgz",
@ -5739,6 +6172,22 @@
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/is-wsl": {
"version": "3.1.1",
"resolved": "https://registry.npmmirror.com/is-wsl/-/is-wsl-3.1.1.tgz",
"integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-inside-container": "^1.0.0"
},
"engines": {
"node": ">=16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/isbinaryfile": {
"version": "5.0.7",
"resolved": "https://registry.npmmirror.com/isbinaryfile/-/isbinaryfile-5.0.7.tgz",
@ -5902,6 +6351,13 @@
"json-buffer": "3.0.1"
}
},
"node_modules/kolorist": {
"version": "1.8.0",
"resolved": "https://registry.npmmirror.com/kolorist/-/kolorist-1.8.0.tgz",
"integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==",
"dev": true,
"license": "MIT"
},
"node_modules/lazy-val": {
"version": "1.0.5",
"resolved": "https://registry.npmmirror.com/lazy-val/-/lazy-val-1.0.5.tgz",
@ -6313,6 +6769,16 @@
"mkdirp": "bin/cmd.js"
}
},
"node_modules/mrmime": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/mrmime/-/mrmime-2.0.1.tgz",
"integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
}
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
@ -6533,6 +6999,13 @@
"node": ">= 0.4"
}
},
"node_modules/ohash": {
"version": "2.0.11",
"resolved": "https://registry.npmmirror.com/ohash/-/ohash-2.0.11.tgz",
"integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==",
"dev": true,
"license": "MIT"
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz",
@ -6558,6 +7031,25 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/open": {
"version": "10.2.0",
"resolved": "https://registry.npmmirror.com/open/-/open-10.2.0.tgz",
"integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==",
"dev": true,
"license": "MIT",
"dependencies": {
"default-browser": "^5.2.1",
"define-lazy-prop": "^3.0.0",
"is-inside-container": "^1.0.0",
"wsl-utils": "^0.1.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.9.4.tgz",
@ -6728,6 +7220,13 @@
"dev": true,
"license": "ISC"
},
"node_modules/pathe": {
"version": "2.0.3",
"resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz",
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
"dev": true,
"license": "MIT"
},
"node_modules/pe-library": {
"version": "0.4.1",
"resolved": "https://registry.npmmirror.com/pe-library/-/pe-library-0.4.1.tgz",
@ -7225,6 +7724,19 @@
"fsevents": "~2.3.2"
}
},
"node_modules/run-applescript": {
"version": "7.1.0",
"resolved": "https://registry.npmmirror.com/run-applescript/-/run-applescript-7.1.0.tgz",
"integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz",
@ -7366,6 +7878,21 @@
"node": ">=10"
}
},
"node_modules/sirv": {
"version": "3.0.2",
"resolved": "https://registry.npmmirror.com/sirv/-/sirv-3.0.2.tgz",
"integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@polka/url": "^1.0.0-next.24",
"mrmime": "^2.0.0",
"totalist": "^3.0.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/slice-ansi": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-3.0.0.tgz",
@ -7798,6 +8325,16 @@
"integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==",
"license": "MIT"
},
"node_modules/totalist": {
"version": "3.0.1",
"resolved": "https://registry.npmmirror.com/totalist/-/totalist-3.0.1.tgz",
"integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/tough-cookie": {
"version": "4.1.4",
"resolved": "https://registry.npmmirror.com/tough-cookie/-/tough-cookie-4.1.4.tgz",
@ -7911,6 +8448,23 @@
"node": ">= 4.0.0"
}
},
"node_modules/unplugin-utils": {
"version": "0.3.1",
"resolved": "https://registry.npmmirror.com/unplugin-utils/-/unplugin-utils-0.3.1.tgz",
"integrity": "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==",
"dev": true,
"license": "MIT",
"dependencies": {
"pathe": "^2.0.3",
"picomatch": "^4.0.3"
},
"engines": {
"node": ">=20.19.0"
},
"funding": {
"url": "https://github.com/sponsors/sxzz"
}
},
"node_modules/update-browserslist-db": {
"version": "1.2.3",
"resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
@ -8092,6 +8646,144 @@
}
}
},
"node_modules/vite-dev-rpc": {
"version": "1.1.0",
"resolved": "https://registry.npmmirror.com/vite-dev-rpc/-/vite-dev-rpc-1.1.0.tgz",
"integrity": "sha512-pKXZlgoXGoE8sEKiKJSng4hI1sQ4wi5YT24FCrwrLt6opmkjlqPPVmiPWWJn8M8byMxRGzp1CrFuqQs4M/Z39A==",
"dev": true,
"license": "MIT",
"dependencies": {
"birpc": "^2.4.0",
"vite-hot-client": "^2.1.0"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0"
}
},
"node_modules/vite-hot-client": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/vite-hot-client/-/vite-hot-client-2.1.0.tgz",
"integrity": "sha512-7SpgZmU7R+dDnSmvXE1mfDtnHLHQSisdySVR7lO8ceAXvM0otZeuQQ6C8LrS5d/aYyP/QZ0hI0L+dIPrm4YlFQ==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"vite": "^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0"
}
},
"node_modules/vite-plugin-inspect": {
"version": "11.3.3",
"resolved": "https://registry.npmmirror.com/vite-plugin-inspect/-/vite-plugin-inspect-11.3.3.tgz",
"integrity": "sha512-u2eV5La99oHoYPHE6UvbwgEqKKOQGz86wMg40CCosP6q8BkB6e5xPneZfYagK4ojPJSj5anHCrnvC20DpwVdRA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansis": "^4.1.0",
"debug": "^4.4.1",
"error-stack-parser-es": "^1.0.5",
"ohash": "^2.0.11",
"open": "^10.2.0",
"perfect-debounce": "^2.0.0",
"sirv": "^3.0.1",
"unplugin-utils": "^0.3.0",
"vite-dev-rpc": "^1.1.0"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"vite": "^6.0.0 || ^7.0.0-0"
},
"peerDependenciesMeta": {
"@nuxt/kit": {
"optional": true
}
}
},
"node_modules/vite-plugin-inspect/node_modules/perfect-debounce": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/perfect-debounce/-/perfect-debounce-2.1.0.tgz",
"integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==",
"dev": true,
"license": "MIT"
},
"node_modules/vite-plugin-vue-devtools": {
"version": "8.0.7",
"resolved": "https://registry.npmmirror.com/vite-plugin-vue-devtools/-/vite-plugin-vue-devtools-8.0.7.tgz",
"integrity": "sha512-BWj/ykGpqVAJVdPyHmSTUm44buz3jPv+6jnvuFdQSRH0kAgP1cEIE4doHiFyqHXOmuB5EQVR/nh2g9YRiRNs9g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vue/devtools-core": "^8.0.7",
"@vue/devtools-kit": "^8.0.7",
"@vue/devtools-shared": "^8.0.7",
"sirv": "^3.0.2",
"vite-plugin-inspect": "^11.3.3",
"vite-plugin-vue-inspector": "^5.3.2"
},
"engines": {
"node": ">=v14.21.3"
},
"peerDependencies": {
"vite": "^6.0.0 || ^7.0.0-0 || ^8.0.0-0"
}
},
"node_modules/vite-plugin-vue-devtools/node_modules/@vue/devtools-kit": {
"version": "8.0.7",
"resolved": "https://registry.npmmirror.com/@vue/devtools-kit/-/devtools-kit-8.0.7.tgz",
"integrity": "sha512-H6esJGHGl5q0E9iV3m2EoBQHJ+V83WMW83A0/+Fn95eZ2iIvdsq4+UCS6yT/Fdd4cGZSchx/MdWDreM3WqMsDw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vue/devtools-shared": "^8.0.7",
"birpc": "^2.6.1",
"hookable": "^5.5.3",
"perfect-debounce": "^2.0.0"
}
},
"node_modules/vite-plugin-vue-devtools/node_modules/@vue/devtools-shared": {
"version": "8.0.7",
"resolved": "https://registry.npmmirror.com/@vue/devtools-shared/-/devtools-shared-8.0.7.tgz",
"integrity": "sha512-CgAb9oJH5NUmbQRdYDj/1zMiaICYSLtm+B1kxcP72LBrifGAjUmt8bx52dDH1gWRPlQgxGPqpAMKavzVirAEhA==",
"dev": true,
"license": "MIT"
},
"node_modules/vite-plugin-vue-devtools/node_modules/perfect-debounce": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/perfect-debounce/-/perfect-debounce-2.1.0.tgz",
"integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==",
"dev": true,
"license": "MIT"
},
"node_modules/vite-plugin-vue-inspector": {
"version": "5.3.2",
"resolved": "https://registry.npmmirror.com/vite-plugin-vue-inspector/-/vite-plugin-vue-inspector-5.3.2.tgz",
"integrity": "sha512-YvEKooQcSiBTAs0DoYLfefNja9bLgkFM7NI2b07bE2SruuvX0MEa9cMaxjKVMkeCp5Nz9FRIdcN1rOdFVBeL6Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.23.0",
"@babel/plugin-proposal-decorators": "^7.23.0",
"@babel/plugin-syntax-import-attributes": "^7.22.5",
"@babel/plugin-syntax-import-meta": "^7.10.4",
"@babel/plugin-transform-typescript": "^7.22.15",
"@vue/babel-plugin-jsx": "^1.1.5",
"@vue/compiler-dom": "^3.3.4",
"kolorist": "^1.8.0",
"magic-string": "^0.30.4"
},
"peerDependencies": {
"vite": "^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0"
}
},
"node_modules/vite/node_modules/@esbuild/aix-ppc64": {
"version": "0.27.3",
"resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz",
@ -8771,6 +9463,22 @@
}
}
},
"node_modules/wsl-utils": {
"version": "0.1.0",
"resolved": "https://registry.npmmirror.com/wsl-utils/-/wsl-utils-0.1.0.tgz",
"integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-wsl": "^3.1.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/xml-name-validator": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz",

View File

@ -25,6 +25,7 @@
"@vuelidate/core": "^2.0.3",
"@vuelidate/validators": "^2.0.4",
"axios": "^1.13.2",
"crypto": "^1.0.1",
"electron-updater": "^6.3.9",
"feather-icons": "^4.29.2",
"hevue-img-preview": "^7.1.3",
@ -47,6 +48,7 @@
"eslint-plugin-vue": "^10.6.2",
"prettier": "^3.7.4",
"vite": "^7.2.6",
"vite-plugin-vue-devtools": "^8.0.7",
"vue": "^3.5.25",
"vue-eslint-parser": "^10.2.0"
}

13
frontend/pc/IM/src/cache/cacheDir.js vendored Normal file
View File

@ -0,0 +1,13 @@
import { app } from "electron";
import path from 'path';
export const CACHE_ROOT = path.join(app.getPath('userData'), 'resource_cache')
export const PROTOCOL_HEAD = 'ql-im://'
export const DIRS = {
Image: 'images',
Video: 'videos',
Voice: 'voices',
File: 'files',
}

View File

@ -0,0 +1,35 @@
import path from "path";
import { FILE_TYPE } from "../renderer/src/constants/fileTypeDefine";
import { DIRS, CACHE_ROOT, PROTOCOL_HEAD } from "./cacheDir";
import crypto from 'crypto'
import fs from 'fs-extra'
import axios from "axios";
export const getCacheResorce = async (url, type = FILE_TYPE.Image) => {
const hash = crypto.createHash('md5').update(url).digest('hex')
const subDir = hash.substring(0,2);
const targetPath = path.join(DIRS[type], subDir)
const filePath = path.join(targetPath, hash)
if(await fs.pathExists(path.join(CACHE_ROOT, filePath))){
return PROTOCOL_HEAD + filePath.replaceAll('\\', '/')
}
await fs.ensureDir(path.join(CACHE_ROOT, targetPath))
const writer = fs.createWriteStream(path.join(CACHE_ROOT, filePath))
const response = await axios({
url,
method: 'GET',
responseType: 'stream'
})
response.data.pipe(writer)
return new Promise((resolve, reject) => {
writer.on('finish', () => resolve(PROTOCOL_HEAD + filePath.replaceAll('\\', '/')));
writer.on('error', reject);
});
}

13
frontend/pc/IM/src/cache/protocolReg.js vendored Normal file
View File

@ -0,0 +1,13 @@
import { net, protocol } from 'electron'
import { CACHE_ROOT } from './cacheDir'
import path from 'path'
export const addProtocolHandler = () => {
protocol.handle('ql-im', (request) => {
const url = request.url.replace('ql-im://', '')
const filePath = path.join(CACHE_ROOT, url.replaceAll('/', '\\'))
return net.fetch(`file://${filePath}`)
})
}

View File

@ -4,6 +4,8 @@ import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import icon from '../../resources/icon.png?asset'
import { registerWindowHandler } from './ipcHandlers/window'
import { createTry } from './trayHandler'
import { registerCacheHandler } from './ipcHandlers/cache'
import { addProtocolHandler } from '../cache/protocolReg'
function createWindow() {
// Create the browser window.
@ -24,7 +26,7 @@ function createWindow() {
createTry(mainWindow);
mainWindow.on('ready-to-show', () => {
mainWindow.show()
// mainWindow.show()
})
@ -49,6 +51,8 @@ app.whenReady().then(() => {
// Set app user model id for windows
electronApp.setAppUserModelId('com.electron')
addProtocolHandler()
// Default open or close DevTools by F12 in development
// and ignore CommandOrControl + R in production.
// see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils
@ -59,7 +63,8 @@ app.whenReady().then(() => {
// IPC test
ipcMain.on('ping', () => console.log('pong'))
registerWindowHandler()
registerWindowHandler()
registerCacheHandler()
createWindow()

View File

@ -0,0 +1,8 @@
import { ipcMain } from "electron";
import { getCacheResorce } from "../../cache/cacheHandler";
export function registerCacheHandler(){
ipcMain.handle('cache-get', (event, url, type) => {
return getCacheResorce(url, type)
})
}

View File

@ -6,7 +6,8 @@ import { is } from '@electron-toolkit/utils'
export function registerWindowHandler() {
const windowMapData = new Map()
ipcMain.on('window-action', (event, action) => {
//**窗口控件操作 */
ipcMain.on('window-action', (event, action, data) => {
const win = BrowserWindow.fromWebContents(event.sender)
if (!win) return
const actions = {
@ -20,14 +21,21 @@ export function registerWindowHandler() {
win.destroy()
}
},
isMaximized: () => win.isMaximized()
isMaximized: () => win.isMaximized(),
changeSize: () => {
win.setSize(data.width, data.height, true)
win.setResizable(data.resizable)
win.center()
},
show: () => win.show()
}
actions[action]?.()
})
ipcMain.on('window-new', (event, { route, data }) => {
/**新开窗口 */
ipcMain.on('window-new', (event, { route, data, width = 900, height=670 }) => {
const win = new BrowserWindow({
width: 900,
height: 670,
width: width,
height: height,
show: true,
autoHideMenuBar: true,
frame: false,

View File

@ -8,9 +8,15 @@ const api = {
maximize: () => ipcRenderer.send('window-action', 'maximize'),
close: () => ipcRenderer.send('window-action', 'close'),
closeThis: () => ipcRenderer.send('window-action', 'closeThis'),
show: () => ipcRenderer.send('window-action', 'show'),
isMaximized: () => ipcRenderer.send('window-action', 'isMaximized'),
newWindow: (route, data) => ipcRenderer.send('window-new', { route, data }),
getWindowData: (winId) => ipcRenderer.invoke('get-window-data', winId)
newWindow: (route, data, width, height) => ipcRenderer.send('window-new', { route, data, width, height }),
getWindowData: (winId) => ipcRenderer.invoke('get-window-data', winId),
setMainSize: (width, height, resizable = true) =>
ipcRenderer.send('window-action', 'changeSize', { width, height, resizable })
},
cache: {
getCache: (url, type) => ipcRenderer.invoke('cache-get', url, type)
}
}

View File

@ -5,13 +5,13 @@
<title>Electron</title>
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
content="default-src 'self' http://192.168.5.116:7070 ql-im:;
script-src 'self' 'unsafe-inline';
style-src 'self' 'unsafe-inline';
connect-src 'self' http://localhost:5202 ws://localhost:5202 http://192.168.5.116:7070 ws://192.168.5.116:7070;
img-src 'self' data: blob: https: http:;
img-src 'self' data: blob: https: http: ql-im:;
font-src 'self' data:;
media-src 'self' blob:;">
media-src 'self' blob: http://192.168.5.116:7070; ql-im:">
</head>
<body>

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

@ -0,0 +1,46 @@
<template>
<div class="img-container">
<img :src="finalUrl" alt="" v-bind="$attrs" @error="imgLoadErrHandler">
</div>
</template>
<script setup>
import { onMounted, ref, watch } from 'vue';
import { useCacheStore } from '../stores/cache';
import { FILE_TYPE } from '../constants/fileTypeDefine';
import default_avatar from '@/assets/default_avatar.png'
import loading_img from '@/assets/loading_img.png'
const cacheStore = useCacheStore()
const props = defineProps({
rawUrl: {
type: String,
required: true
},
noAvatar: {
type: Boolean,
default: false
}
})
const finalUrl = ref(props.noAvatar ? loading_img : default_avatar)
const imgLoadErrHandler = (e) => {
e.target.src = loading_img
}
watch(() => props.rawUrl,
(newVal) => {
if (!props.rawUrl || props.rawUrl == '') return
cacheStore.getCache(props.rawUrl, FILE_TYPE.Image).then(res => {
finalUrl.value = res
})
},
{ immediate: true }
)
</script>

View File

@ -0,0 +1,252 @@
<template>
<div class="v-ui-dropdown" ref="dropdownRef">
<button
type="button"
class="v-ui-dropdown-toggle"
:class="{ 'is-open': isOpen }"
@click.stop="toggleDropdown"
role="button"
aria-haspopup="listbox"
:aria-expanded="isOpen"
:disabled="disable"
>
<span class="v-ui-selected-text">{{ selectedLabel }}</span>
<span class="v-ui-arrow-icon" :class="{ 'v-ui-arrow-up': isOpen }">
<svg viewBox="0 0 1024 1024" width="1em" height="1em">
<path d="M831.872 340.864L512 652.672 192.128 340.864a31.936 31.936 0 0 0-45.248 0 32 32 0 0 0 0 45.248l342.144 333.76a31.936 31.936 0 0 0 45.248 0l342.144-333.76a32 32 0 0 0-45.248-45.248z" fill="currentColor"></path>
</svg>
</span>
</button>
<transition name="v-ui-dropdown-grow">
<ul
v-show="isOpen"
class="v-ui-dropdown-menu"
role="listbox"
:aria-activedescendant="modelValue"
>
<li
v-for="option in options"
:key="option.value"
class="v-ui-dropdown-item"
:class="{ 'is-selected': option.value === modelValue }"
@click.stop="selectOption(option)"
role="option"
:aria-selected="option.value === modelValue"
>
<span class="v-ui-item-label">{{ option.label }}</span>
<span v-if="option.value === modelValue" class="v-ui-check-icon">
<svg viewBox="0 0 1024 1024" width="1em" height="1em">
<path d="M358.4 716.8l-204.8-204.8-51.2 51.2 256 256 512-512-51.2-51.2-460.8 460.8z" fill="currentColor"></path>
</svg>
</span>
</li>
</ul>
</transition>
</div>
</template>
<script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue'
// Props ()
const props = defineProps({
modelValue: {
type: [String, Number],
default: ''
},
options: {
type: Array,
required: true,
// : [{ label: '', value: 1 }, { label: '', value: 2 }]
},
placeholder: {
type: String,
default: '请选择...'
},
disable: {
type: Boolean,
default: false
}
})
// Emits ( v-model, )
const emit = defineEmits(['update:modelValue', 'change'])
const isOpen = ref(false)
const dropdownRef = ref(null)
// ()
const selectedLabel = computed(() => {
const selected = props.options.find(opt => opt.value === props.modelValue)
return selected ? selected.label : props.placeholder
})
// ()
const toggleDropdown = () => {
isOpen.value = !isOpen.value
}
// ()
const selectOption = (option) => {
emit('update:modelValue', option.value)
emit('change', option)
isOpen.value = false
}
// ()
const handleClickOutside = (event) => {
if (dropdownRef.value && !dropdownRef.value.contains(event.target)) {
isOpen.value = false
}
}
// ()
onMounted(() => {
document.addEventListener('click', handleClickOutside)
})
onUnmounted(() => {
document.removeEventListener('click', handleClickOutside)
})
</script>
<style scoped>
/* 使用加强型前缀和特异性选择器防止污染 */
.v-ui-dropdown {
position: relative; /* 强制相对定位 */
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-size: 14px;
display: inline-block; /* 防止父容器布局冲突 */
}
/* 针对 ul 和 li 进行强制 reset防止全局样式干扰 */
.v-ui-dropdown ul {
list-style: none;
padding: 0;
margin: 0;
}
.v-ui-dropdown li {
list-style: none;
}
/* 触发按钮:白底、靛蓝色边框的现代 Filled 风格 */
.v-ui-dropdown-toggle {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
padding: 10px 16px;
background-color: #007aff; /* 强制微灰底色,与纯白背景区分 */
border: 1px solid #e4e4e7; /* 浅灰边框,避免融合 */
border-radius: 12px;
color: #000000; /* 极深灰 */
font-weight: 500;
cursor: pointer;
user-select: none;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
}
.v-ui-dropdown-toggle:hover {
background-color: #cacaff;
border-color: #d1d5db;
}
/* 展开状态下 */
.v-ui-dropdown-toggle.is-open {
background-color: #cacaff;
border-color: #4f46e5; /* 靛蓝色主色 */
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.15); /* Focus 环 */
}
.v-ui-selected-text {
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-right: 10px;
text-align: left;
}
.v-ui-arrow-icon {
display: flex;
font-size: 12px;
color: #000000;
transition: transform 0.3s ease, color 0.2s ease;
}
.v-ui-arrow-up {
transform: rotate(180deg);
color: #4f46e5;
}
/* 下拉菜单:纯白底色,强化悬浮阴影 */
.v-ui-dropdown .v-ui-dropdown-menu {
position: absolute;
top: 100%;
left: 0;
width: 100%;
margin-top: 8px;
padding: 6px;
background-color: #ffffff;
border: 1px solid #e4e4e7;
border-radius: 12px;
/* 强阴影是白色背景上脱颖而出的秘诀 */
box-shadow: 0 12px 32px -4px rgba(0, 0, 0, 0.12), 0 4px 12px -4px rgba(0, 0, 0, 0.08);
z-index: 1000; /* 确保在最上层 */
max-height: 240px;
overflow-y: auto;
}
/* 菜单项样式 */
.v-ui-dropdown-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 12px;
border-radius: 8px;
cursor: pointer;
color: #18181b;
transition: all 0.2s ease;
margin-bottom: 2px; /* Item 呼吸感 */
}
.v-ui-dropdown-item:hover {
background-color: #f4f4f5;
}
/* 选中项的样式 */
.v-ui-dropdown-item.is-selected {
background-color: #eef2ff; /* 极淡的靛蓝色 */
color: #4f46e5;
font-weight: 600;
}
.v-ui-item-label {
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-right: 10px;
}
.v-ui-check-icon {
display: flex;
font-size: 14px;
color: #4f46e5;
}
/* 过渡动画 */
.v-ui-dropdown-grow-enter-active,
.v-ui-dropdown-grow-leave-active {
transition: opacity 0.2s ease, transform 0.2s cubic-bezier(0.2, 0, 0, 1);
transform-origin: top center;
}
.v-ui-dropdown-grow-enter-from,
.v-ui-dropdown-grow-leave-to {
opacity: 0;
transform: scaleY(0.95) translateY(-8px);
}
</style>

View File

@ -5,7 +5,7 @@
<rect width="10" height="1" fill="currentColor" />
</svg>
</button>
<button class="control-btn maximize" @click="toggleMaximize" title="最大化/还原">
<button class="control-btn maximize" @click="toggleMaximize" title="最大化/还原" :disabled="!props.resizable">
<svg v-if="!isMaximized" width="10" height="10" viewBox="0 0 10 10" fill="none" stroke="currentColor" stroke-width="1.2">
<rect x="1.5" y="1.5" width="7" height="7" />
</svg>
@ -14,7 +14,7 @@
<rect x="4" y="5" width="6.5" height="6.5" stroke="currentColor" stroke-width="1.4" />
</svg>
</button>
<button class="control-btn close" @click="close" title="关闭">
<button class="control-btn close" @click="close" title="关闭" >
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" stroke="currentColor" stroke-width="1.2"
stroke-linecap="round">
<path d="M1 1L9 9M9 1L1 9" />
@ -27,11 +27,19 @@
<script setup>
import { ref } from 'vue'
import { ref, defineEmits, defineProps } from 'vue'
import { isElectron } from '../utils/electronHelper'
const isMaximized = ref(false)
const emits = defineEmits(['close'])
const props = defineProps({
resizable: {
type: Boolean,
default: true
}
})
function minimize() {
window.api.window.minimize();
}
@ -41,6 +49,8 @@ function toggleMaximize() {
}
function close() {
window.api.window.close()
emits('close')
emits('close')
}
</script>

View File

@ -1,65 +1,74 @@
<template>
<div v-for="c in props.contacts"
:key="c.id"
class="list-item"
:class="{active: activeContactId === c.id}"
@click="routeUserInfo(c.id)">
<img :src="c.userInfo.avatar" class="avatar-std" />
<div class="info">
<div class="name">{{ c.remarkName }}</div>
</div>
</div>
<div v-for="c in props.contacts" :key="c.id" class="list-item" :class="{ active: activeContactId === c.id }"
@click="routeUserInfo(c.id)">
<AsyncImage :raw-url="c.avatar" class="avatar-std" />
<div class="info">
<div class="name">{{ c.remarkName }}</div>
</div>
</div>
</template>
<script setup>
import { defineProps, ref } from 'vue';
import { useRouter } from 'vue-router';
import { defineProps, computed } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import AsyncImage from '../AsyncImage.vue';
const router = useRouter()
const route = useRoute()
const activeContactId = ref(null)
const activeContactId = computed(() => route.params.id)
const props = defineProps({
contacts: {
type:String,
required: true
}
contacts: {
type: String,
required: true
}
})
const routeUserInfo = (id) => {
router.push(`/contacts/info/${id}`);
activeContactId.value = id;
}
</script>
<style scoped>
.list-item {
.list-item {
display: flex;
padding: 10px 12px;
gap: 12px;
align-items: center;
cursor: pointer;
transition: background 0.2s;
text-decoration: none; /* 去除下划线 */
color: inherit; /* 继承父元素的文本颜色 */
outline: none; /* 去除点击时的蓝框 */
-webkit-tap-highlight-color: transparent; /* 移动端点击高亮 */
text-decoration: none;
/* 去除下划线 */
color: inherit;
/* 继承父元素的文本颜色 */
outline: none;
/* 去除点击时的蓝框 */
-webkit-tap-highlight-color: transparent;
/* 移动端点击高亮 */
}
/* 去除 hover、active 等状态的效果 */
a:hover,
a:active,
a:hover,
a:active,
a:focus {
text-decoration: none;
color: inherit; /* 保持颜色不变 */
color: inherit;
/* 保持颜色不变 */
cursor: pointer;
}
.list-item:hover { background: #e2e2e2; }
.list-item.active { background: #c6c6c6; }
.list-item:hover {
background: #e2e2e2;
}
.avatar-std {
.list-item.active {
background: #c6c6c6;
}
:deep(.avatar-std) {
width: 36px;
height: 36px;
border-radius: 4px;
@ -76,7 +85,16 @@ a:focus {
color: #fff;
font-size: 16px;
}
.icon-box.orange { background: #faad14; }
.icon-box.green { background: #52c41a; }
.icon-box.blue { background: #1890ff; }
</style>
.icon-box.orange {
background: #faad14;
}
.icon-box.green {
background: #52c41a;
}
.icon-box.blue {
background: #1890ff;
}
</style>

View File

@ -1,12 +1,12 @@
<template>
<WindowControls/>
<div></div>
</template>
<script setup>
import { previewImages } from 'hevue-img-preview/v3'
import {onMounted, ref } from 'vue';
import { useRoute } from 'vue-router';
import WindowControls from '../WindowControls.vue';
// import WindowControls from '../WindowControls.vue';
const route = useRoute();

View File

@ -0,0 +1,148 @@
<template>
<Teleport to="body">
<div class="video-overlay">
<div class="video-dialog" :style="isElectron() ? 'width:100vw;height:100vh' : ''">
<WindowControls v-if="isElectron()" @close="windowCloseHandler"/>
<div class="close-bar" v-if="!isElectron()">
<span>正在播放视频</span>
<button class="close-btn" @click="webCloseHandler">&times;</button>
</div>
<div class="player-wrapper" :class="{'electron-play-container': isElectron()}">
<vue3-video-player
v-if="videoLoaded"
:src="videoInfo"
poster="https://xxx.jpg"
:controls="true"
:autoplay="true"
/>
</div>
</div>
</div>
</Teleport>
</template>
<script setup>
import { onMounted, ref, defineEmits } from 'vue';
import { useRoute } from 'vue-router';
import { isElectron } from '../../utils/electronHelper';
import WindowControls from '../WindowControls.vue';
const props = defineProps({
videoData: {
type: String
}
})
const emits = defineEmits(['close'])
const route = useRoute();
const videoInfo = ref(null);
const videoLoaded = ref(false)
const winId = ref(null)
const windowCloseHandler = () => {
window.api.window.closeThis()
}
const webCloseHandler = () => {
emits('close')
}
onMounted(async () => {
if (isElectron()) {
winId.value = route.query.winId;
const data = await window.api.window.getWindowData(winId.value);
videoInfo.value = data;
videoLoaded.value = true;
}else{
videoInfo.value = props.videoData
videoLoaded.value = true;
}
});
</script>
<style scoped>
/* 遮罩层:全屏、黑色半透明、固定定位 */
.video-overlay {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.85);
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
/* 确保在最顶层 */
}
/* 播放器弹窗主体 */
.video-dialog {
position: relative;
width: 90%;
/* max-width: 1000px; */
background: #000;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
}
/* 顶部状态栏(包含关闭按钮) */
.close-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 20px;
background: #1a1a1a;
color: #eee;
font-size: 14px;
}
.close-btn {
background: none;
border: none;
color: #fff;
font-size: 28px;
cursor: pointer;
line-height: 1;
transition: transform 0.2s;
}
.close-btn:hover {
transform: scale(1.2);
color: #ff4d4f;
}
.player-wrapper {
width: 100%;
aspect-ratio: 16 / 9;
/* 锁定 16:9 比例 */
background: #000;
}
/* 进场动画 */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.electron-play-container {
height: calc(100vh - 30px);
}
</style>

View File

@ -1,14 +1,34 @@
<script setup>
import { ref, computed, onMounted } from 'vue';
import { useContactStore } from '@/stores/contact';
import { ref, onMounted, defineEmits } from 'vue';
import { friendService } from '../../services/friend';
import { groupService } from '@/services/group';
import { SYSTEM_BASE_STATUS } from '@/constants/systemBaseStatus';
import { useMessage } from '../messages/useAlert';
import AsyncImage from '../AsyncImage.vue';
const contactStore = useContactStore();
const message = useMessage();
const props = defineProps({ modelValue: Boolean });
const isLoaded = ref(false);
const isError = ref(false)
const props = defineProps({
modelValue: Boolean,
type: {
/**@type {"CreateGroup" | "InviteUser"} */
type: String,
default: 'CreateGroup',
validator: (value) => {
return ['CreateGroup', 'InviteUser'].includes(value)
}
},
title: {
type: String,
default: '创建群聊'
}
});
const emits = defineEmits(['submit'])
const friends = ref([])
@ -20,21 +40,12 @@ const toggle = (id) => {
};
const submit = async () => {
const res = await groupService.createGroup({
name: groupName.value,
avatar: "https://baidu.com",
userIDs: [...selected.value]
});
if(res.code == SYSTEM_BASE_STATUS.SUCCESS){
message.show('群聊创建成功。');
}else{
message.error(res.message);
}
emits('submit', selected.value, groupName.value)
};
onMounted(async () =>{
friends.value = contactStore.contacts;
friends.value = (await friendService.getFriendList()).data;
})
</script>
@ -43,16 +54,16 @@ onMounted(async () =>{
<div v-if="modelValue" class="overlay" @click.self="$emit('update:modelValue', false)">
<div class="mini-modal">
<header>
<span>发起群聊</span>
<span>{{ props.title }}</span>
<button @click="$emit('update:modelValue', false)"></button>
</header>
<main>
<input v-model="groupName" placeholder="群组名称..." class="mini-input" />
<input v-if="props.type == 'CreateGroup'" v-model="groupName" placeholder="群组名称..." class="mini-input" />
<div class="list">
<div v-for="f in friends" :key="f.friendId" @click="toggle(f.friendId)" class="item">
<img :src="f.userInfo.avatar" class="avatar" />
<AsyncImage :raw-url="f.userInfo.avatar" class="avatar" />
<span class="name">{{ f.remarkName }}</span>
<input type="checkbox" :checked="selected.has(f.friendId)" />
</div>
@ -60,8 +71,8 @@ onMounted(async () =>{
</main>
<footer>
<button @click="submit" :disabled="!groupName || !selected.size" class="btn">
创建 ({{ selected.size }})
<button @click="submit" :disabled="(!groupName&& props.type == 'CreateGroup') || !selected.size" class="btn">
{{ props.type == 'CreateGroup' ? '创建' : '确定' }} ({{ selected.size }})
</button>
</footer>
</div>
@ -80,8 +91,8 @@ onMounted(async () =>{
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
header {
padding: 12px 16px; display: flex; justify-content: space-between;
header {
padding: 12px 16px; display: flex; justify-content: space-between;
background: #f9f9f9; font-weight: bold; font-size: 14px;
}
@ -101,7 +112,7 @@ main { padding: 12px; }
}
.item:hover { background: #f5f5f5; }
.avatar { width: 32px; height: 32px; border-radius: 4px; margin-right: 10px; }
:deep(.avatar) { width: 32px; height: 32px; border-radius: 4px; margin-right: 10px; }
.name { flex: 1; font-size: 14px; }
footer { padding: 12px; }
@ -110,4 +121,4 @@ footer { padding: 12px; }
border: none; border-radius: 6px; font-weight: bold; cursor: pointer;
}
.btn:disabled { background: #e1e1e1; color: #999; cursor: not-allowed; }
</style>
</style>

View File

@ -4,12 +4,13 @@
<div class="sidebar-scroll-content">
<section v-if="chatType == MESSAGE_TYPE.GROUP" class="info-card header-section">
<div class="avatar-wrapper">
<img :src="groupData.targetAvatar" class="group-main-avatar" />
<input type="file" style="display: none;" ref="input" @change="fileUploadHandler">
<img :src="groupData.targetAvatar" class="group-main-avatar" @click="uploadGroupAvatar"/>
<div class="edit-badge" v-if="isAdmin" v-html="feather.icons['camera'].toSvg({width:15, height: 15})">
</div>
</div>
<h2 class="group-name">{{ groupData.targetName }}</h2>
<p class="group-id">群ID: {{ groupData.id }}</p>
<p class="group-id">群ID: {{ groupData.targetId }}</p>
</section>
<section v-if="chatType == MESSAGE_TYPE.GROUP" class="info-card">
@ -18,32 +19,32 @@
<button v-if="isAdmin" class="text-link">编辑</button>
</div>
<div class="announcement-box">
{{ groupData.announcement || '暂无群公告,点击编辑添加。' }}
{{ groupInfo ? groupInfo.announcement : '暂无群公告,点击编辑添加。' }}
</div>
</section>
<section v-if="chatType == MESSAGE_TYPE.GROUP" class="info-card">
<div class="section-header">
<h3 class="section-label">群成员 <span class="count-tag">{{ groupData.members?.length || 0 }}</span></h3>
<h3 class="section-label">群成员 <span class="count-tag">{{ groupInfo.members?.length || 0 }}</span></h3>
<button class="text-link" @click="$emit('viewAll')">查看全部</button>
</div>
<div class="member-grid">
<div class="member-item add-btn">
<div class="member-avatar-box dashed">
<div class="member-avatar-box dashed" @click="inviteHandler">
<span>+</span>
</div>
<span class="member-nick">邀请</span>
</div>
<div
v-for="member in groupData.members?.slice(0, 11)"
v-for="member in groupInfo.members?.slice(0, 11)"
:key="member.id"
class="member-item"
>
<div class="member-avatar-box">
<img :src="member.avatar" class="member-img" />
<span v-if="member.role === 'admin'" class="role-badge"></span>
<async-image :raw-url="member.avatar" class="member-img"/>
<span v-if="member.role === GROUP_MEMBER_ROLE.ADMIN || member.role === GROUP_MEMBER_ROLE.MASTER" class="role-badge"></span>
</div>
<span class="member-nick">{{ member.nickname }}</span>
</div>
@ -68,14 +69,23 @@
<button class="danger-btn">删除并退出</button>
</div>
</div>
<create-group v-model="groupInviteModal" type="InviteUser" title="邀请好友" @submit="inviteUserHandler"/>
</aside>
</transition>
</template>
<script setup>
import { computed } from 'vue';
import { computed, onMounted, ref, useTemplateRef, watch } from 'vue';
import { MESSAGE_TYPE } from '../../constants/MessageType';
import feather from 'feather-icons';
import { GROUP_MEMBER_ROLE } from '../../constants/GroupDefine';
import { uploadService } from '../../services/upload/uploadService';
import { groupService } from '../../services/group';
import { SYSTEM_BASE_STATUS } from '../../constants/systemBaseStatus';
import { useMessage } from './useAlert';
import { getFileHash } from '../../utils/uploadTools';
import CreateGroup from '../groups/CreateGroup.vue';
import AsyncImage from '../AsyncImage.vue';
const props = defineProps({
chatType: {
@ -100,13 +110,69 @@ const props = defineProps({
currentUserId: [String, Number]
});
const input = useTemplateRef('input')
const message = useMessage();
const groupInfo = ref({
members: []
})
const groupInviteModal = ref(false)
defineEmits(['close', 'viewAll']);
const uploadGroupAvatar = () => {
input.value.click()
}
const fileUploadHandler = async (e) => {
const file = e.target.files[0];
const hash = await getFileHash(file)
const { data } = await uploadService.uploadSmallFile(file, hash);
const res = await groupService.updateGroupInfo(props.groupData.targetId, {
avatar: data.url
})
if(res.code == SYSTEM_BASE_STATUS.SUCCESS){
message.success('头像更新成功')
}else{
message.error(res.message)
}
}
const inviteHandler = () => {
groupInviteModal.value = true
}
const inviteUserHandler = async (selectedUsers) => {
const res = await groupService.inviteUser(props.groupData.targetId, [...selectedUsers])
if (res.code != SYSTEM_BASE_STATUS.SUCCESS) return message.error(res.message)
message.success('成功')
}
//
const isAdmin = computed(() => {
// members role
return true; // true
});
watch(
() => props.groupData.id,
async (newVal, oldVal) => {
if (props.chatType == MESSAGE_TYPE.GROUP && newVal != oldVal) {
groupInfo.value = (await groupService.getGroupInfo(props.groupData.targetId)).data
groupInfo.value.members = (await groupService.getGroupMember(props.groupData.targetId)).data
}
},
{ immediate: true }
)
onMounted(async () => {
})
</script>
<style scoped>
@ -118,7 +184,7 @@ const isAdmin = computed(() => {
right: 0;
width: 320px;
background-color: #f5f5f5; /* 背景色改为浅灰,突出白色卡片 */
z-index: 1000;
z-index: 100;
box-shadow: -8px 0 24px rgba(0, 0, 0, 0.05);
display: flex;
flex-direction: column;
@ -274,7 +340,7 @@ const isAdmin = computed(() => {
height: 48px;
}
.member-img {
:deep(.member-img) {
width: 100%;
height: 100%;
border-radius: 12px;

View File

@ -0,0 +1,45 @@
export const GROUP_MEMBER_ROLE = Object.freeze({
NORMAL: 'Normal',
ADMIN: 'Administrator',
MASTER: 'Master'
})
/**
* 群请求状态枚举 (对应后端 String 输出)
*/
export const GROUP_REQUEST_STATUS = Object.freeze({
/** 待管理员处理 */
PENDING: 'Pending',
/** 管理员已拒绝 */
DECLINED: 'Declined',
/** 管理员已同意 */
PASSED: 'Passed',
/** 待对方同意 */
TARGET_PENDING: 'TargetPending',
/** 对方拒绝 */
TARGET_DECLINED: 'TargetDeclined'
})
export const GROUP_REQUEST_ACTION = Object.freeze({
ACCEPT: 'Accept',
REJECT: 'Reject'
})
export const getGroupRequestStatusTxt = (status) => {
switch (status) {
case GROUP_REQUEST_STATUS.PENDING:
return '待管理员处理';
case GROUP_REQUEST_STATUS.DECLINED:
return '管理员已拒绝';
case GROUP_REQUEST_STATUS.PASSED:
return '管理员已同意';
case GROUP_REQUEST_STATUS.TARGET_PENDING:
return '待对方同意';
case GROUP_REQUEST_STATUS.TARGET_DECLINED:
return '对方拒绝';
default:
return '未知状态';
}
}

View File

@ -36,5 +36,6 @@ export const FILE_TYPE = Object.freeze({
Image: 'Image',
Video: 'Video',
Voice: 'Voice',
File: 'File'
File: 'File',
TEXT: 'Text'
});

View File

@ -0,0 +1,26 @@
export const GROUP_REQUEST_TYPE = Object.freeze({
//**邀请对方 */
INVITE: 'invite',
/**被邀请 */
INVITED: 'invited',
/**入群请求 */
IS_GROUP: 'is-group',
//**我的申请入群 */
IS_USER: 'is-user',
})
export const getTypeText = (type) => {
switch(type){
case GROUP_REQUEST_TYPE.INVITE:
return '邀请好友入群';
case GROUP_REQUEST_TYPE.INVITED:
return '邀请你入群';
case GROUP_REQUEST_TYPE.IS_GROUP:
return '申请入群';
case GROUP_REQUEST_TYPE.IS_USER:
return '我的申请入群';
default:
'未知状态'
}
}

View File

@ -0,0 +1,34 @@
export const NOTIFICATION_TYPE = Object.freeze({
// --- 基础聊天 (10-19) ---
ChatMsg: 1,
FileMsg: 11,
EmojiSticker: 12,
ForwardMsg: 13,
// --- 系统与通知 (20-29) ---
SystemNotice: 2,
FriendRequest: 21,
FriendAccepted: 22,
UserInLine: 23,
// --- 状态变更与交互 (30-39) ---
ActionStatus: 3,
MsgReadReceipt: 31,
MsgRevoke: 32,
MsgEdit: 33,
// --- 群组管理 (40-49) ---
GroupInvited: 41,
GroupMemberUpdate: 42,
GroupAnnouncement: 43,
GroupDismissed: 44,
// --- 实时通信控制 (50-59) ---
RTC_CallRequest: 51,
RTC_CallHandled: 52,
// --- 异常与安全 (90-99) ---
ErrorInternal: 91,
TokenExpired: 92,
KickedOut: 93
})

View File

@ -1,8 +1,25 @@
import { useConversationStore } from "@/stores/conversation"
import { MESSAGE_TYPE } from "../constants/MessageType";
export const messageHandler = (msg) => {
const conversationStore = useConversationStore();
const conversation = conversationStore.conversations.find(x => (x.targetId == msg.senderId || x.targetId == msg.receiverId) && msg.chatType == x.chatType);
const conversation = conversationStore.conversations.find(x => {
// 1. 如果是私聊:目标 ID 必须是对方(可能是发送者,也可能是接收者)
if (msg.chatType === MESSAGE_TYPE.PRIVATE) {
return x.chatType === MESSAGE_TYPE.PRIVATE &&
(x.targetId === msg.senderId || x.targetId === msg.receiverId);
}
// 2. 如果是群聊:目标 ID 必须是群 ID即消息的 receiverId
if (msg.chatType === MESSAGE_TYPE.GROUP) {
return x.chatType === MESSAGE_TYPE.GROUP &&
x.targetId === msg.receiverId;
}
return false;
});
if (!conversation) return; // 容错处理:如果没找到会话,不执行后续逻辑
conversation.lastMessage = msg.content;
if (conversation.targetId == msg.receiverId) {
conversation.unreadCount = 0;

View File

@ -11,6 +11,7 @@ const message = useMessage();
const routes = [
{ path: '/auth/login', component: () => import('@/views/auth/Login.vue') },
{ path: '/auth/register', component: () => import('@/views/auth/Register.vue') },
{
path: '/',
component: MainView,
@ -57,6 +58,11 @@ const routes = [
path: '/contacts/requests',
name: 'friendRequests',
component: () => import('@/views/contact/FriendRequestList.vue')
},
{
path: '/contacts/grouphandle',
name: 'grouphandle',
component: () => import('@/views/contact/GroupRequest.vue')
}
]
},
@ -72,6 +78,9 @@ const routes = [
{ path: '/test', component: TestView },
{
path: '/imgpre', component: () => import('@/components/electron/ImagePreview.vue')
},
{
path: '/videopre', component: () => import('@/components/electron/VideoPreview.vue')
}
]

View File

@ -1,97 +1,99 @@
import axios from 'axios'
import { useMessage } from '@/components/messages/useAlert';
import router from '@/router';
import { useAuthStore } from '@/stores/auth';
import { authService } from './auth';
import { useMessage } from '@/components/messages/useAlert'
import router from '@/router'
import { useAuthStore } from '@/stores/auth'
import { authService } from './auth'
const message = useMessage();
const message = useMessage()
let waitqueue = [];
let isRefreshing = false;
const authURL = ['/auth/login', '/auth/register', '/auth/refresh'];
let waitqueue = []
let isRefreshing = false
const authURL = ['/auth/login', '/auth/register', '/auth/refresh']
const pushLoginElectron = () => {
window.api.window.close()
window.api.window.newWindow('/auth/login', null, 420, 540)
}
const api = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:3000/api', // 从环境变量中读取基础 URL
timeout: 10000,
headers: {
}
headers: {}
})
api.interceptors.request.use(
config => {
const authStore = useAuthStore();
const token = authStore.token;
(config) => {
const authStore = useAuthStore()
const token = authStore.token
if (token) {
config.headers.Authorization = `Bearer ${token}`;
config.headers.Authorization = `Bearer ${token}`
}
return config;
return config
},
err => {
return Promise.reject(err);
(err) => {
return Promise.reject(err)
}
)
api.interceptors.response.use(
response => {
return response.data;
(response) => {
return response.data
},
async err => {
const authStore = useAuthStore();
const { config, response } = err;
async (err) => {
const authStore = useAuthStore()
const { config, response } = err
if (response) {
switch (response.status) {
case 401:
if (authURL.some(x => config.url.includes(x))) {
authStore.logout();
message.error('未登录,请登录后操作。');
if (authURL.some((x) => config.url.includes(x))) {
authStore.logout()
message.error('未登录,请登录后操作。')
router.push('/auth/login')
break;
break
}
if (config._retry) {
break;
break
}
config._retry = true;
config._retry = true
// 已经在刷新 → 排队
if (isRefreshing) {
return new Promise(resolve => {
waitqueue.push(token => {
return new Promise((resolve) => {
waitqueue.push((token) => {
config.headers.Authorization = `Bearer ${token}`
resolve(api(config))
})
})
}
isRefreshing = true;
const refreshToken = authStore.refreshToken;
isRefreshing = true
const refreshToken = authStore.refreshToken
if (refreshToken != null && refreshToken != '') {
const res = await authService.refresh(refreshToken)
authStore.setLoginInfo(res.data.token, res.data.refreshToken, res.data.userInfo)
waitqueue.forEach(cb => cb(authStore.token));
waitqueue = [];
waitqueue.forEach((cb) => cb(authStore.token))
waitqueue = []
config.headers.Authorization = `Bearer ${authStore.token}`
return api(config)
}
authStore.logout();
message.error('未登录,请登录后操作。');
authStore.logout()
message.error('未登录,请登录后操作。')
router.push('/auth/login')
break;
break
case 400:
if (response.data && response.data.code == 1003) {
message.error(response.data.message);
break;
message.error(response.data.message)
break
}
default:
message.error('请求错误,请检查网络。');
break;
message.error('请求错误,请检查网络。')
break
}
return Promise.reject(err);
return Promise.reject(err)
} else {
message.error('请求错误,请检查网络。');
return Promise.reject(err);
message.error('请求错误,请检查网络。')
return Promise.reject(err)
}
}
)
@ -100,5 +102,5 @@ export const request = {
post: (url, data, config) => api.post(url, data, config),
put: (url, data, config) => api.put(url, data, config),
delete: (url, config) => api.delete(url, config),
instance: api,
};
instance: api
}

View File

@ -3,8 +3,60 @@ import { request } from "./api"
export const groupService = {
/**
* 创建群聊
* @param {*} data
* @returns
* @param {*} data
* @returns
*/
createGroup: (data) => request.post('/Group/CreateGroup', data)
}
createGroup: (data) => request.post('/Group/CreateGroup', data),
/**
* 查询群组成员
* @param {*} groupId
* @returns
*/
getGroupMember: (groupId) => request.get(`/Group/GetGroupMembers?groupId=${groupId}`),
/**
* 更新群组信息
* @param {*} groupId
* @param {*} params
* @returns
*/
updateGroupInfo: (groupId, params) => request.post(`/Group/UpdateGroup?groupId=${groupId}`, params),
/**
* 查询群组信息
* @param {*} groupId
* @returns
*/
getGroupInfo: (groupId) => request.get(`/Group/GetGroupInfo?groupId=${groupId}`),
/**
* 邀请入群
* @param {*} groupId
* @param {*} users
* @returns
*/
inviteUser: (groupId, users) =>
request.post('/Group/InviteUser', { groupId: groupId, ids: users }),
/**
* 获取群聊通知
* @returns
*/
getGroupNotification: () => request.get('/Group/GetGroupNotification'),
/**
* 处理入群邀请
* @param {*} inviteId
* @param {*} action
* @returns
*/
handleGroupInvite: (inviteId, action) =>
request.post('/Group/HandleGroupInvite', { inviteId: inviteId, action: action }),
/**
* 处理入群请求
* @param {*} requestId
* @param {*} action
* @returns
*/
handleGroupRequest: (requestId, action) =>
request.post('/Group/HandleGroupRequest', { requestId: requestId, action: action })
}

View File

@ -0,0 +1,29 @@
import { defineStore } from 'pinia'
import { isElectron } from '../utils/electronHelper'
export const useCacheStore = defineStore('cache', {
state: () => ({
cacheMap: new Map()
}),
actions: {
/**
* 获取文件地址
* @param {String} url 网络路径
* @param {String} type 文件类型
* @returns {Promise} 本地路径
*/
async getCache(url, type) {
if (!isElectron()) return url
if (this.cacheMap.has(url)) {
return this.cacheMap.get(url)
}
const localPath = await window.api.cache.getCache(url, type)
this.cacheMap.set(url, localPath)
return localPath
}
}
})

View File

@ -1,7 +1,6 @@
import { defineStore } from "pinia";
import { messagesDb } from "@/utils/db/messageDB";
import { messageService } from "@/services/message";
import { useConversationStore } from "./conversation";
export const useChatStore = defineStore('chat', {
state: () => ({
@ -51,7 +50,6 @@ export const useChatStore = defineStore('chat', {
this.isEnded = false;
//先从浏览器缓存加载一部分消息列表
const localHistory = await messagesDb.getLatestMessages(sessionId, this.pageSize);
console.log(localHistory)
if (localHistory.length > 0) {
this.messages = localHistory;
this.maxSequenceId = this.messages.reduce((max, m) =>

View File

@ -0,0 +1,27 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { groupService } from '../services/group'
import { useMessage } from '../components/messages/useAlert'
import { SYSTEM_BASE_STATUS } from '../constants/systemBaseStatus'
import { groupRequestDb } from '../utils/db/groupRequestDb'
export const useGroupRequestStore = defineStore('groupRequest', {
state: () => ({
groupRequest: []
}),
actions: {
async loadGroupRequest() {
this.groupRequest = await groupRequestDb.getAll()
const message = useMessage()
const res = await groupService.getGroupNotification()
if (res.code != SYSTEM_BASE_STATUS.SUCCESS) return message.error(res.message)
this.groupRequest = res.data
res.data.forEach((element) => {
groupRequestDb.save(element)
})
}
}
})

View File

@ -1,29 +1,36 @@
import { openDB } from "idb";
import { openDB } from 'idb'
const DBNAME = 'IM_DB';
const STORE_NAME = 'messages';
const CONVERSARION_STORE_NAME = 'conversations';
const CONTACT_STORE_NAME = 'contacts';
const DBNAME = 'IM_DB'
const STORE_NAME = 'messages'
const CONVERSARION_STORE_NAME = 'conversations'
const CONTACT_STORE_NAME = 'contacts'
const GROUP_REQUEST_STORE_NAME = 'groupRequests'
export const dbPromise = openDB(DBNAME, 7, {
upgrade(db) {
if (!db.objectStoreNames.contains(STORE_NAME)) {
const store = db.createObjectStore(STORE_NAME, { keyPath: 'msgId' });
store.createIndex('by-sessionId', 'sessionId');
store.createIndex('by-time', 'timeStamp');
store.createIndex('by-sequenceId', 'sequenceId');
store.createIndex('by-session-sequenceId', ['sessionId', 'sequenceId']);
}
if (!db.objectStoreNames.contains(CONVERSARION_STORE_NAME)) {
const store = db.createObjectStore(CONVERSARION_STORE_NAME, { keyPath: 'id' });
store.createIndex('by-id', 'id');
}
if (!db.objectStoreNames.contains(CONTACT_STORE_NAME)) {
const store = db.createObjectStore(CONTACT_STORE_NAME, { keyPath: 'id' });
store.createIndex('by-id', 'id');
store.createIndex('by-username', 'username');
store.createIndex('by-friendId', 'friendId', { unique: true });
}
upgrade(db) {
if (!db.objectStoreNames.contains(STORE_NAME)) {
const store = db.createObjectStore(STORE_NAME, { keyPath: 'msgId' })
store.createIndex('by-sessionId', 'sessionId')
store.createIndex('by-time', 'timeStamp')
store.createIndex('by-sequenceId', 'sequenceId')
store.createIndex('by-session-sequenceId', ['sessionId', 'sequenceId'])
}
})
if (!db.objectStoreNames.contains(CONVERSARION_STORE_NAME)) {
const store = db.createObjectStore(CONVERSARION_STORE_NAME, { keyPath: 'id' })
store.createIndex('by-id', 'id')
}
if (!db.objectStoreNames.contains(CONTACT_STORE_NAME)) {
const store = db.createObjectStore(CONTACT_STORE_NAME, { keyPath: 'id' })
store.createIndex('by-id', 'id')
store.createIndex('by-username', 'username')
store.createIndex('by-friendId', 'friendId', { unique: true })
}
if (!db.objectStoreNames.contains(GROUP_REQUEST_STORE_NAME)) {
const store = db.createObjectStore(GROUP_REQUEST_STORE_NAME, { keyPath: 'requestId' })
store.createIndex('by-id', 'requestId')
store.createIndex('by-userid', 'userId')
store.createIndex('by-groupid', 'groupId')
}
}
})

View File

@ -0,0 +1,12 @@
import { dbPromise } from "./baseDb";
const STORE_NAME = 'groupRequests'
export const groupRequestDb = {
async save(request){
(await dbPromise).put(STORE_NAME, request)
},
async getAll(){
(await dbPromise).getAll(STORE_NAME)
}
}

View File

@ -10,5 +10,5 @@ export const generateSessionId = (id1, id2, isGroup = false) => {
if (isGroup) {
return `g:${id2}`;
}
return [String(id1), String(id2)].sort().join('_');
return 'p:' + [String(id1), String(id2)].sort().join('_');
};

Some files were not shown because too many files have changed in this diff Show More