This commit is contained in:
Asoka.Wang 2025-08-27 18:39:19 +08:00
commit 21f044712c
334 changed files with 60830 additions and 0 deletions

View File

@ -0,0 +1,30 @@
{
"permissions": {
"allow": [
"Bash(dotnet build:*)",
"Bash(find:*)",
"Bash(grep:*)",
"mcp__ide__getDiagnostics",
"Bash(rm:*)",
"Bash(dir:*)",
"Bash(powershell:*)",
"Bash(git rm:*)",
"Bash(cmd /c \"del nul\")",
"Bash(cmd:*)",
"Bash(git clean:*)",
"Bash(dotnet test:*)",
"Bash(timeout 30 dotnet test NPP.SmartSchedue.Tests --filter \"EquipmentMaintenanceIntegrationTest\" --logger \"console;verbosity=minimal\")",
"Bash(timeout 30 dotnet test NPP.SmartSchedue.Tests --filter \"FullyQualifiedName~EquipmentCalibrationIntegrationTest\")",
"Bash(git add:*)",
"Bash(git commit:*)",
"Bash(git push:*)",
"Bash(cp:*)",
"Bash(mv:*)",
"Bash(dotnet run:*)",
"Bash(mkdir:*)",
"Bash(git restore:*)",
"Bash(ls:*)"
],
"deny": []
}
}

7
.cursor/rules/sse.mdc Normal file
View File

@ -0,0 +1,7 @@
---
description: 自动排班
globs:
alwaysApply: true
---

25
.dockerignore Normal file
View File

@ -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

63
.gitattributes vendored Normal file
View File

@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

403
.gitignore vendored Normal file
View File

@ -0,0 +1,403 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml
**/wwwroot/upload
**/NPP.SmartSchedue.Api/NPP.SmartSchedue.Api.xml
**/NPP.SmartSchedue.Api.Contracts/NPP.SmartSchedue.Api.Contracts.xml

View File

@ -0,0 +1 @@
NPP.SmartSchedue

View File

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

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RiderProjectSettingsUpdater">
<option name="singleClickDiffPreview" value="1" />
<option name="unhandledExceptionsIgnoreList" value="1" />
<option name="vcsConfiguration" value="3" />
</component>
</project>

View File

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

View File

@ -0,0 +1,234 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoGeneratedRunConfigurationManager">
<projectFile kind="Docker">NPP.SmartSchedue.Host/NPP.SmartSchedue.Host.csproj</projectFile>
<projectFile profileName="IIS Express">NPP.SmartSchedue.Host/NPP.SmartSchedue.Host.csproj</projectFile>
<projectFile profileName="NPP.SmartSchedue.Host">NPP.SmartSchedue.Host/NPP.SmartSchedue.Host.csproj</projectFile>
</component>
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="635f35ee-190e-4c9a-82f7-ee1c8f1bea95" name="更改" comment="">
<change beforePath="$PROJECT_DIR$/.idea/.idea.NPP.SmartSchedue/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.NPP.SmartSchedue/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/ExecutiveSummary.md" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/GeneticAlgorithmPerformanceAnalysis.md" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/GeneticAlgorithmTestPlan.md" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/NPP.SmartSchedue.Api/NPP.SmartSchedue.Api.xml" beforeDir="false" afterPath="$PROJECT_DIR$/NPP.SmartSchedue.Api/NPP.SmartSchedue.Api.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/PerformanceOptimizationRecommendations.md" beforeDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="DpaMonitoringSettings">
<option name="firstShow" value="false" />
</component>
<component name="Git.Settings">
<option name="RECENT_BRANCH_BY_REPOSITORY">
<map>
<entry key="$PROJECT_DIR$/../../.." value="dev_schedule_2" />
</map>
</option>
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/../../.." />
</component>
<component name="GitLabMergeRequestFiltersHistory">{
&quot;lastFilter&quot;: {
&quot;state&quot;: &quot;OPENED&quot;,
&quot;assignee&quot;: {
&quot;type&quot;: &quot;org.jetbrains.plugins.gitlab.mergerequest.ui.filters.GitLabMergeRequestsFiltersValue.MergeRequestsMemberFilterValue.MergeRequestsAssigneeFilterValue&quot;,
&quot;username&quot;: &quot;project_698_bot&quot;,
&quot;fullname&quot;: &quot;Rider&quot;
}
}
}</component>
<component name="GitLabMergeRequestsSettings">{
&quot;selectedUrlAndAccountId&quot;: {
&quot;first&quot;: &quot;https://gitspace.wuxibiologics.com/npp-code-management/SPMS.Portal.git&quot;,
&quot;second&quot;: &quot;46b52827-07a1-4c7c-84b0-fd07ed3ba3df&quot;
}
}</component>
<component name="HighlightingSettingsPerFile">
<setting file="file://$PROJECT_DIR$/NPP.SmartSchedue.Api/Services/Integration/GlobalPersonnelAllocationService.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/66b2a0f1b42345cba263118414f9d183a0910/fa/1cbb630b/Enumerable.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/de363d7e26864f26a46f46b9b5e16f534c00/01/6719b288/AsyncDeterminationInterceptor.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/294078ecfce6fdb942ecfee089f09717de7a6fcfe5efd9fdb6f4f93c0fb4813/ActionMethodExecutor.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/2f657497243c260bae22d6d2c67ab907371015db851628463cc13adfaf325/Int64.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/9d3abb8c403eb01b13b989f2e737438c72cfcd9a12885edf04f7e507586ff0/BaseService.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/a4948a1287bc91a8a16e6d426a38bac34ebd47b49bf82a2772477aa9dc7908e/HostApp.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/a6eded6d58086a0199d103a8f2b10471948ce5a18b7773c815d2364b1423c68/ISelect2`16.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/c2e3bc99518b63d562a6388933d90bae1d78433cc7b77c29523941341be61a6/TransactionAsyncInterceptor.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/de533de9e7b3ea79d36aeac96b6426559cfe9f3a96b1ab66b51ce3febeda25f/TimeSpan.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/e399fc861c188bd19ebde14346e2f5f2c1a54c1c0d6fbd5cbe05227afe6d/CollectionExtensions.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="mock://diff.cs" root0="SKIP_HIGHLIGHTING" />
</component>
<component name="MetaFilesCheckinStateConfiguration" checkMetaFiles="true" />
<component name="ProblemsViewState">
<option name="selectedTabId" value="CurrentFile" />
</component>
<component name="ProjectColorInfo">{
&quot;associatedIndex&quot;: 4
}</component>
<component name="ProjectId" id="30zf5rxtLF4AlMwfbHnXdMlDTzF" />
<component name="ProjectLevelVcsManager">
<ConfirmationsSetting value="2" id="Add" />
</component>
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
".NET 启动设置配置文件.NPP.SmartSchedue.Host.executor": "Debug",
"ModuleVcsDetector.initialDetectionPerformed": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager": "true",
"RunOnceActivity.git.unshallow": "true",
"ToolWindow.Debug.ShowToolbar": "false",
"git-widget-placeholder": "dev__schedule",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "npm",
"settings.editor.selected.configurable": "editor.preferences.fonts.default",
"settings.editor.splitter.proportion": "0.1840796",
"ts.external.directory.path": "C:\\GitCodeSpace\\SPMS.Portal\\zhontai.ui.admin.vue3\\node_modules\\typescript\\lib",
"vue.rearranger.settings.migration": "true",
"附加到进程.1596:NPP.SmartSchedue.Host.executor": "Debug",
"附加到进程.19008:NPP.SmartSchedue.Host.executor": "Debug",
"附加到进程.28664:NPP.SmartSchedue.Host.executor": "Debug"
}
}]]></component>
<component name="RunManager" selected=".NET 启动设置配置文件.NPP.SmartSchedue.Host">
<configuration name="NPP.SmartSchedue.Host" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/NPP.SmartSchedue.Host/NPP.SmartSchedue.Host.csproj" />
<option name="LAUNCH_PROFILE_TFM" value="net9.0" />
<option name="LAUNCH_PROFILE_NAME" value="NPP.SmartSchedue.Host" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="RUNTIME_ARGUMENTS" value="" />
<option name="GENERATE_APPLICATIONHOST_CONFIG" value="1" />
<option name="SHOW_IIS_EXPRESS_OUTPUT" value="0" />
<option name="SEND_DEBUG_REQUEST" value="1" />
<option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" />
<method v="2">
<option name="Build" />
</method>
</configuration>
<configuration name="NPP.SmartSchedue.Host: IIS Express" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
<option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/NPP.SmartSchedue.Host/NPP.SmartSchedue.Host.csproj" />
<option name="LAUNCH_PROFILE_TFM" value="net9.0" />
<option name="LAUNCH_PROFILE_NAME" value="IIS Express" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="RUNTIME_ARGUMENTS" value="" />
<option name="GENERATE_APPLICATIONHOST_CONFIG" value="1" />
<option name="SHOW_IIS_EXPRESS_OUTPUT" value="0" />
<option name="SEND_DEBUG_REQUEST" value="1" />
<option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" />
<method v="2">
<option name="Build" />
</method>
</configuration>
<configuration default="true" type="docker-deploy" factoryName="dockerfile" temporary="true">
<deployment type="dockerfile">
<settings />
</deployment>
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="true" isSslEnabled="false" />
<method v="2" />
</configuration>
<configuration name="NPP.SmartSchedue.Host/Dockerfile" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
<deployment type="dockerfile">
<settings>
<option name="containerName" value="npp.smartschedue.host" />
<option name="contextFolderPath" value="C:\666 WXGitSpace\SPMS.Portal\src\modules\schedue" />
<option name="sourceFilePath" value="NPP.SmartSchedue.Host/Dockerfile" />
</settings>
</deployment>
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="true" isSslEnabled="false" />
<method v="2" />
</configuration>
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="默认任务">
<changelist id="635f35ee-190e-4c9a-82f7-ee1c8f1bea95" name="更改" comment="" />
<created>1754635142915</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1754635142915</updated>
<workItem from="1754635143882" duration="4343000" />
<workItem from="1754874747747" duration="7000" />
<workItem from="1754878274269" duration="11438000" />
<workItem from="1755480136705" duration="6336000" />
<workItem from="1755492788122" duration="12633000" />
<workItem from="1755517970088" duration="5154000" />
<workItem from="1755572773370" duration="1830000" />
<workItem from="1755583838242" duration="13230000" />
<workItem from="1755661227196" duration="9632000" />
<workItem from="1755677504783" duration="2660000" />
<workItem from="1755681064691" duration="1596000" />
<workItem from="1755695756877" duration="3164000" />
<workItem from="1755752854232" duration="10000" />
<workItem from="1755752884301" duration="4360000" />
<workItem from="1755759793828" duration="8749000" />
<workItem from="1755825348947" duration="4502000" />
<workItem from="1755850912137" duration="2031000" />
<workItem from="1755852977655" duration="1188000" />
<workItem from="1756084492195" duration="43899000" />
<workItem from="1756185335516" duration="36937000" />
<workItem from="1756289004055" duration="1442000" />
</task>
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
<option name="exactExcludedFiles">
<list>
<option value="$PROJECT_DIR$/../../../npp-smart-schedule-portal/node_modules/zrender/index.js" />
<option value="$PROJECT_DIR$/../../../npp-smart-schedule-portal/node_modules/zrender/index.d.ts" />
<option value="$PROJECT_DIR$/../../../zhontai.ui.admin.vue3/node_modules/zrender/index.js" />
<option value="$PROJECT_DIR$/../../../zhontai.ui.admin.vue3/node_modules/zrender/index.d.ts" />
</list>
</option>
</component>
<component name="UnityCheckinConfiguration" checkUnsavedScenes="true" />
<component name="UnityProjectConfiguration" hasMinimizedUI="false" />
<component name="Vcs.Log.Tabs.Properties">
<option name="TAB_STATES">
<map>
<entry key="MAIN">
<value>
<State />
</value>
</entry>
</map>
</option>
</component>
<component name="VcsManagerConfiguration">
<option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="true" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<breakpoint enabled="true" type="DotNet_Exception_Breakpoints">
<properties exception="System.OperationCanceledException" breakIfHandledByOtherCode="false" displayValue="System.OperationCanceledException" />
<option name="timeStamp" value="1" />
</breakpoint>
<breakpoint enabled="true" type="DotNet_Exception_Breakpoints">
<properties exception="System.Threading.Tasks.TaskCanceledException" breakIfHandledByOtherCode="false" displayValue="System.Threading.Tasks.TaskCanceledException" />
<option name="timeStamp" value="2" />
</breakpoint>
<breakpoint enabled="true" type="DotNet_Exception_Breakpoints">
<properties exception="System.Threading.ThreadAbortException" breakIfHandledByOtherCode="false" displayValue="System.Threading.ThreadAbortException" />
<option name="timeStamp" value="3" />
</breakpoint>
</breakpoints>
</breakpoint-manager>
</component>
<component name="XSLT-Support.FileAssociations.UIState">
<expand />
<select />
</component>
</project>

130
CLAUDE.md Normal file
View File

@ -0,0 +1,130 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
### 代码开发规范
- **引用检查**编写代码时必须检查所有using引用是否正确确保引用的命名空间和类存在
- **编译验证**:完成一个功能时必须执行编译检查,发现错误立即修复,确保代码能够正常编译
### 深度思考与详细实现要求
- **深度思考原则**:对每个业务问题都要进行深度思考,分析所有可能的边界情况和业务场景
- **最终抉择要求**:在分析各种方案后,必须给出明确的最终决策和理由,不允许含糊其辞
- **详细实现标准**:所有功能都必须详细实现,不允许简化或省略关键逻辑
- **完整性验证**:实现功能时必须考虑所有相关的上下文和依赖关系
- **业务场景覆盖**:确保代码能够处理所有合理的业务场景,包括异常情况
- **错误处理完整性**:每个方法都必须包含适当的异常处理和错误信息
- **注释详细程度**:关键业务逻辑必须包含详细的业务思考过程注释
## 项目概述
NPP.SmartSchedue 是一个智能生产调度系统,基于 .NET 9.0 和中台Admin框架开发实现生产任务的智能排班和调度管理。
## 架构设计
### 项目结构
- **NPP.SmartSchedue.Api.Contracts**: 契约层包含实体、接口和DTO定义
- **NPP.SmartSchedue.Api**: 业务逻辑层包含Repository和Service实现
- **NPP.SmartSchedue.Host**: 宿主程序Web API启动入口
- **NPP.SmartSchedue.Tests**: 单元测试项目
### 核心领域模块
1. **Work**: 工作任务管理
- WorkOrderEntity: 工作任务实体(支持多租户)
- WorkOrderFLPersonnelEntity: 任务与FL人员关联
- ProcessEntity: 工序管理
- ProcessGroupEntity: 工序组管理
2. **Time**: 时间和班次管理
- ShiftEntity: 班次定义
- ShiftRuleEntity: 班次规则
- CalendarEntity: 日历管理
- EmployeeLeaveEntity: 员工请假
3. **Personnel**: 人员管理
- PersonnelQualificationEntity: 人员资质
- PersonnelWorkLimitEntity: 人员工作限制
- QualificationEntity: 资质定义
4. **Schedule**: 排班调度
- AutoScheduleInput: 自动排班输入
- ScheduleValidationService: 排班验证服务
- TaskIntegrationInput: 任务整合输入
### 技术栈
- **.NET 9.0**: 主要开发框架
- **FreeSql**: ORM框架支持MySQL
- **ZhonTai.Admin**: 中台管理框架
- **DotNetCore.CAP**: 事件总线支持RabbitMQ
- **xUnit**: 单元测试框架
## 常用命令
### 构建和运行
```bash
# 构建整个解决方案
dotnet build NPP.SmartSchedue.sln
# 运行Host项目
dotnet run --project NPP.SmartSchedue.Host
# 发布项目
dotnet publish NPP.SmartSchedue.Host -c Release
```
### 测试
```bash
# 运行所有测试
dotnet test NPP.SmartSchedue.Tests
# 运行特定测试文件
dotnet test NPP.SmartSchedue.Tests --filter ClassName=TestName
# 生成测试覆盖率报告
dotnet test NPP.SmartSchedue.Tests --collect:"XPlat Code Coverage"
```
### 数据库相关
```bash
# 项目使用FreeSql进行数据库操作支持Code First
# 数据库连接配置在 ConfigCenter/dbconfig.json
# 初始化SQL脚本位于 ConfigCenter/createdbsql.txt
```
## 开发规范
### 实体设计
- 工作任务相关实体继承 `EntityTenant`(支持多租户)
- 基础配置实体继承 `EntityBase`
- 使用 FreeSql 特性进行数据库映射
### 服务层架构
- Repository层数据访问继承自 `AppRepositoryBase<T>`
- Service层业务逻辑实现对应的Interface
- 输入输出模型使用Input/Output后缀命名
### 命名约定
- 实体类Entity后缀
- 仓储接口I前缀 + Repository后缀
- 服务接口I前缀 + Service后缀
- 数据库表名:使用 DbConsts.TableNamePrefix 前缀
### 排班业务逻辑要点
- 任务状态使用 `WorkOrderStatusEnum` 枚举管理
- 支持任务优先级、紧急程度、复杂度等多维度排序
- FL人员与任务为多对多关系通过 WorkOrderFLPersonnelEntity 关联
- 支持批量任务整合和验证功能
- 班次规则支持多种类型,通过 ShiftRuleTypeEnum 管理
### 多任务验证架构决策
- **单一验证原则**:所有冲突检查统一在 `ValidateWorkOrderWithBatchContextAsync` 中完成
- **批次上下文集成**:每个单任务验证都考虑批次内其他任务的影响
- **取消跨任务验证**:原有的 `CheckCrossTaskConflictsAsync` 已被移除,避免重复验证
- **全面冲突检查**:包含时间冲突、工作量限制、班次规则、时间段重叠等所有验证维度
- **性能优化**:减少重复查询,统一数据获取和验证逻辑
## 配置文件
- 应用配置ConfigCenter/appconfig.json
- 数据库配置ConfigCenter/dbconfig.json
- JWT配置ConfigCenter/jwtconfig.json
- 缓存配置ConfigCenter/cacheconfig.json
- CAP事件总线appsettings.json中的CAP节点

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 npp.smartschedue
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,22 @@
namespace NPP.SmartSchedue.Api.Contracts.Core.Consts;
/// <summary>
/// 数据库常量
/// </summary>
public static partial class DbConsts
{
/// <summary>
/// 表名前缀
/// </summary>
public const string TableNamePrefix = "sse_";
/// <summary>
/// aem前缀
/// </summary>
public const string AEMTableNamePrefix = "aem_";
/// <summary>
/// 旧表名前缀
/// </summary>
public const string TableOldNamePrefix = "";
}

View File

@ -0,0 +1,8 @@
namespace NPP.SmartSchedue.Api.Contracts.Core.Consts;
/// <summary>
/// 订阅命名
/// </summary>
public class SubscribeNames
{
}

View File

@ -0,0 +1,85 @@
namespace NPP.SmartSchedue.Api.Contracts.Core.Enums
{
/// <summary>
/// 设备状态枚举
/// </summary>
public enum EquipmentStatusEnum
{
/// <summary>
/// 可用
/// </summary>
Available = 1,
/// <summary>
/// 使用中
/// </summary>
InUse = 2,
/// <summary>
/// 维护中
/// </summary>
Maintenance = 3,
/// <summary>
/// 故障
/// </summary>
Fault = 4,
/// <summary>
/// 停用
/// </summary>
Disabled = 5
}
/// <summary>
/// 维护状态枚举
/// </summary>
public enum MaintenanceStatusEnum
{
/// <summary>
/// 已计划
/// </summary>
Scheduled = 1,
/// <summary>
/// 进行中
/// </summary>
InProgress = 2,
/// <summary>
/// 已完成
/// </summary>
Completed = 3,
/// <summary>
/// 已取消
/// </summary>
Cancelled = 4
}
/// <summary>
/// 校验状态枚举
/// </summary>
public enum CalibrationStatusEnum
{
/// <summary>
/// 已计划
/// </summary>
Scheduled = 1,
/// <summary>
/// 进行中
/// </summary>
InProgress = 2,
/// <summary>
/// 已完成
/// </summary>
Completed = 3,
/// <summary>
/// 已取消
/// </summary>
Cancelled = 4
}
}

View File

@ -0,0 +1,37 @@
namespace NPP.SmartSchedue.Api.Contracts.Core.Enums;
/// <summary>
/// 工序分类枚举
/// </summary>
public enum ProcessCategoryEnum
{
/// <summary>
/// 准备工序
/// </summary>
Preparation = 1,
/// <summary>
/// 生产工序
/// </summary>
Production = 2,
/// <summary>
/// 质检工序
/// </summary>
QualityControl = 3,
/// <summary>
/// 包装工序
/// </summary>
Packaging = 4,
/// <summary>
/// 维护工序
/// </summary>
Maintenance = 5,
/// <summary>
/// 清洁工序
/// </summary>
Cleaning = 6
}

View File

@ -0,0 +1,38 @@
namespace NPP.SmartSchedue.Api.Contracts.Core.Enums;
/// <summary>
/// 资质等级枚举
/// 业务思考:定义资质的技能等级,支持技能匹配和人员成长路径管理
/// </summary>
public enum QualificationLevelEnum
{
/// <summary>
/// 初级 - 基础技能水平
/// 业务场景:新员工、实习生等入门级别
/// </summary>
Junior = 1,
/// <summary>
/// 中级 - 熟练技能水平
/// 业务场景:有一定工作经验的员工
/// </summary>
Intermediate = 2,
/// <summary>
/// 高级 - 专业技能水平
/// 业务场景:资深员工、技术专家
/// </summary>
Senior = 3,
/// <summary>
/// 专家级 - 顶级技能水平
/// 业务场景:技术带头人、首席技师
/// </summary>
Expert = 4,
/// <summary>
/// 不限等级 - 对技能等级无要求
/// 业务场景:基础操作、通用技能
/// </summary>
Any = 0
}

View File

@ -0,0 +1,32 @@
namespace NPP.SmartSchedue.Api.Contracts.Core.Enums;
/// <summary>
/// 资质要求类型枚举
/// 业务思考:定义工序对资质的不同要求级别,支持灵活的人员匹配策略
/// </summary>
public enum QualificationRequirementTypeEnum
{
/// <summary>
/// 必需资质 - 必须拥有此资质才能执行工序
/// 业务场景:安全操作证、特种设备操作证等强制性资质
/// </summary>
Required = 1,
/// <summary>
/// 优选资质 - 拥有此资质的人员优先分配
/// 业务场景:高级技能证书、专业认证等加分项资质
/// </summary>
Preferred = 2,
/// <summary>
/// 可选资质 - 拥有此资质可以提高工作效率
/// 业务场景:辅助技能、相关经验认证等
/// </summary>
Optional = 3,
/// <summary>
/// 禁止资质 - 拥有此资质的人员不能执行该工序
/// 业务场景:某些冲突的资质限制,如化学品处理与食品加工
/// </summary>
Forbidden = 4
}

View File

@ -0,0 +1,57 @@
namespace NPP.SmartSchedue.Api.Contracts.Core.Enums;
/// <summary>
/// 班次规则类型枚举
/// </summary>
public enum ShiftRuleTypeEnum
{
/// <summary>
/// 优先指定人员班次
/// </summary>
PrioritizeSpecifiedPersonnel = 1,
/// <summary>
/// 按班次分组计算总任务数
/// </summary>
CalculateTasksByShiftGroup = 2,
/// <summary>
/// 个人周最大任务数限制
/// </summary>
IndividualWeeklyTaskLimit = 3,
/// <summary>
/// 班次连续性限制
/// </summary>
ShiftContinuityRestriction = 4,
/// <summary>
/// 周末连续工作限制
/// </summary>
WeekendConsecutiveRestriction = 5,
/// <summary>
/// 连续工作天数限制
/// </summary>
ConsecutiveWorkDaysLimit = 6,
/// <summary>
/// 班次后强制休息
/// </summary>
MandatoryRestAfterShift = 7,
/// <summary>
/// 年度班次平均分配
/// </summary>
YearlyShiftAverageDistribution = 8,
/// <summary>
/// 人员资质匹配
/// </summary>
PersonnelQualificationMatch = 9,
/// <summary>
/// 设备可用性检查
/// </summary>
EquipmentAvailabilityCheck = 10
}

View File

@ -0,0 +1,42 @@
namespace NPP.SmartSchedue.Api.Contracts.Core.Enums;
/// <summary>
/// 任务状态枚举
/// </summary>
public enum WorkOrderStatusEnum
{
/// <summary>
/// 待提交
/// </summary>
PendingSubmit = 1,
/// <summary>
/// 待复核
/// </summary>
PendingReview = 2,
/// <summary>
/// 待整合
/// </summary>
PendingIntegration = 3,
/// <summary>
/// 待分配
/// </summary>
PendingAssignment = 4,
/// <summary>
/// 已分配
/// </summary>
Assigned = 5,
/// <summary>
/// 进行中
/// </summary>
InProgress = 6,
/// <summary>
/// 已完成
/// </summary>
Completed = 7
}

View File

@ -0,0 +1,632 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Common
{
/// <summary>
/// 日期范围类
/// 智能排班系统中的时间区间管理,支持工作日计算、工时统计和时间跨度分析
/// 深度业务思考:提供完整的时间范围操作,支持复杂的排班业务场景
/// </summary>
public class DateRange
{
#region
/// <summary>
/// 开始日期
/// </summary>
public DateTime StartDate { get; set; }
/// <summary>
/// 结束日期
/// </summary>
public DateTime EndDate { get; set; }
/// <summary>
/// 时间跨度
/// 计算开始日期和结束日期之间的时间差
/// </summary>
public TimeSpan Duration => EndDate.Date - StartDate.Date;
/// <summary>
/// 总天数(包含开始和结束日期)
/// </summary>
public int TotalDays => Duration.Days + 1;
/// <summary>
/// 纯粹的天数差(不包含结束日期)
/// </summary>
public int DurationDays => Duration.Days;
/// <summary>
/// 工作日天数
/// 排除周末和节假日的实际工作天数
/// </summary>
public int WorkingDays => CalculateWorkingDays();
/// <summary>
/// 自然工作日天数
/// 仅排除周末,不考虑节假日
/// </summary>
public int NaturalWorkingDays => CalculateNaturalWorkingDays();
/// <summary>
/// 周末天数
/// </summary>
public int WeekendDays => CalculateWeekendDays();
/// <summary>
/// 节假日天数
/// </summary>
public int HolidayDays => CalculateHolidayDays();
/// <summary>
/// 是否为有效的日期范围
/// </summary>
public bool IsValid => StartDate <= EndDate;
/// <summary>
/// 是否为单日范围
/// </summary>
public bool IsSingleDay => StartDate.Date == EndDate.Date;
/// <summary>
/// 是否跨越多个月份
/// </summary>
public bool SpansMultipleMonths => StartDate.Month != EndDate.Month || StartDate.Year != EndDate.Year;
/// <summary>
/// 是否跨越多个年份
/// </summary>
public bool SpansMultipleYears => StartDate.Year != EndDate.Year;
#endregion
#region
/// <summary>
/// 默认构造函数
/// </summary>
public DateRange()
{
StartDate = DateTime.Today;
EndDate = DateTime.Today;
}
/// <summary>
/// 指定开始和结束日期的构造函数
/// </summary>
/// <param name="startDate">开始日期</param>
/// <param name="endDate">结束日期</param>
public DateRange(DateTime startDate, DateTime endDate)
{
StartDate = startDate.Date;
EndDate = endDate.Date;
if (!IsValid)
{
throw new ArgumentException("结束日期不能早于开始日期");
}
}
/// <summary>
/// 从指定日期开始,持续指定天数的构造函数
/// </summary>
/// <param name="startDate">开始日期</param>
/// <param name="days">持续天数</param>
public DateRange(DateTime startDate, int days)
{
if (days < 0)
{
throw new ArgumentException("天数不能为负数");
}
StartDate = startDate.Date;
EndDate = startDate.Date.AddDays(days - 1);
}
#endregion
#region
/// <summary>
/// 计算标准工时
/// 基于每天8小时的标准工作时间
/// </summary>
/// <param name="dailyStandardHours">每日标准工时默认8小时</param>
/// <returns>总标准工时</returns>
public decimal CalculateStandardHours(decimal dailyStandardHours = 8.0m)
{
return WorkingDays * dailyStandardHours;
}
/// <summary>
/// 计算自然日标准工时
/// 基于总天数计算,不考虑工作日
/// </summary>
/// <param name="dailyStandardHours">每日标准工时默认8小时</param>
/// <returns>总标准工时</returns>
public decimal CalculateNaturalStandardHours(decimal dailyStandardHours = 8.0m)
{
return TotalDays * dailyStandardHours;
}
/// <summary>
/// 计算工作日工时
/// 仅计算工作日的工时,排除周末和节假日
/// </summary>
/// <param name="dailyWorkingHours">每个工作日的工时默认8小时</param>
/// <returns>工作日总工时</returns>
public decimal CalculateWorkingHours(decimal dailyWorkingHours = 8.0m)
{
return WorkingDays * dailyWorkingHours;
}
/// <summary>
/// 计算可用工时
/// 考虑具体的工作时间配置
/// </summary>
/// <param name="workingTimeConfig">工作时间配置</param>
/// <returns>可用总工时</returns>
public decimal CalculateAvailableHours(WorkingTimeConfiguration workingTimeConfig = null)
{
if (workingTimeConfig == null)
{
return CalculateWorkingHours();
}
decimal totalHours = 0;
var currentDate = StartDate;
while (currentDate <= EndDate)
{
if (IsWorkingDay(currentDate))
{
totalHours += workingTimeConfig.GetDailyWorkingHours(currentDate);
}
currentDate = currentDate.AddDays(1);
}
return totalHours;
}
#endregion
#region
/// <summary>
/// 判断指定日期是否在范围内
/// </summary>
/// <param name="date">要判断的日期</param>
/// <returns>是否在范围内</returns>
public bool Contains(DateTime date)
{
var checkDate = date.Date;
return checkDate >= StartDate && checkDate <= EndDate;
}
/// <summary>
/// 判断是否与另一个日期范围重叠
/// </summary>
/// <param name="other">另一个日期范围</param>
/// <returns>是否重叠</returns>
public bool Overlaps(DateRange other)
{
if (other == null) return false;
return StartDate <= other.EndDate && EndDate >= other.StartDate;
}
/// <summary>
/// 判断是否完全包含另一个日期范围
/// </summary>
/// <param name="other">另一个日期范围</param>
/// <returns>是否完全包含</returns>
public bool Contains(DateRange other)
{
if (other == null) return false;
return StartDate <= other.StartDate && EndDate >= other.EndDate;
}
/// <summary>
/// 判断指定日期是否为工作日
/// </summary>
/// <param name="date">要判断的日期</param>
/// <returns>是否为工作日</returns>
public bool IsWorkingDay(DateTime date)
{
// 排除周末
if (date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday)
{
return false;
}
// 排除节假日
return !IsHoliday(date);
}
/// <summary>
/// 判断指定日期是否为节假日
/// </summary>
/// <param name="date">要判断的日期</param>
/// <returns>是否为节假日</returns>
public bool IsHoliday(DateTime date)
{
// 这里可以集成具体的节假日数据源
// 暂时返回false实际项目中需要根据具体需求实现
return HolidayProvider.IsHoliday(date);
}
#endregion
#region
/// <summary>
/// 获取与另一个日期范围的交集
/// </summary>
/// <param name="other">另一个日期范围</param>
/// <returns>交集范围如果没有交集则返回null</returns>
public DateRange Intersect(DateRange other)
{
if (other == null || !Overlaps(other))
{
return null;
}
var intersectStart = StartDate > other.StartDate ? StartDate : other.StartDate;
var intersectEnd = EndDate < other.EndDate ? EndDate : other.EndDate;
return new DateRange(intersectStart, intersectEnd);
}
/// <summary>
/// 获取与另一个日期范围的并集
/// </summary>
/// <param name="other">另一个日期范围</param>
/// <returns>并集范围</returns>
public DateRange Union(DateRange other)
{
if (other == null)
{
return new DateRange(StartDate, EndDate);
}
var unionStart = StartDate < other.StartDate ? StartDate : other.StartDate;
var unionEnd = EndDate > other.EndDate ? EndDate : other.EndDate;
return new DateRange(unionStart, unionEnd);
}
/// <summary>
/// 扩展日期范围
/// </summary>
/// <param name="daysBefore">向前扩展的天数</param>
/// <param name="daysAfter">向后扩展的天数</param>
/// <returns>扩展后的日期范围</returns>
public DateRange Extend(int daysBefore, int daysAfter)
{
return new DateRange(
StartDate.AddDays(-daysBefore),
EndDate.AddDays(daysAfter)
);
}
/// <summary>
/// 拆分日期范围为指定天数的子范围
/// </summary>
/// <param name="chunkSize">每个子范围的天数</param>
/// <returns>子范围列表</returns>
public List<DateRange> Split(int chunkSize)
{
if (chunkSize <= 0)
{
throw new ArgumentException("块大小必须大于0");
}
var chunks = new List<DateRange>();
var currentStart = StartDate;
while (currentStart <= EndDate)
{
var currentEnd = currentStart.AddDays(chunkSize - 1);
if (currentEnd > EndDate)
{
currentEnd = EndDate;
}
chunks.Add(new DateRange(currentStart, currentEnd));
currentStart = currentEnd.AddDays(1);
}
return chunks;
}
#endregion
#region
/// <summary>
/// 获取范围内的所有日期
/// </summary>
/// <returns>日期列表</returns>
public List<DateTime> GetAllDates()
{
var dates = new List<DateTime>();
var currentDate = StartDate;
while (currentDate <= EndDate)
{
dates.Add(currentDate);
currentDate = currentDate.AddDays(1);
}
return dates;
}
/// <summary>
/// 获取范围内的所有工作日
/// </summary>
/// <returns>工作日列表</returns>
public List<DateTime> GetWorkingDays()
{
return GetAllDates().Where(IsWorkingDay).ToList();
}
/// <summary>
/// 获取范围内的所有周末
/// </summary>
/// <returns>周末日期列表</returns>
public List<DateTime> GetWeekends()
{
return GetAllDates().Where(date =>
date.DayOfWeek == DayOfWeek.Saturday ||
date.DayOfWeek == DayOfWeek.Sunday).ToList();
}
/// <summary>
/// 获取范围内的所有节假日
/// </summary>
/// <returns>节假日列表</returns>
public List<DateTime> GetHolidays()
{
return GetAllDates().Where(IsHoliday).ToList();
}
#endregion
#region
/// <summary>
/// 计算工作日天数
/// </summary>
private int CalculateWorkingDays()
{
return GetWorkingDays().Count;
}
/// <summary>
/// 计算自然工作日天数(仅排除周末)
/// </summary>
private int CalculateNaturalWorkingDays()
{
var workDays = 0;
var currentDate = StartDate;
while (currentDate <= EndDate)
{
if (currentDate.DayOfWeek != DayOfWeek.Saturday &&
currentDate.DayOfWeek != DayOfWeek.Sunday)
{
workDays++;
}
currentDate = currentDate.AddDays(1);
}
return workDays;
}
/// <summary>
/// 计算周末天数
/// </summary>
private int CalculateWeekendDays()
{
return GetWeekends().Count;
}
/// <summary>
/// 计算节假日天数
/// </summary>
private int CalculateHolidayDays()
{
return GetHolidays().Count;
}
#endregion
#region
/// <summary>
/// 创建今天的日期范围
/// </summary>
public static DateRange Today()
{
return new DateRange(DateTime.Today, DateTime.Today);
}
/// <summary>
/// 创建本周的日期范围
/// </summary>
public static DateRange ThisWeek()
{
var today = DateTime.Today;
var startOfWeek = today.AddDays(-(int)today.DayOfWeek);
var endOfWeek = startOfWeek.AddDays(6);
return new DateRange(startOfWeek, endOfWeek);
}
/// <summary>
/// 创建本月的日期范围
/// </summary>
public static DateRange ThisMonth()
{
var today = DateTime.Today;
var startOfMonth = new DateTime(today.Year, today.Month, 1);
var endOfMonth = startOfMonth.AddMonths(1).AddDays(-1);
return new DateRange(startOfMonth, endOfMonth);
}
/// <summary>
/// 创建本年的日期范围
/// </summary>
public static DateRange ThisYear()
{
var today = DateTime.Today;
var startOfYear = new DateTime(today.Year, 1, 1);
var endOfYear = new DateTime(today.Year, 12, 31);
return new DateRange(startOfYear, endOfYear);
}
/// <summary>
/// 创建指定月份的日期范围
/// </summary>
public static DateRange ForMonth(int year, int month)
{
var startOfMonth = new DateTime(year, month, 1);
var endOfMonth = startOfMonth.AddMonths(1).AddDays(-1);
return new DateRange(startOfMonth, endOfMonth);
}
/// <summary>
/// 创建指定年份的日期范围
/// </summary>
public static DateRange ForYear(int year)
{
var startOfYear = new DateTime(year, 1, 1);
var endOfYear = new DateTime(year, 12, 31);
return new DateRange(startOfYear, endOfYear);
}
#endregion
#region
/// <summary>
/// 重写ToString方法
/// </summary>
public override string ToString()
{
if (IsSingleDay)
{
return StartDate.ToString("yyyy-MM-dd");
}
return $"{StartDate:yyyy-MM-dd} ~ {EndDate:yyyy-MM-dd} ({TotalDays}天)";
}
/// <summary>
/// 重写Equals方法
/// </summary>
public override bool Equals(object obj)
{
if (obj is DateRange other)
{
return StartDate == other.StartDate && EndDate == other.EndDate;
}
return false;
}
/// <summary>
/// 重写GetHashCode方法
/// </summary>
public override int GetHashCode()
{
return HashCode.Combine(StartDate, EndDate);
}
#endregion
}
#region
/// <summary>
/// 工作时间配置
/// </summary>
public class WorkingTimeConfiguration
{
/// <summary>
/// 标准每日工作时间
/// </summary>
public decimal StandardDailyHours { get; set; } = 8.0m;
/// <summary>
/// 特殊日期工作时间配置
/// Key: 日期, Value: 工作时间
/// </summary>
public Dictionary<DateTime, decimal> SpecialDayHours { get; set; } = new();
/// <summary>
/// 获取指定日期的工作时间
/// </summary>
public decimal GetDailyWorkingHours(DateTime date)
{
return SpecialDayHours.GetValueOrDefault(date.Date, StandardDailyHours);
}
}
/// <summary>
/// 节假日提供者
/// </summary>
public static class HolidayProvider
{
/// <summary>
/// 节假日缓存
/// </summary>
private static readonly HashSet<DateTime> _holidays = new();
/// <summary>
/// 判断是否为节假日
/// </summary>
public static bool IsHoliday(DateTime date)
{
// 这里可以集成具体的节假日数据源
// 例如国家法定节假日API、企业自定义节假日等
return _holidays.Contains(date.Date);
}
/// <summary>
/// 添加节假日
/// </summary>
public static void AddHoliday(DateTime date)
{
_holidays.Add(date.Date);
}
/// <summary>
/// 批量添加节假日
/// </summary>
public static void AddHolidays(IEnumerable<DateTime> dates)
{
foreach (var date in dates)
{
_holidays.Add(date.Date);
}
}
/// <summary>
/// 移除节假日
/// </summary>
public static void RemoveHoliday(DateTime date)
{
_holidays.Remove(date.Date);
}
/// <summary>
/// 清空所有节假日
/// </summary>
public static void ClearHolidays()
{
_holidays.Clear();
}
}
#endregion
}

View File

@ -0,0 +1,226 @@
using System;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
using NPP.SmartSchedue.Api.Contracts.Core.Consts;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Equipment;
/// <summary>
/// 设备校验实体
/// </summary>
[Table(Name = DbConsts.AEMTableNamePrefix + "equipment_calibration")]
[Index("idx_{tablename}_01", nameof(TenantId) + "," + nameof(EquipmentId) + "," + nameof(CalibrationDate))]
[Index("idx_{tablename}_02", nameof(TenantId) + "," + nameof(CalibrationType))]
[Index("idx_{tablename}_03", nameof(TenantId) + "," + nameof(Status))]
public partial class EquipmentCalibrationEntity : EntityTenant
{
/// <summary>
/// 设备ID
/// </summary>
public long EquipmentId { get; set; }
/// <summary>
/// 设备名称
/// </summary>
[Column(StringLength = 100)]
public string EquipmentName { get; set; }
/// <summary>
/// 校验类型
/// </summary>
[Column(StringLength = 50)]
public string CalibrationType { get; set; }
/// <summary>
/// 校验日期
/// </summary>
public DateTime CalibrationDate { get; set; }
/// <summary>
/// 校验开始时间
/// </summary>
public DateTime? StartTime { get; set; }
/// <summary>
/// 校验结束时间
/// </summary>
public DateTime? EndTime { get; set; }
/// <summary>
/// 校验时长(小时)
/// </summary>
public decimal? CalibrationHours { get; set; }
/// <summary>
/// 校验人员ID
/// </summary>
public long? CalibrationPersonId { get; set; }
/// <summary>
/// 校验人员姓名
/// </summary>
[Column(StringLength = 50)]
public string CalibrationPersonName { get; set; }
/// <summary>
/// 校验机构
/// </summary>
[Column(StringLength = 200)]
public string CalibrationInstitution { get; set; }
/// <summary>
/// 校验证书编号
/// </summary>
[Column(StringLength = 100)]
public string CertificateNumber { get; set; }
/// <summary>
/// 校验结果
/// </summary>
[Column(StringLength = 50)]
public string CalibrationResult { get; set; }
/// <summary>
/// 校验精度
/// </summary>
[Column(StringLength = 100)]
public string CalibrationAccuracy { get; set; }
/// <summary>
/// 校验费用
/// </summary>
public decimal? CalibrationCost { get; set; }
/// <summary>
/// 状态0-计划中1-进行中2-已完成3-已取消)
/// </summary>
public int Status { get; set; } = 0;
/// <summary>
/// 是否计划校验
/// </summary>
public bool IsPlanned { get; set; } = false;
/// <summary>
/// 计划校验周期(天)
/// </summary>
public int? PlannedCycle { get; set; }
/// <summary>
/// 下次计划校验日期
/// </summary>
public DateTime? NextPlannedDate { get; set; }
/// <summary>
/// 校验标准
/// </summary>
[Column(StringLength = 200)]
public string CalibrationStandard { get; set; }
/// <summary>
/// 校验方法
/// </summary>
[Column(StringLength = 500)]
public string CalibrationMethod { get; set; }
/// <summary>
/// 校验环境要求
/// </summary>
[Column(StringLength = 500)]
public string EnvironmentalRequirements { get; set; }
/// <summary>
/// 校验报告路径
/// </summary>
[Column(StringLength = 500)]
public string ReportPath { get; set; }
/// <summary>
/// 备注
/// </summary>
[Column(StringLength = 500)]
public string Remark { get; set; }
}
/// <summary>
/// 校验类型枚举
/// </summary>
public static class CalibrationType
{
/// <summary>
/// 定期校验
/// </summary>
public const string Regular = "Regular";
/// <summary>
/// 首次校验
/// </summary>
public const string Initial = "Initial";
/// <summary>
/// 重新校验
/// </summary>
public const string Recalibration = "Recalibration";
/// <summary>
/// 临时校验
/// </summary>
public const string Temporary = "Temporary";
/// <summary>
/// 强制校验
/// </summary>
public const string Mandatory = "Mandatory";
}
/// <summary>
/// 校验结果枚举
/// </summary>
public static class CalibrationResult
{
/// <summary>
/// 合格
/// </summary>
public const string Pass = "Pass";
/// <summary>
/// 不合格
/// </summary>
public const string Fail = "Fail";
/// <summary>
/// 部分合格
/// </summary>
public const string Partial = "Partial";
/// <summary>
/// 待定
/// </summary>
public const string Pending = "Pending";
}
/// <summary>
/// 校验状态枚举
/// </summary>
public static class CalibrationStatus
{
/// <summary>
/// 计划中
/// </summary>
public const int Planned = 0;
/// <summary>
/// 进行中
/// </summary>
public const int InProgress = 1;
/// <summary>
/// 已完成
/// </summary>
public const int Completed = 2;
/// <summary>
/// 已取消
/// </summary>
public const int Cancelled = 3;
}

View File

@ -0,0 +1,200 @@
using System;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
using NPP.SmartSchedue.Api.Contracts.Core.Consts;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Equipment;
/// <summary>
/// 设备基本信息实体
/// </summary>
[Table(Name = DbConsts.AEMTableNamePrefix + "equipment")]
[Index("idx_{tablename}_01", nameof(TenantId) + "," + nameof(InternalNumber), true)]
[Index("idx_{tablename}_02", nameof(TenantId) + "," + nameof(EquipmentType))]
[Index("idx_{tablename}_03", nameof(TenantId) + "," + nameof(Status))]
public partial class EquipmentEntity : EntityTenant
{
/// <summary>
/// 设备名称
/// </summary>
[Column(StringLength = 100)]
public string Name { get; set; }
/// <summary>
/// 设备型号
/// </summary>
[Column(StringLength = 100)]
public string Model { get; set; }
/// <summary>
/// 内部编号
/// </summary>
[Column(StringLength = 50)]
public string InternalNumber { get; set; }
/// <summary>
/// 房间号
/// </summary>
[Column(StringLength = 50)]
public string RoomNumber { get; set; }
/// <summary>
/// 设备类型
/// </summary>
[Column(StringLength = 50)]
public string EquipmentType { get; set; }
/// <summary>
/// 设备状态0-正常1-维护2-校验3-故障4-报废)
/// </summary>
public int Status { get; set; } = 0;
/// <summary>
/// 适配工序
/// </summary>
public long ProcessID { get; set; }
/// <summary>
/// 固资编号
/// </summary>
[Column(StringLength = 50)]
public string FixedAssetNumber { get; set; }
/// <summary>
/// 设备负责人ID
/// </summary>
public long? ResponsiblePersonId { get; set; }
/// <summary>
/// 设备负责人姓名
/// </summary>
[Column(StringLength = 50)]
public string ResponsiblePersonName { get; set; }
/// <summary>
/// 最大流速
/// </summary>
public decimal? MaxFlowRate { get; set; }
/// <summary>
/// 流速单位
/// </summary>
[Column(StringLength = 20)]
public string FlowRateUnit { get; set; }
/// <summary>
/// 设备规格
/// </summary>
[Column(StringLength = 500)]
public string Specifications { get; set; }
/// <summary>
/// 制造商
/// </summary>
[Column(StringLength = 100)]
public string Manufacturer { get; set; }
/// <summary>
/// 购买日期
/// </summary>
public DateTime? PurchaseDate { get; set; }
/// <summary>
/// 保修期(月)
/// </summary>
public int? WarrantyMonths { get; set; }
/// <summary>
/// 最后维护日期
/// </summary>
public DateTime? LastMaintenanceDate { get; set; }
/// <summary>
/// 下次维护日期
/// </summary>
public DateTime? NextMaintenanceDate { get; set; }
/// <summary>
/// 最后校验日期
/// </summary>
public DateTime? LastCalibrationDate { get; set; }
/// <summary>
/// 下次校验日期
/// </summary>
public DateTime? NextCalibrationDate { get; set; }
/// <summary>
/// 设备位置
/// </summary>
[Column(StringLength = 200)]
public string Location { get; set; }
/// <summary>
/// 备注
/// </summary>
[Column(StringLength = 500)]
public string Remark { get; set; }
}
/// <summary>
/// 设备状态枚举
/// </summary>
public static class EquipmentStatus
{
/// <summary>
/// 正常
/// </summary>
public const int Normal = 0;
/// <summary>
/// 维护
/// </summary>
public const int Maintenance = 1;
/// <summary>
/// 校验
/// </summary>
public const int Calibration = 2;
/// <summary>
/// 故障
/// </summary>
public const int Fault = 3;
/// <summary>
/// 报废
/// </summary>
public const int Scrapped = 4;
}
/// <summary>
/// 设备类型枚举
/// </summary>
public static class EquipmentType
{
/// <summary>
/// 生产设备
/// </summary>
public const string Production = "Production";
/// <summary>
/// 检测设备
/// </summary>
public const string Testing = "Testing";
/// <summary>
/// 实验室设备
/// </summary>
public const string Laboratory = "Laboratory";
/// <summary>
/// 办公设备
/// </summary>
public const string Office = "Office";
/// <summary>
/// 其他设备
/// </summary>
public const string Other = "Other";
}

View File

@ -0,0 +1,176 @@
using System;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
using NPP.SmartSchedue.Api.Contracts.Core.Consts;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Equipment;
/// <summary>
/// 设备维修实体
/// </summary>
[Table(Name = DbConsts.AEMTableNamePrefix + "equipment_maintenance")]
[Index("idx_{tablename}_01", nameof(TenantId) + "," + nameof(EquipmentId) + "," + nameof(MaintenanceDate))]
[Index("idx_{tablename}_02", nameof(TenantId) + "," + nameof(MaintenanceType))]
[Index("idx_{tablename}_03", nameof(TenantId) + "," + nameof(Status))]
public partial class EquipmentMaintenanceEntity : EntityTenant
{
/// <summary>
/// 设备ID
/// </summary>
public long EquipmentId { get; set; }
/// <summary>
/// 设备名称
/// </summary>
[Column(StringLength = 100)]
public string EquipmentName { get; set; }
/// <summary>
/// 维修类型
/// </summary>
[Column(StringLength = 50)]
public string MaintenanceType { get; set; }
/// <summary>
/// 维修日期
/// </summary>
public DateTime MaintenanceDate { get; set; }
/// <summary>
/// 维修开始时间
/// </summary>
public DateTime? StartTime { get; set; }
/// <summary>
/// 维修结束时间
/// </summary>
public DateTime? EndTime { get; set; }
/// <summary>
/// 维修时长(小时)
/// </summary>
public decimal? MaintenanceHours { get; set; }
/// <summary>
/// 维修人员ID
/// </summary>
public long? MaintenancePersonId { get; set; }
/// <summary>
/// 维修人员姓名
/// </summary>
[Column(StringLength = 50)]
public string MaintenancePersonName { get; set; }
/// <summary>
/// 维修内容
/// </summary>
[Column(StringLength = 1000)]
public string MaintenanceContent { get; set; }
/// <summary>
/// 维修结果
/// </summary>
[Column(StringLength = 500)]
public string MaintenanceResult { get; set; }
/// <summary>
/// 维修费用
/// </summary>
public decimal? MaintenanceCost { get; set; }
/// <summary>
/// 状态0-计划中1-进行中2-已完成3-已取消)
/// </summary>
public int Status { get; set; } = 0;
/// <summary>
/// 是否计划维修
/// </summary>
public bool IsPlanned { get; set; } = false;
/// <summary>
/// 计划维修周期(天)
/// </summary>
public int? PlannedCycle { get; set; }
/// <summary>
/// 下次计划维修日期
/// </summary>
public DateTime? NextPlannedDate { get; set; }
/// <summary>
/// 维修工具
/// </summary>
[Column(StringLength = 500)]
public string MaintenanceTools { get; set; }
/// <summary>
/// 维修材料
/// </summary>
[Column(StringLength = 500)]
public string MaintenanceMaterials { get; set; }
/// <summary>
/// 备注
/// </summary>
[Column(StringLength = 500)]
public string Remark { get; set; }
}
/// <summary>
/// 维修类型枚举
/// </summary>
public static class MaintenanceType
{
/// <summary>
/// 预防性维护
/// </summary>
public const string Preventive = "Preventive";
/// <summary>
/// 故障维修
/// </summary>
public const string Corrective = "Corrective";
/// <summary>
/// 紧急维修
/// </summary>
public const string Emergency = "Emergency";
/// <summary>
/// 定期保养
/// </summary>
public const string Regular = "Regular";
/// <summary>
/// 升级改造
/// </summary>
public const string Upgrade = "Upgrade";
}
/// <summary>
/// 维修状态枚举
/// </summary>
public static class MaintenanceStatus
{
/// <summary>
/// 计划中
/// </summary>
public const int Planned = 0;
/// <summary>
/// 进行中
/// </summary>
public const int InProgress = 1;
/// <summary>
/// 已完成
/// </summary>
public const int Completed = 2;
/// <summary>
/// 已取消
/// </summary>
public const int Cancelled = 3;
}

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ZhonTai.Admin.Core.Repositories;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Equipment;
/// <summary>
/// 设备校验仓储接口简化版本专用于SmartSchedule模块
/// </summary>
public interface IEquipmentCalibrationRepository : IRepositoryBase<EquipmentCalibrationEntity>
{
/// <summary>
/// 根据设备ID获取校验记录
/// </summary>
/// <param name="equipmentId">设备ID</param>
/// <returns>校验记录列表</returns>
Task<List<EquipmentCalibrationEntity>> GetByEquipmentIdAsync(long equipmentId);
/// <summary>
/// 检查设备是否有进行中的校验
/// </summary>
/// <param name="equipmentId">设备ID</param>
/// <returns>是否有进行中的校验</returns>
Task<bool> HasInProgressCalibrationAsync(long equipmentId);
/// <summary>
/// 获取指定日期需要校验的设备ID列表
/// </summary>
/// <param name="date">指定日期</param>
/// <returns>设备ID列表</returns>
Task<List<long>> GetCalibrationEquipmentIdsAsync(DateTime date);
}

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ZhonTai.Admin.Core.Repositories;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Equipment;
/// <summary>
/// 设备维护仓储接口简化版本专用于SmartSchedule模块
/// </summary>
public interface IEquipmentMaintenanceRepository : IRepositoryBase<EquipmentMaintenanceEntity>
{
/// <summary>
/// 根据设备ID获取维护记录
/// </summary>
/// <param name="equipmentId">设备ID</param>
/// <returns>维护记录列表</returns>
Task<List<EquipmentMaintenanceEntity>> GetByEquipmentIdAsync(long equipmentId);
/// <summary>
/// 检查设备是否有进行中的维护
/// </summary>
/// <param name="equipmentId">设备ID</param>
/// <returns>是否有进行中的维护</returns>
Task<bool> HasInProgressMaintenanceAsync(long equipmentId);
/// <summary>
/// 获取指定日期需要维护的设备ID列表
/// </summary>
/// <param name="date">指定日期</param>
/// <returns>设备ID列表</returns>
Task<List<long>> GetMaintenanceEquipmentIdsAsync(DateTime date);
}

View File

@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ZhonTai.Admin.Core.Repositories;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Equipment;
/// <summary>
/// 设备仓储接口
/// </summary>
public interface IEquipmentRepository : IRepositoryBase<EquipmentEntity>
{
/// <summary>
/// 根据设备类型获取设备列表
/// </summary>
/// <param name="equipmentType">设备类型</param>
/// <returns>设备列表</returns>
Task<List<EquipmentEntity>> GetByTypeAsync(string equipmentType);
/// <summary>
/// 根据状态获取设备列表
/// </summary>
/// <param name="status">设备状态</param>
/// <returns>设备列表</returns>
Task<List<EquipmentEntity>> GetByStatusAsync(int status);
/// <summary>
/// 根据内部编号获取设备
/// </summary>
/// <param name="internalNumber">内部编号</param>
/// <returns>设备信息</returns>
Task<EquipmentEntity> GetByInternalNumberAsync(string internalNumber);
/// <summary>
/// 获取可用设备列表(正常状态)
/// </summary>
/// <param name="date">指定日期</param>
/// <returns>可用设备列表</returns>
Task<List<EquipmentEntity>> GetAvailableEquipmentAsync(DateTime date);
/// <summary>
/// 根据工序获取适配设备列表
/// </summary>
/// <param name="processName">工序名称</param>
/// <returns>适配设备列表</returns>
Task<List<EquipmentEntity>> GetByProcessAsync(string processName);
/// <summary>
/// 检查设备是否可用
/// </summary>
/// <param name="equipmentId">设备ID</param>
/// <param name="date">指定日期</param>
/// <returns>是否可用</returns>
Task<bool> IsEquipmentAvailableAsync(long equipmentId, DateTime date);
/// <summary>
/// 获取设备使用情况
/// </summary>
/// <param name="equipmentId">设备ID</param>
/// <param name="startDate">开始日期</param>
/// <param name="endDate">结束日期</param>
/// <returns>设备使用情况</returns>
Task<EquipmentUsageInfo> GetUsageAsync(long equipmentId, DateTime startDate, DateTime endDate);
/// <summary>
/// 获取需要维护的设备列表
/// </summary>
/// <param name="date">指定日期</param>
/// <returns>需要维护的设备列表</returns>
Task<List<EquipmentEntity>> GetNeedMaintenanceAsync(DateTime date);
/// <summary>
/// 获取需要校验的设备列表
/// </summary>
/// <param name="date">指定日期</param>
/// <returns>需要校验的设备列表</returns>
Task<List<EquipmentEntity>> GetNeedCalibrationAsync(DateTime date);
/// <summary>
/// 检查指定设备类型是否有可用设备
/// </summary>
/// <param name="equipmentType">设备类型</param>
/// <returns>是否有可用设备</returns>
Task<bool> HasAvailableEquipmentByTypeAsync(string equipmentType);
}
/// <summary>
/// 设备使用情况信息
/// </summary>
public class EquipmentUsageInfo
{
/// <summary>
/// 设备ID
/// </summary>
public long EquipmentId { get; set; }
/// <summary>
/// 设备名称
/// </summary>
public string EquipmentName { get; set; }
/// <summary>
/// 使用天数
/// </summary>
public int UsageDays { get; set; }
/// <summary>
/// 使用小时数
/// </summary>
public int UsageHours { get; set; }
/// <summary>
/// 维护次数
/// </summary>
public int MaintenanceCount { get; set; }
/// <summary>
/// 校验次数
/// </summary>
public int CalibrationCount { get; set; }
/// <summary>
/// 故障次数
/// </summary>
public int FaultCount { get; set; }
}

View File

@ -0,0 +1,389 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ZhonTai.Admin.Core.Repositories;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Output;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Integration
{
/// <summary>
/// 智能整合记录仓储接口
///
/// 业务思考:
/// 1. 提供丰富的查询接口,支持多维度的历史数据分析
/// 2. 考虑查询性能,提供必要的分页和索引优化
/// 3. 支持统计分析功能,为业务决策提供数据支持
/// 4. 考虑数据量增长,提供数据归档和清理机制
/// </summary>
public interface IIntegrationRecordRepository : IRepositoryBase<IntegrationRecordEntity>
{
#region
/// <summary>
/// 根据批次编码获取整合记录
/// 业务场景:根据批次编码快速定位特定的整合操作
/// </summary>
/// <param name="batchCode">批次编码</param>
/// <returns>整合记录如果不存在返回null</returns>
Task<IntegrationRecordEntity?> GetByBatchCodeAsync(string batchCode);
/// <summary>
/// 获取指定时间范围内的整合记录
/// 业务场景:时间范围查询,支持日报、周报、月报等业务需求
/// </summary>
/// <param name="startTime">开始时间(包含)</param>
/// <param name="endTime">结束时间(包含)</param>
/// <param name="pageIndex">页码从1开始</param>
/// <param name="pageSize">每页大小</param>
/// <returns>整合记录分页列表</returns>
Task<(List<IntegrationRecordEntity> Records, long Total)> GetByTimeRangeAsync(
DateTime startTime,
DateTime endTime,
int pageIndex = 1,
int pageSize = 20);
/// <summary>
/// 根据操作人员获取整合记录
/// 业务场景:查看特定操作员的整合历史,用于工作量统计和绩效分析
/// </summary>
/// <param name="operatorUserId">操作员用户ID</param>
/// <param name="pageIndex">页码</param>
/// <param name="pageSize">每页大小</param>
/// <returns>整合记录分页列表</returns>
Task<(List<IntegrationRecordEntity> Records, long Total)> GetByOperatorAsync(
long operatorUserId,
int pageIndex = 1,
int pageSize = 20);
/// <summary>
/// 根据项目编号获取相关整合记录
/// 业务场景:项目维度的整合历史查询和分析
/// </summary>
/// <param name="projectNumber">项目编号</param>
/// <param name="pageIndex">页码</param>
/// <param name="pageSize">每页大小</param>
/// <returns>整合记录分页列表</returns>
Task<(List<IntegrationRecordEntity> Records, long Total)> GetByProjectNumberAsync(
string projectNumber,
int pageIndex = 1,
int pageSize = 20);
#endregion
#region
/// <summary>
/// 多维度综合查询整合记录
/// 业务场景:复杂查询场景,支持多个条件的组合查询
/// </summary>
/// <param name="operatorUserId">操作员ID可选</param>
/// <param name="projectNumber">项目编号(可选)</param>
/// <param name="integrationType">整合类型(可选)</param>
/// <param name="startTime">开始时间(可选)</param>
/// <param name="endTime">结束时间(可选)</param>
/// <param name="minSuccessRate">最小成功率(可选)</param>
/// <param name="pageIndex">页码</param>
/// <param name="pageSize">每页大小</param>
/// <returns>整合记录分页列表</returns>
Task<(List<IntegrationRecordEntity> Records, long Total)> GetByMultipleConditionsAsync(
long? operatorUserId = null,
string? projectNumber = null,
string? integrationType = null,
DateTime? startTime = null,
DateTime? endTime = null,
decimal? minSuccessRate = null,
int pageIndex = 1,
int pageSize = 20);
/// <summary>
/// 获取包含指定任务的整合记录
/// 业务场景根据任务ID反向查询相关的整合历史
/// </summary>
/// <param name="taskId">任务ID</param>
/// <returns>包含该任务的整合记录列表</returns>
Task<List<IntegrationRecordEntity>> GetRecordsContainingTaskAsync(long taskId);
#endregion
#region
/// <summary>
/// 获取指定时间段的整合统计数据
/// 业务场景:生成统计报表,分析整合效果和趋势
/// </summary>
/// <param name="startTime">开始时间</param>
/// <param name="endTime">结束时间</param>
/// <returns>统计数据</returns>
Task<IntegrationStatistics> GetIntegrationStatisticsAsync(DateTime startTime, DateTime endTime);
/// <summary>
/// 获取操作员整合统计数据
/// 业务场景:操作员工作量和效率分析
/// </summary>
/// <param name="operatorUserId">操作员ID</param>
/// <param name="startTime">开始时间</param>
/// <param name="endTime">结束时间</param>
/// <returns>操作员统计数据</returns>
Task<OperatorIntegrationStats> GetOperatorStatisticsAsync(
long operatorUserId,
DateTime startTime,
DateTime endTime);
/// <summary>
/// 获取策略效果分析数据
/// 业务场景:分析不同分配策略的效果,为策略优化提供数据支持
/// </summary>
/// <param name="startTime">开始时间</param>
/// <param name="endTime">结束时间</param>
/// <returns>策略效果统计数据</returns>
Task<List<StrategyEffectivenessStats>> GetStrategyEffectivenessAsync(
DateTime startTime,
DateTime endTime);
/// <summary>
/// 获取整合性能趋势数据
/// 业务场景:监控系统性能,识别性能瓶颈和优化机会
/// </summary>
/// <param name="days">最近天数</param>
/// <returns>性能趋势数据</returns>
Task<List<IntegrationPerformanceTrend>> GetPerformanceTrendAsync(int days = 30);
#endregion
#region
/// <summary>
/// 检查批次编码是否已存在
/// 业务场景:防止批次编码重复,确保数据唯一性
/// </summary>
/// <param name="batchCode">批次编码</param>
/// <returns>是否存在</returns>
Task<bool> BatchCodeExistsAsync(string batchCode);
/// <summary>
/// 获取最近的整合记录
/// 业务场景:快速查看最新的整合状态,支持监控面板显示
/// </summary>
/// <param name="count">获取记录数量</param>
/// <returns>最近的整合记录列表</returns>
Task<List<IntegrationRecordEntity>> GetRecentRecordsAsync(int count = 10);
/// <summary>
/// 获取失败率高的整合记录
/// 业务场景:识别问题操作,支持质量改进和问题排查
/// </summary>
/// <param name="minFailureRate">最小失败率阈值(百分比)</param>
/// <param name="startTime">开始时间</param>
/// <param name="endTime">结束时间</param>
/// <param name="count">最大返回数量</param>
/// <returns>高失败率的整合记录</returns>
Task<List<IntegrationRecordEntity>> GetHighFailureRateRecordsAsync(
decimal minFailureRate,
DateTime startTime,
DateTime endTime,
int count = 50);
/// <summary>
/// 软删除过期的测试数据
/// 业务场景:定期清理测试数据,保持生产环境数据整洁
/// </summary>
/// <param name="beforeDate">删除此日期之前的测试数据</param>
/// <returns>删除的记录数量</returns>
Task<int> SoftDeleteExpiredTestDataAsync(DateTime beforeDate);
#endregion
}
#region
/// <summary>
/// 整合统计数据
/// </summary>
public class IntegrationStatistics
{
/// <summary>
/// 统计时间范围开始
/// </summary>
public DateTime StartTime { get; set; }
/// <summary>
/// 统计时间范围结束
/// </summary>
public DateTime EndTime { get; set; }
/// <summary>
/// 整合操作总次数
/// </summary>
public int TotalIntegrations { get; set; }
/// <summary>
/// 涉及任务总数
/// </summary>
public long TotalTasks { get; set; }
/// <summary>
/// 成功分配任务数
/// </summary>
public long SuccessfulTasks { get; set; }
/// <summary>
/// 失败分配任务数
/// </summary>
public long FailedTasks { get; set; }
/// <summary>
/// 平均成功率
/// </summary>
public decimal AverageSuccessRate { get; set; }
/// <summary>
/// 平均执行耗时(毫秒)
/// </summary>
public long AverageElapsedTime { get; set; }
/// <summary>
/// 平均人员公平性评分
/// </summary>
public decimal AveragePersonnelFairnessScore { get; set; }
/// <summary>
/// 平均设备利用率
/// </summary>
public decimal AverageEquipmentUtilizationRate { get; set; }
/// <summary>
/// 活跃操作员数量
/// </summary>
public int ActiveOperatorCount { get; set; }
/// <summary>
/// 涉及项目数量
/// </summary>
public int InvolvedProjectCount { get; set; }
}
/// <summary>
/// 操作员整合统计数据
/// </summary>
public class OperatorIntegrationStats
{
/// <summary>
/// 操作员用户ID
/// </summary>
public long OperatorUserId { get; set; }
/// <summary>
/// 操作员用户名
/// </summary>
public string OperatorUserName { get; set; } = string.Empty;
/// <summary>
/// 操作员真实姓名
/// </summary>
public string OperatorRealName { get; set; } = string.Empty;
/// <summary>
/// 执行整合次数
/// </summary>
public int IntegrationCount { get; set; }
/// <summary>
/// 处理任务总数
/// </summary>
public long TotalTasks { get; set; }
/// <summary>
/// 平均成功率
/// </summary>
public decimal AverageSuccessRate { get; set; }
/// <summary>
/// 总耗时(毫秒)
/// </summary>
public long TotalElapsedTime { get; set; }
/// <summary>
/// 平均每次整合耗时
/// </summary>
public long AverageIntegrationTime { get; set; }
/// <summary>
/// 最后操作时间
/// </summary>
public DateTime LastOperationTime { get; set; }
}
/// <summary>
/// 策略效果统计数据
/// </summary>
public class StrategyEffectivenessStats
{
/// <summary>
/// 人员分配策略
/// </summary>
public string PersonnelStrategy { get; set; } = string.Empty;
/// <summary>
/// 设备分配策略
/// </summary>
public string EquipmentStrategy { get; set; } = string.Empty;
/// <summary>
/// 使用次数
/// </summary>
public int UsageCount { get; set; }
/// <summary>
/// 平均成功率
/// </summary>
public decimal AverageSuccessRate { get; set; }
/// <summary>
/// 平均人员公平性评分
/// </summary>
public decimal AveragePersonnelFairnessScore { get; set; }
/// <summary>
/// 平均设备利用率
/// </summary>
public decimal AverageEquipmentUtilizationRate { get; set; }
/// <summary>
/// 平均执行耗时
/// </summary>
public long AverageElapsedTime { get; set; }
}
/// <summary>
/// 整合性能趋势数据
/// </summary>
public class IntegrationPerformanceTrend
{
/// <summary>
/// 日期
/// </summary>
public DateTime Date { get; set; }
/// <summary>
/// 当日整合次数
/// </summary>
public int IntegrationCount { get; set; }
/// <summary>
/// 当日平均成功率
/// </summary>
public decimal AverageSuccessRate { get; set; }
/// <summary>
/// 当日平均耗时(毫秒)
/// </summary>
public long AverageElapsedTime { get; set; }
/// <summary>
/// 当日处理任务总数
/// </summary>
public long TotalTasks { get; set; }
}
#endregion
}

View File

@ -0,0 +1,338 @@
using System;
using System.Collections.Generic;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Output;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Integration
{
/// <summary>
/// 整合记录变更详情
/// 记录版本间的详细变更信息,支持变更分析和回滚操作
/// </summary>
public class IntegrationChangeDetails
{
/// <summary>
/// 变更类型列表
/// 可能的值TaskModified, TaskAdded, TaskRemoved, PersonnelChanged, EquipmentChanged,
/// TaskTimeConflict, PersonnelUnavailable, EquipmentUnavailable, PriorityAdjusted
/// </summary>
public List<string> ChangeTypes { get; set; } = new();
/// <summary>
/// 发生变更的任务ID列表
/// </summary>
public List<long> ChangedTaskIds { get; set; } = new();
/// <summary>
/// 新增的任务ID列表
/// </summary>
public List<long> AddedTaskIds { get; set; } = new();
/// <summary>
/// 移除的任务ID列表
/// </summary>
public List<long> RemovedTaskIds { get; set; } = new();
/// <summary>
/// 受影响的人员ID列表
/// </summary>
public List<long> AffectedPersonnelIds { get; set; } = new();
/// <summary>
/// 受影响的设备ID列表
/// </summary>
public List<long> AffectedEquipmentIds { get; set; } = new();
/// <summary>
/// 具体的任务修改详情
/// </summary>
public List<TaskChangeDetail> TaskModifications { get; set; } = new();
/// <summary>
/// 人员分配变更详情
/// </summary>
public List<PersonnelAssignmentChange> PersonnelChanges { get; set; } = new();
/// <summary>
/// 设备分配变更详情
/// </summary>
public List<EquipmentAssignmentChange> EquipmentChanges { get; set; } = new();
/// <summary>
/// 变更触发的原始事件
/// 记录导致变更的原始事件信息
/// </summary>
public ChangeTriggeredEvent TriggerEvent { get; set; } = new();
/// <summary>
/// 变更检测时间
/// </summary>
public DateTime DetectedTime { get; set; } = DateTime.Now;
/// <summary>
/// 变更处理状态
/// Detected-已检测, Processing-处理中, Completed-已完成, Failed-处理失败
/// </summary>
public string ProcessingStatus { get; set; } = "Detected";
/// <summary>
/// 变更影响分析
/// </summary>
public ChangeImpactAnalysis ImpactAnalysis { get; set; } = new();
}
/// <summary>
/// 任务变更详情Domain层
/// </summary>
public class TaskChangeDetail
{
/// <summary>
/// 任务ID
/// </summary>
public long TaskId { get; set; }
/// <summary>
/// 任务代码
/// </summary>
public string TaskCode { get; set; } = string.Empty;
/// <summary>
/// 修改类型
/// TimeChanged-时间变更, PriorityChanged-优先级变更, PersonnelRequirementChanged-人员需求变更,
/// EquipmentRequirementChanged-设备需求变更, StatusChanged-状态变更
/// </summary>
public string ModificationType { get; set; } = string.Empty;
/// <summary>
/// 修改前的值JSON格式
/// </summary>
public string BeforeValue { get; set; } = "{}";
/// <summary>
/// 修改后的值JSON格式
/// </summary>
public string AfterValue { get; set; } = "{}";
/// <summary>
/// 修改时间
/// </summary>
public DateTime ModifiedTime { get; set; } = DateTime.Now;
/// <summary>
/// 修改说明
/// </summary>
public string Description { get; set; } = string.Empty;
/// <summary>
/// 影响评估
/// 评估这个修改对整体分配的影响程度
/// </summary>
public string ImpactAssessment { get; set; } = string.Empty;
/// <summary>
/// 变更类型兼容性属性映射到ModificationType
/// </summary>
public string ChangeType => ModificationType;
/// <summary>
/// 影响级别根据ImpactAssessment计算
/// </summary>
public TaskChangeImpactLevel ImpactLevel
{
get
{
if (ImpactAssessment.Contains("高影响") || ImpactAssessment.Contains("严重"))
return TaskChangeImpactLevel.High;
if (ImpactAssessment.Contains("中等") || ImpactAssessment.Contains("一般"))
return TaskChangeImpactLevel.Medium;
if (ImpactAssessment.Contains("低影响") || ImpactAssessment.Contains("轻微"))
return TaskChangeImpactLevel.Low;
return TaskChangeImpactLevel.Medium; // 默认中等影响
}
}
}
/// <summary>
/// 人员分配变更
/// </summary>
public class PersonnelAssignmentChange
{
/// <summary>
/// 任务ID
/// </summary>
public long TaskId { get; set; }
/// <summary>
/// 原分配人员ID
/// </summary>
public long? PreviousPersonnelId { get; set; }
/// <summary>
/// 原分配人员姓名
/// </summary>
public string PreviousPersonnelName { get; set; } = string.Empty;
/// <summary>
/// 新分配人员ID
/// </summary>
public long? NewPersonnelId { get; set; }
/// <summary>
/// 新分配人员姓名
/// </summary>
public string NewPersonnelName { get; set; } = string.Empty;
/// <summary>
/// 变更原因
/// </summary>
public string ChangeReason { get; set; } = string.Empty;
/// <summary>
/// 变更时间
/// </summary>
public DateTime ChangeTime { get; set; } = DateTime.Now;
/// <summary>
/// 是否为自动变更
/// </summary>
public bool IsAutomaticChange { get; set; } = false;
}
/// <summary>
/// 设备分配变更
/// </summary>
public class EquipmentAssignmentChange
{
/// <summary>
/// 任务ID
/// </summary>
public long TaskId { get; set; }
/// <summary>
/// 原分配设备ID
/// </summary>
public long? PreviousEquipmentId { get; set; }
/// <summary>
/// 原分配设备名称
/// </summary>
public string PreviousEquipmentName { get; set; } = string.Empty;
/// <summary>
/// 新分配设备ID
/// </summary>
public long? NewEquipmentId { get; set; }
/// <summary>
/// 新分配设备名称
/// </summary>
public string NewEquipmentName { get; set; } = string.Empty;
/// <summary>
/// 变更原因
/// </summary>
public string ChangeReason { get; set; } = string.Empty;
/// <summary>
/// 变更时间
/// </summary>
public DateTime ChangeTime { get; set; } = DateTime.Now;
/// <summary>
/// 是否为自动变更
/// </summary>
public bool IsAutomaticChange { get; set; } = false;
}
/// <summary>
/// 变更触发事件
/// </summary>
public class ChangeTriggeredEvent
{
/// <summary>
/// 事件类型
/// TaskModified-任务修改, UserRequest-用户请求, SystemOptimization-系统优化,
/// ResourceUnavailable-资源不可用, ConflictDetected-冲突检测
/// </summary>
public string EventType { get; set; } = string.Empty;
/// <summary>
/// 事件来源
/// 标识触发变更的具体来源
/// </summary>
public string EventSource { get; set; } = string.Empty;
/// <summary>
/// 事件详情
/// </summary>
public string EventDetails { get; set; } = string.Empty;
/// <summary>
/// 事件发生时间
/// </summary>
public DateTime EventTime { get; set; } = DateTime.Now;
/// <summary>
/// 触发用户ID
/// </summary>
public long? TriggeredByUserId { get; set; }
/// <summary>
/// 触发用户姓名
/// </summary>
public string TriggeredByUserName { get; set; } = string.Empty;
}
/// <summary>
/// 变更影响分析
/// </summary>
public class ChangeImpactAnalysis
{
/// <summary>
/// 影响范围
/// Local-局部影响, Regional-区域影响, Global-全局影响
/// </summary>
public string ImpactScope { get; set; } = "Local";
/// <summary>
/// 影响严重程度
/// Low-轻微, Medium-中等, High-严重, Critical-关键
/// </summary>
public string SeverityLevel { get; set; } = "Low";
/// <summary>
/// 预计影响的任务数量
/// </summary>
public int EstimatedAffectedTasks { get; set; } = 0;
/// <summary>
/// 预计影响的人员数量
/// </summary>
public int EstimatedAffectedPersonnel { get; set; } = 0;
/// <summary>
/// 预计影响的设备数量
/// </summary>
public int EstimatedAffectedEquipment { get; set; } = 0;
/// <summary>
/// 建议的处理策略
/// AutoReallocation-自动重新分配, ManualReview-手动复审, FullReintegration-完全重新整合
/// </summary>
public string RecommendedAction { get; set; } = "AutoReallocation";
/// <summary>
/// 预计处理耗时(分钟)
/// </summary>
public int EstimatedProcessingTimeMinutes { get; set; } = 0;
/// <summary>
/// 风险评估
/// </summary>
public string RiskAssessment { get; set; } = string.Empty;
/// <summary>
/// 业务影响说明
/// </summary>
public string BusinessImpactDescription { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,74 @@
namespace NPP.SmartSchedue.Api.Contracts.Domain.Integration
{
/// <summary>
/// 整合生命周期阶段枚举
/// 定义整合记录在其生命周期中所处的不同阶段
/// </summary>
public enum IntegrationLifecycleStage
{
/// <summary>
/// 创建阶段 - 刚创建,正在初始化
/// </summary>
Created = 1,
/// <summary>
/// 草稿阶段 - 正在编辑和完善
/// </summary>
Draft = 2,
/// <summary>
/// 验证阶段 - 正在进行验证检查
/// </summary>
Validating = 3,
/// <summary>
/// 准备发布 - 验证通过,准备发布
/// </summary>
ReadyToPublish = 4,
/// <summary>
/// 已发布 - 正式发布,开始执行
/// </summary>
Published = 5,
/// <summary>
/// 执行中 - 正在执行任务
/// </summary>
InProgress = 6,
/// <summary>
/// 部分完成 - 部分任务已完成
/// </summary>
PartiallyCompleted = 7,
/// <summary>
/// 已完成 - 所有任务都已完成
/// </summary>
Completed = 8,
/// <summary>
/// 已暂停 - 执行被暂停
/// </summary>
Paused = 9,
/// <summary>
/// 已取消 - 整合被取消
/// </summary>
Cancelled = 10,
/// <summary>
/// 已过期 - 超过有效期限
/// </summary>
Expired = 11,
/// <summary>
/// 已归档 - 归档保存
/// </summary>
Archived = 12,
/// <summary>
/// 错误状态 - 出现错误需要处理
/// </summary>
Error = 99
}
}

View File

@ -0,0 +1,721 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Integration
{
/// <summary>
/// 智能整合记录实体
/// 用于记录每次智能任务整合的完整过程和结果
///
/// 业务思考:
/// 1. 作为重要的业务审计数据,需要完整记录整合的全过程
/// 2. 支持多租户模式,确保数据安全隔离
/// 3. 提供丰富的查询维度,支持历史分析和决策支持
/// 4. 考虑JSON存储复杂结果数据平衡存储效率和查询性能
/// </summary>
[Table(Name = "sse_integration_record")]
[Index("idx_integration_batch_code", "IntegrationBatchCode", true)] // 批次编码唯一索引
[Index("idx_integration_time", "IntegrationTime")] // 时间索引,支持时间范围查询
[Index("idx_operator", "OperatorUserId")] // 操作员索引
[Index("idx_tenant_time", "TenantId,IntegrationTime")] // 租户+时间组合索引
public class IntegrationRecordEntity : EntityTenant
{
/// <summary>
/// 整合批次编码
/// 格式INT + yyyyMMddHHmmss + XXXINT20240314143025123
/// 业务意义:唯一标识一次整合操作,便于追踪和关联
/// </summary>
[Column(StringLength = 30)]
[Required(ErrorMessage = "整合批次编码不能为空")]
public string IntegrationBatchCode { get; set; } = string.Empty;
/// <summary>
/// 整合执行时间
/// 记录实际执行整合操作的时间点
/// </summary>
[Required]
public DateTime IntegrationTime { get; set; } = DateTime.Now;
/// <summary>
/// 操作人员用户ID
/// 关联到系统用户表,记录执行整合的操作员
/// </summary>
[Required(ErrorMessage = "操作人员ID不能为空")]
public long OperatorUserId { get; set; }
/// <summary>
/// 操作人员用户名
/// 冗余存储,提高查询性能,避免频繁关联用户表
/// </summary>
[Column(StringLength = 50)]
[Required(ErrorMessage = "操作人员用户名不能为空")]
public string OperatorUserName { get; set; } = string.Empty;
/// <summary>
/// 操作人员真实姓名
/// 用于业务场景下的可读性显示
/// </summary>
[Column(StringLength = 50)]
[Required(ErrorMessage = "操作人员姓名不能为空")]
public string OperatorRealName { get; set; } = string.Empty;
/// <summary>
/// 整合的任务ID列表JSON格式存储
/// 存储格式:[1,2,3,4,5]
/// 业务意义:记录本次整合涉及的所有任务,支持反向查询
/// </summary>
[Column(DbType = "longtext")]
[Required(ErrorMessage = "任务ID列表不能为空")]
public string TaskIdsJson { get; set; } = "[]";
/// <summary>
/// 整合策略配置JSON格式存储
/// 包含:人员分配策略、设备分配策略、各种配置参数
/// 业务价值:记录决策依据,支持策略效果分析和优化
/// </summary>
[Column(DbType = "json")]
[Required]
public string StrategyConfigJson { get; set; } = "{}";
/// <summary>
/// 人员分配结果详情JSON格式存储
/// 包含:成功匹配列表、失败原因、工作负载分析等
/// 存储完整的PersonnelAllocationResult对象
/// </summary>
[Column(DbType = "json")]
public string PersonnelAllocationResultJson { get; set; } = "{}";
/// <summary>
/// 设备分配结果详情JSON格式存储
/// 包含:成功匹配列表、失败原因、利用率分析等
/// 存储完整的EquipmentAllocationResult对象
/// </summary>
[Column(DbType = "json")]
public string EquipmentAllocationResultJson { get; set; } = "{}";
/// <summary>
/// 成功分配的任务数量
/// 统计字段,提高查询性能
/// </summary>
[Required]
public int SuccessTaskCount { get; set; } = 0;
/// <summary>
/// 分配失败的任务数量
/// 统计字段,用于成功率计算和分析
/// </summary>
[Required]
public int FailedTaskCount { get; set; } = 0;
/// <summary>
/// 整合执行总耗时(毫秒)
/// 性能监控指标,用于系统优化分析
/// </summary>
[Required]
public long ElapsedMilliseconds { get; set; } = 0;
/// <summary>
/// 人员分配公平性评分0-100
/// 业务指标,评估人员工作负载分配的公平程度
/// </summary>
public int PersonnelFairnessScore { get; set; } = 0;
/// <summary>
/// 设备整体利用率百分比保留1位小数
/// 业务指标,评估设备资源利用效率
/// </summary>
[Column(DbType = "decimal(5,1)")]
public decimal EquipmentUtilizationRate { get; set; } = 0.0m;
/// <summary>
/// 整合结果摘要描述
/// 简洁的文本描述,便于快速了解整合结果
/// 示例:总任务数: 25, 成功: 23, 失败: 2, 成功率: 92%
/// </summary>
[Column(StringLength = 500)]
public string ResultSummary { get; set; } = string.Empty;
/// <summary>
/// 失败原因分类统计JSON格式存储
/// 格式:{"PersonnelAllocationFailed": 2, "EquipmentAllocationFailed": 1}
/// 业务价值:支持失败原因分析和系统改进
/// </summary>
[Column(DbType = "json")]
public string FailureReasonStats { get; set; } = "{}";
/// <summary>
/// 涉及的项目编号列表(逗号分隔)
/// 便于按项目查询整合历史,支持项目级别的数据分析
/// 示例PRJ001,PRJ002,PRJ003
/// </summary>
[Column(StringLength = 500)]
public string ProjectNumbers { get; set; } = string.Empty;
/// <summary>
/// 整合类型
/// 标识整合的触发方式Manual-手动触发, Scheduled-定时触发, Auto-自动触发
/// </summary>
[Column(StringLength = 20)]
[Required]
public string IntegrationType { get; set; } = "Manual";
/// <summary>
/// 业务备注信息
/// 操作员填写的备注,记录特殊情况或业务背景
/// </summary>
[Column(StringLength = 1000)]
public string Remarks { get; set; } = string.Empty;
/// <summary>
/// 是否为测试数据
/// 区分生产数据和测试数据,便于数据清理和分析
/// </summary>
[Required]
public bool IsTestData { get; set; } = false;
/// <summary>
/// 数据版本号
/// 支持数据结构演进和向后兼容
/// </summary>
[Required]
public int DataVersion { get; set; } = 1;
/// <summary>
/// 整合记录发布状态
/// 控制整合记录的生命周期管理
/// Draft-草稿, Published-已发布, Completed-已完成, Cancelled-已撤销
/// </summary>
[Column(StringLength = 20)]
[Required]
public string PublishStatus { get; set; } = IntegrationRecordPublishStatus.Draft;
/// <summary>
/// 发布时间
/// 记录正式发布生效的时间点
/// </summary>
public DateTime? PublishedTime { get; set; }
/// <summary>
/// 发布操作员用户ID
/// 记录执行发布操作的用户,可能与创建者不同
/// </summary>
public long? PublishedByUserId { get; set; }
/// <summary>
/// 发布操作员用户名
/// </summary>
[Column(StringLength = 50)]
public string PublishedByUserName { get; set; } = string.Empty;
/// <summary>
/// 发布操作员真实姓名
/// </summary>
[Column(StringLength = 50)]
public string PublishedByRealName { get; set; } = string.Empty;
/// <summary>
/// 发布说明
/// 记录发布时的业务说明或特殊情况备注
/// </summary>
[Column(StringLength = 500)]
public string PublishRemarks { get; set; } = string.Empty;
/// <summary>
/// 完成时间
/// 所有任务执行完毕的时间点
/// </summary>
public DateTime? CompletedTime { get; set; }
/// <summary>
/// 撤销时间
/// 记录被撤销的时间点
/// </summary>
public DateTime? CancelledTime { get; set; }
/// <summary>
/// 撤销操作员用户ID
/// </summary>
public long? CancelledByUserId { get; set; }
/// <summary>
/// 撤销操作员用户名
/// </summary>
[Column(StringLength = 50)]
public string CancelledByUserName { get; set; } = string.Empty;
/// <summary>
/// 撤销原因
/// 记录撤销的具体原因和说明
/// </summary>
[Column(StringLength = 500)]
public string CancelReason { get; set; } = string.Empty;
#region
/// <summary>
/// 当前版本号
/// 每次修改后自增,用于版本管理和冲突检测
/// </summary>
[Required]
public int CurrentVersion { get; set; } = 1;
/// <summary>
/// 父版本ID
/// 指向上一个版本的整合记录,构建版本链
/// null表示这是初始版本
/// </summary>
public long? ParentVersionId { get; set; }
/// <summary>
/// 根版本ID
/// 指向版本链的根节点,用于快速定位同一整合记录的所有版本
/// </summary>
[Required]
public long RootVersionId { get; set; }
/// <summary>
/// 版本创建原因
/// 记录为什么创建这个新版本TaskModified-任务修改, ManualAdjustment-手动调整, SystemReallocation-系统重新分配
/// </summary>
[Column(StringLength = 50)]
public string VersionReason { get; set; } = string.Empty;
/// <summary>
/// 变更摘要
/// 简述本版本相对于上一版本的主要变更内容
/// </summary>
[Column(StringLength = 1000)]
public string ChangeSummary { get; set; } = string.Empty;
/// <summary>
/// 变更详情JSON
/// 存储详细的变更信息,包括变更类型、影响的任务、前后对比等
/// 格式:{"changedTasks": [...], "modifications": [...], "affectedPersonnel": [...]}
/// </summary>
[Column(DbType = "json")]
public string ChangeDetailsJson { get; set; } = "{}";
/// <summary>
/// 是否为活跃版本
/// true表示这是当前生效的版本每个根版本只能有一个活跃版本
/// </summary>
[Required]
public bool IsActiveVersion { get; set; } = true;
/// <summary>
/// 变更触发源
/// 记录变更的触发来源TaskChange-任务变更, UserModification-用户修改, SystemOptimization-系统优化
/// </summary>
[Column(StringLength = 30)]
public string ChangeTriggerSource { get; set; } = "Initial";
/// <summary>
/// 原始任务数量
/// 记录初始分配时的任务数量,用于对比分析
/// </summary>
public int OriginalTaskCount { get; set; } = 0;
/// <summary>
/// 变更影响评分
/// 0-100分评估本次变更对整体分配方案的影响程度
/// </summary>
public int ChangeImpactScore { get; set; } = 0;
/// <summary>
/// 自动重新分配标志
/// 标记是否可以自动进行重新分配,还是需要人工干预
/// </summary>
[Required]
public bool AllowAutoReallocation { get; set; } = true;
/// <summary>
/// 上次检查变更时间
/// 用于变更检测和增量更新机制
/// </summary>
public DateTime? LastChangeCheckTime { get; set; }
/// <summary>
/// 快照数据JSON
/// 存储关键业务数据的快照,用于版本对比和回滚
/// 包含:任务分配快照、人员工作负载快照、设备利用率快照等
/// </summary>
[Column(DbType = "json")]
public string SnapshotDataJson { get; set; } = "{}";
#endregion
#region
/// <summary>
/// 整合成功率(计算属性)
/// 返回成功率百分比保留1位小数
/// </summary>
[Navigate(nameof(SuccessTaskCount))]
public decimal SuccessRate
{
get
{
var totalTasks = SuccessTaskCount + FailedTaskCount;
return totalTasks > 0 ? Math.Round((decimal)SuccessTaskCount / totalTasks * 100, 1) : 0;
}
set { } // FreeSql需要set访问器但这是计算属性所以提供空实现
}
/// <summary>
/// 任务总数(计算属性)
/// </summary>
[Navigate(nameof(SuccessTaskCount))]
public int TotalTaskCount
{
get => SuccessTaskCount + FailedTaskCount;
set { } // FreeSql需要set访问器但这是计算属性所以提供空实现
}
/// <summary>
/// 整体匹配成功率(计算属性)
/// </summary>
public decimal OverallMatchSuccessRate => SuccessRate / 100;
/// <summary>
/// 平均任务复杂度(计算属性)
/// </summary>
public decimal AverageTaskComplexity => 2.5m; // 暂时使用固定值
/// <summary>
/// 平均每任务耗时(计算属性)
/// 返回毫秒数,用于性能分析
/// </summary>
[Navigate(nameof(ElapsedMilliseconds))]
public long AverageTimePerTask
{
get
{
var totalTasks = TotalTaskCount;
return totalTasks > 0 ? ElapsedMilliseconds / totalTasks : 0;
}
set { } // FreeSql需要set访问器但这是计算属性所以提供空实现
}
#endregion
#region
/// <summary>
/// 反序列化任务ID列表
/// 将JSON格式的TaskIdsJson转换为List&lt;long&gt;
/// </summary>
public List<long> GetTaskIds()
{
try
{
if (string.IsNullOrWhiteSpace(TaskIdsJson))
return new List<long>();
// 优先尝试JSON反序列化
try
{
return System.Text.Json.JsonSerializer.Deserialize<List<long>>(TaskIdsJson) ?? new List<long>();
}
catch
{
// 兼容旧格式(逗号分隔)
return TaskIdsJson.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(p => p.Trim())
.Where(p => !string.IsNullOrEmpty(p))
.Select(long.Parse)
.ToList();
}
}
catch
{
return new List<long>();
}
}
/// <summary>
/// 设置任务ID列表
/// 将List&lt;long&gt;序列化为JSON存储
/// </summary>
public void SetTaskIds(List<long> taskIds)
{
TaskIdsJson = System.Text.Json.JsonSerializer.Serialize(taskIds ?? new List<long>());
}
/// <summary>
/// 获取项目编号列表
/// 将逗号分隔的项目编号字符串转换为列表
/// </summary>
public List<string> GetProjectNumbers()
{
if (string.IsNullOrWhiteSpace(ProjectNumbers))
return new List<string>();
return ProjectNumbers.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(p => p.Trim())
.Where(p => !string.IsNullOrEmpty(p))
.ToList();
}
/// <summary>
/// 设置项目编号列表
/// 将列表转换为逗号分隔的字符串存储
/// </summary>
public void SetProjectNumbers(List<string> projectNumbers)
{
if (projectNumbers == null || !projectNumbers.Any())
{
ProjectNumbers = string.Empty;
return;
}
ProjectNumbers = string.Join(",", projectNumbers.Where(p => !string.IsNullOrWhiteSpace(p)));
}
/// <summary>
/// 更新统计信息
/// 根据分配结果更新各项统计字段
/// </summary>
public void UpdateStatistics(int successCount, int failedCount, long elapsedMs, int fairnessScore, decimal utilizationRate)
{
SuccessTaskCount = successCount;
FailedTaskCount = failedCount;
ElapsedMilliseconds = elapsedMs;
PersonnelFairnessScore = fairnessScore;
EquipmentUtilizationRate = utilizationRate;
ResultSummary = $"总任务数: {TotalTaskCount}, 成功: {SuccessTaskCount}, 失败: {FailedTaskCount}, 成功率: {SuccessRate}%";
}
#region
/// <summary>
/// 创建新版本
/// 基于当前版本创建一个新的版本记录,用于变更追踪
/// </summary>
/// <param name="reason">版本创建原因</param>
/// <param name="changeSummary">变更摘要</param>
/// <param name="operatorUserId">操作员用户ID</param>
/// <param name="operatorName">操作员姓名</param>
/// <returns>新版本的整合记录实体</returns>
public IntegrationRecordEntity CreateNewVersion(string reason, string changeSummary, long operatorUserId, string operatorName)
{
var newVersion = new IntegrationRecordEntity
{
// 继承基本信息
IntegrationBatchCode = this.IntegrationBatchCode,
TenantId = this.TenantId,
RootVersionId = this.RootVersionId == 0 ? this.Id : this.RootVersionId,
ParentVersionId = this.Id,
CurrentVersion = this.CurrentVersion + 1,
// 版本变更信息
VersionReason = reason,
ChangeSummary = changeSummary,
ChangeTriggerSource = reason,
IsActiveVersion = true, // 新版本为活跃版本
// 操作员信息
OperatorUserId = operatorUserId,
OperatorUserName = operatorName,
OperatorRealName = operatorName,
IntegrationTime = DateTime.Now,
// 继承配置信息
StrategyConfigJson = this.StrategyConfigJson,
IntegrationType = this.IntegrationType,
// 继承发布状态相关信息
PublishStatus = this.PublishStatus,
PublishedTime = this.PublishedTime,
PublishedByUserId = this.PublishedByUserId,
PublishedByUserName = this.PublishedByUserName,
PublishedByRealName = this.PublishedByRealName,
PublishRemarks = this.PublishRemarks,
// 初始化新版本的其他字段
TaskIdsJson = "[]",
PersonnelAllocationResultJson = "{}",
EquipmentAllocationResultJson = "{}",
FailureReasonStats = "{}",
ChangeDetailsJson = "{}",
SnapshotDataJson = "{}",
DataVersion = this.DataVersion,
AllowAutoReallocation = true,
LastChangeCheckTime = DateTime.Now
};
// 当前版本标记为非活跃
this.IsActiveVersion = false;
return newVersion;
}
/// <summary>
/// 获取变更详情
/// 解析ChangeDetailsJson并返回结构化的变更详情
/// </summary>
public IntegrationChangeDetails GetChangeDetails()
{
try
{
if (string.IsNullOrWhiteSpace(ChangeDetailsJson) || ChangeDetailsJson == "{}")
return new IntegrationChangeDetails();
return System.Text.Json.JsonSerializer.Deserialize<IntegrationChangeDetails>(ChangeDetailsJson)
?? new IntegrationChangeDetails();
}
catch
{
return new IntegrationChangeDetails();
}
}
/// <summary>
/// 设置变更详情
/// 将变更详情对象序列化为JSON存储
/// </summary>
public void SetChangeDetails(IntegrationChangeDetails changeDetails)
{
ChangeDetailsJson = System.Text.Json.JsonSerializer.Serialize(changeDetails ?? new IntegrationChangeDetails());
}
/// <summary>
/// 获取快照数据
/// 解析SnapshotDataJson并返回快照数据对象
/// </summary>
public IntegrationSnapshot GetSnapshotData()
{
try
{
if (string.IsNullOrWhiteSpace(SnapshotDataJson) || SnapshotDataJson == "{}")
return new IntegrationSnapshot();
return System.Text.Json.JsonSerializer.Deserialize<IntegrationSnapshot>(SnapshotDataJson)
?? new IntegrationSnapshot();
}
catch
{
return new IntegrationSnapshot();
}
}
/// <summary>
/// 设置快照数据
/// 将快照数据对象序列化为JSON存储
/// </summary>
public void SetSnapshotData(IntegrationSnapshot snapshotData)
{
SnapshotDataJson = System.Text.Json.JsonSerializer.Serialize(snapshotData ?? new IntegrationSnapshot());
}
/// <summary>
/// 计算变更影响评分
/// 基于变更的任务数量、人员影响、设备影响等计算影响评分
/// </summary>
public int CalculateChangeImpactScore(IntegrationChangeDetails changeDetails)
{
if (changeDetails == null) return 0;
int score = 0;
int totalTasks = TotalTaskCount > 0 ? TotalTaskCount : 1;
// 基于变更任务比例计算基础分数 (40%)
var changedTaskRatio = (double)changeDetails.ChangedTaskIds.Count / totalTasks;
score += (int)(changedTaskRatio * 40);
// 基于人员变更数量计算分数 (30%)
var personnelChangeRatio = Math.Min(1.0, (double)changeDetails.AffectedPersonnelIds.Count / 10);
score += (int)(personnelChangeRatio * 30);
// 基于设备变更数量计算分数 (20%)
var equipmentChangeRatio = Math.Min(1.0, (double)changeDetails.AffectedEquipmentIds.Count / 10);
score += (int)(equipmentChangeRatio * 20);
// 基于变更类型的严重程度 (10%)
var severityScore = changeDetails.ChangeTypes.Contains("TaskTimeConflict") ? 10 :
changeDetails.ChangeTypes.Contains("PersonnelUnavailable") ? 8 :
changeDetails.ChangeTypes.Contains("EquipmentUnavailable") ? 6 : 2;
score += severityScore;
return Math.Min(100, Math.Max(0, score));
}
/// <summary>
/// 检查是否需要重新分配
/// 基于变更影响评分和业务规则判断是否需要重新分配
/// </summary>
public bool ShouldTriggerReallocation()
{
// 如果不允许自动重新分配返回false
if (!AllowAutoReallocation) return false;
// 如果变更影响评分超过阈值,需要重新分配
if (ChangeImpactScore >= 30) return true;
// 如果有任务时间冲突,必须重新分配
var changeDetails = GetChangeDetails();
if (changeDetails.ChangeTypes.Contains("TaskTimeConflict")) return true;
// 如果有关键人员不可用,需要重新分配
if (changeDetails.ChangeTypes.Contains("PersonnelUnavailable")) return true;
return false;
}
#endregion
#endregion
}
/// <summary>
/// 整合类型枚举
/// </summary>
public static class IntegrationType
{
/// <summary>
/// 手动触发
/// </summary>
public const string Manual = "Manual";
/// <summary>
/// 定时触发
/// </summary>
public const string Scheduled = "Scheduled";
/// <summary>
/// 自动触发
/// </summary>
public const string Auto = "Auto";
}
/// <summary>
/// 整合记录发布状态枚举
/// 定义整合记录的生命周期状态
/// </summary>
public static class IntegrationRecordPublishStatus
{
/// <summary>
/// 草稿状态 - 刚生成的整合记录,未正式生效
/// </summary>
public const string Draft = "Draft";
/// <summary>
/// 已发布状态 - 已发布生效,任务开始执行
/// </summary>
public const string Published = "Published";
/// <summary>
/// 已完成状态 - 所有任务执行完毕
/// </summary>
public const string Completed = "Completed";
/// <summary>
/// 已撤销状态 - 发布后被撤销
/// </summary>
public const string Cancelled = "Cancelled";
}
}

View File

@ -0,0 +1,209 @@
using System;
using System.Collections.Generic;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Integration;
/// <summary>
/// 整合记录快照数据
/// 用于记录整合记录在特定时刻的完整状态
///
/// 业务价值:
/// 1. 状态追踪:记录整合记录在关键时刻的完整状态
/// 2. 变更对比:支持前后状态的对比分析
/// 3. 回滚支持:为状态回滚提供数据基础
/// 4. 审计完整:提供完整的状态变更审计信息
/// </summary>
public class IntegrationSnapshot
{
/// <summary>
/// 快照时间
/// </summary>
public DateTime SnapshotTime { get; set; } = DateTime.Now;
/// <summary>
/// 快照类型
/// </summary>
public string SnapshotType { get; set; } = string.Empty;
/// <summary>
/// 整合记录状态
/// </summary>
public string RecordStatus { get; set; } = string.Empty;
/// <summary>
/// 任务状态快照
/// 记录所有相关任务在快照时刻的状态
/// </summary>
public List<TaskStatusSnapshot> TaskStatusSnapshots { get; set; } = new();
/// <summary>
/// 人员分配快照
/// 记录人员分配在快照时刻的状态
/// </summary>
public List<PersonnelAssignmentSnapshot> PersonnelAssignmentSnapshots { get; set; } = new();
/// <summary>
/// 设备分配快照
/// 记录设备分配在快照时刻的状态
/// </summary>
public List<EquipmentAssignmentSnapshot> EquipmentAssignmentSnapshots { get; set; } = new();
/// <summary>
/// 统计信息快照
/// </summary>
public StatisticsSnapshot StatisticsSnapshot { get; set; } = new();
/// <summary>
/// 备注信息
/// </summary>
public string Remarks { get; set; } = string.Empty;
}
/// <summary>
/// 任务状态快照
/// </summary>
public class TaskStatusSnapshot
{
/// <summary>
/// 任务ID
/// </summary>
public long TaskId { get; set; }
/// <summary>
/// 任务代码
/// </summary>
public string TaskCode { get; set; } = string.Empty;
/// <summary>
/// 任务状态
/// </summary>
public string Status { get; set; } = string.Empty;
/// <summary>
/// 分配的人员ID
/// </summary>
public long? AssignedPersonnelId { get; set; }
/// <summary>
/// 分配的人员姓名
/// </summary>
public string AssignedPersonnelName { get; set; } = string.Empty;
/// <summary>
/// 分配的设备ID
/// </summary>
public long? AssignedEquipmentId { get; set; }
/// <summary>
/// 分配的设备名称
/// </summary>
public string AssignedEquipmentName { get; set; } = string.Empty;
/// <summary>
/// 快照时间
/// </summary>
public DateTime SnapshotTime { get; set; }
}
/// <summary>
/// 人员分配快照
/// </summary>
public class PersonnelAssignmentSnapshot
{
/// <summary>
/// 人员ID
/// </summary>
public long PersonnelId { get; set; }
/// <summary>
/// 人员姓名
/// </summary>
public string PersonnelName { get; set; } = string.Empty;
/// <summary>
/// 分配的任务ID列表
/// </summary>
public List<long> AssignedTaskIds { get; set; } = new();
/// <summary>
/// 工作负载百分比
/// </summary>
public decimal WorkloadPercentage { get; set; }
/// <summary>
/// 快照时间
/// </summary>
public DateTime SnapshotTime { get; set; }
}
/// <summary>
/// 设备分配快照
/// </summary>
public class EquipmentAssignmentSnapshot
{
/// <summary>
/// 设备ID
/// </summary>
public long EquipmentId { get; set; }
/// <summary>
/// 设备名称
/// </summary>
public string EquipmentName { get; set; } = string.Empty;
/// <summary>
/// 分配的任务ID列表
/// </summary>
public List<long> AssignedTaskIds { get; set; } = new();
/// <summary>
/// 利用率百分比
/// </summary>
public decimal UtilizationRate { get; set; }
/// <summary>
/// 快照时间
/// </summary>
public DateTime SnapshotTime { get; set; }
}
/// <summary>
/// 统计信息快照
/// </summary>
public class StatisticsSnapshot
{
/// <summary>
/// 总任务数
/// </summary>
public int TotalTaskCount { get; set; }
/// <summary>
/// 成功任务数
/// </summary>
public int SuccessTaskCount { get; set; }
/// <summary>
/// 失败任务数
/// </summary>
public int FailedTaskCount { get; set; }
/// <summary>
/// 成功率
/// </summary>
public decimal SuccessRate { get; set; }
/// <summary>
/// 人员公平性评分
/// </summary>
public int PersonnelFairnessScore { get; set; }
/// <summary>
/// 设备利用率
/// </summary>
public decimal EquipmentUtilizationRate { get; set; }
/// <summary>
/// 快照时间
/// </summary>
public DateTime SnapshotTime { get; set; }
}

View File

@ -0,0 +1,586 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Integration
{
/// <summary>
/// 任务变更事件实体
/// 记录任务变更事件,用于变更感知和自动触发机制
///
/// 业务思考:
/// 1. 事件驱动架构:基于事件的变更检测和处理机制
/// 2. 变更溯源:完整记录变更的前因后果和处理过程
/// 3. 批量处理:支持批量变更事件的聚合处理
/// 4. 性能优化:通过事件队列机制避免实时处理对系统性能的影响
/// </summary>
[Table(Name = "sse_task_change_event")]
[Index("idx_task_id", "TaskId")] // 任务ID索引
[Index("idx_integration_record", "IntegrationRecordId")] // 整合记录索引
[Index("idx_event_time", "EventTime")] // 事件时间索引
[Index("idx_processing_status", "ProcessingStatus")] // 处理状态索引
[Index("idx_tenant_time", "TenantId,EventTime")] // 租户+时间组合索引
public class TaskChangeEventEntity : EntityTenant
{
/// <summary>
/// 任务ID
/// 发生变更的任务ID
/// </summary>
[Required]
public long TaskId { get; set; }
/// <summary>
/// 任务代码
/// 冗余存储,提高查询性能
/// </summary>
[Column(StringLength = 50)]
[Required]
public string TaskCode { get; set; } = string.Empty;
/// <summary>
/// 关联的整合记录ID
/// 指向受影响的整合记录
/// </summary>
public long? IntegrationRecordId { get; set; }
/// <summary>
/// 根版本整合记录ID
/// 指向版本链的根节点,用于快速定位整个版本链
/// </summary>
public long? RootIntegrationRecordId { get; set; }
/// <summary>
/// 事件类型
/// TaskModified, TaskDeleted, TaskStatusChanged, TaskPriorityChanged,
/// TaskTimeChanged, TaskPersonnelChanged, TaskEquipmentChanged, TaskCompleted
/// </summary>
[Column(StringLength = 50)]
[Required]
public string EventType { get; set; } = string.Empty;
/// <summary>
/// 变更字段名称
/// 具体发生变更的字段名,多个字段用逗号分隔
/// </summary>
[Column(StringLength = 200)]
public string ChangedFields { get; set; } = string.Empty;
/// <summary>
/// 变更前的值JSON格式
/// 存储变更前的字段值快照
/// </summary>
[Column(DbType = "json")]
public string BeforeValueJson { get; set; } = "{}";
/// <summary>
/// 变更后的值JSON格式
/// 存储变更后的字段值快照
/// </summary>
[Column(DbType = "json")]
public string AfterValueJson { get; set; } = "{}";
/// <summary>
/// 事件发生时间
/// 任务实际发生变更的时间
/// </summary>
[Required]
public DateTime EventTime { get; set; } = DateTime.Now;
/// <summary>
/// 变更触发用户ID
/// 执行变更操作的用户ID
/// </summary>
public long? TriggeredByUserId { get; set; }
/// <summary>
/// 变更触发用户名
/// </summary>
[Column(StringLength = 50)]
public string TriggeredByUserName { get; set; } = string.Empty;
/// <summary>
/// 变更触发用户真实姓名
/// </summary>
[Column(StringLength = 50)]
public string TriggeredByRealName { get; set; } = string.Empty;
/// <summary>
/// 事件来源
/// Manual-手动操作, System-系统自动, Import-数据导入, API-API调用, Sync-同步操作
/// </summary>
[Column(StringLength = 20)]
[Required]
public string EventSource { get; set; } = "Manual";
/// <summary>
/// 事件优先级
/// 1-99为最高优先级影响处理顺序
/// </summary>
[Required]
public int EventPriority { get; set; } = 5;
/// <summary>
/// 影响评估评分
/// 0-100分评估该变更对整合记录的潜在影响
/// </summary>
public int ImpactAssessmentScore { get; set; } = 0;
/// <summary>
/// 处理状态
/// Pending-待处理, Processing-处理中, Completed-已完成, Failed-处理失败, Ignored-已忽略
/// </summary>
[Column(StringLength = 20)]
[Required]
public string ProcessingStatus { get; set; } = "Pending";
/// <summary>
/// 处理开始时间
/// </summary>
public DateTime? ProcessingStartTime { get; set; }
/// <summary>
/// 处理完成时间
/// </summary>
public DateTime? ProcessingCompletedTime { get; set; }
/// <summary>
/// 处理人员用户ID
/// 实际处理该事件的用户ID
/// </summary>
public long? ProcessedByUserId { get; set; }
/// <summary>
/// 处理人员用户名
/// </summary>
[Column(StringLength = 50)]
public string ProcessedByUserName { get; set; } = string.Empty;
/// <summary>
/// 处理结果摘要
/// 简述处理结果和采取的行动
/// </summary>
[Column(StringLength = 500)]
public string ProcessingResultSummary { get; set; } = string.Empty;
/// <summary>
/// 处理详情JSON
/// 存储详细的处理过程和结果信息
/// </summary>
[Column(DbType = "json")]
public string ProcessingDetailsJson { get; set; } = "{}";
/// <summary>
/// 是否触发了重新分配
/// </summary>
[Required]
public bool TriggeredReallocation { get; set; } = false;
/// <summary>
/// 创建的新版本ID
/// 如果该事件导致创建了新版本
/// </summary>
public long? CreatedNewVersionId { get; set; }
/// <summary>
/// 事件分组ID
/// 用于将相关的多个事件分组处理,如批量修改
/// </summary>
public long? EventGroupId { get; set; }
/// <summary>
/// 事件分组序号
/// 在同一分组内的事件序号
/// </summary>
public int EventGroupSequence { get; set; } = 1;
/// <summary>
/// 是否需要通知
/// 标记该事件是否需要发送通知给相关人员
/// </summary>
[Required]
public bool RequiresNotification { get; set; } = true;
/// <summary>
/// 通知状态
/// NotSent-未发送, Sent-已发送, Failed-发送失败, NotRequired-无需发送
/// </summary>
[Column(StringLength = 20)]
[Required]
public string NotificationStatus { get; set; } = "NotSent";
/// <summary>
/// 通知发送时间
/// </summary>
public DateTime? NotificationSentTime { get; set; }
/// <summary>
/// 重试次数
/// 处理失败后的重试次数
/// </summary>
[Required]
public int RetryCount { get; set; } = 0;
/// <summary>
/// 最大重试次数
/// </summary>
[Required]
public int MaxRetryCount { get; set; } = 3;
/// <summary>
/// 下次重试时间
/// </summary>
public DateTime? NextRetryTime { get; set; }
/// <summary>
/// 错误信息
/// 记录处理过程中的错误信息
/// </summary>
[Column(StringLength = 1000)]
public string ErrorMessage { get; set; } = string.Empty;
/// <summary>
/// 事件标签
/// 用于事件分类和筛选,多个标签用逗号分隔
/// </summary>
[Column(StringLength = 200)]
public string EventTags { get; set; } = string.Empty;
/// <summary>
/// 业务备注
/// </summary>
[Column(StringLength = 500)]
public string Remarks { get; set; } = string.Empty;
/// <summary>
/// 是否为测试事件
/// </summary>
[Required]
public bool IsTestEvent { get; set; } = false;
/// <summary>
/// 数据版本
/// </summary>
[Required]
public int DataVersion { get; set; } = 1;
#region
/// <summary>
/// 处理耗时(毫秒)
/// </summary>
[Navigate(nameof(ProcessingStartTime))]
public long ProcessingElapsedMilliseconds
{
get
{
if (ProcessingStartTime.HasValue && ProcessingCompletedTime.HasValue)
{
return (long)(ProcessingCompletedTime.Value - ProcessingStartTime.Value).TotalMilliseconds;
}
return 0;
}
set { } // FreeSql需要set访问器但这是计算属性所以提供空实现
}
/// <summary>
/// 事件年龄(自事件发生到现在的分钟数)
/// </summary>
[Navigate(nameof(EventTime))]
public int EventAgeMinutes
{
get
{
return (int)(DateTime.Now - EventTime).TotalMinutes;
}
set { } // FreeSql需要set访问器但这是计算属性所以提供空实现
}
/// <summary>
/// 是否超时
/// 判断事件是否长时间未处理
/// </summary>
[Navigate(nameof(EventTime))]
public bool IsOverdue
{
get
{
if (ProcessingStatus == "Completed" || ProcessingStatus == "Ignored")
return false;
var timeoutMinutes = EventPriority >= 8 ? 30 : EventPriority >= 5 ? 120 : 480; // 高优先级30分钟中等2小时低优先级8小时
return EventAgeMinutes > timeoutMinutes;
}
set { } // FreeSql需要set访问器但这是计算属性所以提供空实现
}
#endregion
#region
/// <summary>
/// 获取变更前的值
/// 将JSON反序列化为字典
/// </summary>
public Dictionary<string, object> GetBeforeValues()
{
try
{
if (string.IsNullOrWhiteSpace(BeforeValueJson) || BeforeValueJson == "{}")
return new Dictionary<string, object>();
return System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(BeforeValueJson)
?? new Dictionary<string, object>();
}
catch
{
return new Dictionary<string, object>();
}
}
/// <summary>
/// 获取变更后的值
/// 将JSON反序列化为字典
/// </summary>
public Dictionary<string, object> GetAfterValues()
{
try
{
if (string.IsNullOrWhiteSpace(AfterValueJson) || AfterValueJson == "{}")
return new Dictionary<string, object>();
return System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(AfterValueJson)
?? new Dictionary<string, object>();
}
catch
{
return new Dictionary<string, object>();
}
}
/// <summary>
/// 设置变更前的值
/// </summary>
public void SetBeforeValues(Dictionary<string, object> values)
{
BeforeValueJson = System.Text.Json.JsonSerializer.Serialize(values ?? new Dictionary<string, object>());
}
/// <summary>
/// 设置变更后的值
/// </summary>
public void SetAfterValues(Dictionary<string, object> values)
{
AfterValueJson = System.Text.Json.JsonSerializer.Serialize(values ?? new Dictionary<string, object>());
}
/// <summary>
/// 获取处理详情
/// </summary>
public Dictionary<string, object> GetProcessingDetails()
{
try
{
if (string.IsNullOrWhiteSpace(ProcessingDetailsJson) || ProcessingDetailsJson == "{}")
return new Dictionary<string, object>();
return System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(ProcessingDetailsJson)
?? new Dictionary<string, object>();
}
catch
{
return new Dictionary<string, object>();
}
}
/// <summary>
/// 设置处理详情
/// </summary>
public void SetProcessingDetails(Dictionary<string, object> details)
{
ProcessingDetailsJson = System.Text.Json.JsonSerializer.Serialize(details ?? new Dictionary<string, object>());
}
/// <summary>
/// 开始处理事件
/// 设置处理开始时间和状态
/// </summary>
public void StartProcessing(long processedByUserId, string processedByUserName)
{
ProcessingStatus = "Processing";
ProcessingStartTime = DateTime.Now;
ProcessedByUserId = processedByUserId;
ProcessedByUserName = processedByUserName;
}
/// <summary>
/// 完成处理事件
/// 设置处理完成时间和状态
/// </summary>
public void CompleteProcessing(string resultSummary, bool triggeredReallocation = false, long? createdVersionId = null)
{
ProcessingStatus = "Completed";
ProcessingCompletedTime = DateTime.Now;
ProcessingResultSummary = resultSummary;
TriggeredReallocation = triggeredReallocation;
CreatedNewVersionId = createdVersionId;
}
/// <summary>
/// 处理失败
/// 设置失败状态和错误信息
/// </summary>
public void FailProcessing(string errorMessage)
{
ProcessingStatus = "Failed";
ProcessingCompletedTime = DateTime.Now;
ErrorMessage = errorMessage;
RetryCount++;
// 计算下次重试时间(指数退避)
if (RetryCount <= MaxRetryCount)
{
var delayMinutes = Math.Pow(2, RetryCount) * 5; // 5, 10, 20 分钟
NextRetryTime = DateTime.Now.AddMinutes(delayMinutes);
ProcessingStatus = "Pending"; // 重置为待处理状态以便重试
}
}
/// <summary>
/// 忽略事件
/// 设置忽略状态,不再处理
/// </summary>
public void IgnoreEvent(string reason)
{
ProcessingStatus = "Ignored";
ProcessingCompletedTime = DateTime.Now;
ProcessingResultSummary = $"事件已忽略: {reason}";
}
/// <summary>
/// 判断是否可以重试
/// </summary>
public bool CanRetry()
{
return ProcessingStatus == "Pending" &&
RetryCount < MaxRetryCount &&
(!NextRetryTime.HasValue || NextRetryTime.Value <= DateTime.Now);
}
/// <summary>
/// 计算影响评估评分
/// 基于变更类型、字段和业务规则计算影响评分
/// </summary>
public int CalculateImpactScore()
{
int score = 0;
// 基于事件类型的基础分数
score += EventType switch
{
"TaskDeleted" => 90,
"TaskStatusChanged" => 80,
"TaskTimeChanged" => 70,
"TaskPriorityChanged" => 60,
"TaskPersonnelChanged" => 75,
"TaskEquipmentChanged" => 75,
"TaskModified" => 50,
"TaskCompleted" => 30,
_ => 20
};
// 基于变更字段的影响调整
if (ChangedFields.Contains("WorkOrderDate")) score += 20;
if (ChangedFields.Contains("ShiftId")) score += 15;
if (ChangedFields.Contains("Priority")) score += 10;
if (ChangedFields.Contains("AssignedPersonnelId")) score += 15;
if (ChangedFields.Contains("AssignedEquipmentId")) score += 15;
if (ChangedFields.Contains("Status")) score += 25;
// 基于事件优先级调整
score += EventPriority * 2;
return Math.Min(100, Math.Max(0, score));
}
#endregion
}
/// <summary>
/// 事件处理状态枚举
/// </summary>
public static class TaskChangeEventProcessingStatus
{
/// <summary>
/// 待处理
/// </summary>
public const string Pending = "Pending";
/// <summary>
/// 处理中
/// </summary>
public const string Processing = "Processing";
/// <summary>
/// 已完成
/// </summary>
public const string Completed = "Completed";
/// <summary>
/// 处理失败
/// </summary>
public const string Failed = "Failed";
/// <summary>
/// 已忽略
/// </summary>
public const string Ignored = "Ignored";
}
/// <summary>
/// 事件类型枚举
/// </summary>
public static class TaskChangeEventType
{
/// <summary>
/// 任务修改
/// </summary>
public const string TaskModified = "TaskModified";
/// <summary>
/// 任务删除
/// </summary>
public const string TaskDeleted = "TaskDeleted";
/// <summary>
/// 任务状态变更
/// </summary>
public const string TaskStatusChanged = "TaskStatusChanged";
/// <summary>
/// 任务优先级变更
/// </summary>
public const string TaskPriorityChanged = "TaskPriorityChanged";
/// <summary>
/// 任务时间变更
/// </summary>
public const string TaskTimeChanged = "TaskTimeChanged";
/// <summary>
/// 任务人员变更
/// </summary>
public const string TaskPersonnelChanged = "TaskPersonnelChanged";
/// <summary>
/// 任务设备变更
/// </summary>
public const string TaskEquipmentChanged = "TaskEquipmentChanged";
/// <summary>
/// 任务完成
/// </summary>
public const string TaskCompleted = "TaskCompleted";
}
}

View File

@ -0,0 +1,19 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using NPP.SmartSchedue.Api.Contracts.Domain.Personnel;
using ZhonTai.Admin.Core.Repositories;
namespace NPP.SmartSchedue.Api.Contracts;
/// <summary>
/// 人员资质绑定仓储接口
/// </summary>
public interface IPersonnelQualificationRepository : IRepositoryBase<PersonnelQualificationEntity>
{
/// <summary>
/// 根据工序ID获取符合资质要求的人员
/// </summary>
/// <param name="processId">工序ID</param>
/// <returns>符合资质的人员列表</returns>
Task<List<PersonnelQualificationEntity>> GetQualifiedPersonnelByProcessAsync(long processId);
}

View File

@ -0,0 +1,11 @@
using NPP.SmartSchedue.Api.Contracts.Domain.Personnel;
using ZhonTai.Admin.Core.Repositories;
namespace NPP.SmartSchedue.Api.Contracts;
/// <summary>
/// 人员工作限制仓储接口
/// </summary>
public interface IPersonnelWorkLimitRepository : IRepositoryBase<PersonnelWorkLimitEntity>
{
}

View File

@ -0,0 +1,11 @@
using NPP.SmartSchedue.Api.Contracts.Domain.Personnel;
using ZhonTai.Admin.Core.Repositories;
namespace NPP.SmartSchedue.Api.Contracts;
/// <summary>
/// 资质仓储接口
/// </summary>
public interface IQualificationRepository : IRepositoryBase<QualificationEntity>
{
}

View File

@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
using NPP.SmartSchedue.Api.Contracts.Core.Consts;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Personnel;
/// <summary>
/// 人员实体
/// </summary>
[Table(Name = DbConsts.TableNamePrefix + "personnel")]
public partial class PersonnelEntity : EntityBase
{
/// <summary>
/// 人员编号
/// </summary>
[Column(StringLength = 50)]
public string PersonnelCode { get; set; } = "";
/// <summary>
/// 人员姓名
/// </summary>
[Column(StringLength = 100)]
public string PersonnelName { get; set; } = "";
/// <summary>
/// 部门ID
/// </summary>
public long? DepartmentId { get; set; }
/// <summary>
/// 部门名称
/// </summary>
[Column(StringLength = 100)]
public string DepartmentName { get; set; } = "";
/// <summary>
/// 职位
/// </summary>
[Column(StringLength = 100)]
public string Position { get; set; } = "";
/// <summary>
/// 是否激活
/// </summary>
public bool IsActive { get; set; } = true;
/// <summary>
/// 联系方式
/// </summary>
[Column(StringLength = 100)]
public string Contact { get; set; } = "";
/// <summary>
/// 备注
/// </summary>
[Column(StringLength = 500)]
public string Remarks { get; set; } = "";
/// <summary>
/// 人员资质列表
/// </summary>
[Navigate("PersonnelId")]
public List<PersonnelQualificationEntity> PersonnelQualifications { get; set; } = new List<PersonnelQualificationEntity>();
/// <summary>
/// 人员工作限制列表
/// </summary>
[Navigate("PersonnelId")]
public List<PersonnelWorkLimitEntity> WorkLimitations { get; set; } = new List<PersonnelWorkLimitEntity>();
}

View File

@ -0,0 +1,58 @@
using System;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
using NPP.SmartSchedue.Api.Contracts.Core.Consts;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Personnel;
/// <summary>
/// 人员资质绑定
/// </summary>
[Table(Name = DbConsts.TableNamePrefix + "personnel_qualification")]
public partial class PersonnelQualificationEntity : EntityTenant
{
/// <summary>
/// 人员ID
/// </summary>
public long PersonnelId { get; set; }
/// <summary>
/// 人员姓名
/// </summary>
public string PersonnelName { get; set; }
/// <summary>
/// 人员工号
/// </summary>
public string PersonnelCode { get; set; }
/// <summary>
/// 资质ID
/// </summary>
public long QualificationId { get; set; }
/// <summary>
/// 资质等级
/// </summary>
public string QualificationLevel { get; set; }
/// <summary>
/// 有效期(截止日期)
/// </summary>
public DateTime? ExpiryDate { get; set; }
/// <summary>
/// 有效期预警天数
/// </summary>
public int? ExpiryWarningDays { get; set; }
/// <summary>
/// 续期日期
/// </summary>
public DateTime? RenewalDate { get; set; }
/// <summary>
/// 绑定状态
/// </summary>
public bool IsActive { get; set; } = true;
}

View File

@ -0,0 +1,34 @@
using System;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
using NPP.SmartSchedue.Api.Contracts.Core.Consts;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Personnel;
/// <summary>
/// 人员工作限制
/// </summary>
[Table(Name = DbConsts.TableNamePrefix + "personnel_work_limit")]
public partial class PersonnelWorkLimitEntity : EntityTenant
{
/// <summary>
/// 人员ID
/// </summary>
public long PersonnelId { get; set; }
/// <summary>
/// 连续工作日限制
/// </summary>
public int? MaxContinuousWorkDays { get; set; }
/// <summary>
/// 当周最大排班次数
/// </summary>
public int? MaxShiftsPerWeek { get; set; }
/// <summary>
/// 特殊限制规则
/// </summary>
[Column(StringLength = 200)]
public string SpecialRule { get; set; }
}

View File

@ -0,0 +1,31 @@
using System;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
using NPP.SmartSchedue.Api.Contracts.Core.Consts;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Personnel;
/// <summary>
/// 资质实体
/// </summary>
[Table(Name = DbConsts.TableNamePrefix + "qualification")]
public partial class QualificationEntity : EntityTenant
{
/// <summary>
/// 名称
/// </summary>
[Column(StringLength = 100)]
public string Name { get; set; }
/// <summary>
/// 描述
/// </summary>
[Column(StringLength = 500)]
public string Description { get; set; }
/// <summary>
/// 等级
/// </summary>
[Column(StringLength = 50)]
public string Level { get; set; }
}

View File

@ -0,0 +1,35 @@
using System;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
using NPP.SmartSchedue.Api.Contracts.Core.Consts;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Time;
/// <summary>
/// 基础日历
/// </summary>
[Table(Name = DbConsts.TableNamePrefix + "calendar")]
public partial class CalendarEntity : EntityTenant
{
/// <summary>
/// 日期
/// </summary>
public DateTime Date { get; set; }
/// <summary>
/// 日期类型
/// </summary>
[Column(StringLength = 50)]
public string DateType { get; set; }
/// <summary>
/// 是否工作日
/// </summary>
public bool IsWorkDay { get; set; } = true;
/// <summary>
/// 特殊日期说明
/// </summary>
[Column(StringLength = 200)]
public string Description { get; set; }
}

View File

@ -0,0 +1,89 @@
using System;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
using NPP.SmartSchedue.Api.Contracts.Core.Consts;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Time;
/// <summary>
/// 员工休假
/// </summary>
[Table(Name = DbConsts.TableNamePrefix + "employee_leave")]
public partial class EmployeeLeaveEntity : EntityTenant
{
/// <summary>
/// 员工ID
/// </summary>
public long EmployeeId { get; set; }
/// <summary>
/// 人员ID (与PersonnelId对应)
/// </summary>
public long PersonnelId
{
get => EmployeeId;
set => EmployeeId = value;
}
/// <summary>
/// 休假类型
/// </summary>
[Column(StringLength = 50)]
public string LeaveType { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public DateTime StartTime { get; set; }
/// <summary>
/// 结束时间
/// </summary>
public DateTime EndTime { get; set; }
/// <summary>
/// 开始日期 (与StartTime对应)
/// </summary>
public DateTime StartDate
{
get => StartTime.Date;
set => StartTime = value;
}
/// <summary>
/// 结束日期 (与EndTime对应)
/// </summary>
public DateTime EndDate
{
get => EndTime.Date;
set => EndTime = value;
}
/// <summary>
/// 休假状态
/// </summary>
[Column(StringLength = 20)]
public string Status { get; set; }
/// <summary>
/// 申请原因
/// </summary>
[Column(StringLength = 500)]
public string Reason { get; set; }
/// <summary>
/// 审批人ID
/// </summary>
public long? ApproverId { get; set; }
/// <summary>
/// 审批时间
/// </summary>
public DateTime? ApprovalTime { get; set; }
/// <summary>
/// 审批意见
/// </summary>
[Column(StringLength = 200)]
public string ApprovalComment { get; set; }
}

View File

@ -0,0 +1,11 @@
using NPP.SmartSchedue.Api.Contracts.Domain.Time;
using ZhonTai.Admin.Core.Repositories;
namespace NPP.SmartSchedue.Api.Contracts;
/// <summary>
/// 基础日历仓储接口
/// </summary>
public interface ICalendarRepository : IRepositoryBase<CalendarEntity>
{
}

View File

@ -0,0 +1,11 @@
using NPP.SmartSchedue.Api.Contracts.Domain.Time;
using ZhonTai.Admin.Core.Repositories;
namespace NPP.SmartSchedue.Api.Contracts;
/// <summary>
/// 员工休假仓储接口
/// </summary>
public interface IEmployeeLeaveRepository : IRepositoryBase<EmployeeLeaveEntity>
{
}

View File

@ -0,0 +1,11 @@
using NPP.SmartSchedue.Api.Contracts.Domain.Time;
using ZhonTai.Admin.Core.Repositories;
namespace NPP.SmartSchedue.Api.Contracts;
/// <summary>
/// 人员班次分配仓储接口
/// </summary>
public interface IPersonnelShiftAssignmentRepository : IRepositoryBase<PersonnelShiftAssignmentEntity>
{
}

View File

@ -0,0 +1,11 @@
using NPP.SmartSchedue.Api.Contracts.Domain.Time;
using ZhonTai.Admin.Core.Repositories;
namespace NPP.SmartSchedue.Api.Contracts;
/// <summary>
/// 生产班次仓储接口
/// </summary>
public interface IShiftRepository : IRepositoryBase<ShiftEntity>
{
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using NPP.SmartSchedue.Api.Contracts.Domain.Time;
using ZhonTai.Admin.Core.Repositories;
namespace NPP.SmartSchedue.Api.Contracts;
/// <summary>
/// 班次规则关联仓储接口
/// </summary>
public interface IShiftRuleMappingRepository : IRepositoryBase<ShiftRuleMappingEntity>
{
/// <summary>
/// 根据班次ID获取有效的班次规则列表
/// 深度业务思考:通过映射表关联,获取班次对应的所有有效规则
/// </summary>
/// <param name="shiftId">班次ID</param>
/// <param name="targetDate">目标日期(用于生效时间判断)</param>
/// <returns>有效的班次规则列表</returns>
Task<List<ShiftRuleEntity>> GetEffectiveShiftRulesAsync(long shiftId, DateTime? targetDate = null);
/// <summary>
/// 批量获取多个班次的规则映射
/// 深度业务思考批量查询优化避免N+1查询问题
/// </summary>
/// <param name="shiftIds">班次ID列表</param>
/// <param name="targetDate">目标日期(用于生效时间判断)</param>
/// <returns>班次ID到规则列表的映射</returns>
Task<Dictionary<long, List<ShiftRuleEntity>>> GetBatchShiftRulesAsync(List<long> shiftIds, DateTime? targetDate = null);
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using NPP.SmartSchedue.Api.Contracts.Domain.Time;
using ZhonTai.Admin.Core.Repositories;
namespace NPP.SmartSchedue.Api.Contracts;
/// <summary>
/// 班次规则仓储接口
/// </summary>
public interface IShiftRuleRepository : IRepositoryBase<ShiftRuleEntity>
{
/// <summary>
/// 获取适用于特定人员、日期和班次的排班规则
/// </summary>
/// <param name="personnelId">人员ID</param>
/// <param name="targetDate">目标日期</param>
/// <param name="shiftId">班次ID可选</param>
/// <returns>适用的排班规则列表</returns>
Task<List<ShiftRuleEntity>> GetApplicableRulesAsync(long personnelId, DateTime targetDate, long? shiftId);
}

View File

@ -0,0 +1,67 @@
using System;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
using NPP.SmartSchedue.Api.Contracts.Core.Consts;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Time;
/// <summary>
/// 人员班次分配
/// </summary>
[Table(Name = DbConsts.TableNamePrefix + "personnel_shift_assignment")]
public partial class PersonnelShiftAssignmentEntity : EntityTenant
{
/// <summary>
/// 人员ID
/// </summary>
public long PersonnelId { get; set; }
/// <summary>
/// 班次ID
/// </summary>
public long ShiftId { get; set; }
/// <summary>
/// 分配日期
/// </summary>
public DateTime AssignmentDate { get; set; }
/// <summary>
/// 分配类型 (指定/自动)
/// </summary>
[Column(StringLength = 20)]
public string AssignmentType { get; set; }
/// <summary>
/// 分配原因
/// </summary>
[Column(StringLength = 200)]
public string AssignmentReason { get; set; }
/// <summary>
/// 分配状态
/// </summary>
[Column(StringLength = 20)]
public string Status { get; set; }
/// <summary>
/// 是否违反规则
/// </summary>
public bool IsRuleViolation { get; set; } = false;
/// <summary>
/// 违反规则描述
/// </summary>
[Column(StringLength = 500)]
public string ViolationDescription { get; set; }
/// <summary>
/// 年度累计班次数
/// </summary>
public int YearlyShiftCount { get; set; } = 0;
/// <summary>
/// 周累计班次数
/// </summary>
public int WeeklyShiftCount { get; set; } = 0;
}

View File

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
using NPP.SmartSchedue.Api.Contracts.Core.Consts;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Time;
/// <summary>
/// 生产班次
/// </summary>
[Table(Name = DbConsts.TableNamePrefix + "shift")]
[Index("ix_shift_shiftnumber_enabled", nameof(ShiftNumber))]
[Index("ix_shift_starttime_endtime", nameof(StartTime))]
public partial class ShiftEntity : EntityTenant
{
/// <summary>
/// 班次名称
/// </summary>
[Column(StringLength = 100)]
public string Name { get; set; }
public int ShiftNumber { get; set; }
/// <summary>
/// 班次开始时间
/// </summary>
public TimeSpan StartTime { get; set; }
/// <summary>
/// 班次结束时间
/// </summary>
public TimeSpan EndTime { get; set; }
public bool IsEnabled { get; set; } = true;
/// <summary>
/// 班次描述
/// </summary>
[Column(StringLength = 200)]
public string Description { get; set; }
/// <summary>
/// 班次后强制休息天数 (默认值,可被规则覆盖)
/// </summary>
public int RestDaysAfterShift { get; set; } = 1;
/// <summary>
/// 是否允许连续排班 (默认值,可被规则覆盖)
/// </summary>
public bool AllowConsecutive { get; set; } = false;
/// <summary>
/// 班次优先级权重
/// </summary>
public int PriorityWeight { get; set; } = 1;
}

View File

@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
using NPP.SmartSchedue.Api.Contracts.Core.Consts;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Time;
/// <summary>
/// 班次规则配置
/// </summary>
[Table(Name = DbConsts.TableNamePrefix + "shift_rule")]
[Index("ix_shiftrule_type_enabled", nameof(RuleType))]
[Index("ix_shiftrule_effective_time", nameof(EffectiveStartTime))]
public partial class ShiftRuleEntity : EntityTenant
{
/// <summary>
/// 规则名称
/// </summary>
[Column(StringLength = 100)]
public string RuleName { get; set; }
/// <summary>
/// 规则类型
/// </summary>
[Column(StringLength = 50)]
public string RuleType { get; set; }
/// <summary>
/// 规则描述
/// </summary>
[Column(StringLength = 500)]
public string Description { get; set; }
/// <summary>
/// 是否启用
/// </summary>
public bool IsEnabled { get; set; } = true;
/// <summary>
/// 规则参数 (JSON格式)
/// </summary>
[Column(StringLength = 2000)]
public string RuleParameters { get; set; }
/// <summary>
/// 默认优先级
/// </summary>
public int DefaultPriority { get; set; } = 1;
/// <summary>
/// 规则生效开始时间
/// </summary>
public DateTime? EffectiveStartTime { get; set; }
/// <summary>
/// 规则生效结束时间
/// </summary>
public DateTime? EffectiveEndTime { get; set; }
/// <summary>
/// 规则版本号
/// </summary>
[Column(StringLength = 20)]
public string Version { get; set; } = "1.0";
/// <summary>
/// 规则映射集合
/// </summary>
[Navigate(nameof(ShiftRuleMappingEntity.RuleId))]
public virtual List<ShiftRuleMappingEntity> ShiftRuleMappings { get; set; }
}

View File

@ -0,0 +1,55 @@
using System;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
using NPP.SmartSchedue.Api.Contracts.Core.Consts;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Time;
/// <summary>
/// 班次规则关联
/// </summary>
[Table(Name = DbConsts.TableNamePrefix + "shift_rule_mapping")]
public partial class ShiftRuleMappingEntity : EntityTenant
{
/// <summary>
/// 班次ID
/// </summary>
public long ShiftId { get; set; }
/// <summary>
/// 规则ID
/// </summary>
public long RuleId { get; set; }
/// <summary>
/// 规则覆盖参数 (JSON格式覆盖规则默认参数)
/// </summary>
[Column(StringLength = 1500)]
public string OverrideParameters { get; set; }
/// <summary>
/// 是否启用该规则
/// </summary>
public bool IsEnabled { get; set; } = true;
/// <summary>
/// 规则执行优先级 (数字越小优先级越高)
/// </summary>
public int ExecutionPriority { get; set; } = 1;
/// <summary>
/// 规则生效开始时间 (覆盖规则默认时间)
/// </summary>
public DateTime? EffectiveStartTime { get; set; }
/// <summary>
/// 规则生效结束时间 (覆盖规则默认时间)
/// </summary>
public DateTime? EffectiveEndTime { get; set; }
/// <summary>
/// 映射描述
/// </summary>
[Column(StringLength = 300)]
public string MappingDescription { get; set; }
}

View File

@ -0,0 +1,11 @@
using NPP.SmartSchedue.Api.Contracts.Domain.Work;
using ZhonTai.Admin.Core.Repositories;
namespace NPP.SmartSchedue.Api.Contracts;
/// <summary>
/// 工序组关联关系仓储接口
/// </summary>
public interface IProcessGroupRelationRepository : IRepositoryBase<ProcessGroupRelationEntity>
{
}

View File

@ -0,0 +1,11 @@
using NPP.SmartSchedue.Api.Contracts.Domain.Work;
using ZhonTai.Admin.Core.Repositories;
namespace NPP.SmartSchedue.Api.Contracts;
/// <summary>
/// 工序组仓储接口
/// </summary>
public interface IProcessGroupRepository : IRepositoryBase<ProcessGroupEntity>
{
}

View File

@ -0,0 +1,11 @@
using NPP.SmartSchedue.Api.Contracts.Domain.Work;
using ZhonTai.Admin.Core.Repositories;
namespace NPP.SmartSchedue.Api.Contracts;
/// <summary>
/// 工序仓储接口
/// </summary>
public interface IProcessRepository : IRepositoryBase<ProcessEntity>
{
}

View File

@ -0,0 +1,51 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using NPP.SmartSchedue.Api.Contracts.Domain.Work;
using ZhonTai.Admin.Core.Repositories;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Work;
/// <summary>
/// 工作任务FL人员关联仓储接口
/// </summary>
public interface IWorkOrderFLPersonnelRepository : IRepositoryBase<WorkOrderFLPersonnelEntity>
{
/// <summary>
/// 根据工作任务ID获取FL人员列表
/// </summary>
/// <param name="workOrderId">工作任务ID</param>
/// <returns>FL人员列表</returns>
Task<List<WorkOrderFLPersonnelEntity>> GetByWorkOrderIdAsync(long workOrderId);
/// <summary>
/// 根据FL人员ID获取工作任务列表
/// </summary>
/// <param name="flPersonnelId">FL人员ID</param>
/// <returns>工作任务列表</returns>
Task<List<WorkOrderFLPersonnelEntity>> GetByPersonnelIdAsync(long personnelId);
/// <summary>
/// 批量添加工作任务FL人员关联
/// </summary>
/// <param name="workOrderId">工作任务ID</param>
/// <param name="flPersonnelIds">FL人员ID列表</param>
/// <param name="flPersonnelNames">FL人员姓名列表</param>
/// <returns>添加结果</returns>
Task<bool> BatchAddAsync(long workOrderId, List<long> flPersonnelIds, List<string> flPersonnelNames);
/// <summary>
/// 根据工作任务ID删除所有FL人员关联
/// </summary>
/// <param name="workOrderId">工作任务ID</param>
/// <returns>删除结果</returns>
Task<bool> DeleteByWorkOrderIdAsync(long workOrderId);
/// <summary>
/// 更新工作任务的FL人员关联
/// </summary>
/// <param name="workOrderId">工作任务ID</param>
/// <param name="flPersonnelIds">新的FL人员ID列表</param>
/// <param name="flPersonnelNames">新的FL人员姓名列表</param>
/// <returns>更新结果</returns>
Task<bool> UpdateByWorkOrderIdAsync(long workOrderId, List<long> flPersonnelIds, List<string> flPersonnelNames);
}

View File

@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using NPP.SmartSchedue.Api.Contracts.Domain.Work;
using NPP.SmartSchedue.Api.Contracts.Core.Enums;
using ZhonTai.Admin.Core.Repositories;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Work;
/// <summary>
/// 工作任务仓储接口
/// </summary>
public interface IWorkOrderRepository : IRepositoryBase<WorkOrderEntity>
{
/// <summary>
/// 根据日期获取工作任务列表
/// </summary>
/// <param name="date">日期</param>
/// <returns>工作任务列表</returns>
Task<List<WorkOrderEntity>> GetByDateAsync(DateTime date);
/// <summary>
/// 根据人员ID和日期范围获取工作任务列表
/// </summary>
/// <param name="personnelId">人员ID</param>
/// <param name="startDate">开始日期</param>
/// <param name="endDate">结束日期</param>
/// <returns>工作任务列表</returns>
Task<List<WorkOrderEntity>> GetByPersonnelAndDateRangeAsync(long personnelId, DateTime startDate, DateTime endDate);
/// <summary>
/// 根据状态获取工作任务列表
/// </summary>
/// <param name="status">任务状态</param>
/// <returns>工作任务列表</returns>
Task<List<WorkOrderEntity>> GetByStatusAsync(WorkOrderStatusEnum status);
/// <summary>
/// 根据班次ID获取工作任务列表
/// </summary>
/// <param name="shiftId">班次ID</param>
/// <param name="date">日期</param>
/// <returns>工作任务列表</returns>
Task<List<WorkOrderEntity>> GetByShiftAndDateAsync(long shiftId, DateTime date);
/// <summary>
/// 根据工序ID获取工作任务列表
/// </summary>
/// <param name="processId">工序ID</param>
/// <param name="startDate">开始日期</param>
/// <param name="endDate">结束日期</param>
/// <returns>工作任务列表</returns>
Task<List<WorkOrderEntity>> GetByProcessAndDateRangeAsync(long processId, DateTime startDate, DateTime endDate);
/// <summary>
/// 检查任务代码是否存在
/// </summary>
/// <param name="workOrderCode">任务代码</param>
/// <param name="excludeId">排除的ID</param>
/// <returns>是否存在</returns>
Task<bool> ExistsWorkOrderCodeAsync(string workOrderCode, long? excludeId = null);
/// <summary>
/// 生成任务代码
/// </summary>
/// <param name="projectNumber">项目号</param>
/// <param name="shiftCode">班次代码</param>
/// <param name="processCode">工序代码</param>
/// <returns>任务代码</returns>
string GenerateWorkOrderCode(string projectNumber, string shiftCode, string processCode);
/// <summary>
/// 获取人员在指定日期范围内的任务数量
/// </summary>
/// <param name="personnelId">人员ID</param>
/// <param name="startDate">开始日期</param>
/// <param name="endDate">结束日期</param>
/// <returns>任务数量</returns>
Task<int> GetPersonnelTaskCountByDateRangeAsync(long personnelId, DateTime startDate, DateTime endDate);
}

View File

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
using NPP.SmartSchedue.Api.Contracts.Core.Consts;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Work;
/// <summary>
/// 工序实体
/// </summary>
[Table(Name = DbConsts.TableNamePrefix + "process")]
public partial class ProcessEntity : EntityTenant
{
/// <summary>
/// 工序编号
/// </summary>
[Column(StringLength = 50)]
public string ProcessCode { get; set; }
/// <summary>
/// 工序名称
/// </summary>
[Column(StringLength = 100)]
public string ProcessName { get; set; }
/// <summary>
/// 工序分类
/// </summary>
[Column(StringLength = 50)]
public string ProcessCategory { get; set; }
/// <summary>
/// 人员资质要求
/// </summary>
[Column(StringLength = 500)]
public string QualificationRequirements { get; set; }
/// <summary>
/// 设备类型
/// </summary>
public string? EquipmentType { get; set; }
/// <summary>
/// 理论任务时长(小时)
/// </summary>
public decimal TheoreticalDuration { get; set; }
/// <summary>
/// 工序描述
/// </summary>
[Column(StringLength = 500)]
public string Description { get; set; }
/// <summary>
/// 是否启用
/// </summary>
public bool IsEnabled { get; set; } = true;
/// <summary>
/// 工序优先级
/// </summary>
public int Priority { get; set; } = 1;
/// <summary>
/// 预估持续时间
/// </summary>
public TimeSpan? EstimatedDuration { get; set; }
/// <summary>
/// 设备类型ID
/// </summary>
public long? EquipmentTypeId { get; set; }
}

View File

@ -0,0 +1,41 @@
using System;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
using NPP.SmartSchedue.Api.Contracts.Core.Consts;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Work;
/// <summary>
/// 工序组实体
/// </summary>
[Table(Name = DbConsts.TableNamePrefix + "process_group")]
public partial class ProcessGroupEntity : EntityTenant
{
/// <summary>
/// 工序组名称
/// </summary>
[Column(StringLength = 100)]
public string GroupName { get; set; }
/// <summary>
/// 项目类别
/// </summary>
[Column(StringLength = 50)]
public string ProjectCategory { get; set; }
/// <summary>
/// 工序组描述
/// </summary>
[Column(StringLength = 500)]
public string Description { get; set; }
/// <summary>
/// 是否启用
/// </summary>
public bool IsEnabled { get; set; } = true;
/// <summary>
/// 工序组优先级
/// </summary>
public int Priority { get; set; } = 1;
}

View File

@ -0,0 +1,49 @@
using System;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
using NPP.SmartSchedue.Api.Contracts.Core.Consts;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Work;
/// <summary>
/// 工序组关联关系实体
/// </summary>
[Table(Name = DbConsts.TableNamePrefix + "process_group_relation")]
public partial class ProcessGroupRelationEntity : EntityTenant
{
/// <summary>
/// 工序组ID
/// </summary>
public long ProcessGroupId { get; set; }
/// <summary>
/// 工序ID
/// </summary>
public long ProcessId { get; set; }
/// <summary>
/// 关联类型 (A=>B, A=>B=>C)
/// </summary>
[Column(StringLength = 20)]
public string RelationType { get; set; }
/// <summary>
/// 前置工序ID
/// </summary>
public long? PredecessorProcessId { get; set; }
/// <summary>
/// 后置工序ID
/// </summary>
public long? SuccessorProcessId { get; set; }
/// <summary>
/// 关联顺序
/// </summary>
public int RelationOrder { get; set; }
/// <summary>
/// 是否启用
/// </summary>
public bool IsEnabled { get; set; } = true;
}

View File

@ -0,0 +1,275 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
using NPP.SmartSchedue.Api.Contracts.Core.Consts;
using NPP.SmartSchedue.Api.Contracts.Core.Enums;
using NPP.SmartSchedue.Api.Contracts.Domain.Personnel;
using NPP.SmartSchedue.Api.Contracts.Domain.Time;
using NPP.SmartSchedue.Api.Contracts.Domain.Equipment;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Work;
/// <summary>
/// 工作任务实体
/// </summary>
[Table(Name = DbConsts.TableNamePrefix + "work_order")]
public partial class WorkOrderEntity : EntityTenant
{
#region
/// <summary>
/// 项目号
/// </summary>
[Column(StringLength = 50)]
[Required(ErrorMessage = "项目号不能为空")]
public string ProjectNumber { get; set; }
/// <summary>
/// 项目类别
/// </summary>
[Column(StringLength = 50)]
[Required(ErrorMessage = "项目类别不能为空")]
public string ProjectCategory { get; set; }
/// <summary>
/// 班次ID
/// </summary>
public long? ShiftId { get; set; }
/// <summary>
/// 班次代码
/// </summary>
[Column(StringLength = 20)]
public string ShiftCode { get; set; }
/// <summary>
/// 班次名称
/// </summary>
[Column(StringLength = 100)]
public string ShiftName { get; set; }
/// <summary>
/// 工序ID
/// </summary>
[Required(ErrorMessage = "工序不能为空")]
public long ProcessId { get; set; }
/// <summary>
/// 工序代码
/// </summary>
[Column(StringLength = 20)]
public string ProcessCode { get; set; }
/// <summary>
/// 工序名称
/// </summary>
[Column(StringLength = 100)]
public string ProcessName { get; set; }
/// <summary>
/// 工序分类
/// </summary>
public string ProcessCategory { get; set; }
#endregion
#region
/// <summary>
/// 任务代码项目号_班次code_工序code
/// </summary>
[Column(StringLength = 100)]
public string WorkOrderCode { get; set; }
/// <summary>
/// 批号
/// </summary>
[Column(StringLength = 50)]
public string BatchNumber { get; set; }
/// <summary>
/// 任务日期
/// </summary>
[Required(ErrorMessage = "任务日期不能为空")]
public DateTime WorkOrderDate { get; set; }
/// <summary>
/// 任务状态
/// </summary>
public int Status { get; set; } = (int)WorkOrderStatusEnum.PendingSubmit;
/// <summary>
/// 优先级1-10数字越大优先级越高
/// </summary>
public int Priority { get; set; } = 5;
/// <summary>
/// 预计工时(小时)
/// </summary>
[Column(Precision = 10, Scale = 2)]
public decimal? EstimatedHours { get; set; }
/// <summary>
/// 紧急程度1-10数字越大越紧急
/// </summary>
public int Urgency { get; set; } = 5;
/// <summary>
/// 任务复杂度别名使用Priority表示
/// </summary>
[Column(MapType = typeof(int), IsIgnore = true)]
public int Complexity
{
get => Priority;
set => Priority = value;
}
/// <summary>
/// 权重系数(用于排序和优先级计算)
/// </summary>
[Column(Precision = 10, Scale = 4)]
public double WeightFactor { get; set; } = 1.0;
#endregion
#region
/// <summary>
/// 任务实施人员ID
/// </summary>
public long? AssignedPersonnelId { get; set; }
/// <summary>
/// 任务实施人员姓名
/// </summary>
[Column(StringLength = 100)]
public string AssignedPersonnelName { get; set; }
/// <summary>
/// 任务设备ID
/// </summary>
public long? AssignedEquipmentId { get; set; }
/// <summary>
/// 任务设备名称
/// </summary>
[Column(StringLength = 200)]
public string AssignedEquipmentName { get; set; }
#endregion
#region
/// <summary>
/// 任务实际开始时间
/// </summary>
public DateTime? ActualStartTime { get; set; }
/// <summary>
/// 任务实际结束时间
/// </summary>
public DateTime? ActualEndTime { get; set; }
/// <summary>
/// 实际完成工时(小时)
/// </summary>
[Column(Precision = 10, Scale = 2)]
public decimal? ActualWorkHours { get; set; }
/// <summary>
/// 实际完成工时(别名,与 ActualWorkHours 相同)
/// </summary>
[Column(MapType = typeof(decimal?), IsIgnore = true)]
public decimal? ActualCompletedHours
{
get => ActualWorkHours;
set => ActualWorkHours = value;
}
/// <summary>
/// 任务分配时间
/// </summary>
public DateTime? AssignedTime { get; set; }
/// <summary>
/// 最后修改时间
/// </summary>
public DateTime? LastModifiedTime { get; set; }
/// <summary>
/// 备注信息
/// </summary>
[Column(StringLength = 1000)]
public string Remarks { get; set; } = "";
/// <summary>
/// 计划开始时间
/// </summary>
public DateTime PlannedStartTime { get; set; }
/// <summary>
/// 计划结束时间
/// </summary>
public DateTime PlannedEndTime { get; set; }
/// <summary>
/// 任务代码/编号
/// </summary>
[Column(StringLength = 100)]
public string Code { get; set; } = "";
/// <summary>
/// 紧急程度级别使用Urgency的别名
/// </summary>
[Column(MapType = typeof(int), IsIgnore = true)]
public int UrgencyLevel
{
get => Urgency;
set => Urgency = value;
}
/// <summary>
/// 复杂度级别使用Priority的别名
/// </summary>
[Column(MapType = typeof(int), IsIgnore = true)]
public int ComplexityLevel
{
get => Priority;
set => Priority = value;
}
/// <summary>
/// 整合记录ID
/// </summary>
public long? IntegrationRecordId { get; set; }
#endregion
#region
/// <summary>
/// 工序实体
/// </summary>
[Navigate("ProcessId")]
public ProcessEntity? ProcessEntity { get; set; }
/// <summary>
/// 班次实体
/// </summary>
[Navigate("ShiftId")]
public ShiftEntity? ShiftEntity { get; set; }
/// <summary>
/// FL人员关联列表
/// </summary>
[Navigate("WorkOrderId")]
public List<WorkOrderFLPersonnelEntity> WorkOrderFLPersonnels { get; set; } = new List<WorkOrderFLPersonnelEntity>();
#endregion
}

View File

@ -0,0 +1,41 @@
using System;
using FreeSql.DataAnnotations;
using ZhonTai.Admin.Core.Entities;
using NPP.SmartSchedue.Api.Contracts.Core.Consts;
using NPP.SmartSchedue.Api.Contracts.Domain.Personnel;
namespace NPP.SmartSchedue.Api.Contracts.Domain.Work;
/// <summary>
/// 工作任务FL人员关联实体
/// </summary>
[Table(Name = DbConsts.TableNamePrefix + "work_order_fl_personnel")]
public partial class WorkOrderFLPersonnelEntity : EntityBase
{
/// <summary>
/// 工作任务ID
/// </summary>
public long WorkOrderId { get; set; }
/// <summary>
/// FL人员ID
/// </summary>
public long FLPersonnelId { get; set; }
/// <summary>
/// FL人员姓名
/// </summary>
[Column(StringLength = 100)]
public string FLPersonnelName { get; set; } = "";
/// <summary>
/// 人员实体
/// </summary>
[Navigate("PersonnelId")]
public PersonnelEntity? PersonnelEntity { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public new DateTime CreatedTime { get; set; } = DateTime.Now;
}

View File

@ -0,0 +1,52 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>NPP.SmartSchedue接口契约库</Description>
<Version>1.0.0</Version>
<OpenApiGenerateDocuments>false</OpenApiGenerateDocuments>
<TargetFramework>net9.0</TargetFramework>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<DocumentationFile>$(MSBuildProjectName).xml</DocumentationFile>
<IsPackable>true</IsPackable>
<Authors>xiaoxue</Authors>
<Company>zhontai</Company>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://admin.zhontai.net</PackageProjectUrl>
<RepositoryUrl>https://github.com/zhontai/Admin.Core</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>ZhonTai Admin Api Contracts;</PackageTags>
<NoWarn>1701;1702;1591;8632;SYSLIB0020;CS8002;NU1902;NU1903;NU1904;</NoWarn>
<SignAssembly>true</SignAssembly>
<DelaySign>false</DelaySign>
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ZhonTai.Admin.Core" Version="9.1.1">
<IsBuild>true</IsBuild>
</PackageReference>
<PackageReference Include="ZhonTai.Admin.Contracts" Version="9.1.1">
<IsBuild>true</IsBuild>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Domain\"/>
<Folder Include="Domain\Schedule\" />
<Folder Include="Services\"/>
</ItemGroup>
<Target Name="AfterTargetsBuild" AfterTargets="Build">
<ItemGroup>
<PackageReferenceXmlFiles Condition="'%(PackageReference.IsBuild)' == 'true'" Include="$(NugetPackageRoot)\$([MSBuild]::Escape('%(PackageReference.Identity)').ToLower())\%(PackageReference.Version)\**\*.xml"/>
<PackageReferenceJsonFiles Condition="'%(PackageReference.IsBuild)' == 'true'" Include="$(NugetPackageRoot)\$([MSBuild]::Escape('%(PackageReference.Identity)').ToLower())\%(PackageReference.Version)\**\*.json"/>
</ItemGroup>
<Copy Condition="'%(PackageReferenceXmlFiles.Identity)' != ''" SourceFiles="@(PackageReferenceXmlFiles)" DestinationFolder="./../NPP.SmartSchedue.Host/$(OutDir)"/>
<Copy Condition="'%(PackageReferenceJsonFiles.Identity)' != ''" SourceFiles="@(PackageReferenceJsonFiles)" DestinationFolder="./../NPP.SmartSchedue.Host/$(OutDir)Resources"/>
<Copy Condition="'%(PackageReferenceXmlFiles.Identity)' != ''" SourceFiles="@(PackageReferenceXmlFiles)" DestinationFolder="./../NPP.SmartSchedue.Tests/$(OutDir)"/>
<Copy Condition="'%(PackageReferenceJsonFiles.Identity)' != ''" SourceFiles="@(PackageReferenceJsonFiles)" DestinationFolder="./../NPP.SmartSchedue.Tests/$(OutDir)Resources"/>
</Target>
</Project>

View File

@ -0,0 +1,14 @@
using FreeSql;
using NPP.SmartSchedue.Api.Contracts.Domain.Equipment;
using ZhonTai.Admin.Core.Repositories;
namespace NPP.SmartSchedue.Api.Contracts.Repositories.Equipment
{
/// <summary>
/// 设备仓储接口
/// 职责:定义设备实体的数据访问接口
/// </summary>
public interface IEquipmentRepository : IRepositoryBase<EquipmentEntity>
{
}
}

View File

@ -0,0 +1,76 @@
using System;
namespace NPP.SmartSchedue.Api.Contracts.Services.Equipment.Dto;
/// <summary>
/// 设备列表输出
/// </summary>
public class EquipmentListOutput
{
/// <summary>
/// 设备ID
/// </summary>
public long Id { get; set; }
/// <summary>
/// 设备名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 设备型号
/// </summary>
public string Model { get; set; }
/// <summary>
/// 内部编号
/// </summary>
public string InternalNumber { get; set; }
/// <summary>
/// 房间号
/// </summary>
public string RoomNumber { get; set; }
/// <summary>
/// 设备类型
/// </summary>
public string EquipmentType { get; set; }
/// <summary>
/// 设备状态
/// </summary>
public int Status { get; set; }
/// <summary>
/// 设备负责人姓名
/// </summary>
public string ResponsiblePersonName { get; set; }
/// <summary>
/// 设备位置
/// </summary>
public string Location { get; set; }
/// <summary>
/// 最后维护日期
/// </summary>
public DateTime? LastMaintenanceDate { get; set; }
/// <summary>
/// 下次维护日期
/// </summary>
public DateTime? NextMaintenanceDate { get; set; }
/// <summary>
/// 最后校验日期
/// </summary>
public DateTime? LastCalibrationDate { get; set; }
/// <summary>
/// 下次校验日期
/// </summary>
public DateTime? NextCalibrationDate { get; set; }
public long ProcessId { get; set; }
}

View File

@ -0,0 +1,149 @@
using System;
using System.Collections.Generic;
namespace NPP.SmartSchedue.Api.Contracts.Services.Equipment.Dto;
/// <summary>
/// 按设备类型统计输出模型
/// 包含设备数量、状态分布等核心统计信息
/// </summary>
public class EquipmentTypeStatisticsOutput
{
/// <summary>
/// 设备类型Production, Testing, Laboratory, Office, Other
/// </summary>
public string EquipmentType { get; set; } = string.Empty;
/// <summary>
/// 设备类型显示名称
/// </summary>
public string EquipmentTypeName { get; set; } = string.Empty;
/// <summary>
/// 总设备数量
/// </summary>
public int TotalCount { get; set; }
/// <summary>
/// 按状态分组的设备数量统计
/// 业务深度思考:涵盖设备全生命周期状态,支持设备管理决策
/// </summary>
public EquipmentStatusDistribution StatusDistribution { get; set; } = new();
/// <summary>
/// 平均设备使用年限(年)
/// </summary>
public decimal AverageServiceYears { get; set; }
/// <summary>
/// 设备价值统计(总价值、平均单价)
/// </summary>
public EquipmentValueStatistics ValueStatistics { get; set; } = new();
/// <summary>
/// 最近维护信息汇总
/// </summary>
public MaintenanceSummary MaintenanceSummary { get; set; } = new();
}
/// <summary>
/// 设备状态分布统计
/// 深度业务场景:支持设备健康度评估和维护规划
/// </summary>
public class EquipmentStatusDistribution
{
/// <summary>
/// 正常状态设备数量
/// </summary>
public int NormalCount { get; set; }
/// <summary>
/// 维护中设备数量
/// </summary>
public int MaintenanceCount { get; set; }
/// <summary>
/// 校验中设备数量
/// </summary>
public int CalibrationCount { get; set; }
/// <summary>
/// 故障设备数量
/// </summary>
public int FaultCount { get; set; }
/// <summary>
/// 报废设备数量
/// </summary>
public int ScrapCount { get; set; }
/// <summary>
/// 停用设备数量
/// </summary>
public int InactiveCount { get; set; }
/// <summary>
/// 设备健康度百分比(正常设备占比)
/// </summary>
public decimal HealthPercentage => TotalActiveCount > 0 ?
(decimal)NormalCount / TotalActiveCount * 100 : 0;
/// <summary>
/// 活跃设备总数(排除报废和停用)
/// </summary>
public int TotalActiveCount => NormalCount + MaintenanceCount + CalibrationCount + FaultCount;
}
/// <summary>
/// 设备价值统计
/// 业务深度思考:支持资产管理和投资回报分析
/// </summary>
public class EquipmentValueStatistics
{
/// <summary>
/// 总资产价值
/// </summary>
public decimal TotalValue { get; set; }
/// <summary>
/// 平均单台价值
/// </summary>
public decimal AverageValue { get; set; }
/// <summary>
/// 最高单台价值
/// </summary>
public decimal MaxValue { get; set; }
/// <summary>
/// 最低单台价值
/// </summary>
public decimal MinValue { get; set; }
}
/// <summary>
/// 维护信息汇总
/// 深度业务场景:支持维护成本分析和维护策略优化
/// </summary>
public class MaintenanceSummary
{
/// <summary>
/// 最近30天内维护次数
/// </summary>
public int RecentMaintenanceCount { get; set; }
/// <summary>
/// 平均维护间隔天数
/// </summary>
public decimal AverageMaintenanceInterval { get; set; }
/// <summary>
/// 下次预计维护日期
/// </summary>
public DateTime? NextMaintenanceDate { get; set; }
/// <summary>
/// 维护成本趋势(相比上期增长百分比)
/// </summary>
public decimal MaintenanceCostTrend { get; set; }
}

View File

@ -0,0 +1,322 @@
using System;
using System.Collections.Generic;
namespace NPP.SmartSchedue.Api.Contracts.Services.Equipment.Dto;
/// <summary>
/// 设备类型任务分配统计输出模型
/// 深度业务场景:支持工艺流程分析、设备负荷均衡评估和生产计划优化
/// </summary>
public class EquipmentTypeTaskAllocationOutput
{
/// <summary>
/// 设备类型
/// </summary>
public string EquipmentType { get; set; } = string.Empty;
/// <summary>
/// 设备类型显示名称
/// </summary>
public string EquipmentTypeName { get; set; } = string.Empty;
/// <summary>
/// 统计时间段
/// </summary>
public DateTime StatisticsPeriodStart { get; set; }
public DateTime StatisticsPeriodEnd { get; set; }
/// <summary>
/// 任务分配汇总统计
/// 深度业务思考:全面反映该设备类型的工作负荷情况
/// </summary>
public TaskAllocationSummary AllocationSummary { get; set; } = new();
/// <summary>
/// 按优先级分组的任务分配统计
/// 业务深度逻辑:支持紧急任务和常规任务的资源分配决策
/// </summary>
public List<TaskPriorityAllocation> PriorityAllocations { get; set; } = new();
/// <summary>
/// 按工序类型分组的任务分配统计
/// 深度业务场景:分析该设备类型在不同工序中的使用情况
/// </summary>
public List<ProcessTypeAllocation> ProcessAllocations { get; set; } = new();
/// <summary>
/// 按时间段的任务分配分布
/// 支持24小时工作负荷分析和班次安排优化
/// </summary>
public List<TimeSlotAllocation> TimeSlotAllocations { get; set; } = new();
/// <summary>
/// 设备负荷均衡分析
/// 深度业务思考:评估设备间的工作负荷分布是否合理
/// </summary>
public LoadBalanceAnalysis LoadBalanceAnalysis { get; set; } = new();
/// <summary>
/// 任务完成质量指标
/// 业务深度场景:评估该设备类型在任务执行中的表现
/// </summary>
public TaskCompletionQuality CompletionQuality { get; set; } = new();
}
/// <summary>
/// 任务分配汇总统计
/// </summary>
public class TaskAllocationSummary
{
/// <summary>
/// 总任务数量
/// </summary>
public int TotalTaskCount { get; set; }
/// <summary>
/// 已完成任务数量
/// </summary>
public int CompletedTaskCount { get; set; }
/// <summary>
/// 进行中任务数量
/// </summary>
public int InProgressTaskCount { get; set; }
/// <summary>
/// 待分配任务数量
/// </summary>
public int PendingTaskCount { get; set; }
/// <summary>
/// 已取消任务数量
/// </summary>
public int CancelledTaskCount { get; set; }
/// <summary>
/// 总预估工时(小时)
/// </summary>
public decimal TotalEstimatedHours { get; set; }
/// <summary>
/// 总实际工时(小时)
/// </summary>
public decimal TotalActualHours { get; set; }
/// <summary>
/// 工时准确率(实际工时与预估工时的比值)
/// 深度业务逻辑:评估工时预估的准确性,支持后续预估优化
/// </summary>
public decimal TimeAccuracyRate => TotalEstimatedHours > 0 ?
TotalActualHours / TotalEstimatedHours * 100 : 0;
/// <summary>
/// 任务完成率(百分比)
/// </summary>
public decimal CompletionRate => TotalTaskCount > 0 ?
(decimal)CompletedTaskCount / TotalTaskCount * 100 : 0;
}
/// <summary>
/// 按优先级的任务分配统计
/// 深度业务思考:分析不同优先级任务的分配和完成情况
/// </summary>
public class TaskPriorityAllocation
{
/// <summary>
/// 优先级等级
/// </summary>
public int PriorityLevel { get; set; }
/// <summary>
/// 优先级名称(紧急、高、中、低)
/// </summary>
public string PriorityName { get; set; } = string.Empty;
/// <summary>
/// 该优先级任务数量
/// </summary>
public int TaskCount { get; set; }
/// <summary>
/// 该优先级任务占比(百分比)
/// </summary>
public decimal TaskPercentage { get; set; }
/// <summary>
/// 平均完成时间(小时)
/// </summary>
public decimal AverageCompletionTime { get; set; }
/// <summary>
/// 按时完成率(百分比)
/// 深度业务指标:评估高优先级任务的及时完成情况
/// </summary>
public decimal OnTimeCompletionRate { get; set; }
}
/// <summary>
/// 按工序类型的任务分配统计
/// </summary>
public class ProcessTypeAllocation
{
/// <summary>
/// 工序类型
/// </summary>
public string ProcessType { get; set; } = string.Empty;
/// <summary>
/// 工序名称
/// </summary>
public string ProcessName { get; set; } = string.Empty;
/// <summary>
/// 该工序类型的任务数量
/// </summary>
public int TaskCount { get; set; }
/// <summary>
/// 该工序类型任务占比
/// </summary>
public decimal TaskPercentage { get; set; }
/// <summary>
/// 该工序的平均耗时(小时)
/// </summary>
public decimal AverageDuration { get; set; }
/// <summary>
/// 该工序的标准耗时(小时)
/// </summary>
public decimal StandardDuration { get; set; }
/// <summary>
/// 工序效率指标(实际耗时与标准耗时的比值)
/// 深度业务分析:评估工序执行效率,识别改进机会
/// </summary>
public decimal EfficiencyRatio => StandardDuration > 0 ?
StandardDuration / AverageDuration * 100 : 0;
}
/// <summary>
/// 时间段任务分配分布
/// 深度业务场景支持24小时生产排程和班次优化决策
/// </summary>
public class TimeSlotAllocation
{
/// <summary>
/// 时间段小时0-23
/// </summary>
public int TimeSlot { get; set; }
/// <summary>
/// 该时间段的任务数量
/// </summary>
public int TaskCount { get; set; }
/// <summary>
/// 该时间段的设备使用率
/// </summary>
public decimal UtilizationRate { get; set; }
/// <summary>
/// 该时间段的平均任务持续时间
/// </summary>
public decimal AverageTaskDuration { get; set; }
/// <summary>
/// 该时间段对应的班次信息
/// </summary>
public string ShiftName { get; set; } = string.Empty;
}
/// <summary>
/// 负荷均衡分析
/// 深度业务思考:评估设备类型内各设备间的工作分配是否均衡
/// </summary>
public class LoadBalanceAnalysis
{
/// <summary>
/// 最高负荷设备的工作量
/// </summary>
public decimal MaxWorkload { get; set; }
/// <summary>
/// 最低负荷设备的工作量
/// </summary>
public decimal MinWorkload { get; set; }
/// <summary>
/// 平均工作量
/// </summary>
public decimal AverageWorkload { get; set; }
/// <summary>
/// 负荷均衡系数0-1越接近1越均衡
/// 计算逻辑1 - (最大工作量 - 最小工作量) / 平均工作量
/// </summary>
public decimal BalanceCoefficient { get; set; }
/// <summary>
/// 工作量标准差
/// 深度统计分析:衡量设备间工作量分布的离散程度
/// </summary>
public decimal WorkloadStandardDeviation { get; set; }
/// <summary>
/// 负荷均衡评级Excellent, Good, Average, Poor
/// </summary>
public string BalanceRating { get; set; } = "Average";
/// <summary>
/// 均衡优化建议
/// </summary>
public List<string> OptimizationSuggestions { get; set; } = new();
}
/// <summary>
/// 任务完成质量指标
/// 深度业务评估:从多维度评价设备类型的任务执行质量
/// </summary>
public class TaskCompletionQuality
{
/// <summary>
/// 准时完成率(百分比)
/// </summary>
public decimal OnTimeCompletionRate { get; set; }
/// <summary>
/// 质量合格率(百分比)
/// </summary>
public decimal QualityPassRate { get; set; }
/// <summary>
/// 返工率(百分比)
/// </summary>
public decimal ReworkRate { get; set; }
/// <summary>
/// 平均延期天数
/// </summary>
public decimal AverageDelayDays { get; set; }
/// <summary>
/// 客户满意度评分1-5分
/// </summary>
public decimal CustomerSatisfactionScore { get; set; }
/// <summary>
/// 综合质量得分0-100分
/// 深度业务算法:综合考虑准时性、质量、客户满意度等因素
/// </summary>
public decimal OverallQualityScore { get; set; }
/// <summary>
/// 质量等级Excellent, Good, Average, Poor
/// </summary>
public string QualityGrade { get; set; } = "Average";
/// <summary>
/// 质量改进建议
/// </summary>
public List<string> ImprovementRecommendations { get; set; } = new();
}

View File

@ -0,0 +1,511 @@
using System;
using System.Collections.Generic;
namespace NPP.SmartSchedue.Api.Contracts.Services.Equipment.Dto;
/// <summary>
/// 设备类型趋势分析输出模型
/// 深度业务场景:支持长期设备投资规划、维护策略制定和产能预测
/// </summary>
public class EquipmentTypeTrendOutput
{
/// <summary>
/// 设备类型
/// </summary>
public string EquipmentType { get; set; } = string.Empty;
/// <summary>
/// 设备类型显示名称
/// </summary>
public string EquipmentTypeName { get; set; } = string.Empty;
/// <summary>
/// 趋势分析时间段
/// </summary>
public DateTime TrendPeriodStart { get; set; }
public DateTime TrendPeriodEnd { get; set; }
/// <summary>
/// 分组周期类型Day, Week, Month
/// </summary>
public string GroupByPeriod { get; set; } = "Day";
/// <summary>
/// 时间序列趋势数据点
/// 深度业务分析:按时间周期组织的关键指标变化趋势
/// </summary>
public List<TrendDataPoint> TrendDataPoints { get; set; } = new();
/// <summary>
/// 趋势分析汇总
/// </summary>
public TrendAnalysisSummary AnalysisSummary { get; set; } = new();
/// <summary>
/// 预测分析结果
/// 深度业务智能:基于历史数据的未来趋势预测
/// </summary>
public PredictionAnalysis PredictionAnalysis { get; set; } = new();
/// <summary>
/// 异常检测结果
/// 业务深度思考:识别异常波动和潜在风险点
/// </summary>
public List<AnomalyDetection> AnomalyDetections { get; set; } = new();
/// <summary>
/// 季节性分析
/// 支持识别生产淡旺季对设备使用的影响
/// </summary>
public SeasonalityAnalysis SeasonalityAnalysis { get; set; } = new();
}
/// <summary>
/// 趋势数据点
/// 时间序列中的单个数据点,包含关键业务指标
/// </summary>
public class TrendDataPoint
{
/// <summary>
/// 数据点时间
/// </summary>
public DateTime DataPointTime { get; set; }
/// <summary>
/// 时间段标识2024-01-01 或 2024-W01
/// </summary>
public string PeriodLabel { get; set; } = string.Empty;
/// <summary>
/// 设备使用率(百分比)
/// </summary>
public decimal UtilizationRate { get; set; }
/// <summary>
/// 任务完成数量
/// </summary>
public int CompletedTaskCount { get; set; }
/// <summary>
/// 平均任务持续时间(小时)
/// </summary>
public decimal AverageTaskDuration { get; set; }
/// <summary>
/// 设备可用率(百分比)
/// 深度业务指标:考虑维护、故障等因素的实际可用程度
/// </summary>
public decimal AvailabilityRate { get; set; }
/// <summary>
/// 维护事件次数
/// </summary>
public int MaintenanceEventCount { get; set; }
/// <summary>
/// 故障事件次数
/// </summary>
public int FaultEventCount { get; set; }
/// <summary>
/// 工作负荷指数0-100
/// 综合考虑使用率、任务复杂度、时间压力等因素
/// </summary>
public decimal WorkloadIndex { get; set; }
/// <summary>
/// 效率评分0-100
/// 基于任务完成质量、时间准确性等综合评估
/// </summary>
public decimal EfficiencyScore { get; set; }
/// <summary>
/// 成本指标
/// 包含运行成本、维护成本等
/// </summary>
public CostMetrics CostMetrics { get; set; } = new();
}
/// <summary>
/// 成本指标
/// 深度财务分析:设备运行的各项成本统计
/// </summary>
public class CostMetrics
{
/// <summary>
/// 运行成本(元)
/// 包含电费、人工、材料等直接成本
/// </summary>
public decimal OperatingCost { get; set; }
/// <summary>
/// 维护成本(元)
/// </summary>
public decimal MaintenanceCost { get; set; }
/// <summary>
/// 故障损失成本(元)
/// 包含停机损失、紧急维修等间接成本
/// </summary>
public decimal FailureCost { get; set; }
/// <summary>
/// 单位产出成本(元/件)
/// 深度业务分析:评估设备经济效益的关键指标
/// </summary>
public decimal UnitCost { get; set; }
}
/// <summary>
/// 趋势分析汇总
/// 深度统计分析:提供趋势的整体特征和关键洞察
/// </summary>
public class TrendAnalysisSummary
{
/// <summary>
/// 整体趋势方向
/// Increasing: 上升趋势
/// Decreasing: 下降趋势
/// Stable: 稳定趋势
/// Volatile: 波动趋势
/// </summary>
public string OverallTrend { get; set; } = "Stable";
/// <summary>
/// 趋势强度系数(-1到1正值表示上升负值表示下降
/// </summary>
public decimal TrendStrength { get; set; }
/// <summary>
/// 数据波动性系数0-1越接近1越不稳定
/// </summary>
public decimal VolatilityCoefficient { get; set; }
/// <summary>
/// 最高使用率及其时间点
/// </summary>
public PeakDataPoint PeakUsage { get; set; } = new();
/// <summary>
/// 最低使用率及其时间点
/// </summary>
public PeakDataPoint LowUsage { get; set; } = new();
/// <summary>
/// 平均增长率(月环比或周环比)
/// </summary>
public decimal AverageGrowthRate { get; set; }
/// <summary>
/// 趋势置信度0-100基于数据质量和一致性
/// </summary>
public decimal TrendConfidence { get; set; }
/// <summary>
/// 关键拐点时间列表
/// 深度算法识别:使用统计方法识别趋势变化的关键时刻
/// </summary>
public List<DateTime> KeyTurningPoints { get; set; } = new();
}
/// <summary>
/// 峰值数据点
/// </summary>
public class PeakDataPoint
{
/// <summary>
/// 峰值时间
/// </summary>
public DateTime PeakTime { get; set; }
/// <summary>
/// 峰值数值
/// </summary>
public decimal PeakValue { get; set; }
/// <summary>
/// 峰值原因分析
/// </summary>
public string CauseAnalysis { get; set; } = string.Empty;
}
/// <summary>
/// 预测分析结果
/// 深度机器学习应用:基于历史数据预测未来趋势
/// </summary>
public class PredictionAnalysis
{
/// <summary>
/// 预测周期(天数)
/// </summary>
public int PredictionPeriodDays { get; set; }
/// <summary>
/// 预测结果数据点
/// </summary>
public List<PredictionDataPoint> PredictionDataPoints { get; set; } = new();
/// <summary>
/// 预测模型准确度0-100
/// 基于历史预测与实际结果的对比
/// </summary>
public decimal ModelAccuracy { get; set; }
/// <summary>
/// 置信区间范围(百分比)
/// </summary>
public decimal ConfidenceInterval { get; set; } = 95;
/// <summary>
/// 风险预警列表
/// 深度业务智能:基于预测结果识别潜在风险
/// </summary>
public List<RiskWarning> RiskWarnings { get; set; } = new();
}
/// <summary>
/// 预测数据点
/// </summary>
public class PredictionDataPoint
{
/// <summary>
/// 预测时间
/// </summary>
public DateTime PredictedTime { get; set; }
/// <summary>
/// 预测使用率
/// </summary>
public decimal PredictedUtilizationRate { get; set; }
/// <summary>
/// 预测置信度上限
/// </summary>
public decimal UpperConfidenceBound { get; set; }
/// <summary>
/// 预测置信度下限
/// </summary>
public decimal LowerConfidenceBound { get; set; }
/// <summary>
/// 影响因子分析
/// 列出影响该时间点预测结果的关键因素
/// </summary>
public List<string> InfluencingFactors { get; set; } = new();
}
/// <summary>
/// 风险预警
/// 深度业务风控:基于预测分析识别经营风险
/// </summary>
public class RiskWarning
{
/// <summary>
/// 风险类型
/// 如OverCapacity(超负荷), UnderUtilization(利用率不足), MaintenanceRisk(维护风险)等
/// </summary>
public string RiskType { get; set; } = string.Empty;
/// <summary>
/// 风险等级Low, Medium, High, Critical
/// </summary>
public string RiskLevel { get; set; } = "Medium";
/// <summary>
/// 预计发生时间
/// </summary>
public DateTime EstimatedOccurrenceTime { get; set; }
/// <summary>
/// 风险描述
/// </summary>
public string RiskDescription { get; set; } = string.Empty;
/// <summary>
/// 建议应对措施
/// </summary>
public List<string> RecommendedActions { get; set; } = new();
/// <summary>
/// 风险概率0-100
/// </summary>
public decimal RiskProbability { get; set; }
}
/// <summary>
/// 异常检测结果
/// 深度统计分析:基于统计学方法识别异常数据点
/// </summary>
public class AnomalyDetection
{
/// <summary>
/// 异常发生时间
/// </summary>
public DateTime AnomalyTime { get; set; }
/// <summary>
/// 异常类型
/// 如Spike(尖峰), Drop(骤降), Trend(趋势异常), Seasonal(季节性异常)等
/// </summary>
public string AnomalyType { get; set; } = string.Empty;
/// <summary>
/// 异常严重程度1-10
/// </summary>
public int SeverityLevel { get; set; }
/// <summary>
/// 异常值
/// </summary>
public decimal AnomalyValue { get; set; }
/// <summary>
/// 期望值(正常情况下的预期值)
/// </summary>
public decimal ExpectedValue { get; set; }
/// <summary>
/// 偏差程度(百分比)
/// </summary>
public decimal DeviationPercentage { get; set; }
/// <summary>
/// 异常原因推测
/// 深度业务分析:结合业务知识推测异常发生的可能原因
/// </summary>
public List<string> PossibleCauses { get; set; } = new();
/// <summary>
/// 异常影响评估
/// </summary>
public string ImpactAssessment { get; set; } = string.Empty;
}
/// <summary>
/// 季节性分析
/// 深度时间序列分析:识别业务的周期性规律
/// </summary>
public class SeasonalityAnalysis
{
/// <summary>
/// 是否存在季节性模式
/// </summary>
public bool HasSeasonalPattern { get; set; }
/// <summary>
/// 季节性周期长度(天数)
/// </summary>
public int SeasonalCycleDays { get; set; }
/// <summary>
/// 季节性强度系数0-1
/// </summary>
public decimal SeasonalityStrength { get; set; }
/// <summary>
/// 按季节的使用率分布
/// </summary>
public List<SeasonalUsagePattern> SeasonalPatterns { get; set; } = new();
/// <summary>
/// 淡旺季分析
/// 深度业务洞察:识别生产淡旺季规律
/// </summary>
public PeakSeasonAnalysis PeakSeasonAnalysis { get; set; } = new();
}
/// <summary>
/// 季节性使用模式
/// </summary>
public class SeasonalUsagePattern
{
/// <summary>
/// 季节名称(春、夏、秋、冬 或 Q1、Q2、Q3、Q4
/// </summary>
public string SeasonName { get; set; } = string.Empty;
/// <summary>
/// 季节开始时间
/// </summary>
public DateTime SeasonStart { get; set; }
/// <summary>
/// 季节结束时间
/// </summary>
public DateTime SeasonEnd { get; set; }
/// <summary>
/// 该季节的平均使用率
/// </summary>
public decimal AverageUtilizationRate { get; set; }
/// <summary>
/// 相对年均值的变化百分比
/// </summary>
public decimal VariationFromYearlyAverage { get; set; }
/// <summary>
/// 该季节的特征描述
/// </summary>
public string SeasonCharacteristics { get; set; } = string.Empty;
}
/// <summary>
/// 淡旺季分析
/// 深度业务策略支持:为生产计划和资源配置提供决策依据
/// </summary>
public class PeakSeasonAnalysis
{
/// <summary>
/// 旺季时间段
/// </summary>
public List<SeasonPeriod> PeakSeasons { get; set; } = new();
/// <summary>
/// 淡季时间段
/// </summary>
public List<SeasonPeriod> LowSeasons { get; set; } = new();
/// <summary>
/// 旺季与淡季的使用率差异百分比
/// </summary>
public decimal PeakLowDifference { get; set; }
/// <summary>
/// 季节性规划建议
/// 深度业务智慧:基于季节性分析提供运营建议
/// </summary>
public List<string> SeasonalPlanningRecommendations { get; set; } = new();
}
/// <summary>
/// 季节期间
/// </summary>
public class SeasonPeriod
{
/// <summary>
/// 季节类型Peak 或 Low
/// </summary>
public string SeasonType { get; set; } = string.Empty;
/// <summary>
/// 开始时间
/// </summary>
public DateTime StartTime { get; set; }
/// <summary>
/// 结束时间
/// </summary>
public DateTime EndTime { get; set; }
/// <summary>
/// 该期间的平均使用率
/// </summary>
public decimal AverageUtilizationRate { get; set; }
/// <summary>
/// 持续天数
/// </summary>
public int DurationDays { get; set; }
}

View File

@ -0,0 +1,190 @@
using System;
using System.Collections.Generic;
namespace NPP.SmartSchedue.Api.Contracts.Services.Equipment.Dto;
/// <summary>
/// 设备类型使用率统计输出模型
/// 深度业务场景:支持设备使用效率分析和产能评估
/// </summary>
public class EquipmentTypeUsageOutput
{
/// <summary>
/// 设备类型
/// </summary>
public string EquipmentType { get; set; } = string.Empty;
/// <summary>
/// 设备类型显示名称
/// </summary>
public string EquipmentTypeName { get; set; } = string.Empty;
/// <summary>
/// 统计时间段
/// </summary>
public DateTime StatisticsPeriodStart { get; set; }
public DateTime StatisticsPeriodEnd { get; set; }
/// <summary>
/// 平均使用率(百分比)
/// 业务深度思考:基于实际工作时间与理论可用时间的比值
/// </summary>
public decimal AverageUtilizationRate { get; set; }
/// <summary>
/// 峰值使用率(百分比)
/// </summary>
public decimal PeakUtilizationRate { get; set; }
/// <summary>
/// 最低使用率(百分比)
/// </summary>
public decimal MinUtilizationRate { get; set; }
/// <summary>
/// 总工作时长(小时)
/// </summary>
public decimal TotalWorkingHours { get; set; }
/// <summary>
/// 理论可用时长(小时)
/// 深度业务逻辑:考虑设备维护、停机时间后的实际可用时间
/// </summary>
public decimal TotalAvailableHours { get; set; }
/// <summary>
/// 设备空闲时长(小时)
/// </summary>
public decimal TotalIdleHours { get; set; }
/// <summary>
/// 维护停机时长(小时)
/// </summary>
public decimal MaintenanceDowntimeHours { get; set; }
/// <summary>
/// 故障停机时长(小时)
/// </summary>
public decimal FaultDowntimeHours { get; set; }
/// <summary>
/// 使用率趋势分析
/// 深度业务场景:支持设备负荷预测和产能规划
/// </summary>
public UsageTrendAnalysis TrendAnalysis { get; set; } = new();
/// <summary>
/// 按班次的使用率分布
/// </summary>
public List<ShiftUsageDistribution> ShiftUsageDistribution { get; set; } = new();
/// <summary>
/// 设备使用效率评级
/// 业务深度思考:基于使用率、故障率、维护频次的综合评估
/// </summary>
public EquipmentEfficiencyRating EfficiencyRating { get; set; } = new();
}
/// <summary>
/// 使用率趋势分析
/// 深度业务逻辑:基于历史数据分析未来使用趋势
/// </summary>
public class UsageTrendAnalysis
{
/// <summary>
/// 使用率变化趋势(相比上期百分比变化)
/// </summary>
public decimal UsageRateChange { get; set; }
/// <summary>
/// 趋势方向Increasing, Decreasing, Stable
/// </summary>
public string TrendDirection { get; set; } = "Stable";
/// <summary>
/// 预测下期使用率
/// </summary>
public decimal PredictedUsageRate { get; set; }
/// <summary>
/// 趋势置信度0-100
/// </summary>
public decimal TrendConfidence { get; set; }
}
/// <summary>
/// 班次使用率分布
/// 业务深度思考:支持班次安排优化和人员调度决策
/// </summary>
public class ShiftUsageDistribution
{
/// <summary>
/// 班次名称
/// </summary>
public string ShiftName { get; set; } = string.Empty;
/// <summary>
/// 班次开始时间
/// </summary>
public TimeSpan ShiftStartTime { get; set; }
/// <summary>
/// 班次结束时间
/// </summary>
public TimeSpan ShiftEndTime { get; set; }
/// <summary>
/// 该班次的平均使用率
/// </summary>
public decimal AverageUsageRate { get; set; }
/// <summary>
/// 该班次的工作天数
/// </summary>
public int WorkingDays { get; set; }
/// <summary>
/// 该班次的总工作小时数
/// </summary>
public decimal TotalWorkingHours { get; set; }
}
/// <summary>
/// 设备使用效率评级
/// 深度业务场景:支持设备性能评估和改进建议
/// </summary>
public class EquipmentEfficiencyRating
{
/// <summary>
/// 综合效率得分0-100分
/// 计算逻辑使用率权重40% + 可用率权重30% + 质量指标权重30%
/// </summary>
public decimal OverallScore { get; set; }
/// <summary>
/// 效率等级Excellent, Good, Average, Poor
/// </summary>
public string EfficiencyGrade { get; set; } = "Average";
/// <summary>
/// 使用率得分0-100
/// </summary>
public decimal UtilizationScore { get; set; }
/// <summary>
/// 可用率得分0-100
/// 深度业务逻辑:考虑计划内维护和非计划停机的影响
/// </summary>
public decimal AvailabilityScore { get; set; }
/// <summary>
/// 质量指标得分0-100
/// 基于故障频次、维护成本等指标
/// </summary>
public decimal QualityScore { get; set; }
/// <summary>
/// 改进建议列表
/// </summary>
public List<string> ImprovementSuggestions { get; set; } = new();
}

View File

@ -0,0 +1,37 @@
namespace NPP.SmartSchedue.Api.Contracts.Services.Equipment.Dto;
/// <summary>
/// 获取设备列表输入
/// </summary>
public class GetEquipmentListInput
{
/// <summary>
/// 设备类型
/// </summary>
public string EquipmentType { get; set; }
/// <summary>
/// 设备状态
/// </summary>
public int? Status { get; set; }
/// <summary>
/// 设备名称(模糊查询)
/// </summary>
public string Name { get; set; }
/// <summary>
/// 内部编号(模糊查询)
/// </summary>
public string InternalNumber { get; set; }
/// <summary>
/// 设备负责人ID
/// </summary>
public long? ResponsiblePersonId { get; set; }
/// <summary>
/// 工序ID
/// </summary>
public long? ProcessID { get; set; }
}

View File

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using NPP.SmartSchedue.Api.Contracts.Services.Equipment.Dto;
namespace NPP.SmartSchedue.Api.Contracts.Services.Equipment;
/// <summary>
/// 设备本地服务接口专用于SmartSchedule模块
/// </summary>
public interface IEquipmentLocalService
{
/// <summary>
/// 获取设备列表
/// </summary>
/// <param name="input">查询条件</param>
/// <returns>设备列表</returns>
Task<List<EquipmentListOutput>> GetListAsync(GetEquipmentListInput input);
/// <summary>
/// 获取设备详情
/// </summary>
/// <param name="id">设备ID</param>
/// <returns>设备详情</returns>
Task<EquipmentListOutput> GetAsync(long id);
/// <summary>
/// 获取可用设备列表
/// </summary>
/// <param name="date">指定日期</param>
/// <param name="processId">工序ID可选</param>
/// <returns>可用设备列表</returns>
Task<List<EquipmentListOutput>> GetAvailableEquipmentAsync(DateTime date, long? processId = null);
/// <summary>
/// 检查设备是否可用
/// </summary>
/// <param name="equipmentId">设备ID</param>
/// <param name="date">指定日期</param>
/// <returns>是否可用</returns>
Task<bool> IsEquipmentAvailableAsync(long equipmentId, DateTime date);
/// <summary>
/// 获取需要维护的设备列表
/// </summary>
/// <param name="date">指定日期</param>
/// <returns>需要维护的设备列表</returns>
Task<List<EquipmentListOutput>> GetNeedMaintenanceAsync(DateTime date);
/// <summary>
/// 获取需要校验的设备列表
/// </summary>
/// <param name="date">指定日期</param>
/// <returns>需要校验的设备列表</returns>
Task<List<EquipmentListOutput>> GetNeedCalibrationAsync(DateTime date);
/// <summary>
/// 批量检查设备可用性
/// </summary>
/// <param name="equipmentIds">设备ID列表</param>
/// <param name="date">指定日期</param>
/// <returns>设备可用性字典</returns>
Task<Dictionary<long, bool>> BatchCheckEquipmentAvailabilityAsync(List<long> equipmentIds, DateTime date);
}

View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Output;
namespace NPP.SmartSchedue.Api.Contracts.Services.Equipment;
/// <summary>
/// 设备服务接口
/// 提供设备查询和可用性检查等功能
/// </summary>
public interface IEquipmentService
{
/// <summary>
/// 获取指定日期的可用设备列表
/// </summary>
/// <param name="date">查询日期</param>
/// <param name="processId">工序ID可选</param>
/// <returns>可用设备列表</returns>
Task<List<EquipmentBasicInfo>> GetAvailableEquipmentAsync(DateTime date, long? processId = null);
/// <summary>
/// 检查指定设备在指定日期是否可用
/// </summary>
/// <param name="equipmentId">设备ID</param>
/// <param name="date">检查日期</param>
/// <returns>是否可用</returns>
Task<bool> IsEquipmentAvailableAsync(long equipmentId, DateTime date);
/// <summary>
/// 获取指定日期范围内的设备使用统计
/// </summary>
/// <param name="startDate">开始日期</param>
/// <param name="endDate">结束日期</param>
/// <returns>设备使用统计</returns>
Task<EquipmentUsageStatistics> GetEquipmentUsageStatisticsAsync(DateTime startDate, DateTime endDate);
/// <summary>
/// 批量检查设备可用性
/// </summary>
/// <param name="equipmentIds">设备ID列表</param>
/// <param name="date">检查日期</param>
/// <returns>设备可用性结果字典</returns>
Task<Dictionary<long, bool>> BatchCheckEquipmentAvailabilityAsync(List<long> equipmentIds, DateTime date);
}

View File

@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using NPP.SmartSchedue.Api.Contracts.Services.Equipment.Dto;
namespace NPP.SmartSchedue.Api.Contracts.Services.Equipment;
/// <summary>
/// 设备统计分析服务接口
/// 提供按设备类型的统计分析功能,独立于设备分配业务逻辑
/// </summary>
public interface IEquipmentStatisticsService
{
/// <summary>
/// 按设备类型统计设备数量和状态分布
/// 深度业务场景:支持生产规划时了解各类型设备资源配置情况
/// </summary>
/// <param name="startDate">统计开始日期</param>
/// <param name="endDate">统计结束日期</param>
/// <param name="includeInactive">是否包含非活跃设备(报废、停用等)</param>
/// <returns>按设备类型分组的统计结果</returns>
Task<List<EquipmentTypeStatisticsOutput>> GetEquipmentStatisticsByTypeAsync(
DateTime? startDate = null,
DateTime? endDate = null,
bool includeInactive = false);
/// <summary>
/// 按设备类型统计使用率和工作负荷
/// 深度业务场景:支持设备使用效率分析和设备采购决策
/// </summary>
/// <param name="startDate">统计开始日期</param>
/// <param name="endDate">统计结束日期</param>
/// <returns>设备类型使用率统计</returns>
Task<List<EquipmentTypeUsageOutput>> GetEquipmentUsageByTypeAsync(
DateTime startDate,
DateTime endDate);
/// <summary>
/// 按设备类型统计任务分配情况
/// 深度业务场景:支持工艺流程分析和设备负荷均衡评估
/// </summary>
/// <param name="startDate">统计开始日期</param>
/// <param name="endDate">统计结束日期</param>
/// <param name="includeCompletedTasks">是否包含已完成任务</param>
/// <returns>设备类型任务分配统计</returns>
Task<List<EquipmentTypeTaskAllocationOutput>> GetTaskAllocationByTypeAsync(
DateTime startDate,
DateTime endDate,
bool includeCompletedTasks = true);
/// <summary>
/// 获取设备类型趋势分析数据
/// 深度业务场景:支持长期设备投资规划和维护策略制定
/// </summary>
/// <param name="equipmentType">指定设备类型null则返回所有类型</param>
/// <param name="startDate">分析开始日期</param>
/// <param name="endDate">分析结束日期</param>
/// <param name="groupByPeriod">分组周期Day, Week, Month</param>
/// <returns>设备类型趋势数据</returns>
Task<List<EquipmentTypeTrendOutput>> GetEquipmentTypeTrendAsync(
string? equipmentType,
DateTime startDate,
DateTime endDate,
string groupByPeriod = "Day");
}

View File

@ -0,0 +1,17 @@
using System.Threading.Tasks;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Input;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Output;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration
{
/// <summary>
/// 设备分配服务接口
/// </summary>
public interface IEquipmentAllocationService
{
/// <summary>
/// 智能设备分配
/// </summary>
Task<EquipmentAllocationResult> AllocateEquipmentSmartlyAsync(EquipmentAllocationInput input);
}
}

View File

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Output;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration
{
/// <summary>
/// 设备服务客户端接口
/// 用于调度模块与EAM设备管理模块之间的通信
/// 避免直接依赖EAM模块的服务接口实现模块解耦
/// </summary>
public interface IEquipmentClientService
{
/// <summary>
/// 获取指定日期的可用设备列表
/// 用于任务整合前的资源充足性检查
/// </summary>
/// <param name="date">指定日期</param>
/// <param name="processId">工序ID可选用于筛选特定工序的设备</param>
/// <returns>可用设备列表</returns>
Task<List<EquipmentBasicInfo>> GetAvailableEquipmentAsync(DateTime date, long? processId = null);
/// <summary>
/// 检查指定设备在指定日期是否可用
/// 用于验证特定设备的可用性状态
/// </summary>
/// <param name="equipmentId">设备ID</param>
/// <param name="date">指定日期</param>
/// <returns>是否可用</returns>
Task<bool> IsEquipmentAvailableAsync(long equipmentId, DateTime date);
/// <summary>
/// 获取指定日期范围内的设备使用统计
/// 用于资源容量计算和负荷分析
/// </summary>
/// <param name="startDate">开始日期</param>
/// <param name="endDate">结束日期</param>
/// <returns>设备使用统计信息</returns>
Task<EquipmentUsageStatistics> GetEquipmentUsageStatisticsAsync(DateTime startDate, DateTime endDate);
/// <summary>
/// 获取指定日期需要维护的设备列表
/// 用于计算维护中不可用的设备数量
/// </summary>
/// <param name="date">指定日期</param>
/// <returns>需要维护的设备列表</returns>
Task<List<EquipmentBasicInfo>> GetMaintenanceEquipmentAsync(DateTime date);
/// <summary>
/// 获取指定日期需要校验的设备列表
/// 用于计算校验中不可用的设备数量
/// </summary>
/// <param name="date">指定日期</param>
/// <returns>需要校验的设备列表</returns>
Task<List<EquipmentBasicInfo>> GetCalibrationEquipmentAsync(DateTime date);
/// <summary>
/// 批量检查设备可用性
/// 用于大批量任务的设备资源验证,提高查询效率
/// </summary>
/// <param name="equipmentIds">设备ID列表</param>
/// <param name="date">指定日期</param>
/// <returns>设备可用性状态字典Key为设备IDValue为是否可用</returns>
Task<Dictionary<long, bool>> BatchCheckEquipmentAvailabilityAsync(List<long> equipmentIds, DateTime date);
}
}

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Input;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Output;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Internal;
using NPP.SmartSchedue.Api.Contracts.Domain.Work;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration
{
/// <summary>
/// 全局优化人员分配服务接口
/// 基于遗传算法和基尼系数的智能全局优化分配
/// </summary>
public interface IGlobalPersonnelAllocationService
{
Task<GlobalAllocationResult> AllocatePersonnelGloballyAsync(GlobalAllocationInput input);
Task<GlobalAllocationAnalysisResult> AnalyzeAllocationFeasibilityAsync(GlobalAllocationInput input);
/// <summary>
/// 【性能优化】公共的人员可用性计算方法 - 专为遗传算法优化
/// 替代原有的反射调用消除15-20%的性能开销
/// </summary>
Task<double> CalculatePersonnelAvailabilityForGeneticAsync(
GlobalPersonnelInfo personnel, WorkOrderEntity task, List<WorkOrderEntity> contextTasks);
/// <summary>
/// 【性能优化】公共的班次规则合规性评分方法 - 专为遗传算法优化
/// 替代原有的反射调用,提升约束检查性能
/// </summary>
Task<double> CalculateShiftRuleComplianceForGeneticAsync(
long personnelId, DateTime workDate, long shiftId, GlobalAllocationContext context);
}
}

View File

@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Input;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Output;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration
{
/// <summary>
/// 整合记录服务接口
/// </summary>
public interface IIntegrationRecordService
{
/// <summary>
/// 生成整合记录
/// </summary>
Task<IntegrationRecord> GenerateIntegrationRecordAsync(IntegrationRecordInput input);
/// <summary>
/// 根据记录ID查询整合记录信息并附加任务集
/// </summary>
/// <param name="recordId">整合记录ID</param>
/// <returns>包含任务集的整合记录信息</returns>
Task<IntegrationRecordWithTasksOutput> GetIntegrationRecordWithTasksAsync(long recordId);
/// <summary>
/// 查询所有整合记录列表
/// </summary>
/// <param name="input">查询条件</param>
/// <returns>整合记录列表</returns>
Task<List<IntegrationRecordListOutput>> GetIntegrationRecordsAsync(IntegrationRecordGetListInput input);
#region
/// <summary>
/// 发布整合记录
/// 将草稿状态的整合记录发布生效,更新任务分配状态
/// </summary>
/// <param name="input">发布输入参数</param>
/// <returns>发布结果</returns>
Task<PublishIntegrationRecordResult> PublishIntegrationRecordAsync(PublishIntegrationRecordInput input);
/// <summary>
/// 更新整合记录状态
/// 支持状态转换:草稿->已发布->已完成->已撤销
/// </summary>
/// <param name="recordId">整合记录ID</param>
/// <param name="newStatus">新状态</param>
/// <param name="operatorUserId">操作员用户ID</param>
/// <param name="operatorName">操作员姓名</param>
/// <param name="remarks">状态更新说明</param>
/// <returns>更新结果</returns>
Task<bool> UpdateIntegrationRecordStatusAsync(long recordId, string newStatus, long operatorUserId, string operatorName, string remarks = "");
/// <summary>
/// 发布修改后的任务
/// 将任务的修改内容发布到生产系统
/// </summary>
/// <param name="recordId">整合记录ID</param>
/// <param name="modifiedTaskIds">修改的任务ID列表</param>
/// <param name="operatorUserId">操作员用户ID</param>
/// <param name="operatorName">操作员姓名</param>
/// <param name="publishRemarks">发布说明</param>
/// <returns>发布结果</returns>
Task<PublishIntegrationRecordResult> PublishTaskModificationsAsync(long recordId, List<long> modifiedTaskIds, long operatorUserId, string operatorName, string publishRemarks = "");
#endregion
#region
/// <summary>
/// 发送发布通知(预留接口)
/// 向相关人员发送整合记录发布的通知信息
/// </summary>
/// <param name="recordId">整合记录ID</param>
/// <param name="notificationType">通知类型</param>
/// <param name="targetPersonnelIds">目标人员ID列表</param>
/// <param name="customMessage">自定义消息</param>
/// <returns>通知发送结果</returns>
Task<NotificationSendResult> SendPublishNotificationAsync(long recordId, string notificationType, List<long> targetPersonnelIds, string customMessage = "");
/// <summary>
/// 创建待办任务(预留接口)
/// 为相关人员创建与发布记录相关的待办任务
/// </summary>
/// <param name="recordId">整合记录ID</param>
/// <param name="todoType">待办类型</param>
/// <param name="assigneeIds">负责人ID列表</param>
/// <param name="title">待办标题</param>
/// <param name="description">待办描述</param>
/// <param name="dueDate">截止时间</param>
/// <returns>创建结果</returns>
Task<CreateTodoResult> CreatePublishRelatedTodoAsync(long recordId, string todoType, List<long> assigneeIds, string title, string description, DateTime? dueDate = null);
#endregion
}
}

View File

@ -0,0 +1,14 @@
using System.Threading.Tasks;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Input;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Output;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration
{
/// <summary>
/// 人员分配服务接口
/// </summary>
public interface IPersonnelAllocationService
{
Task<PersonnelAllocationResult> AllocatePersonnelSmartlyAsync(PersonnelAllocationInput input);
}
}

View File

@ -0,0 +1,6 @@
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration;
public interface ISmartScheduleOrchestratorService
{
}

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using NPP.SmartSchedue.Api.Contracts.Core.Enums;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Input;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Output;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration
{
/// <summary>
/// 任务整合前自检服务接口
/// </summary>
public interface ITaskIntegrationPreCheckService
{
/// <summary>
/// 加载待整合的任务列表,支持多项目号筛选,按项目号分组展示
/// </summary>
Task<TaskIntegrationListOutput> LoadPendingIntegrationTasksAsync(LoadPendingTasksInput input);
/// <summary>
/// 对勾选的项目和任务进行整合前自检
/// </summary>
Task<TaskIntegrationPreCheckResult> ExecutePreCheckAsync(TaskIntegrationPreCheckInput input);
/// <summary>
/// 获取项目任务数量与可用人员数量对比(按日和周)
/// </summary>
Task<ProjectResourceComparisonResult> GetProjectResourceComparisonAsync(ProjectResourceComparisonInput input);
}
}

View File

@ -0,0 +1,29 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Input;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Output;
using NPP.SmartSchedue.Api.Contracts.Domain.Work;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration
{
/// <summary>
/// 任务验证服务接口
/// </summary>
public interface ITaskValidationService
{
/// <summary>
/// 分析任务需求
/// </summary>
Task<TaskRequirementAnalysisResult> AnalyzeTaskRequirementsAsync(List<WorkOrderEntity> tasks);
/// <summary>
/// 验证任务数据完整性
/// </summary>
Task<TaskDataValidationResult> ValidateTaskDataIntegrityAsync(List<WorkOrderEntity> tasks);
/// <summary>
/// 加载任务详细信息
/// </summary>
Task<TaskDetailLoadResult> LoadTaskDetailedInfoAsync(List<WorkOrderEntity> tasks);
}
}

View File

@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration.Input;
/// <summary>
/// 撤销整合记录输入参数
/// 包含撤销操作的所有必要信息和业务规则
///
/// 业务思考:
/// 1. 撤销是发布后的逆向操作,需要严格的权限控制
/// 2. 撤销会将任务状态从Assigned回退到PendingIntegration
/// 3. 撤销操作必须记录详细的审计信息
/// 4. 支持部分撤销,提高操作的灵活性
/// </summary>
public class CancelIntegrationRecordInput
{
/// <summary>
/// 整合记录ID
/// </summary>
[Required(ErrorMessage = "整合记录ID不能为空")]
[Range(1, long.MaxValue, ErrorMessage = "整合记录ID必须大于0")]
public long IntegrationRecordId { get; set; }
/// <summary>
/// 撤销操作员用户ID
/// </summary>
[Required(ErrorMessage = "撤销操作员用户ID不能为空")]
[Range(1, long.MaxValue, ErrorMessage = "撤销操作员用户ID必须大于0")]
public long CancelledByUserId { get; set; }
/// <summary>
/// 撤销操作员用户名
/// </summary>
[Required(ErrorMessage = "撤销操作员用户名不能为空")]
[StringLength(50, ErrorMessage = "撤销操作员用户名长度不能超过50个字符")]
public string CancelledByUserName { get; set; } = string.Empty;
/// <summary>
/// 撤销原因
/// 必填字段,用于审计和问题追踪
/// </summary>
[Required(ErrorMessage = "撤销原因不能为空")]
[StringLength(500, ErrorMessage = "撤销原因长度不能超过500个字符")]
public string CancelReason { get; set; } = string.Empty;
/// <summary>
/// 是否强制撤销
/// 当存在已开始执行的任务时,是否强制撤销
/// 需要更高级别的权限
/// </summary>
public bool ForceCancelInProgressTasks { get; set; } = false;
/// <summary>
/// 是否通知相关人员
/// 撤销后是否通知已分配的人员和设备管理员
/// </summary>
public bool NotifyRelatedPersonnel { get; set; } = true;
/// <summary>
/// 撤销范围限制
/// 指定只撤销特定任务null表示撤销整合记录中的所有任务
///
/// 业务价值:
/// - 支持部分撤销功能,提高撤销的灵活性
/// - 当某些任务需要重新分配时,可以单独撤销
/// - 减少对正常执行任务的影响
/// </summary>
public List<long>? SpecificTaskIds { get; set; }
/// <summary>
/// 撤销后处理方式
/// 控制撤销后任务的处理方式
/// </summary>
public CancelAfterProcessingType AfterProcessingType { get; set; } = CancelAfterProcessingType.ReturnToPendingIntegration;
}
/// <summary>
/// 撤销后处理方式枚举
/// </summary>
public enum CancelAfterProcessingType
{
/// <summary>
/// 回退到待整合状态
/// 任务状态回退到PendingIntegration等待重新整合
/// </summary>
ReturnToPendingIntegration = 0,
/// <summary>
/// 标记为需要重新分配
/// 任务保持在特殊状态,需要手动处理
/// </summary>
MarkForReassignment = 1,
/// <summary>
/// 暂停任务
/// 将任务状态设置为暂停,等待进一步决策
/// </summary>
PauseTasks = 2
}

View File

@ -0,0 +1,194 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using NPP.SmartSchedue.Api.Contracts.Domain.Work;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration.Input
{
/// <summary>
/// 全局优化分配输入
/// </summary>
public class GlobalAllocationInput
{
/// <summary>
/// 待分配的任务ID列表当Tasks为空时使用
/// </summary>
public List<long> TaskIds { get; set; } = new();
/// <summary>
/// 待分配的任务对象列表(性能优化:避免重复数据库查询)
/// </summary>
public List<WorkOrderEntity> Tasks { get; set; } = new();
/// <summary>
/// 排除的人员ID列表
/// </summary>
public List<long> ExcludedPersonnelIds { get; set; } = new();
/// <summary>
/// 全局优化配置
/// </summary>
public GlobalOptimizationConfig OptimizationConfig { get; set; } = new();
}
/// <summary>
/// 全局优化配置
/// </summary>
public class GlobalOptimizationConfig
{
/// <summary>
/// 遗传算法种群大小
/// 生产环境推荐:小规模(20任务)使用50-100中规模(50-100任务)使用80-150
/// </summary>
[Range(50, 500, ErrorMessage = "种群大小应在50-500之间")]
public int PopulationSize { get; set; } = 100; // 从200降低到100适合100任务规模
/// <summary>
/// 最大迭代代数
/// 生产环境推荐:由于预筛选机制,可以适当减少迭代次数
/// </summary>
[Range(20, 200, ErrorMessage = "迭代代数应在20-200之间")]
public int MaxGenerations { get; set; } = 60; // 从100降低到60在质量和性能间平衡
/// <summary>
/// 最大执行时间(秒)
/// 生产环境为100任务增加更宽裕的时间限制
/// </summary>
[Range(5, 300, ErrorMessage = "执行时间应在5-300秒之间")]
public int MaxExecutionTimeSeconds { get; set; } = 120; // 从30秒增加到120秒适应100任务的复杂度
/// <summary>
/// 基尼系数公平性权重0-1
/// </summary>
[Range(0.0, 1.0, ErrorMessage = "公平性权重应在0-1之间")]
public double FairnessWeight { get; set; } = 0.3;
/// <summary>
/// 约束满足权重0-1
/// </summary>
[Range(0.0, 1.0, ErrorMessage = "约束权重应在0-1之间")]
public double ConstraintWeight { get; set; } = 0.6;
/// <summary>
/// 资质匹配权重0-1
/// </summary>
[Range(0.0, 1.0, ErrorMessage = "资质权重应在0-1之间")]
public double QualificationWeight { get; set; } = 0.1;
/// <summary>
/// 是否启用智能协商
/// </summary>
public bool EnableIntelligentNegotiation { get; set; } = true;
/// <summary>
/// 收敛阈值
/// </summary>
[Range(0.001, 0.1, ErrorMessage = "收敛阈值应在0.001-0.1之间")]
public double ConvergenceThreshold { get; set; } = 0.001;
/// <summary>
/// 创建适合生产环境的优化配置
/// 适用7天100任务30人员的大规模调度场景
/// </summary>
/// <param name="taskCount">任务数量</param>
/// <param name="personnelCount">人员数量</param>
/// <returns>优化后的配置</returns>
public static GlobalOptimizationConfig CreateProductionConfig(int taskCount, int personnelCount)
{
var config = new GlobalOptimizationConfig();
// 根据任务规模动态调整参数
if (taskCount <= 20)
{
// 小规模超快速模式针对6个任务优化
if (taskCount <= 6)
{
config.PopulationSize = 15; // 从50降到15减少计算量
config.MaxGenerations = 10; // 从30降到10快速收敛
config.MaxExecutionTimeSeconds = 15; // 从60降到15秒
}
else
{
config.PopulationSize = 30; // 7-20任务使用中等参数
config.MaxGenerations = 20;
config.MaxExecutionTimeSeconds = 30;
}
}
else if (taskCount <= 50)
{
// 中规模:平衡模式
config.PopulationSize = 80;
config.MaxGenerations = 50;
config.MaxExecutionTimeSeconds = 90;
}
else if (taskCount <= 100)
{
// 大规模:高质量模式(适合生产环境)
config.PopulationSize = 100;
config.MaxGenerations = 60;
config.MaxExecutionTimeSeconds = 120;
}
else
{
// 超大规模:保守模式
config.PopulationSize = Math.Min(150, taskCount + 50);
config.MaxGenerations = 80;
config.MaxExecutionTimeSeconds = 180;
}
// 根据人员数量调整权重
if (personnelCount < 20)
{
// 人员较少,提高公平性权重
config.FairnessWeight = 0.4;
config.ConstraintWeight = 0.5;
config.QualificationWeight = 0.1;
}
else
{
// 人员充足,保持默认权重
config.FairnessWeight = 0.3;
config.ConstraintWeight = 0.6;
config.QualificationWeight = 0.1;
}
return config;
}
/// <summary>
/// 创建快速测试配置(用于开发和测试环境)
/// </summary>
/// <returns>快速测试配置</returns>
public static GlobalOptimizationConfig CreateFastTestConfig()
{
return new GlobalOptimizationConfig
{
PopulationSize = 30,
MaxGenerations = 20,
MaxExecutionTimeSeconds = 30,
FairnessWeight = 0.2,
ConstraintWeight = 0.7,
QualificationWeight = 0.1,
ConvergenceThreshold = 0.01 // 更宽松的收敛条件以加速测试
};
}
/// <summary>
/// 创建高质量配置(用于关键业务场景)
/// </summary>
/// <returns>高质量配置</returns>
public static GlobalOptimizationConfig CreateHighQualityConfig()
{
return new GlobalOptimizationConfig
{
PopulationSize = 200,
MaxGenerations = 100,
MaxExecutionTimeSeconds = 300,
FairnessWeight = 0.35,
ConstraintWeight = 0.55,
QualificationWeight = 0.1,
ConvergenceThreshold = 0.0005
};
}
}
}

View File

@ -0,0 +1,39 @@
using System;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration.Input;
/// <summary>
/// 整合记录列表查询输入
/// </summary>
public class IntegrationRecordGetListInput
{
/// <summary>
/// 整合批次编码
/// </summary>
public string IntegrationBatchCode { get; set; }
/// <summary>
/// 项目编号
/// </summary>
public string ProjectNumber { get; set; }
/// <summary>
/// 操作员用户名
/// </summary>
public string OperatorUserName { get; set; }
/// <summary>
/// 操作员真实姓名
/// </summary>
public string OperatorRealName { get; set; }
/// <summary>
/// 开始日期
/// </summary>
public DateTime? StartDate { get; set; }
/// <summary>
/// 结束日期
/// </summary>
public DateTime? EndDate { get; set; }
}

View File

@ -0,0 +1,81 @@
using System.Collections.Generic;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration.Input;
/// <summary>
/// 整合记录任务修改输入
/// 用于手动修改整合记录中的任务分配信息
/// </summary>
public class IntegrationRecordTaskModifyInput
{
/// <summary>
/// 整合记录ID
/// </summary>
public long IntegrationRecordId { get; set; }
/// <summary>
/// 操作员用户ID
/// </summary>
public long OperatorUserId { get; set; }
/// <summary>
/// 操作员用户名
/// </summary>
public string OperatorUserName { get; set; } = string.Empty;
/// <summary>
/// 任务修改列表
/// </summary>
public List<TaskModificationInput> TaskModifications { get; set; } = new();
/// <summary>
/// 修改原因说明
/// </summary>
public string ModificationReason { get; set; } = string.Empty;
/// <summary>
/// 是否强制执行(忽略部分警告)
/// </summary>
public bool ForceExecute { get; set; } = false;
}
/// <summary>
/// 单个任务修改输入
/// </summary>
public class TaskModificationInput
{
/// <summary>
/// 任务ID
/// </summary>
public long TaskId { get; set; }
/// <summary>
/// 任务代码(可选,用于显示)
/// </summary>
public string? TaskCode { get; set; }
/// <summary>
/// 新的人员ID可选
/// </summary>
public long? NewPersonnelId { get; set; }
/// <summary>
/// 新的人员姓名(可选)
/// </summary>
public string? NewPersonnelName { get; set; }
/// <summary>
/// 新的设备ID可选
/// </summary>
public long? NewEquipmentId { get; set; }
/// <summary>
/// 新的设备名称(可选)
/// </summary>
public string? NewEquipmentName { get; set; }
/// <summary>
/// 修改备注
/// </summary>
public string ModificationNote { get; set; } = string.Empty;
}

View File

@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using NPP.SmartSchedue.Api.Contracts.Core.Enums;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration.Input
{
/// <summary>
/// 加载待整合任务输入
/// </summary>
public class LoadPendingTasksInput
{
/// <summary>
/// 项目号列表(支持多个项目号筛选)
/// </summary>
public List<string> ProjectNumbers { get; set; } = new();
/// <summary>
/// 任务日期范围
/// </summary>
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
/// <summary>
/// 工序代码列表
/// </summary>
public List<string> ProcessCodes { get; set; } = new();
/// <summary>
/// 班次ID列表
/// </summary>
public List<long> ShiftIds { get; set; } = new();
/// <summary>
/// 任务状态(默认查询待整合状态)
/// </summary>
public WorkOrderStatusEnum Status { get; set; } = WorkOrderStatusEnum.PendingIntegration;
/// <summary>
/// 分页参数
/// </summary>
public int PageIndex { get; set; } = 1;
public int PageSize { get; set; } = 50;
}
/// <summary>
/// 任务整合前自检输入
/// </summary>
public class TaskIntegrationPreCheckInput
{
/// <summary>
/// 选中的项目号列表
/// </summary>
public List<string> SelectedProjectNumbers { get; set; } = new();
/// <summary>
/// 选中的任务ID列表
/// </summary>
public List<long> SelectedTaskIds { get; set; } = new();
/// <summary>
/// 是否检查人员资源充足性
/// </summary>
public bool CheckPersonnelSufficiency { get; set; } = true;
/// <summary>
/// 是否检查设备资源充足性
/// </summary>
public bool CheckEquipmentSufficiency { get; set; } = true;
/// <summary>
/// 检查的时间范围(按日和周)
/// </summary>
public DateTime CheckStartDate { get; set; }
public DateTime CheckEndDate { get; set; }
}
/// <summary>
/// 项目资源对比输入
/// </summary>
public class ProjectResourceComparisonInput
{
/// <summary>
/// 项目号列表
/// </summary>
public List<string> ProjectNumbers { get; set; } = new();
/// <summary>
/// 对比时间范围
/// </summary>
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
/// <summary>
/// 对比维度(按日、按周)
/// </summary>
public ComparisonDimension Dimension { get; set; } = ComparisonDimension.Daily;
}
/// <summary>
/// 对比维度枚举
/// </summary>
public enum ComparisonDimension
{
/// <summary>
/// 按日对比
/// </summary>
Daily = 1,
/// <summary>
/// 按周对比
/// </summary>
Weekly = 2
}
}

View File

@ -0,0 +1,805 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration.Input
{
/// <summary>
/// 智能人员分配优化权重配置
/// 五层决策模型第三层:优化决策阶段的核心权重配置
/// 支持多策略、多场景、动态调整的智能权重管理
/// 深度业务思考:平衡效率、公平性、连续性、专业性等多维度目标
/// </summary>
public class OptimizationWeights
{
#region
/// <summary>
/// 指定人员优先权重 (0.0-1.0)
/// 业务含义:当任务有明确指定人员时的优先级权重
/// 适用场景:特殊技能需求、客户指定、专项任务等
/// </summary>
[Range(0.0, 1.0, ErrorMessage = "指定人员权重必须在0.0-1.0范围内")]
public double AssignedPersonnelWeight { get; set; } = 0.8;
/// <summary>
/// 项目FL人员优先权重 (0.0-1.0)
/// 业务含义项目内部FL(First Line)人员的优先级权重
/// 适用场景:项目连续性、知识传承、团队稳定性
/// </summary>
[Range(0.0, 1.0, ErrorMessage = "项目FL人员权重必须在0.0-1.0范围内")]
public double ProjectFLWeight { get; set; } = 0.6;
/// <summary>
/// 工作负载均衡权重 (0.0-1.0)
/// 业务含义:人员工作负载分布均衡的重要性权重
/// 适用场景:公平分配、避免过劳、提升团队稳定性
/// </summary>
[Range(0.0, 1.0, ErrorMessage = "工作负载均衡权重必须在0.0-1.0范围内")]
public double WorkloadBalanceWeight { get; set; } = 0.4;
/// <summary>
/// 班次连续性权重 (0.0-1.0)
/// 业务含义:保持人员班次连续性和规律性的权重
/// 适用场景:生物钟保护、工作效率优化、人员健康管理
/// </summary>
[Range(0.0, 1.0, ErrorMessage = "班次连续性权重必须在0.0-1.0范围内")]
public double ShiftContinuityWeight { get; set; } = 0.3;
/// <summary>
/// 技能匹配优先权重 (0.0-1.0)
/// 业务含义:人员技能与任务需求匹配度的权重
/// 适用场景:质量保证、效率提升、风险控制
/// </summary>
[Range(0.0, 1.0, ErrorMessage = "技能匹配权重必须在0.0-1.0范围内")]
public double SkillMatchWeight { get; set; } = 0.5;
/// <summary>
/// 协作历史权重 (0.0-1.0)
/// 业务含义:人员在相关项目的历史协作经验权重
/// 适用场景:团队默契、沟通效率、项目风险降低
/// </summary>
[Range(0.0, 1.0, ErrorMessage = "协作历史权重必须在0.0-1.0范围内")]
public double CollaborationHistoryWeight { get; set; } = 0.2;
#endregion
#region
/// <summary>
/// 成本效益权重 (0.0-1.0)
/// 业务含义:考虑人员成本与任务价值匹配的权重
/// 适用场景成本控制、资源优化配置、ROI最大化
/// </summary>
[Range(0.0, 1.0, ErrorMessage = "成本效益权重必须在0.0-1.0范围内")]
public double CostEfficiencyWeight { get; set; } = 0.3;
/// <summary>
/// 地理位置便利性权重 (0.0-1.0)
/// 业务含义:人员地理位置与工作地点便利性的权重
/// 适用场景:交通成本、响应速度、突发事件处理
/// </summary>
[Range(0.0, 1.0, ErrorMessage = "地理位置便利性权重必须在0.0-1.0范围内")]
public double LocationConvenienceWeight { get; set; } = 0.2;
/// <summary>
/// 培训发展权重 (0.0-1.0)
/// 业务含义:为人员提供学习和发展机会的权重
/// 适用场景:人才培养、技能提升、职业发展规划
/// </summary>
[Range(0.0, 1.0, ErrorMessage = "培训发展权重必须在0.0-1.0范围内")]
public double TrainingDevelopmentWeight { get; set; } = 0.1;
/// <summary>
/// 紧急响应能力权重 (0.0-1.0)
/// 业务含义:人员处理紧急情况能力的权重
/// 适用场景:应急任务、关键节点、风险管控
/// </summary>
[Range(0.0, 1.0, ErrorMessage = "紧急响应能力权重必须在0.0-1.0范围内")]
public double EmergencyResponseWeight { get; set; } = 0.4;
#endregion
#region
/// <summary>
/// 权重配置名称
/// 用于识别和管理不同的权重配置方案
/// </summary>
[Required(ErrorMessage = "权重配置名称不能为空")]
[StringLength(100, ErrorMessage = "权重配置名称长度不能超过100字符")]
public string ConfigurationName { get; set; } = "默认配置";
/// <summary>
/// 权重配置描述
/// 详细说明该配置的适用场景和特点
/// </summary>
[StringLength(500, ErrorMessage = "权重配置描述长度不能超过500字符")]
public string Description { get; set; } = string.Empty;
/// <summary>
/// 配置策略类型
/// 标识该权重配置所属的分配策略类型
/// </summary>
public OptimizationStrategy StrategyType { get; set; } = OptimizationStrategy.Balanced;
/// <summary>
/// 是否为系统预设配置
/// 标识是否为系统内置的标准配置
/// </summary>
public bool IsSystemPreset { get; set; } = false;
/// <summary>
/// 配置创建者ID
/// 记录创建该配置的用户或系统标识
/// </summary>
public long? CreatedBy { get; set; }
/// <summary>
/// 配置创建时间
/// </summary>
public DateTime CreatedTime { get; set; } = DateTime.Now;
/// <summary>
/// 最后修改时间
/// </summary>
public DateTime LastModifiedTime { get; set; } = DateTime.Now;
/// <summary>
/// 配置版本号
/// 用于跟踪配置的变更历史
/// </summary>
public string Version { get; set; } = "1.0.0";
#endregion
#region
/// <summary>
/// 自定义权重规则
/// 支持用户定义的特殊权重计算规则
/// </summary>
public Dictionary<string, CustomWeightRule> CustomWeightRules { get; set; } = new();
/// <summary>
/// 权重动态调整配置
/// 根据实时条件动态调整权重的规则配置
/// </summary>
public DynamicWeightAdjustment DynamicAdjustment { get; set; } = new();
/// <summary>
/// 权重约束条件
/// 定义权重配置必须满足的约束条件
/// </summary>
public WeightConstraints Constraints { get; set; } = new();
/// <summary>
/// 权重归一化方式
/// 定义如何对权重进行标准化处理
/// </summary>
public WeightNormalizationMethod NormalizationMethod { get; set; } = WeightNormalizationMethod.ProportionalSum;
#endregion
#region
/// <summary>
/// 验证权重配置的有效性
/// 深度业务思考:确保权重配置符合业务逻辑和数学约束
/// </summary>
public WeightValidationResult ValidateConfiguration()
{
var result = new WeightValidationResult { IsValid = true, Issues = new List<string>() };
try
{
// 1. 基础范围验证通过DataAnnotations已覆盖
var properties = GetType().GetProperties()
.Where(p => p.PropertyType == typeof(double) && p.Name.EndsWith("Weight"));
foreach (var prop in properties)
{
var value = (double)prop.GetValue(this);
if (value < 0.0 || value > 1.0)
{
result.IsValid = false;
result.Issues.Add($"{prop.Name} 值 {value} 超出有效范围 [0.0, 1.0]");
}
}
// 2. 权重总和合理性检查
var totalWeight = GetTotalWeight();
if (totalWeight < 0.1)
{
result.Issues.Add($"权重总和过低 ({totalWeight:F2}),可能导致分配结果不稳定");
}
else if (totalWeight > 5.0)
{
result.Issues.Add($"权重总和过高 ({totalWeight:F2}),建议进行归一化处理");
}
// 3. 业务逻辑一致性检查
if (AssignedPersonnelWeight < 0.5 && StrategyType == OptimizationStrategy.AssignedPersonnelFirst)
{
result.Issues.Add("指定人员优先策略下指定人员权重应不低于0.5");
}
if (WorkloadBalanceWeight < 0.6 && StrategyType == OptimizationStrategy.LoadBalanceFirst)
{
result.Issues.Add("负载均衡优先策略下工作负载均衡权重应不低于0.6");
}
// 4. 约束条件检查
if (Constraints != null)
{
var constraintResult = Constraints.ValidateConstraints(this);
if (!constraintResult.IsValid)
{
result.IsValid = false;
result.Issues.AddRange(constraintResult.Issues);
}
}
return result;
}
catch (Exception ex)
{
result.IsValid = false;
result.Issues.Add($"权重配置验证异常:{ex.Message}");
return result;
}
}
/// <summary>
/// 获取权重总和
/// </summary>
public double GetTotalWeight()
{
return AssignedPersonnelWeight + ProjectFLWeight + WorkloadBalanceWeight +
ShiftContinuityWeight + SkillMatchWeight + CollaborationHistoryWeight +
CostEfficiencyWeight + LocationConvenienceWeight + TrainingDevelopmentWeight +
EmergencyResponseWeight;
}
/// <summary>
/// 归一化权重配置
/// 将所有权重按比例调整到指定的总和
/// </summary>
public void NormalizeWeights(double targetSum = 1.0)
{
var currentSum = GetTotalWeight();
if (currentSum <= 0) return;
var factor = targetSum / currentSum;
AssignedPersonnelWeight *= factor;
ProjectFLWeight *= factor;
WorkloadBalanceWeight *= factor;
ShiftContinuityWeight *= factor;
SkillMatchWeight *= factor;
CollaborationHistoryWeight *= factor;
CostEfficiencyWeight *= factor;
LocationConvenienceWeight *= factor;
TrainingDevelopmentWeight *= factor;
EmergencyResponseWeight *= factor;
LastModifiedTime = DateTime.Now;
}
/// <summary>
/// 转换为字典格式
/// 用于与现有系统的权重配置格式兼容
/// </summary>
public Dictionary<string, double> ToDictionary()
{
return new Dictionary<string, double>
{
["AssignedPersonnel"] = AssignedPersonnelWeight,
["ProjectFL"] = ProjectFLWeight,
["WorkloadBalance"] = WorkloadBalanceWeight,
["ShiftContinuity"] = ShiftContinuityWeight,
["SkillMatch"] = SkillMatchWeight,
["CollaborationHistory"] = CollaborationHistoryWeight,
["CostEfficiency"] = CostEfficiencyWeight,
["LocationConvenience"] = LocationConvenienceWeight,
["TrainingDevelopment"] = TrainingDevelopmentWeight,
["EmergencyResponse"] = EmergencyResponseWeight
};
}
/// <summary>
/// 从字典加载权重配置
/// </summary>
public void LoadFromDictionary(Dictionary<string, double> weights)
{
if (weights == null) return;
AssignedPersonnelWeight = weights.GetValueOrDefault("AssignedPersonnel", AssignedPersonnelWeight);
ProjectFLWeight = weights.GetValueOrDefault("ProjectFL", ProjectFLWeight);
WorkloadBalanceWeight = weights.GetValueOrDefault("WorkloadBalance", WorkloadBalanceWeight);
ShiftContinuityWeight = weights.GetValueOrDefault("ShiftContinuity", ShiftContinuityWeight);
SkillMatchWeight = weights.GetValueOrDefault("SkillMatch", SkillMatchWeight);
CollaborationHistoryWeight = weights.GetValueOrDefault("CollaborationHistory", CollaborationHistoryWeight);
CostEfficiencyWeight = weights.GetValueOrDefault("CostEfficiency", CostEfficiencyWeight);
LocationConvenienceWeight = weights.GetValueOrDefault("LocationConvenience", LocationConvenienceWeight);
TrainingDevelopmentWeight = weights.GetValueOrDefault("TrainingDevelopment", TrainingDevelopmentWeight);
EmergencyResponseWeight = weights.GetValueOrDefault("EmergencyResponse", EmergencyResponseWeight);
LastModifiedTime = DateTime.Now;
}
/// <summary>
/// 深拷贝权重配置
/// </summary>
public OptimizationWeights DeepClone()
{
return new OptimizationWeights
{
AssignedPersonnelWeight = AssignedPersonnelWeight,
ProjectFLWeight = ProjectFLWeight,
WorkloadBalanceWeight = WorkloadBalanceWeight,
ShiftContinuityWeight = ShiftContinuityWeight,
SkillMatchWeight = SkillMatchWeight,
CollaborationHistoryWeight = CollaborationHistoryWeight,
CostEfficiencyWeight = CostEfficiencyWeight,
LocationConvenienceWeight = LocationConvenienceWeight,
TrainingDevelopmentWeight = TrainingDevelopmentWeight,
EmergencyResponseWeight = EmergencyResponseWeight,
ConfigurationName = ConfigurationName + "_Copy",
Description = Description,
StrategyType = StrategyType,
IsSystemPreset = false,
CreatedBy = CreatedBy,
CreatedTime = DateTime.Now,
LastModifiedTime = DateTime.Now,
Version = "1.0.0",
CustomWeightRules = new Dictionary<string, CustomWeightRule>(CustomWeightRules),
DynamicAdjustment = DynamicAdjustment?.DeepClone(),
Constraints = Constraints?.DeepClone(),
NormalizationMethod = NormalizationMethod
};
}
#endregion
#region
/// <summary>
/// 创建效率优先配置
/// 适用场景:紧急任务、关键交付、高价值项目
/// </summary>
public static OptimizationWeights CreateEfficiencyFirstConfiguration()
{
return new OptimizationWeights
{
ConfigurationName = "效率优先配置",
Description = "优先考虑技能匹配和协作历史,适用于紧急任务和关键交付",
StrategyType = OptimizationStrategy.EfficiencyFirst,
IsSystemPreset = true,
AssignedPersonnelWeight = 0.9,
SkillMatchWeight = 0.8,
CollaborationHistoryWeight = 0.7,
ProjectFLWeight = 0.6,
EmergencyResponseWeight = 0.8,
WorkloadBalanceWeight = 0.2,
ShiftContinuityWeight = 0.2,
CostEfficiencyWeight = 0.3,
LocationConvenienceWeight = 0.1,
TrainingDevelopmentWeight = 0.1
};
}
/// <summary>
/// 创建公平分配配置
/// 适用场景:日常任务、团队建设、长期项目
/// </summary>
public static OptimizationWeights CreateFairDistributionConfiguration()
{
return new OptimizationWeights
{
ConfigurationName = "公平分配配置",
Description = "注重工作负载均衡和培训发展,适用于日常任务和团队建设",
StrategyType = OptimizationStrategy.FairDistribution,
IsSystemPreset = true,
WorkloadBalanceWeight = 0.8,
TrainingDevelopmentWeight = 0.6,
SkillMatchWeight = 0.5,
ShiftContinuityWeight = 0.5,
ProjectFLWeight = 0.4,
CollaborationHistoryWeight = 0.3,
AssignedPersonnelWeight = 0.3,
CostEfficiencyWeight = 0.4,
LocationConvenienceWeight = 0.3,
EmergencyResponseWeight = 0.2
};
}
/// <summary>
/// 创建连续性优先配置
/// 适用场景:轮班制工作、健康管理、规律性要求高的任务
/// </summary>
public static OptimizationWeights CreateContinuityFirstConfiguration()
{
return new OptimizationWeights
{
ConfigurationName = "连续性优先配置",
Description = "强调班次连续性和人员稳定性,适用于轮班制和规律性要求高的工作",
StrategyType = OptimizationStrategy.ContinuityFirst,
IsSystemPreset = true,
ShiftContinuityWeight = 0.9,
ProjectFLWeight = 0.7,
CollaborationHistoryWeight = 0.6,
WorkloadBalanceWeight = 0.6,
SkillMatchWeight = 0.5,
LocationConvenienceWeight = 0.4,
AssignedPersonnelWeight = 0.4,
CostEfficiencyWeight = 0.3,
TrainingDevelopmentWeight = 0.2,
EmergencyResponseWeight = 0.3
};
}
#endregion
}
#region
/// <summary>
/// 优化策略类型枚举
/// </summary>
public enum OptimizationStrategy
{
/// <summary>
/// 平衡策略
/// </summary>
Balanced = 0,
/// <summary>
/// 效率优先
/// </summary>
EfficiencyFirst = 1,
/// <summary>
/// 公平分配
/// </summary>
FairDistribution = 2,
/// <summary>
/// 连续性优先
/// </summary>
ContinuityFirst = 3,
/// <summary>
/// 指定人员优先
/// </summary>
AssignedPersonnelFirst = 4,
/// <summary>
/// 负载均衡优先
/// </summary>
LoadBalanceFirst = 5,
/// <summary>
/// 技能匹配优先
/// </summary>
SkillMatchFirst = 6,
/// <summary>
/// 成本优化
/// </summary>
CostOptimized = 7,
/// <summary>
/// 自定义策略
/// </summary>
Custom = 99
}
/// <summary>
/// 权重归一化方法
/// </summary>
public enum WeightNormalizationMethod
{
/// <summary>
/// 不进行归一化
/// </summary>
None = 0,
/// <summary>
/// 按比例归一化到总和为1
/// </summary>
ProportionalSum = 1,
/// <summary>
/// 按最大值归一化
/// </summary>
MaxValue = 2,
/// <summary>
/// 按标准差归一化
/// </summary>
StandardDeviation = 3
}
/// <summary>
/// 权重验证结果
/// </summary>
public class WeightValidationResult
{
/// <summary>
/// 验证是否通过
/// </summary>
public bool IsValid { get; set; }
/// <summary>
/// 验证问题列表
/// </summary>
public List<string> Issues { get; set; } = new();
/// <summary>
/// 验证建议
/// </summary>
public List<string> Suggestions { get; set; } = new();
}
/// <summary>
/// 自定义权重规则
/// </summary>
public class CustomWeightRule
{
/// <summary>
/// 规则名称
/// </summary>
public string RuleName { get; set; } = string.Empty;
/// <summary>
/// 规则表达式
/// </summary>
public string RuleExpression { get; set; } = string.Empty;
/// <summary>
/// 规则权重
/// </summary>
public double Weight { get; set; }
/// <summary>
/// 是否启用
/// </summary>
public bool IsEnabled { get; set; } = true;
/// <summary>
/// 规则描述
/// </summary>
public string Description { get; set; } = string.Empty;
}
/// <summary>
/// 动态权重调整配置
/// </summary>
public class DynamicWeightAdjustment
{
/// <summary>
/// 是否启用动态调整
/// </summary>
public bool IsEnabled { get; set; } = false;
/// <summary>
/// 调整触发条件
/// </summary>
public List<AdjustmentTrigger> Triggers { get; set; } = new();
/// <summary>
/// 调整规则
/// </summary>
public List<AdjustmentRule> Rules { get; set; } = new();
/// <summary>
/// 最大调整幅度
/// </summary>
public double MaxAdjustmentRange { get; set; } = 0.3;
/// <summary>
/// 深拷贝
/// </summary>
public DynamicWeightAdjustment DeepClone()
{
return new DynamicWeightAdjustment
{
IsEnabled = IsEnabled,
Triggers = new List<AdjustmentTrigger>(Triggers),
Rules = new List<AdjustmentRule>(Rules),
MaxAdjustmentRange = MaxAdjustmentRange
};
}
}
/// <summary>
/// 调整触发条件
/// </summary>
public class AdjustmentTrigger
{
/// <summary>
/// 触发条件名称
/// </summary>
public string TriggerName { get; set; } = string.Empty;
/// <summary>
/// 触发条件表达式
/// </summary>
public string ConditionExpression { get; set; } = string.Empty;
/// <summary>
/// 触发阈值
/// </summary>
public double Threshold { get; set; }
}
/// <summary>
/// 调整规则
/// </summary>
public class AdjustmentRule
{
/// <summary>
/// 目标权重字段
/// </summary>
public string TargetWeightField { get; set; } = string.Empty;
/// <summary>
/// 调整方式
/// </summary>
public AdjustmentType AdjustmentType { get; set; } = AdjustmentType.Multiply;
/// <summary>
/// 调整值
/// </summary>
public double AdjustmentValue { get; set; }
}
/// <summary>
/// 调整方式枚举
/// </summary>
public enum AdjustmentType
{
/// <summary>
/// 加法调整
/// </summary>
Add = 1,
/// <summary>
/// 乘法调整
/// </summary>
Multiply = 2,
/// <summary>
/// 设置固定值
/// </summary>
SetValue = 3
}
/// <summary>
/// 权重约束条件
/// </summary>
public class WeightConstraints
{
/// <summary>
/// 总权重最小值
/// </summary>
public double MinTotalWeight { get; set; } = 0.1;
/// <summary>
/// 总权重最大值
/// </summary>
public double MaxTotalWeight { get; set; } = 10.0;
/// <summary>
/// 必须权重字段
/// 这些权重字段不能为0
/// </summary>
public List<string> RequiredWeightFields { get; set; } = new();
/// <summary>
/// 互斥权重组
/// 同组内只能有一个权重大于指定阈值
/// </summary>
public List<MutuallyExclusiveWeightGroup> MutuallyExclusiveGroups { get; set; } = new();
/// <summary>
/// 验证约束条件
/// </summary>
public WeightValidationResult ValidateConstraints(OptimizationWeights weights)
{
var result = new WeightValidationResult { IsValid = true, Issues = new List<string>() };
// 验证总权重范围
var totalWeight = weights.GetTotalWeight();
if (totalWeight < MinTotalWeight)
{
result.IsValid = false;
result.Issues.Add($"总权重 {totalWeight:F2} 低于最小值 {MinTotalWeight:F2}");
}
if (totalWeight > MaxTotalWeight)
{
result.IsValid = false;
result.Issues.Add($"总权重 {totalWeight:F2} 超过最大值 {MaxTotalWeight:F2}");
}
// 验证必须权重字段
var weightDict = weights.ToDictionary();
foreach (var requiredField in RequiredWeightFields)
{
if (weightDict.TryGetValue(requiredField, out var value) && value <= 0)
{
result.IsValid = false;
result.Issues.Add($"必须权重字段 {requiredField} 不能为0");
}
}
// 验证互斥权重组
foreach (var group in MutuallyExclusiveGroups)
{
var highWeightFields = group.WeightFields
.Where(field => weightDict.TryGetValue(field, out var value) && value > group.Threshold)
.ToList();
if (highWeightFields.Count > 1)
{
result.IsValid = false;
result.Issues.Add($"互斥权重组 {group.GroupName} 中有多个字段超过阈值:{string.Join(", ", highWeightFields)}");
}
}
return result;
}
/// <summary>
/// 深拷贝
/// </summary>
public WeightConstraints DeepClone()
{
return new WeightConstraints
{
MinTotalWeight = MinTotalWeight,
MaxTotalWeight = MaxTotalWeight,
RequiredWeightFields = new List<string>(RequiredWeightFields),
MutuallyExclusiveGroups = MutuallyExclusiveGroups.Select(g => g.DeepClone()).ToList()
};
}
}
/// <summary>
/// 互斥权重组
/// </summary>
public class MutuallyExclusiveWeightGroup
{
/// <summary>
/// 组名称
/// </summary>
public string GroupName { get; set; } = string.Empty;
/// <summary>
/// 权重字段列表
/// </summary>
public List<string> WeightFields { get; set; } = new();
/// <summary>
/// 阈值
/// </summary>
public double Threshold { get; set; } = 0.5;
/// <summary>
/// 深拷贝
/// </summary>
public MutuallyExclusiveWeightGroup DeepClone()
{
return new MutuallyExclusiveWeightGroup
{
GroupName = GroupName,
WeightFields = new List<string>(WeightFields),
Threshold = Threshold
};
}
}
#endregion
}

View File

@ -0,0 +1,366 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Input;
using System.Linq;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Models; // Added for .Any() and .Intersect()
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration.Input
{
/// <summary>
/// 人员分配推荐输入参数
/// 用于智能推荐系统中获取最优人员分配方案的输入数据
/// 支持多种推荐策略、批量任务处理和灵活配置选项
/// </summary>
public class PersonnelAllocationRecommendationInput
{
#region
/// <summary>
/// 工作任务ID列表
/// 需要推荐人员分配的具体工作任务
/// </summary>
[Required(ErrorMessage = "工作任务ID列表不能为空")]
[MinLength(1, ErrorMessage = "至少需要一个工作任务")]
public List<long> WorkOrderIds { get; set; } = new();
/// <summary>
/// 推荐策略
/// 控制推荐算法的优先级和侧重点
/// </summary>
public PersonnelAllocationStrategy Strategy { get; set; } = PersonnelAllocationStrategy.FairDistribution;
#endregion
#region
/// <summary>
/// 每个任务的推荐人数
/// 为每个任务推荐的前N个候选人员数量
/// </summary>
[Range(1, 10, ErrorMessage = "推荐人数应在1-10之间")]
public int RecommendationCount { get; set; } = 3;
/// <summary>
/// 是否包含详细评分
/// 在推荐结果中包含各维度的详细评分信息
/// </summary>
public bool IncludeDetailedScores { get; set; } = true;
/// <summary>
/// 是否包含风险评估
/// 在推荐结果中包含潜在风险和冲突检测
/// </summary>
public bool IncludeRiskAssessment { get; set; } = true;
/// <summary>
/// 是否包含替代方案
/// 当最优方案不可行时,提供替代分配方案
/// </summary>
public bool IncludeAlternativeSolutions { get; set; } = false;
#endregion
#region
/// <summary>
/// 排除的人员ID列表
/// 明确指定不参与推荐的人员
/// </summary>
public List<long> ExcludedPersonnelIds { get; set; } = new();
/// <summary>
/// 优先考虑的人员ID列表
/// 在同等条件下优先推荐的人员
/// </summary>
public List<long> PreferredPersonnelIds { get; set; } = new();
/// <summary>
/// 最小资质匹配度要求 (0-100)
/// 推荐人员必须达到的最低资质匹配分数
/// </summary>
[Range(0, 100, ErrorMessage = "最小资质匹配度应在0-100之间")]
public double MinimumQualificationScore { get; set; } = 60.0;
/// <summary>
/// 最小约束符合度要求 (0-100)
/// 推荐人员必须达到的最低约束符合分数
/// </summary>
[Range(0, 100, ErrorMessage = "最小约束符合度应在0-100之间")]
public double MinimumConstraintScore { get; set; } = 60.0;
#endregion
#region
/// <summary>
/// 推荐基准日期
/// 作为推荐计算的基准时间点
/// </summary>
public DateTime RecommendationBaseDate { get; set; } = DateTime.Now;
/// <summary>
/// 推荐时间范围
/// 限制推荐计算的时间窗口
/// </summary>
public DateRange? TimeRange { get; set; }
#endregion
#region
/// <summary>
/// 推荐请求来源
/// 标识推荐触发的业务场景
/// </summary>
public RecommendationSource RequestSource { get; set; } = RecommendationSource.Manual;
/// <summary>
/// 操作员信息
/// 记录执行推荐的用户
/// </summary>
public OperatorInfo Operator { get; set; } = new();
/// <summary>
/// 推荐批次标识
/// 用于关联和追踪推荐过程
/// </summary>
public string RecommendationBatchId { get; set; } = Guid.NewGuid().ToString();
/// <summary>
/// 业务场景标识
/// 标识具体的业务使用场景
/// </summary>
public string BusinessScenario { get; set; } = string.Empty;
/// <summary>
/// 优先级权重配置
/// 自定义各评分维度的权重分配
/// </summary>
public Dictionary<string, double> CustomWeights { get; set; } = new();
#endregion
#region
/// <summary>
/// 推荐超时时间(秒)
/// 防止推荐过程过长影响用户体验
/// </summary>
[Range(5, 300, ErrorMessage = "推荐超时时间应在5-300秒之间")]
public int RecommendationTimeoutSeconds { get; set; } = 60;
/// <summary>
/// 最小推荐置信度 (0-100)
/// 只返回置信度达到此阈值的推荐结果
/// </summary>
[Range(0, 100, ErrorMessage = "最小推荐置信度应在0-100之间")]
public double MinimumConfidenceLevel { get; set; } = 70.0;
/// <summary>
/// 是否启用缓存
/// 使用缓存提高推荐性能
/// </summary>
public bool EnableCaching { get; set; } = true;
#endregion
#region
/// <summary>
/// 负载均衡策略
/// 控制推荐时的人员工作负载分配策略
/// </summary>
public LoadBalanceStrategy LoadBalanceStrategy { get; set; } = LoadBalanceStrategy.Moderate;
/// <summary>
/// 技能匹配策略
/// 控制技能匹配的严格程度
/// </summary>
public SkillMatchStrategy SkillMatchStrategy { get; set; } = SkillMatchStrategy.Balanced;
/// <summary>
/// 历史表现权重
/// 历史工作表现对推荐的影响权重
/// </summary>
[Range(0, 1, ErrorMessage = "历史表现权重应在0-1之间")]
public double HistoricalPerformanceWeight { get; set; } = 0.3;
#endregion
#region
/// <summary>
/// 是否启用严格验证
/// 启用更严格的推荐结果验证
/// </summary>
public bool EnableStrictValidation { get; set; } = false;
/// <summary>
/// 是否包含合规性检查
/// 在推荐中包含法规和制度合规性检查
/// </summary>
public bool IncludeComplianceCheck { get; set; } = true;
/// <summary>
/// 是否包含成本效益分析
/// 在推荐中包含成本效益评估
/// </summary>
public bool IncludeCostBenefitAnalysis { get; set; } = false;
#endregion
#region
/// <summary>
/// 输出语言
/// 推荐结果的显示语言
/// </summary>
public string OutputLanguage { get; set; } = "zh-CN";
/// <summary>
/// 是否包含可视化数据
/// 在结果中包含图表和可视化所需的数据
/// </summary>
public bool IncludeVisualizationData { get; set; } = false;
/// <summary>
/// 是否包含执行建议
/// 在结果中包含具体的执行建议和注意事项
/// </summary>
public bool IncludeExecutionAdvice { get; set; } = true;
#endregion
#region
public PersonnelAllocationRecommendationInput()
{
// 设置默认值
WorkOrderIds = new List<long>();
ExcludedPersonnelIds = new List<long>();
PreferredPersonnelIds = new List<long>();
CustomWeights = new Dictionary<string, double>();
TimeRange = null;
}
public PersonnelAllocationRecommendationInput(List<long> workOrderIds, PersonnelAllocationStrategy strategy = PersonnelAllocationStrategy.FairDistribution)
{
WorkOrderIds = workOrderIds ?? new List<long>();
Strategy = strategy;
ExcludedPersonnelIds = new List<long>();
PreferredPersonnelIds = new List<long>();
CustomWeights = new Dictionary<string, double>();
TimeRange = null;
}
#endregion
}
#region
/// <summary>
/// 推荐请求来源
/// </summary>
public enum RecommendationSource
{
/// <summary>
/// 手动触发
/// </summary>
Manual = 1,
/// <summary>
/// 系统自动
/// </summary>
System = 2,
/// <summary>
/// 定时任务
/// </summary>
Scheduled = 3,
/// <summary>
/// 外部接口
/// </summary>
External = 4,
/// <summary>
/// 工作流触发
/// </summary>
Workflow = 5
}
/// <summary>
/// 负载均衡策略
/// </summary>
public enum LoadBalanceStrategy
{
/// <summary>
/// 保守策略
/// 优先考虑人员休息和负载均衡
/// </summary>
Conservative = 1,
/// <summary>
/// 平衡策略
/// 平衡效率和负载均衡
/// </summary>
Moderate = 2,
/// <summary>
/// 激进策略
/// 优先考虑任务完成效率
/// </summary>
Aggressive = 3
}
/// <summary>
/// 技能匹配策略
/// </summary>
public enum SkillMatchStrategy
{
/// <summary>
/// 严格匹配
/// 要求技能完全匹配
/// </summary>
Strict = 1,
/// <summary>
/// 平衡匹配
/// 允许部分技能匹配,考虑学习能力
/// </summary>
Balanced = 2,
/// <summary>
/// 宽松匹配
/// 允许技能相近,优先考虑人员发展
/// </summary>
Flexible = 3
}
#endregion
#region
/// <summary>
/// 日期范围
/// </summary>
public class DateRange
{
/// <summary>
/// 开始日期
/// </summary>
public DateTime StartDate { get; set; }
/// <summary>
/// 结束日期
/// </summary>
public DateTime EndDate { get; set; }
/// <summary>
/// 时间范围跨度
/// </summary>
public TimeSpan Duration => EndDate - StartDate;
}
#endregion
}

View File

@ -0,0 +1,613 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration.Input
{
/// <summary>
/// 人员分配验证输入
/// 用于智能分配系统中验证人员分配方案的可行性和合规性
/// 支持批量验证、多维度检查和灵活配置
/// </summary>
public class PersonnelAllocationValidationInput
{
#region
/// <summary>
/// 待验证的人员分配列表
/// 包含任务与人员的具体分配关系
/// </summary>
[Required(ErrorMessage = "人员分配列表不能为空")]
[MinLength(1, ErrorMessage = "至少需要一个分配项")]
public List<PersonnelAssignment> Assignments { get; set; } = new();
#endregion
#region
/// <summary>
/// 验证级别
/// 控制验证的严格程度和覆盖范围
/// </summary>
public ValidationLevel ValidationLevel { get; set; } = ValidationLevel.Standard;
/// <summary>
/// 验证范围配置
/// 可选择验证的具体维度
/// </summary>
public ValidationScopeConfig ValidationScope { get; set; } = new();
/// <summary>
/// 是否包含冲突检测
/// 检测分配间的相互冲突
/// </summary>
public bool IncludeConflictDetection { get; set; } = true;
/// <summary>
/// 是否包含性能分析
/// 分析验证对系统性能的影响
/// </summary>
public bool IncludePerformanceAnalysis { get; set; } = false;
/// <summary>
/// 验证超时时间(秒)
/// 防止验证过程过长影响用户体验
/// </summary>
[Range(5, 300, ErrorMessage = "验证超时时间应在5-300秒之间")]
public int ValidationTimeoutSeconds { get; set; } = 30;
#endregion
#region
/// <summary>
/// 验证请求来源
/// 标识验证触发的业务场景
/// </summary>
public ValidationSource RequestSource { get; set; } = ValidationSource.Manual;
/// <summary>
/// 操作员信息
/// 记录执行验证的用户
/// </summary>
public OperatorInfo Operator { get; set; } = new();
/// <summary>
/// 验证批次标识
/// 用于关联和追踪验证过程
/// </summary>
public string ValidationBatchId { get; set; } = Guid.NewGuid().ToString();
/// <summary>
/// 业务场景标识
/// 标识具体的业务使用场景
/// </summary>
public string BusinessScenario { get; set; } = string.Empty;
#endregion
#region
/// <summary>
/// 验证基准日期
/// 作为验证计算的基准时间点
/// </summary>
public DateTime ValidationBaseDate { get; set; } = DateTime.Now;
/// <summary>
/// 验证时间范围
/// 限制验证的时间窗口
/// </summary>
public DateTimeRange ValidationTimeRange { get; set; } = new();
/// <summary>
/// 是否忽略历史数据
/// 是否跳过已过时的分配验证
/// </summary>
public bool IgnoreHistoricalData { get; set; } = true;
#endregion
#region
/// <summary>
/// 自定义验证规则列表
/// 支持业务特定的验证逻辑
/// </summary>
public List<CustomValidationRule> CustomRules { get; set; } = new();
/// <summary>
/// 验证权重配置
/// 各类验证项的重要性权重
/// </summary>
public ValidationWeights Weights { get; set; } = new();
/// <summary>
/// 排除验证的项目
/// 明确不需要验证的特定项目
/// </summary>
public List<string> ExcludedValidationTypes { get; set; } = new();
#endregion
#region
/// <summary>
/// 验证输入数据的完整性
/// </summary>
public ValidationInputCheckResult ValidateInput()
{
var result = new ValidationInputCheckResult { IsValid = true, Issues = new List<string>() };
// 基础数据验证
if (!Assignments.Any())
{
result.IsValid = false;
result.Issues.Add("分配列表不能为空");
}
// 分配数据完整性检查
foreach (var assignment in Assignments)
{
if (assignment.WorkOrderId <= 0)
{
result.IsValid = false;
result.Issues.Add($"无效的工作任务ID: {assignment.WorkOrderId}");
}
if (assignment.PersonnelId <= 0)
{
result.IsValid = false;
result.Issues.Add($"无效的人员ID: {assignment.PersonnelId}");
}
if (assignment.AssignmentDate == default)
{
result.IsValid = false;
result.Issues.Add($"任务ID {assignment.WorkOrderId} 的分配日期无效");
}
}
// 时间范围合理性检查
if (ValidationTimeRange.IsValid() && ValidationTimeRange.EndDate < ValidationTimeRange.StartDate)
{
result.IsValid = false;
result.Issues.Add("验证时间范围配置错误");
}
// 超时时间合理性检查
if (ValidationTimeoutSeconds < 5 || ValidationTimeoutSeconds > 300)
{
result.IsValid = false;
result.Issues.Add("验证超时时间配置超出有效范围");
}
return result;
}
/// <summary>
/// 获取验证统计信息
/// </summary>
public ValidationInputStatistics GetStatistics()
{
return new ValidationInputStatistics
{
TotalAssignments = Assignments.Count,
UniquePersonnelCount = Assignments.Select(a => a.PersonnelId).Distinct().Count(),
UniqueTaskCount = Assignments.Select(a => a.WorkOrderId).Distinct().Count(),
DateRangeSpan = Assignments.Any()
? (Assignments.Max(a => a.AssignmentDate) - Assignments.Min(a => a.AssignmentDate)).Days
: 0,
ValidationScopeCount = ValidationScope.GetEnabledScopeCount(),
CustomRuleCount = CustomRules.Count,
EstimatedExecutionTimeSeconds = EstimateExecutionTime()
};
}
/// <summary>
/// 估算验证执行时间
/// </summary>
private int EstimateExecutionTime()
{
// 基础验证时间每个分配项约0.1秒)
var baseTime = Assignments.Count * 0.1;
// 冲突检测额外时间
if (IncludeConflictDetection)
baseTime += Assignments.Count * 0.05;
// 性能分析额外时间
if (IncludePerformanceAnalysis)
baseTime += 2;
// 自定义规则额外时间
baseTime += CustomRules.Count * 0.2;
return Math.Max(1, (int)Math.Ceiling(baseTime));
}
#endregion
}
#region
/// <summary>
/// 人员分配项
/// 定义具体的任务-人员分配关系
/// </summary>
public class PersonnelAssignment
{
/// <summary>
/// 工作任务ID
/// </summary>
[Required]
[Range(1, long.MaxValue, ErrorMessage = "工作任务ID必须大于0")]
public long WorkOrderId { get; set; }
/// <summary>
/// 人员ID
/// </summary>
[Required]
[Range(1, long.MaxValue, ErrorMessage = "人员ID必须大于0")]
public long PersonnelId { get; set; }
/// <summary>
/// 分配日期
/// </summary>
[Required]
public DateTime AssignmentDate { get; set; }
/// <summary>
/// 班次ID
/// </summary>
public long? ShiftId { get; set; }
/// <summary>
/// 预计工作小时数
/// </summary>
[Range(0.1, 24, ErrorMessage = "预计工作小时数应在0.1-24之间")]
public decimal EstimatedWorkHours { get; set; }
/// <summary>
/// 分配优先级
/// 用于冲突时的优先级判断
/// </summary>
[Range(1, 10, ErrorMessage = "优先级应在1-10之间")]
public int Priority { get; set; } = 5;
/// <summary>
/// 分配标签
/// 用于分类和筛选
/// </summary>
public List<string> Tags { get; set; } = new();
/// <summary>
/// 备注信息
/// </summary>
[MaxLength(500, ErrorMessage = "备注信息不能超过500字符")]
public string Remarks { get; set; } = string.Empty;
/// <summary>
/// 是否为强制分配
/// 强制分配将跳过某些验证规则
/// </summary>
public bool IsMandatoryAssignment { get; set; } = false;
}
/// <summary>
/// 验证级别枚举
/// </summary>
public enum ValidationLevel
{
/// <summary>
/// 基础验证 - 仅检查最基本的约束
/// </summary>
Basic = 1,
/// <summary>
/// 标准验证 - 包含常用的验证规则
/// </summary>
Standard = 2,
/// <summary>
/// 严格验证 - 全面的验证检查
/// </summary>
Strict = 3,
/// <summary>
/// 自定义验证 - 根据配置执行验证
/// </summary>
Custom = 4
}
/// <summary>
/// 验证范围配置
/// 控制具体验证的维度
/// </summary>
public class ValidationScopeConfig
{
/// <summary>
/// 验证资质匹配
/// </summary>
public bool ValidateQualification { get; set; } = true;
/// <summary>
/// 验证时间冲突
/// </summary>
public bool ValidateTimeConflict { get; set; } = true;
/// <summary>
/// 验证工作限制
/// </summary>
public bool ValidateWorkLimit { get; set; } = true;
/// <summary>
/// 验证班次规则
/// </summary>
public bool ValidateShiftRule { get; set; } = true;
/// <summary>
/// 验证负载均衡
/// </summary>
public bool ValidateLoadBalance { get; set; } = false;
/// <summary>
/// 验证技能匹配
/// </summary>
public bool ValidateSkillMatch { get; set; } = false;
/// <summary>
/// 验证成本控制
/// </summary>
public bool ValidateCostControl { get; set; } = false;
/// <summary>
/// 获取启用的验证范围数量
/// </summary>
public int GetEnabledScopeCount()
{
int count = 0;
if (ValidateQualification) count++;
if (ValidateTimeConflict) count++;
if (ValidateWorkLimit) count++;
if (ValidateShiftRule) count++;
if (ValidateLoadBalance) count++;
if (ValidateSkillMatch) count++;
if (ValidateCostControl) count++;
return count;
}
}
/// <summary>
/// 验证来源枚举
/// </summary>
public enum ValidationSource
{
/// <summary>
/// 手动验证
/// </summary>
Manual = 1,
/// <summary>
/// 自动验证
/// </summary>
Automatic = 2,
/// <summary>
/// 批量验证
/// </summary>
Batch = 3,
/// <summary>
/// 定时验证
/// </summary>
Scheduled = 4,
/// <summary>
/// API调用验证
/// </summary>
ApiCall = 5
}
/// <summary>
/// 操作员信息
/// </summary>
public class OperatorInfo
{
/// <summary>
/// 操作员ID
/// </summary>
public long OperatorId { get; set; }
/// <summary>
/// 操作员姓名
/// </summary>
public string OperatorName { get; set; } = string.Empty;
/// <summary>
/// 操作时间
/// </summary>
public DateTime OperationTime { get; set; } = DateTime.Now;
/// <summary>
/// 操作IP地址
/// </summary>
public string IpAddress { get; set; } = string.Empty;
/// <summary>
/// 操作角色
/// </summary>
public string Role { get; set; } = string.Empty;
}
/// <summary>
/// 日期时间范围
/// </summary>
public class DateTimeRange
{
/// <summary>
/// 开始时间
/// </summary>
public DateTime StartDate { get; set; }
/// <summary>
/// 结束时间
/// </summary>
public DateTime EndDate { get; set; }
/// <summary>
/// 是否为有效的时间范围
/// </summary>
public bool IsValid()
{
return StartDate != default && EndDate != default && StartDate <= EndDate;
}
/// <summary>
/// 获取时间跨度(天数)
/// </summary>
public int GetDaySpan()
{
return IsValid() ? (EndDate - StartDate).Days : 0;
}
}
/// <summary>
/// 自定义验证规则
/// </summary>
public class CustomValidationRule
{
/// <summary>
/// 规则ID
/// </summary>
public string RuleId { get; set; } = string.Empty;
/// <summary>
/// 规则名称
/// </summary>
public string RuleName { get; set; } = string.Empty;
/// <summary>
/// 规则类型
/// </summary>
public string RuleType { get; set; } = string.Empty;
/// <summary>
/// 规则配置参数
/// </summary>
public Dictionary<string, object> Parameters { get; set; } = new();
/// <summary>
/// 规则权重
/// </summary>
[Range(0.1, 10.0, ErrorMessage = "规则权重应在0.1-10.0之间")]
public double Weight { get; set; } = 1.0;
/// <summary>
/// 是否启用
/// </summary>
public bool IsEnabled { get; set; } = true;
}
/// <summary>
/// 验证权重配置
/// </summary>
public class ValidationWeights
{
/// <summary>
/// 资质验证权重
/// </summary>
[Range(0.0, 10.0)]
public double QualificationWeight { get; set; } = 1.0;
/// <summary>
/// 时间冲突验证权重
/// </summary>
[Range(0.0, 10.0)]
public double TimeConflictWeight { get; set; } = 1.0;
/// <summary>
/// 工作限制验证权重
/// </summary>
[Range(0.0, 10.0)]
public double WorkLimitWeight { get; set; } = 1.0;
/// <summary>
/// 班次规则验证权重
/// </summary>
[Range(0.0, 10.0)]
public double ShiftRuleWeight { get; set; } = 0.8;
/// <summary>
/// 负载均衡验证权重
/// </summary>
[Range(0.0, 10.0)]
public double LoadBalanceWeight { get; set; } = 0.6;
/// <summary>
/// 技能匹配验证权重
/// </summary>
[Range(0.0, 10.0)]
public double SkillMatchWeight { get; set; } = 0.7;
}
/// <summary>
/// 验证输入检查结果
/// </summary>
public class ValidationInputCheckResult
{
/// <summary>
/// 输入是否有效
/// </summary>
public bool IsValid { get; set; }
/// <summary>
/// 问题列表
/// </summary>
public List<string> Issues { get; set; } = new();
}
/// <summary>
/// 验证输入统计信息
/// </summary>
public class ValidationInputStatistics
{
/// <summary>
/// 总分配数量
/// </summary>
public int TotalAssignments { get; set; }
/// <summary>
/// 唯一人员数量
/// </summary>
public int UniquePersonnelCount { get; set; }
/// <summary>
/// 唯一任务数量
/// </summary>
public int UniqueTaskCount { get; set; }
/// <summary>
/// 日期范围跨度(天)
/// </summary>
public int DateRangeSpan { get; set; }
/// <summary>
/// 验证范围数量
/// </summary>
public int ValidationScopeCount { get; set; }
/// <summary>
/// 自定义规则数量
/// </summary>
public int CustomRuleCount { get; set; }
/// <summary>
/// 预估执行时间(秒)
/// </summary>
public int EstimatedExecutionTimeSeconds { get; set; }
}
#endregion
}

View File

@ -0,0 +1,424 @@
using System;
using System.Collections.Generic;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Output;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration.Input
{
/// <summary>
/// 处理任务变更输入
/// 用于检测和处理发布后的任务变更,触发智能重新分配
/// </summary>
public class ProcessTaskChangesInput
{
/// <summary>
/// 变更的任务ID列表
/// 指定需要处理变更的任务
/// </summary>
public List<long> ChangedTaskIds { get; set; } = new();
/// <summary>
/// 整合记录ID
/// 指定要更新的整合记录
/// </summary>
public long IntegrationRecordId { get; set; }
/// <summary>
/// 变更触发源
/// TaskModification-任务修改, ResourceUnavailable-资源不可用, ConflictDetected-冲突检测, UserRequest-用户请求
/// </summary>
public string ChangeTriggerSource { get; set; } = "TaskModification";
/// <summary>
/// 处理策略
/// AutoReallocation-自动重新分配, ManualReview-手动审核, CreateNewVersion-创建新版本
/// </summary>
public string ProcessingStrategy { get; set; } = "AutoReallocation";
/// <summary>
/// 操作员用户ID
/// </summary>
public long OperatorUserId { get; set; }
/// <summary>
/// 操作员用户名
/// </summary>
public string OperatorUserName { get; set; } = string.Empty;
/// <summary>
/// 操作员真实姓名
/// </summary>
public string OperatorRealName { get; set; } = string.Empty;
/// <summary>
/// 变更原因说明
/// </summary>
public string ChangeReason { get; set; } = string.Empty;
/// <summary>
/// 是否强制重新分配
/// 即使影响评分较低也强制执行重新分配
/// </summary>
public bool ForceReallocation { get; set; } = false;
/// <summary>
/// 是否保持现有分配
/// 尽量保持当前的人员和设备分配,只调整有问题的部分
/// </summary>
public bool PreserveExistingAllocations { get; set; } = true;
/// <summary>
/// 重新分配范围
/// ChangedOnly-仅重新分配变更的任务, Affected-重新分配受影响的任务, All-重新分配所有任务
/// </summary>
public string ReallocationScope { get; set; } = "Affected";
/// <summary>
/// 优先级调整策略
/// None-不调整, Boost-提升变更任务优先级, Balance-平衡所有任务优先级
/// </summary>
public string PriorityAdjustmentStrategy { get; set; } = "None";
/// <summary>
/// 通知相关人员
/// 变更处理完成后是否通知受影响的人员
/// </summary>
public bool NotifyAffectedPersonnel { get; set; } = true;
/// <summary>
/// 创建变更日志
/// 是否详细记录变更处理过程
/// </summary>
public bool CreateChangeLog { get; set; } = true;
/// <summary>
/// 允许的最大处理时间(分钟)
/// 超时则转为手动处理
/// </summary>
public int MaxProcessingTimeMinutes { get; set; } = 30;
/// <summary>
/// 业务备注
/// </summary>
public string Remarks { get; set; } = string.Empty;
/// <summary>
/// 分析深度
/// 指定变更分析的深度级别
/// </summary>
public TaskChangeAnalysisDepth AnalysisDepth { get; set; } = TaskChangeAnalysisDepth.Standard;
/// <summary>
/// 版本创建原因
/// 当处理策略为CreateNewVersion时使用
/// </summary>
public string VersionReason { get; set; } = string.Empty;
/// <summary>
/// 是否发送通知
/// 处理完成后是否发送通知给相关人员
/// </summary>
public bool SendNotifications { get; set; } = true;
}
/// <summary>
/// 智能重新分配输入
/// 用于触发智能重新分配算法
/// </summary>
public class SmartReallocationInput
{
/// <summary>
/// 整合记录ID根版本ID
/// </summary>
public long RootIntegrationRecordId { get; set; }
/// <summary>
/// 需要重新分配的任务ID列表
/// 为空则表示重新分配所有任务
/// </summary>
public List<long> TaskIdsToReallocate { get; set; } = new();
/// <summary>
/// 重新分配策略配置
/// 可以重用原策略或指定新策略
/// </summary>
public SmartReallocationStrategyConfig Strategy { get; set; } = new();
/// <summary>
/// 约束条件
/// 指定重新分配时需要遵守的约束条件
/// </summary>
public List<ReallocationConstraint> Constraints { get; set; } = new();
/// <summary>
/// 操作员用户ID
/// </summary>
public long OperatorUserId { get; set; }
/// <summary>
/// 操作员用户名
/// </summary>
public string OperatorUserName { get; set; } = string.Empty;
/// <summary>
/// 操作员真实姓名
/// </summary>
public string OperatorRealName { get; set; } = string.Empty;
/// <summary>
/// 重新分配原因
/// </summary>
public string ReallocationReason { get; set; } = string.Empty;
/// <summary>
/// 是否创建新版本
/// true-创建新版本保留历史, false-更新当前版本
/// </summary>
public bool CreateNewVersion { get; set; } = true;
/// <summary>
/// 预期完成时间
/// 指定重新分配的预期完成时间
/// </summary>
public DateTime? ExpectedCompletionTime { get; set; }
/// <summary>
/// 质量优先级
/// 分配时的质量要求优先级Low, Medium, High, Critical
/// </summary>
public string QualityPriority { get; set; } = "Medium";
/// <summary>
/// 成本控制要求
/// 是否需要考虑成本控制
/// </summary>
public bool ConsiderCostControl { get; set; } = false;
/// <summary>
/// 最大成本预算
/// </summary>
public decimal? MaxBudget { get; set; }
/// <summary>
/// 业务备注
/// </summary>
public string Remarks { get; set; } = string.Empty;
/// <summary>
/// 整合记录ID
/// 相关的整合记录标识
/// </summary>
public long IntegrationRecordId { get; set; }
/// <summary>
/// 变更的任务ID列表
/// 需要进行重新分配的任务
/// </summary>
public List<long> ChangedTaskIds { get; set; } = new();
/// <summary>
/// 版本创建原因
/// 重新分配时创建版本的原因说明
/// </summary>
public string VersionReason { get; set; } = string.Empty;
/// <summary>
/// 受影响的任务ID列表
/// 可能受到变更影响的任务
/// </summary>
public List<long> AffectedTaskIds { get; set; } = new();
/// <summary>
/// 是否重新分配人员
/// </summary>
public bool ReallocatePersonnel { get; set; } = true;
/// <summary>
/// 是否重新分配设备
/// </summary>
public bool ReallocateEquipment { get; set; } = true;
}
/// <summary>
/// 智能重新分配策略配置
/// </summary>
public class SmartReallocationStrategyConfig
{
/// <summary>
/// 是否使用原策略
/// </summary>
public bool UseOriginalStrategy { get; set; } = true;
/// <summary>
/// 人员分配策略
/// </summary>
public string PersonnelStrategy { get; set; } = string.Empty;
/// <summary>
/// 设备分配策略
/// </summary>
public string EquipmentStrategy { get; set; } = string.Empty;
/// <summary>
/// 强制执行班次规则
/// </summary>
public bool EnforceShiftRules { get; set; } = true;
/// <summary>
/// 优化目标
/// Efficiency-效率优先, Fairness-公平优先, Balance-平衡, Quality-质量优先
/// </summary>
public string OptimizationTarget { get; set; } = "Balance";
/// <summary>
/// 变更影响最小化
/// 尽量减少对现有分配的影响
/// </summary>
public bool MinimizeChangeImpact { get; set; } = true;
/// <summary>
/// 允许跨班次调整
/// </summary>
public bool AllowCrossShiftAdjustment { get; set; } = false;
/// <summary>
/// 允许跨项目资源共享
/// </summary>
public bool AllowCrossProjectSharing { get; set; } = false;
/// <summary>
/// 高级配置参数
/// </summary>
public Dictionary<string, object> AdvancedSettings { get; set; } = new();
}
/// <summary>
/// 重新分配约束条件
/// </summary>
public class ReallocationConstraint
{
/// <summary>
/// 约束类型
/// Personnel-人员约束, Equipment-设备约束, Time-时间约束, Cost-成本约束
/// </summary>
public string ConstraintType { get; set; } = string.Empty;
/// <summary>
/// 约束目标ID
/// 人员ID、设备ID等
/// </summary>
public long? TargetId { get; set; }
/// <summary>
/// 约束操作
/// MustInclude-必须包含, MustExclude-必须排除, Prefer-优先选择, Avoid-尽量避免
/// </summary>
public string ConstraintOperation { get; set; } = string.Empty;
/// <summary>
/// 约束值
/// 具体的约束值或条件
/// </summary>
public string ConstraintValue { get; set; } = string.Empty;
/// <summary>
/// 约束优先级
/// 1-99为最高优先级
/// </summary>
public int Priority { get; set; } = 5;
/// <summary>
/// 约束说明
/// </summary>
public string Description { get; set; } = string.Empty;
/// <summary>
/// 是否为硬约束
/// true-硬约束(必须满足), false-软约束(尽量满足)
/// </summary>
public bool IsHardConstraint { get; set; } = false;
}
/// <summary>
/// 版本历史查询输入
/// </summary>
public class IntegrationVersionHistoryInput
{
/// <summary>
/// 整合记录ID
/// </summary>
public long IntegrationRecordId { get; set; }
/// <summary>
/// 根版本ID
/// </summary>
public long RootVersionId { get; set; }
/// <summary>
/// 需要比较的版本ID列表
/// </summary>
public List<long> CompareVersionIds { get; set; } = new();
/// <summary>
/// 查询开始时间
/// </summary>
public DateTime? StartTime { get; set; }
/// <summary>
/// 查询结束时间
/// </summary>
public DateTime? EndTime { get; set; }
/// <summary>
/// 版本状态过滤
/// Active-活跃版本, Inactive-非活跃版本, All-所有版本
/// </summary>
public string VersionStatusFilter { get; set; } = "All";
/// <summary>
/// 变更类型过滤
/// </summary>
public List<string> ChangeTypeFilter { get; set; } = new();
/// <summary>
/// 操作员过滤
/// </summary>
public List<long> OperatorFilter { get; set; } = new();
/// <summary>
/// 是否包含快照数据
/// </summary>
public bool IncludeSnapshotData { get; set; } = false;
/// <summary>
/// 是否包含变更详情
/// </summary>
public bool IncludeChangeDetails { get; set; } = true;
/// <summary>
/// 页码
/// </summary>
public int PageIndex { get; set; } = 1;
/// <summary>
/// 页大小
/// </summary>
public int PageSize { get; set; } = 20;
/// <summary>
/// 排序字段
/// CreatedTime, Version, ImpactScore
/// </summary>
public string SortBy { get; set; } = "CreatedTime";
/// <summary>
/// 排序方向
/// Asc, Desc
/// </summary>
public string SortDirection { get; set; } = "Desc";
/// <summary>
/// 是否包含性能指标
/// </summary>
public bool IncludePerformanceMetrics { get; set; } = false;
}
}

View File

@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration.Input;
/// <summary>
/// 发布整合记录输入参数
/// 包含发布操作的所有必要信息和业务规则验证参数
///
/// 业务思考:
/// 1. 发布是整合记录生命周期的关键节点,需要严格的权限验证
/// 2. 发布后任务状态将从PendingIntegration更新为Assigned这是不可逆操作
/// 3. 支持发布备注,记录发布的业务背景和特殊说明
/// 4. 包含强制发布选项,应对特殊业务场景但需要额外权限
/// </summary>
public class PublishIntegrationRecordInput
{
/// <summary>
/// 整合记录ID
/// </summary>
[Required(ErrorMessage = "整合记录ID不能为空")]
[Range(1, long.MaxValue, ErrorMessage = "整合记录ID必须大于0")]
public long IntegrationRecordId { get; set; }
/// <summary>
/// 发布操作员用户ID
/// </summary>
[Required(ErrorMessage = "发布操作员用户ID不能为空")]
[Range(1, long.MaxValue, ErrorMessage = "发布操作员用户ID必须大于0")]
public long PublishedByUserId { get; set; }
/// <summary>
/// 发布操作员用户名
/// </summary>
[Required(ErrorMessage = "发布操作员用户名不能为空")]
[StringLength(50, ErrorMessage = "发布操作员用户名长度不能超过50个字符")]
public string PublishedByUserName { get; set; } = string.Empty;
/// <summary>
/// 发布操作员真实姓名
/// </summary>
[Required(ErrorMessage = "发布操作员真实姓名不能为空")]
[StringLength(50, ErrorMessage = "发布操作员真实姓名长度不能超过50个字符")]
public string PublishedByRealName { get; set; } = string.Empty;
/// <summary>
/// 发布说明
/// 记录发布的业务背景、特殊情况或注意事项
/// </summary>
[StringLength(500, ErrorMessage = "发布说明长度不能超过500个字符")]
public string PublishRemarks { get; set; } = string.Empty;
/// <summary>
/// 是否跳过发布前验证
/// 默认falsetrue时需要额外权限验证
///
/// 业务意义:
/// - 正常情况应该为false进行完整的发布前验证
/// - 紧急情况下可以设为true但需要管理员权限
/// - 跳过验证的发布需要记录审计日志
/// </summary>
public bool SkipPrePublishValidation { get; set; } = false;
/// <summary>
/// 是否强制发布
/// 当发现潜在冲突但仍需要发布时使用,需要特殊权限
///
/// 业务场景:
/// - 临时调整导致的轻微冲突但业务必须继续
/// - 系统维护期间的特殊发布需求
/// - 应急处理场景下的破例发布
/// </summary>
public bool ForcePublish { get; set; } = false;
/// <summary>
/// 预期发布生效时间
/// null表示立即生效否则按指定时间生效
///
/// 业务考虑:
/// - 支持定时发布功能,便于计划性任务安排
/// - 立即发布适用于紧急任务调度
/// - 定时发布可以配合班次计划进行优化
/// </summary>
public DateTime? ScheduledPublishTime { get; set; }
/// <summary>
/// 发布后是否自动开始任务
/// 控制发布后是否将任务状态进一步更新为InProgress
///
/// 业务逻辑:
/// - true发布后任务自动开始执行PendingIntegration -> Assigned -> InProgress
/// - false发布后任务处于已分配状态等待手动开始PendingIntegration -> Assigned
/// </summary>
public bool AutoStartTasksAfterPublish { get; set; } = false;
/// <summary>
/// 通知相关人员
/// 发布后是否通知相关的人员和设备管理员
/// </summary>
public bool NotifyRelatedPersonnel { get; set; } = true;
/// <summary>
/// 发布范围限制
/// 指定只发布特定任务null表示发布整合记录中的所有任务
///
/// 业务价值:
/// - 支持部分发布功能,提高发布的灵活性
/// - 当某些任务出现问题时,可以单独发布其他正常任务
/// - 便于分阶段发布和风险控制
/// </summary>
public List<long>? SpecificTaskIds { get; set; }
}

View File

@ -0,0 +1,292 @@
using System;
using System.Collections.Generic;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Output;
using NPP.SmartSchedue.Api.Contracts.Domain.Work;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration.Input
{
/// <summary>
/// 智能整合输入
/// </summary>
public class SmartIntegrationInput
{
/// <summary>
/// 选中的任务ID列表
/// </summary>
public List<long> SelectedTaskIds { get; set; } = new();
/// <summary>
/// 选中的项目号列表
/// </summary>
public List<string> SelectedProjectNumbers { get; set; } = new();
/// <summary>
/// 整合策略配置
/// </summary>
public IntegrationStrategy Strategy { get; set; } = new();
/// <summary>
/// 操作员信息
/// </summary>
public long OperatorUserId { get; set; }
public string OperatorName { get; set; }
/// <summary>
/// 整合批次名称(可选)
/// </summary>
public string BatchName { get; set; }
/// <summary>
/// 整合备注
/// </summary>
public string Remarks { get; set; }
}
/// <summary>
/// 整合策略
/// </summary>
public class IntegrationStrategy
{
/// <summary>
/// 人员分配策略
/// </summary>
public PersonnelAllocationStrategy PersonnelStrategy { get; set; } = PersonnelAllocationStrategy.FairDistribution;
/// <summary>
/// 设备分配策略
/// </summary>
public EquipmentAllocationStrategy EquipmentStrategy { get; set; } = EquipmentAllocationStrategy.MaxUtilization;
/// <summary>
/// 是否强制满足班次规则
/// </summary>
public bool EnforceShiftRules { get; set; } = true;
/// <summary>
/// 是否优先分配高优先级任务
/// </summary>
public bool PrioritizeHighPriorityTasks { get; set; } = true;
/// <summary>
/// 是否考虑人员资质匹配
/// </summary>
public bool ConsiderQualificationMatch { get; set; } = true;
/// <summary>
/// 是否启用负载均衡
/// </summary>
public bool EnableLoadBalancing { get; set; } = true;
/// <summary>
/// 最大连续工作天数限制
/// </summary>
public int? MaxContinuousWorkDays { get; set; }
/// <summary>
/// 设备利用率目标(百分比)
/// </summary>
public decimal TargetEquipmentUtilization { get; set; } = 80.0m;
}
/// <summary>
/// 人员分配策略枚举
/// </summary>
public enum PersonnelAllocationStrategy
{
/// <summary>
/// 公平分配(均衡工作量)
/// </summary>
FairDistribution = 1,
/// <summary>
/// 技能优先(优先匹配最佳技能)
/// </summary>
SkillPriority = 2,
/// <summary>
/// 效率优先(优先分配给高效人员)
/// </summary>
EfficiencyPriority = 3,
/// <summary>
/// 负载均衡(平衡所有人员工作负荷)
/// </summary>
LoadBalance = 4
}
/// <summary>
/// 设备分配策略枚举
/// </summary>
public enum EquipmentAllocationStrategy
{
/// <summary>
/// 最大利用率(优先使用利用率高的设备)
/// </summary>
MaxUtilization = 1,
/// <summary>
/// 负载均衡(平衡所有设备使用率)
/// </summary>
LoadBalance = 2,
/// <summary>
/// 性能优先(优先使用性能最佳的设备)
/// </summary>
PerformancePriority = 3,
/// <summary>
/// 就近分配(优先分配距离最近的设备)
/// </summary>
ProximityPriority = 4
}
/// <summary>
/// 人员分配输入
/// 深度架构思考:支持两种输入模式,避免重复数据库查询,提升性能和数据一致性
/// </summary>
public class PersonnelAllocationInput
{
/// <summary>
/// 待分配的任务ID列表当Tasks为空时使用
/// </summary>
public List<long> TaskIds { get; set; } = new();
/// <summary>
/// 待分配的任务对象列表(性能优化:避免重复数据库查询)
/// 深度业务考量当上级调用方已经加载了完整的task对象时直接传入可以
/// 1. 避免重复数据库查询,提升性能
/// 2. 确保数据一致性,防止查询间隙的数据变更
/// 3. 减少Include操作的开销
/// 使用优先级Tasks > TaskIds
/// </summary>
public List<WorkOrderEntity> Tasks { get; set; } = new();
/// <summary>
/// 人员分配策略
/// </summary>
public PersonnelAllocationStrategy Strategy { get; set; }
/// <summary>
/// 是否强制满足班次规则
/// </summary>
public bool EnforceShiftRules { get; set; } = true;
/// <summary>
/// 排除的人员ID列表不参与分配
/// </summary>
public List<long> ExcludedPersonnelIds { get; set; } = new();
/// <summary>
/// 优先考虑的人员ID列表
/// </summary>
public List<long> PreferredPersonnelIds { get; set; } = new();
}
/// <summary>
/// 设备分配输入
/// 深度架构优化:支持两种输入模式,避免重复数据库查询,提升性能和数据一致性
/// </summary>
public class EquipmentAllocationInput
{
/// <summary>
/// 待分配的任务ID列表当Tasks为空时使用
/// </summary>
public List<long> TaskIds { get; set; } = new();
/// <summary>
/// 待分配的任务对象列表(性能优化:避免重复数据库查询)
/// 深度业务考量当上级调用方SmartScheduleOrchestratorService已经加载了完整的task对象时直接传入可以
/// 1. 避免重复数据库查询提升性能50%以上
/// 2. 确保数据一致性,防止查询间隙的数据变更
/// 3. 减少Include操作的开销降低内存占用
/// 4. 保持与PersonnelAllocationInput相同的优化模式
/// 使用优先级Tasks > TaskIds
/// </summary>
public List<WorkOrderEntity> Tasks { get; set; } = new();
/// <summary>
/// 设备分配策略
/// </summary>
public EquipmentAllocationStrategy Strategy { get; set; }
/// <summary>
/// 目标利用率(百分比)
/// </summary>
public decimal TargetUtilization { get; set; } = 80.0m;
/// <summary>
/// 排除的设备ID列表不参与分配
/// </summary>
public List<long> ExcludedEquipmentIds { get; set; } = new();
/// <summary>
/// 优先考虑的设备ID列表
/// </summary>
public List<long> PreferredEquipmentIds { get; set; } = new();
}
/// <summary>
/// 整合记录输入
/// </summary>
public class IntegrationRecordInput
{
/// <summary>
/// 整合的任务ID列表
/// </summary>
public List<long> TaskIds { get; set; } = new();
/// <summary>
/// 人员分配结果
/// </summary>
public PersonnelAllocationResult PersonnelAllocation { get; set; }
/// <summary>
/// 设备分配结果
/// </summary>
public EquipmentAllocationResult EquipmentAllocation { get; set; }
/// <summary>
/// 整合策略
/// </summary>
public IntegrationStrategy Strategy { get; set; }
/// <summary>
/// 操作员信息
/// </summary>
public long OperatorUserId { get; set; }
public string OperatorName { get; set; }
/// <summary>
/// 整合备注
/// </summary>
public string Remarks { get; set; }
}
/// <summary>
/// 整合历史查询输入
/// </summary>
public class IntegrationHistoryQueryInput
{
/// <summary>
/// 操作员ID
/// </summary>
public long? OperatorUserId { get; set; }
/// <summary>
/// 项目号
/// </summary>
public string ProjectNumber { get; set; }
/// <summary>
/// 整合时间范围
/// </summary>
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
/// <summary>
/// 分页参数
/// </summary>
public int PageIndex { get; set; } = 1;
public int PageSize { get; set; } = 20;
}
}

View File

@ -0,0 +1,37 @@
using System.Collections.Generic;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Output;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration.Internal
{
/// <summary>
/// 最终业务规则验证结果
/// 业务用途:对遗传算法输出进行严格的业务规则二次验证的结果
/// </summary>
public class FinalValidationResult
{
/// <summary>
/// 是否通过验证
/// </summary>
public bool IsValid { get; set; }
/// <summary>
/// 错误消息
/// </summary>
public string ErrorMessage { get; set; } = string.Empty;
/// <summary>
/// 违规详情列表
/// </summary>
public List<GlobalConflictDetectionInfo> Violations { get; set; } = new List<GlobalConflictDetectionInfo>();
/// <summary>
/// 验证的任务数量
/// </summary>
public int ValidatedTaskCount { get; set; }
/// <summary>
/// 检测到的违规数量
/// </summary>
public int ViolationCount => Violations.Count;
}
}

View File

@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using NPP.SmartSchedue.Api.Contracts.Domain.Personnel;
using NPP.SmartSchedue.Api.Contracts.Domain.Work;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Input;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Output;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration.Models;
public class AllocationContext
{
public AllocationContext()
{
// 初始化所有集合属性,避免空引用异常
WorkOrders = new List<WorkOrderEntity>();
WeightConfiguration = new Dictionary<string, double>();
AvailablePersonnel = new List<PersonnelEntity>();
ProcessingLog = new List<string>();
Errors = new List<string>();
ConstraintResults = new Dictionary<long, List<ConstraintEvaluationResult>>();
FilteredCandidates = new Dictionary<long, List<PersonnelCandidate>>();
Metrics = new Dictionary<string, object>();
OptimizationResults = new Dictionary<long, List<OptimizationScoreResult>>();
}
public string ContextId { get; set; }
public DateTime CreatedAt { get; set; }
public List<WorkOrderEntity> WorkOrders { get; set; }
public PersonnelAllocationStrategy Strategy { get; set; }
public Dictionary<string, double> WeightConfiguration { get; set; }
public List<PersonnelEntity> AvailablePersonnel { get; set; }
public List<string> ProcessingLog { get; set; }
public List<string> Errors { get; set; }
public Dictionary<long, List<ConstraintEvaluationResult>> ConstraintResults { get; set; }
public Dictionary<long, List<PersonnelCandidate>> FilteredCandidates { get; set; }
/// <summary>
/// 性能指标字典
/// 存储分配过程中各阶段的性能数据,如执行时间、处理数量等
/// Key: 指标名称Value: 指标值
/// </summary>
public Dictionary<string, object> Metrics { get; set; }
/// <summary>
/// 优化决策结果字典
/// 存储每个工作任务的优化决策详细结果
/// Key: 工作任务ID, Value: 优化评分结果列表
/// </summary>
public Dictionary<long, List<OptimizationScoreResult>> OptimizationResults { get; set; }
}

View File

@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration.Models
{
/// <summary>
/// 人员工作负载分析
/// 用于智能分配算法中的人员工作量评估和负载均衡
/// </summary>
public class PersonnelWorkloadAnalysis
{
/// <summary>
/// 人员ID
/// </summary>
public long PersonnelId { get; set; }
/// <summary>
/// 人员姓名
/// </summary>
public string PersonnelName { get; set; } = string.Empty;
/// <summary>
/// 已分配任务数量
/// </summary>
public int AssignedTaskCount { get; set; }
/// <summary>
/// 计划工作小时数
/// </summary>
public decimal ScheduledWorkHours { get; set; }
/// <summary>
/// 工作负载百分比 (0-100)
/// 相对于标准工作量的百分比
/// </summary>
public double WorkloadPercentage { get; set; }
/// <summary>
/// 负载状态描述
/// </summary>
public string WorkloadStatus { get; set; } = string.Empty;
/// <summary>
/// 是否超负荷
/// </summary>
public bool IsOverloaded => WorkloadPercentage > 100;
/// <summary>
/// 剩余可分配容量
/// </summary>
public decimal RemainingCapacity { get; set; }
/// <summary>
/// 技能匹配度平均分
/// </summary>
public decimal AverageSkillMatchScore { get; set; }
/// <summary>
/// 分配的任务列表
/// </summary>
public List<AssignedTaskInfo> AssignedTasks { get; set; } = new();
/// <summary>
/// 工作时间段分布
/// Key: 日期, Value: 工作小时数
/// </summary>
public Dictionary<DateTime, decimal> DailyWorkHoursDistribution { get; set; } = new();
/// <summary>
/// 负载均衡评分 (0-100)
/// 评估当前负载是否合理均衡
/// </summary>
public int LoadBalanceScore { get; set; }
/// <summary>
/// 最后更新时间
/// </summary>
public DateTime LastUpdated { get; set; } = DateTime.Now;
public List<DateTime> WorkDates { get; set; }
/// <summary>
/// 计算连续工作天数
/// </summary>
public int ContinuousWorkDays { get; set; }
/// <summary>
/// 总工时
/// </summary>
public decimal? TotalEstimatedHours { get; set; }
}
/// <summary>
/// 已分配任务信息
/// </summary>
public class AssignedTaskInfo
{
/// <summary>
/// 任务ID
/// </summary>
public long TaskId { get; set; }
/// <summary>
/// 任务编码
/// </summary>
public string TaskCode { get; set; } = string.Empty;
/// <summary>
/// 预计工作小时数
/// </summary>
public decimal EstimatedWorkHours { get; set; }
/// <summary>
/// 任务优先级
/// </summary>
public int Priority { get; set; }
/// <summary>
/// 计划开始时间
/// </summary>
public DateTime ScheduledStartTime { get; set; }
/// <summary>
/// 计划结束时间
/// </summary>
public DateTime ScheduledEndTime { get; set; }
/// <summary>
/// 技能匹配度
/// </summary>
public decimal SkillMatchScore { get; set; }
}
}

View File

@ -0,0 +1,852 @@
using System;
using System.Collections.Generic;
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Output;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration.Models
{
/// <summary>
/// 验证违规信息
/// 通用的验证违规模型,用于各类验证场景
/// </summary>
public class ValidationViolation
{
/// <summary>
/// 违规ID
/// </summary>
public string ViolationId { get; set; } = Guid.NewGuid().ToString();
/// <summary>
/// 违规类型
/// </summary>
public string ViolationType { get; set; } = string.Empty;
/// <summary>
/// 违规描述
/// </summary>
public string Description { get; set; } = string.Empty;
/// <summary>
/// 违规严重程度
/// </summary>
public ViolationSeverity Severity { get; set; } = ViolationSeverity.Medium;
/// <summary>
/// 相关实体ID
/// </summary>
public long EntityId { get; set; }
/// <summary>
/// 相关实体类型
/// </summary>
public string EntityType { get; set; } = string.Empty;
/// <summary>
/// 违规详细信息
/// </summary>
public Dictionary<string, object> Details { get; set; } = new();
/// <summary>
/// 建议解决方案
/// </summary>
public List<string> SuggestedSolutions { get; set; } = new();
/// <summary>
/// 发现时间
/// </summary>
public DateTime DetectedAt { get; set; } = DateTime.Now;
/// <summary>
/// 是否为阻塞性问题
/// </summary>
public bool IsBlockingIssue { get; set; } = false;
/// <summary>
/// 业务影响度 (1-10)
/// </summary>
public int BusinessImpact { get; set; } = 5;
/// <summary>
/// 违规分类
/// </summary>
public ViolationCategory Category { get; set; } = ViolationCategory.General;
/// <summary>
/// 是否可通过审批强制执行
/// </summary>
public bool CanOverrideWithApproval { get; set; } = true;
/// <summary>
/// 所需审批级别
/// </summary>
public ApprovalLevel RequiredApprovalLevel { get; set; } = ApprovalLevel.None;
/// <summary>
/// 违规风险评估
/// </summary>
public ViolationRiskAssessment RiskAssessment { get; set; } = new();
}
/// <summary>
/// 验证警告信息
/// 通用的验证警告模型,用于各类验证场景
/// </summary>
public class ValidationWarning
{
/// <summary>
/// 警告ID
/// </summary>
public string WarningId { get; set; } = Guid.NewGuid().ToString();
/// <summary>
/// 警告类型
/// </summary>
public string WarningType { get; set; } = string.Empty;
/// <summary>
/// 警告消息
/// </summary>
public string Message { get; set; } = string.Empty;
/// <summary>
/// 警告级别
/// </summary>
public WarningLevel Level { get; set; } = WarningLevel.Medium;
/// <summary>
/// 相关实体ID
/// </summary>
public long EntityId { get; set; }
/// <summary>
/// 相关实体类型
/// </summary>
public string EntityType { get; set; } = string.Empty;
/// <summary>
/// 建议关注程度 (1-10)
/// </summary>
public int AttentionLevel { get; set; } = 5;
/// <summary>
/// 相关任务ID列表
/// </summary>
public List<long> RelatedTaskIds { get; set; } = new();
/// <summary>
/// 建议操作
/// </summary>
public string SuggestedAction { get; set; } = string.Empty;
/// <summary>
/// 发现时间
/// </summary>
public DateTime DetectedAt { get; set; } = DateTime.Now;
}
/// <summary>
/// 约束违规信息
/// 专门用于约束评估过程中的违规记录,比通用违规类更轻量
/// </summary>
public class ConstraintViolation
{
/// <summary>
/// 违规ID
/// </summary>
public string ViolationId { get; set; } = Guid.NewGuid().ToString();
/// <summary>
/// 违规类型
/// </summary>
public string ViolationType { get; set; } = string.Empty;
/// <summary>
/// 违规描述
/// </summary>
public string Description { get; set; } = string.Empty;
/// <summary>
/// 违规严重程度
/// </summary>
public ViolationSeverity Severity { get; set; } = ViolationSeverity.Medium;
/// <summary>
/// 违规详细信息
/// </summary>
public Dictionary<string, object> Details { get; set; } = new();
/// <summary>
/// 发现时间
/// </summary>
public DateTime DetectedAt { get; set; } = DateTime.Now;
/// <summary>
/// 是否为阻塞性问题
/// </summary>
public bool IsBlockingIssue { get; set; } = false;
/// <summary>
/// 业务影响度 (1-10)
/// </summary>
public int BusinessImpact { get; set; } = 5;
/// <summary>
/// 违规分类
/// </summary>
public ViolationCategory Category { get; set; } = ViolationCategory.General;
/// <summary>
/// 是否可通过审批强制执行
/// </summary>
public bool CanOverrideWithApproval { get; set; } = true;
/// <summary>
/// 所需审批级别
/// </summary>
public ApprovalLevel RequiredApprovalLevel { get; set; } = ApprovalLevel.None;
/// <summary>
/// 建议解决方案
/// </summary>
public List<string> SuggestedSolutions { get; set; } = new();
/// <summary>
/// 违规风险评估
/// </summary>
public ViolationRiskAssessment RiskAssessment { get; set; } = new();
/// <summary>
/// 创建新的约束违规实例
/// </summary>
public static ConstraintViolation Create(string violationType, string description, ViolationSeverity severity = ViolationSeverity.Medium)
{
return new ConstraintViolation
{
ViolationType = violationType,
Description = description,
Severity = severity,
DetectedAt = DateTime.Now
};
}
/// <summary>
/// 创建阻塞性违规
/// </summary>
public static ConstraintViolation CreateBlocking(string violationType, string description, ViolationSeverity severity = ViolationSeverity.High)
{
return new ConstraintViolation
{
ViolationType = violationType,
Description = description,
Severity = severity,
IsBlockingIssue = true,
DetectedAt = DateTime.Now
};
}
}
/// <summary>
/// 违规类型枚举
/// 定义人员分配过程中可能出现的各种违规类型
/// </summary>
public enum ViolationType
{
/// <summary>
/// 通用违规
/// </summary>
General = 0,
/// <summary>
/// 资质不匹配
/// 业务场景:人员资质与任务要求不符
/// </summary>
QualificationMismatch = 1,
/// <summary>
/// 时间冲突
/// 业务场景:人员在同一时间段被分配多个任务
/// </summary>
TimeConflict = 2,
/// <summary>
/// 工作量超限
/// 业务场景:人员工作负载超过限制
/// </summary>
WorkloadExceeded = 3,
/// <summary>
/// 班次规则冲突
/// 业务场景:违反班次连续性、同天班次等规则
/// </summary>
ShiftRuleViolation = 4,
/// <summary>
/// 工作限制违规
/// 业务场景:违反连续工作天数、周班次数等限制
/// </summary>
WorkLimitViolation = 5,
/// <summary>
/// 系统状态违规
/// 业务场景:人员状态异常、系统配置问题等
/// </summary>
SystemStateViolation = 6,
/// <summary>
/// 业务规则冲突
/// 业务场景:违反项目特定规则、部门限制等
/// </summary>
BusinessRuleViolation = 7
}
/// <summary>
/// 违规严重程度枚举
/// 定义违规的严重程度级别,用于决策和审批流程
/// </summary>
public enum ViolationSeverity
{
/// <summary>
/// 信息级 - 纯信息提示,不影响分配
/// 业务场景:建议性信息、优化提示、统计数据
/// 处理方式:记录但不影响分配决策
/// </summary>
Info = 0,
/// <summary>
/// 低级 - 轻微问题,可接受
/// 业务场景:次优选择、轻微偏好违背、资源利用率稍低
/// 处理方式:允许分配,但降低优先级
/// </summary>
Low = 1,
/// <summary>
/// 警告级 - 需要关注但不阻止
/// 业务场景:连续工作天数较多、工作负载偏高、非首选班次
/// 处理方式:允许分配,但给出明确警告
/// </summary>
Warning = 2,
/// <summary>
/// 中级 - 需要关注的问题
/// 业务场景:技能匹配度不理想、班次连续性问题、资源冲突风险
/// 处理方式:默认阻止分配,可通过管理员审批
/// </summary>
Medium = 3,
/// <summary>
/// 高级 - 重要问题,建议阻止
/// 业务场景:工作限制超出、重要资质缺失、严重时间冲突
/// 处理方式:强烈建议阻止,需要高级权限审批
/// </summary>
High = 4,
/// <summary>
/// 错误级 - 业务规则违反,必须处理
/// 业务场景:违反硬性约束、安全规定冲突、合规性问题
/// 处理方式:阻止分配,必须修复后重试
/// </summary>
Error = 5,
/// <summary>
/// 严重级 - 系统级问题,完全阻止
/// 业务场景:数据完整性问题、系统状态异常、关键资源不可用
/// 处理方式:完全阻止分配,需要系统级修复
/// </summary>
Critical = 6
}
/// <summary>
/// 警告级别枚举
/// </summary>
public enum WarningLevel
{
/// <summary>
/// 低级警告
/// </summary>
Low = 1,
/// <summary>
/// 中级警告
/// </summary>
Medium = 2,
/// <summary>
/// 高级警告
/// </summary>
High = 3
}
/// <summary>
/// 违规分类枚举
/// </summary>
public enum ViolationCategory
{
/// <summary>
/// 通用违规
/// </summary>
General = 0,
/// <summary>
/// 资质相关违规
/// </summary>
Qualification = 1,
/// <summary>
/// 时间冲突违规
/// </summary>
TimeConflict = 2,
/// <summary>
/// 工作限制违规
/// </summary>
WorkLimit = 3,
/// <summary>
/// 班次规则违规
/// </summary>
ShiftRule = 4,
/// <summary>
/// 业务规则违规
/// </summary>
BusinessRule = 5,
/// <summary>
/// 安全规定违规
/// </summary>
Safety = 6,
/// <summary>
/// 合规性违规
/// </summary>
Compliance = 7,
/// <summary>
/// 系统状态违规
/// </summary>
SystemState = 8
}
/// <summary>
/// 审批级别枚举
/// </summary>
public enum ApprovalLevel
{
/// <summary>
/// 无需审批
/// </summary>
None = 0,
/// <summary>
/// 自动审批
/// </summary>
Automatic = 1,
/// <summary>
/// 主管审批
/// </summary>
Supervisor = 2,
/// <summary>
/// 管理员审批
/// </summary>
Manager = 3,
/// <summary>
/// 高级管理员审批
/// </summary>
SeniorManager = 4,
/// <summary>
/// 系统管理员审批
/// </summary>
SystemAdmin = 5
}
/// <summary>
/// 违规风险评估
/// </summary>
public class ViolationRiskAssessment
{
/// <summary>
/// 安全风险等级 (1-10)
/// </summary>
public int SafetyRiskLevel { get; set; } = 1;
/// <summary>
/// 合规风险等级 (1-10)
/// </summary>
public int ComplianceRiskLevel { get; set; } = 1;
/// <summary>
/// 运营风险等级 (1-10)
/// </summary>
public int OperationalRiskLevel { get; set; } = 1;
/// <summary>
/// 财务风险等级 (1-10)
/// </summary>
public int FinancialRiskLevel { get; set; } = 1;
/// <summary>
/// 综合风险评分 (1-10)
/// </summary>
public double OverallRiskScore => (SafetyRiskLevel + ComplianceRiskLevel + OperationalRiskLevel + FinancialRiskLevel) / 4.0;
/// <summary>
/// 风险描述
/// </summary>
public string RiskDescription { get; set; } = string.Empty;
/// <summary>
/// 缓解措施建议
/// </summary>
public List<string> MitigationSuggestions { get; set; } = new();
}
/// <summary>
/// 违规严重程度判定辅助类
/// 智能排班系统违规严重程度业务逻辑判定器
/// 深度业务思考:根据不同业务场景智能判定违规的真实严重程度和处理方式
/// </summary>
public static class ViolationSeverityJudge
{
/// <summary>
/// 判定是否为阻塞性违规
/// 深度业务思考:根据严重程度和业务影响综合判断是否应该阻止分配
/// </summary>
public static bool IsBlockingViolation(ViolationSeverity severity, int businessImpact = 5, ViolationCategory category = ViolationCategory.General)
{
// 信息级和低级违规不阻塞
if (severity <= ViolationSeverity.Low) return false;
// 警告级违规根据业务影响和分类判断
if (severity == ViolationSeverity.Warning)
{
// 安全和合规相关的警告需要阻塞
if (category == ViolationCategory.Safety || category == ViolationCategory.Compliance)
return businessImpact >= 7;
// 其他警告不阻塞
return false;
}
// 中级违规根据分类判断
if (severity == ViolationSeverity.Medium)
{
// 资质和安全相关的中级违规需要阻塞
return category == ViolationCategory.Qualification ||
category == ViolationCategory.Safety ||
category == ViolationCategory.Compliance;
}
// 高级及以上违规都需要阻塞
return severity >= ViolationSeverity.High;
}
/// <summary>
/// 计算违规失败阈值
/// 深度业务思考:不同业务场景下的违规容忍度不同
/// </summary>
public static ViolationSeverity GetFailureThreshold(ValidationContext context)
{
// 紧急情况下提高容忍度
if (context.IsEmergencyMode)
return ViolationSeverity.Error;
// 关键任务降低容忍度
if (context.IsCriticalTask)
return ViolationSeverity.Medium;
// 安全相关任务严格控制
if (context.IsSafetyRelated)
return ViolationSeverity.Warning;
// 默认阈值:高级违规
return ViolationSeverity.High;
}
/// <summary>
/// 获取所需审批级别
/// </summary>
public static ApprovalLevel GetRequiredApprovalLevel(ViolationSeverity severity, ViolationCategory category)
{
return (severity, category) switch
{
(ViolationSeverity.Info or ViolationSeverity.Low, _) => ApprovalLevel.None,
(ViolationSeverity.Warning, ViolationCategory.Safety or ViolationCategory.Compliance) => ApprovalLevel.Supervisor,
(ViolationSeverity.Warning, _) => ApprovalLevel.Automatic,
(ViolationSeverity.Medium, ViolationCategory.Safety) => ApprovalLevel.Manager,
(ViolationSeverity.Medium, _) => ApprovalLevel.Supervisor,
(ViolationSeverity.High, ViolationCategory.Safety or ViolationCategory.Compliance) => ApprovalLevel.SeniorManager,
(ViolationSeverity.High, _) => ApprovalLevel.Manager,
(ViolationSeverity.Error, ViolationCategory.SystemState) => ApprovalLevel.SystemAdmin,
(ViolationSeverity.Error, _) => ApprovalLevel.SeniorManager,
(ViolationSeverity.Critical, _) => ApprovalLevel.SystemAdmin,
_ => ApprovalLevel.None
};
}
/// <summary>
/// 判断是否可以通过审批强制执行
/// </summary>
public static bool CanOverrideWithApproval(ViolationSeverity severity, ViolationCategory category)
{
// 系统状态和关键安全违规不能强制执行
if (category == ViolationCategory.SystemState && severity >= ViolationSeverity.Error)
return false;
if (category == ViolationCategory.Safety && severity >= ViolationSeverity.Critical)
return false;
// 严重级系统违规不能强制执行
if (severity == ViolationSeverity.Critical &&
(category == ViolationCategory.SystemState || category == ViolationCategory.Compliance))
return false;
return true;
}
/// <summary>
/// 计算违规权重
/// 用于验证评分计算
/// </summary>
public static double GetViolationWeight(ViolationSeverity severity)
{
return severity switch
{
ViolationSeverity.Info => 0.5,
ViolationSeverity.Low => 1.0,
ViolationSeverity.Warning => 2.0,
ViolationSeverity.Medium => 5.0,
ViolationSeverity.High => 10.0,
ViolationSeverity.Error => 20.0,
ViolationSeverity.Critical => 50.0,
_ => 1.0
};
}
}
/// <summary>
/// 验证上下文
/// 用于判定违规严重程度的业务上下文
/// </summary>
public class ValidationContext
{
/// <summary>
/// 是否为紧急模式
/// </summary>
public bool IsEmergencyMode { get; set; } = false;
/// <summary>
/// 是否为关键任务
/// </summary>
public bool IsCriticalTask { get; set; } = false;
/// <summary>
/// 是否与安全相关
/// </summary>
public bool IsSafetyRelated { get; set; } = false;
/// <summary>
/// 业务优先级 (1-10)
/// </summary>
public int BusinessPriority { get; set; } = 5;
/// <summary>
/// 验证模式
/// </summary>
public ValidationMode Mode { get; set; } = ValidationMode.Standard;
/// <summary>
/// 额外上下文信息
/// </summary>
public Dictionary<string, object> AdditionalContext { get; set; } = new();
}
/// <summary>
/// 验证模式枚举
/// </summary>
public enum ValidationMode
{
/// <summary>
/// 标准验证
/// </summary>
Standard = 0,
/// <summary>
/// 严格验证
/// </summary>
Strict = 1,
/// <summary>
/// 宽松验证
/// </summary>
Lenient = 2,
/// <summary>
/// 紧急验证
/// </summary>
Emergency = 3
}
/// <summary>
/// 优化评分结果
/// 用于记录人员分配优化过程中的各项评分和决策信息
/// </summary>
public class OptimizationScoreResult
{
/// <summary>
/// 候选人信息
/// </summary>
public object Candidate { get; set; }
/// <summary>
/// 各维度评分
/// </summary>
public Dictionary<string, double> DimensionScores { get; set; } = new();
/// <summary>
/// 优化总分
/// </summary>
public double OptimizationScore { get; set; }
/// <summary>
/// 置信度
/// </summary>
public double Confidence { get; set; }
/// <summary>
/// 推荐等级
/// </summary>
public RecommendationLevel RecommendationLevel { get; set; }
/// <summary>
/// 优化理由
/// </summary>
public string OptimizationReason { get; set; } = string.Empty;
/// <summary>
/// 风险评估
/// </summary>
public RiskAssessment RiskAssessment { get; set; } = new();
}
/// <summary>
/// 推荐等级枚举
/// </summary>
public enum RecommendationLevel
{
/// <summary>
/// 强烈推荐
/// </summary>
HighlyRecommended = 5,
/// <summary>
/// 推荐
/// </summary>
Recommended = 4,
/// <summary>
/// 可接受
/// </summary>
Acceptable = 3,
/// <summary>
/// 不推荐
/// </summary>
NotRecommended = 2,
/// <summary>
/// 不可行
/// </summary>
NotFeasible = 1
}
/// <summary>
/// 风险评估
/// </summary>
public class RiskAssessment
{
/// <summary>
/// 风险因子列表
/// </summary>
public List<RiskFactor> RiskFactors { get; set; } = new();
/// <summary>
/// 总体风险等级
/// </summary>
public RiskLevel OverallRiskLevel { get; set; } = RiskLevel.Low;
/// <summary>
/// 风险评分
/// </summary>
public double RiskScore { get; set; }
/// <summary>
/// 风险描述
/// </summary>
public string RiskDescription { get; set; } = string.Empty;
/// <summary>
/// 缓解建议
/// </summary>
public List<string> MitigationSuggestions { get; set; } = new();
}
/// <summary>
/// 风险因子
/// </summary>
public class RiskFactor
{
/// <summary>
/// 风险类型
/// </summary>
public string RiskType { get; set; } = string.Empty;
/// <summary>
/// 风险描述
/// </summary>
public string Description { get; set; } = string.Empty;
/// <summary>
/// 风险等级
/// </summary>
public RiskLevel Level { get; set; } = RiskLevel.Low;
/// <summary>
/// 发生概率 (0-100)
/// </summary>
public double Probability { get; set; }
/// <summary>
/// 影响程度 (0-100)
/// </summary>
public double Impact { get; set; }
}
/// <summary>
/// 决策评分
/// </summary>
public class DecisionScore
{
/// <summary>
/// 最终评分
/// </summary>
public double FinalScore { get; set; }
/// <summary>
/// 置信度
/// </summary>
public double ConfidenceLevel { get; set; }
/// <summary>
/// 风险等级
/// </summary>
public RiskLevel RiskLevel { get; set; } = RiskLevel.Low;
/// <summary>
/// 决策理由
/// </summary>
public string DecisionReason { get; set; } = string.Empty;
}
}

View File

@ -0,0 +1,324 @@
using System;
using System.Collections.Generic;
using NPP.SmartSchedue.Api.Contracts.Services.Time.Output;
using NPP.SmartSchedue.Api.Contracts.Services.Work.Output;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration.Output;
/// <summary>
/// 撤销整合记录结果
/// 包含撤销操作的详细结果和状态信息
/// </summary>
public class CancelIntegrationRecordResult
{
/// <summary>
/// 撤销是否成功
/// </summary>
public bool IsSuccess { get; set; }
/// <summary>
/// 撤销成功消息
/// </summary>
public string SuccessMessage { get; set; } = string.Empty;
/// <summary>
/// 撤销失败消息
/// </summary>
public string ErrorMessage { get; set; } = string.Empty;
/// <summary>
/// 整合记录ID
/// </summary>
public long IntegrationRecordId { get; set; }
/// <summary>
/// 撤销时间
/// </summary>
public DateTime CancelledTime { get; set; }
/// <summary>
/// 撤销的批次编码
/// </summary>
public string IntegrationBatchCode { get; set; } = string.Empty;
/// <summary>
/// 成功撤销的任务详情
/// </summary>
public List<CancelledTaskDetail> CancelledTasks { get; set; } = new();
/// <summary>
/// 撤销失败的任务详情
/// </summary>
public List<FailedCancelTaskDetail> FailedCancelTasks { get; set; } = new();
/// <summary>
/// 任务状态回滚结果
/// </summary>
public TaskStatusRollbackResult TaskStatusRollbackResult { get; set; } = new();
/// <summary>
/// 撤销前验证结果
/// </summary>
public CancelValidationResult ValidationResult { get; set; } = new();
/// <summary>
/// 通知发送结果
/// </summary>
public List<NotificationSendResult> NotificationResults { get; set; } = new();
/// <summary>
/// 撤销统计信息
/// </summary>
public CancelStatistics Statistics { get; set; } = new();
/// <summary>
/// 警告信息列表
/// </summary>
public List<string> WarningMessages { get; set; } = new();
}
/// <summary>
/// 已撤销任务详情
/// </summary>
public class CancelledTaskDetail
{
/// <summary>
/// 任务ID
/// </summary>
public long TaskId { get; set; }
/// <summary>
/// 任务代码
/// </summary>
public string TaskCode { get; set; } = string.Empty;
/// <summary>
/// 撤销前分配的人员ID
/// </summary>
public long? PreviousAssignedPersonnelId { get; set; }
/// <summary>
/// 撤销前分配的人员姓名
/// </summary>
public string PreviousAssignedPersonnelName { get; set; } = string.Empty;
/// <summary>
/// 撤销前分配的设备ID
/// </summary>
public long? PreviousAssignedEquipmentId { get; set; }
/// <summary>
/// 撤销前分配的设备名称
/// </summary>
public string PreviousAssignedEquipmentName { get; set; } = string.Empty;
/// <summary>
/// 撤销前状态
/// </summary>
public string PreviousStatus { get; set; } = string.Empty;
/// <summary>
/// 撤销后状态
/// </summary>
public string CurrentStatus { get; set; } = string.Empty;
/// <summary>
/// 任务撤销时间
/// </summary>
public DateTime CancelTime { get; set; }
}
/// <summary>
/// 撤销失败任务详情
/// </summary>
public class FailedCancelTaskDetail
{
/// <summary>
/// 任务ID
/// </summary>
public long TaskId { get; set; }
/// <summary>
/// 任务代码
/// </summary>
public string TaskCode { get; set; } = string.Empty;
/// <summary>
/// 失败原因
/// </summary>
public string FailureReason { get; set; } = string.Empty;
/// <summary>
/// 详细错误信息
/// </summary>
public List<string> DetailedErrors { get; set; } = new();
/// <summary>
/// 解决建议
/// </summary>
public List<string> Suggestions { get; set; } = new();
/// <summary>
/// 当前任务状态
/// </summary>
public string CurrentTaskStatus { get; set; } = string.Empty;
}
/// <summary>
/// 任务状态回滚结果
/// </summary>
public class TaskStatusRollbackResult
{
/// <summary>
/// 回滚是否完全成功
/// </summary>
public bool IsFullySuccessful { get; set; }
/// <summary>
/// 成功回滚的任务数量
/// </summary>
public int SuccessfulRollbackCount { get; set; }
/// <summary>
/// 回滚失败的任务数量
/// </summary>
public int FailedRollbackCount { get; set; }
/// <summary>
/// 回滚详细结果
/// </summary>
public List<TaskRollbackDetail> RollbackDetails { get; set; } = new();
/// <summary>
/// 回滚耗时(毫秒)
/// </summary>
public long RollbackElapsedMilliseconds { get; set; }
}
/// <summary>
/// 任务回滚详情
/// </summary>
public class TaskRollbackDetail
{
/// <summary>
/// 任务ID
/// </summary>
public long TaskId { get; set; }
/// <summary>
/// 任务代码
/// </summary>
public string TaskCode { get; set; } = string.Empty;
/// <summary>
/// 回滚是否成功
/// </summary>
public bool IsRollbackSuccessful { get; set; }
/// <summary>
/// 原始状态
/// </summary>
public string OriginalStatus { get; set; } = string.Empty;
/// <summary>
/// 目标状态
/// </summary>
public string TargetStatus { get; set; } = string.Empty;
/// <summary>
/// 实际状态
/// </summary>
public string ActualStatus { get; set; } = string.Empty;
/// <summary>
/// 回滚错误信息
/// </summary>
public string RollbackError { get; set; } = string.Empty;
/// <summary>
/// 回滚时间
/// </summary>
public DateTime RollbackTime { get; set; }
}
/// <summary>
/// 撤销验证结果
/// </summary>
public class CancelValidationResult
{
/// <summary>
/// 验证是否通过
/// </summary>
public bool IsValid { get; set; }
/// <summary>
/// 验证执行时间
/// </summary>
public DateTime ValidationTime { get; set; }
/// <summary>
/// 阻塞性错误(会阻止撤销)
/// </summary>
public List<IntegrationValidationError> BlockingErrors { get; set; } = new();
/// <summary>
/// 警告性问题(不阻止撤销但需要注意)
/// </summary>
public List<ValidationWarning> Warnings { get; set; } = new();
/// <summary>
/// 验证详情
/// </summary>
public string ValidationDetails { get; set; } = string.Empty;
/// <summary>
/// 发现的进行中任务数量
/// </summary>
public int InProgressTaskCount { get; set; }
/// <summary>
/// 需要强制撤销的任务列表
/// </summary>
public List<long> TasksRequiringForceCancel { get; set; } = new();
}
/// <summary>
/// 撤销统计信息
/// </summary>
public class CancelStatistics
{
/// <summary>
/// 总任务数
/// </summary>
public int TotalTaskCount { get; set; }
/// <summary>
/// 成功撤销任务数
/// </summary>
public int SuccessfulCancelCount { get; set; }
/// <summary>
/// 撤销失败任务数
/// </summary>
public int FailedCancelCount { get; set; }
/// <summary>
/// 涉及人员数量
/// </summary>
public int InvolvedPersonnelCount { get; set; }
/// <summary>
/// 涉及设备数量
/// </summary>
public int InvolvedEquipmentCount { get; set; }
/// <summary>
/// 撤销成功率
/// </summary>
public decimal CancelSuccessRate { get; set; }
/// <summary>
/// 撤销总耗时(毫秒)
/// </summary>
public long TotalElapsedMilliseconds { get; set; }
}

View File

@ -0,0 +1,262 @@
using System;
using System.Collections.Generic;
namespace NPP.SmartSchedue.Api.Contracts.Services.Integration.Output;
/// <summary>
/// 完成整合记录结果
/// 包含完成操作的详细结果和统计信息
/// </summary>
public class CompleteIntegrationRecordResult
{
/// <summary>
/// 完成操作是否成功
/// </summary>
public bool IsSuccess { get; set; }
/// <summary>
/// 完成成功消息
/// </summary>
public string SuccessMessage { get; set; } = string.Empty;
/// <summary>
/// 完成失败消息
/// </summary>
public string ErrorMessage { get; set; } = string.Empty;
/// <summary>
/// 整合记录ID
/// </summary>
public long IntegrationRecordId { get; set; }
/// <summary>
/// 完成时间
/// </summary>
public DateTime CompletedTime { get; set; }
/// <summary>
/// 整合批次编码
/// </summary>
public string IntegrationBatchCode { get; set; } = string.Empty;
/// <summary>
/// 完成验证结果
/// 验证所有任务是否都已完成
/// </summary>
public CompleteValidationResult ValidationResult { get; set; } = new();
/// <summary>
/// 完成统计信息
/// </summary>
public CompleteStatistics Statistics { get; set; } = new();
/// <summary>
/// 警告信息列表
/// </summary>
public List<string> WarningMessages { get; set; } = new();
}
/// <summary>
/// 完成验证结果
/// </summary>
public class CompleteValidationResult
{
/// <summary>
/// 验证是否通过
/// </summary>
public bool IsValid { get; set; }
/// <summary>
/// 验证时间
/// </summary>
public DateTime ValidationTime { get; set; }
/// <summary>
/// 总任务数
/// </summary>
public int TotalTaskCount { get; set; }
/// <summary>
/// 已完成任务数
/// </summary>
public int CompletedTaskCount { get; set; }
/// <summary>
/// 未完成任务数
/// </summary>
public int IncompleteTaskCount { get; set; }
/// <summary>
/// 未完成任务列表
/// </summary>
public List<IncompleteTaskInfo> IncompleteTasks { get; set; } = new();
/// <summary>
/// 完成率
/// </summary>
public decimal CompletionRate { get; set; }
/// <summary>
/// 验证详情
/// </summary>
public string ValidationDetails { get; set; } = string.Empty;
}
/// <summary>
/// 未完成任务信息
/// </summary>
public class IncompleteTaskInfo
{
/// <summary>
/// 任务ID
/// </summary>
public long TaskId { get; set; }
/// <summary>
/// 任务代码
/// </summary>
public string TaskCode { get; set; } = string.Empty;
/// <summary>
/// 当前状态
/// </summary>
public string CurrentStatus { get; set; } = string.Empty;
/// <summary>
/// 分配人员姓名
/// </summary>
public string AssignedPersonnelName { get; set; } = string.Empty;
/// <summary>
/// 分配设备名称
/// </summary>
public string AssignedEquipmentName { get; set; } = string.Empty;
/// <summary>
/// 计划工作日期
/// </summary>
public DateTime WorkOrderDate { get; set; }
/// <summary>
/// 未完成原因
/// </summary>
public string IncompleteReason { get; set; } = string.Empty;
}
/// <summary>
/// 完成统计信息
/// </summary>
public class CompleteStatistics
{
/// <summary>
/// 整合记录持续时间(从发布到完成的毫秒数)
/// </summary>
public long IntegrationDurationMilliseconds { get; set; }
/// <summary>
/// 平均任务执行时间(毫秒)
/// </summary>
public long AverageTaskExecutionTime { get; set; }
/// <summary>
/// 最快完成任务时间(毫秒)
/// </summary>
public long FastestTaskTime { get; set; }
/// <summary>
/// 最慢完成任务时间(毫秒)
/// </summary>
public long SlowestTaskTime { get; set; }
/// <summary>
/// 人员效率统计
/// </summary>
public List<PersonnelEfficiencyStats> PersonnelEfficiencyStats { get; set; } = new();
/// <summary>
/// 设备利用率统计
/// </summary>
public List<EquipmentUtilizationStats> EquipmentUtilizationStats { get; set; } = new();
/// <summary>
/// 整体效率评分0-100
/// </summary>
public int OverallEfficiencyScore { get; set; }
}
/// <summary>
/// 人员效率统计
/// </summary>
public class PersonnelEfficiencyStats
{
/// <summary>
/// 人员ID
/// </summary>
public long PersonnelId { get; set; }
/// <summary>
/// 人员姓名
/// </summary>
public string PersonnelName { get; set; } = string.Empty;
/// <summary>
/// 完成任务数
/// </summary>
public int CompletedTaskCount { get; set; }
/// <summary>
/// 平均任务耗时(毫秒)
/// </summary>
public long AverageTaskTime { get; set; }
/// <summary>
/// 效率评分0-100
/// </summary>
public int EfficiencyScore { get; set; }
/// <summary>
/// 任务质量评分0-100
/// </summary>
public int QualityScore { get; set; }
}
/// <summary>
/// 设备利用率统计
/// </summary>
public class EquipmentUtilizationStats
{
/// <summary>
/// 设备ID
/// </summary>
public long EquipmentId { get; set; }
/// <summary>
/// 设备名称
/// </summary>
public string EquipmentName { get; set; } = string.Empty;
/// <summary>
/// 完成任务数
/// </summary>
public int CompletedTaskCount { get; set; }
/// <summary>
/// 总使用时间(毫秒)
/// </summary>
public long TotalUsageTime { get; set; }
/// <summary>
/// 实际利用率(百分比)
/// </summary>
public decimal ActualUtilizationRate { get; set; }
/// <summary>
/// 计划利用率(百分比)
/// </summary>
public decimal PlannedUtilizationRate { get; set; }
/// <summary>
/// 利用率达成度(百分比)
/// </summary>
public decimal UtilizationAchievementRate { get; set; }
}

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