Skip to content

Commit d4cac39

Browse files
committed
feat: 导出所有源码类到 docs/ 目录(78个.cs文件按层归类)
1 parent 245c155 commit d4cac39

78 files changed

Lines changed: 7914 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
using Juggle.Application.Models.Request;
2+
using Juggle.Application.Models.Response;
3+
using Juggle.Domain.Entities;
4+
using Juggle.Infrastructure.Persistence;
5+
using Microsoft.AspNetCore.Authorization;
6+
using Microsoft.AspNetCore.Mvc;
7+
using Microsoft.EntityFrameworkCore;
8+
using System.Text.Json;
9+
10+
namespace Juggle.Api.Controllers.Api;
11+
12+
[ApiController]
13+
[Route("api/suite/api")]
14+
[Authorize]
15+
public class ApiController : ControllerBase
16+
{
17+
private readonly JuggleDbContext _db;
18+
private readonly IHttpClientFactory _httpClientFactory;
19+
20+
public ApiController(JuggleDbContext db, IHttpClientFactory httpClientFactory)
21+
{
22+
_db = db;
23+
_httpClientFactory = httpClientFactory;
24+
}
25+
26+
[HttpPost("add")]
27+
public async Task<ApiResult> Add([FromBody] ApiAddRequest req)
28+
{
29+
// 检查套件是否存在
30+
var suite = await _db.Suites.FirstOrDefaultAsync(s => s.SuiteCode == req.SuiteCode && s.Deleted == 0);
31+
if (suite == null) return ApiResult.Fail("套件不存在");
32+
33+
var code = $"api_{Guid.NewGuid():N}";
34+
var entity = new ApiEntity
35+
{
36+
SuiteCode = req.SuiteCode,
37+
MethodCode = code,
38+
MethodName = req.MethodName,
39+
MethodDesc = req.MethodDesc,
40+
Url = req.Url,
41+
RequestType = req.RequestType,
42+
ContentType = req.ContentType,
43+
MockJson = req.MockJson,
44+
MethodType = req.MethodType,
45+
CreatedAt = DateTime.Now.ToString("o")
46+
};
47+
_db.Apis.Add(entity);
48+
await _db.SaveChangesAsync();
49+
return ApiResult.Success(entity.Id);
50+
}
51+
52+
[HttpDelete("delete/{id}")]
53+
public async Task<ApiResult> Delete(long id)
54+
{
55+
var entity = await _db.Apis.FindAsync(id);
56+
if (entity == null) return ApiResult.Fail("接口不存在");
57+
entity.Deleted = 1;
58+
entity.UpdatedAt = DateTime.Now.ToString("o");
59+
await _db.SaveChangesAsync();
60+
return ApiResult.Success();
61+
}
62+
63+
[HttpPut("update")]
64+
public async Task<ApiResult> Update([FromBody] ApiUpdateRequest req)
65+
{
66+
var entity = await _db.Apis.FindAsync(req.Id);
67+
if (entity == null) return ApiResult.Fail("接口不存在");
68+
entity.MethodName = req.MethodName;
69+
entity.MethodDesc = req.MethodDesc;
70+
entity.Url = req.Url;
71+
entity.RequestType = req.RequestType;
72+
entity.ContentType = req.ContentType;
73+
entity.MockJson = req.MockJson;
74+
entity.MethodType = req.MethodType;
75+
entity.UpdatedAt = DateTime.Now.ToString("o");
76+
await _db.SaveChangesAsync();
77+
return ApiResult.Success();
78+
}
79+
80+
[HttpGet("info/{id}")]
81+
public async Task<ApiResult> Info(long id)
82+
{
83+
var entity = await _db.Apis.FindAsync(id);
84+
if (entity == null || entity.Deleted == 1) return ApiResult.Fail("接口不存在");
85+
var inputParams = await _db.Parameters.Where(p => p.OwnerId == id && p.ParamType == 1 && p.Deleted == 0).OrderBy(p => p.SortNum).ToListAsync();
86+
var outputParams = await _db.Parameters.Where(p => p.OwnerId == id && p.ParamType == 2 && p.Deleted == 0).OrderBy(p => p.SortNum).ToListAsync();
87+
var headerParams = await _db.Parameters.Where(p => p.OwnerId == id && p.ParamType == 4 && p.Deleted == 0).OrderBy(p => p.SortNum).ToListAsync();
88+
return ApiResult.Success(new { api = entity, inputParams, outputParams, headerParams });
89+
}
90+
91+
[HttpPost("list")]
92+
public async Task<ApiResult> List([FromBody] dynamic req)
93+
{
94+
string suiteCode = req.GetProperty("suiteCode").GetString() ?? "";
95+
var list = await _db.Apis.Where(a => a.SuiteCode == suiteCode && a.Deleted == 0).OrderBy(a => a.Id).ToListAsync();
96+
return ApiResult.Success(list);
97+
}
98+
99+
[HttpPost("debug")]
100+
public async Task<ApiResult> Debug([FromBody] ApiDebugRequest req)
101+
{
102+
var api = await _db.Apis.FindAsync(req.ApiId);
103+
if (api == null) return ApiResult.Fail("接口不存在");
104+
105+
var methodType = api.MethodType?.ToUpper() ?? "HTTP";
106+
107+
try
108+
{
109+
// Mock 模式:如果接口配置了 MockJson,直接返回预设数据
110+
if (!string.IsNullOrEmpty(api.MockJson))
111+
{
112+
return ApiResult.Success(new { response = api.MockJson, mock = true });
113+
}
114+
115+
// WebService(SOAP 1.1)调试
116+
if (methodType == "WEBSERVICE")
117+
{
118+
return await DebugWebService(api, req);
119+
}
120+
121+
// HTTP 调用(原有逻辑)
122+
var client = _httpClientFactory.CreateClient();
123+
foreach (var h in req.Headers)
124+
client.DefaultRequestHeaders.TryAddWithoutValidation(h.Key, h.Value?.ToString());
125+
126+
string responseJson;
127+
var requestType = api.RequestType?.ToUpper() ?? "GET";
128+
129+
if (requestType == "GET" || requestType == "DELETE")
130+
{
131+
var url = api.Url!;
132+
if (req.Params.Count > 0)
133+
{
134+
var query = string.Join("&", req.Params.Select(kv =>
135+
$"{Uri.EscapeDataString(kv.Key)}={Uri.EscapeDataString(kv.Value?.ToString() ?? "")}"));
136+
url = url.Contains('?') ? $"{url}&{query}" : $"{url}?{query}";
137+
}
138+
var resp = requestType == "GET" ? await client.GetAsync(url) : await client.DeleteAsync(url);
139+
responseJson = await resp.Content.ReadAsStringAsync();
140+
}
141+
else
142+
{
143+
var content = new StringContent(
144+
JsonSerializer.Serialize(req.Params),
145+
System.Text.Encoding.UTF8, "application/json");
146+
var resp = requestType == "PUT" ? await client.PutAsync(api.Url, content) : await client.PostAsync(api.Url, content);
147+
responseJson = await resp.Content.ReadAsStringAsync();
148+
}
149+
150+
return ApiResult.Success(new { response = responseJson });
151+
}
152+
catch (Exception ex)
153+
{
154+
return ApiResult.Fail($"调用失败: {ex.Message}");
155+
}
156+
}
157+
158+
/// <summary>调试 WebService(SOAP 1.1)接口</summary>
159+
private async Task<ApiResult> DebugWebService(ApiEntity api, ApiDebugRequest req)
160+
{
161+
// 从 Url 中提取 soapAction(可通过 Header "SOAPAction" 传入,也可为空)
162+
var soapAction = req.Headers.ContainsKey("SOAPAction") ? req.Headers["SOAPAction"]?.ToString() ?? "" : "";
163+
164+
// 构建 SOAP 1.1 请求体:用入参 key/value 组装 XML 参数
165+
var paramXml = string.Join("", req.Params.Select(kv =>
166+
$"<{kv.Key}>{System.Security.SecurityElement.Escape(kv.Value?.ToString() ?? "")}</{kv.Key}>"));
167+
168+
// 从 Url 中解析 method name(取路径最后一段,例如 http://ws/HelloService?op=SayHello → SayHello)
169+
var methodName = "Request";
170+
var uri = new Uri(api.Url!);
171+
// 解析 ?op=MethodName 参数
172+
var queryParams = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(uri.Query);
173+
if (queryParams.TryGetValue("op", out var opVal) && !string.IsNullOrEmpty(opVal))
174+
methodName = opVal!;
175+
176+
var soapBody = $@"<?xml version=""1.0"" encoding=""utf-8""?>
177+
<soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
178+
<soap:Body>
179+
<{methodName} xmlns=""{uri.GetLeftPart(UriPartial.Path)}"">
180+
{paramXml}
181+
</{methodName}>
182+
</soap:Body>
183+
</soap:Envelope>";
184+
185+
var client = _httpClientFactory.CreateClient();
186+
// SOAP 1.1 必须 POST,Content-Type: text/xml
187+
var content = new StringContent(soapBody, System.Text.Encoding.UTF8, "text/xml");
188+
if (!string.IsNullOrEmpty(soapAction))
189+
content.Headers.Add("SOAPAction", $"\"{soapAction}\"");
190+
191+
// 附加其他 headers
192+
foreach (var h in req.Headers)
193+
if (h.Key != "SOAPAction")
194+
client.DefaultRequestHeaders.TryAddWithoutValidation(h.Key, h.Value?.ToString());
195+
196+
var resp = await client.PostAsync(api.Url, content);
197+
var responseText = await resp.Content.ReadAsStringAsync();
198+
return ApiResult.Success(new { response = responseText, soapBody });
199+
}
200+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using Juggle.Domain.Entities;
2+
using Juggle.Infrastructure.Persistence;
3+
using Juggle.Application.Models.Request;
4+
using Juggle.Application.Models.Response;
5+
using Juggle.Application.Services;
6+
using Microsoft.AspNetCore.Authorization;
7+
using Microsoft.AspNetCore.Mvc;
8+
using Microsoft.EntityFrameworkCore;
9+
10+
namespace Juggle.Api.Controllers.Api;
11+
12+
[ApiController]
13+
[Route("api/audit-log")]
14+
public class AuditLogController : ControllerBase
15+
{
16+
private readonly JuggleDbContext _db;
17+
private readonly ITenantAccessor _tenant;
18+
19+
public AuditLogController(JuggleDbContext db, ITenantAccessor tenant)
20+
{
21+
_db = db;
22+
_tenant = tenant;
23+
}
24+
25+
/// <summary>审计日志分页列表(超级管理员)</summary>
26+
[HttpPost("page"), Authorize]
27+
public async Task<ApiResult> Page([FromBody] AuditLogPageRequest req)
28+
{
29+
if (!_tenant.IsSuperAdmin)
30+
return ApiResult.Fail("仅超级管理员可查看", 403);
31+
32+
var query = _db.AuditLogs.Where(a => a.Deleted == 0);
33+
if (!string.IsNullOrEmpty(req.Module))
34+
query = query.Where(a => a.Module == req.Module);
35+
if (!string.IsNullOrEmpty(req.ActionType))
36+
query = query.Where(a => a.ActionType == req.ActionType);
37+
if (!string.IsNullOrEmpty(req.Keyword))
38+
query = query.Where(a => a.ChangeContent.Contains(req.Keyword)
39+
|| (a.OperatorName != null && a.OperatorName.Contains(req.Keyword)));
40+
41+
var total = await query.CountAsync();
42+
var records = await query.OrderByDescending(a => a.Id)
43+
.Skip((req.PageNum - 1) * req.PageSize)
44+
.Take(req.PageSize)
45+
.Select(a => new
46+
{
47+
a.Id, a.Module, a.ActionType, a.TargetId, a.ChangeContent,
48+
a.OperatorName, a.OperatorId, a.OperatorTenantId, a.CreatedAt
49+
})
50+
.ToListAsync();
51+
52+
return ApiResult.Success(new { total, records });
53+
}
54+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
using Juggle.Application.Models.Request;
2+
using Juggle.Application.Models.Response;
3+
using Juggle.Application.Services.Impl;
4+
using Juggle.Domain.Entities;
5+
using Juggle.Infrastructure.Persistence;
6+
using Microsoft.AspNetCore.Authorization;
7+
using Microsoft.AspNetCore.Mvc;
8+
using Microsoft.EntityFrameworkCore;
9+
10+
namespace Juggle.Api.Controllers.Api;
11+
12+
[ApiController]
13+
[Route("api/system/datasource")]
14+
[Authorize]
15+
public class DataSourceController : ControllerBase
16+
{
17+
private readonly JuggleDbContext _db;
18+
private readonly DataSourceService _dsService;
19+
20+
public DataSourceController(JuggleDbContext db, DataSourceService dsService)
21+
{
22+
_db = db;
23+
_dsService = dsService;
24+
}
25+
26+
[HttpPost("add")]
27+
public async Task<ApiResult> Add([FromBody] DataSourceAddRequest req)
28+
{
29+
var entity = new DataSourceEntity
30+
{
31+
DsName = req.DsName,
32+
DsType = req.DsType,
33+
Host = req.Host,
34+
Port = req.Port,
35+
DbName = req.DbName,
36+
Username = req.Username,
37+
Password = req.Password,
38+
CreatedAt = DateTime.Now.ToString("o")
39+
};
40+
_db.DataSources.Add(entity);
41+
await _db.SaveChangesAsync();
42+
return ApiResult.Success(entity.Id);
43+
}
44+
45+
[HttpDelete("delete/{id}")]
46+
public async Task<ApiResult> Delete(long id)
47+
{
48+
var entity = await _db.DataSources.FindAsync(id);
49+
if (entity == null) return ApiResult.Fail("数据源不存在");
50+
entity.Deleted = 1;
51+
await _db.SaveChangesAsync();
52+
return ApiResult.Success();
53+
}
54+
55+
[HttpPut("update")]
56+
public async Task<ApiResult> Update([FromBody] DataSourceUpdateRequest req)
57+
{
58+
var entity = await _db.DataSources.FindAsync(req.Id);
59+
if (entity == null) return ApiResult.Fail("数据源不存在");
60+
entity.DsName = req.DsName;
61+
entity.Host = req.Host;
62+
entity.Port = req.Port;
63+
entity.DbName = req.DbName;
64+
entity.Username = req.Username;
65+
entity.Password = req.Password;
66+
entity.UpdatedAt = DateTime.Now.ToString("o");
67+
await _db.SaveChangesAsync();
68+
return ApiResult.Success();
69+
}
70+
71+
[HttpGet("list")]
72+
public async Task<ApiResult> List()
73+
{
74+
var list = await _db.DataSources
75+
.Where(d => d.Deleted == 0)
76+
.OrderByDescending(d => d.Id)
77+
.Select(d => new { dataSourceName = d.DsName, dataSourceType = d.DsType, id = d.Id })
78+
.ToListAsync();
79+
return ApiResult.Success(list);
80+
}
81+
82+
/// <summary>测试数据源连接</summary>
83+
[HttpPost("test/{id}")]
84+
public async Task<ApiResult> Test(long id)
85+
{
86+
var (ok, msg) = await _dsService.TestConnectionAsync(id);
87+
return ok ? ApiResult.Success(msg) : ApiResult.Fail(msg);
88+
}
89+
90+
[HttpPost("page")]
91+
public async Task<ApiResult> Page([FromBody] PageRequest req)
92+
{
93+
var query = _db.DataSources.Where(d => d.Deleted == 0);
94+
var total = await query.CountAsync();
95+
var records = await query
96+
.OrderByDescending(d => d.Id)
97+
.Skip((req.PageNum - 1) * req.PageSize)
98+
.Take(req.PageSize)
99+
.ToListAsync();
100+
return ApiResult.Success(new PageResult<DataSourceEntity>
101+
{
102+
Total = total, PageNum = req.PageNum, PageSize = req.PageSize, Records = records
103+
});
104+
}
105+
}

0 commit comments

Comments
 (0)