Explorar o código

提示词排序调优

Lyyyi hai 3 semanas
pai
achega
223b8cca6d

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 549 - 0
.github/upgrades/scenarios/dotnet-version-upgrade/assessment.csv


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 13322 - 0
.github/upgrades/scenarios/dotnet-version-upgrade/assessment.json


+ 604 - 0
.github/upgrades/scenarios/dotnet-version-upgrade/assessment.md

@@ -0,0 +1,604 @@
+# Projects and dependencies analysis
+
+This document provides a comprehensive overview of the projects and their dependencies in the context of upgrading to .NETCoreApp,Version=v10.0.
+
+## Table of Contents
+
+- [Executive Summary](#executive-Summary)
+  - [Highlevel Metrics](#highlevel-metrics)
+  - [Projects Compatibility](#projects-compatibility)
+  - [Package Compatibility](#package-compatibility)
+  - [API Compatibility](#api-compatibility)
+  - [Binding Redirect Configuration](#binding-redirect-configuration)
+- [Aggregate NuGet packages details](#aggregate-nuget-packages-details)
+- [Top API Migration Challenges](#top-api-migration-challenges)
+  - [Technologies and Features](#technologies-and-features)
+  - [Most Frequent API Issues](#most-frequent-api-issues)
+- [Projects Relationship Graph](#projects-relationship-graph)
+- [Project Details](#project-details)
+
+  - [_Doc\_Doc.csproj](#_doc_doccsproj)
+  - [EntitySync\EntitySync.csproj](#entitysyncentitysynccsproj)
+  - [OASystem.Api\OASystem.API.csproj](#oasystemapioasystemapicsproj)
+  - [OASystem.Domain\OASystem.Domain.csproj](#oasystemdomainoasystemdomaincsproj)
+  - [OASystem.Infrastructure\OASystem.Infrastructure.csproj](#oasysteminfrastructureoasysteminfrastructurecsproj)
+  - [OASystem.RedisRepository\OASystem.RedisRepository.csproj](#oasystemredisrepositoryoasystemredisrepositorycsproj)
+  - [OpWin\OpWin.csproj](#opwinopwincsproj)
+
+
+## Executive Summary
+
+### Highlevel Metrics
+
+| Metric | Count | Status |
+| :--- | :---: | :--- |
+| Total Projects | 7 | All require upgrade |
+| Total NuGet Packages | 54 | 16 need upgrade |
+| Total Code Files | 663 |  |
+| Total Code Files with Incidents | 47 |  |
+| Total Lines of Code | 234099 |  |
+| Total Number of Issues | 548 |  |
+| Estimated LOC to modify | 522+ | at least 0.2% of codebase |
+
+### Projects Compatibility
+
+| Project | Target Framework | Difficulty | Package Issues | API Issues | Binding Issues | Est. LOC Impact | Description |
+| :--- | :---: | :---: | :---: | :---: | :---: | :---: | :--- |
+| [_Doc\_Doc.csproj](#_doc_doccsproj) | net6.0 | 🟢 Low | 0 | 0 | 0 |  | ClassLibrary, Sdk Style = True |
+| [EntitySync\EntitySync.csproj](#entitysyncentitysynccsproj) | net6.0 | 🟢 Low | 0 | 0 | 0 |  | DotNetCoreApp, Sdk Style = True |
+| [OASystem.Api\OASystem.API.csproj](#oasystemapioasystemapicsproj) | net6.0 | 🟡 Medium | 9 | 255 | 0 | 255+ | AspNetCore, Sdk Style = True |
+| [OASystem.Domain\OASystem.Domain.csproj](#oasystemdomainoasystemdomaincsproj) | net6.0 | 🟢 Low | 2 | 16 | 0 | 16+ | ClassLibrary, Sdk Style = True |
+| [OASystem.Infrastructure\OASystem.Infrastructure.csproj](#oasysteminfrastructureoasysteminfrastructurecsproj) | net6.0 | 🟢 Low | 7 | 9 | 0 | 9+ | ClassLibrary, Sdk Style = True |
+| [OASystem.RedisRepository\OASystem.RedisRepository.csproj](#oasystemredisrepositoryoasystemredisrepositorycsproj) | net6.0 | 🟢 Low | 1 | 2 | 0 | 2+ | ClassLibrary, Sdk Style = True |
+| [OpWin\OpWin.csproj](#opwinopwincsproj) | net6.0-windows | 🟡 Medium | 0 | 240 | 0 | 240+ | WinForms, Sdk Style = True |
+
+### Package Compatibility
+
+| Status | Count | Percentage |
+| :--- | :---: | :---: |
+| ✅ Compatible | 38 | 70.4% |
+| ⚠️ Incompatible | 6 | 11.1% |
+| 🔄 Upgrade Recommended | 10 | 18.5% |
+| ***Total NuGet Packages*** | ***54*** | ***100%*** |
+
+### API Compatibility
+
+| Category | Count | Impact |
+| :--- | :---: | :--- |
+| 🔴 Binary Incompatible | 291 | High - Require code changes |
+| 🟡 Source Incompatible | 98 | Medium - Needs re-compilation and potential conflicting API error fixing |
+| 🔵 Behavioral change | 133 | Low - Behavioral changes that may require testing at runtime |
+| ✅ Compatible | 251555 |  |
+| ***Total APIs Analyzed*** | ***252077*** |  |
+
+## Aggregate NuGet packages details
+
+| Package | Current Version | Suggested Version | Projects | Description |
+| :--- | :---: | :---: | :--- | :--- |
+| AlibabaCloud.SDK.Dysmsapi20170525 | 2.0.23 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| AspNetCore.HealthChecks.UI | 6.0.1 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| AspNetCore.HealthChecks.UI.Client | 6.0.2 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| AspNetCore.HealthChecks.UI.InMemory.Storage | 6.0.2 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| AspNetCoreRateLimit | 5.0.0 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| Aspose.Cells | 23.4.0 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj)<br/>[OASystem.Infrastructure.csproj](#oasysteminfrastructureoasysteminfrastructurecsproj) | ✅Compatible |
+| Autofac | 6.4.0 |  | [EntitySync.csproj](#entitysyncentitysynccsproj)<br/>[OASystem.API.csproj](#oasystemapioasystemapicsproj)<br/>[OASystem.Domain.csproj](#oasystemdomainoasystemdomaincsproj)<br/>[OASystem.Infrastructure.csproj](#oasysteminfrastructureoasysteminfrastructurecsproj) | ✅Compatible |
+| Autofac.Extensions.DependencyInjection | 8.0.0 |  | [EntitySync.csproj](#entitysyncentitysynccsproj)<br/>[OASystem.API.csproj](#oasystemapioasystemapicsproj)<br/>[OASystem.Domain.csproj](#oasystemdomainoasystemdomaincsproj)<br/>[OASystem.Infrastructure.csproj](#oasysteminfrastructureoasysteminfrastructurecsproj) | ✅Compatible |
+| AutoMapper | 12.0.0 | 16.1.1 | [OASystem.API.csproj](#oasystemapioasystemapicsproj)<br/>[OASystem.Domain.csproj](#oasystemdomainoasystemdomaincsproj)<br/>[OASystem.Infrastructure.csproj](#oasysteminfrastructureoasysteminfrastructurecsproj) | NuGet 包有安全漏洞 |
+| AutoMapper.Extensions.Microsoft.DependencyInjection | 12.0.0 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj)<br/>[OASystem.Domain.csproj](#oasystemdomainoasystemdomaincsproj)<br/>[OASystem.Infrastructure.csproj](#oasysteminfrastructureoasysteminfrastructurecsproj) | ✅Compatible |
+| Betalgo.OpenAI.GPT3 | 6.8.3 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ⚠️NuGet 包已弃用 |
+| BouncyCastle.NetCore | 1.8.8 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| CommonServiceLocator | 2.0.7 |  | [OASystem.Infrastructure.csproj](#oasysteminfrastructureoasysteminfrastructurecsproj) | ✅Compatible |
+| CurlThin | 0.0.7 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| CurlThin.Native | 0.0.8 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| EPPlus | 7.4.1 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| EyeSoft.FluentValidation | 3.0.7760.34875 |  | [OASystem.Domain.csproj](#oasystemdomainoasystemdomaincsproj) | ✅Compatible |
+| Flurl.Http | 3.2.4 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| iTextSharp | 5.5.13.5 | 5.5.13.3 | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ⚠️NuGet 包不兼容 |
+| JsonDiffPatch.Net | 2.3.0 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| MailKit | 4.15.1 | 4.17.0 | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | NuGet 包有安全漏洞 |
+| Markdig | 0.33.0 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| Microsoft.AspNetCore.Authentication.JwtBearer | 6.0.11 | 10.0.9 | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | 建议升级 NuGet 包 |
+| Microsoft.AspNetCore.Http.Abstractions | 2.2.0 |  | [OASystem.Infrastructure.csproj](#oasysteminfrastructureoasysteminfrastructurecsproj) | ⚠️NuGet 包已弃用 |
+| Microsoft.AspNetCore.Http.Features | 2.2.0 |  | [OASystem.Domain.csproj](#oasystemdomainoasystemdomaincsproj) | ⚠️NuGet 包已弃用 |
+| Microsoft.Extensions.Configuration | 7.0.0 | 10.0.9 | [OASystem.Infrastructure.csproj](#oasysteminfrastructureoasysteminfrastructurecsproj)<br/>[OASystem.RedisRepository.csproj](#oasystemredisrepositoryoasystemredisrepositorycsproj) | 建议升级 NuGet 包 |
+| Microsoft.Extensions.Configuration.Abstractions | 7.0.0 | 10.0.9 | [OASystem.Infrastructure.csproj](#oasysteminfrastructureoasysteminfrastructurecsproj) | 建议升级 NuGet 包 |
+| Microsoft.Extensions.Configuration.Binder | 7.0.0 | 10.0.9 | [OASystem.Infrastructure.csproj](#oasysteminfrastructureoasysteminfrastructurecsproj) | 建议升级 NuGet 包 |
+| Microsoft.Extensions.Diagnostics.HealthChecks | 6.0.0 | 10.0.9 | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | 建议升级 NuGet 包 |
+| Microsoft.Extensions.Logging.Abstractions | 6.0.0 | 10.0.9 | [OASystem.Infrastructure.csproj](#oasysteminfrastructureoasysteminfrastructurecsproj) | 建议升级 NuGet 包 |
+| Microsoft.Graph | 5.103.0 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| NodaTime | 3.2.0 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| NPOI | 2.6.0 |  | [OASystem.Infrastructure.csproj](#oasysteminfrastructureoasysteminfrastructurecsproj) | ⚠️NuGet 包已弃用 |
+| NPOI | 2.7.1 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ⚠️NuGet 包已弃用 |
+| PinYinConverterCore | 1.0.2 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| QRCoder | 1.4.1 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| Quartz | 3.6.2 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| QuartzUI.Extension.AspNetCore | 1.1.8 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| RestSharp | 106.15.0 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| Serilog | 4.0.0 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| Serilog.AspNetCore | 8.0.0 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| Serilog.Sinks.Console | 6.0.0 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| Serilog.Sinks.File | 5.0.0 |  | [OASystem.Domain.csproj](#oasystemdomainoasystemdomaincsproj)<br/>[OASystem.Infrastructure.csproj](#oasysteminfrastructureoasysteminfrastructurecsproj) | ✅Compatible |
+| Serilog.Sinks.File | 6.0.0 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| SqlSugarCore | 5.1.3.32 |  | [OASystem.Domain.csproj](#oasystemdomainoasystemdomaincsproj)<br/>[OASystem.Infrastructure.csproj](#oasysteminfrastructureoasysteminfrastructurecsproj) | ✅Compatible |
+| SqlSugarCore | 5.1.4.193 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| StackExchange.Redis | 2.6.96 |  | [OASystem.Infrastructure.csproj](#oasysteminfrastructureoasysteminfrastructurecsproj)<br/>[OASystem.RedisRepository.csproj](#oasystemredisrepositoryoasystemredisrepositorycsproj) | ✅Compatible |
+| Swashbuckle.AspNetCore | 6.4.0 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| System.Data.OleDb | 8.0.0 | 10.0.9 | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | 建议升级 NuGet 包 |
+| System.Security.Permissions | 6.0.1 | 10.0.9 | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | 建议升级 NuGet 包 |
+| TencentCloudSDK.Hunyuan | 3.0.1378 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| TencentCloudSDK.Ocr | 3.0.734 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+| TinyPinyin.Net | 1.0.2 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj)<br/>[OASystem.Infrastructure.csproj](#oasysteminfrastructureoasysteminfrastructurecsproj) | ✅Compatible |
+| UAParser | 3.1.47 |  | [OASystem.API.csproj](#oasystemapioasystemapicsproj) | ✅Compatible |
+
+## Top API Migration Challenges
+
+### Technologies and Features
+
+| Technology | Issues | Percentage | Migration Path |
+| :--- | :---: | :---: | :--- |
+| Windows Forms | 238 | 45.6% | Windows Forms APIs for building Windows desktop applications with traditional Forms-based UI that are available in .NET on Windows. Enable Windows Desktop support: Option 1 (Recommended): Target net9.0-windows; Option 2: Add <UseWindowsDesktop>true</UseWindowsDesktop>; Option 3 (Legacy): Use Microsoft.NET.Sdk.WindowsDesktop SDK. |
+| IdentityModel & Claims-based Security | 44 | 8.4% | Windows Identity Foundation (WIF), SAML, and claims-based authentication APIs that have been replaced by modern identity libraries. WIF was the original identity framework for .NET Framework. Migrate to Microsoft.IdentityModel.* packages (modern identity stack). |
+| GDI+ / System.Drawing | 22 | 4.2% | System.Drawing APIs for 2D graphics, imaging, and printing that are available via NuGet package System.Drawing.Common. Note: Not recommended for server scenarios due to Windows dependencies; consider cross-platform alternatives like SkiaSharp or ImageSharp for new code. |
+| Legacy Cryptography | 4 | 0.8% | Obsolete or insecure cryptographic algorithms that have been deprecated for security reasons. These algorithms are no longer considered secure by modern standards. Migrate to modern cryptographic APIs using secure algorithms. |
+| Deprecated Remoting & Serialization | 3 | 0.6% | Legacy .NET Remoting, BinaryFormatter, and related serialization APIs that are deprecated and removed for security reasons. Remoting provided distributed object communication but had significant security vulnerabilities. Migrate to gRPC, HTTP APIs, or modern serialization (System.Text.Json, protobuf). |
+
+### Most Frequent API Issues
+
+| API | Count | Percentage | Category |
+| :--- | :---: | :---: | :--- |
+| T:System.Net.Http.HttpContent | 72 | 13.8% | Behavioral Change |
+| T:System.Windows.Forms.Label | 41 | 7.9% | Binary Incompatible |
+| T:System.Uri | 23 | 4.4% | Behavioral Change |
+| T:System.Windows.Forms.ComboBox | 22 | 4.2% | Binary Incompatible |
+| T:System.Windows.Forms.Button | 22 | 4.2% | Binary Incompatible |
+| M:System.TimeSpan.FromSeconds(System.Double) | 16 | 3.1% | Source Incompatible |
+| T:System.Text.Json.JsonDocument | 15 | 2.9% | Behavioral Change |
+| M:System.TimeSpan.FromMinutes(System.Double) | 14 | 2.7% | Source Incompatible |
+| P:System.Windows.Forms.Label.Text | 14 | 2.7% | Binary Incompatible |
+| M:System.Uri.#ctor(System.String) | 10 | 1.9% | Behavioral Change |
+| P:System.Windows.Forms.Control.ForeColor | 9 | 1.7% | Binary Incompatible |
+| T:System.IdentityModel.Tokens.Jwt.JwtSecurityToken | 7 | 1.3% | Binary Incompatible |
+| T:System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler | 7 | 1.3% | Binary Incompatible |
+| M:Microsoft.Extensions.Configuration.ConfigurationBinder.Get''1(Microsoft.Extensions.Configuration.IConfiguration) | 6 | 1.1% | Binary Incompatible |
+| M:System.TimeSpan.FromHours(System.Double) | 6 | 1.1% | Source Incompatible |
+| T:System.Windows.Forms.MessageBox | 6 | 1.1% | Binary Incompatible |
+| T:System.Windows.Forms.DialogResult | 6 | 1.1% | Binary Incompatible |
+| M:System.Windows.Forms.MessageBox.Show(System.String) | 6 | 1.1% | Binary Incompatible |
+| P:System.Windows.Forms.Control.Name | 6 | 1.1% | Binary Incompatible |
+| M:System.Net.Http.HttpContent.ReadAsStreamAsync | 5 | 1.0% | Behavioral Change |
+| M:System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.#ctor | 5 | 1.0% | Binary Incompatible |
+| M:Microsoft.Extensions.DependencyInjection.HttpClientFactoryServiceCollectionExtensions.AddHttpClient(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.String,System.Action{System.Net.Http.HttpClient}) | 5 | 1.0% | Behavioral Change |
+| T:System.Windows.Forms.Control.ControlCollection | 5 | 1.0% | Binary Incompatible |
+| P:System.Windows.Forms.Control.Controls | 5 | 1.0% | Binary Incompatible |
+| M:System.Windows.Forms.Control.ControlCollection.Add(System.Windows.Forms.Control) | 5 | 1.0% | Binary Incompatible |
+| P:System.Windows.Forms.Control.TabIndex | 5 | 1.0% | Binary Incompatible |
+| P:System.Windows.Forms.Control.Size | 5 | 1.0% | Binary Incompatible |
+| P:System.Windows.Forms.Control.Location | 5 | 1.0% | Binary Incompatible |
+| T:System.IdentityModel.Tokens.Jwt.JwtPayload | 4 | 0.8% | Binary Incompatible |
+| M:System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ReadJwtToken(System.String) | 4 | 0.8% | Binary Incompatible |
+| T:System.Drawing.Imaging.ImageFormat | 4 | 0.8% | Source Incompatible |
+| T:Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerEvents | 4 | 0.8% | Source Incompatible |
+| T:System.Windows.Forms.Application | 4 | 0.8% | Binary Incompatible |
+| T:System.Windows.Forms.ComboBox.ObjectCollection | 4 | 0.8% | Binary Incompatible |
+| P:System.Windows.Forms.ComboBox.Items | 4 | 0.8% | Binary Incompatible |
+| P:System.IdentityModel.Tokens.Jwt.JwtSecurityToken.Payload | 3 | 0.6% | Binary Incompatible |
+| P:System.Drawing.Image.Height | 3 | 0.6% | Source Incompatible |
+| P:System.Drawing.Image.Width | 3 | 0.6% | Source Incompatible |
+| M:System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.WriteToken(Microsoft.IdentityModel.Tokens.SecurityToken) | 3 | 0.6% | Binary Incompatible |
+| T:System.Security.Cryptography.RijndaelManaged | 3 | 0.6% | Source Incompatible |
+| T:System.Runtime.Serialization.Formatters.Binary.BinaryFormatter | 3 | 0.6% | Source Incompatible |
+| P:System.Windows.Forms.ComboBox.Text | 3 | 0.6% | Binary Incompatible |
+| T:System.Windows.Forms.AutoScaleMode | 3 | 0.6% | Binary Incompatible |
+| M:System.TimeSpan.FromDays(System.Double) | 2 | 0.4% | Source Incompatible |
+| T:System.IdentityModel.Tokens.Jwt.JwtRegisteredClaimNames | 2 | 0.4% | Binary Incompatible |
+| F:System.IdentityModel.Tokens.Jwt.JwtRegisteredClaimNames.Exp | 2 | 0.4% | Binary Incompatible |
+| T:System.Drawing.Image | 2 | 0.4% | Source Incompatible |
+| P:System.Drawing.Imaging.ImageFormat.Jpeg | 2 | 0.4% | Source Incompatible |
+| T:System.Drawing.Bitmap | 2 | 0.4% | Source Incompatible |
+| P:Microsoft.AspNetCore.Authentication.JwtBearer.MessageReceivedContext.Token | 2 | 0.4% | Source Incompatible |
+
+## Projects Relationship Graph
+
+Legend:
+📦 SDK-style project
+⚙️ Classic project
+
+```mermaid
+flowchart LR
+    P1["<b>📦&nbsp;OASystem.API.csproj</b><br/><small>net6.0</small>"]
+    P2["<b>📦&nbsp;EntitySync.csproj</b><br/><small>net6.0</small>"]
+    P3["<b>📦&nbsp;_Doc.csproj</b><br/><small>net6.0</small>"]
+    P4["<b>📦&nbsp;OASystem.RedisRepository.csproj</b><br/><small>net6.0</small>"]
+    P5["<b>📦&nbsp;OpWin.csproj</b><br/><small>net6.0-windows</small>"]
+    P6["<b>📦&nbsp;OASystem.Domain.csproj</b><br/><small>net6.0</small>"]
+    P7["<b>📦&nbsp;OASystem.Infrastructure.csproj</b><br/><small>net6.0</small>"]
+    P1 --> P4
+    P1 --> P6
+    P1 --> P7
+    P2 --> P1
+    P5 --> P1
+    P7 --> P4
+    P7 --> P6
+    click P1 "#oasystemapioasystemapicsproj"
+    click P2 "#entitysyncentitysynccsproj"
+    click P3 "#_doc_doccsproj"
+    click P4 "#oasystemredisrepositoryoasystemredisrepositorycsproj"
+    click P5 "#opwinopwincsproj"
+    click P6 "#oasystemdomainoasystemdomaincsproj"
+    click P7 "#oasysteminfrastructureoasysteminfrastructurecsproj"
+
+```
+
+## Project Details
+
+<a id="_doc_doccsproj"></a>
+### _Doc\_Doc.csproj
+
+#### Project Info
+
+- **Current Target Framework:** net6.0
+- **Proposed Target Framework:** net10.0
+- **SDK-style**: True
+- **Project Kind:** ClassLibrary
+- **Dependencies**: 0
+- **Dependants**: 0
+- **Number of Files**: 0
+- **Number of Files with Incidents**: 1
+- **Lines of Code**: 0
+- **Estimated LOC to modify**: 0+ (at least 0.0% of the project)
+
+#### Dependency Graph
+
+Legend:
+📦 SDK-style project
+⚙️ Classic project
+
+```mermaid
+flowchart TB
+    subgraph current["_Doc.csproj"]
+        MAIN["<b>📦&nbsp;_Doc.csproj</b><br/><small>net6.0</small>"]
+        click MAIN "#_doc_doccsproj"
+    end
+
+```
+
+### API Compatibility
+
+| Category | Count | Impact |
+| :--- | :---: | :--- |
+| 🔴 Binary Incompatible | 0 | High - Require code changes |
+| 🟡 Source Incompatible | 0 | Medium - Needs re-compilation and potential conflicting API error fixing |
+| 🔵 Behavioral change | 0 | Low - Behavioral changes that may require testing at runtime |
+| ✅ Compatible | 0 |  |
+| ***Total APIs Analyzed*** | ***0*** |  |
+
+<a id="entitysyncentitysynccsproj"></a>
+### EntitySync\EntitySync.csproj
+
+#### Project Info
+
+- **Current Target Framework:** net6.0
+- **Proposed Target Framework:** net10.0
+- **SDK-style**: True
+- **Project Kind:** DotNetCoreApp
+- **Dependencies**: 1
+- **Dependants**: 0
+- **Number of Files**: 1
+- **Number of Files with Incidents**: 1
+- **Lines of Code**: 191
+- **Estimated LOC to modify**: 0+ (at least 0.0% of the project)
+
+#### Dependency Graph
+
+Legend:
+📦 SDK-style project
+⚙️ Classic project
+
+```mermaid
+flowchart TB
+    subgraph current["EntitySync.csproj"]
+        MAIN["<b>📦&nbsp;EntitySync.csproj</b><br/><small>net6.0</small>"]
+        click MAIN "#entitysyncentitysynccsproj"
+    end
+    subgraph downstream["Dependencies (1"]
+        P1["<b>📦&nbsp;OASystem.API.csproj</b><br/><small>net6.0</small>"]
+        click P1 "#oasystemapioasystemapicsproj"
+    end
+    MAIN --> P1
+
+```
+
+### API Compatibility
+
+| Category | Count | Impact |
+| :--- | :---: | :--- |
+| 🔴 Binary Incompatible | 0 | High - Require code changes |
+| 🟡 Source Incompatible | 0 | Medium - Needs re-compilation and potential conflicting API error fixing |
+| 🔵 Behavioral change | 0 | Low - Behavioral changes that may require testing at runtime |
+| ✅ Compatible | 58 |  |
+| ***Total APIs Analyzed*** | ***58*** |  |
+
+<a id="oasystemapioasystemapicsproj"></a>
+### OASystem.Api\OASystem.API.csproj
+
+#### Project Info
+
+- **Current Target Framework:** net6.0
+- **Proposed Target Framework:** net10.0
+- **SDK-style**: True
+- **Project Kind:** AspNetCore
+- **Dependencies**: 3
+- **Dependants**: 2
+- **Number of Files**: 102
+- **Number of Files with Incidents**: 28
+- **Lines of Code**: 119063
+- **Estimated LOC to modify**: 255+ (at least 0.2% of the project)
+
+#### Dependency Graph
+
+Legend:
+📦 SDK-style project
+⚙️ Classic project
+
+```mermaid
+flowchart TB
+    subgraph upstream["Dependants (2)"]
+        P2["<b>📦&nbsp;EntitySync.csproj</b><br/><small>net6.0</small>"]
+        P5["<b>📦&nbsp;OpWin.csproj</b><br/><small>net6.0-windows</small>"]
+        click P2 "#entitysyncentitysynccsproj"
+        click P5 "#opwinopwincsproj"
+    end
+    subgraph current["OASystem.API.csproj"]
+        MAIN["<b>📦&nbsp;OASystem.API.csproj</b><br/><small>net6.0</small>"]
+        click MAIN "#oasystemapioasystemapicsproj"
+    end
+    subgraph downstream["Dependencies (3"]
+        P4["<b>📦&nbsp;OASystem.RedisRepository.csproj</b><br/><small>net6.0</small>"]
+        P6["<b>📦&nbsp;OASystem.Domain.csproj</b><br/><small>net6.0</small>"]
+        P7["<b>📦&nbsp;OASystem.Infrastructure.csproj</b><br/><small>net6.0</small>"]
+        click P4 "#oasystemredisrepositoryoasystemredisrepositorycsproj"
+        click P6 "#oasystemdomainoasystemdomaincsproj"
+        click P7 "#oasysteminfrastructureoasysteminfrastructurecsproj"
+    end
+    P2 --> MAIN
+    P5 --> MAIN
+    MAIN --> P4
+    MAIN --> P6
+    MAIN --> P7
+
+```
+
+### API Compatibility
+
+| Category | Count | Impact |
+| :--- | :---: | :--- |
+| 🔴 Binary Incompatible | 53 | High - Require code changes |
+| 🟡 Source Incompatible | 74 | Medium - Needs re-compilation and potential conflicting API error fixing |
+| 🔵 Behavioral change | 128 | Low - Behavioral changes that may require testing at runtime |
+| ✅ Compatible | 144679 |  |
+| ***Total APIs Analyzed*** | ***144934*** |  |
+
+#### Project Technologies and Features
+
+| Technology | Issues | Percentage | Migration Path |
+| :--- | :---: | :---: | :--- |
+| GDI+ / System.Drawing | 22 | 8.6% | System.Drawing APIs for 2D graphics, imaging, and printing that are available via NuGet package System.Drawing.Common. Note: Not recommended for server scenarios due to Windows dependencies; consider cross-platform alternatives like SkiaSharp or ImageSharp for new code. |
+| IdentityModel & Claims-based Security | 44 | 17.3% | Windows Identity Foundation (WIF), SAML, and claims-based authentication APIs that have been replaced by modern identity libraries. WIF was the original identity framework for .NET Framework. Migrate to Microsoft.IdentityModel.* packages (modern identity stack). |
+
+<a id="oasystemdomainoasystemdomaincsproj"></a>
+### OASystem.Domain\OASystem.Domain.csproj
+
+#### Project Info
+
+- **Current Target Framework:** net6.0
+- **Proposed Target Framework:** net10.0
+- **SDK-style**: True
+- **Project Kind:** ClassLibrary
+- **Dependencies**: 0
+- **Dependants**: 2
+- **Number of Files**: 455
+- **Number of Files with Incidents**: 7
+- **Lines of Code**: 65557
+- **Estimated LOC to modify**: 16+ (at least 0.0% of the project)
+
+#### Dependency Graph
+
+Legend:
+📦 SDK-style project
+⚙️ Classic project
+
+```mermaid
+flowchart TB
+    subgraph upstream["Dependants (2)"]
+        P1["<b>📦&nbsp;OASystem.API.csproj</b><br/><small>net6.0</small>"]
+        P7["<b>📦&nbsp;OASystem.Infrastructure.csproj</b><br/><small>net6.0</small>"]
+        click P1 "#oasystemapioasystemapicsproj"
+        click P7 "#oasysteminfrastructureoasysteminfrastructurecsproj"
+    end
+    subgraph current["OASystem.Domain.csproj"]
+        MAIN["<b>📦&nbsp;OASystem.Domain.csproj</b><br/><small>net6.0</small>"]
+        click MAIN "#oasystemdomainoasystemdomaincsproj"
+    end
+    P1 --> MAIN
+    P7 --> MAIN
+
+```
+
+### API Compatibility
+
+| Category | Count | Impact |
+| :--- | :---: | :--- |
+| 🔴 Binary Incompatible | 0 | High - Require code changes |
+| 🟡 Source Incompatible | 16 | Medium - Needs re-compilation and potential conflicting API error fixing |
+| 🔵 Behavioral change | 0 | Low - Behavioral changes that may require testing at runtime |
+| ✅ Compatible | 52900 |  |
+| ***Total APIs Analyzed*** | ***52916*** |  |
+
+#### Project Technologies and Features
+
+| Technology | Issues | Percentage | Migration Path |
+| :--- | :---: | :---: | :--- |
+| Legacy Cryptography | 4 | 25.0% | Obsolete or insecure cryptographic algorithms that have been deprecated for security reasons. These algorithms are no longer considered secure by modern standards. Migrate to modern cryptographic APIs using secure algorithms. |
+| Deprecated Remoting & Serialization | 1 | 6.3% | Legacy .NET Remoting, BinaryFormatter, and related serialization APIs that are deprecated and removed for security reasons. Remoting provided distributed object communication but had significant security vulnerabilities. Migrate to gRPC, HTTP APIs, or modern serialization (System.Text.Json, protobuf). |
+
+<a id="oasysteminfrastructureoasysteminfrastructurecsproj"></a>
+### OASystem.Infrastructure\OASystem.Infrastructure.csproj
+
+#### Project Info
+
+- **Current Target Framework:** net6.0
+- **Proposed Target Framework:** net10.0
+- **SDK-style**: True
+- **Project Kind:** ClassLibrary
+- **Dependencies**: 2
+- **Dependants**: 1
+- **Number of Files**: 93
+- **Number of Files with Incidents**: 3
+- **Lines of Code**: 42988
+- **Estimated LOC to modify**: 9+ (at least 0.0% of the project)
+
+#### Dependency Graph
+
+Legend:
+📦 SDK-style project
+⚙️ Classic project
+
+```mermaid
+flowchart TB
+    subgraph upstream["Dependants (1)"]
+        P1["<b>📦&nbsp;OASystem.API.csproj</b><br/><small>net6.0</small>"]
+        click P1 "#oasystemapioasystemapicsproj"
+    end
+    subgraph current["OASystem.Infrastructure.csproj"]
+        MAIN["<b>📦&nbsp;OASystem.Infrastructure.csproj</b><br/><small>net6.0</small>"]
+        click MAIN "#oasysteminfrastructureoasysteminfrastructurecsproj"
+    end
+    subgraph downstream["Dependencies (2"]
+        P4["<b>📦&nbsp;OASystem.RedisRepository.csproj</b><br/><small>net6.0</small>"]
+        P6["<b>📦&nbsp;OASystem.Domain.csproj</b><br/><small>net6.0</small>"]
+        click P4 "#oasystemredisrepositoryoasystemredisrepositorycsproj"
+        click P6 "#oasystemdomainoasystemdomaincsproj"
+    end
+    P1 --> MAIN
+    MAIN --> P4
+    MAIN --> P6
+
+```
+
+### API Compatibility
+
+| Category | Count | Impact |
+| :--- | :---: | :--- |
+| 🔴 Binary Incompatible | 0 | High - Require code changes |
+| 🟡 Source Incompatible | 5 | Medium - Needs re-compilation and potential conflicting API error fixing |
+| 🔵 Behavioral change | 4 | Low - Behavioral changes that may require testing at runtime |
+| ✅ Compatible | 46724 |  |
+| ***Total APIs Analyzed*** | ***46733*** |  |
+
+<a id="oasystemredisrepositoryoasystemredisrepositorycsproj"></a>
+### OASystem.RedisRepository\OASystem.RedisRepository.csproj
+
+#### Project Info
+
+- **Current Target Framework:** net6.0
+- **Proposed Target Framework:** net10.0
+- **SDK-style**: True
+- **Project Kind:** ClassLibrary
+- **Dependencies**: 0
+- **Dependants**: 2
+- **Number of Files**: 12
+- **Number of Files with Incidents**: 2
+- **Lines of Code**: 1060
+- **Estimated LOC to modify**: 2+ (at least 0.2% of the project)
+
+#### Dependency Graph
+
+Legend:
+📦 SDK-style project
+⚙️ Classic project
+
+```mermaid
+flowchart TB
+    subgraph upstream["Dependants (2)"]
+        P1["<b>📦&nbsp;OASystem.API.csproj</b><br/><small>net6.0</small>"]
+        P7["<b>📦&nbsp;OASystem.Infrastructure.csproj</b><br/><small>net6.0</small>"]
+        click P1 "#oasystemapioasystemapicsproj"
+        click P7 "#oasysteminfrastructureoasysteminfrastructurecsproj"
+    end
+    subgraph current["OASystem.RedisRepository.csproj"]
+        MAIN["<b>📦&nbsp;OASystem.RedisRepository.csproj</b><br/><small>net6.0</small>"]
+        click MAIN "#oasystemredisrepositoryoasystemredisrepositorycsproj"
+    end
+    P1 --> MAIN
+    P7 --> MAIN
+
+```
+
+### API Compatibility
+
+| Category | Count | Impact |
+| :--- | :---: | :--- |
+| 🔴 Binary Incompatible | 0 | High - Require code changes |
+| 🟡 Source Incompatible | 2 | Medium - Needs re-compilation and potential conflicting API error fixing |
+| 🔵 Behavioral change | 0 | Low - Behavioral changes that may require testing at runtime |
+| ✅ Compatible | 510 |  |
+| ***Total APIs Analyzed*** | ***512*** |  |
+
+#### Project Technologies and Features
+
+| Technology | Issues | Percentage | Migration Path |
+| :--- | :---: | :---: | :--- |
+| Deprecated Remoting & Serialization | 2 | 100.0% | Legacy .NET Remoting, BinaryFormatter, and related serialization APIs that are deprecated and removed for security reasons. Remoting provided distributed object communication but had significant security vulnerabilities. Migrate to gRPC, HTTP APIs, or modern serialization (System.Text.Json, protobuf). |
+
+<a id="opwinopwincsproj"></a>
+### OpWin\OpWin.csproj
+
+#### Project Info
+
+- **Current Target Framework:** net6.0-windows
+- **Proposed Target Framework:** net10.0-windows
+- **SDK-style**: True
+- **Project Kind:** WinForms
+- **Dependencies**: 1
+- **Dependants**: 0
+- **Number of Files**: 4
+- **Number of Files with Incidents**: 5
+- **Lines of Code**: 5240
+- **Estimated LOC to modify**: 240+ (at least 4.6% of the project)
+
+#### Dependency Graph
+
+Legend:
+📦 SDK-style project
+⚙️ Classic project
+
+```mermaid
+flowchart TB
+    subgraph current["OpWin.csproj"]
+        MAIN["<b>📦&nbsp;OpWin.csproj</b><br/><small>net6.0-windows</small>"]
+        click MAIN "#opwinopwincsproj"
+    end
+    subgraph downstream["Dependencies (1"]
+        P1["<b>📦&nbsp;OASystem.API.csproj</b><br/><small>net6.0</small>"]
+        click P1 "#oasystemapioasystemapicsproj"
+    end
+    MAIN --> P1
+
+```
+
+### API Compatibility
+
+| Category | Count | Impact |
+| :--- | :---: | :--- |
+| 🔴 Binary Incompatible | 238 | High - Require code changes |
+| 🟡 Source Incompatible | 1 | Medium - Needs re-compilation and potential conflicting API error fixing |
+| 🔵 Behavioral change | 1 | Low - Behavioral changes that may require testing at runtime |
+| ✅ Compatible | 6684 |  |
+| ***Total APIs Analyzed*** | ***6924*** |  |
+
+#### Project Technologies and Features
+
+| Technology | Issues | Percentage | Migration Path |
+| :--- | :---: | :---: | :--- |
+| Windows Forms | 238 | 99.2% | Windows Forms APIs for building Windows desktop applications with traditional Forms-based UI that are available in .NET on Windows. Enable Windows Desktop support: Option 1 (Recommended): Target net9.0-windows; Option 2: Add <UseWindowsDesktop>true</UseWindowsDesktop>; Option 3 (Legacy): Use Microsoft.NET.Sdk.WindowsDesktop SDK. |
+

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 17071 - 0
.github/upgrades/scenarios/dotnet-version-upgrade/dependencies-health.json


+ 14 - 0
.github/upgrades/scenarios/dotnet-version-upgrade/scenario.json

@@ -0,0 +1,14 @@
+{
+  "scenarioId": "dotnet-version-upgrade",
+  "operationId": "1a3e159b-594c-41d6-a5a1-f8e670bda913",
+  "description": "Upgrade .NET projects to newer .NET versions, including guidance on current release status, support lifecycle (LTS/STS), and recommended upgrade targets.",
+  "startTime": "2026-06-12T01:49:15.5588562Z",
+  "lastUpdateTime": "2026-06-12T01:53:13.373704Z",
+  "properties": {
+    "UpgradeTargetFramework": "net10.0",
+    "taskStates": {
+      "01-libs": "InProgress"
+    }
+  },
+  "folderPath": ""
+}

+ 6 - 0
.github/upgrades/scenarios/dotnet-version-upgrade/tasks/01-libs/task.md

@@ -0,0 +1,6 @@
+# 01-libs: 基础类库和公共库
+
+   - 01.01 OASystem.Domain: 升级 NuGet 包(AutoMapper、Microsoft.Extensions 等),编译并修复兼容性问题
+   - 01.02 OASystem.Infrastructure: 升级 NuGet 包并验证数据库访问、配置绑定
+   - 01.03 OASystem.RedisRepository: 升级 Redis 相关包并验证
+

+ 13 - 0
.github/upgrades/scenarios/dotnet-version-upgrade/tasks/01.01-domain/task.md

@@ -0,0 +1,13 @@
+# 01.01-domain: 升级 Domain
+
+## Objective
+升级 OASystem.Domain 的 NuGet 包并修复源码不兼容。
+
+## Steps
+1. 将 AutoMapper 升级到 16.x。
+2. 更新 Microsoft.Extensions.* 到兼容版本。
+3. 构建并修复所有警告。
+
+## Done when
+- 包已升级,项目构建无警告,相关测试通过
+

+ 14 - 0
.github/upgrades/scenarios/dotnet-version-upgrade/tasks/01.02-infrastructure/task.md

@@ -0,0 +1,14 @@
+# 01.02-infrastructure: 升级 Infrastructure
+
+## Objective
+升级 OASystem.Infrastructure 的包并修复配置与数据库访问兼容性。
+
+## Steps
+1. 更新 Microsoft.Extensions.* 包到兼容版本。
+2. 构建并修复兼容性问题。
+3. 验证配置绑定行为。
+
+## Done when
+- 包已更新且项目构建无警告
+- 配置绑定测试正常
+

+ 15 - 11
OASystem/OASystem.Api/Controllers/GroupsController.cs

@@ -11626,7 +11626,7 @@ FROM
                                 }
 
                                 // 2026 版 费用名称 处理(新版机票费用格式、费用创建时间))
-                                if (jpRes.AirTicketBasicInfos.Any() && jpRes.CreateTime >= GlobalConfig.AirTicketIntegrationDateTime)
+                                if (jpRes.IsNew)
                                 {
                                     var flights = FlightParser.ParseFlights(jpRes.FlightsDescription);
                                     var flightNumbers = flights.Select(x => x.FlightNumber).ToList();
@@ -13630,7 +13630,7 @@ FROM
         #region 合并相同值的列
 
         /// <summary>
-        /// 合并工作表中指定列中相邻的相同值单元格
+        /// 合并工作表中指定列中相邻的相同值单元格(空值和空字符串不合并)
         /// </summary>
         /// <param name="worksheet">要操作的工作表对象</param>
         /// <param name="columnIndex">需要合并的列的索引(从0开始计数,0表示第一列)</param>
@@ -13638,8 +13638,6 @@ FROM
         private void MergeSameValuesInColumn(Worksheet worksheet, int columnIndex, int startRow = 1)
         {
             Cells cells = worksheet.Cells;
-
-            // 使用 GetLastDataRow 方法获取列中有数据的最后一行索引
             int lastRow = cells.GetLastDataRow(columnIndex);
 
             if (startRow > lastRow) return;
@@ -13651,14 +13649,20 @@ FROM
             {
                 string cellValue = (row <= lastRow) ? cells[row, columnIndex].StringValue : null;
 
-                if ((row > lastRow) || cellValue != currentValue)
+                // 判断是否需要结束合并
+                bool shouldBreak = (row > lastRow) ||
+                                   (string.IsNullOrEmpty(cellValue) != string.IsNullOrEmpty(currentValue)) ||
+                                   (cellValue != currentValue);
+
+                if (shouldBreak)
                 {
+                    // 仅当值非空且合并行数大于1时才执行合并
                     int mergeRows = row - mergeStartRow;
-                    if (mergeRows > 1)
+                    if (mergeRows > 1 && !string.IsNullOrEmpty(currentValue))
                     {
                         cells.Merge(mergeStartRow, columnIndex, mergeRows, 1);
 
-                        // 可选:设置合并后单元格居中对齐
+                        // 设置居中对齐
                         Aspose.Cells.Style style = cells[mergeStartRow, columnIndex].GetStyle();
                         style.HorizontalAlignment = TextAlignmentType.Center;
                         style.VerticalAlignment = TextAlignmentType.Center;
@@ -13673,7 +13677,7 @@ FROM
                 }
             }
         }
-        
+
         #endregion
 
         /// <summary>
@@ -13984,7 +13988,7 @@ FROM
                                            .TrimStart().TrimEnd()
                                            .Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
 
-                            var star_Three = threeCodeList.FirstOrDefault(a => a.Three == tempstr[3].Substring(0, 3));
+                            var star_Three = threeCodeList.FirstOrDefault(a => a.Three == tempstr[2].Substring(0, 3));
                             string starCity = "";
                             if (star_Three != null)
                             {
@@ -13997,7 +14001,7 @@ FROM
                                 }
                                 starCity = str2;
                             }
-                            var End_Three = threeCodeList.FirstOrDefault(a => a.Three == tempstr[3].Substring(3, 3));
+                            var End_Three = threeCodeList.FirstOrDefault(a => a.Three == tempstr[2].Substring(3, 3));
                             string EndCity = "";
                             if (End_Three != null)
                             {
@@ -14020,7 +14024,7 @@ FROM
                                 str = _airTicketResRep.Processing(str);
                             }
                             air.SeatingClass = str;
-                            string dateTime = tempstr[2];
+                            string dateTime = tempstr[1];
                             string DateTemp = dateTime.Substring(2, 5).ToUpper();
                             air.FlightDate = DateTemp;
                             air.DepartureTime = tempstr[5];

+ 31 - 5
OASystem/OASystem.Api/Controllers/SearchController.cs

@@ -495,8 +495,8 @@ namespace OASystem.API.Controllers
                 .ToListAsync();
 
             var airInfos = await _sqlSugar.Queryable<Grp_AirTicketReservations>()
-                .Where(x => x.IsDel == 0 && groupIds.Contains(x.DIId) && !string.IsNullOrEmpty(x.TicketCode))
-                .Select(x => new { x.DIId, x.TicketCode, x.ClientName })
+                .Where(x => x.IsDel == 0 && groupIds.Contains(x.DIId))
+                .Select(x => new { x.DIId, x.TicketCode, x.ClientName,x.CustTicketInfos })
                 .ToListAsync();
 
             // 2. 解析客户名称ID
@@ -562,9 +562,35 @@ namespace OASystem.API.Controllers
             }
 
             // 5. 构建分组数据
-            var airLookup = airInfos
+            var airLookupOld = airInfos
                 .GroupBy(x => x.DIId)
-                .ToDictionary(g => g.Key, g => g.Select(x => x.TicketCode).Distinct().ToList());
+                .ToDictionary(
+                    g => g.Key,
+                    g => g.Select(x => x?.TicketCode?.Trim())
+                          .Where(code => !string.IsNullOrWhiteSpace(code)) 
+                          .Distinct()
+                          .ToList()
+                );
+
+            var airLookupNew = airInfos
+                .GroupBy(x => x.DIId)
+                .ToDictionary(
+                    g => g.Key,
+                    g => g.SelectMany(x => x.CustTicketInfos?.Select(y => y.TicketCode.Trim()) ?? Enumerable.Empty<string>())
+                          .Where(code => !string.IsNullOrWhiteSpace(code)) 
+                          .Distinct()
+                          .ToList()
+                );
+
+            var airLookup = airLookupOld
+                 .Concat(airLookupNew)
+                 .GroupBy(kvp => kvp.Key)
+                 .ToDictionary(
+                     g => g.Key,
+                     g => g.SelectMany(kvp => kvp.Value)
+                           .Distinct()
+                           .ToList()
+                 );
 
             var clientLookup = airInfos
                 .Where(x => !string.IsNullOrEmpty(x.ClientName) && clientNameCache.ContainsKey(x.ClientName))
@@ -678,7 +704,7 @@ namespace OASystem.API.Controllers
                         FieldWeights = new Dictionary<string, int>
                             {
                                 { "TeamName", 10 },
-                                { "TicketCodesLabel", 10 },
+                                { "TicketCodesLabel", 20 },
                                 { "ClientsLabel", 10 }
                             }
                     };

+ 1 - 1
OASystem/OASystem.Api/Controllers/StatisticsController.cs

@@ -868,7 +868,7 @@ ORDER BY
                     var currFlight = flights.Where(it => it.Id == item.AirId).FirstOrDefault();
                     if (currFlight != null)
                     {
-                        if (currFlight.AirTicketBasicInfos.Any() && currFlight.CreateTime >= GlobalConfig.AirTicketIntegrationDateTime)
+                        if (currFlight.IsNew)
                         {
                             item.FlightsCode = string.Join("、", currFlight.AirTicketBasicInfos.Select(x => x.FlightsCode).ToList());
                             item.FlightsCity = string.Join("/", currFlight.AirTicketBasicInfos.Select(x => x.FlightsCity).ToList());

+ 444 - 77
OASystem/OASystem.Api/OAMethodLib/GenericSearch/DynamicSearchService.cs

@@ -535,46 +535,9 @@ namespace OASystem.API.OAMethodLib.GenericSearch
         #endregion
 
         #region 私有方法 - 匹配度计算含出现位置权重(单字检索时全部出现)
-        /// <summary>
-        /// 在应用层计算匹配度
-        /// </summary>
-        private List<SearchResultItem<T>> CalculateMatchScore(List<T> data, DynamicSearchRequest request)
-        {
-            if (string.IsNullOrWhiteSpace(request.Keyword))
-            {
-                // 无关键词时,所有记录匹配度为0
-                return data.Select(item => new SearchResultItem<T>
-                {
-                    Data = item,
-                    MatchScore = 0
-                }).ToList();
-            }
-
-            var searchAnalysis = AnalyzeSearchPattern(request.Keyword);
-            var searchFields = request.FieldWeights?.Keys.ToList() ?? GetDefaultSearchFields();
-            var fieldWeights = request.FieldWeights ?? GetDefaultFieldWeights(searchFields);
-
-            var scoredItems = data.Select(item =>
-            {
-                var matchResult = CalculateItemMatchScore(item, searchAnalysis, searchFields, fieldWeights, request.RequireAllSingleChars);
-
-                return new SearchResultItem<T>
-                {
-                    Data = item,
-                    MatchScore = matchResult.TotalScore,
-                    MatchFields = matchResult.MatchFields
-                };
-            })
-            .Where(item => item.MatchScore > 0) // 只保留有匹配的记录
-            .OrderByDescending(item => item.MatchScore)
-            .ThenByDescending(item => GetCreateTime(item.Data))
-            .ToList();
-
-            return scoredItems;
-        }
 
         /// <summary>
-        /// 计算单个项的匹配度详情
+        /// 计算单个项的匹配度详情(激进提高完全匹配权重)
         /// </summary>
         private (int TotalScore, List<MatchFieldInfo> MatchFields) CalculateItemMatchScore(
             T item,
@@ -586,12 +549,9 @@ namespace OASystem.API.OAMethodLib.GenericSearch
             int totalScore = 0;
             var matchFields = new List<MatchFieldInfo>();
 
-            // 新增:根据参数检查是否所有单字都出现
             if (requireAllSingleChars && analysis.SingleChars.Any())
             {
                 bool allSingleCharsExist = CheckAllSingleCharsExist(item, analysis.SingleChars, searchFields);
-
-                // 如果要求所有单字必须出现但未完全匹配,直接返回0分
                 if (!allSingleCharsExist)
                 {
                     return (0, matchFields);
@@ -608,69 +568,158 @@ namespace OASystem.API.OAMethodLib.GenericSearch
                 int fieldScore = 0;
                 var fieldMatchReasons = new List<string>();
 
-                // 符号分割关键字匹配
+                // ========== 1. 符号分割关键字匹配 ==========
                 foreach (var segment in analysis.SymbolSegments)
                 {
                     var cleanSegment = Regex.Replace(segment, @"[^\u4e00-\u9fa5a-zA-Z0-9]", "");
-                    if (!string.IsNullOrEmpty(cleanSegment) && fieldValue.Contains(cleanSegment))
+                    if (string.IsNullOrEmpty(cleanSegment))
+                        continue;
+
+                    // ========== ★ 完全匹配:绝对优先 ==========
+                    if (fieldValue.Equals(cleanSegment))
+                    {
+                        int segmentScore = weight * 50;  // 超级权重,确保绝对第一
+                        fieldScore += segmentScore;
+                        fieldMatchReasons.Add($"★★★ 完全匹配 '{cleanSegment}' +{segmentScore}");
+                        continue;
+                    }
+
+                    // 检查是否包含完整关键字
+                    if (fieldValue.Contains(cleanSegment))
                     {
                         int segmentScore = weight;
 
-                        if (fieldValue.Equals(cleanSegment))
+                        if (fieldValue.StartsWith(cleanSegment))
                         {
-                            segmentScore += 15;
-                            fieldMatchReasons.Add($"完全匹配 '{cleanSegment}'");
-                        }
-                        else if (fieldValue.StartsWith(cleanSegment))
-                        {
-                            segmentScore += 10;
-                            fieldMatchReasons.Add($"开头匹配 '{cleanSegment}'");
+                            segmentScore += weight * 2;
+                            fieldMatchReasons.Add($"开头匹配 '{cleanSegment}' +{segmentScore}");
                         }
                         else if (fieldValue.EndsWith(cleanSegment))
                         {
-                            segmentScore += 5;
-                            fieldMatchReasons.Add($"结尾匹配 '{cleanSegment}'");
+                            segmentScore += weight;
+                            fieldMatchReasons.Add($"结尾匹配 '{cleanSegment}' +{segmentScore}");
                         }
                         else
                         {
-                            fieldMatchReasons.Add($"包含 '{cleanSegment}'");
+                            // 包含匹配:大幅降低得分,避免干扰完全匹配
+                            segmentScore = (int)(weight * 0.2);
+
+                            // 只有连续出现多次才稍微加分
+                            int consecutiveCount = CountConsecutiveOccurrences(fieldValue, cleanSegment);
+                            if (consecutiveCount > 1)
+                            {
+                                segmentScore += (int)(weight * 0.1 * consecutiveCount);
+                                fieldMatchReasons.Add($"连续出现 {consecutiveCount} 次 +{segmentScore}");
+                            }
+                            else
+                            {
+                                fieldMatchReasons.Add($"包含 '{cleanSegment}' +{segmentScore}");
+                            }
                         }
 
                         fieldScore += segmentScore;
                     }
+                    else
+                    {
+                        // ========== 按顺序匹配:大幅降低权重 ==========
+                        var orderedResult = CheckOrderedMatchWithConsecutive(fieldValue, cleanSegment);
+                        if (orderedResult.IsMatch && orderedResult.MatchedCount >= 2)
+                        {
+                            // 只有匹配率达到一定阈值才给分
+                            double matchRate = (double)orderedResult.MatchedCount / cleanSegment.Length;
+
+                            // 如果匹配率低于70%,几乎不给分
+                            if (matchRate < 0.7)
+                            {
+                                continue;
+                            }
+
+                            int orderedScore = (int)(weight * 0.1); // 极低基础分
+
+                            // 只有完全连续匹配且匹配率高才加分
+                            if (orderedResult.ConsecutiveLength >= cleanSegment.Length * 0.8)
+                            {
+                                orderedScore += (int)(weight * 0.3);
+                                fieldMatchReasons.Add($"连续匹配 {orderedResult.ConsecutiveLength} 个字符 +{orderedScore}");
+                            }
+
+                            fieldMatchReasons.Add($"按顺序匹配 '{cleanSegment}' ({orderedResult.MatchedCount}/{cleanSegment.Length}) +{orderedScore}");
+                            fieldScore += orderedScore;
+                        }
+                    }
                 }
 
-                // 单字匹配 - 加入位置权重计算
-                foreach (var singleChar in analysis.SingleChars)
+                // ========== 2. 单字匹配:大幅降低权重 ==========
+                if (analysis.SingleChars.Any())
                 {
-                    int count = fieldValue.Count(c => c == singleChar);
-                    if (count > 0)
-                    {
-                        int charScore = count * (int)(weight * 0.3);
+                    // 单字连续匹配检测:降低权重
+                    string singleCharString = new string(analysis.SingleChars.ToArray());
 
-                        // 计算位置权重奖励
-                        var positionBonus = CalculateSingleCharPositionBonus(fieldValue, singleChar, weight);
-                        charScore += positionBonus.Bonus;
+                    int maxConsecutiveSingle = 0;
+                    string bestConsecutiveMatch = "";
 
-                        if (fieldValue.StartsWith(singleChar.ToString()))
-                        {
-                            charScore += weight;
-                            fieldMatchReasons.Add($"开头单字 '{singleChar}' +{weight}");
-                        }
-                        else if (positionBonus.Bonus > 0)
+                    for (int i = 0; i < singleCharString.Length; i++)
+                    {
+                        for (int j = i + 1; j <= singleCharString.Length; j++)
                         {
-                            fieldMatchReasons.Add($"靠前单字 '{singleChar}' +{positionBonus.Bonus}");
+                            string subPattern = singleCharString.Substring(i, j - i);
+                            if (subPattern.Length >= 2 && fieldValue.Contains(subPattern))
+                            {
+                                if (subPattern.Length > maxConsecutiveSingle)
+                                {
+                                    maxConsecutiveSingle = subPattern.Length;
+                                    bestConsecutiveMatch = subPattern;
+                                }
+                            }
                         }
+                    }
 
-                        // 添加位置信息到原因
-                        if (positionBonus.FirstPosition >= 0)
+                    // 连续单字匹配加分(降低权重)
+                    if (maxConsecutiveSingle >= 3)  // 至少3个连续单字才加分
+                    {
+                        int consecutiveSingleBonus = (int)(weight * 0.2 * maxConsecutiveSingle);
+                        fieldScore += consecutiveSingleBonus;
+                        fieldMatchReasons.Add($"连续单字匹配 '{bestConsecutiveMatch}'({maxConsecutiveSingle}个) +{consecutiveSingleBonus}");
+                    }
+
+                    // 原有单字匹配逻辑(大幅降低权重)
+                    foreach (var singleChar in analysis.SingleChars)
+                    {
+                        int count = fieldValue.Count(c => c == singleChar);
+                        if (count > 0)
                         {
-                            fieldMatchReasons.Add($"位置{positionBonus.FirstPosition + 1}");
+                            int charScore = count * (int)(weight * 0.1);  // 从0.35降到0.1
+
+                            var positionBonus = CalculateSingleCharPositionBonus(fieldValue, singleChar, weight);
+                            charScore += (int)(positionBonus.Bonus * 0.3);  // 降低位置权重
+
+                            if (fieldValue.StartsWith(singleChar.ToString()))
+                            {
+                                charScore += (int)(weight * 0.2);
+                                fieldMatchReasons.Add($"开头单字 '{singleChar}' +{charScore}");
+                            }
+
+                            fieldMatchReasons.Add($"包含单字 '{singleChar}'({count}次)");
+                            fieldScore += charScore;
                         }
+                    }
+                }
 
-                        fieldMatchReasons.Add($"包含单字 '{singleChar}'({count}次)");
+                // ========== 3. 完整关键词匹配 ==========
+                string fullKeyword = string.Join("", analysis.SymbolSegments)
+                    .Replace(" ", "")
+                    .Replace(",", "")
+                    .Replace(",", "")
+                    .Replace("、", "")
+                    .Replace(";", "");
 
-                        fieldScore += charScore;
+                if (!string.IsNullOrEmpty(fullKeyword) && fullKeyword.Length >= 3)
+                {
+                    if (fieldValue.Contains(fullKeyword))
+                    {
+                        int fullMatchScore = weight * 3;
+                        fieldScore += fullMatchScore;
+                        fieldMatchReasons.Add($"完整关键词匹配 '{fullKeyword}' +{fullMatchScore}");
                     }
                 }
 
@@ -687,12 +736,330 @@ namespace OASystem.API.OAMethodLib.GenericSearch
                 }
             }
 
-            // 按分数排序匹配字段
             matchFields = matchFields.OrderByDescending(m => m.Score).ToList();
-
             return (totalScore, matchFields);
         }
 
+        /// <summary>
+        /// 检查按顺序匹配(含连续匹配信息)
+        /// </summary>
+        private OrderedMatchResult CheckOrderedMatchWithConsecutive(string fieldValue, string searchText)
+        {
+            var result = new OrderedMatchResult { IsMatch = false };
+
+            if (string.IsNullOrEmpty(fieldValue) || string.IsNullOrEmpty(searchText))
+                return result;
+
+            int searchIndex = 0;
+            int fieldIndex = 0;
+            var matchedPositions = new List<int>();
+            int consecutiveCount = 0;
+            int maxConsecutive = 0;
+
+            while (searchIndex < searchText.Length && fieldIndex < fieldValue.Length)
+            {
+                if (searchText[searchIndex] == fieldValue[fieldIndex])
+                {
+                    matchedPositions.Add(fieldIndex);
+                    searchIndex++;
+                    consecutiveCount++;
+                    maxConsecutive = Math.Max(maxConsecutive, consecutiveCount);
+                }
+                else
+                {
+                    consecutiveCount = 0;
+                }
+                fieldIndex++;
+            }
+
+            if (searchIndex >= 2)
+            {
+                result.IsMatch = true;
+                result.MatchedCount = searchIndex;
+                result.ConsecutiveLength = maxConsecutive;
+                result.StartPosition = matchedPositions.Any() ? matchedPositions.First() : -1;
+
+                // 计算平均间隔
+                if (matchedPositions.Count > 1)
+                {
+                    int totalGap = 0;
+                    for (int i = 1; i < matchedPositions.Count; i++)
+                    {
+                        totalGap += matchedPositions[i] - matchedPositions[i - 1] - 1;
+                    }
+                    result.AverageGap = totalGap / (matchedPositions.Count - 1);
+                }
+                else
+                {
+                    result.AverageGap = 0;
+                }
+            }
+
+            return result;
+        }
+
+        /// <summary>
+        /// 计算连续出现次数
+        /// </summary>
+        private int CountConsecutiveOccurrences(string text, string pattern)
+        {
+            if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(pattern))
+                return 0;
+
+            int count = 0;
+            int index = 0;
+            while ((index = text.IndexOf(pattern, index, StringComparison.Ordinal)) != -1)
+            {
+                count++;
+                index += pattern.Length;
+
+                // 检查是否紧接着再次出现
+                if (index < text.Length && text.IndexOf(pattern, index, StringComparison.Ordinal) == index)
+                {
+                    continue;
+                }
+                break;
+            }
+            return count;
+        }
+
+        /// <summary>
+        /// 计算按顺序匹配的分数
+        /// </summary>
+        private (int Score, List<string> Reasons) CalculateOrderedMatchScore(
+            string fieldValue,
+            string searchText,
+            int weight)
+        {
+            var reasons = new List<string>();
+            int score = 0;
+
+            if (string.IsNullOrEmpty(fieldValue) || string.IsNullOrEmpty(searchText))
+                return (0, reasons);
+
+            // 使用双指针检查是否按顺序出现
+            var orderedMatchResult = CheckOrderedMatch(fieldValue, searchText);
+
+            if (orderedMatchResult.IsMatch)
+            {
+                // 基础匹配分
+                int baseScore = weight / 2;
+
+                // 匹配率加分
+                double matchRate = (double)orderedMatchResult.MatchedCount / searchText.Length;
+                if (matchRate >= 0.9)
+                {
+                    int matchRateBonus = (int)(weight * 0.3);
+                    baseScore += matchRateBonus;
+                    reasons.Add($"按顺序匹配 '{searchText}' (匹配率{matchRate:P0}) +{matchRateBonus}");
+                }
+                else
+                {
+                    reasons.Add($"按顺序匹配 '{searchText}' (匹配率{matchRate:P0})");
+                }
+
+                // 连续匹配加分(匹配的字符在字段值中连续出现)
+                if (orderedMatchResult.ConsecutiveLength >= 2)
+                {
+                    int consecutiveBonus = (int)(weight * 0.2 * orderedMatchResult.ConsecutiveLength);
+                    baseScore += consecutiveBonus;
+                    reasons.Add($"连续匹配 {orderedMatchResult.ConsecutiveLength} 个字符 +{consecutiveBonus}");
+                }
+
+                // 开头匹配加分
+                if (orderedMatchResult.StartPosition == 0)
+                {
+                    int startBonus = weight / 3;
+                    baseScore += startBonus;
+                    reasons.Add($"开头匹配 +{startBonus}");
+                }
+
+                // 完全匹配(搜索词完全包含在字段值中且顺序一致)
+                if (orderedMatchResult.MatchedCount == searchText.Length &&
+                    orderedMatchResult.ConsecutiveLength >= searchText.Length)
+                {
+                    int fullMatchBonus = weight * 2;
+                    baseScore += fullMatchBonus;
+                    reasons.Add($"完全连续匹配 +{fullMatchBonus}");
+                }
+
+                score += baseScore;
+            }
+            else
+            {
+                // 部分匹配:搜索词的部分字符按顺序出现
+                var partialMatch = FindLongestOrderedSubsequence(fieldValue, searchText);
+                if (partialMatch.Length >= 2)
+                {
+                    int partialScore = (int)(weight * 0.3 * (partialMatch.Length / (double)searchText.Length));
+                    score += partialScore;
+                    reasons.Add($"部分按顺序匹配 '{partialMatch}' ({partialMatch.Length}/{searchText.Length}) +{partialScore}");
+                }
+            }
+
+            return (score, reasons);
+        }
+
+        /// <summary>
+        /// 检查是否按顺序匹配
+        /// </summary>
+        private OrderedMatchResult CheckOrderedMatch(string fieldValue, string searchText)
+        {
+            var result = new OrderedMatchResult { IsMatch = false };
+
+            // 使用双指针检查是否按顺序出现
+            int searchIndex = 0;
+            int fieldIndex = 0;
+            var matchedPositions = new List<int>();
+            int consecutiveCount = 0;
+            int maxConsecutive = 0;
+
+            while (searchIndex < searchText.Length && fieldIndex < fieldValue.Length)
+            {
+                if (searchText[searchIndex] == fieldValue[fieldIndex])
+                {
+                    matchedPositions.Add(fieldIndex);
+                    searchIndex++;
+                    consecutiveCount++;
+                    maxConsecutive = Math.Max(maxConsecutive, consecutiveCount);
+                }
+                else
+                {
+                    consecutiveCount = 0;
+                }
+                fieldIndex++;
+            }
+
+            // 如果至少匹配了2个字符
+            if (searchIndex >= 2)
+            {
+                result.IsMatch = true;
+                result.MatchedCount = searchIndex;
+                result.ConsecutiveLength = maxConsecutive;
+                result.StartPosition = matchedPositions.Any() ? matchedPositions.First() : -1;
+
+                // 计算平均间隔
+                if (matchedPositions.Count > 1)
+                {
+                    int totalGap = 0;
+                    for (int i = 1; i < matchedPositions.Count; i++)
+                    {
+                        totalGap += matchedPositions[i] - matchedPositions[i - 1] - 1;
+                    }
+                    result.AverageGap = totalGap / (matchedPositions.Count - 1);
+                }
+                else
+                {
+                    result.AverageGap = 0;
+                }
+            }
+
+            return result;
+        }
+
+        /// <summary>
+        /// 查找最长有序子序列(LCS算法)
+        /// </summary>
+        private string FindLongestOrderedSubsequence(string fieldValue, string searchText)
+        {
+            if (string.IsNullOrEmpty(fieldValue) || string.IsNullOrEmpty(searchText))
+                return "";
+
+            // 动态规划求最长公共子序列
+            int m = fieldValue.Length;
+            int n = searchText.Length;
+            var dp = new int[m + 1, n + 1];
+
+            for (int i = 1; i <= m; i++)
+            {
+                for (int j = 1; j <= n; j++)
+                {
+                    if (fieldValue[i - 1] == searchText[j - 1])
+                        dp[i, j] = dp[i - 1, j - 1] + 1;
+                    else
+                        dp[i, j] = Math.Max(dp[i - 1, j], dp[i, j - 1]);
+                }
+            }
+
+            // 回溯获取最长公共子序列
+            int length = dp[m, n];
+            if (length < 2) return "";
+
+            var result = new char[length];
+            int idx = length - 1;
+            int x = m, y = n;
+
+            while (x > 0 && y > 0)
+            {
+                if (fieldValue[x - 1] == searchText[y - 1])
+                {
+                    result[idx--] = fieldValue[x - 1];
+                    x--;
+                    y--;
+                }
+                else if (dp[x - 1, y] > dp[x, y - 1])
+                {
+                    x--;
+                }
+                else
+                {
+                    y--;
+                }
+            }
+
+            return new string(result);
+        }
+
+        /// <summary>
+        /// 按顺序匹配结果
+        /// </summary>
+        private class OrderedMatchResult
+        {
+            public bool IsMatch { get; set; }
+            public int MatchedCount { get; set; }
+            public int ConsecutiveLength { get; set; }
+            public int StartPosition { get; set; }
+            public int AverageGap { get; set; }
+        }
+
+        /// <summary>
+        /// 在应用层计算匹配度
+        /// </summary>
+        private List<SearchResultItem<T>> CalculateMatchScore(List<T> data, DynamicSearchRequest request)
+        {
+            if (string.IsNullOrWhiteSpace(request.Keyword))
+            {
+                // 无关键词时,所有记录匹配度为0
+                return data.Select(item => new SearchResultItem<T>
+                {
+                    Data = item,
+                    MatchScore = 0
+                }).ToList();
+            }
+
+            var searchAnalysis = AnalyzeSearchPattern(request.Keyword);
+            var searchFields = request.FieldWeights?.Keys.ToList() ?? GetDefaultSearchFields();
+            var fieldWeights = request.FieldWeights ?? GetDefaultFieldWeights(searchFields);
+
+            var scoredItems = data.Select(item =>
+            {
+                var matchResult = CalculateItemMatchScore(item, searchAnalysis, searchFields, fieldWeights, request.RequireAllSingleChars);
+
+                return new SearchResultItem<T>
+                {
+                    Data = item,
+                    MatchScore = matchResult.TotalScore,
+                    MatchFields = matchResult.MatchFields
+                };
+            })
+            .Where(item => item.MatchScore > 0) // 只保留有匹配的记录
+            .OrderByDescending(item => item.MatchScore)
+            .ThenByDescending(item => GetCreateTime(item.Data))
+            .ToList();
+
+            return scoredItems;
+        }
+
         /// <summary>
         /// 新增:检查所有单字是否在任意字段中出现
         /// </summary>

+ 7 - 0
OASystem/OASystem.Domain/Entities/Groups/Grp_AirTicketReservations.cs

@@ -10,6 +10,13 @@ public class Grp_AirTicketReservations : EntityBase
 {
     /************************* 2026版数据结构 *************************/
 
+    /// <summary>
+    /// 区分新老数据
+    /// false 老数据 true 新数据
+    /// </summary>
+    [SugarColumn(IsNullable = true, ColumnDataType = "bool")]
+    public bool IsNew { get; set; } = false;
+
     /// <summary>
     /// 团组外键编号
     /// </summary>

+ 7 - 0
OASystem/OASystem.Domain/ViewModels/Groups/AirTicketReservationsView.cs

@@ -56,6 +56,8 @@ public class AirGroupCostParameterView
 
 public class DeriveInfo : Grp_AirTicketReservations
 {
+    public string AdditionalServices { get; set; }
+
     public string CTypeName { get; set; }
 
     /// <summary>
@@ -397,6 +399,11 @@ public class GroupAirTicketInfo : GroupAirInfoView
     /// 航班描述
     /// </summary>
     public string FlightsDescription { get; set; }
+
+    /// <summary>
+    /// 是否是新数据
+    /// </summary>
+    public bool IsNew { get; set; } = false;
 }
 
 /// <summary>

+ 9 - 5
OASystem/OASystem.Infrastructure/Repositories/Groups/AirTicketResRepository.cs

@@ -421,6 +421,7 @@ public class AirTicketResRepository : BaseRepository<Grp_AirTicketReservations,
             int id = 0;
             var grp_AirTicket = _mapper.Map<Grp_AirTicketReservations>(dto.AirTicketResOpData);
             var clientName = string.Join(",", dto.AirTicketResOpData.ClientName);
+            grp_AirTicket.IsNew = false;
 
             if (dto.Status == 1)
             {
@@ -1431,11 +1432,13 @@ public class AirTicketResRepository : BaseRepository<Grp_AirTicketReservations,
         var cabinTypes = await _sqlSugar.Queryable<Sys_SetData>().Where(x => x.IsDel == 0 && x.STid == 44).ToListAsync();
 
         // 5. 按【航段】进行高级业务聚合
+        var isNew = false;
         var groupedByFlights = dbAirTicketList
             .GroupBy(x => x.Air.FlightsDescription)
             .Select(g =>
             {
                 var rawList = g.ToList();
+                isNew = g.FirstOrDefault()?.Air?.IsNew ?? false;
 
                 // 直接利用 IEnumerable 接口,避开泛型类型转换限制
                 var hasValidCabin = rawList.Any(x => x.Air.CType > 0);
@@ -1542,6 +1545,7 @@ public class AirTicketResRepository : BaseRepository<Grp_AirTicketReservations,
 
         var flightsDescAll = string.Join("", groupedByFlights.Select(x => x.FlightsDescription).Distinct());
         groupInfo.FlightsDescription = flightsDescAll;
+        groupInfo.IsNew = isNew;
 
         return JsonView.Success(new AirTicketFeeInfoView()
         {
@@ -1731,6 +1735,7 @@ public class AirTicketResRepository : BaseRepository<Grp_AirTicketReservations,
                 if (dbAir == null)
                 {
                     var airEntity = _mapper.Map<Grp_AirTicketReservations>(item);
+                    airEntity.IsNew = true;
                     airEntity.DIId = groupId;
                     airEntity.CreateUserId = currUserId;
                     airEntity.CreateTime = DateTime.Now;
@@ -1738,7 +1743,6 @@ public class AirTicketResRepository : BaseRepository<Grp_AirTicketReservations,
                     airEntity.Price = currentSegmentPrice;
                     airEntity.ClientNum = item.CustTicketInfos?.Select(x => x.ClientId).Distinct().Count() ?? 0;
                     airEntity.ClientName = string.Join(",", item.CustTicketInfos?.Select(x => x.ClientId).Distinct() ?? new List<int>());
-
                     airEntity.RecordType = item.RecordType;
 
                     if (item.RecordType == 1)
@@ -1822,6 +1826,7 @@ public class AirTicketResRepository : BaseRepository<Grp_AirTicketReservations,
                     }
 
                     var frontendClients = item.CustTicketInfos ?? new List<CustTicketInfo>();
+                    dbAir.IsNew = true;
                     dbAir.FlightsDescription = item.FlightsDescription;
                     dbAir.CType = item.CType;
                     dbAir.CustTicketInfos = frontendClients;
@@ -2619,7 +2624,7 @@ public class AirTicketResRepository : BaseRepository<Grp_AirTicketReservations,
                 item.ClientName = string.Join("、", clientNames);
 
                 // 新数据单独处理
-                if (item.CreateTime < GlobalConfig.AirTicketIntegrationDateTime) continue;
+                if (!item.IsNew) continue;
 
                 // 航段文本深度解析
                 var flightInfoList = FlightParser.ParseFlights(item.FlightsDescription);
@@ -2655,7 +2660,7 @@ public class AirTicketResRepository : BaseRepository<Grp_AirTicketReservations,
 
                 if (serviceTypes.Any())
                 {
-                    item.CTypeName += $"(含{string.Join("、", serviceTypes)}等服务)";
+                    item.AdditionalServices = string.Join("、", serviceTypes);
                 }
 
                 //// 金额单价防呆计算
@@ -2739,7 +2744,7 @@ Order By a.CreateTime desc", dto.DiId);
             item.ClientName = string.Join("、", clientNames);
 
             // 新数据单独处理
-            if (item.CreateTime < GlobalConfig.AirTicketIntegrationDateTime) continue;
+            if (!item.IsNew) continue;
 
             // 航段文本深度解析
             var flightInfoList = FlightParser.ParseFlights(item.FlightsDescription);
@@ -2768,7 +2773,6 @@ Order By a.CreateTime desc", dto.DiId);
 
             // FlightInfoList
             item.FlightInfoList = FlightParser.ParseFlights(item.FlightDescription);
-
         }
 
         return JsonView<List<AirTicketReservationsView>>.Success("查询成功", airInfoList);