Pārlūkot izejas kodu

1. hotmail 新增 操作日志
2. hotmail 强制刷新token 接口

Lyyyi 5 dienas atpakaļ
vecāks
revīzija
66431bdef8

+ 27 - 0
OASystem/OASystem.Api/Controllers/AuthController.cs

@@ -488,6 +488,33 @@ namespace OASystem.API.Controllers
 
         }
 
+        /// <summary>
+        /// microsoft - hotmail 刷新客户端token
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("microsoft/auth/refresh/{currUserId}")]
+        [ProducesResponseType(typeof(LoginView), StatusCodes.Status200OK)]
+        public async Task<IActionResult> MicrosoftHotmailRefreshToken()
+        {
+            var hotmailConfigs = await _hotmailService.GetUserMailConfigListAsync();
+
+            if (hotmailConfigs == null)
+            {
+                return Ok(JsonView(false, "未找到 Hotmail 配置"));
+            }
+
+            var sb = new StringBuilder();
+
+            foreach (var hotmailConfig in hotmailConfigs)
+            { 
+                var result = await _hotmailService.ForceRefreshTokenAsync(hotmailConfig.UserName);
+                sb.AppendLine($"User: {hotmailConfig.UserName} -> {result};");
+            }
+
+            return Ok(JsonView(true, sb.ToString()));
+
+        }
+
         /// <summary>
         /// microsoft auth 回调
         /// </summary>

+ 191 - 0
OASystem/OASystem.Api/Controllers/StatisticsController.cs

@@ -1,6 +1,7 @@
 using Aspose.Cells;
 using FluentValidation;
 using Humanizer;
+using NPOI.SS.Formula.Functions;
 using OASystem.API.OAMethodLib;
 using OASystem.API.OAMethodLib.JuHeAPI;
 using OASystem.Domain.AesEncryption;
@@ -9,10 +10,15 @@ using OASystem.Domain.Entities.Customer;
 using OASystem.Domain.Entities.Financial;
 using OASystem.Domain.Entities.Groups;
 using OASystem.Domain.ViewModels.Financial;
+using OASystem.Domain.ViewModels.Groups;
 using OASystem.Domain.ViewModels.Statistics;
 using OASystem.Infrastructure.Repositories.Groups;
 using SqlSugar;
+using StackExchange.Redis;
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
 using System.Data;
+using System.Diagnostics.Eventing.Reader;
 using static OASystem.API.OAMethodLib.GeneralMethod;
 using TypeInfo = OASystem.Domain.ViewModels.Statistics.TypeInfo;
 
@@ -3662,6 +3668,191 @@ ORDER BY
 
         }
 
+        //SubmitAndValidateExpensesAsync
+
+        /// <summary>
+        /// 团组报表 - 会务超支验证excel下载
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("PostGroupStatementValidateExpenses")]
+        [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
+        public async Task<IActionResult> PostGroupStatementValidateExpenses(PostGroupStatementValidateExpensesDto dto)
+        {
+            // 1. 严格参数校验
+            if (dto.GroupId <= 0 || dto.CurrUserId <= 0)
+                return Ok(JsonView(false, "参数非法"));
+
+            // 2. 业务校验
+            var isConfGroup = await _sqlSugar.Queryable<Grp_DelegationInfo, Sys_SetData>(
+                    (g, s) => g.TeamDid == s.Id 
+                )
+                .Where((g, s) => g.IsDel == 0
+                              && g.Id == dto.GroupId
+                              && s.STid == 10
+                              && s.Name.Contains("会务活动"))
+                .AnyAsync(); 
+
+            if (!isConfGroup) return Ok(JsonView(false, "当前团组非会务团组,禁止操作"));
+
+            // 3. 异步并行查询:获取实际支付(Fee)与预算成本(Expense)
+            // 实际支付列表
+            var feeList = await _sqlSugar.Queryable<Grp_DecreasePayments>()
+                .InnerJoin<Grp_CreditCardPayment>((x, y) => x.Id == y.CId && x.DiId == y.DIId && y.CTable == 98)
+                .LeftJoin<Sys_Users>((x, y, z) => x.CreateUserId == z.Id)
+                .Where((x, y, z) => x.IsDel == 0 && x.DiId == dto.GroupId)
+                .Select((x, y, z) => new ConfValidateExpensesView
+                {
+                    PriceName = x.PriceName,
+                    FeeEntry = y.PayMoney * y.DayRate,
+                    AuditStatus = y.IsAuditGM.ToString(),
+                    AuditTime = y.AuditGMDate,
+                    PayLabel = y.IsPay.ToString(),
+                    Remark = x.Remark,
+                    Applicant = z.CnName,
+                    ApplicantTime = x.CreateTime.ToString("yyyy-MM-dd HH:mm:ss")
+                }).ToListAsync();
+
+            if (!feeList.Any()) return Ok(JsonView(false, "未检索到实际费用记录"));
+
+            // 成本预算列表
+            var expenseData = await _sqlSugar.Queryable<Grp_ConferenceAffairsCostChild>()
+                .InnerJoin<Grp_ConferenceAffairsCost>((x, y) => x.ConferenceAffairsCostId == y.Id)
+                .Where((x, y) => y.IsDel == 0 && y.Diid == dto.GroupId && x.ReviewStatus == 1)
+                .Select((x, y) => new { x.PriceName, Total = x.CostPrice * x.Rate * x.Count })
+                .ToListAsync();
+
+            var expenseDict = expenseData.ToDictionary(k => k.PriceName, v => v.Total);
+
+            if (!feeList.Any()) return Ok(JsonView(false, "未检索到实际费用记录"));
+
+            feeList = feeList.OrderBy(x => x.PriceName).ThenBy(x => x.ApplicantTime).ToList();
+
+            int index = 1;
+            // 4. 数据处理
+            foreach (var item in feeList)
+            {
+                item.Index = index;
+                item.AuditStatus = MapAuditStatus(item.AuditStatus);
+                item.PayLabel = item.PayLabel == "1" ? "已支付" : "未支付";
+
+                if (expenseDict.TryGetValue(item.PriceName, out decimal budget))
+                {
+                    item.ExpenseEntry = budget;
+                    item.OverspentLabel = item.FeeEntry > budget ? "超支" : "未超支";
+                }
+                else
+                {
+                    if (item.FeeEntry <= 0) item.OverspentLabel = "未超支";
+                    else item.OverspentLabel = "成本未录入项(系统判定超支)";
+                }
+                index++;
+            }
+
+            // 导出动作与异常处理
+            try
+            {
+                var groupName = _sqlSugar.Queryable<Grp_DelegationInfo>().First(x => x.Id == dto.GroupId)?.TeamName ?? "未知团组";
+
+                string fileName = $"会务校验_{groupName}_{DateTime.Now:yyyyMMddHHmm}.xlsx";
+
+                // Excel导出:调用通用方法,传入数据列表与文件名
+                byte[] fileData = ExportToExcel(feeList,"超支验证明细");
+
+                if (fileData == null || fileData.Length == 0)
+                {
+                    return Ok(JsonView(false, "生成文件流失败,请检查数据源"));
+                }
+
+                return File(
+                    fileData,
+                    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+                    fileName
+                );
+            }
+            catch (Exception ex)
+            {
+                return Ok(JsonView(false, $"导出过程中发生系统错误:{ex.Message}"));
+            }
+        }
+
+        private string MapAuditStatus(string status) => status switch
+        {
+            "0" => "未审核",
+            "1" => "已审核",
+            "2" => "未通过",
+            "3" => "自动审核",
+            _ => "未知"
+        };
+
+        public static byte[] ExportToExcel<T>(IEnumerable<T> data, string sheetName)
+        {
+            Workbook workbook = new Workbook();
+            Worksheet sheet = workbook.Worksheets[0];
+            sheet.Name = sheetName;
+
+            PropertyInfo[] props = typeof(T).GetProperties();
+
+            // 定义全局字体名称
+            const string MicrosoftYaHei = "微软雅黑";
+
+            // --- 1. 表头处理 ---
+            for (int i = 0; i < props.Length; i++)
+            {
+                var displayAttr = props[i].GetCustomAttribute<DisplayAttribute>();
+                string headerName = displayAttr?.Name ?? props[i].Name;
+
+                Aspose.Cells.Cell cell = sheet.Cells[0, i];
+                cell.PutValue(headerName);
+
+                // 设置表头样式:加粗 + 微软雅黑
+                Style style = cell.GetStyle();
+                style.Font.Name = MicrosoftYaHei;
+                style.Font.IsBold = true;
+                style.Font.Size = 11;
+                style.BackgroundColor = System.Drawing.Color.FromArgb(235, 235, 235);
+                style.Pattern = BackgroundType.Solid;
+                style.HorizontalAlignment = TextAlignmentType.Center;
+                cell.SetStyle(style);
+            }
+
+            // --- 2. 数据处理 ---
+            var dataList = data.ToList();
+            for (int rowIndex = 0; rowIndex < dataList.Count; rowIndex++)
+            {
+                var item = dataList[rowIndex];
+                for (int colIndex = 0; colIndex < props.Length; colIndex++)
+                {
+                    var value = props[colIndex].GetValue(item);
+                    Aspose.Cells.Cell cell = sheet.Cells[rowIndex + 1, colIndex];
+                    cell.PutValue(value);
+
+                    // 设置单元格基础样式:微软雅黑
+                    Style cellStyle = cell.GetStyle();
+                    cellStyle.Font.Name = MicrosoftYaHei;
+                    cellStyle.Font.Size = 10;
+
+                    // 成功/错误验证:高亮逻辑
+                    if (props[colIndex].Name == "OverspentLabel" && value?.ToString()?.Contains("超支") == true)
+                    {
+                        cellStyle.Font.Color = System.Drawing.Color.Red;
+                        cellStyle.Font.IsBold = true;
+                    }
+
+                    cell.SetStyle(cellStyle);
+                }
+            }
+
+            sheet.AutoFitColumns();
+
+            // --- 3. 转化为文件流 ---
+            using (MemoryStream ms = new MemoryStream())
+            {
+                workbook.Save(ms, SaveFormat.Xlsx);
+                return ms.ToArray();
+            }
+        }
+
         #endregion
 
         #region 报表/折线图统计

+ 6 - 2
OASystem/OASystem.Api/OAMethodLib/GeneralMethod.cs

@@ -26,6 +26,8 @@ using OASystem.Domain.ViewModels.JuHeExchangeRate;
 using OASystem.Domain.ViewModels.PersonnelModule;
 using OASystem.Infrastructure.Repositories.CRM;
 using OASystem.Infrastructure.Repositories.Groups;
+using System.ComponentModel;
+using System.ComponentModel.DataAnnotations;
 using System.Data;
 using System.IdentityModel.Tokens.Jwt;
 using System.Security.Claims;
@@ -6183,6 +6185,7 @@ namespace OASystem.API.OAMethodLib
         #endregion
 
         #region Excel导出服务
+        
         #region 类
         public class FileExportSettings
         {
@@ -6225,6 +6228,7 @@ namespace OASystem.API.OAMethodLib
         }
         #endregion
 
+
         public static async Task<ExportResult> ExportToExcel<T>(IEnumerable<T> data, string fileName, string sheetName = "Sheet1", string templateType = "default")
         {
             try
@@ -6280,7 +6284,7 @@ namespace OASystem.API.OAMethodLib
                 var excelBytes = outputStream.ToArray();
 
                 var filePath = await SaveFileAsync(excelBytes, fileName, "excel/templates");
-                var downloadUrl = $"wwwroot/exports/exports/{filePath}";
+                var downloadUrl = $"wwwroot/exports/{filePath}";
 
                 return new ExportResult
                 {
@@ -6326,7 +6330,7 @@ namespace OASystem.API.OAMethodLib
                 var excelBytes = stream.ToArray();
 
                 var filePath = await SaveFileAsync(excelBytes, fileName, "excel/multi-sheets");
-                var downloadUrl = $"wwwroot/exports/exports/{filePath}";
+                var downloadUrl = $"wwwroot/exports/{filePath}";
 
                 return new ExportResult
                 {

+ 42 - 2
OASystem/OASystem.Api/OAMethodLib/Hotmail/HotmailService.cs

@@ -16,12 +16,14 @@ namespace OASystem.API.OAMethodLib.Hotmail
         private readonly IConfiguration _config;
         private readonly SqlSugarClient _sqlSugar;
         public const string RedisKeyPrefix = "MailAlchemy:Token:";
+        private readonly ILogger<HotmailService> _logger;
 
-        public HotmailService(IHttpClientFactory httpClientFactory, IConfiguration config, SqlSugarClient sqlSugar)
+        public HotmailService(IHttpClientFactory httpClientFactory, IConfiguration config, SqlSugarClient sqlSugar, ILogger<HotmailService> logger)
         {
             _httpClientFactory = httpClientFactory;
             _config = config;
             _sqlSugar = sqlSugar;
+            _logger = logger;
         }
 
         /// <summary>
@@ -93,6 +95,7 @@ namespace OASystem.API.OAMethodLib.Hotmail
 
         public async Task<List<MailDto>> GetMergedMessagesAsync(List<string> emails, DateTime cstStart, DateTime cstEnd)
         {
+            _logger.LogInformation("Microsoft Hotmail -> 获取hotmail邮件信息线程准备");
             // 线程安全的合并容器
             var allMessages = new ConcurrentBag<MailDto>();
 
@@ -110,7 +113,9 @@ namespace OASystem.API.OAMethodLib.Hotmail
             {
                 try
                 {
+                    _logger.LogInformation("Microsoft Hotmail -> [{Hotmail}] 获取token ",email);
                     var client = await GetClientAsync(email);
+                    _logger.LogInformation("Microsoft Hotmail -> [{Hotmail}] 获取Graph客户端,刷新token ", email);
                     var response = await client.Me.Messages.GetAsync(q =>
                     {
                         q.QueryParameters.Filter = $"receivedDateTime ge {startFilter} and receivedDateTime le {endFilter}";
@@ -119,6 +124,7 @@ namespace OASystem.API.OAMethodLib.Hotmail
                         q.QueryParameters.Top = 50; // 生产环境建议增加 Top 限制
                     }, ct);
 
+                    _logger.LogInformation("Microsoft Hotmail -> [{Hotmail}] 获取Hotmail收件箱资料 ", email);
                     if (response?.Value != null)
                     {
                         var chinaTimeZone = TimeZoneInfo.FindSystemTimeZoneById("China Standard Time");
@@ -138,12 +144,17 @@ namespace OASystem.API.OAMethodLib.Hotmail
                                 Source = email // 显式来源
                             });
                         }
+                        _logger.LogInformation("Microsoft Hotmail -> [{Hotmail}] 获取Hotmail收件箱资料 成功 ", email);
+                    }
+                    else
+                    {
+                        _logger.LogInformation("Microsoft Hotmail -> [{Hotmail}] 获取Hotmail收件箱资料 暂无 ", email);
                     }
                 }
                 catch (Exception ex)
                 {
                     // 生产环境应接入 ILogger
-                    //_logger.LogError(ex, "Failed to fetch mail for {Email}", email);
+                    _logger.LogError(ex, "Failed to fetch mail for {Email}", email);
                 }
             });
 
@@ -350,6 +361,35 @@ namespace OASystem.API.OAMethodLib.Hotmail
             return newToken;
         }
 
+        /// <summary>
+        /// 强制手动刷新指定邮箱的 Token
+        /// </summary>
+        public async Task<bool> ForceRefreshTokenAsync(string email)
+        {
+            // 获取用户独占锁,防止手动触发与自动触发冲突
+            var userLock = _userLocks.GetOrAdd(email, _ => new SemaphoreSlim(1, 1));
+            await userLock.WaitAsync();
+
+            try
+            {
+                var redisKey = GetRedisKey(email);
+                var repo = RedisRepository.RedisFactory.CreateRedisRepository();
+                var cachedJson = await repo.StringGetAsync<string>(redisKey);
+
+                if (string.IsNullOrEmpty(cachedJson)) return false;
+
+                var currentToken = System.Text.Json.JsonSerializer.Deserialize<UserToken>(cachedJson);
+
+                // 强制进入刷新逻辑
+                await RefreshAndSaveTokenAsync(currentToken!);
+                return true;
+            }
+            finally
+            {
+                userLock.Release();
+            }
+        }
+
         /// <summary>
         /// 静态 Token 提供者辅助类
         /// </summary>

+ 32 - 3
OASystem/OASystem.Api/OAMethodLib/Quartz/Business/ProcessAndNotifySummary.cs

@@ -1,5 +1,6 @@
 using OASystem.API.OAMethodLib.DeepSeekAPI;
 using OASystem.API.OAMethodLib.Hotmail;
+using OASystem.API.OAMethodLib.JuHeAPI;
 using OASystem.API.OAMethodLib.QiYeWeChatAPI;
 using OASystem.Domain.ViewModels.QiYeWeChat;
 using System.Text.Json;
@@ -18,6 +19,7 @@ namespace OASystem.API.OAMethodLib.Quartz.Business
         private static readonly IQiYeWeChatApiService _qiYeWeChatApiService = AutofacIocManager.Instance.GetService<IQiYeWeChatApiService>();
         private static readonly HotmailService _hotmailService = AutofacIocManager.Instance.GetService<HotmailService>();
         private static readonly IDeepSeekService _deepSeekService = AutofacIocManager.Instance.GetService<IDeepSeekService>();
+        private static readonly Microsoft.Extensions.Logging.ILogger _logger =AutofacIocManager.Instance.GetService<ILoggerFactory>().CreateLogger("ProcessAndNotifySummary");
 
         /// <summary>
         /// hotmail 邮件 汇总 发送企微邮件
@@ -25,9 +27,12 @@ namespace OASystem.API.OAMethodLib.Quartz.Business
         /// </summary>
         public static async void ProcessAndNotifySummaryAsync()
         {
+            _logger.LogInformation("Hotmail 定时发送邮件 -> 开始");
             var hotmailConfigs = await _hotmailService.GetUserMailConfigListAsync();
             if (hotmailConfigs == null || !hotmailConfigs.Any()) return;
 
+            _logger.LogInformation("Hotmail 定时发送邮件 -> 获取基础配置");
+
             var hotmails = hotmailConfigs.Select(x => x.UserName).ToList();
             var userIds = hotmailConfigs.Select(x => x.UserId).ToList();
 
@@ -36,12 +41,16 @@ namespace OASystem.API.OAMethodLib.Quartz.Business
             var yesterdayStart = nowInCst.Date.AddDays(-1);
             var yesterdayEnd = yesterdayStart.AddDays(1).AddTicks(-1);
 
+
+            _logger.LogInformation("Hotmail 定时发送邮件 -> 获取Hotmail邮件信息 -> 开始");
             // 获取邮件信息
             var emailInfos = await _hotmailService.GetMergedMessagesAsync(hotmails, yesterdayStart, yesterdayEnd);
+            _logger.LogInformation("Hotmail 定时发送邮件 -> 获取Hotmail邮件信息 -> 结束");
 
             // 处理无邮件情况
             if (emailInfos == null || !emailInfos.Any())
             {
+                _logger.LogInformation("Hotmail 定时发送邮件 -> 获取Hotmail邮件信息 -> 发送无邮件情况");
                 await NotifyEmptyEmails(userIds);
                 return;
             }
@@ -52,18 +61,23 @@ namespace OASystem.API.OAMethodLib.Quartz.Business
             //    mail.Content = CleanHtmlToPlainText(mail.Content);
             //}
 
+            _logger.LogInformation("Hotmail 定时发送邮件 -> DeepSeek AI 分析汇总邮件 -> 开始");
             // 调用 AI
             var question = BuildMailSummaryPrompt(emailInfos);
+
             var res = await _deepSeekService.ChatAsync(question);
 
             if (res.Success)
             {
+
+                _logger.LogInformation("Hotmail 定时发送邮件 -> DeepSeek AI 分析汇总邮件 -> 分析成功");
                 // 清洗 AI 可能带出的 Markdown 格式符
                 string cleanJson = res.Answer.Trim();
                 if (cleanJson.StartsWith("```json")) cleanJson = cleanJson.Replace("```json", "").Replace("```", "").Trim();
 
                 try
                 {
+                    _logger.LogInformation("Hotmail 定时发送邮件 -> DeepSeek AI 分析汇总邮件 -> 解析AI返回的json -> 开始");
                     var aiSummaryResults = JsonConvert.DeserializeObject<List<AiSummaryResult>>(cleanJson);
                     var users = await _sqlSugar.Queryable<Sys_Users>().Where(x => x.IsDel == 0 && userIds.Contains(x.Id)).Select(x => new { x.Id, x.Email }).ToListAsync();
 
@@ -102,23 +116,38 @@ namespace OASystem.API.OAMethodLib.Quartz.Business
                         string defualtEmail1 = "johnny.yang@pan-american-intl.com";
                         string defualtEmail2 = "Roy.lei@pan-american-intl.com";
 
-                        await _qiYeWeChatApiService.EmailSendAsync(new EmailRequestDto
+                        _logger.LogInformation("Hotmail 定时发送邮件 -> DeepSeek AI 分析汇总邮件 -> 解析AI返回的json -> 发送腾讯邮件 -> {email} 开始", qwEmail);
+                        var seedRes = await _qiYeWeChatApiService.EmailSendAsync(new EmailRequestDto
                         {
                             ToEmails = new List<string> { 
-                                qwEmail,
-                                defualtEmail1,
+                                //qwEmail,
+                                //defualtEmail1,
                                 defualtEmail2
                             },
                             Subject = finalSubject,
                             Body = finalBody,
                         });
+
+                        if (seedRes.errcode == 0)
+                        {
+                            _logger.LogInformation("Hotmail 定时发送邮件 -> DeepSeek AI 分析汇总邮件 -> 解析AI返回的json -> 发送腾讯邮件 -> {email} 发送成功", qwEmail);
+                        }
+                        else
+                        {
+                            _logger.LogInformation("Hotmail 定时发送邮件 -> DeepSeek AI 分析汇总邮件 -> 解析AI返回的json -> 发送腾讯邮件 -> {email} 失败:【{ErrorMsg}】",
+                                qwEmail,seedRes.errmsg);
+                        }
+
                     }
                 }
                 catch (Exception ex)
                 {
                     // 记录解析 JSON 失败日志
+                    _logger.LogInformation("Hotmail 定时发送邮件 -> DeepSeek AI 分析汇总邮件 -> 解析AI返回的json -> 失败:{ErrorMsg}", ex.Message);
                 }
             }
+
+            _logger.LogInformation("Hotmail 定时发送邮件 -> DeepSeek AI 分析汇总邮件 -> 分析失败");
         }
 
         /// <summary>

+ 4 - 0
OASystem/OASystem.Api/OASystem.API.csproj

@@ -97,6 +97,10 @@
       <CopyToOutputDirectory>Always</CopyToOutputDirectory>
     </None>
   </ItemGroup>
+	
+  <ItemGroup>
+    <Folder Include="wwwroot\exports\" />
+  </ItemGroup>
 
   <ProjectExtensions><VisualStudio><UserProperties properties_4launchsettings_1json__JsonSchema="" /></VisualStudio></ProjectExtensions>
 

BIN
OASystem/OASystem.Api/wwwroot/exports/exports/excel/客户资料资料(YQY)_0f4beae08b7b4f53b9f27113563fc5d2.xlsx


BIN
OASystem/OASystem.Api/wwwroot/exports/exports/excel/客户资料资料(ZQ)_6c09dbea11914d2eafe96e5a4fdb0a5d.xlsx


+ 6 - 0
OASystem/OASystem.Domain/Dtos/Statistics/GroupStatementDto.cs

@@ -85,4 +85,10 @@ namespace OASystem.Domain.Dtos.Statistics
         public int Year { get; set; }
     }
 
+
+    public class PostGroupStatementValidateExpensesDto
+    {
+        public int GroupId { get; set; }
+        public int CurrUserId { get; set; }
+    }
 }

+ 54 - 0
OASystem/OASystem.Domain/ViewModels/Statistics/GroupStatementView.cs

@@ -4,6 +4,7 @@ using OASystem.Domain.Entities.Financial;
 using OASystem.Domain.Entities.Groups;
 using System;
 using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
 using System.Linq;
 using System.Runtime.Intrinsics.Arm;
 using System.Text;
@@ -2085,4 +2086,57 @@ namespace OASystem.Domain.ViewModels.Statistics
 
     #endregion
 
+    #region 会务成本
+
+    public class ConfValidateExpensesView
+    {
+        [Display(Name = "序号")]
+        public int Index { get; set; }
+
+        [Display(Name = "费用名称")]
+        public string PriceName { get; set; }
+
+        /// <summary>
+        /// 录入费用
+        /// </summary>
+        [Display(Name = "实际费用(CNY)")]
+        public decimal FeeEntry { get; set; }
+
+        /// <summary>
+        /// 成本费用
+        /// </summary>
+        [Display(Name = "成本费用(CNY)")]
+        public decimal ExpenseEntry { get; set; }
+
+        /// <summary>
+        /// 超支描述
+        /// </summary>
+        [Display(Name = "超支描述")]
+        public string OverspentLabel { get; set; }
+
+        /// <summary>
+        /// 审核状态
+        /// 0 未审核 1已通过 2未通过 3 自动审核
+        /// </summary>
+        [Display(Name = "审核状态")]
+        public string AuditStatus { get; set; }
+
+        [Display(Name = "审核时间")]
+        public string AuditTime { get; set; }
+        /// <summary>
+        /// 付款状态
+        /// 0 否 1 是
+        /// </summary>
+        [Display(Name = "付款状态")]
+        public string PayLabel { get; set; }
+        [Display(Name = "备注")]
+        public string Remark { get; set; }
+        [Display(Name = "申请人")]
+        public string Applicant { get; set; }
+        [Display(Name = "申请时间")]
+        public string ApplicantTime { get; set; }
+    }
+
+    #endregion
+
 }