添加项目文件。

This commit is contained in:
2025-12-02 13:10:10 +08:00
parent 93a2382a16
commit 289aa4cbe7
400 changed files with 91177 additions and 0 deletions

View File

@@ -0,0 +1,188 @@
namespace Atomx.Utils.Extension
{
public static class DateTimeExtension
{
/// <summary>
/// 时间距离现在多久
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public static string DateFromNow(this DateTime time)
{
if (time == DateTime.MinValue)
{
return string.Empty;
}
TimeSpan timeSpan = DateTime.Now - time;
if (Math.Floor(timeSpan.TotalDays) > 365)
{
return Math.Floor(timeSpan.TotalDays) / 365 + "年前";
}
else if (Math.Floor(timeSpan.TotalDays) > 30)
{
return Math.Floor(timeSpan.TotalDays) / 30 + "月前";
}
else if (Math.Floor(timeSpan.TotalDays) > 7)
{
return Math.Floor(timeSpan.TotalDays) / 7 + "周前";
}
else if (Math.Floor(timeSpan.TotalDays) > 1)
{
return Math.Floor(timeSpan.TotalDays) + "天前";
}
else if (Math.Floor(timeSpan.TotalHours) > 1)
{
return Math.Floor(timeSpan.TotalHours) + "小时前";
}
else if (Math.Floor(timeSpan.TotalMinutes) > 1)
{
return Math.Floor(timeSpan.TotalMinutes) + "分钟前";
}
else
{
return Math.Floor(timeSpan.TotalSeconds) + "秒前";
}
}
/// <summary>
/// 字符串时间转换DateTime
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public static DateTime ToDateTime(this string text)
{
DateTime.TryParse(text, out DateTime time);
return time;
}
/// <summary>
/// 字符串时间转换DateTime
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public static DateTime ToUtcDateTime(this string text)
{
var state = DateTime.TryParse(text, out DateTime time);
if (state)
{
return DateTime.SpecifyKind(time, DateTimeKind.Utc);
}
return DateTime.MinValue;
}
/// <summary>
/// 获取当月第一天0时0分0秒
/// </summary>
/// <returns></returns>
public static DateTime GetMonthStartDate()
{
return DateTime.Now.AddDays(1 - DateTime.Now.Day).Date;
}
/// <summary>
/// 获取当月最后一天23时59分59秒
/// </summary>
/// <returns></returns>
public static DateTime GetMonthEndDate()
{
return DateTime.Now.AddDays(1 - DateTime.Now.Day).Date.AddMonths(1).AddSeconds(-1);
}
/// <summary>
/// 获取当前时间的周一开始时间
/// </summary>
/// <returns></returns>
public static DateTime GetWeekStartDate()
{
DateTime today = DateTime.Today;
return today.AddDays(-(int)today.DayOfWeek + (int)DayOfWeek.Monday).Date;
}
/// <summary>
/// 获取当前时间所在的周的最后一天结束时间
/// </summary>
/// <returns></returns>
public static DateTime GetWeekEndDate()
{
DateTime today = DateTime.Today;
return today.AddDays(-(int)today.DayOfWeek + (int)DayOfWeek.Monday).AddDays(7).AddSeconds(-1);
}
/// <summary>
/// 转换成每日开始时间
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public static DateTime ConvertStartDateTime(this DateTime time)
{
return time.Date;
}
/// <summary>
/// 转换成每日开始UTC时间
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public static DateTime ConvertStartDateUTCTime(this DateTime time)
{
return DateTime.SpecifyKind(time.Date, DateTimeKind.Utc);
}
/// <summary>
/// 转换成每日结束时间
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public static DateTime ConvertEndDateTime(this DateTime time)
{
return time.Date.AddDays(1).AddSeconds(-1);
}
/// <summary>
/// 转换成每日结束UTC时间
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public static DateTime ConvertEndDateUTCTime(this DateTime time)
{
return DateTime.SpecifyKind(time.Date.AddDays(1).AddSeconds(-1), DateTimeKind.Utc);
}
/// <summary>
/// long --> DateTime
/// </summary>
/// <param name="d"></param>
/// <returns></returns>
public static DateTime ConvertLongToDateTime(this long d)
{
DateTime dtStart = TimeZoneInfo.ConvertTimeToUtc(new DateTime(1970, 1, 1));
long lTime = long.Parse(d + "0000");
TimeSpan toNow = new TimeSpan(lTime);
DateTime dtResult = dtStart.Add(toNow);
return dtResult;
}
public static DateTime NumberToDateTime(this string number)
{
var year = number.Substring(0, 4);
//Console.WriteLine($"年:{year}");
var month = number.Substring(4, 2);
//Console.WriteLine($"月:{month}");
var day = number.Substring(6, 2);
//Console.WriteLine($"日:{day}");
var hour = number.Substring(8, 2);
//Console.WriteLine($"时:{hour}");
var minute = number.Substring(10, 2);
//Console.WriteLine($"分:{minute}");
var second = number.Substring(12);
//Console.WriteLine($"秒:{second}");
var datetime = $"{year}-{month}-{day} {hour}:{minute}:{second}";
DateTime date = DateTime.Parse(datetime);
return date;
}
}
}

View File

@@ -0,0 +1,37 @@
using System.Text;
namespace Atomx.Utils.Extension
{
public static class IdCodeExtension
{
private static readonly char[] Base62Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray();
/// <summary>
/// 将long类型ID编码为10位Base62邀请码
/// </summary>
public static string IdToCode(this long id)
{
ulong value = (ulong)id;
var sb = new StringBuilder();
for (int i = 0; i < 10; i++)
{
sb.Insert(0, Base62Chars[(int)(value % 62)]);
value /= 62;
}
return sb.ToString();
}
/// <summary>
/// 将10位Base62邀请码还原为long类型ID
/// </summary>
public static long CodeToId(this string code)
{
ulong value = 0;
foreach (var c in code)
{
value = value * 62 + (ulong)Array.IndexOf(Base62Chars, c);
}
return (long)value;
}
}
}

View File

@@ -0,0 +1,81 @@
namespace Atomx.Utils.Extension
{
public static class NumberExtension
{
/// <summary>
/// 字符串转 int64位数字,转换失败则返回0
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public static long ToLong(this string text)
{
long.TryParse(text, out long num);
return num;
}
/// <summary>
/// 字符转Int32位数字转换失败则返回0
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public static int ToInt(this string text)
{
int.TryParse(text, out int num);
return num;
}
public static decimal ToDecimal(this string text)
{
decimal.TryParse(text, out decimal num);
return num;
}
/// <summary>
/// 字符串转 int64位数字,转换失败则返回0
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public static double ToDouble(this string text)
{
double.TryParse(text, out double num);
return num;
}
/// <summary>
/// 移除小数点后面的0
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static decimal RemoveZero(this decimal value)
{
var text = value.ToString();
text = text.TrimEnd('0').TrimStart('.');
return Convert.ToDecimal(text);
}
/// <summary>
/// 删除无意义的0
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static string RemoveTrailingZeros(this decimal value)
{
string str = value.ToString();
if (str.Contains('.'))
{
str = str.TrimEnd('0');
if (str.EndsWith("."))
{
str = str.Substring(0, str.Length - 1);
}
}
return str;
}
public static long DateToNumber(this DateTime data)
{
return data.ToString("yyyyMMddHHmmss").ToLong();
}
}
}

View File

@@ -0,0 +1,46 @@
using System.Reflection;
using System.Xml.Serialization;
namespace Atomx.Utils.Extension
{
public static class ObjectExtension
{
/// <summary>
/// 利用反射实现深拷贝
/// </summary>
/// <param name="_object"></param>
/// <returns></returns>
public static object DeepCopy(object _object)
{
Type T = _object.GetType();
object o = Activator.CreateInstance(T);
PropertyInfo[] PI = T.GetProperties();
for (int i = 0; i < PI.Length; i++)
{
PropertyInfo P = PI[i];
P.SetValue(o, P.GetValue(_object));
}
return o;
}
/// <summary>
/// 深度克隆对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
public static T Clone<T>(this T obj)
{
T ret = default;
if (obj != null)
{
XmlSerializer cloner = new XmlSerializer(typeof(T));
MemoryStream stream = new MemoryStream();
cloner.Serialize(stream, obj);
stream.Seek(0, SeekOrigin.Begin);
ret = (T)cloner.Deserialize(stream);
}
return ret;
}
}
}

View File

@@ -0,0 +1,86 @@
using System.Text;
namespace Atomx.Utils.Extension
{
public static class PathExtension
{
/// <summary>
/// 是否是绝对路径
/// windows下判断 路径是否包含 ":"
/// Mac OS、Linux下判断 路径是否包含 "\"
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static bool IsAbsolute(this string path)
{
return Path.VolumeSeparatorChar == ':' ? path.IndexOf(Path.VolumeSeparatorChar) > 0 : path.IndexOf('\\') > 0;
}
/// <summary>
/// 获取文件绝对路径
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static string MapPath(string root, string path)
{
return path.IsAbsolute() ? path : Path.Combine(root, path.TrimStart('~', '/').Replace('/', Path.DirectorySeparatorChar));
}
/// <summary>
/// 检测指定路径是否存在
/// </summary>
/// <param name="path">路径</param>
/// <param name="isDirectory">是否是目录</param>
/// <returns></returns>
public static bool IsExist(string root, string path, bool isDirectory)
{
if (isDirectory)
{
return Directory.Exists(path.IsAbsolute() ? path : MapPath(root, path));
}
else
{
return File.Exists(path.IsAbsolute() ? path : MapPath(root, path));
}
}
/// <summary>
/// 根据指定目录,当前日期和扩展名,获取一个完整的存储路径和名称
/// </summary>
/// <param name="path">指定存储文件根目录,默认 upload</param>
/// <param name="fixedpath">是否固定存储在根目录,如果不固定,将自动根据时间生成子文件夹进行存储</param>
/// <param name="name">存储文件名,如果为空将自动生成文件名</param>
/// <param name="extension">文件存储后缀,不能为空</param>
/// <returns></returns>
public static string GetFileNameByData(string path, bool fixedpath, string name, string extension)
{
if (string.IsNullOrEmpty(extension)) throw new ArgumentNullException("extension");
if (!extension.StartsWith(".")) extension = "." + extension;
if (string.IsNullOrEmpty(path))
{
path = "/uploads";
}
if (path.StartsWith("/")) path = path.Substring(1, path.Length - 1);
if (path.EndsWith("/")) path = path.Substring(0, path.Length - 1);
StringBuilder fileName = new StringBuilder(path);
if (!fixedpath)
{
fileName.AppendFormat("/{0}/{1}/", DateTime.Now.ToString("yyyyMM"), DateTime.Now.ToString("dd"));
}
if (string.IsNullOrEmpty(name))
{
Random random = new Random(Guid.NewGuid().GetHashCode());
fileName.Append(DateTime.Now.ToString("yyyyMMddHHmmss") + random.Next(1000, 10000));
}
else
{
fileName.Append("/" + name);
}
return fileName.ToString() + extension;
}
}
}

View File

@@ -0,0 +1,60 @@
using System.Text.RegularExpressions;
namespace Atomx.Utils.Extension
{
public class RegexExtension
{
/// <summary>
/// 判断是否是电子邮件格式
/// </summary>
/// <param name="email"></param>
/// <returns></returns>
public static bool IsEmail(string email)
{
return Regex.IsMatch(email, @"^\S+@\S+\.\S+$");
}
/// <summary>
/// 判断手机号码是否符合规则,不考虑国家代码的情况下
/// </summary>
/// <param name="mobile"></param>
/// <returns></returns>
public static bool IsValidMobile(string mobile)
{
string pattern = "^\\d{7,15}$";
return Regex.IsMatch(mobile, pattern);
}
/// <summary>
/// 判断手机号码是否符合规则,不考虑国家代码的情况下
/// </summary>
/// <param name="mobile"></param>
/// <returns></returns>
public static bool IsValidGlobalMobile(string mobile)
{
// 正则表达式规则解释:
// ^ 开始
// \\+ 匹配一个加号 (E.164要求号码以加号开始)
// \\d{1,3} 匹配1到3位数字即国家代码
// \\d{7,15} 匹配7到15位数字即电话号码
// $ 结束
string pattern = "^\\+\\d{1,3}\\d{7,15}$";
return Regex.IsMatch(mobile, pattern);
}
/// <summary>
/// 验证账号是否是邮箱地址或者手机号
/// </summary>
/// <param name="account"></param>
/// <returns></returns>
public static bool IsValidAccount(string account)
{
string pattern = @"^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$";
if (Regex.IsMatch(account, pattern))
{
return true;
}
return IsValidMobile(account);
}
}
}

View File

@@ -0,0 +1,195 @@
using System.Security.Cryptography;
using System.Text;
using System.Web;
namespace Atomx.Utils.Extension
{
public static class StringExtension
{
// <summary>
/// MD5加密输出的字母是大写
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public static string ToMD5(this string text)
{
MD5 md5 = MD5.Create();
return BitConverter.ToString(md5.ComputeHash(Encoding.UTF8.GetBytes(text))).Replace("-", "");
}
/// <summary>
/// 字符串加密为通用的密码
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public static string ToMd5Password(this string text)
{
var md5 = text.ToMD5().ToMD5();
return md5;
}
/// <summary>
/// 随机数字字符串
/// </summary>
/// <param name="length"></param>
/// <returns></returns>
public static string GetRandomNumberString(int length)
{
string buffer = "0123456789";
StringBuilder sb = new StringBuilder();
Random r = new Random();
int range = buffer.Length;
for (var i = 0; i < length; i++)
{
sb.Append(buffer.Substring(r.Next(range), 1));
}
return sb.ToString();
}
/// <summary>
/// 随机数字字符串
/// </summary>
/// <param name="length"></param>
/// <returns></returns>
public static string GetRandomString(int length)
{
string buffer = "abcdefghijklmnopqrstuvwxyz";
StringBuilder sb = new StringBuilder();
Random r = new Random();
int range = buffer.Length;
for (var i = 0; i < length; i++)
{
sb.Append(buffer.Substring(r.Next(range), 1));
}
return sb.ToString();
}
/// <summary>
/// 获取URL参数字段值
/// </summary>
/// <param name="queryString"></param>
/// <param name="paramName"></param>
/// <returns></returns>
public static string GetQueryString(this string queryString, string paramName)
{
if (string.IsNullOrEmpty(queryString) || string.IsNullOrEmpty(paramName))
{
return "";
}
string paramValue = HttpUtility.ParseQueryString(queryString).Get(paramName)?.ToString() ?? string.Empty;
return paramValue ?? "";
}
/// <summary>
/// 转换URL参数
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static string BuildQueryString(this object source)
{
var buff = new StringBuilder(string.Empty);
if (source == null)
return buff.ToString();
var modelDict = source.GetType().GetProperties().ToDictionary(a => a.Name.ToLower());
foreach (var item in modelDict)
{
if (item.Value.PropertyType != typeof(DateTime?[]))
{
System.Reflection.PropertyInfo? pi = null;
if (modelDict.TryGetValue(item.Key, out pi))
{
object? obj = pi.GetValue(source, null);
if (pi != null && obj != null)
{
var value = obj.ToString();
if (!string.IsNullOrEmpty(value))
{
buff.Append($"{item.Key}={value}&");
}
}
}
}
else
{
System.Reflection.PropertyInfo? pi = null;
if (modelDict.TryGetValue(item.Key, out pi))
{
object? obj = pi.GetValue(source, null);
if (pi != null && obj != null)
{
var data = obj as DateTime?[];
if (data != null)
{
long start = 0;
long end = 0;
if (data[0].HasValue) {
var time1 = data[0].Value.ConvertStartDateTime();
start = time1.DateToNumber();
}
if (data[1].HasValue)
{
var time1 = data[1].Value.ConvertEndDateTime();
end = time1.DateToNumber();
}
if (start > 0 && end > 0)
{
buff.Append($"{item.Key}={start}-{end}&");
}
}
}
}
}
}
return buff.ToString().Trim('&');
}
/// <summary>
/// url参数转换成字典
/// </summary>
/// <param name="formData"></param>
/// <returns></returns>
public static Dictionary<string, object> ToUrlDictionary(this string formData)
{
if (string.IsNullOrEmpty(formData))
{
return new Dictionary<string, object>();
}
try
{
//将参数存入字符数组
string[] dataArry = formData.Split('&');
//定义字典,将参数按照键值对存入字典中
Dictionary<string, object> dataDic = new Dictionary<string, object>();
//遍历字符数组
for (int i = 0; i <= dataArry.Length - 1; i++)
{
//当前参数值
string dataParm = dataArry[i];
//"="的索引值
int dIndex = dataParm.IndexOf("=");
//参数名作为key
string key = dataParm.Substring(0, dIndex);
//参数值作为Value
string value = dataParm.Substring(dIndex + 1, dataParm.Length - dIndex - 1);
//将编码后的Value解码
string deValue = HttpUtility.UrlDecode(value, Encoding.GetEncoding("utf-8"));
if (key != "__VIEWSTATE")
{
//将参数以键值对存入字典
dataDic.Add(key, deValue);
}
}
return dataDic;
}
catch (Exception)
{
return new Dictionary<string, object>();
}
}
}
}

View File

@@ -0,0 +1,189 @@
using Atomx.Utils.Json;
using Atomx.Utils.Models;
using Microsoft.AspNetCore.Http;
using System.Net;
namespace Atomx.Utils.Extension
{
public class UploadExtension
{
/// <summary>
/// 上传
/// </summary>
/// <param name="file">文件</param>
/// <param name="rootPath">站点根目录</param>
/// <param name="path">存储目录</param>
/// <param name="fixedPath">是否固定存储在根目录,如果不固定,将自动根据时间生成子文件夹进行存储</param>
/// <param name="fileName">文件名</param>
/// <param name="currentPath">覆盖上传的路径</param>
/// <param name="extension">文件类型</param>
/// <returns></returns>
public Result<string> LocalUpload(IFormFile file, string rootPath, string path, bool fixedPath, string fileName, string currentPath, string extension)
{
var result = new Result<string>();
var filepath = string.Empty;
if (!string.IsNullOrEmpty(currentPath))
{
filepath = currentPath;
}
else
{
filepath = PathExtension.GetFileNameByData(path, fixedPath, fileName, extension);
}
var savepath = Path.Combine(rootPath, filepath.Replace("/", "\\"));
var newpath = Path.GetDirectoryName(savepath);
if (string.IsNullOrEmpty(newpath))
{
result.Message = "Storage path exception";
result.Success = false;
return result;
}
try
{
if (!Directory.Exists(newpath))
{
Directory.CreateDirectory(newpath);
}
}
catch
{
result.Message = "Folder failure is established";
result.Success = false;
return result;
}
try
{
using (FileStream fs = File.Create(savepath))
{
file.CopyTo(fs);
fs.Flush();
}
}
catch (Exception ex)
{
result.Message = ex.Message;
result.Success = false;
}
result.Data = filepath;
return result;
}
/// <summary>
/// 上传
/// </summary>
/// <param name="file">文件</param>
/// <param name="rootPath">站点根目录</param>
/// <param name="path">存储目录</param>
/// <param name="fixedPath">是否固定存储在根目录,如果不固定,将自动根据时间生成子文件夹进行存储</param>
/// <param name="fileName">文件名</param>
/// <param name="currentPath">覆盖上传的路径</param>
/// <param name="extension">文件类型</param>
/// <returns></returns>
public async Task<Result<string>> LocalUploadEncryptAsync(IFormFile file, string rootPath, string path, bool fixedPath, string fileName, string currentPath, string extension)
{
var result = new Result<string>();
var filepath = string.Empty;
if (!string.IsNullOrEmpty(currentPath))
{
filepath = currentPath;
}
else
{
filepath = PathExtension.GetFileNameByData(path, fixedPath, fileName, extension);
}
var savepath = Path.Combine(rootPath, filepath.Replace("/", "\\"));
var newpath = Path.GetDirectoryName(savepath);
if(string.IsNullOrEmpty(newpath))
{
result.Message = "Storage path exception";
result.Success = false;
return result;
}
try
{
if (!Directory.Exists(newpath))
{
Directory.CreateDirectory(newpath);
}
}
catch
{
result.Message = "Folder failure is established";
result.Success = false;
return result;
}
try
{
var stream = file.OpenReadStream();
byte[] bytes = new byte[stream.Length];
await stream.ReadAsync(bytes, 0, bytes.Length);
for (int i = 0; i < bytes.Length; i++)
{
++bytes[i];
}
var fsw = new FileStream(savepath, FileMode.Create, FileAccess.Write);
fsw.Write(bytes, 0, bytes.Length);
fsw.Close();
}
catch (Exception ex)
{
result.Message = ex.Message;
result.Success = false;
}
result.Data = filepath;
return result;
}
/// <summary>
/// 远程上传文件
/// </summary>
/// <param name="file"></param>
/// <param name="url"></param>
/// <param name="rootpath"></param>
/// <param name="fixedpath"></param>
/// <param name="filename"></param>
/// <param name="currentpath"></param>
/// <returns></returns>
public async Task<UploadResult> RemoteUploadAsync(IFormFile file, string url, string rootpath, bool fixedpath, string filename, string currentpath)
{
var result = new UploadResult();
var dic = new Dictionary<string, string>();
dic.Add("rootpath", rootpath);
dic.Add("fixedpath", fixedpath.ToString().ToLower());
dic.Add("filename", filename);
dic.Add("currentpath", currentpath);
using (var client = new HttpClient())
{
using (var content = new MultipartFormDataContent())
{
content.Add(new StreamContent(file.OpenReadStream()), "file", file.FileName);
foreach (var item in dic)
{
content.Add(new StringContent(item.Value), item.Key);
}
var response = await client.PostAsync(url, content);
if (response.StatusCode == HttpStatusCode.OK)
{
var uploadresult = await response.Content.ReadAsStringAsync();
result = uploadresult.FromJson<UploadResult>();
}
else
{
//result.Code = UploadCodes.Failure;
//result.Message = "remote server is error";
}
}
}
return result;
}
}
}