新增利润统计接口

This commit is contained in:
chfei committed 2026-08-07 18:53:43 +08:00
1 parent e37f15737c
commit bd08d1c3d7
11 files changed
+2780 -1916

No files matched your search

@@ -0,0 +1,2 @@
*
!.gitignore
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,300 @@
using KJD_Web.Model;
using KJD_Web.Model.WxModel;
using KJD_Web.Upload.Prod;
using KJD_Web.Utils;
using MySql.Data.MySqlClient;
using Mysqlx.Crud;
using NaiBa.Util.Extension;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Web;
using System.Web.ApplicationServices;
using System.Web.Security;
using System.Web.UI.WebControls;
namespace KJD_Web.BLL.WXXD
{
public class WXShopRevenueStatisticsManage
{
public WXShopRevenueStatisticsManage()
{
}
public string GetShopOrderAmountRange(string inputData)
{
Result ret = Result.ArgumentNull();
if (!string.IsNullOrEmpty(inputData))
{
try
{
// todo 获取当前用户微信店铺,或指定某一个店铺,某一段时间
// 获取店铺下时间范围内的所有订单涉及到的金额
// 直接返回
if (!WXUserManage.GetSign(inputData))
throw new ArgumentException("校验失败");
var timeCalc = DateTime.Now;
string shop_ids = RegexUtils.GetStringQuery(ref inputData, "shop_ids")?.Replace("'", "");//所有店铺信息
if (string.IsNullOrEmpty(shop_ids))
throw new ArgumentException("请选择店铺");
List<string> shopIdLst = shop_ids.Split(',').ToList();
if (shopIdLst.Count > 0)
shop_ids = "'" + string.Join("','", shopIdLst) + "'";
string start_Time = RegexUtils.GetStringQuery(ref inputData, "start_time")?.Replace("'", "");
string end_Time = RegexUtils.GetStringQuery(ref inputData, "end_time")?.Replace("'", "");
DateTime startTime = DateTime.Now.AddDays(-7);
DateTime endTime = DateTime.Now;
if (!string.IsNullOrEmpty(start_Time))
startTime = TimeUtils.StampMillisecondsToDateTime(start_Time.ParseToLong());
if (!string.IsNullOrEmpty(end_Time))
endTime = TimeUtils.StampMillisecondsToDateTime(end_Time.ParseToLong());
if (endTime <= startTime)
throw new ArgumentException("结束时间必须大于开始时间");
if (endTime > startTime.AddMonths(3))
throw new ArgumentException("时间范围不能超过3个月");
int startTimestamp = TimeUtils.DateTimeToTimestampSeconds(startTime);
int endTimestamp = TimeUtils.DateTimeToTimestampSeconds(endTime);
StringBuilder sb = new StringBuilder();
sb.Append("SELECT ");
sb.Append("A.shop_name, ");
sb.Append("A.create_time, ");
sb.Append("A.order_id, ");
sb.Append("A.`status`, ");
sb.Append("A.product_price, ");
sb.Append("A.order_price, ");
sb.Append("A.purchase_price, ");
sb.Append("A.freight, ");
sb.Append("A.predict_commission_fee, ");
sb.Append("A.commission_amount, ");
sb.Append("A.discounted_price, ");
sb.Append("A.profit, ");
sb.Append("A.purchase_status, ");
sb.Append("A.out_amount, ");
sb.Append("B.refund_status, ");
sb.Append("c.`status` as refund_status_string, ");
sb.Append("IFNULL(C.refund_amount, 0) AS refund_amount ");
sb.Append("FROM erp.oms_wei_order AS A ");
sb.Append("INNER JOIN erp.`oms_wei_order_item` AS B ON A.`order_id` = B.`order_id` ");
sb.Append("LEFT JOIN ( SELECT order_id,`status`,refund_amount,id FROM erp.`oms_wei_refund` WHERE id IN ( SELECT MAX(id) FROM erp.`oms_wei_refund` GROUP BY order_id)) AS C ON A.order_id = C.order_id ");
sb.Append("WHERE A.create_time BETWEEN " + startTimestamp + " AND " + endTimestamp + " ");
sb.Append("AND A.`status` > 10 ");
sb.Append("AND B.shop_id IN (" + shop_ids + ") ");
sb.Append("ORDER BY A.create_time asc");
string conn = System.Configuration.ConfigurationManager.ConnectionStrings["ConnKJD"].ConnectionString;
MysqlUtils mySql = new MysqlUtils(conn);
DataTable dt = mySql.ExecuteDataTable(sb.ToString());
mySql.Close();
if (!string.IsNullOrEmpty(mySql.Message))
throw new Exception(mySql.Message);
// out_amount 为空或为0的订单,从中转仓订单表(GetTransitOrderTable)补全外采金额
// external_procurement:0=未查到,1=从 GetTransitOrderTable 查询到
Dictionary<string, int> transitOutAmountMap = new Dictionary<string, int>();
if (dt != null && dt.Rows.Count > 0)
{
HashSet<string> needLookupOrderIds = new HashSet<string>();
foreach (DataRow row in dt.Rows)
{
int? rowOutAmount = row["out_amount"].ParseToInt();
if (rowOutAmount == null || rowOutAmount.Value == 0)
{
string orderId = row["order_id"].ParseToString();
if (!string.IsNullOrEmpty(orderId))
needLookupOrderIds.Add(orderId);
}
}
if (needLookupOrderIds.Count > 0)
{
WXOrderManage wxOrderManage = new WXOrderManage();
const int chunkSize = 100;
const int transitPageSize = 500;
List<string> needLookupList = needLookupOrderIds.ToList();
for (int i = 0; i < needLookupList.Count; i += chunkSize)
{
int takeCount = Math.Min(chunkSize, needLookupList.Count - i);
string chunkOrderIds = string.Join(",", needLookupList.GetRange(i, takeCount));
int pageIndex = 1;
while (true)
{
int count = -1;
var transitList = wxOrderManage.GetTransitOrderTable(pageIndex, transitPageSize, chunkOrderIds, null, null, null, null, "true", out count);
if (transitList == null || transitList.Count == 0)
break;
foreach (var transit in transitList)
{
if (transit != null && !string.IsNullOrEmpty(transit.order_no) && needLookupOrderIds.Contains(transit.order_no))
{
if (!transitOutAmountMap.ContainsKey(transit.order_no))
transitOutAmountMap[transit.order_no] = transit.out_amount ?? 0;
}
}
if (transitList.Count < transitPageSize)
break;
pageIndex++;
}
}
}
}
List<WXOrderAmountInfo> orderList = new List<WXOrderAmountInfo>();
if (dt != null)
{
foreach (DataRow row in dt.Rows)
orderList.Add(BuildOrderAmountInfo(row, transitOutAmountMap));
}
// 买手号退款金额:退款订单(refund_status>1)且非外采时,从买手售后表补全退款金额
FillBuyerRefundAmount(orderList, conn);
ret.Code = 200;
ret.Msg = "success";
ret.Data = orderList;
}
catch (Exception ex)
{
ret.Code = 500;
ret.Msg = ex.Message;
}
}
return JsonUtils.SerializeObjectToString(ret, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
});
}
/// <summary>
/// 将订单行转换为金额详情:out_amount 为空或0时从中转仓订单表补全,并计算利润
/// </summary>
private WXOrderAmountInfo BuildOrderAmountInfo(DataRow row, Dictionary<string, int> transitOutAmountMap)
{
string orderId = row["order_id"].ParseToString();
int outAmount = row["out_amount"].ParseToInt();
int externalProcurement = 0;
if (outAmount == 0)
{
int transitAmount;
if (transitOutAmountMap.TryGetValue(orderId, out transitAmount))
{
externalProcurement = 1;
outAmount = transitAmount;
}
}
int orderPrice = row["order_price"].ParseToInt();
int predictCommissionFee = row["predict_commission_fee"].ParseToInt();
int commissionAmount = row["commission_amount"].ParseToInt();
int refund_amount = row["refund_amount"].ParseToInt();
// 利润 = 订单金额 - 外采金额 - 平台服务费 - 达人佣金(为空按0处理)
int profit = orderPrice - outAmount - predictCommissionFee - commissionAmount;
if (refund_amount > 0) //退款利润计算
{
profit = orderPrice - refund_amount;
}
return new WXOrderAmountInfo
{
shop_name = row["shop_name"].ParseToString(),
create_time = row["create_time"].ParseToInt(),
order_id = orderId,
status = row["status"].ParseToInt(),
product_price = row["product_price"].ParseToInt(),
order_price = orderPrice,
purchase_price = row["purchase_price"].ParseToInt(),
freight = row["freight"].ParseToInt(),
predict_commission_fee = predictCommissionFee,
commission_amount = commissionAmount,
discounted_price = row["discounted_price"].ParseToInt(),
profit = profit,
purchase_status = row["purchase_status"].ParseToInt(),
out_amount = outAmount,
refund_status = row["refund_status"].ParseToInt(),
refund_status_string = row["refund_status_string"].ParseToString(),
refund_amount = row["refund_amount"].ParseToInt(),
external_procurement = externalProcurement
};
}
/// <summary>
/// 买手号退款金额:退款订单(refund_status>1)且非外采时,从买手售后表(wxxd.order_pdd_buyer_after_sale)查询退款金额(refundAmount)填入
/// </summary>
private void FillBuyerRefundAmount(List<WXOrderAmountInfo> orderList, string conn)
{
if (orderList == null || orderList.Count == 0)
return;
// 退款订单(refund_status>1)且非外采(out_amount、external_procurement都为0)的订单才查询买手号退款金额
HashSet<string> needLookupOrderIds = new HashSet<string>();
foreach (WXOrderAmountInfo order in orderList)
{
if (order.refund_status > 1 && order.external_procurement == 1 && order.out_amount > 0)
{
if (!string.IsNullOrEmpty(order.order_id))
needLookupOrderIds.Add(order.order_id);
}
}
if (needLookupOrderIds.Count == 0)
return;
Dictionary<string, Tuple<int, string>> buyerRefundAmountMap = new Dictionary<string, Tuple<int, string>>();
MysqlUtils mySql = new MysqlUtils(conn);
try
{
const int chunkSize = 100;
List<string> needLookupList = needLookupOrderIds.ToList();
for (int i = 0; i < needLookupList.Count; i += chunkSize)
{
int takeCount = Math.Min(chunkSize, needLookupList.Count - i);
string chunkOrderIds = string.Join("','", needLookupList.GetRange(i, takeCount));
string sql = "SELECT WX_ORDER_ID,refundAmount,statusText FROM wxxd.order_pdd_buyer_after_sale a " +
"WHERE a.WX_ORDER_ID IN ('" + chunkOrderIds + "') AND a.id = ( SELECT MAX(b.id) FROM wxxd.order_pdd_buyer_after_sale b WHERE b.WX_ORDER_ID = a.WX_ORDER_ID) ORDER BY a.WX_ORDER_ID;";
DataTable buyerDt = mySql.ExecuteDataTable(sql);
if (buyerDt != null)
{
foreach (DataRow row in buyerDt.Rows)
{
string wxOrderId = row["WX_ORDER_ID"].ParseToString();
int refundAmount = row["refundAmount"].ParseToInt();
string statusText = row["statusText"].ParseToString();
if (!string.IsNullOrEmpty(wxOrderId) && !buyerRefundAmountMap.ContainsKey(wxOrderId))
buyerRefundAmountMap[wxOrderId] = new Tuple<int, string>(refundAmount, statusText);
}
}
}
}
finally
{
mySql.Close();
}
if (!string.IsNullOrEmpty(mySql.Message))
throw new Exception(mySql.Message);
foreach (WXOrderAmountInfo order in orderList)
{
Tuple<int, string> buyerRefundAmount;
if (buyerRefundAmountMap.TryGetValue(order.order_id, out buyerRefundAmount))
{
order.buyer_refund_amount = buyerRefundAmount.Item1;
order.buyer_refund_status = buyerRefundAmount.Item2;
}
}
}
}
}
+16 -2
View File
@@ -4,6 +4,7 @@ using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using KJD_Web.Utils;
namespace KJD_Web
{
@@ -159,14 +160,27 @@ namespace KJD_Web
{
hPath = hPath.Replace("/wxxd_order/", "/WXOrderService.asmx/");
Context.RewritePath(hPath);
}
}
}
else if (!hPath.Contains(".asmx") && hPath.Contains("/wxxd_shop_revenue_statistics/"))
{
hPath = hPath.Replace("/wxxd_shop_revenue_statistics/", "/WXShopRevenueStatistics.asmx/");
Context.RewritePath(hPath);
}
// 请求录制:捕获请求链接与请求内容,用于迁移后的回放校验
//try { ApiRequestLogger.BeginRequest(Context); } catch { }
}
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
}
protected void Application_EndRequest(object sender, EventArgs e)
{
// 请求录制:合并响应内容并落盘
//try { ApiRequestLogger.EndRequest(Context); } catch { }
}
protected void Application_Error(object sender, EventArgs e)
{
@@ -81,6 +81,7 @@
<Content Include="WXProductService.asmx" />
<Content Include="WXShopService.asmx" />
<Content Include="DYShopService.asmx" />
<Content Include="WXShopRevenueStatistics.asmx" />
<Content Include="WXUserService.asmx" />
<Content Include="DYUserService.asmx" />
<Content Include="Global.asax" />
@@ -120,6 +121,7 @@
<Compile Include="BLL\WXXD\WXOrderManage.cs" />
<Compile Include="BLL\WXXD\WXProductManage.cs" />
<Compile Include="BLL\WXXD\WXShopManage.cs" />
<Compile Include="BLL\WXXD\WXShopRevenueStatisticsManage.cs" />
<Compile Include="BLL\WXXD\WXUserManage.cs" />
<Compile Include="Model\ErpModel\ErpMerchantInfo.cs" />
<Compile Include="Model\JSTDownProdSkuInfo.cs" />
@@ -130,6 +132,7 @@
<Compile Include="Model\PddModel\PDDProductDetailInfo.cs" />
<Compile Include="Model\PddModel\PDDProductInfo.cs" />
<Compile Include="Model\PddModel\PDDProductPropertyInfo.cs" />
<Compile Include="Model\Result.cs" />
<Compile Include="Model\ShopModel\JSTListProductSkuInfo.cs" />
<Compile Include="Model\WXAddressInfo.cs" />
<Compile Include="Model\WxModel\oem.cs" />
@@ -147,9 +150,11 @@
<Compile Include="Model\WxModel\WXClientProductInfoLite.cs" />
<Compile Include="Model\WxModel\WXGetEditProductInfoLite.cs" />
<Compile Include="Model\WxModel\WxOptimizeExpressInfo.cs" />
<Compile Include="Model\WxModel\WXOrderAmountInfo.cs" />
<Compile Include="Model\WxModel\WXOrderDecryptAddressInfo.cs" />
<Compile Include="Model\WxProdSecretSpuIdShopIdMapParam.cs" />
<Compile Include="Model\WXShopDefaultAddressInfo.cs" />
<Compile Include="Utils\ApiRequestLogger.cs" />
<Compile Include="WXOrderService.asmx.cs">
<DependentUpon>WXOrderService.asmx</DependentUpon>
<SubType>Component</SubType>
@@ -184,6 +189,10 @@
<DependentUpon>DYShopService.asmx</DependentUpon>
<SubType>Component</SubType>
</Compile>
<Compile Include="WXShopRevenueStatistics.asmx.cs">
<DependentUpon>WXShopRevenueStatistics.asmx</DependentUpon>
<SubType>Component</SubType>
</Compile>
<Compile Include="WXUserService.asmx.cs">
<DependentUpon>WXUserService.asmx</DependentUpon>
<SubType>Component</SubType>
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<UseIISExpress>true</UseIISExpress>
@@ -8,8 +8,8 @@
<IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode />
<UseGlobalApplicationHostFile />
<LastActiveSolutionConfig>Release|Any CPU</LastActiveSolutionConfig>
<ProjectView>ShowAllFiles</ProjectView>
<LastActiveSolutionConfig>Debug|Any CPU</LastActiveSolutionConfig>
<ProjectView>ProjectFiles</ProjectView>
</PropertyGroup>
<ProjectExtensions>
<VisualStudio>
+47
View File
@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace KJD_Web.Model
{
public class Result
{
public Result()
{
}
public Result(int code, string msg)
{
Code = code;
Msg = msg;
}
public int Code { get; set; }
public string Msg { get; set; }
public object Data { get; set; }
public static Result Success(string msg)
{
return new Result
{
Code = 200,
Msg = msg
};
}
public static Result Failure(string msg)
{
return new Result
{
Code = 500,
Msg = msg
};
}
//参数不合法
public static Result ArgumentNull()
{
return new Result { Code = 19999, Msg = "输入为空" };
}
}
}
@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace KJD_Web.Model.WxModel
{
/// <summary>
/// 微信订单金额详情
/// </summary>
public class WXOrderAmountInfo
{
/// <summary>
/// 店铺名称
/// </summary>
public string shop_name { get; set; }
/// <summary>
/// 下单时间(秒级时间戳)
/// </summary>
public int create_time { get; set; }
/// <summary>
/// 订单号
/// </summary>
public string order_id { get; set; }
/// <summary>
/// 订单状态
/// </summary>
public int status { get; set; }
/// <summary>
/// 商品总价(分)
/// </summary>
public int product_price { get; set; }
/// <summary>
/// 订单金额(分)
/// </summary>
public int order_price { get; set; }
/// <summary>
/// 采购价(分)
/// </summary>
public int purchase_price { get; set; }
/// <summary>
/// 运费(分)
/// </summary>
public int freight { get; set; }
/// <summary>
/// 平台服务费(预计技术服务费,分)
/// </summary>
public int predict_commission_fee { get; set; }
/// <summary>
/// 达人佣金(分)
/// </summary>
public int commission_amount { get; set; }
/// <summary>
/// 优惠金额(分)
/// </summary>
public int discounted_price { get; set; }
/// <summary>
/// 利润 = 订单金额 - 外采金额 - 平台服务费 - 达人佣金(分)
/// </summary>
public int profit { get; set; }
/// <summary>
/// 采购状态
/// </summary>
public int purchase_status { get; set; }
/// <summary>
/// 外采金额(分),out_amount 为空或0时从中转仓订单表补全
/// </summary>
public int out_amount { get; set; }
/// <summary>
/// 售后状态(订单明细 refund_status)
/// </summary>
public int refund_status { get; set; }
/// <summary>
/// 售后状态(退款单 status)
/// </summary>
public string refund_status_string { get; set; }
/// <summary>
/// 售后退款金额(分),无退款默认0
/// </summary>
public int refund_amount { get; set; }
/// <summary>
/// 是否外采:0=未从中转仓订单表查到,1=查到
/// </summary>
public int external_procurement { get; set; }
/// <summary>
/// 买手号退款金额(分):退款订单且非外采时,从买手售后表(order_pdd_buyer_after_sale)补全,无退款默认0
/// </summary>
public int buyer_refund_amount { get; set; }
/// <summary>
/// 买手号退款状态
/// </summary>
public string buyer_refund_status { get; set; }
}
}
@@ -0,0 +1,303 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using Newtonsoft.Json;
namespace KJD_Web.Utils
{
/// <summary>
/// API 请求录制工具:挂接在 Global.asax 的 BeginRequest / EndRequest,
/// 捕获请求链接(action/service)、请求内容(body/query)与响应,按天落盘为 JSON Lines,
/// 用于 .NET Core 迁移后的回放校验。
/// 配置(Web.config appSettings):
/// ApiRequestLog = 1 开启 / 0 关闭(默认开启)
/// ApiRequestLogDir = 日志目录(默认 ~/App_Data/ApiLogs)
/// </summary>
public static class ApiRequestLogger
{
private const string ItemKey = "__ApiRequestLog__";
private const string FilterItemKey = "__ApiResponseCapture__";
private const int MaxBodyLogLength = 100000;
private static readonly object SyncRoot = new object();
private static readonly Regex SensitiveKeyValueRegex = new Regex(
@"(?i)(\b(?:password|passwd|pwd|token|access_token|secret|app_secret|client_secret|sign|signature|api_key|authorization|key)=)([^&\s""]*)",
RegexOptions.Compiled);
private static readonly Regex SensitiveRegex = new Regex(
"\"((?i)password|passwd|pwd|token|access_token|secret|app_secret|client_secret|sign|signature|api_key|authorization|key)\"\\s*:\\s*\"([^\"]*)\"",
RegexOptions.Compiled);
private static readonly string[] FriendlyPrefixes =
{
"/user/", "/shop/", "/update/", "/order/", "/product/", "/product_third/", "/price/",
"/bxx_user/", "/bxx_shop/", "/bxx_product/", "/bxx_product_third/", "/bxx_price/",
"/dyxd_user/", "/dyxd_shop/", "/dyxd_product/", "/dyxd_product_third/", "/dyxd_price/",
"/wxxd_user/", "/wxxd_shop/", "/wxxd_product/", "/wxxd_product_third/", "/wxxd_price/", "/wxxd_order/"
};
private static bool _configLoaded;
private static bool _enabled = true;
private static string _logDir;
private sealed class RequestRecord
{
public string id;
public DateTime time;
public string service;
public string action;
public string url;
public string path;
public string method;
public string query;
public string body;
public string ip;
public string ua;
}
/// <summary>请求入口:解析 action/service、读取并缓存请求体、安装响应捕获。</summary>
public static void BeginRequest(HttpContext context)
{
try
{
EnsureConfig(context);
if (!_enabled) return;
string path = context.Request.Path ?? "";
if (!IsApiPath(path)) return;
string service, action;
ParsePath(path, out service, out action);
string body = ReadBody(context);
var record = new RequestRecord
{
id = Guid.NewGuid().ToString("N"),
time = DateTime.Now,
service = service,
action = action,
path = path,
method = context.Request.HttpMethod,
url = SafeGet(() => context.Request.Url == null ? path : context.Request.Url.ToString(), path),
query = Desensitize(SafeGet(() => context.Request.Url == null ? "" : context.Request.Url.Query, "")),
body = Truncate(Desensitize(body)),
ip = SafeGet(() => context.Request.UserHostAddress, ""),
ua = SafeGet(() => context.Request.UserAgent, "")
};
context.Items[ItemKey] = record;
try { context.Response.Headers["X-Request-Id"] = record.id; } catch { }
try
{
var filter = new ApiResponseCaptureStream(context.Response.Filter);
context.Response.Filter = filter;
context.Items[FilterItemKey] = filter;
}
catch { }
}
catch { }
}
/// <summary>请求出口:合并响应,写一条 JSON Lines 记录。</summary>
public static void EndRequest(HttpContext context)
{
try
{
if (!_enabled) return;
var record = context.Items[ItemKey] as RequestRecord;
if (record == null) return;
string responseText = null;
try
{
var filter = context.Items[FilterItemKey] as ApiResponseCaptureStream;
if (filter != null) responseText = Truncate(Desensitize(filter.GetCapturedText()));
}
catch { }
var line = JsonConvert.SerializeObject(new
{
id = record.id,
time = record.time.ToString("yyyy-MM-dd HH:mm:ss.fff"),
service = record.service,
action = record.action,
method = record.method,
url = record.url,
path = record.path,
query = record.query,
body = record.body,
response = responseText,
ip = record.ip,
ua = record.ua,
status = SafeGet(() => context.Response.StatusCode, 0)
});
string fileName = Path.Combine(_logDir, "api_" + DateTime.Now.ToString("yyyyMMdd") + ".jsonl");
lock (SyncRoot)
{
File.AppendAllText(fileName, line + Environment.NewLine, Encoding.UTF8);
}
}
catch { }
}
private static void EnsureConfig(HttpContext context)
{
if (_configLoaded) return;
lock (SyncRoot)
{
if (_configLoaded) return;
try
{
string sw = ConfigurationManager.AppSettings["ApiRequestLog"];
if (!string.IsNullOrEmpty(sw))
_enabled = (sw == "1" || sw.Equals("true", StringComparison.OrdinalIgnoreCase) || sw.Equals("on", StringComparison.OrdinalIgnoreCase));
string dir = ConfigurationManager.AppSettings["ApiRequestLogDir"];
if (string.IsNullOrEmpty(dir)) dir = "~/App_Data/ApiLogs";
_logDir = dir.StartsWith("~/") ? context.Server.MapPath(dir) : dir;
if (!Directory.Exists(_logDir)) Directory.CreateDirectory(_logDir);
}
catch { }
_configLoaded = true;
}
}
private static string ReadBody(HttpContext context)
{
try
{
var input = context.Request.InputStream;
if (input == null || !input.CanRead || input.Length <= 0) return "";
string text;
using (var reader = new StreamReader(input, Encoding.UTF8, true, 1024, true))
{
text = reader.ReadToEnd();
}
try { if (input.CanSeek) input.Position = 0; } catch { }
return text;
}
catch { return ""; }
}
private static bool IsApiPath(string path)
{
if (string.IsNullOrEmpty(path)) return false;
if (path.IndexOf(".asmx", StringComparison.OrdinalIgnoreCase) >= 0) return true;
foreach (string p in FriendlyPrefixes)
{
if (path.StartsWith(p, StringComparison.OrdinalIgnoreCase)) return true;
}
return false;
}
private static void ParsePath(string path, out string service, out string action)
{
service = "";
action = "";
if (string.IsNullOrEmpty(path)) return;
string p = path.TrimStart('/');
if (p.EndsWith("/")) p = p.TrimEnd('/');
string[] segs = p.Split('/');
if (segs.Length == 0) return;
action = segs[segs.Length - 1];
if (segs.Length >= 2)
{
int asmxIdx = -1;
for (int i = 0; i < segs.Length; i++)
{
if (segs[i].EndsWith(".asmx", StringComparison.OrdinalIgnoreCase)) { asmxIdx = i; break; }
}
if (asmxIdx >= 0) service = segs[asmxIdx].Replace(".asmx", "");
else service = segs[0];
}
else if (p.EndsWith(".asmx", StringComparison.OrdinalIgnoreCase))
{
service = p.Replace(".asmx", "");
action = service;
}
}
private static string Desensitize(string text)
{
if (string.IsNullOrEmpty(text)) return text;
string r = SensitiveRegex.Replace(text, "\"$1\":\"***\"");
r = SensitiveKeyValueRegex.Replace(r, "$1***");
return r;
}
private static string Truncate(string text)
{
if (string.IsNullOrEmpty(text) || text.Length <= MaxBodyLogLength) return text;
return text.Substring(0, MaxBodyLogLength) + " [truncated...]";
}
private static T SafeGet<T>(Func<T> fn, T def)
{
try { return fn(); }
catch { return def; }
}
/// <summary>响应捕获流:包装 Response.Filter,缓存写出内容。</summary>
private sealed class ApiResponseCaptureStream : Stream
{
private readonly Stream _inner;
private readonly MemoryStream _buffer = new MemoryStream();
private string _capturedText;
public ApiResponseCaptureStream(Stream inner)
{
_inner = inner ?? new MemoryStream();
}
public string GetCapturedText()
{
if (_capturedText == null) _capturedText = BytesToText(_buffer.ToArray());
return _capturedText;
}
private static string BytesToText(byte[] bytes)
{
if (bytes == null || bytes.Length == 0) return "";
bool binary = false;
for (int i = 0; i < bytes.Length; i++)
{
byte b = bytes[i];
if (b == 0 || b < 8) { binary = true; break; }
}
if (binary) return "<binary length=" + bytes.Length + ">";
return Encoding.UTF8.GetString(bytes);
}
public override bool CanRead { get { return _inner.CanRead; } }
public override bool CanSeek { get { return _inner.CanSeek; } }
public override bool CanWrite { get { return _inner.CanWrite; } }
public override long Length { get { return _inner.Length; } }
public override long Position { get { return _inner.Position; } set { _inner.Position = value; } }
public override void Flush() { _inner.Flush(); }
public override int Read(byte[] buffer, int offset, int count) { return _inner.Read(buffer, offset, count); }
public override long Seek(long offset, SeekOrigin origin) { return _inner.Seek(offset, origin); }
public override void SetLength(long value) { _inner.SetLength(value); }
public override void Write(byte[] buffer, int offset, int count)
{
_buffer.Write(buffer, offset, count);
_inner.Write(buffer, offset, count);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
try { GetCapturedText(); } catch { }
try { _inner.Dispose(); } catch { }
}
base.Dispose(disposing);
}
}
}
}
@@ -0,0 +1 @@
<%@ WebService Language="C#" CodeBehind="WXShopRevenueStatistics.asmx.cs" Class="KJD_Web.WXShopRevenueStatistics" %>
@@ -0,0 +1,68 @@
using KJD_Web.BLL.BXX;
using KJD_Web.BLL.WXXD;
using KJD_Web.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Services;
namespace KJD_Web
{
/// <summary>
/// UserService 的摘要说明
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。
// [System.Web.Script.Services.ScriptService]
public class WXShopRevenueStatistics : System.Web.Services.WebService
{
public WXShopRevenueStatistics()
{
}
private string GetRequestJsonString()
{
Context.Response.ContentType = "text/html;charset=utf-8";
Context.Response.ContentEncoding = System.Text.Encoding.GetEncoding("utf-8");
using (Stream s = HttpContext.Current.Request.InputStream) // 获得json 字符流
{
// 还原数据流
byte[] b = new byte[s.Length];
s.Read(b, 0, (int)s.Length);
string jsonText = Encoding.UTF8.GetString(b); // JSON字符串
if (string.IsNullOrEmpty(jsonText))
{
var qs = HttpContext.Current.Request.QueryString;
if (qs != null && qs.Keys.Count > 0)
{
jsonText = "{";
foreach (var key in qs.Keys)
{
jsonText += "\"" + key + "\":" + "\"" + qs[key.ToString()] + "\";";
}
jsonText = jsonText.TrimEnd(';') + "}";
}
}
return jsonText;
}
}
[WebMethod]
public void get_shop_order_amount()
{
string jsontext = GetRequestJsonString();
var result = jsontext;
result = new WXShopRevenueStatisticsManage().GetShopOrderAmountRange(jsontext);
Context.Response.Write(result);
Context.Response.End();
}
}
}