Files
17168ERP/web/App_Code/Model/Partial/follower.cs
2025-11-12 18:57:51 +08:00

304 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.Serialization;
using System.Web;
using System.Web.Http;
using tyme.solar;
namespace Model
{
// 為對應資料表MODEL宣告額外參數類別(Metadata)
// [JsonIgnore] 避免WEBAPI自動抓關聯資料
[MetadataType(typeof(followerMetadata))]
public partial class follower
{
private class followerMetadata
{
[JsonIgnore]
public virtual ICollection<follower> followers1 { get; set; }
[JsonIgnore]
public virtual follower follower1 { get; set; }
[JsonIgnore]
public virtual ICollection<activity_check> activity_check { get; set; }
[JsonIgnore]
public virtual country country1 { get; set; }
[JsonIgnore]
public virtual ICollection<member> members { get; set; }
[JsonIgnore]
public virtual ICollection<pro_order_detail> pro_order_detail { get; set; }
[JsonIgnore]
public virtual ICollection<pro_order_detail> pro_order_detail1 { get; set; }
[JsonIgnore]
public virtual ICollection<pro_order> pro_order { get; set; }
[JsonIgnore]
public virtual ICollection<pro_order> pro_order1 { get; set; }
[JsonIgnore]
public virtual ICollection<followers_tablet> followers_tablet { get; set; }
[JsonIgnore]
public virtual appellation appellation { get; set; }
/// <summary>
/// added
/// </summary>
[JsonIgnore]
public virtual ICollection<family_members> family_members { get; set; }
[JsonIgnore]
public virtual ICollection<transfer_register> transfer_register { get; set; }
[JsonIgnore]
public virtual ICollection<transfer_register> transfer_register1 { get; set; }
[JsonIgnore]
public virtual ICollection<GuaDanOrder> GuaDanOrder { get; set; }
[JsonIgnore]
public virtual ICollection<GuaDanOrderGuest> GuaDanOrderGuest { get; set; }
}
public enum type : int
{
[Description("出家眾")]
Monk = 1,// 4,
[Description("個人")]
Personal = 2, //1,
[Description("法人")]
Legal = 3, //2,
[Description("往生菩薩")]
Bodhisattva = 4, //3,
[Description("蓮友")]
Seeker = 10,
}
// TODO: CRITICAL - 靜態字段設計問題
// 【現狀問題】
// 1. 靜態字段會在類加載時創建新的 DbContext但從未 Dispose
// 2. ToList() 會立即載入所有 followers 到內存(可能數千筆),佔用大量內存且數據會過時
// 3. AsEnumerable() 看似更好(延遲執行),但會導致 DbContext 生命週期問題
//
// 【權衡】
// - 用 AsEnumerable(): 不立即佔內存,但 DbContext 未 Dispose後續訪問可能出錯
// - 用 ToList(): DbContext 可安全關閉,但立即佔用大量內存且數據過時
//
// 【建議改法】
// 方案 A: 改為實例方法 `public static List<follower> GetAllFollowers() { using(var db = new ezEntities()) return db.followers.ToList(); }`
// 方案 B: 使用緩存機制MemoryCache定期更新
// 方案 C: 完全移除此字段,改為按需查詢
//
// 暫時保留 AsEnumerable() 避免立即載入大量數據(雖然有 DbContext 問題,但至少不會內存爆掉)
public static IEnumerable<Model.follower> allFaollowers = new Model.ezEntities().followers.AsEnumerable();
//public static string identity_type_list()
#region &
public enum chinese
{
= 1, = 2, = 3, = 4, = 5, = 6,
= 7, = 8, = 9, = 10, = 11, = 12
}
public enum heavenlyStems
{
= 1, , , , , , , , ,
}
public enum earthlyBranches
{
= 1, , , , , , , , , , ,
}
public static string chagenSign(DateTime? date)
{ //可改公用
//生肖
if (date == null) return null;
DateTime d = date.Value;
// 使用 tyme4net 方法
try
{
var solarDay = SolarDay.FromYmd(d.Year, d.Month, d.Day);
var lunarDay = solarDay.GetLunarDay();
// 使用正確的 tyme4net API
var lunarYear = tyme.lunar.LunarYear.FromYear(lunarDay.Year);
return lunarYear.SixtyCycle.EarthBranch.GetZodiac().GetName();
}
catch (Exception ex)
{
return $"生肖計算錯誤: {ex.Message}";
}
}
public static string sexagenary(DateTime? date)
{
try
{
if (date != null)
{
DateTime d = date ?? DateTime.Now;
//依農曆年計算,故同一年的1月跟6月會得不同結果
//ChineseLunisolarCalendar chineseDate = new ChineseLunisolarCalendar();
//int y = chineseDate.GetYear(d);// 農曆年分
//int a = chineseDate.GetSexagenaryYear(d); // 獲取干支纪年值
//heavenlyStems tg = (heavenlyStems)chineseDate.GetCelestialStem(a);
//earthlyBranches dz = (earthlyBranches)chineseDate.GetTerrestrialBranch(a);
//return $"{tg}{dz}";
int year = d.Year;
if (year > 3)
{
int tgIndex = (year - 4) % 10;
int dzIndex = (year - 4) % 12;
return $"{(heavenlyStems)(tgIndex + 1)}{(earthlyBranches)(dzIndex + 1)}";
}
//throw new ArgumentOutOfRangeException("無效的年份!");
return null;
}
}
catch
{
//return null;
}
return null;
}
public static string ChkNewFollower(Model.follower newFollower)
{
Model.ezEntities _db = new Model.ezEntities();
if (string.IsNullOrWhiteSpace(newFollower.u_name))
{
return "姓名不應為空白";
}
MyWeb.encrypt encrypt = new MyWeb.encrypt();
// 解密並只保留數字
string decryptedNewPhone = !string.IsNullOrWhiteSpace(newFollower.phone)
? new string(encrypt.DecryptAutoKey(newFollower.phone).Where(char.IsDigit).ToArray()) : "";
string decryptedNewCellphone = !string.IsNullOrWhiteSpace(newFollower.cellphone)
? new string(encrypt.DecryptAutoKey(newFollower.cellphone).Where(char.IsDigit).ToArray()) : "";
var existingFollowers = _db.followers.Where(f => f.u_name == newFollower.u_name).ToList();
if (!existingFollowers.Any())
{
return "";
}
foreach (var follower in existingFollowers)
{
string decryptedPhone = !string.IsNullOrWhiteSpace(follower.phone)
? new string(encrypt.DecryptAutoKey(follower.phone).Where(char.IsDigit).ToArray()) : "";
string decryptedCellphone = !string.IsNullOrWhiteSpace(follower.cellphone)
? new string(encrypt.DecryptAutoKey(follower.cellphone).Where(char.IsDigit).ToArray()) : "";
if ((!string.IsNullOrWhiteSpace(decryptedNewPhone) && decryptedNewPhone == decryptedPhone) ||
(!string.IsNullOrWhiteSpace(decryptedNewCellphone) && decryptedNewCellphone == decryptedCellphone))
{
return "姓名重複 + 電話或手機重複";
}
}
return "";
}
#endregion
public static string generate_f_number(string sex = "男眾")
{
string selectedSex = sex;
var datePart = DateTime.Now.ToString("yyyyMMdd");
// 使用重試機制確保不重號
int maxRetries = 5;
for (int retry = 0; retry < maxRetries; retry++)
{
try
{
using (var _db = new Model.ezEntities())
using (var transaction = _db.Database.BeginTransaction())
{
// 在交易中查詢最大序號
int nextSerial = GetNextSerialFromDatabase(_db, datePart, selectedSex);
string f_number = GenerateFNumber(selectedSex, datePart, nextSerial);
// 立即檢查是否重複(在交易中)
if (!_db.followers.Any(f => f.f_number == f_number))
{
transaction.Commit();
return f_number;
}
// 如果重複,回滾交易並重試
transaction.Rollback();
// 短暫延遲後重試
if (retry < maxRetries - 1)
{
System.Threading.Thread.Sleep(10 + retry * 5); // 10ms, 15ms, 20ms, 25ms
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"生成編號失敗 (重試 {retry + 1}): {ex.Message}");
if (retry == maxRetries - 1)
{
// 最後一次重試失敗,使用時間戳記確保唯一性
return GenerateFNumberWithTimestamp(selectedSex, datePart);
}
}
}
// 如果所有重試都失敗,使用時間戳記
return GenerateFNumberWithTimestamp(selectedSex, datePart);
}
private static int GetNextSerialFromDatabase(Model.ezEntities _db, string datePart, string sex)
{
var prefix = sex == "男眾" ? "M" : "F";
var searchPattern = prefix + datePart;
var maxFNumber = _db.followers
.Where(m =>
m.f_number.Length == 14 &&
m.f_number.StartsWith(searchPattern))
.OrderByDescending(m => m.f_number)
.Select(m => m.f_number)
.FirstOrDefault();
if (!string.IsNullOrEmpty(maxFNumber))
{
var serialPart = maxFNumber.Substring(9, 5);
return int.Parse(serialPart) + 1;
}
return 1;
}
private static string GenerateFNumber(string sex, string datePart, int serial)
{
string prefix = sex == "男眾" ? "M" : "F";
return prefix + datePart + serial.ToString("D5");
}
private static string GenerateFNumberWithTimestamp(string sex, string datePart)
{
// 使用時間戳記確保唯一性(最後手段)
string prefix = sex == "男眾" ? "M" : "F";
var timestamp = DateTime.Now.ToString("HHmmss");
return prefix + datePart + timestamp;
}
}
}