3 Commits

Author SHA1 Message Date
b71f72774a 合併掛單系統的SCHEMA SQL 2025-09-12 15:52:40 +08:00
c90d181b5e chinese
date
2025-09-11 00:47:51 +08:00
05a7cc3e9b 重寫信眾編號程式 2025-09-10 00:21:47 +08:00
10 changed files with 150 additions and 109 deletions

Binary file not shown.

View File

@@ -8,5 +8,5 @@ using System.Web;
/// </summary> /// </summary>
public static class GlobalVariables public static class GlobalVariables
{ {
public static readonly object FNumberLock = new object(); // FNumberLock 已移除,因為改用資料庫直接取號,不再需要 Application 狀態鎖定
} }

View File

@@ -10,6 +10,8 @@ using System.Reflection.Emit;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Web; using System.Web;
using System.Web.Http; using System.Web.Http;
using tyme.solar;
namespace Model namespace Model
{ {
@@ -71,12 +73,12 @@ namespace Model
= 1, = 2, = 3, = 4, = 5, = 6, = 1, = 2, = 3, = 4, = 5, = 6,
= 7, = 8, = 9, = 10, = 11, = 12 = 7, = 8, = 9, = 10, = 11, = 12
} }
enum heavenlyStems public enum heavenlyStems
{ {
= 1, , , , , , , , , = 1, , , , , , , , ,
} }
enum earthlyBranches public enum earthlyBranches
{ {
= 1, , , , , , , , , , , = 1, , , , , , , , , , ,
} }
@@ -85,28 +87,24 @@ namespace Model
public static string chagenSign(DateTime? date) public static string chagenSign(DateTime? date)
{ //可改公用 { //可改公用
//生肖 //生肖
if (date == null) return null;
DateTime d = date.Value;
// 使用 tyme4net 方法
try try
{ {
if (date != null) var solarDay = SolarDay.FromYmd(d.Year, d.Month, d.Day);
{ var lunarDay = solarDay.GetLunarDay();
DateTime d = date ?? DateTime.Now;
int year = d.Year;
int birthpet; //宣告生肖要用的變數
birthpet = year % 12; //西元年除12取餘數 // 使用正確的 tyme4net API
birthpet -= 3; var lunarYear = tyme.lunar.LunarYear.FromYear(lunarDay.Year);
//餘數-3 return lunarYear.SixtyCycle.EarthBranch.GetZodiac().GetName();
if (birthpet <= 0) birthpet += 12;
//判斷餘數是否大於0小於0必須+12
return Enum.GetName(typeof(chinese), birthpet);
//return ((chinese)birthpet).ToString(); //也可以
} }
} catch (Exception ex)
catch
{ {
//return null; return $"生肖計算錯誤: {ex.Message}";
} }
return null;
} }
public static string sexagenary(DateTime? date) public static string sexagenary(DateTime? date)
{ {
@@ -190,21 +188,87 @@ namespace Model
public static string generate_f_number(string sex = "男眾") public static string generate_f_number(string sex = "男眾")
{ {
string selectedSex = sex; string selectedSex = sex;
string f_number = selectedSex == "男眾" ? "M" : "F";
var datePart = DateTime.Now.ToString("yyyyMMdd"); var datePart = DateTime.Now.ToString("yyyyMMdd");
f_number += datePart;
// 使用重試機制確保不重號
int nextSerial = 1; int maxRetries = 5;
for (int retry = 0; retry < maxRetries; retry++)
lock (GlobalVariables.FNumberLock)
{ {
nextSerial = (int)HttpContext.Current.Application["FNumberSerial"] + 1; try
HttpContext.Current.Application["FNumberSerial"] = nextSerial; {
} using (var _db = new Model.ezEntities())
f_number += nextSerial.ToString("D5"); 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; 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;
}
} }
} }

View File

@@ -8,6 +8,9 @@ using System.Drawing.Imaging;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Web; using System.Web;
using tyme.solar;
using tyme.lunar;
using tyme.sixtycycle;
/// <summary> /// <summary>
/// publicFun 的摘要描述 /// publicFun 的摘要描述
@@ -86,27 +89,35 @@ public class publicFun
public static string chagenDate(DateTime? date)//因為欄位值是nullable, 所以把null的處理拉進函數做 public static string chagenDate(DateTime? date)//因為欄位值是nullable, 所以把null的處理拉進函數做
{ //可改公用 { //可改公用
//農曆年 //農曆年
ChineseLunisolarCalendar chineseDate = new ChineseLunisolarCalendar(); if (date == null) return null;
DateTime d = date.Value;
// 使用 tyme4net 方法
try try
{ {
if (date != null) var solarDay = SolarDay.FromYmd(d.Year, d.Month, d.Day);
var lunarDay = solarDay.GetLunarDay();
int minYear = lunarDay.Year - 1911;
return $"民{minYear}年/{lunarDay.ToString().Substring(2)}";
}
catch (Exception ex)
{ {
DateTime d = date ?? DateTime.Now; // 如果 tyme4net 完全失敗,回退到原本的方法
try
{
ChineseLunisolarCalendar chineseDate = new ChineseLunisolarCalendar();
int yy = chineseDate.GetYear(d) - 1911; int yy = chineseDate.GetYear(d) - 1911;
int mm = chineseDate.GetMonth(d); int mm = chineseDate.GetMonth(d);
int dd = chineseDate.GetDayOfMonth(d); int dd = chineseDate.GetDayOfMonth(d);
string dstr = $"民{yy}年{mm:00}月{dd:00}日"; return $"民{yy}年{mm:00}月{dd:00}日";
return dstr;
}
} }
catch catch
{ //try catch可能會很慢, 已知條件先判斷 {
//return null; return $"農曆轉換錯誤: {ex.Message}";
}
} }
return null;
//民國年
//System.Globalization.TaiwanCalendar tc = new System.Globalization.TaiwanCalendar();
// tc.GetYear(d), tc.GetMonth(d), tc.GetDayOfMonth(d)
} }
#region for api #region for api

BIN
web/Bin/tyme.dll Normal file

Binary file not shown.

View File

@@ -27,8 +27,6 @@
//GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear(); //GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
//註冊自訂路由 //註冊自訂路由
RouteConfig.RegisterRoutes(RouteTable.Routes); RouteConfig.RegisterRoutes(RouteTable.Routes);
InitializeFNumberSerial();//啟動項目的時候查詢出信眾編號的最大值放在記憶體中
//bundle js、css //bundle js、css
//BundleConfig.RegisterBundles(BundleTable.Bundles); //BundleConfig.RegisterBundles(BundleTable.Bundles);
@@ -63,38 +61,4 @@
System.Web.HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required); System.Web.HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required);
} }
private void InitializeFNumberSerial()
{
try
{
using (var _db = new Model.ezEntities())
{
var maxFNumber = _db.followers
.Where(m =>
////m.IsDel == false && ////不確定是否新增欄位? 先註解
m.f_number.Length == 14 &&
(m.f_number.StartsWith("M") || m.f_number.StartsWith("F")))
.OrderByDescending(m => m.reg_time)
.Select(m => m.f_number)
.FirstOrDefault();
int nextSerial = 0;
if (!string.IsNullOrEmpty(maxFNumber))
{
try
{
var serialPart = maxFNumber.Substring(9, 5);
nextSerial = int.Parse(serialPart);
}
catch { }
}
Application["FNumberSerial"] = nextSerial;
}
}
catch (Exception ex)
{
Application["FNumberSerial"] = 0;
}
}
</script> </script>

View File

@@ -45,7 +45,6 @@
{ text: '身分別', value: 'identity_type_desc' }, { text: '身分別', value: 'identity_type_desc' },
{ text: '性別', value: 'sex' }, { text: '性別', value: 'sex' },
{ text: '生日', value: 'birthday' }, { text: '生日', value: 'birthday' },
{ text: '生肖/干支', value: 'sign', sortable: false },
{ text: '報名記錄', value: 'order_record' }, { text: '報名記錄', value: 'order_record' },
{ text: '', value: 'slot', sortable: false }, { text: '', value: 'slot', sortable: false },
{ text: '', value: 'slot_btn', sortable: false, align: 'end' }, { text: '', value: 'slot_btn', sortable: false, align: 'end' },
@@ -414,11 +413,15 @@
class="elevation-1"> class="elevation-1">
<template #item.birthday="{ item }" > <template #item.birthday="{ item }" >
<div><span class="badge bg-secondary">西元</span> {{ item.birthday|timeString('YYYY/MM/DD') }} </div> <div v-if="item.birthday">
<div><span class="badge bg-secondary">農曆</span> {{ item.birthday2 }} </div> <span class="badge bg-secondary">西元</span> {{ item.birthday|timeString('YYYY/MM/DD') }}
</template> </div>
<template #item.sign="{ item }" > <div v-if="item.birthday2">
{{ item.sign }}/{{ item.sexagenary }} <span class="badge bg-secondary">農曆</span> {{ item.birthday2 }} ({{ item.sign }})
</div>
<div v-if="!item.birthday && !item.birthday2">
<span class="badge bg-light text-muted">未填寫</span>
</div>
</template> </template>
<template #item.slot_btn="{ item }"> <template #item.slot_btn="{ item }">
<a :href="'reg.aspx?num='+item.num" class="btn btn-outline-secondary btn-sm"><i class="mdi mdi-pencil-box-outline"></i>修改</a> <a :href="'reg.aspx?num='+item.num" class="btn btn-outline-secondary btn-sm"><i class="mdi mdi-pencil-box-outline"></i>修改</a>

View File

@@ -528,6 +528,13 @@
// //this.calculateLunarBirthday(); // //this.calculateLunarBirthday();
// } // }
//} //}
// 提示訊息
snackbar: {
show: false,
message: '',
color: 'error'
}
}, },
methods: { methods: {
search_show(curr) { search_show(curr) {
@@ -1046,6 +1053,15 @@
}, },
fam_save(item) { fam_save(item) {
console.log("fam_save 1:", this.family.edItem); console.log("fam_save 1:", this.family.edItem);
// 驗證必填欄位 - 只有姓名必填
if (!this.family.edItem.fam_name || this.family.edItem.fam_name.trim() === '') {
this.snackbar.message = '請填寫姓名';
this.snackbar.color = 'error';
this.snackbar.show = true;
return;
}
if (!this.family.is_tw) { if (!this.family.is_tw) {
this.family.edItem.city = ''; this.family.edItem.city = '';
this.family.edItem.area = ''; this.family.edItem.area = '';
@@ -1956,7 +1972,7 @@
<v-form ref="familyForm"> <v-form ref="familyForm">
<v-text-field <v-text-field
v-model="family.edItem.fam_name" v-model="family.edItem.fam_name"
label="姓名" label="姓名 * "
required required
></v-text-field> ></v-text-field>
@@ -2124,9 +2140,10 @@
</v-dialog> </v-dialog>
<v-snackbar <v-snackbar
v-model="snackbar.show" v-model="snackbar.show"
timeout="2000" :color="snackbar.color"
timeout="3000"
> >
{{ snackbar.text }} {{ snackbar.message }}
<template v-slot:action="{ attrs }"> <template v-slot:action="{ attrs }">
<v-btn <v-btn
text text

View File

@@ -105,7 +105,6 @@ public partial class admin_follower_reg : MyWeb.config
{ {
Literal1.Text = publicFun.chagenDate(prod.birthday.Value); Literal1.Text = publicFun.chagenDate(prod.birthday.Value);
Literal2.Text = Model.follower.chagenSign(prod.birthday.Value); Literal2.Text = Model.follower.chagenSign(prod.birthday.Value);
} }
if (prod.leader.HasValue) if (prod.leader.HasValue)
{ {
@@ -207,25 +206,8 @@ public partial class admin_follower_reg : MyWeb.config
} }
} }
} }
// 使用新的 generate_f_number 方法,已內建重號檢查和重試機制
followers.f_number = follower.generate_f_number(sex.SelectedValue); followers.f_number = follower.generate_f_number(sex.SelectedValue);
if (chk_pro_num(followers.f_number))
{
}
else
{
followers.f_number = follower.generate_f_number(sex.SelectedValue);
if (chk_pro_num(followers.f_number))
{
}
else
{
L_msg.Type = alert_type.danger;
L_msg.Text = "信眾編號重複";
return;
}
}
followers.identity_type = Val(identity_type.SelectedValue); followers.identity_type = Val(identity_type.SelectedValue);
if(!isStrNull(leader.Value)) followers.leader = Val(leader.Value); if(!isStrNull(leader.Value)) followers.leader = Val(leader.Value);
if (!isStrNull(country.Value)) followers.country = country.Value; if (!isStrNull(country.Value)) followers.country = country.Value;

View File

@@ -378,7 +378,7 @@
start_date: new Date().format("yyyy-MM-dd"), start_date: new Date().format("yyyy-MM-dd"),
extend_date: '', extend_date: '',
price: 0, price: 0,
qty: 0, qty: 1,
writeBedQty: 0, writeBedQty: 0,
notBedQty: 0, notBedQty: 0,
category: 0, category: 0,