diff --git a/.ionide/symbolCache.db b/.ionide/symbolCache.db
new file mode 100644
index 0000000..8a73c4f
Binary files /dev/null and b/.ionide/symbolCache.db differ
diff --git a/.vs/Znyc.Dispatching/DesignTimeBuild/.dtbcache.v2 b/.vs/Znyc.Dispatching/DesignTimeBuild/.dtbcache.v2
new file mode 100644
index 0000000..f92d16d
Binary files /dev/null and b/.vs/Znyc.Dispatching/DesignTimeBuild/.dtbcache.v2 differ
diff --git a/.vs/Znyc.Dispatching/config/applicationhost.config b/.vs/Znyc.Dispatching/config/applicationhost.config
new file mode 100644
index 0000000..b96f9bc
--- /dev/null
+++ b/.vs/Znyc.Dispatching/config/applicationhost.config
@@ -0,0 +1,998 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.vs/Znyc.Dispatching/v16/.suo b/.vs/Znyc.Dispatching/v16/.suo
new file mode 100644
index 0000000..c4114ba
Binary files /dev/null and b/.vs/Znyc.Dispatching/v16/.suo differ
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..8524d96
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,69 @@
+{
+ // 使用 IntelliSense 了解相关属性。
+ // 悬停以查看现有属性的描述。
+ // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": ".NET Core Launch (console)",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ "program": "${workspaceFolder}/bin/Debug//",
+ "args": [],
+ "cwd": "${workspaceFolder}",
+ "stopAtEntry": false,
+ "console": "internalConsole",
+ "pipeTransport": {
+ "pipeCwd": "${workspaceFolder}",
+ "pipeProgram": "enter the fully qualified path for the pipe program name, for example '/usr/bin/ssh'",
+ "pipeArgs": [],
+ "debuggerPath": "enter the path for the debugger on the target machine, for example ~/vsdbg/vsdbg"
+ }
+ },
+ {
+ "name": ".NET Core Launch (web)",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ "program": "${workspaceFolder}/bin/Debug//",
+ "args": [],
+ "cwd": "${workspaceFolder}",
+ "stopAtEntry": false,
+ "serverReadyAction": {
+ "action": "openExternally",
+ "pattern": "\\bNow listening on:\\s+(https?://\\S+)"
+ },
+ "env": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "sourceFileMap": {
+ "/Views": "${workspaceFolder}/Views"
+ }
+ },
+ {
+ "name": ".NET Core Launch (console)",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ "program": "${workspaceFolder}/bin/Debug//",
+ "args": [],
+ "cwd": "${workspaceFolder}",
+ "stopAtEntry": false,
+ "console": "internalConsole"
+ },
+
+ {
+ "name": ".NET Core Launch (console)",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ "program": "${workspaceFolder}/bin/Debug//",
+ "args": [],
+ "cwd": "${workspaceFolder}",
+ "stopAtEntry": false,
+ "console": "internalConsole"
+ }
+
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/solution-explorer/class.cs-template b/.vscode/solution-explorer/class.cs-template
new file mode 100644
index 0000000..015da46
--- /dev/null
+++ b/.vscode/solution-explorer/class.cs-template
@@ -0,0 +1,8 @@
+using System;
+
+namespace {{namespace}}
+{
+ public class {{name}}
+ {
+ }
+}
diff --git a/.vscode/solution-explorer/class.ts-template b/.vscode/solution-explorer/class.ts-template
new file mode 100644
index 0000000..ff2edef
--- /dev/null
+++ b/.vscode/solution-explorer/class.ts-template
@@ -0,0 +1,3 @@
+export class {{name}} {
+
+}
\ No newline at end of file
diff --git a/.vscode/solution-explorer/class.vb-template b/.vscode/solution-explorer/class.vb-template
new file mode 100644
index 0000000..38ef67f
--- /dev/null
+++ b/.vscode/solution-explorer/class.vb-template
@@ -0,0 +1,9 @@
+Imports System
+
+Namespace {{namespace}}
+
+ Public Class {{name}}
+
+ End Class
+
+End Namespace
diff --git a/.vscode/solution-explorer/default.ts-template b/.vscode/solution-explorer/default.ts-template
new file mode 100644
index 0000000..04af870
--- /dev/null
+++ b/.vscode/solution-explorer/default.ts-template
@@ -0,0 +1,3 @@
+export default {{name}} {
+
+}
\ No newline at end of file
diff --git a/.vscode/solution-explorer/enum.cs-template b/.vscode/solution-explorer/enum.cs-template
new file mode 100644
index 0000000..7d4cdee
--- /dev/null
+++ b/.vscode/solution-explorer/enum.cs-template
@@ -0,0 +1,8 @@
+using System;
+
+namespace {{namespace}}
+{
+ public enum {{name}}
+ {
+ }
+}
diff --git a/.vscode/solution-explorer/interface.cs-template b/.vscode/solution-explorer/interface.cs-template
new file mode 100644
index 0000000..6b5dec1
--- /dev/null
+++ b/.vscode/solution-explorer/interface.cs-template
@@ -0,0 +1,8 @@
+using System;
+
+namespace {{namespace}}
+{
+ public interface {{name}}
+ {
+ }
+}
diff --git a/.vscode/solution-explorer/interface.ts-template b/.vscode/solution-explorer/interface.ts-template
new file mode 100644
index 0000000..3ea404b
--- /dev/null
+++ b/.vscode/solution-explorer/interface.ts-template
@@ -0,0 +1,3 @@
+export interface {{name}} {
+
+}
\ No newline at end of file
diff --git a/.vscode/solution-explorer/template-list.json b/.vscode/solution-explorer/template-list.json
new file mode 100644
index 0000000..2849622
--- /dev/null
+++ b/.vscode/solution-explorer/template-list.json
@@ -0,0 +1,46 @@
+{
+ "templates": [
+ {
+ "name": "Class",
+ "extension": "cs",
+ "file": "./class.cs-template",
+ "parameters": "./template-parameters.js"
+ },
+ {
+ "name": "Interface",
+ "extension": "cs",
+ "file": "./interface.cs-template",
+ "parameters": "./template-parameters.js"
+ },
+ {
+ "name": "Enum",
+ "extension": "cs",
+ "file": "./enum.cs-template",
+ "parameters": "./template-parameters.js"
+ },
+ {
+ "name": "Class",
+ "extension": "ts",
+ "file": "./class.ts-template",
+ "parameters": "./template-parameters.js"
+ },
+ {
+ "name": "Interface",
+ "extension": "ts",
+ "file": "./interface.ts-template",
+ "parameters": "./template-parameters.js"
+ },
+ {
+ "name": "Default",
+ "extension": "ts",
+ "file": "./default.ts-template",
+ "parameters": "./template-parameters.js"
+ },
+ {
+ "name": "Class",
+ "extension": "vb",
+ "file": "./class.vb-template",
+ "parameters": "./template-parameters.js"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/solution-explorer/template-parameters.js b/.vscode/solution-explorer/template-parameters.js
new file mode 100644
index 0000000..daba8b2
--- /dev/null
+++ b/.vscode/solution-explorer/template-parameters.js
@@ -0,0 +1,17 @@
+var path = require("path");
+
+module.exports = function(filename, projectPath, folderPath) {
+ var namespace = "Unknown";
+ if (projectPath) {
+ namespace = path.basename(projectPath, path.extname(projectPath));
+ if (folderPath) {
+ namespace += "." + folderPath.replace(path.dirname(projectPath), "").substring(1).replace(/[\\\/]/g, ".");
+ }
+ namespace = namespace.replace(/[\\\-]/g, "_");
+ }
+
+ return {
+ namespace: namespace,
+ name: path.basename(filename, path.extname(filename))
+ }
+};
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..31c32bd
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,24 @@
+{
+ // See https://go.microsoft.com/fwlink/?LinkId=733558
+ // for the documentation about the tasks.json format
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "shell",
+ "args": [
+ "build",
+ // Ask dotnet build to generate full paths for file names.
+ "/property:GenerateFullPaths=true",
+ // Do not generate summary otherwise it leads to duplicate errors in Problems panel
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "group": "build",
+ "presentation": {
+ "reveal": "silent"
+ },
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 0000000..0012440
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,34 @@
+#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
+
+FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
+WORKDIR /app
+EXPOSE 80
+EXPOSE 443
+
+ENV TZ=Asia/Shanghai
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+
+
+
+FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
+WORKDIR /src
+COPY ["Znyc.Dispatching.Web.Entry/Znyc.Dispatching.Web.Entry.csproj", "Znyc.Dispatching.Web.Entry/"]
+COPY ["Znyc.Dispatching.Web.Core/Znyc.Dispatching.Web.Core.csproj", "Znyc.Dispatching.Web.Core/"]
+COPY ["Znyc.Dispatching.Database.Migrations/Znyc.Dispatching.Database.Migrations.csproj", "Znyc.Dispatching.Database.Migrations/"]
+COPY ["Znyc.Dispatching.EntityFramework.Core/Znyc.Dispatching.EntityFramework.Core.csproj", "Znyc.Dispatching.EntityFramework.Core/"]
+COPY ["Znyc.Dispatching.Core/Znyc.Dispatching.Core.csproj", "Znyc.Dispatching.Core/"]
+COPY ["Znyc.Dispatching.Application/Znyc.Dispatching.Application.csproj", "Znyc.Dispatching.Application/"]
+COPY ["Znyc.Dispatching.MongoDb.Repository/Znyc.Dispatching.MongoDb.Repository.csproj", "Znyc.Dispatching.MongoDb.Repository/"]
+COPY ["Znyc.Dispatching.WeChat.Core/Znyc.Dispatching.WeChat.Core.csproj", "Znyc.Dispatching.WeChat.Core/"]
+RUN dotnet restore "Znyc.Dispatching.Web.Entry/Znyc.Dispatching.Web.Entry.csproj"
+COPY . .
+WORKDIR "/src/Znyc.Dispatching.Web.Entry"
+RUN dotnet build "Znyc.Dispatching.Web.Entry.csproj" -c Release -o /app/build
+
+FROM build AS publish
+RUN dotnet publish "Znyc.Dispatching.Web.Entry.csproj" -c Release -o /app/publish
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "Znyc.Dispatching.Web.Entry.dll"]
\ No newline at end of file
diff --git a/src/.dockerignore b/src/.dockerignore
new file mode 100644
index 0000000..3729ff0
--- /dev/null
+++ b/src/.dockerignore
@@ -0,0 +1,25 @@
+**/.classpath
+**/.dockerignore
+**/.env
+**/.git
+**/.gitignore
+**/.project
+**/.settings
+**/.toolstarget
+**/.vs
+**/.vscode
+**/*.*proj.user
+**/*.dbmdl
+**/*.jfm
+**/azds.yaml
+**/bin
+**/charts
+**/docker-compose*
+**/Dockerfile*
+**/node_modules
+**/npm-debug.log
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
+LICENSE
+README.md
\ No newline at end of file
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..be42968
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1,28 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+*.log
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the
\ No newline at end of file
diff --git a/src/.vscode/launch.json b/src/.vscode/launch.json
new file mode 100644
index 0000000..69f0818
--- /dev/null
+++ b/src/.vscode/launch.json
@@ -0,0 +1,34 @@
+{
+ // 使用 IntelliSense 了解相关属性。
+ // 悬停以查看现有属性的描述。
+ // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": ".NET Core Launch (web)",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ "program": "${workspaceFolder}/Znyc.Dispatching.Web.Entry/bin/Debug/net5.0/Znyc.Dispatching.Web.Entry.dll",
+ "args": [],
+ "cwd": "${workspaceFolder}/Znyc.Dispatching.Web.Entry",
+ "stopAtEntry": false,
+ "serverReadyAction": {
+ "action": "openExternally",
+ "pattern": "\\bNow listening on:\\s+(https?://\\S+)"
+ },
+ "env": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "sourceFileMap": {
+ "/Views": "${workspaceFolder}/Views"
+ }
+ },
+ {
+ "name": ".NET Core Attach",
+ "type": "coreclr",
+ "request": "attach",
+ "processId": "${command:pickProcess}"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/.vscode/solution-explorer/class.cs-template b/src/.vscode/solution-explorer/class.cs-template
new file mode 100644
index 0000000..015da46
--- /dev/null
+++ b/src/.vscode/solution-explorer/class.cs-template
@@ -0,0 +1,8 @@
+using System;
+
+namespace {{namespace}}
+{
+ public class {{name}}
+ {
+ }
+}
diff --git a/src/.vscode/solution-explorer/class.ts-template b/src/.vscode/solution-explorer/class.ts-template
new file mode 100644
index 0000000..ff2edef
--- /dev/null
+++ b/src/.vscode/solution-explorer/class.ts-template
@@ -0,0 +1,3 @@
+export class {{name}} {
+
+}
\ No newline at end of file
diff --git a/src/.vscode/solution-explorer/class.vb-template b/src/.vscode/solution-explorer/class.vb-template
new file mode 100644
index 0000000..38ef67f
--- /dev/null
+++ b/src/.vscode/solution-explorer/class.vb-template
@@ -0,0 +1,9 @@
+Imports System
+
+Namespace {{namespace}}
+
+ Public Class {{name}}
+
+ End Class
+
+End Namespace
diff --git a/src/.vscode/solution-explorer/default.ts-template b/src/.vscode/solution-explorer/default.ts-template
new file mode 100644
index 0000000..04af870
--- /dev/null
+++ b/src/.vscode/solution-explorer/default.ts-template
@@ -0,0 +1,3 @@
+export default {{name}} {
+
+}
\ No newline at end of file
diff --git a/src/.vscode/solution-explorer/enum.cs-template b/src/.vscode/solution-explorer/enum.cs-template
new file mode 100644
index 0000000..7d4cdee
--- /dev/null
+++ b/src/.vscode/solution-explorer/enum.cs-template
@@ -0,0 +1,8 @@
+using System;
+
+namespace {{namespace}}
+{
+ public enum {{name}}
+ {
+ }
+}
diff --git a/src/.vscode/solution-explorer/interface.cs-template b/src/.vscode/solution-explorer/interface.cs-template
new file mode 100644
index 0000000..6b5dec1
--- /dev/null
+++ b/src/.vscode/solution-explorer/interface.cs-template
@@ -0,0 +1,8 @@
+using System;
+
+namespace {{namespace}}
+{
+ public interface {{name}}
+ {
+ }
+}
diff --git a/src/.vscode/solution-explorer/interface.ts-template b/src/.vscode/solution-explorer/interface.ts-template
new file mode 100644
index 0000000..3ea404b
--- /dev/null
+++ b/src/.vscode/solution-explorer/interface.ts-template
@@ -0,0 +1,3 @@
+export interface {{name}} {
+
+}
\ No newline at end of file
diff --git a/src/.vscode/solution-explorer/template-list.json b/src/.vscode/solution-explorer/template-list.json
new file mode 100644
index 0000000..2849622
--- /dev/null
+++ b/src/.vscode/solution-explorer/template-list.json
@@ -0,0 +1,46 @@
+{
+ "templates": [
+ {
+ "name": "Class",
+ "extension": "cs",
+ "file": "./class.cs-template",
+ "parameters": "./template-parameters.js"
+ },
+ {
+ "name": "Interface",
+ "extension": "cs",
+ "file": "./interface.cs-template",
+ "parameters": "./template-parameters.js"
+ },
+ {
+ "name": "Enum",
+ "extension": "cs",
+ "file": "./enum.cs-template",
+ "parameters": "./template-parameters.js"
+ },
+ {
+ "name": "Class",
+ "extension": "ts",
+ "file": "./class.ts-template",
+ "parameters": "./template-parameters.js"
+ },
+ {
+ "name": "Interface",
+ "extension": "ts",
+ "file": "./interface.ts-template",
+ "parameters": "./template-parameters.js"
+ },
+ {
+ "name": "Default",
+ "extension": "ts",
+ "file": "./default.ts-template",
+ "parameters": "./template-parameters.js"
+ },
+ {
+ "name": "Class",
+ "extension": "vb",
+ "file": "./class.vb-template",
+ "parameters": "./template-parameters.js"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/.vscode/solution-explorer/template-parameters.js b/src/.vscode/solution-explorer/template-parameters.js
new file mode 100644
index 0000000..daba8b2
--- /dev/null
+++ b/src/.vscode/solution-explorer/template-parameters.js
@@ -0,0 +1,17 @@
+var path = require("path");
+
+module.exports = function(filename, projectPath, folderPath) {
+ var namespace = "Unknown";
+ if (projectPath) {
+ namespace = path.basename(projectPath, path.extname(projectPath));
+ if (folderPath) {
+ namespace += "." + folderPath.replace(path.dirname(projectPath), "").substring(1).replace(/[\\\/]/g, ".");
+ }
+ namespace = namespace.replace(/[\\\-]/g, "_");
+ }
+
+ return {
+ namespace: namespace,
+ name: path.basename(filename, path.extname(filename))
+ }
+};
\ No newline at end of file
diff --git a/src/.vscode/tasks.json b/src/.vscode/tasks.json
new file mode 100644
index 0000000..85740d9
--- /dev/null
+++ b/src/.vscode/tasks.json
@@ -0,0 +1,42 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}/Znyc.Dispatching.Web.Entry/Znyc.Dispatching.Web.Entry.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "publish",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "publish",
+ "${workspaceFolder}/Znyc.Dispatching.Web.Entry/Znyc.Dispatching.Web.Entry.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "watch",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "watch",
+ "run",
+ "${workspaceFolder}/Znyc.Dispatching.Web.Entry/Znyc.Dispatching.Web.Entry.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/Dockerfile b/src/Dockerfile
new file mode 100644
index 0000000..c221dd2
--- /dev/null
+++ b/src/Dockerfile
@@ -0,0 +1,33 @@
+#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
+
+FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
+WORKDIR /app
+EXPOSE 80
+EXPOSE 443
+
+ENV TZ=Asia/Shanghai
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+
+
+FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
+WORKDIR /src
+COPY ["Znyc.Dispatching.Web.Entry/Znyc.Dispatching.Web.Entry.csproj", "Znyc.Dispatching.Web.Entry/"]
+COPY ["Znyc.Dispatching.Web.Core/Znyc.Dispatching.Web.Core.csproj", "Znyc.Dispatching.Web.Core/"]
+COPY ["Znyc.Dispatching.Database.Migrations/Znyc.Dispatching.Database.Migrations.csproj", "Znyc.Dispatching.Database.Migrations/"]
+COPY ["Znyc.Dispatching.EntityFramework.Core/Znyc.Dispatching.EntityFramework.Core.csproj", "Znyc.Dispatching.EntityFramework.Core/"]
+COPY ["Znyc.Dispatching.Core/Znyc.Dispatching.Core.csproj", "Znyc.Dispatching.Core/"]
+COPY ["Znyc.Dispatching.Application/Znyc.Dispatching.Application.csproj", "Znyc.Dispatching.Application/"]
+COPY ["Znyc.Dispatching.MongoDb.Repository/Znyc.Dispatching.MongoDb.Repository.csproj", "Znyc.Dispatching.MongoDb.Repository/"]
+COPY ["Znyc.Dispatching.WeChat.Core/Znyc.Dispatching.WeChat.Core.csproj", "Znyc.Dispatching.WeChat.Core/"]
+RUN dotnet restore "Znyc.Dispatching.Web.Entry/Znyc.Dispatching.Web.Entry.csproj"
+COPY . .
+WORKDIR "/src/Znyc.Dispatching.Web.Entry"
+RUN dotnet build "Znyc.Dispatching.Web.Entry.csproj" -c Release -o /app/build
+
+FROM build AS publish
+RUN dotnet publish "Znyc.Dispatching.Web.Entry.csproj" -c Release -o /app/publish
+
+FROM base AS final
+WORKDIR /app
+COPY --from=publish /app/publish .
+ENTRYPOINT ["dotnet", "Znyc.Dispatching.Web.Entry.dll"]
\ No newline at end of file
diff --git a/src/Znyc.Dispatchimg.Test/ServiceTests/LoginServiceTest.cs b/src/Znyc.Dispatchimg.Test/ServiceTests/LoginServiceTest.cs
new file mode 100644
index 0000000..d9aecc3
--- /dev/null
+++ b/src/Znyc.Dispatchimg.Test/ServiceTests/LoginServiceTest.cs
@@ -0,0 +1,18 @@
+using Furion;
+using Znyc.Dispatching.Application;
+
+namespace Znyc.Dispatching.Tests.ServiceTests
+{
+ ///
+ /// 登录单元测试
+ ///
+ public class LoginServiceTest
+ {
+ private readonly ILoginService _loginService;
+ public LoginServiceTest()
+ {
+ _loginService = App.GetService();
+ }
+
+ }
+}
diff --git a/src/Znyc.Dispatchimg.Test/ServiceTests/VehicleServiceTest.cs b/src/Znyc.Dispatchimg.Test/ServiceTests/VehicleServiceTest.cs
new file mode 100644
index 0000000..a801d57
--- /dev/null
+++ b/src/Znyc.Dispatchimg.Test/ServiceTests/VehicleServiceTest.cs
@@ -0,0 +1,77 @@
+using Furion;
+using Furion.DatabaseAccessor;
+using Xunit;
+using Znyc.Dispatching.Core.Entitys;
+
+namespace Znyc.Dispatching.Tests
+{
+ ///
+ /// 车辆测试
+ ///
+ public class VehicleServiceTest
+ {
+ private readonly IRepository _employeeRepository;
+
+ /// private readonly ilo _vehicleService;
+ public VehicleServiceTest()
+ {
+ _employeeRepository = App.GetService>();
+ }
+
+ ///
+ /// 根据id获取车辆信息
+ ///
+ [Fact]
+ public async void GetVehicleByIdAsync()
+ {
+ Employee res = await _employeeRepository.FindAsync(162538803421253);
+ Assert.NotNull(res);
+ }
+
+ /////
+ ///// 根据id获取车辆Gps信息
+ /////
+ //[Fact]
+ //public async void GetVehicleGpsByIdAsync()
+ //{
+ // var res = await _vehicleService.GetVehicleGpsByIdAsync(162538803421253);
+ // Assert.NotNull(res);
+ //}
+ /////
+ ///// 获取地图信息
+ /////
+ //[Fact]
+ //public async void GetMapMonitorAsync()
+ //{
+ // var res = await _vehicleService.GetMapMonitorAsync();
+ // Assert.NotNull(res);
+ //}
+
+ /////
+ ///// 分页查询
+ /////
+ //[Fact]
+ //public async void PageAsync()
+ //{
+ // var res = await _vehicleService.PageAsync(0, 1, 10);
+ // Assert.NotNull(res);
+ //}
+
+ /////
+ ///// 修改车辆信息
+ /////
+ //[Fact]
+ //public async void UpdateAsync()
+ //{
+ // VehicleUpdateInput input = new VehicleUpdateInput()
+ // {
+ // VehicleCode = "Z01",
+ // VehiclePlate = "粤",
+ // ContactPerson = "单元",
+ // ContactPhone = "13111111111"
+ // };
+ // await _vehicleService.UpdateAsync(input);
+ // Assert.True(true);
+ //}
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatchimg.Test/Startup.cs b/src/Znyc.Dispatchimg.Test/Startup.cs
new file mode 100644
index 0000000..29ba202
--- /dev/null
+++ b/src/Znyc.Dispatchimg.Test/Startup.cs
@@ -0,0 +1,32 @@
+using Furion;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using Xunit;
+using Xunit.Abstractions;
+using Xunit.Sdk;
+using Znyc.Dispatching.Core;
+
+// 配置启动类类型,第一个参数是 Startup 类完整限定名,第二个参数是当前项目程序集名称
+[assembly: TestFramework("Znyc.Dispatching.Tests.Startup", "Znyc.Dispatching.Tests")]
+
+namespace Znyc.Dispatching.Tests
+{
+ ///
+ /// 单元测试启动类
+ ///
+ /// 在这里可以使用 Furion 几乎所有功能
+ public sealed class Startup : XunitTestFramework
+ {
+ public Startup(IMessageSink messageSink) : base(messageSink)
+ {
+ // 初始化 IServiceCollection 对象
+ IServiceCollection services = Inject.Create();
+
+ services.AddScoped();
+ services.TryAddSingleton();
+ // 构建 ServiceProvider 对象
+ services.Build();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatchimg.Test/UnitTest1.cs b/src/Znyc.Dispatchimg.Test/UnitTest1.cs
new file mode 100644
index 0000000..a3acb36
--- /dev/null
+++ b/src/Znyc.Dispatchimg.Test/UnitTest1.cs
@@ -0,0 +1,13 @@
+using Xunit;
+
+namespace Znyc.Dispatching.Tests
+{
+ public class UnitTest1
+ {
+ [Fact]
+ public void Test1()
+ {
+ Assert.Equal(2, 1 + 1);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatchimg.Test/Znyc.Dispatching.Tests.csproj b/src/Znyc.Dispatchimg.Test/Znyc.Dispatching.Tests.csproj
new file mode 100644
index 0000000..49b9cb3
--- /dev/null
+++ b/src/Znyc.Dispatchimg.Test/Znyc.Dispatching.Tests.csproj
@@ -0,0 +1,26 @@
+
+
+
+ net6.0
+ false
+
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Cache/Services/CacheService.cs b/src/Znyc.Dispatching.Application/Cache/Services/CacheService.cs
new file mode 100644
index 0000000..e5ba643
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Cache/Services/CacheService.cs
@@ -0,0 +1,1235 @@
+using CSRedis;
+using Furion.DatabaseAccessor;
+using Furion.DependencyInjection;
+using Furion.DynamicApiController;
+using Mapster;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Znyc.Dispatching.Core;
+using Znyc.Dispatching.Core.Cache;
+using Znyc.Dispatching.Core.Entitys;
+using Znyc.Dispatching.Core.Extension;
+using Znyc.Dispatching.MongoDb.Repository.Collection;
+
+namespace Znyc.Dispatching.Application
+{
+ ///
+ /// 系统缓存服务
+ ///
+ [ApiDescriptionSettings(Name = "cache", Order = 100)]
+ public class CacheService : ICacheService, IDynamicApiController, ITransient
+ {
+ private readonly IRepository _companyRepository;
+ private readonly IRepository _dictionaryRepository;
+ private readonly IRepository _employeeRepository;
+ private readonly IRedisCache _redisCache;
+ private readonly IRepository _vehicleRepository;
+ private readonly IRepository _yardRepository;
+ private readonly IRepository _userYardRepository;
+ private readonly IRepository _projectRepository;
+ private readonly IRepository _projectPersonRepository;
+ private readonly IRepository _orderRepository;
+ private readonly IRepository _vehiclePersonRepository;
+ private readonly IRepository _userRepository;
+
+ public CacheService(IRedisCache redisCache,
+ IRepository vehicleRepository,
+ IRepository companyRepository,
+ IRepository dictionaryRepository,
+ IRepository yardRepository,
+ IRepository userYardRepository,
+ IRepository employeeRepository,
+ IRepository vehiclePersonRepositor,
+ IRepository projectPersonRepository,
+ IRepository projectRepository,
+ IRepository userRepository,
+ IRepository orderRepository)
+ {
+ _redisCache = redisCache;
+ _vehicleRepository = vehicleRepository;
+ _companyRepository = companyRepository;
+ _dictionaryRepository = dictionaryRepository;
+ _employeeRepository = employeeRepository;
+ _yardRepository = yardRepository;
+ _userYardRepository = userYardRepository;
+ _projectRepository = projectRepository;
+ _projectPersonRepository = projectPersonRepository;
+ _vehiclePersonRepository = vehiclePersonRepositor;
+ _userRepository = userRepository;
+ _orderRepository = orderRepository;
+ }
+
+ #region 短信验证码
+
+ ///
+ /// 获取短信验证码缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task GetSmsCodeAsync(string phone)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_CODE + $"{phone}";
+ return await _redisCache.GetAsync(cacheKey);
+ }
+
+ ///
+ /// 设置短信验证码缓存
+ ///
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetSmsCodeAsync(string phone, string smsCode)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_CODE + $"{phone}";
+ return await _redisCache.SetAsync(cacheKey, smsCode, TimeSpan.FromMinutes(5));
+ }
+
+ ///
+ /// 删除短信验证码缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task RemoveSmsCodeAsync(string phone)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_CODE + $"{phone}";
+ await _redisCache.DelAsync(cacheKey);
+ }
+
+ #endregion 短信验证码
+
+ #region 权限
+
+ ///
+ /// 获取权限缓存(按钮)
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task> GetPermissionAsync(long userId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_PERMISSION + $"{userId}";
+ return await _redisCache.GetAsync>(cacheKey);
+ }
+
+ ///
+ /// 缓存权限
+ ///
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetPermissionAsync(long userId, List permissions)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_PERMISSION + $"{userId}";
+ await _redisCache.SetAsync(cacheKey, permissions);
+ }
+
+ #endregion 权限
+
+ #region 车辆分组
+
+ ///
+ /// 同步车辆分组缓存
+ ///
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetVehicleGroupListAsync(long companyId, List vehicleGroup)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_PERMISSION + $"{companyId}";
+ await _redisCache.SetAsync(cacheKey, vehicleGroup, TimeSpan.FromDays(31));
+ }
+
+ ///
+ /// 获取车辆分组缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task> GetVehicleGroupListAsync(long companyId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_PERMISSION + $"{companyId}";
+ return await _redisCache.GetAsync>(cacheKey);
+ }
+
+ ///
+ /// 同步车辆类型缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetVehicleTypeListAsync(List vehicleType)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_VEHICLETYPE;
+ await _redisCache.SetAsync(cacheKey, vehicleType, TimeSpan.FromDays(33));
+ }
+
+ ///
+ /// 获取车辆分组缓存
+ ///
+ ///
+ [NonAction]
+ public async Task> GetVehicleTypeListAsync()
+ {
+ string cacheKey = CommonConst.CACHE_KEY_VEHICLETYPE;
+
+ return await _redisCache.GetAsync>(cacheKey);
+ }
+
+ #endregion 车辆分组
+
+ #region 角色菜单
+
+ ///
+ /// 同步角色菜单缓存
+ ///
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetRoleMenuAsync(long roleId, List menuList)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_ROLEMENU + $"{roleId}";
+ await _redisCache.SetAsync(cacheKey, menuList, TimeSpan.FromDays(34));
+ }
+
+ ///
+ /// 获取角色菜单缓存
+ ///
+ ///
+ [NonAction]
+ public async Task> GetRoleMenuAsync(long roleId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_ROLEMENU + $"{roleId}";
+
+ return await _redisCache.GetAsync>(cacheKey);
+ }
+
+ ///
+ /// 删除角色菜单缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task RemoveRoleMenuAsync(long roleId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_ROLEMENU + $"{roleId}";
+ await _redisCache.DelAsync(cacheKey);
+ }
+
+ ///
+ /// 同步角色缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetRoleAsync(List role)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_ROLE;
+ await _redisCache.SetAsync(cacheKey, role, TimeSpan.FromDays(35));
+ }
+
+ ///
+ /// 获取角色缓存
+ ///
+ ///
+ [NonAction]
+ public async Task> GetRoleAsync()
+ {
+ string cacheKey = CommonConst.CACHE_KEY_ROLE;
+ return await _redisCache.GetAsync>(cacheKey);
+ }
+
+ #endregion 角色菜单
+
+ #region 字典类型
+
+ ///
+ /// 同步字典类型缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetDictionaryListAsync(List dictionaryLists)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_DICTIONARY;
+ await _redisCache.SetAsync(cacheKey, dictionaryLists);
+ }
+
+ ///
+ /// 获取字典缓存
+ ///
+ ///
+ [NonAction]
+ public async Task> GetDictionaryListAsync()
+ {
+ string cacheKey = CommonConst.CACHE_KEY_DICTIONARY;
+ return await _redisCache.CacheShellAsync(cacheKey, (int)TimeSpan.FromDays(365).TotalSeconds,
+ () => _dictionaryRepository.DetachedEntities
+ .Where(x => x.IsEnabled == (int)CommonStatusEnum.ENABLE)
+ .OrderBy(x => x.Sort)
+ .Select(x => new DictionaryOutput
+ {
+ Id = x.Id,
+ Code = x.Code,
+ Value = x.Value,
+ Name = x.Name,
+ Sort = x.Sort
+ })
+ .ToListAsync());
+ }
+
+ #endregion 字典类型
+
+ #region 公司
+
+ ///
+ /// 同步公司缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetComanyAsync(CompanyOutput company)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_COMPANY + $"{company.Id}";
+ await _redisCache.SetAsync(cacheKey, company, TimeSpan.FromDays(36));
+ }
+
+ ///
+ /// 获取公司缓存
+ ///
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task GetCompanyAsync(long companyId, long userId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_COMPANY + $"{companyId}";
+ //CompanyOutput companyOutput = await _redisCache.GetAsync(cacheKey);
+ var companyOutput = await _redisCache.CacheShellAsync(cacheKey, (int)TimeSpan.FromDays(30).TotalSeconds,
+ () => _companyRepository.Where(x => x.Id == companyId).Select(x => new CompanyOutput
+ {
+ Id = x.Id,
+ CompanyName = x.CompanyName,
+ Longitude = x.Longitude,
+ Latitude = x.Latitude,
+ Address = x.Address,
+ Status = x.Status,
+ StopTag = x.StopTag,
+ IsOpenDispatch = x.IsOpenDispatch,
+ IsSchedulingAddProject = x.IsSchedulingAddProject,
+ IsOpenVehicleType = x.IsOpenVehicleType
+ }).FirstOrDefaultAsync());
+ if (companyOutput.IsNotNull())
+ {
+ List yardList = await GetYardListAsync(companyId);
+ UserYard userYard = await _userYardRepository.DetachedEntities
+ .FirstOrDefaultAsync(x => x.UserId == userId && x.CompanyId == companyId && x.IsDefault == true);
+ List listOutputs = yardList.Adapt>();
+ if (userYard.IsNotNull())
+ {
+ foreach (var item in listOutputs)
+ {
+ if (item.Id == userYard.YardId)
+ {
+ item.IsDefault = true;
+ }
+ }
+ listOutputs = listOutputs.OrderByDescending(x => x.IsDefault).ToList();
+ }
+ companyOutput.yardList = yardList.Count != 0 ? listOutputs : new List() {
+ new YardListOutput()
+ {
+ Id = 0,
+ Address = companyOutput.Address,
+ Latitude = companyOutput.Latitude,
+ Longitude = companyOutput.Longitude,
+ IsDefault = false
+ }
+ };
+ }
+ return companyOutput;
+ }
+
+ ///
+ /// 删除公司缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task RemoveCompanyAsync(long companyId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_COMPANY + $"{companyId}";
+ await _redisCache.DelAsync(cacheKey);
+ }
+
+ #endregion 公司
+
+ #region 用户
+
+ ///
+ /// 同步用户缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetUserAsync(UserOutput user)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_USER + $"{user.Id}";
+ await _redisCache.SetAsync(cacheKey, user, TimeSpan.FromDays(41));
+ }
+
+ ///
+ /// 获取用户缓存
+ ///
+ ///
+ [NonAction]
+ public async Task GetUserAsync(long userId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_USER + $"{userId}";
+ var userOutput = await _redisCache.GetAsync(cacheKey);
+ return userOutput;
+ }
+
+ ///
+ /// 移除用户缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task RemoveUserAsync(long userId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_USER + $"{userId}";
+ await _redisCache.DelAsync(cacheKey);
+ }
+
+ ///
+ /// 删除用户所有缓存
+ ///
+ ///
+ [NonAction]
+ public async Task RemoveCacheByUserIdAsync(long userId)
+ {
+ await RemoveUserAsync(userId);
+ await RemoveCompanyAsync(userId);
+ await RemoveTokenAsync(userId);
+ }
+
+ #endregion 用户
+
+ #region Token
+
+ ///
+ /// 写入token
+ ///
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetTokenAsync(long userId, string token)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_TOKEN, userId);
+ await _redisCache.SetAsync(cacheKey, token, TimeSpan.FromDays(60));
+ }
+
+ ///
+ /// 移除token
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task RemoveTokenAsync(long userId)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_TOKEN, userId);
+ await _redisCache.DelAsync(cacheKey);
+ }
+
+ ///
+ /// 获取token
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task GetTokenAsync(long userId)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_TOKEN, userId);
+ return await _redisCache.GetAsync(cacheKey);
+ }
+
+ #endregion Token
+
+ #region 公司车辆
+
+ ///
+ /// 设置公司车辆缓存
+ ///
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetVehicleByCompanyIdAsync(long companyId, List vehicles)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_VEHICLEBYCOMPANYID + $"{companyId}";
+ await _redisCache.SetAsync(cacheKey, vehicles, TimeSpan.FromDays(7));
+ }
+
+ ///
+ /// 删除公司车辆缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task RemoveVehicleByCompanyIdAsync(long companyId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_VEHICLEBYCOMPANYID + $"{companyId}";
+ await _redisCache.DelAsync(cacheKey);
+ }
+
+ ///
+ /// 删除公司车辆缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task RemoveAllVehicleByCompanyIdAsync()
+ {
+ string cacheKey = CommonConst.CACHE_KEY_VEHICLEBYCOMPANYID + $"*";
+ await _redisCache.DelAsync(cacheKey);
+ }
+
+ ///
+ /// 获取公司车辆缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task> GetVehicleByCompanyIdAsync(long companyId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_VEHICLEBYCOMPANYID + $"{companyId}";
+ return await _redisCache.CacheShellAsync(cacheKey, (int)TimeSpan.FromDays(60).TotalSeconds, () =>
+ _vehicleRepository
+ .Where(x => x.CompanyId == companyId)
+ .Select(x => new VehicleGpsOutput
+ {
+ Id = x.Id,
+ CompanyId = x.CompanyId,
+ VehiclePlate = x.VehiclePlate,
+ VehicleCode = x.VehicleCode,
+ ContactPerson = x.ContactPerson,
+ ContactPhone = x.ContactPhone,
+ Status = x.Status,
+ IsActivate = x.IsActivate,
+ IsGps = x.IsGps,
+ SimNo = x.SimNo,
+ IsOverspeedAlarm = x.IsOverspeedAlarm,
+ Overspeed = x.Overspeed,
+ ImeiNo = x.ImeiNo,
+ OpenTime = x.OpenTime,
+ ExpireTime = x.ExpireTime,
+ Sort = x.Sort,
+ })
+ .OrderBy(x => x.Sort)
+ .ToListAsync());
+ }
+
+ ///
+ /// 获取公司车辆缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task> GetAllVehicleByCompanyIdAsync()
+ {
+ string cacheKey = CommonConst.CACHE_KEY_VEHICLEBYCOMPANYID + $"*";
+ return await _redisCache.CacheShellAsync(cacheKey, (int)TimeSpan.FromDays(1).TotalSeconds, () =>
+ _vehicleRepository
+ .Where(x => x.CompanyId != 0)
+ .Select(x => new VehicleGpsOutput
+ {
+ Id = x.Id,
+ CompanyId = x.CompanyId,
+ VehiclePlate = x.VehiclePlate,
+ VehicleCode = x.VehicleCode,
+ ContactPerson = x.ContactPerson,
+ ContactPhone = x.ContactPhone,
+ Status = x.Status,
+ IsActivate = x.IsActivate,
+ IsGps = x.IsGps,
+ SimNo = x.SimNo,
+ IsOverspeedAlarm = x.IsOverspeedAlarm,
+ Overspeed = x.Overspeed,
+ ImeiNo = x.ImeiNo,
+ OpenTime = x.OpenTime,
+ ExpireTime = x.ExpireTime,
+ Sort = x.Sort,
+ })
+ .OrderBy(x => x.Sort)
+ .ToListAsync());
+ }
+
+
+
+ #endregion 公司车辆
+
+ #region 车辆
+
+ ///
+ /// 设置车辆缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetVehicleAsync(Vehicle vehicle)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_VEHICLE + $"{vehicle.Id}";
+ await _redisCache.SetAsync(cacheKey, vehicle, TimeSpan.FromDays(8));
+ }
+
+ ///
+ /// 删除车辆缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task RemoveVehicleAsync(long vehicleId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_VEHICLE + $"{vehicleId}";
+ await _redisCache.DelAsync(cacheKey);
+ }
+
+ ///
+ /// 获取车辆缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task GetVehicleAsync(long vehicleId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_VEHICLE + $"{vehicleId}";
+ return await _redisCache.CacheShellAsync(cacheKey, (int)TimeSpan.FromDays(90).TotalSeconds,
+ () => _vehicleRepository.Where(x => x.Id == vehicleId).FirstOrDefaultAsync());
+ }
+
+
+ #endregion 车辆
+
+ #region 员工
+
+ ///
+ /// 设置员工缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetEmployeeAsync(EmployeeOutput employee)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_EMPLOYEE, employee.Id);
+ await _redisCache.SetAsync(cacheKey, employee, TimeSpan.FromDays(11));
+ }
+
+ ///
+ /// 删除员工缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task RemoveEmployeeAsync(long employeeId)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_EMPLOYEE, employeeId);
+ await _redisCache.DelAsync(cacheKey);
+ }
+
+ ///
+ /// 获取员工缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task GetEmployeeAsync(long employeeId)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_EMPLOYEE, employeeId);
+ return await _redisCache.CacheShellAsync(cacheKey, (int)TimeSpan.FromDays(90).TotalSeconds, () =>
+ _employeeRepository.Where(x => x.Id == employeeId).Select(x => new EmployeeOutput
+ {
+ Id = x.Id,
+ UserId = x.UserId,
+ AvatarUrl = x.AvatarUrl,
+ RoleId = x.RoleId,
+ RoleName = x.RoleName,
+ CompanyId = x.CompanyId,
+ EmployeeName = x.EmployeeName,
+ EmployeePhone = x.EmployeePhone,
+ Status = x.Status
+ }).FirstOrDefaultAsync());
+ }
+
+ ///
+ /// 设置员工列表缓存
+ ///
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetEmployeeListAsync(long companyId, List employees)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_EMPLOYEES, companyId);
+ await _redisCache.SetAsync(cacheKey, employees, TimeSpan.FromDays(13));
+ }
+
+ ///
+ /// 删除员工列表缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task RemoveEmployeeListAsync(long companyId)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_EMPLOYEES, companyId);
+ await _redisCache.DelAsync(cacheKey);
+ }
+
+ ///
+ /// 获取员工列表缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task> GetEmployeeListAsync(long companyId)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_EMPLOYEES, companyId);
+
+ return await _redisCache.CacheShellAsync(cacheKey, (int)TimeSpan.FromDays(95).TotalSeconds, () =>
+ _employeeRepository.DetachedEntities
+ .Where(x => x.CompanyId == companyId
+ && x.IsDeleted == false)
+ .Select(x => new EmployeeOutput
+ {
+ Id = x.Id,
+ UserId = x.UserId,
+ RoleId = x.RoleId,
+ RoleName = x.RoleName,
+ CompanyId = x.CompanyId,
+ EmployeeName = x.EmployeeName,
+ EmployeePhone = x.EmployeePhone,
+ Status = x.Status
+ }).ToListAsync());
+ }
+
+ public async Task PublishAsync(string channel, string message)
+ {
+ return await _redisCache.PublishAsync(channel, message);
+ }
+
+ public CSRedisClient.SubscribeObject Subscribe(
+ params (string, Action)[] channels)
+ {
+ return _redisCache.Subscribe(channels);
+ }
+
+ #endregion 员工
+
+ #region 未读警报提醒
+
+ ///
+ /// 设置未读警报提醒缓存
+ ///
+ ///
+ ///
+ public async Task SetUnreadAlarmAsync(long userId)
+ {
+ string key = string.Format(CommonConst.CACHE_KEY_UNREADALARM, userId);
+ await _redisCache.SetAsync(key, DateTime.Now, TimeSpan.FromDays(5));
+ }
+
+ ///
+ /// 删除未读警报提醒缓存
+ ///
+ ///
+ ///
+ public async Task RemoveUnreadAlarmAsync(long userId)
+ {
+ string key = string.Format(CommonConst.CACHE_KEY_UNREADALARM, userId);
+ await _redisCache.DelAsync(key);
+ }
+
+ ///
+ /// 获取未读警报提醒缓存
+ ///
+ ///
+ public async Task GetUnreadAlarmAsync(long userId)
+ {
+ string key = string.Format(CommonConst.CACHE_KEY_UNREADALARM, userId);
+ return await _redisCache.GetAsync(key);
+ }
+
+ #endregion
+
+ #region 轨迹回放
+ ///
+ /// 同步轨迹回放缓存
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task SeTrackPlaybackAsync(TrackPlaybackListOutput trackPlaybackListOutput, long vehicleId, DateTime startTime, DateTime endTime, TimeSpan expire)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_TRACKPLAYBACK + $"{vehicleId}{startTime.ToTimestamp()}{endTime.ToTimestamp()}";
+ await _redisCache.SetAsync(cacheKey, trackPlaybackListOutput, expire);
+ }
+
+ ///
+ /// 获取轨迹回放缓存
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task GetTrackPlaybackAsync(long vehicleId, DateTime startTime, DateTime endTime)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_TRACKPLAYBACK + $"{vehicleId}{startTime.ToTimestamp()}{endTime.ToTimestamp()}";
+ return await _redisCache.GetAsync(cacheKey);
+
+ }
+
+ ///
+ /// 删除轨迹回放缓存
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task RemoveTrackPlaybackAsync(long vehicleId, DateTime startTime, DateTime endTime)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_TRACKPLAYBACK + $"{vehicleId}{startTime.ToTimestamp()}{endTime.ToTimestamp()}";
+ await _redisCache.DelAsync(cacheKey);
+ }
+ #endregion
+
+ #region 车场
+ ///
+ /// 设置车场缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetYardAsync(YardOutput yard)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_YARD, yard.Id);
+ await _redisCache.SetAsync(cacheKey, yard, TimeSpan.FromDays(11));
+ }
+
+ ///
+ /// 删除车场缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task RemoveYardAsync(long yardId)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_YARD, yardId);
+ await _redisCache.DelAsync(cacheKey);
+ }
+
+ ///
+ /// 获取车场缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task GetYardAsync(long yardId)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_YARD, yardId);
+ return await _redisCache.CacheShellAsync(cacheKey, (int)TimeSpan.FromDays(90).TotalSeconds, () =>
+ _yardRepository.Where(x => x.Id == yardId).Select(x => new YardOutput
+ {
+ Id = x.Id,
+ ContactPerson = x.ContactPerson,
+ ContactPhone = x.ContactPhone,
+ IsDefault = false,
+ Latitude = x.Latitude,
+ Longitude = x.Longitude,
+ Address = x.Address,
+ }).FirstOrDefaultAsync());
+ }
+
+ ///
+ /// 设置车场列表缓存
+ ///
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetYardListAsync(long companyId, List yards)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_YARDS, companyId);
+ await _redisCache.SetAsync(cacheKey, yards, TimeSpan.FromDays(13));
+ }
+
+ ///
+ /// 删除车场列表缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task RemoveYardListAsync(long companyId)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_YARDS, companyId);
+ await _redisCache.DelAsync(cacheKey);
+ }
+
+ ///
+ /// 获取车场列表缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task> GetYardListAsync(long companyId)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_YARDS, companyId);
+ return await _redisCache.CacheShellAsync(cacheKey, (int)TimeSpan.FromDays(95).TotalSeconds, () =>
+ _yardRepository.DetachedEntities
+ .Where(x => x.CompanyId == companyId && x.Status == (int)CommonStatusEnum.ENABLE)
+ .Select(x => new YardOutput
+ {
+ Id = x.Id,
+ ContactPerson = x.ContactPerson,
+ ContactPhone = x.ContactPhone,
+ IsDefault = false,
+ Latitude = x.Latitude,
+ Longitude = x.Longitude,
+ Address = x.Address,
+ Status = x.Status
+ }).ToListAsync());
+ }
+ #endregion
+
+ #region 工程信息
+ ///
+ /// 同步工程列表缓存
+ ///
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetProjectListAsync(List projects, long companyId)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_PROJECTS, companyId);
+ await _redisCache.SetAsync(cacheKey, projects, TimeSpan.FromDays(15));
+ }
+
+ ///
+ /// 获取工程列表缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task> GetProjectListAsync(long companyId)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_PROJECTS, companyId);
+ var projectOutput = await _redisCache.GetAsync>(cacheKey);
+ if (projectOutput.IsNull())
+ {
+ projectOutput = await _projectRepository.DetachedEntities
+ .Where(x => x.IsDeleted == false && x.CompanyId == companyId)
+ .Select(x => new ProjectListOutput
+ {
+ Id = x.Id,
+ ProjectName = x.ProjectName,
+ SalesmanId = x.SalesmanId,
+ Address = x.Address,
+ Latitude = x.Latitude,
+ Longitude = x.Longitude,
+ IsEnabled = x.IsEnabled,
+ ConstructionId = x.ConstructionId
+ }).ToListAsync();
+ long[] projectIds = projectOutput.Select(x => x.Id).Distinct().ToArray();
+ List projectPersons = await _projectPersonRepository.DetachedEntities
+ .Where(x => projectIds.Contains(x.ProjectId) && x.IsDeleted == false)
+ .ToListAsync();
+ projectOutput.ForEach(item =>
+ {
+ item.ProjectPeoples = projectPersons.Where(x => x.ProjectId == item.Id).Select(x => new ProjectPersonOutput
+ {
+ ProjectPersonId = x.ProjectPersonId,
+ ProjectPersonName = x.ProjectPersonName,
+ ProjectPersonPhone = x.ProjectPersonPhone
+ }).ToList();
+ });
+ await SetProjectListAsync(projectOutput, companyId);
+ }
+
+ return projectOutput;
+ }
+
+ ///
+ /// 删除工程列表缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task RemoveProjectListAsync(long companyId)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_PROJECTS, companyId);
+ await _redisCache.DelAsync(cacheKey);
+ }
+
+ ///
+ /// 设置工程缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetProjectAsync(ProjectOutput project)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_PROJECT, project.Id);
+ await _redisCache.SetAsync(cacheKey, project, TimeSpan.FromDays(11));
+ }
+
+ ///
+ /// 删除工程缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task RemoveProjectAsync(long projectId)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_PROJECT, projectId);
+ await _redisCache.DelAsync(cacheKey);
+ }
+
+ ///
+ /// 获取工程缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task GetProjectAsync(long projectId)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_PROJECT, projectId);
+ List projectPeoples = await _projectPersonRepository.DetachedEntities
+ .Where(x => x.ProjectId == projectId && x.IsDeleted == false)
+ .Select(x => new ProjectPersonOutput
+ {
+ ProjectPersonId = x.ProjectPersonId,
+ ProjectPersonName = x.ProjectPersonName,
+ ProjectPersonPhone = x.ProjectPersonPhone
+ }).ToListAsync();
+ return await _redisCache.CacheShellAsync(cacheKey, (int)TimeSpan.FromDays(90).TotalSeconds, () =>
+ _projectRepository.Where(x => x.Id == projectId).Select(x => new ProjectOutput
+ {
+ Id = x.Id,
+ ProjectName = x.ProjectName,
+ SalesmanId = x.SalesmanId,
+ Longitude = x.Longitude,
+ Latitude = x.Latitude,
+ Address = x.Address,
+ IsEnabled = x.IsEnabled,
+ ProjectPeoples = projectPeoples,
+ ConstructionId = x.ConstructionId,
+ ConstructionName = x.ConstructionName
+ }).FirstOrDefaultAsync());
+ }
+
+ #endregion
+
+
+
+ #region 订单
+
+ ///
+ /// 设置订单列表缓存
+ ///
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetOrderListAsync(long companyId, List orders)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_EMPLOYEES, companyId);
+ await _redisCache.SetAsync(cacheKey, orders, TimeSpan.FromDays(5));
+ }
+
+ ///
+ /// 删除订单列表缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task RemoveOrderListAsync(long companyId)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_ORDERS, companyId);
+ await _redisCache.DelAsync(cacheKey);
+ }
+
+ ///
+ /// 获取订单列表缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task> GetOrderListAsync(long companyId)
+ {
+ string cacheKey = string.Format(CommonConst.CACHE_KEY_ORDERS, companyId);
+
+ return await _redisCache.CacheShellAsync(cacheKey, (int)TimeSpan.FromDays(30).TotalSeconds, () =>
+ _orderRepository.DetachedEntities
+ .Where(x => x.CompanyId == companyId)
+ .Select(x => new OrderListOutput
+ {
+ OrderSourceName = "222"
+ //RoleId = x.RoleId,
+ //RoleName = x.RoleName,
+ //CompanyId = x.CompanyId,
+ //EmployeeName = x.EmployeeName,
+ //OrderContent = x.or
+ }).ToListAsync());
+ }
+ #endregion
+
+ #region 车组人员
+ ///
+ /// 设置车辆车组人员缓存
+ ///
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task SetVehiclePersonAsync(List vehiclePerson, long vehicleId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_VEHICLEPERSON + $"{vehicleId}";
+ await _redisCache.SetAsync(cacheKey, vehiclePerson, TimeSpan.FromDays(8));
+ }
+
+ ///
+ /// 删除车辆车组人员缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task RemoveVehiclePersonAsync(long vehicleId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_VEHICLEPERSON + $"{vehicleId}";
+ await _redisCache.DelAsync(cacheKey);
+ }
+
+ ///
+ /// 获取车辆车组人员缓存
+ ///
+ ///
+ ///
+ [NonAction]
+ public async Task> GetVehiclePersonAsync(long vehicleId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_VEHICLEPERSON + $"{vehicleId}";
+ return await _redisCache.CacheShellAsync(cacheKey, (int)TimeSpan.FromDays(90).TotalSeconds,
+ () => _vehiclePersonRepository.Where(x => x.IsDeleted == false).Select(x => new VehiclePersonOutput
+ {
+ Id = x.Id,
+ VehicleId = x.VehicleId,
+ UserId = x.UserId,
+ UserName = x.UserName,
+ UserPhone = x.UserPhone,
+ IsDriver = x.IsDriver
+ }).Where(x => x.VehicleId == vehicleId).ToListAsync());
+ }
+
+ #endregion
+
+
+ #region Order
+ ///
+ /// 设置缓存
+ ///
+ ///
+ ///
+ ///
+ public async Task SetVehicleGpsAsync(long orderId, dynamic clay)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_GPSREALTIME + $"{orderId}";
+ await _redisCache.SetAsync(cacheKey, clay, TimeSpan.FromDays(1));
+
+ }
+
+ ///
+ /// 删除缓存
+ ///
+ ///
+ ///
+ public async Task RemoveVehicleGpsAsync(long orderId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_GPSREALTIME + $"{orderId}";
+ await _redisCache.DelAsync(cacheKey);
+
+ }
+
+ ///
+ /// 获取缓存
+ ///
+ ///
+ ///
+ public async Task GetVehicleGpsAsync(long orderId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_GPSREALTIME + $"{orderId}";
+ return await _redisCache.GetAsync(cacheKey);
+ }
+ #endregion
+
+
+
+ ///
+ /// 设置缓存
+ ///
+ ///
+ ///
+ public async Task SetOrderReadAsync(long orderId, string messageType)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_ORDERREAD + $"{orderId}";
+ await _redisCache.SetAsync(cacheKey, messageType);
+ }
+
+ ///
+ /// 删除缓存
+ ///
+ ///
+ ///
+ public async Task RemoveOrderReadAsync(long orderId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_ORDERREAD + $"{orderId}";
+ await _redisCache.DelAsync(cacheKey);
+ }
+
+ ///
+ /// 获取缓存
+ ///
+ ///
+ ///
+ public async Task GetOrderReadAsync(long orderId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_ORDERREAD + $"{orderId}";
+ return await _redisCache.GetAsync(cacheKey);
+ }
+
+ ///
+ /// 获取缓存
+ ///
+ ///
+ ///
+ public async Task ExistsOrderReadAsync(long orderId)
+ {
+ string cacheKey = CommonConst.CACHE_KEY_ORDERREAD + $"{orderId}";
+ return await _redisCache.ExistsAsync(cacheKey);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Cache/Services/ICacheService.cs b/src/Znyc.Dispatching.Application/Cache/Services/ICacheService.cs
new file mode 100644
index 0000000..d6375ab
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Cache/Services/ICacheService.cs
@@ -0,0 +1,554 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Znyc.Dispatching.Core.Entitys;
+using Znyc.Dispatching.MongoDb.Repository.Collection;
+using static CSRedis.CSRedisClient;
+
+namespace Znyc.Dispatching.Application
+{
+ public interface ICacheService
+ {
+ ///
+ /// 获取短信验证码
+ ///
+ ///
+ ///
+ Task GetSmsCodeAsync(string phone);
+
+ ///
+ /// 设置验证码缓存
+ ///
+ ///
+ ///
+ ///
+ Task SetSmsCodeAsync(string phone, string smsCode);
+
+ ///
+ /// 删除验证码
+ ///
+ ///
+ ///
+ Task RemoveSmsCodeAsync(string phone);
+
+ ///
+ /// 获取权限缓存(按钮)
+ ///
+ ///
+ ///
+ Task> GetPermissionAsync(long userId);
+
+ ///
+ /// 缓存权限
+ ///
+ ///
+ ///
+ ///
+ Task SetPermissionAsync(long userId, List permissions);
+
+ ///
+ /// 同步车辆分组缓存
+ ///
+ ///
+ ///
+ ///
+ Task SetVehicleGroupListAsync(long companyId, List vehicleGroup);
+
+ ///
+ /// 获取车辆分组缓存
+ ///
+ ///
+ ///
+ Task> GetVehicleGroupListAsync(long companyId);
+
+ ///
+ /// 同步车辆类型缓存
+ ///
+ ///
+ ///
+ Task SetVehicleTypeListAsync(List vehicleType);
+
+ ///
+ /// 获取车辆类型缓存
+ ///
+ ///
+ Task> GetVehicleTypeListAsync();
+
+ ///
+ /// 同步角色菜单缓存
+ ///
+ ///
+ ///
+ ///
+ Task SetRoleMenuAsync(long roleId, List menuList);
+
+ ///
+ /// 获取角色菜单缓存
+ ///
+ ///
+ ///
+ Task> GetRoleMenuAsync(long roleId);
+
+ ///
+ /// 删除角色菜单缓存
+ ///
+ ///
+ ///
+ Task RemoveRoleMenuAsync(long roleId);
+
+ ///
+ /// 同步角色缓存
+ ///
+ ///
+ ///
+ Task SetRoleAsync(List role);
+
+ ///
+ /// 获取角色缓存
+ ///
+ ///
+ Task> GetRoleAsync();
+
+ ///
+ /// 获取字典缓存
+ ///
+ ///
+ Task> GetDictionaryListAsync();
+
+ ///
+ /// 同步字典缓存
+ ///
+ ///
+ ///
+ Task SetDictionaryListAsync(List dictionaryLists);
+
+ ///
+ /// 同步公司缓存
+ ///
+ ///
+ ///
+ Task SetComanyAsync(CompanyOutput company);
+
+ ///
+ /// 获取公司缓存
+ ///
+ ///
+ ///
+ ///
+ Task GetCompanyAsync(long companyId, long userId);
+
+ ///
+ /// 删除公司缓存
+ ///
+ ///
+ ///
+ Task RemoveCompanyAsync(long companyId);
+
+ ///
+ /// 同步用户缓存
+ ///
+ ///
+ ///
+ Task SetUserAsync(UserOutput user);
+
+ ///
+ /// 获取用户缓存
+ ///
+ ///
+ ///
+ Task GetUserAsync(long userId);
+
+ ///
+ /// 移除用户缓存
+ ///
+ ///
+ ///
+ Task RemoveUserAsync(long userId);
+
+ ///
+ /// 删除用户所有缓存
+ ///
+ ///
+ Task RemoveCacheByUserIdAsync(long userId);
+
+ ///
+ /// 写入token
+ ///
+ ///
+ ///
+ ///
+ Task SetTokenAsync(long userId, string token);
+
+ ///
+ /// 移除token
+ ///
+ ///
+ ///
+ Task RemoveTokenAsync(long userId);
+
+ ///
+ /// 获取token
+ ///
+ ///
+ ///
+ Task GetTokenAsync(long userId);
+
+
+ ///
+ /// 发布
+ ///
+ ///
+ ///
+ ///
+ Task PublishAsync(string channel, string message);
+
+
+ ///
+ /// 订阅
+ ///
+ ///
+ ///
+ SubscribeObject Subscribe(params (string, Action)[] channels);
+
+ #region 公司车辆
+
+ ///
+ /// 设置公司车辆缓存
+ ///
+ ///
+ ///
+ ///
+ Task SetVehicleByCompanyIdAsync(long companyId, List vehicles);
+
+ ///
+ /// 删除公司车辆缓存
+ ///
+ ///
+ ///
+ Task RemoveVehicleByCompanyIdAsync(long companyId);
+
+
+ ///
+ /// 删除公司车辆缓存
+ ///
+ ///
+ ///
+ Task RemoveAllVehicleByCompanyIdAsync();
+
+
+ ///
+ /// 获取所有公司车辆缓存
+ ///
+ ///
+ ///
+ Task> GetAllVehicleByCompanyIdAsync();
+
+ ///
+ /// 获取公司车辆缓存
+ ///
+ ///
+ ///
+ Task> GetVehicleByCompanyIdAsync(long companyId);
+
+ #endregion 公司车辆
+
+ #region 车辆
+
+ ///
+ /// 设置车辆缓存
+ ///
+ ///
+ ///
+ Task SetVehicleAsync(Vehicle vehicle);
+
+ ///
+ /// 删除车辆缓存
+ ///
+ ///
+ ///
+ Task RemoveVehicleAsync(long vehicleId);
+
+ ///
+ /// 获取车辆缓存
+ ///
+ ///
+ ///
+ Task GetVehicleAsync(long vehicleId);
+
+ #endregion 车辆
+
+ #region 员工
+
+ ///
+ /// 设置车辆缓存
+ ///
+ ///
+ ///
+ Task SetEmployeeAsync(EmployeeOutput employee);
+
+ ///
+ /// 删除员工缓存
+ ///
+ ///
+ ///
+ Task RemoveEmployeeAsync(long employeeId);
+
+ ///
+ /// 获取员工缓存
+ ///
+ ///
+ ///
+ Task GetEmployeeAsync(long employeeId);
+
+ ///
+ /// 设置员工列表缓存
+ ///
+ ///
+ ///
+ ///
+ Task SetEmployeeListAsync(long companyId, List employees);
+
+ ///
+ /// 删除员工列表缓存
+ ///
+ ///
+ ///
+ Task RemoveEmployeeListAsync(long companyId);
+
+ ///
+ /// 获取员工列表缓存
+ ///
+ ///
+ ///
+ Task> GetEmployeeListAsync(long companyId);
+
+ #endregion 员工
+
+ #region 未读警报提醒
+
+ ///
+ /// 设置未读警报提醒缓存
+ ///
+ ///
+ ///
+ Task SetUnreadAlarmAsync(long userId);
+
+ ///
+ /// 删除未读警报提醒缓存
+ ///
+ ///
+ ///
+ Task RemoveUnreadAlarmAsync(long userId);
+
+ ///
+ /// 获取未读警报提醒缓存
+ ///
+ ///
+ Task GetUnreadAlarmAsync(long userId);
+
+ #endregion
+
+ #region 轨迹回放
+ ///
+ /// 同步轨迹回放缓存
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task SeTrackPlaybackAsync(TrackPlaybackListOutput trackPlaybackListOutput, long vehicleId, DateTime startTime, DateTime endTime, TimeSpan expire);
+
+ ///
+ /// 获取轨迹回放缓存
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task GetTrackPlaybackAsync(long vehicleId, DateTime startTime, DateTime endTime);
+
+ ///
+ /// 删除轨迹回放缓存
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task RemoveTrackPlaybackAsync(long vehicleId, DateTime startTime, DateTime endTime);
+ #endregion
+
+ #region 车场
+ ///
+ /// 设置车场缓存
+ ///
+ ///
+ ///
+ Task SetYardAsync(YardOutput yard);
+
+ ///
+ /// 删除车场缓存
+ ///
+ ///
+ ///
+ Task RemoveYardAsync(long yardId);
+
+ ///
+ /// 获取车场缓存
+ ///
+ ///
+ ///
+ Task GetYardAsync(long yardId);
+
+ ///
+ /// 设置车场列表缓存
+ ///
+ ///
+ ///
+ ///
+ Task SetYardListAsync(long companyId, List yards);
+
+ ///
+ /// 删除车场列表缓存
+ ///
+ ///
+ ///
+ Task RemoveYardListAsync(long companyId);
+
+ ///
+ /// 获取车场列表缓存
+ ///
+ ///
+ ///
+ Task> GetYardListAsync(long companyId);
+ #endregion
+
+
+ #region 工程信息
+ ///
+ /// 同步工程列表缓存
+ ///
+ ///
+ ///
+ ///
+ Task SetProjectListAsync(List projects, long companyId);
+
+ ///
+ /// 获取工程列表缓存
+ ///
+ ///
+ ///
+ Task> GetProjectListAsync(long companyId);
+
+ ///
+ /// 删除工程列表缓存
+ ///
+ ///
+ ///
+ Task RemoveProjectListAsync(long companyId);
+
+ ///
+ /// 设置工程缓存
+ ///
+ ///
+ ///
+ Task SetProjectAsync(ProjectOutput project);
+
+ ///
+ /// 删除工程缓存
+ ///
+ ///
+ ///
+ Task RemoveProjectAsync(long projectId);
+
+ ///
+ /// 获取工程缓存
+ ///
+ ///
+ ///
+ Task GetProjectAsync(long projectId);
+ #endregion
+
+ #region 车组人员
+ ///
+ /// 设置车辆车组人员缓存
+ ///
+ ///
+ ///
+ ///
+ Task SetVehiclePersonAsync(List vehiclePerson, long vehicleId);
+
+ ///
+ /// 删除车辆车组人员缓存
+ ///
+ ///
+ ///
+ Task RemoveVehiclePersonAsync(long vehicleId);
+
+ ///
+ /// 获取车辆车组人员缓存
+ ///
+ ///
+ ///
+ Task> GetVehiclePersonAsync(long vehicleId);
+
+ #endregion
+
+ #region Order
+ ///
+ /// 设置缓存
+ ///
+ ///
+ ///
+ ///
+ Task SetVehicleGpsAsync(long orderId, dynamic clay);
+
+ ///
+ /// 删除缓存
+ ///
+ ///
+ ///
+ Task RemoveVehicleGpsAsync(long orderId);
+
+ ///
+ /// 获取缓存
+ ///
+ ///
+ ///
+ Task GetVehicleGpsAsync(long orderId);
+
+
+ ///
+ /// 设置缓存
+ ///
+ ///
+ ///
+ ///
+ Task SetOrderReadAsync(long orderId, string messageType);
+
+ ///
+ /// 删除缓存
+ ///
+ ///
+ ///
+ Task RemoveOrderReadAsync(long orderId);
+
+ ///
+ /// 获取缓存
+ ///
+ ///
+ ///
+ Task GetOrderReadAsync(long orderId);
+
+
+
+ ///
+ /// 是否存在
+ ///
+ ///
+ ///
+ Task ExistsOrderReadAsync(long orderId);
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Company/Dto/Input/CompanyAddInput.cs b/src/Znyc.Dispatching.Application/Company/Dto/Input/CompanyAddInput.cs
new file mode 100644
index 0000000..3008b70
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Company/Dto/Input/CompanyAddInput.cs
@@ -0,0 +1,59 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Znyc.Dispatching.Application
+{
+ ///
+ /// 公司输入实体
+ ///
+ public class CompanyAddInput
+ {
+ ///
+ /// 公司名称
+ ///
+ [Required(ErrorMessage = "公司名称不能为空!")]
+ [MaxLength(18, ErrorMessage = "公司名称不得超过18个字")]
+ public string CompanyName { get; set; }
+
+ /////
+ ///// 公司Logo
+ /////
+ // public string CompanyLogo { get; set; }
+
+ ///
+ /// 联系人
+ ///
+ [MaxLength(8, ErrorMessage = "联系人不得超过8个字")]
+ public string ContactPerson { get; set; }
+
+ ///
+ /// 联系人电话
+ ///
+ //[Required(ErrorMessage = "联系人电话不能为空!"), MaxLength(11, ErrorMessage = "联系电话不能超过11位")]
+ //[RegularExpression("^[1][3,4,5,6,7,8,9][0-9]{9}$", ErrorMessage = "请输入正确的手机号码")]
+ public string ContactPhone { get; set; }
+
+ ///
+ /// 精度
+ ///
+ [Required(ErrorMessage = "地址不能为空!")]
+ public decimal Longitude { get; set; }
+
+ ///
+ /// 纬度
+ ///
+ [Required(ErrorMessage = "地址不能为空!")]
+ public decimal Latitude { get; set; }
+
+ ///
+ /// 地址
+ ///
+ [Required(ErrorMessage = "地址不能为空!")]
+ [MaxLength(35, ErrorMessage = "地址不得超过35个字")]
+ public string Address { get; set; }
+
+ ///
+ /// OpenId
+ ///
+ public string JsCode { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Company/Dto/Input/CompanyUpdateInput.cs b/src/Znyc.Dispatching.Application/Company/Dto/Input/CompanyUpdateInput.cs
new file mode 100644
index 0000000..1b6b05e
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Company/Dto/Input/CompanyUpdateInput.cs
@@ -0,0 +1,9 @@
+namespace Znyc.Dispatching.Application
+{
+ ///
+ ///
+ public class CompanyUpdateInput : CompanyAddInput
+ {
+ public long Id { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Company/Dto/Input/RegisterInuput.cs b/src/Znyc.Dispatching.Application/Company/Dto/Input/RegisterInuput.cs
new file mode 100644
index 0000000..e996f2d
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Company/Dto/Input/RegisterInuput.cs
@@ -0,0 +1,61 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Znyc.Dispatching.Application
+{
+ ///
+ /// 平台入驻
+ ///
+ public class RegisterInuput
+ {
+
+ ///
+ /// JsCode
+ ///
+ public string JsCode { get; set; }
+
+ ///
+ /// 用户名
+ ///
+ [MaxLength(8, ErrorMessage = "用户名不得超过8个字")]
+ public string UserName { get; set; }
+
+ ///
+ /// 头像
+ ///
+ public string AvatarUrl { get; set; }
+
+ ///
+ /// 手机号
+ ///
+ [MaxLength(11, ErrorMessage = "手机号输入格式不正确")]
+ public string Phone { get; set; }
+
+
+ ///
+ /// 公司名称
+ ///
+ [Required(ErrorMessage = "公司名称不能为空!")]
+ [MaxLength(18, ErrorMessage = "公司名称不得超过18个字")]
+ public string CompanyName { get; set; }
+
+
+ ///
+ /// 精度
+ ///
+ [Required(ErrorMessage = "地址不能为空!")]
+ public decimal Longitude { get; set; }
+
+ ///
+ /// 纬度
+ ///
+ [Required(ErrorMessage = "地址不能为空!")]
+ public decimal Latitude { get; set; }
+
+ ///
+ /// 地址
+ ///
+ [Required(ErrorMessage = "地址不能为空!")]
+ [MaxLength(35, ErrorMessage = "地址不得超过35个字")]
+ public string Address { get; set; }
+ }
+}
diff --git a/src/Znyc.Dispatching.Application/Company/Dto/OutPut/CompanyOutput.cs b/src/Znyc.Dispatching.Application/Company/Dto/OutPut/CompanyOutput.cs
new file mode 100644
index 0000000..81b5fd9
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Company/Dto/OutPut/CompanyOutput.cs
@@ -0,0 +1,81 @@
+using System.Collections.Generic;
+
+namespace Znyc.Dispatching.Application
+{
+ public class CompanyOutput
+ {
+ ///
+ /// 主键
+ ///
+ public long Id { get; set; }
+
+ ///
+ /// 公司名称
+ ///
+ public string CompanyName { get; set; }
+
+ ///
+ /// 公司Logo
+ ///
+ public string CompanyLogo { get; set; }
+
+ ///
+ /// 精度
+ ///
+ public decimal Longitude { get; set; }
+
+ ///
+ /// 纬度
+ ///
+
+ public decimal Latitude { get; set; }
+
+ ///
+ /// 地址
+ ///
+ public string Address { get; set; }
+
+ ///
+ /// 状态(字典 0正常 1停用 2删除)
+ ///
+ public int Status { get; set; }
+
+ ///
+ /// 停留标示Id
+ ///
+ public long StopTag { get; set; }
+
+ ///
+ /// 车场
+ ///
+ public List yardList { get; set; }
+
+
+ #region #v1.2.3
+
+
+ ///
+ /// 一键派工是否显示工程名称
+ ///
+ public bool IsOpenDispatch { get; set; }
+
+
+ ///
+ /// 调度角色是否有添 加工程名称的权限
+ ///
+ public bool IsSchedulingAddProject { get; set; }
+
+ #endregion
+
+
+
+ #region v1.2.7
+
+ ///
+ /// 是否启用任务车型选项,默认为关
+ ///
+ public bool IsOpenVehicleType { get; set; }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Company/Services/CompanyService.cs b/src/Znyc.Dispatching.Application/Company/Services/CompanyService.cs
new file mode 100644
index 0000000..8f4f6f1
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Company/Services/CompanyService.cs
@@ -0,0 +1,307 @@
+using Furion.DatabaseAccessor;
+using Furion.DependencyInjection;
+using Furion.DynamicApiController;
+using Furion.FriendlyException;
+using Mapster;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Options;
+using Senparc.Weixin.WxOpen.AdvancedAPIs.Sns;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Threading.Tasks;
+using Znyc.Dispatching.Core;
+using Znyc.Dispatching.Core.Entitys;
+using Znyc.Dispatching.Core.Extension;
+using Znyc.Dispatching.Core.Helpers;
+
+namespace Znyc.Dispatching.Application
+{
+ ///
+ /// 公司服务
+ ///
+ [ApiDescriptionSettings(Name = "company", Order = 30)]
+ public class CompanyService : ICompanyService, IDynamicApiController, ITransient
+ {
+ private readonly ICacheService _cacheService;
+ private readonly IRepository _employeeRepository;
+ private readonly IRepository _repository;
+ private readonly IUserManager _userManager;
+ private readonly IRepository _userRepository;
+ private readonly IRepository _vehicleGroupRepository;
+ private readonly WeixinSettingOptions _weixinSettingOptions;
+ private readonly IRepository _yardRepository;
+ private readonly IRepository _userYardRepository;
+
+ public CompanyService(
+ IRepository repository,
+ IRepository employeeRepository,
+ IRepository userRepository,
+ IRepository vehicleGroupRepository,
+ IUserManager userManager,
+ ICacheService cacheService,
+ IRepository yardRepository,
+ IOptions weixinSettingOptions,
+ IRepository userYardRepository
+ )
+ {
+ _employeeRepository = employeeRepository;
+ _userRepository = userRepository;
+ _vehicleGroupRepository = vehicleGroupRepository;
+ _repository = repository;
+ _userManager = userManager;
+ _cacheService = cacheService;
+ _yardRepository = yardRepository;
+ _weixinSettingOptions = weixinSettingOptions.Value;
+ _userYardRepository = userYardRepository;
+ }
+
+
+
+ ///
+ /// 获取当前公司信息
+ ///
+ ///
+ [HttpGet]
+ [Route("api/v1/company")]
+ public async Task GetAsync()
+ {
+ return await _cacheService.GetCompanyAsync(_userManager.CompanyId, _userManager.UserId);
+ }
+
+ ///
+ /// 根据Id获取公司信息
+ ///
+ ///
+ ///
+ [HttpGet]
+ [Route("api/v1/company/{companyId}")]
+ public async Task GetByIdAsync(long companyId)
+ {
+ return await _cacheService.GetCompanyAsync(companyId, _userManager.UserId);
+ }
+
+ ///
+ /// 更新公司信息
+ ///
+ ///
+ ///
+ [HttpPut]
+ [Route("api/v1/company")]
+ public async Task UpdateAsync(CompanyUpdateInput companyUpdate)
+ {
+ var company = await _repository.FindAsync(companyUpdate.Id);
+ if (company.IsNotNull())
+ {
+ company.CompanyName = companyUpdate.CompanyName;
+ company.Latitude = companyUpdate.Latitude;
+ company.Longitude = companyUpdate.Longitude;
+ company.Address = companyUpdate.Address;
+ }
+ var companyId = (await _repository.UpdateNowAsync(company)).Entity.Id;
+ if (companyId == 0)
+ {
+ throw Oops.Bah("更新失败");
+ }
+ await _cacheService.RemoveCompanyAsync(_userManager.CompanyId);
+ await _cacheService.RemoveUserAsync(_userManager.UserId);
+ }
+
+ ///
+ /// 平台入驻
+ ///
+ ///
+ ///
+ [AllowAnonymous]
+ [UnitOfWork]
+ [HttpPost]
+ [Route("api/v1/register")]
+ public async Task RegisterAsync(RegisterInuput registerInuput)
+ {
+ var jsCode2JsonResult =
+ await SnsApi.JsCode2JsonAsync(_weixinSettingOptions.WxOpenAppId, _weixinSettingOptions.WxOpenAppSecret,
+ registerInuput.JsCode);
+ if (jsCode2JsonResult.IsNull())
+ {
+ throw Oops.Bah(ErrorCode.D1506);
+ }
+ var user = await _userRepository.FirstOrDefaultAsync(x => x.OpenId == jsCode2JsonResult.openid);
+ if (user.IsNotNull())
+ {
+ var employeeList = await _employeeRepository.DetachedEntities
+ .Where(x => x.UserId == user.Id && x.Status == (int)CommonStatusEnum.ENABLE)
+ .ToListAsync();
+ var cIds = employeeList.Select(x => x.CompanyId).ToArray();
+
+ //如果未包含管理员权限,可以一直注册
+ if (employeeList.Where(x => x.RoleId == (long)RoleStatusEnum.Administrator && x.Status == (int)CommonStatusEnum.ENABLE).Any())
+ {
+ throw Oops.Bah("您已注册公司");
+ }
+
+ }
+
+ var entity = registerInuput.Adapt();
+ entity.Status = (int)CommonStatusEnum.REVIEW;
+ entity.ContactPerson = registerInuput.UserName ?? "企业管理员";
+ entity.ContactPhone = registerInuput.Phone;
+ entity.CompanyLogo = CommonConst.DEFAULT_AVATARURL;
+ entity.StopTag = CommonConst.DEFAULT_STAPTAG;
+ var companyId = (await _repository.InsertNowAsync(entity)).Entity.Id;
+ if (companyId > 0)
+ {
+ var userId = user.IsNull() ? 0 : user.Id;
+ if (user.IsNull())
+ {
+ //用户
+ userId = (await _userRepository.InsertNowAsync(new User
+ {
+ OpenId = jsCode2JsonResult.openid,
+ AvatarUrl = registerInuput.AvatarUrl,
+ UserName = registerInuput.UserName ?? "企业管理员",
+ Phone = registerInuput.Phone,
+ Status = CommonStatusEnum.ENABLE
+ })).Entity.Id;
+ }
+ //员工
+ await _employeeRepository.InsertNowAsync(new Employee
+ {
+ UserId = userId,
+ AvatarUrl = CommonConst.DEFAULT_AVATARURL,
+ EmployeeName = registerInuput.UserName ?? "企业管理员",
+ EmployeePhone = registerInuput.Phone,
+ CompanyId = companyId,
+ RoleId = (int)RoleStatusEnum.Administrator,
+ RoleName = typeof(RoleStatusEnum).GetDescription((int)RoleStatusEnum.Administrator),
+ Status = (int)CommonStatusEnum.ENABLE,
+ IsDefault = true
+ });
+ //车辆分组
+ await _vehicleGroupRepository.InsertNowAsync(new VehicleGroup
+ {
+ CompanyId = companyId,
+ Name = "默认分组",
+ ParentId = 0
+ });
+ //车场
+ var yardId = (await _yardRepository.InsertNowAsync(new Yard
+ {
+ CompanyId = companyId,
+ Status = (int)CommonStatusEnum.ENABLE,
+ ContactPerson = registerInuput.UserName ?? "企业管理员",
+ ContactPhone = registerInuput.Phone,
+ Longitude = registerInuput.Longitude,
+ Latitude = registerInuput.Latitude,
+ Address = registerInuput.Address,
+
+ })).Entity.Id;
+
+ //用户车场映射
+ await _userYardRepository.InsertNowAsync(new UserYard
+ {
+ UserId = userId,
+ YardId = yardId,
+ CompanyId = companyId,
+ IsDefault = true
+ });
+ }
+ }
+
+
+ ///
+ /// 获取位置名称
+ ///
+ ///
+ ///
+ ///
+ [HttpGet]
+ [AllowAnonymous]
+ [Route("api/v1/address/{longitude}/{latitude}")]
+ public string GetAddress([Required] decimal longitude, [Required] decimal latitude)
+ {
+ string adress = MapHelper.GetLocationByLngLat(longitude, latitude);
+ return adress;
+ }
+
+ ///
+ /// 修改公司停留标示
+ ///
+ ///
+ ///
+ [HttpPut]
+ [Route("api/v1/company/stoptag/{stopTag}")]
+ public async Task UpdatStopTagAsync([Required] long stopTag)
+ {
+ var company = await _repository.FirstOrDefaultAsync(x => x.Id == _userManager.CompanyId);
+ if (company.IsNull())
+ {
+ throw Oops.Bah("公司不存在");
+ }
+ company.StopTag = stopTag;
+ await _repository.UpdateNowAsync(company);
+ await _cacheService.RemoveCompanyAsync(_userManager.CompanyId);
+ }
+
+
+
+
+ ///
+ /// 一键派工是否显示工程名称
+ ///
+ ///
+ [HttpPut]
+ [Route("api/v1/company/opendispatch")]
+ public async Task UpdateIsOpenDispatchAsync()
+ {
+ var company = await _repository.FirstOrDefaultAsync(x => x.Id == _userManager.CompanyId);
+ if (company.IsNull())
+ {
+ throw Oops.Bah("公司不存在");
+
+ }
+ company.IsOpenDispatch = !company.IsOpenDispatch;
+ await _repository.UpdateNowAsync(company);
+ await _cacheService.RemoveCompanyAsync(_userManager.CompanyId);
+ }
+
+
+ ///
+ /// 调度角色是否有添 加工程名称的权限
+ ///
+ ///
+ [HttpPut]
+ [Route("api/v1/company/schedulingaddproject")]
+ public async Task UpdateIsSchedulingAddProjectAsync()
+ {
+ var company = await _repository.FirstOrDefaultAsync(x => x.Id == _userManager.CompanyId);
+ if (company.IsNull())
+ {
+ throw Oops.Bah("公司不存在");
+
+ }
+ company.IsSchedulingAddProject = !company.IsSchedulingAddProject;
+ await _repository.UpdateNowAsync(company);
+ await _cacheService.RemoveCompanyAsync(_userManager.CompanyId);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ [HttpPut]
+ [Route("api/v1/company/isOpenVehicleType")]
+ public async Task UpdateIsOpenVehicleTypeAsync()
+ {
+ var company = await _repository.FirstOrDefaultAsync(x => x.Id == _userManager.CompanyId);
+ if (company.IsNull())
+ {
+ throw Oops.Bah("公司不存在");
+
+ }
+ company.IsOpenVehicleType = !company.IsOpenVehicleType;
+ await _repository.UpdateNowAsync(company);
+ await _cacheService.RemoveCompanyAsync(_userManager.CompanyId);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Company/Services/ICompanyService.cs b/src/Znyc.Dispatching.Application/Company/Services/ICompanyService.cs
new file mode 100644
index 0000000..82cc206
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Company/Services/ICompanyService.cs
@@ -0,0 +1,68 @@
+using System.Threading.Tasks;
+
+namespace Znyc.Dispatching.Application
+{
+ public interface ICompanyService
+ {
+ ///
+ /// 注册公司
+ ///
+ ///
+ ///
+ Task RegisterAsync(RegisterInuput registerInuput);
+
+ ///
+ /// 获取当前公司信息
+ ///
+ ///
+ Task GetAsync();
+
+ ///
+ /// 根据Id获取公司信息
+ ///
+ ///
+ Task GetByIdAsync(long companyId);
+
+ ///
+ /// 更新公司信息
+ ///
+ ///
+ ///
+ Task UpdateAsync(CompanyUpdateInput input);
+
+ ///
+ /// 获取位置名称
+ ///
+ ///
+ ///
+ ///
+ string GetAddress(decimal longitude, decimal latitude);
+
+ ///
+ /// 修改公司停留标示
+ ///
+ ///
+ ///
+ Task UpdatStopTagAsync(long stopTag);
+
+
+ ///
+ /// 一键派工是否显示工程名称
+ ///
+ ///
+ Task UpdateIsOpenDispatchAsync();
+
+ ///
+ /// 调度角色是否有添 加工程名称的权限
+ ///
+ ///
+ Task UpdateIsSchedulingAddProjectAsync();
+
+
+ ///
+ /// 新增是否启用任务车型选项,默认为关
+ ///
+ ///
+ Task UpdateIsOpenVehicleTypeAsync();
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Construction/Dto/Input/ConstructionAddInput.cs b/src/Znyc.Dispatching.Application/Construction/Dto/Input/ConstructionAddInput.cs
new file mode 100644
index 0000000..2df89bd
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Construction/Dto/Input/ConstructionAddInput.cs
@@ -0,0 +1,32 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace ZNYC.Recruitment.Service.Dictionary
+{
+ ///
+ /// 添加
+ ///
+ public class ConstructionAddInput
+ {
+ ///
+ /// 施工单位
+ ///
+ [Required(ErrorMessage = "请填写施工单位")]
+ public string ConstructionName { get; set; }
+
+ ///
+ /// 联系人
+ ///
+ public string ContactName { get; set; }
+
+ ///
+ /// 联系电话
+ ///
+ public string ContactPhone { get; set; }
+
+ ///
+ /// 状态
+ ///
+ public bool Status { get; set; }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Construction/Dto/Input/ConstructionUpdateInput.cs b/src/Znyc.Dispatching.Application/Construction/Dto/Input/ConstructionUpdateInput.cs
new file mode 100644
index 0000000..5462746
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Construction/Dto/Input/ConstructionUpdateInput.cs
@@ -0,0 +1,14 @@
+namespace ZNYC.Recruitment.Service.Dictionary
+{
+ ///
+ /// 修改
+ ///
+ public class ConstructionUpdateInput : ConstructionAddInput
+ {
+ ///
+ /// 主键Id
+ ///
+ public long Id { get; set; }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Construction/Dto/Output/ConstructionOutput.cs b/src/Znyc.Dispatching.Application/Construction/Dto/Output/ConstructionOutput.cs
new file mode 100644
index 0000000..305f659
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Construction/Dto/Output/ConstructionOutput.cs
@@ -0,0 +1,56 @@
+using System.Collections.Generic;
+
+namespace Znyc.Dispatching.Application
+{
+ public class ConstructionBaiscList
+ {
+ public long Total { get; set; }
+
+ public List ConstructionLetterOutputs { get; set; }
+ }
+
+
+ public class ConstructionLetterOutput
+ {
+ public string Char { get; set; }
+
+ public List List { get; set; }
+ }
+
+ public class ConstructionOutput
+ {
+
+ ///
+ /// Id
+ ///
+ public long Id { get; set; }
+
+ ///
+ /// 匹配索引列表,与车组人员共用一个列表,所以需增加UserId来进行匹配
+ ///
+ public long UserId
+ {
+ get { return Id; }
+ set { Id = value; }
+ }
+ ///
+ /// 施工单位
+ ///
+ public string ConstructionName { get; set; }
+
+ ///
+ /// 联系人
+ ///
+ public string ContactName { get; set; }
+
+ ///
+ /// 联系电话
+ ///
+ public string ContactPhone { get; set; }
+
+ ///
+ /// 状态
+ ///
+ public bool Status { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Construction/Services/ConstructionService.cs b/src/Znyc.Dispatching.Application/Construction/Services/ConstructionService.cs
new file mode 100644
index 0000000..6594c9f
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Construction/Services/ConstructionService.cs
@@ -0,0 +1,151 @@
+using Furion.DatabaseAccessor;
+using Furion.DependencyInjection;
+using Furion.DynamicApiController;
+using Furion.FriendlyException;
+using Mapster;
+using Microsoft.AspNetCore.Mvc;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Znyc.Dispatching.Core;
+using Znyc.Dispatching.Core.Entitys;
+using Znyc.Dispatching.Core.Extension;
+using Znyc.Dispatching.Core.Helpers;
+using ZNYC.Recruitment.Service.Dictionary;
+
+namespace Znyc.Dispatching.Application.Services
+{
+ ///
+ /// 施工单位
+ ///
+ [ApiDescriptionSettings(Name = "construction", Order = 259)]
+ public class ConstructionService : IConstructionService, IDynamicApiController, ITransient
+ {
+ private readonly ICacheService _cacheService;
+ private readonly IRepository _repository;
+ private readonly IRepository _projectRepository;
+
+ private readonly IUserManager _userManager;
+ private string[] INDEX_STRINGS = {"A", "B", "C", "D", "E", "F", "G", "H", "I",
+ "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
+ "W", "X", "Y", "Z", "#"};
+ public ConstructionService(
+ IRepository repository,
+ ICacheService cacheService,
+ IUserManager userManager,
+ IRepository projectRepository)
+ {
+ _repository = repository;
+ _cacheService = cacheService;
+ _userManager = userManager;
+ _projectRepository = projectRepository;
+ }
+
+ ///
+ /// InsertAsync
+ ///
+ ///
+ ///
+ [HttpPost]
+ [Route("api/v1/construction")]
+ public async Task InsertAsync(ConstructionAddInput constructionAddInput)
+ {
+ var result = false;
+ if (constructionAddInput.IsNotNull())
+ {
+ var isRepeatConstructionName = await _repository.AnyAsync(x => x.ConstructionName == constructionAddInput.ConstructionName && x.CompanyId == _userManager.CompanyId);
+ if (isRepeatConstructionName)
+ {
+ throw Oops.Bah($"施工单位重名,请修改");
+ }
+ var construction = constructionAddInput.Adapt();
+ construction.CompanyId = _userManager.CompanyId;
+ long id = (await _repository.InsertNowAsync(construction)).Entity.Id;
+ if (id > 0)
+ {
+ result = true;
+ }
+ }
+ return result;
+ }
+
+
+ ///
+ /// UpdateAsync
+ ///
+ ///
+ ///
+ [HttpPut]
+ [Route("api/v1/construction")]
+ public async Task UpdateAsync(ConstructionUpdateInput constructionUpdateInput)
+ {
+ var result = false;
+ if (constructionUpdateInput.IsNotNull())
+ {
+ var construction = await _repository.FindAsync(constructionUpdateInput.Id);
+ if (construction.IsNotNull())
+ {
+ var isRepeatConstructionName = await _repository.AnyAsync(x => x.ConstructionName == constructionUpdateInput.ConstructionName && x.Id != constructionUpdateInput.Id && x.CompanyId == _userManager.CompanyId);
+ if (isRepeatConstructionName)
+ {
+ throw Oops.Bah($"施工单位重名,请修改");
+ }
+ construction.ConstructionName = constructionUpdateInput.ConstructionName;
+ construction.ContactName = constructionUpdateInput.ContactName;
+ construction.ContactPhone = constructionUpdateInput.ContactPhone;
+ construction.Status = constructionUpdateInput.Status;
+ long id = (await _repository.UpdateNowAsync(construction)).Entity.Id;
+ if (id > 0)
+ {
+ //同步工程列表中施工单位名称
+ var projects = _projectRepository.Where(x => x.ConstructionId == id).ToList();
+ if (projects.Count > 0)
+ {
+ foreach (var project in projects)
+ {
+ project.ConstructionName = construction.ConstructionName;
+ await _projectRepository.UpdateNowAsync(project);
+ await _cacheService.RemoveProjectAsync(project.Id);
+ }
+ }
+ await _cacheService.RemoveProjectListAsync(_userManager.CompanyId);
+
+ result = true;
+ }
+ }
+ }
+ return result;
+ }
+
+
+
+ ///
+ /// ListAsync
+ ///
+ ///
+ [HttpGet]
+ [Route("api/v1/constructions/search")]
+ public async Task ListAsync(string key, int status)
+ {
+ var constructions = _repository.Where(x => x.CompanyId == _userManager.CompanyId)
+ .Where(key.IsNotEmptyOrNull(), x => x.ConstructionName.Contains(key))
+ .Where(status > 0, x => x.Status)
+ .ToList().Adapt>();
+ var constructionOutputs = new List();
+ foreach (var INDEX_STRING in INDEX_STRINGS)
+ {
+ constructionOutputs.Add(new ConstructionLetterOutput()
+ {
+ Char = INDEX_STRING,
+ List = constructions.Where(x => StringHelper.GetStringFirstSpell(x.ConstructionName) == INDEX_STRING).ToList()
+ });
+ };
+ var data = new ConstructionBaiscList()
+ {
+ ConstructionLetterOutputs = constructionOutputs,
+ Total = constructions.Count
+ };
+ return data;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Construction/Services/IConstructionService.cs b/src/Znyc.Dispatching.Application/Construction/Services/IConstructionService.cs
new file mode 100644
index 0000000..780d092
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Construction/Services/IConstructionService.cs
@@ -0,0 +1,31 @@
+using System.Threading.Tasks;
+using ZNYC.Recruitment.Service.Dictionary;
+
+namespace Znyc.Dispatching.Application.Services
+{
+ public interface IConstructionService
+ {
+
+ ///
+ /// InsertAsync
+ ///
+ ///
+ ///
+ public Task InsertAsync(ConstructionAddInput constructionAddInput);
+
+
+ ///
+ /// UpdateAsync
+ ///
+ ///
+ ///
+ public Task UpdateAsync(ConstructionUpdateInput constructionUpdateInput);
+
+
+ ///
+ ///
+ ///
+ ///
+ Task ListAsync(string key, int status);
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Dictionary/Dto/Input/DictionaryAddInput.cs b/src/Znyc.Dispatching.Application/Dictionary/Dto/Input/DictionaryAddInput.cs
new file mode 100644
index 0000000..10bbd5c
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Dictionary/Dto/Input/DictionaryAddInput.cs
@@ -0,0 +1,38 @@
+namespace ZNYC.Recruitment.Service.Dictionary
+{
+ ///
+ /// 添加
+ ///
+ public class DictionaryAddInput
+ {
+ ///
+ /// 字典父级
+ ///
+ public int ParentId { get; set; }
+
+ ///
+ /// 字典名称
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// 字典编码
+ ///
+ public string Code { get; set; }
+
+ ///
+ /// 字典值
+ ///
+ public string Value { get; set; }
+
+ ///
+ /// 描述
+ ///
+ public string Description { get; set; }
+
+ ///
+ /// 启用
+ ///
+ public bool IsEnable { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Dictionary/Dto/Input/DictionaryUpdateInput.cs b/src/Znyc.Dispatching.Application/Dictionary/Dto/Input/DictionaryUpdateInput.cs
new file mode 100644
index 0000000..931fd9d
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Dictionary/Dto/Input/DictionaryUpdateInput.cs
@@ -0,0 +1,18 @@
+namespace ZNYC.Recruitment.Service.Dictionary
+{
+ ///
+ /// 修改
+ ///
+ public class DictionaryUpdateInput : DictionaryAddInput
+ {
+ ///
+ /// 主键Id
+ ///
+ public int Id { get; set; }
+
+ ///
+ /// 版本
+ ///
+ public int Version { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Dictionary/Dto/Output/DictionaryOutput.cs b/src/Znyc.Dispatching.Application/Dictionary/Dto/Output/DictionaryOutput.cs
new file mode 100644
index 0000000..ca9cf48
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Dictionary/Dto/Output/DictionaryOutput.cs
@@ -0,0 +1,30 @@
+namespace Znyc.Dispatching.Application
+{
+ public class DictionaryOutput
+ {
+ ///
+ /// 主键Id
+ ///
+ public long Id { get; set; }
+
+ ///
+ /// 字典编码
+ ///
+ public string Code { get; set; }
+
+ ///
+ /// 字典值
+ ///
+ public string Value { get; set; }
+
+ ///
+ /// 字典名称
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// 排序
+ ///
+ public int Sort { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Dictionary/Services/DictionaryService.cs b/src/Znyc.Dispatching.Application/Dictionary/Services/DictionaryService.cs
new file mode 100644
index 0000000..8301aa5
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Dictionary/Services/DictionaryService.cs
@@ -0,0 +1,52 @@
+using Furion.DatabaseAccessor;
+using Furion.DependencyInjection;
+using Furion.DynamicApiController;
+using Microsoft.AspNetCore.Mvc;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Znyc.Dispatching.Core.Entitys;
+
+namespace Znyc.Dispatching.Application.Services
+{
+ ///
+ /// 字典服务
+ ///
+ [ApiDescriptionSettings(Name = "dictionary", Order = 200)]
+ public class DictionaryService : IDictionaryService, IDynamicApiController, ITransient
+ {
+ private readonly ICacheService _cacheService;
+ private readonly IRepository _repository;
+
+ public DictionaryService(
+ IRepository repository,
+ ICacheService cacheService)
+ {
+ _repository = repository;
+ _cacheService = cacheService;
+ }
+
+ ///
+ /// 根据Id获取字典
+ ///
+ ///
+ ///
+ [HttpGet]
+ public async Task GetAsync(long id)
+ {
+ List dictionarys = await _cacheService.GetDictionaryListAsync();
+ return dictionarys.Find(x => x.Id == id);
+ }
+
+ ///
+ /// 根据code获取字典
+ ///
+ ///
+ ///
+ [HttpGet]
+ public async Task> ListAsync(string code)
+ {
+ List dictionarys = await _cacheService.GetDictionaryListAsync();
+ return dictionarys.FindAll(x => x.Code == code);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Dictionary/Services/IDictionaryService.cs b/src/Znyc.Dispatching.Application/Dictionary/Services/IDictionaryService.cs
new file mode 100644
index 0000000..5844d34
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Dictionary/Services/IDictionaryService.cs
@@ -0,0 +1,22 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Znyc.Dispatching.Application.Services
+{
+ public interface IDictionaryService
+ {
+ ///
+ /// 根据Id获取字典
+ ///
+ ///
+ ///
+ Task GetAsync(long id);
+
+ ///
+ /// 根据code获取字典
+ ///
+ ///
+ ///
+ Task> ListAsync(string code);
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Document/Dto/Output/BucketTokenOutput.cs b/src/Znyc.Dispatching.Application/Document/Dto/Output/BucketTokenOutput.cs
new file mode 100644
index 0000000..a7b7a08
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Document/Dto/Output/BucketTokenOutput.cs
@@ -0,0 +1,24 @@
+namespace Znyc.Dispatching.Application
+{
+ public class BucketTokenOutput
+ {
+ public Credentials Credentials { get; set; }
+
+ public string Expiration { get; set; }
+
+ public int ExpiredTime { get; set; }
+
+ public string RequestId { get; set; }
+
+ public int StartTime { get; set; }
+ }
+
+ public class Credentials
+ {
+ public string TmpSecretId { get; set; }
+
+ public string TmpSecretKey { get; set; }
+
+ public string Token { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Document/Services/DocumentService.cs b/src/Znyc.Dispatching.Application/Document/Services/DocumentService.cs
new file mode 100644
index 0000000..e2f5917
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Document/Services/DocumentService.cs
@@ -0,0 +1,58 @@
+using COSSTS;
+using Furion.DependencyInjection;
+using Furion.DynamicApiController;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using Znyc.Dispatching.Core;
+
+namespace Znyc.Dispatching.Application
+{
+ ///
+ /// Cos服务
+ ///
+ [ApiDescriptionSettings(Name = "document", Order = 150, IgnoreApi = false)]
+ public class DocumentService : IDocumentService, IDynamicApiController, ITransient
+ {
+ private readonly UploadInfoOptions _uploadInfoOptions;
+
+ public DocumentService(
+ IOptions options
+ )
+ {
+ _uploadInfoOptions = options.Value;
+ }
+
+ ///
+ /// 获取COS_Token
+ ///
+ ///
+ [HttpGet]
+ [AllowAnonymous]
+ [Route("api/v1/costoken")]
+ public BucketTokenOutput GetBucketTokenAsync()
+ {
+ Dictionary values = new Dictionary
+ {
+ ["allowActions"] = _uploadInfoOptions.allowActions,
+ ["bucket"] = _uploadInfoOptions.bucket,
+ ["region"] = _uploadInfoOptions.region,
+ ["allowPrefix"] = _uploadInfoOptions.allowPrefix,
+ ["allowActions"] = _uploadInfoOptions.allowActions,
+ ["durationSeconds"] = _uploadInfoOptions.durationSeconds,
+ ["secretId"] = _uploadInfoOptions.secretId,
+ ["secretKey"] = _uploadInfoOptions.secretKey
+ };
+ Dictionary credential = STSClient.genCredential(values);
+ foreach (KeyValuePair kvp in credential)
+ {
+ Console.WriteLine("{0} = {1}", kvp.Key, kvp.Value);
+ }
+
+ return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(credential));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Document/Services/IDocumentService.cs b/src/Znyc.Dispatching.Application/Document/Services/IDocumentService.cs
new file mode 100644
index 0000000..6be73ad
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Document/Services/IDocumentService.cs
@@ -0,0 +1,11 @@
+namespace Znyc.Dispatching.Application
+{
+ public interface IDocumentService
+ {
+ ///
+ /// 获取COS_Token
+ ///
+ ///
+ BucketTokenOutput GetBucketTokenAsync();
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Employee/Dto/Input/EmployeeAddInput.cs b/src/Znyc.Dispatching.Application/Employee/Dto/Input/EmployeeAddInput.cs
new file mode 100644
index 0000000..34f0368
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Employee/Dto/Input/EmployeeAddInput.cs
@@ -0,0 +1,33 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Znyc.Dispatching.Application
+{
+ public class EmployeeAddInput
+ {
+ ///
+ /// 员工名
+ ///
+ [Required(ErrorMessage = "员工名不能为空!")]
+ public string EmployeeName { get; set; }
+
+ ///
+ /// 手机号
+ ///
+ [Required(ErrorMessage = "请输入手机号")]
+ [MaxLength(11, ErrorMessage = "手机号不能超过11位")]
+ [RegularExpression("^[1][3,4,5,6,7,8,9][0-9]{9}$", ErrorMessage = "请输入正确的手机号码")]
+ public string EmployeePhone { get; set; }
+
+ ///
+ /// 角色
+ ///
+ public int RoleId { get; set; }
+
+ ///
+ /// 角色名称
+ ///
+ [Required(ErrorMessage = "角色名称不能为空!")]
+ [MaxLength(20, ErrorMessage = "角色名称不得超过8个字")]
+ public string RoleName { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Employee/Dto/Input/EmployeeUpdateInput.cs b/src/Znyc.Dispatching.Application/Employee/Dto/Input/EmployeeUpdateInput.cs
new file mode 100644
index 0000000..2080557
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Employee/Dto/Input/EmployeeUpdateInput.cs
@@ -0,0 +1,17 @@
+namespace Znyc.Dispatching.Application
+{
+ public class EmployeeUpdateInput : EmployeeAddInput
+ {
+ public long Id { get; set; }
+
+ ///
+ /// 状态
+ ///
+ public int Status { get; set; }
+
+ ///
+ /// 员工头像
+ ///
+ public string AvatarUrl { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Employee/Dto/OutPut/EmployeeListOutput.cs b/src/Znyc.Dispatching.Application/Employee/Dto/OutPut/EmployeeListOutput.cs
new file mode 100644
index 0000000..632d5dc
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Employee/Dto/OutPut/EmployeeListOutput.cs
@@ -0,0 +1,58 @@
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+
+namespace Znyc.Dispatching.Application
+{
+ public class EmployeeListOutput
+ {
+ ///
+ ///
+ public long Id { get; set; }
+
+ ///
+ /// 用户Id
+ ///
+ public long UserId { get; set; }
+
+
+ ///
+ ///
+ ///
+ public int RoleId { get; set; }
+
+ ///
+ ///
+ ///
+ public string RoleName { get; set; }
+
+ ///
+ /// 员工名
+ ///
+ public string EmployeeName { get; set; }
+
+ ///
+ /// 手机号
+ ///
+ [MaxLength(11)]
+ public string EmployeePhone { get; set; }
+
+
+ public int Status { get; set; }
+
+ }
+
+ public class EmployeeListOutputs
+ {
+ public string Char { get; set; }
+
+ public List List { get; set; }
+
+ }
+
+ public class EmployeeListPage
+ {
+ public List EmployeeList { get; set; }
+
+ public long Total { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Employee/Dto/OutPut/EmployeeOutput.cs b/src/Znyc.Dispatching.Application/Employee/Dto/OutPut/EmployeeOutput.cs
new file mode 100644
index 0000000..2e2ddf6
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Employee/Dto/OutPut/EmployeeOutput.cs
@@ -0,0 +1,52 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Znyc.Dispatching.Application
+{
+ public class EmployeeOutput
+ {
+ ///
+ ///
+ public long Id { get; set; }
+
+ ///
+ /// 用户Id
+ ///
+ public long UserId { get; set; }
+
+ ///
+ /// 公司Id
+ ///
+ public long CompanyId { get; set; }
+
+ ///
+ /// 员工名
+ ///
+ public string EmployeeName { get; set; }
+
+ ///
+ /// 手机号
+ ///
+ [MaxLength(11)]
+ public string EmployeePhone { get; set; }
+
+ ///
+ /// 角色
+ ///
+ public long RoleId { get; set; }
+
+ ///
+ /// 角色名称
+ ///
+ public string RoleName { get; set; }
+
+ ///
+ /// 状态
+ ///
+ public int Status { get; set; }
+
+ ///
+ /// 员工头像
+ ///
+ public string AvatarUrl { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Employee/Dto/OutPut/NoticeOutput.cs b/src/Znyc.Dispatching.Application/Employee/Dto/OutPut/NoticeOutput.cs
new file mode 100644
index 0000000..9e39a27
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Employee/Dto/OutPut/NoticeOutput.cs
@@ -0,0 +1,7 @@
+namespace Znyc.Dispatching.Application
+{
+ public class NoticeOutput
+ {
+ public string OpenId { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Employee/Services/EmployeeService.cs b/src/Znyc.Dispatching.Application/Employee/Services/EmployeeService.cs
new file mode 100644
index 0000000..c756bdf
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Employee/Services/EmployeeService.cs
@@ -0,0 +1,305 @@
+using Furion.DatabaseAccessor;
+using Furion.DependencyInjection;
+using Furion.DynamicApiController;
+using Furion.FriendlyException;
+using Mapster;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Options;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Threading.Tasks;
+using Znyc.Dispatching.Common.Extensions;
+using Znyc.Dispatching.Core;
+using Znyc.Dispatching.Core.Entitys;
+using Znyc.Dispatching.Core.Extension;
+using Znyc.Dispatching.Core.Helpers;
+
+namespace Znyc.Dispatching.Application
+{
+ ///
+ /// 员工服务
+ ///
+ [ApiDescriptionSettings(Name = "employee", Order = 20)]
+ public class EmployeeService : IEmployeeService, IDynamicApiController, ITransient
+ {
+ private string[] INDEX_STRINGS = {"A", "B", "C", "D", "E", "F", "G", "H", "I",
+ "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
+ "W", "X", "Y", "Z", "#"};
+
+ private string[] ROLEINDEX_STRINGS = { "C", "D", "J", "G", "W", "Y", "X", "#" };
+
+
+ private readonly ICacheService _cacheService;
+ private readonly IRepository _repository;
+ private readonly IRepository _userRepository;
+ private readonly IRepository _userRoleRepository;
+ private readonly IRepository _companyRepository;
+ private readonly IUserManager _userManager;
+ private readonly IRepository _vehiclePersonRepository;
+ private readonly IRepository _projectPersonRepository;
+
+
+ public EmployeeService(
+ IRepository repository,
+ IRepository userRepository,
+ IRepository companyRepository,
+ IUserManager userManager,
+ ICacheService cacheService,
+ IRepository userRoleRepository,
+ IOptions smsProviderOptions,
+ IRepository vehiclePersonRepository,
+ IRepository projectPersonRepository
+ )
+ {
+ _repository = repository;
+ _userRepository = userRepository;
+ _companyRepository = companyRepository;
+ _userManager = userManager;
+ _cacheService = cacheService;
+ _userRoleRepository = userRoleRepository;
+ _vehiclePersonRepository = vehiclePersonRepository;
+ _projectPersonRepository = projectPersonRepository;
+ }
+
+ ///
+ /// 员工信息
+ ///
+ ///
+ ///
+ ///
+ /// 0全部,停用-1,正常1
+ ///
+ ///
+ ///
+ [HttpGet]
+ [Route("api/v1/employees/search")]
+ public async Task PageAsync([Required] int currentPage, [Required] int pageSize, [FromQuery] int status, [Required] int roleId, [FromQuery] string orderby, [FromQuery] string key = "")
+ {
+
+ var employees = (await _cacheService.GetEmployeeListAsync(_userManager.CompanyId))
+ .WhereIf(status != 0, x => x.Status == status)
+ .WhereIf(roleId > 0, x => x.RoleId == roleId)
+ .WhereIf(new long[] { (long)RoleStatusEnum.Scheduling, (long)RoleStatusEnum.CarCaptain }.Contains(_userManager.RoleId),
+ x => new long[] { (long)RoleStatusEnum.CrewMembers, (long)RoleStatusEnum.Outside,
+ (long)RoleStatusEnum.PartTimeSalesman,(long)RoleStatusEnum.Salesman }.Contains(x.RoleId))
+ .WhereIf(key.IsNotEmptyOrNull(), x => x.EmployeeName.Contains(key) || x.EmployeePhone.Contains(key))
+ .Adapt>();
+ var employeeOutputs = new List();
+
+ if (orderby == "role")
+ {
+ employees = employees.OrderBy(x => x.RoleName).ToList();
+ foreach (var INDEX_STRING in ROLEINDEX_STRINGS)
+ {
+ employeeOutputs.Add(new EmployeeListOutputs()
+ {
+ Char = INDEX_STRING,
+ List = employees.Where(x => StringHelper.GetStringFirstSpell(x.RoleName) == INDEX_STRING).ToList()
+ });
+ };
+ }
+ else
+ {
+ employees = employees.OrderBy(x => x.EmployeeName).ToList();
+
+ foreach (var INDEX_STRING in INDEX_STRINGS)
+ {
+ employeeOutputs.Add(new EmployeeListOutputs()
+ {
+ Char = INDEX_STRING,
+ List = employees.Where(x => StringHelper.GetStringFirstSpell(x.EmployeeName) == INDEX_STRING).ToList()
+ });
+ };
+ }
+ var data = new EmployeeListPage()
+ {
+ EmployeeList = employeeOutputs,
+ Total = employees.Count
+ };
+ return data;
+ }
+
+ ///
+ /// 根据id获取员工资料
+ ///
+ ///
+ [HttpGet]
+ [Route("api/v1/employee/{id}")]
+ public async Task GetByIdAsync(long id)
+ {
+ return await _cacheService.GetEmployeeAsync(id);
+ }
+
+ ///
+ /// 添加员工信息
+ ///
+ ///
+ ///
+ [HttpPost]
+ [UnitOfWork]
+ [NonAction]
+ //[Route("api/v1/employee")]
+ public async Task AddAsync(EmployeeAddInput employeeAdd)
+ {
+ var user = await _userRepository.Where(x => x.Phone == employeeAdd.EmployeePhone).FirstOrDefaultAsync();
+ if (user.IsNotNull())
+ {
+ return user.Id;
+ }
+
+ var company = await _companyRepository.FindOrDefaultAsync(_userManager.CompanyId);
+ if (company.IsNotNull())
+ {
+ //用户
+ var userEntity = await _userRepository.InsertNowAsync(new User
+ {
+ OpenId = "",
+ UserName = employeeAdd.EmployeeName,
+ AvatarUrl = CommonConst.DEFAULT_AVATARURL_ALL,
+ Phone = employeeAdd.EmployeePhone,
+ Status = CommonStatusEnum.ENABLE
+ });
+ //员工
+ var employee = await _repository.InsertNowAsync(new Employee
+ {
+ UserId = userEntity.Entity.Id,
+ AvatarUrl = CommonConst.DEFAULT_AVATARURL,
+ EmployeeName = employeeAdd.EmployeeName,
+ EmployeePhone = employeeAdd.EmployeePhone,
+ CompanyId = company.Id,
+ RoleId = employeeAdd.RoleId,
+ RoleName = employeeAdd.RoleName,
+ IsDefault = true,
+ Status = (int)CommonStatusEnum.ENABLE
+ });
+ //用户角色
+ await _userRoleRepository.InsertNowAsync(new UserRole
+ {
+ UserId = userEntity.Entity.Id,
+ RoleId = employeeAdd.RoleId,
+ });
+ //清除员工列表Cache
+ await _cacheService.RemoveEmployeeListAsync(_userManager.CompanyId);
+ return employee.Entity.UserId;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ ///
+ /// 编辑员工信息
+ ///
+ ///
+ [HttpPut]
+ [UnitOfWork]
+ [Route("api/v1/employee")]
+ public async Task UpdateAsync(EmployeeUpdateInput input)
+ {
+ var employee = await _repository.FindOrDefaultAsync(input.Id);
+ //权限变动,清除对应缓存
+ if (!employee.RoleId.Equals(input.RoleId))
+ {
+ await _cacheService.RemoveTokenAsync(employee.UserId);
+ }
+ employee = input.Adapt(employee);
+ employee.AvatarUrl = CommonConst.Prefix_AvataUrl + employee.AvatarUrl[(employee.AvatarUrl.LastIndexOf("/") + 1)..];
+ var result = await _repository.UpdateNowAsync(employee);
+ if (result.IsNull())
+ {
+ throw Oops.Oh("更新员工信息失败");
+ }
+ //同步更新user
+ var user = await _userRepository.FirstOrDefaultAsync(x => x.Id == employee.UserId);
+ if (user.IsNotNull())
+ {
+ user.UserName = input.EmployeeName;
+ user.Phone = input.EmployeePhone;
+ user.AvatarUrl = employee.AvatarUrl;
+ await _userRepository.UpdateNowAsync(user);
+ await _cacheService.RemoveUserAsync(user.Id);
+ }
+
+ //更新当前用户下所有角色姓名
+ var employees = await _repository.Where(x => x.UserId == user.Id).ToListAsync();
+ foreach (var employee2 in employees)
+ {
+ if (employee.IsNotNull())
+ {
+ employee.EmployeePhone = input.EmployeePhone;
+ employee.EmployeeName = input.EmployeeName;
+ employee.AvatarUrl = CommonConst.Prefix_AvataUrl + input.AvatarUrl[(input.AvatarUrl.LastIndexOf("/") + 1)..];
+ await _repository.UpdateNowAsync(employee2);
+ await _cacheService.RemoveEmployeeAsync(employee2.Id);
+ await _cacheService.RemoveEmployeeListAsync(employee2.CompanyId);
+ }
+ }
+
+
+ //清除员工Cache
+ await _cacheService.RemoveEmployeeAsync(employee.Id);
+ //清除用户Cache
+ await _cacheService.RemoveUserAsync(employee.UserId);
+ //清除员工列表Cache
+ await _cacheService.RemoveEmployeeListAsync(_userManager.CompanyId);
+ //同步车组人员表
+ var vehiclePersons = await _vehiclePersonRepository.Where(x => x.IsDeleted == false && x.UserId == user.Id).ToListAsync();
+ foreach (var item in vehiclePersons)
+ {
+ //解除车组人员关联
+ if (input.Status == (int)CommonStatusEnum.DISABLE)
+ {
+ item.IsDeleted = true;
+ }
+ item.UserName = input.EmployeeName;
+ item.UserPhone = input.EmployeePhone;
+ await _vehiclePersonRepository.UpdateNowAsync(item);
+ //删除车组人员Cache
+ await _cacheService.RemoveVehiclePersonAsync(item.VehicleId);
+ }
+ //同步工程联系人表
+ var projectPersons = await _projectPersonRepository.Where(x => x.IsDeleted == false && x.ProjectPersonId == user.Id).ToListAsync();
+ foreach (var item in projectPersons)
+ {
+ item.ProjectPersonName = input.EmployeeName;
+ item.ProjectPersonPhone = input.EmployeePhone;
+ await _projectPersonRepository.UpdateNowAsync(item);
+ //清除工程信息Cache
+ await _cacheService.RemoveProjectAsync(item.ProjectId);
+ //清除工程列表信息Cache
+ await _cacheService.RemoveProjectListAsync(_userManager.CompanyId);
+ }
+ //同步用户角色表
+ //var userRole = await _userRoleRepository.FirstOrDefaultAsync(x => x.UserId == employee.UserId);
+ //userRole.RoleId = employee.RoleId;
+ //await _userRoleRepository.UpdateNowAsync(userRole);
+
+ }
+
+
+ ///
+ /// 软删除员工信息
+ ///
+ ///
+ ///
+ [HttpDelete]
+ [Route("api/v1/employee")]
+
+ public async Task DeleteByIdAsync(long id)
+ {
+ Employee employee = await _repository
+ .FirstOrDefaultAsync(x => x.Id == id && x.CompanyId == _userManager.CompanyId);
+ employee.IsDeleted = true;
+ await _repository.UpdateNowAsync(employee);
+ await _cacheService.RemoveCacheByUserIdAsync(employee.UserId);
+ await _cacheService.RemoveEmployeeAsync(employee.Id);
+ await _cacheService.RemoveEmployeeListAsync(_userManager.CompanyId);
+ await _cacheService.RemoveUserAsync(employee.UserId);
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Employee/Services/IEmployeeService.cs b/src/Znyc.Dispatching.Application/Employee/Services/IEmployeeService.cs
new file mode 100644
index 0000000..e4df847
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Employee/Services/IEmployeeService.cs
@@ -0,0 +1,50 @@
+using System.Threading.Tasks;
+
+namespace Znyc.Dispatching.Application
+{
+ public interface IEmployeeService
+ {
+ ///
+ /// 员工信息
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task PageAsync(int currentPage, int pageSize, int status, int roleId, string key, string orderby);
+
+
+ ///
+ /// 根据id获取员工资料
+ ///
+ ///
+ Task GetByIdAsync(long id);
+
+ ///
+ /// 添加员工信息
+ ///
+ ///
+ ///
+ Task AddAsync(EmployeeAddInput input);
+
+ ///
+ /// 编辑员工信息
+ ///
+ ///
+ Task UpdateAsync(EmployeeUpdateInput input);
+
+
+ ///
+ /// 软删除员工信息
+ ///
+ ///
+ ///
+ Task DeleteByIdAsync(long id);
+
+
+
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Job/Dto/Input/JobInput.cs b/src/Znyc.Dispatching.Application/Job/Dto/Input/JobInput.cs
new file mode 100644
index 0000000..910ada6
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Job/Dto/Input/JobInput.cs
@@ -0,0 +1,83 @@
+using Furion.DataValidation;
+using Furion.TaskScheduler;
+using System.ComponentModel.DataAnnotations;
+using Znyc.Dispatching.Core;
+
+namespace Dilon.Core.Service
+{
+ ///
+ /// 任务调度参数
+ ///
+ public class JobInput : PageInputBase
+ {
+ ///
+ /// 任务名称
+ ///
+ public string JobName { get; set; }
+
+ ///
+ /// 执行间隔时间(单位秒)
+ ///
+ /// 5
+ public int Interval { get; set; }
+
+ ///
+ /// Cron表达式
+ ///
+ public string Cron { get; set; }
+
+ ///
+ /// 定时器类型
+ ///
+ public SpareTimeTypes TimerType { get; set; }
+
+ ///
+ /// 执行次数
+ ///
+ public int? RunNumber { get; set; }
+
+ ///
+ /// 请求url
+ ///
+ public string RequestUrl { get; set; }
+
+ ///
+ /// 请求参数(Post,Put请求用)
+ ///
+ public string RequestParameters { get; set; }
+
+ ///
+ /// Headers(可以包含如:Authorization授权认证)
+ /// 格式:{"Authorization":"userpassword.."}
+ ///
+ public string Headers { get; set; }
+
+ ///
+ /// 请求类型
+ ///
+ public RequestTypeEnum RequestType { get; set; }
+
+ ///
+ /// 备注
+ ///
+ public string Remark { get; set; }
+ }
+
+ public class DeleteJobInput : JobInput
+ {
+ ///
+ /// 任务Id
+ ///
+ [Required(ErrorMessage = "任务Id不能为空")]
+ [DataValidation(ValidationTypes.Numeric)]
+ public long Id { get; set; }
+ }
+
+ public class UpdateJobInput : DeleteJobInput
+ {
+ }
+
+ public class QueryJobInput : DeleteJobInput
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Job/Dto/Output/JobOutput.cs b/src/Znyc.Dispatching.Application/Job/Dto/Output/JobOutput.cs
new file mode 100644
index 0000000..c83a32a
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Job/Dto/Output/JobOutput.cs
@@ -0,0 +1,78 @@
+using Furion.TaskScheduler;
+using Znyc.Dispatching.Core;
+
+namespace Dilon.Core.Service
+{
+ ///
+ /// 任务信息---任务详情
+ ///
+ public class JobOutput
+ {
+ ///
+ /// Id
+ ///
+ public long Id { get; set; }
+
+ ///
+ /// 任务名称
+ ///
+ public string JobName { get; set; }
+
+ ///
+ /// 执行间隔时间(单位秒)
+ ///
+ public int Interval { get; set; }
+
+ ///
+ /// Cron表达式
+ ///
+ public string Cron { get; set; }
+
+ ///
+ /// 定时器类型
+ ///
+ public SpareTimeTypes TimerType { get; set; }
+
+ ///
+ /// 执行次数
+ ///
+ public long? RunNumber { get; set; }
+
+ ///
+ /// 请求url
+ ///
+ public string RequestUrl { get; set; }
+
+ ///
+ /// 请求参数(Post,Put请求用)
+ ///
+ public string RequestParameters { get; set; }
+
+ ///
+ /// Headers(可以包含如:Authorization授权认证)
+ /// 格式:{"Authorization":"userpassword.."}
+ ///
+ public string Headers { get; set; }
+
+ ///
+ /// 请求类型
+ ///
+ /// 2
+ public RequestTypeEnum RequestType { get; set; }
+
+ ///
+ /// 备注
+ ///
+ public string Remark { get; set; }
+
+ ///
+ /// 定时器状态
+ ///
+ public SpareTimeStatus TimerStatus { get; set; } = SpareTimeStatus.Stopped;
+
+ ///
+ /// 异常信息
+ ///
+ public string Exception { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Job/IJobService.cs b/src/Znyc.Dispatching.Application/Job/IJobService.cs
new file mode 100644
index 0000000..225b82b
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Job/IJobService.cs
@@ -0,0 +1,10 @@
+using System.Threading.Tasks;
+
+namespace Dilon.Core.Service
+{
+ public interface IJobService
+ {
+
+ Task SyncOrderStatusAsync();
+ }
+}
\ No newline at end of file
diff --git a/src/Znyc.Dispatching.Application/Job/JobService.cs b/src/Znyc.Dispatching.Application/Job/JobService.cs
new file mode 100644
index 0000000..bc45e24
--- /dev/null
+++ b/src/Znyc.Dispatching.Application/Job/JobService.cs
@@ -0,0 +1,277 @@
+using Furion.DatabaseAccessor;
+using Furion.DependencyInjection;
+using Furion.DynamicApiController;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Options;
+using Newtonsoft.Json;
+using Senparc.Weixin.MP.AdvancedAPIs;
+using Senparc.Weixin.MP.AdvancedAPIs.TemplateMessage;
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using Znyc.Dispatching.Application;
+using Znyc.Dispatching.Core;
+using Znyc.Dispatching.Core.Entitys;
+using Znyc.Dispatching.Core.Extension;
+using Znyc.Dispatching.Core.Helpers;
+using Znyc.Dispatching.MongoDb.Repository.Repositorys;
+using Znyc.Dispatching.WeChat.Core.CommonService.TemplateMessage;
+
+namespace Dilon.Core.Service
+{
+ ///
+ /// 任务调度服务
+ ///
+ [ApiDescriptionSettings(Name = "job", Order = 40)]
+ public class JobService : IJobService, IDynamicApiController, IScoped
+ {
+ private readonly IRepository _roleRepository;
+ private readonly IVehicleService _vehicleService;
+ private readonly IRepository