35 Commits

Author SHA1 Message Date
minom a1751e4b99 匯款沖帳功能調整 2026-05-15 17:04:49 +08:00
minom 07e29c32aa 調整匯款沖帳 2026-05-11 15:59:23 +08:00
minom 3c5617b403 merge dapper and 0.1 into dapper 2026-04-28 17:09:04 +08:00
minomdu 50c2203ebf Merge remote-tracking branch 'origin/0.1' into dapper
# Conflicts:
#	web/App_Code/Model/Model.Designer.cs
#	web/App_Code/Model/Model.cs
#	web/App_Code/Model/Model.edmx
#	web/web.config
2026-04-28 16:26:19 +08:00
EnChia 7644df57d0 1. 優化報名頁面:彈出查詢頁面、顯示剛新增資料
2. 新增報名頁面加上取消鍵
3. 優化登入頁面:按下 enter 自動換格/送出
4. 修復新增報名頁面中,不同 search_dialog 中的 page 參數相互連動之異常
5. 修改報名頁面列印格式
6. 修復報名頁面匯出功能
7. 優化報到功能
8. 報名頁面中,無查詢資料時不可點選匯出/列印按鈕
9. 匯出/列印報名管理報表時,若無資料則顯示提示
10. 修復列印管理報表後父視窗 UI 不能點擊的問題
11. 新增報名管理表單匯出 excel 功能
12. 於新增信眾、新增活動頁面加上取消鍵
13. 優化報名管理匯出功能:若篩選條件包含特定活動,自動於「匯出條件」欄位標註活動名稱
14. 優化報名查詢匯出功能:匯出之文件中加上「匯出條件」欄位
15. 修復信眾資料頁面中,使用「生日」作為篩選基準時,後續執行「列印查詢資料」與「匯出查詢資料」會報錯
16. 修復「列印信眾查詢」功能中,電話搜尋欄位未正確帶入查詢條件之異常
17. 解決中文輸入法輸入電話號碼的跳字問題
18. 新增品項管理介面排序功能
2026-04-21 09:03:57 +08:00
minom 3273072fb3 排版設定 2026-04-16 17:51:02 +08:00
minom d9e651fe72 左右正名可選可輸入 2026-04-15 17:46:35 +08:00
minom 08b339e0cd 牌位報名與列印 2026-04-14 15:45:42 +08:00
minom a81967ddbd 新增親友功能 2026-04-13 17:44:13 +08:00
minom 1afb90f3ba 新增親友 2026-04-12 20:55:09 +08:00
minom 21a3ec6198 still 牌位版面調整 2026-04-10 17:24:46 +08:00
minom c5fc2469d7 1.報名牌位 2.牌位列印 2026-04-09 17:42:29 +08:00
EnChia aa5941a324 1. 加上返回鍵
2. 修改報名記錄中的活動開始結束時間
3. 修正列印問題
4. 信眾資料及報名管理起始不會出現資料
5. 信眾不得重複報名相同活動
6. 信眾資料的 cache(含結果與搜尋條件)
7. 修復信眾、活動、品項刪除功能
8. 增加自訂是否自動編號
9. 優化信眾資料頁面(彈出查詢頁面、顯示剛新增資料)
10. 新增管理表單匯出 excel 功能
11. 無查詢資料時不可點選匯出/列印按鈕
12. 匯出/列印管理報表時,若無資料則顯示提示
13. 新增信眾資料時,加入日期預設為今日
2026-04-09 17:37:00 +08:00
minom 8fe243356e 牌位設定 2026-04-08 17:54:28 +08:00
minom 83a7c67439 增加一個新的報名牌位編輯功能 2026-04-07 18:04:08 +08:00
minom 36174834a8 牌位排版 2026-04-06 19:06:22 +08:00
minom f087e4aa61 底圖 2026-04-02 18:22:46 +08:00
minom 7998312785 排版 2026-04-02 18:22:18 +08:00
minom 37d0b928ec 牌位設定列印 2026-04-01 18:03:42 +08:00
minom 5f8da12363 陽上 2026-03-31 18:03:45 +08:00
minom f16b3e3678 排版 2026-03-30 18:07:41 +08:00
minom ad1c99c3e9 牌位列印 2026-03-27 19:24:04 +08:00
minom 7722cc16ff print 2026-03-26 18:08:20 +08:00
minom 35ca33315d go 2026-03-25 18:04:13 +08:00
minom 8154473d1a 要改列印的功能 2026-03-24 18:02:44 +08:00
minom c235a138ee .... 2026-03-20 18:14:27 +08:00
minom 1b79aa9d14 報名 2026-03-19 17:44:27 +08:00
minom 095b310109 排版功能調整 2026-03-13 17:59:14 +08:00
minom f92fa65133 go 2026-03-12 17:44:08 +08:00
minom d81b99fd7d 1 2026-03-12 11:22:28 +08:00
minom f900649724 .. 2026-03-11 17:38:27 +08:00
minom 0bb9da198b .. 2026-03-11 17:37:27 +08:00
minom 5baac4fdb7 預覽 2026-03-11 15:37:05 +08:00
minom b66976b7c4 增加紙張尺寸設定 2026-03-10 17:59:57 +08:00
minom bfd07ebe90 .. 2026-03-09 18:09:32 +08:00
64 changed files with 12824 additions and 885 deletions
+169 -17
View File
@@ -24,6 +24,72 @@ public class StyleDataAccess
//
}
public object[] AddTabletPaper(TabletPaperSize tps)
{
try
{
using (var context = new ezEntities())
{
StringBuilder sb = new StringBuilder();
var sp = new List<SqlParameter>();
sb.Append("insert into TabletPaperSize (PaperID,PaperName,Width,Height,CUser,CDate,CTime,UUser,UDate,UTime ) ");
sb.Append("values (@PaperID,@PaperName,@Width,@Height,@CUser,@CDate,@CTime,@UUser,@UDate,@UTime )");
sp.Add(new SqlParameter("@PaperID",tps.PaperID));
sp.Add(new SqlParameter("@PaperName", tps.PaperName));
sp.Add(new SqlParameter("@Width", tps.Width));
sp.Add(new SqlParameter("@Height", tps.Height));
sp.Add(new SqlParameter("@CUser", tps.CUser));
sp.Add(new SqlParameter("@CDate", tps.CDate));
sp.Add(new SqlParameter("@CTime", tps.CTime));
sp.Add(new SqlParameter("@UUser", tps.UUser));
sp.Add(new SqlParameter("@UDate", tps.UDate));
sp.Add(new SqlParameter("@UTime", tps.UTime));
context.Database.ExecuteSqlCommand(sb.ToString(),sp.ToArray());
}
}
catch (Exception ex)
{
log.writeErrorPath("AddTabletPaper:" + ex.Message + ex.StackTrace);
obj[0] = "N";
obj[1] = ex.Message;
}
return obj;
}
public object[] GetTabletPaper(string paperID, string name)
{
try
{
using (var context = new ezEntities())
{
StringBuilder sb = new StringBuilder();
var sp = new List<SqlParameter>();
sb.Append("select * from TabletPaperSize where 1=1 ");
if (!string.IsNullOrEmpty(paperID))
{
sb.Append("and PaperID=@PaperID ");
sp.Add(new SqlParameter("@PaperID", paperID));
}
if (!string.IsNullOrEmpty(name))
{
sb.Append("and Name=@Name ");
sp.Add(new SqlParameter("@Name", name));
}
var data = context.Database.SqlQuery<TabletPaperSize>(sb.ToString(), sp.ToArray()).ToList();
obj[2] = data;
}
}
catch (Exception ex)
{
log.writeErrorPath("GetTabletElement:" + ex.Message + ex.StackTrace);
obj[0] = "N";
obj[1] = ex.Message;
}
return obj;
}
public object[] GetTabletElement(string elementID ,string name)
{
try
@@ -31,20 +97,20 @@ public class StyleDataAccess
using (var context = new ezEntities())
{
StringBuilder sb = new StringBuilder();
SqlParameter[] sp = new SqlParameter[] { };
var sp = new List<SqlParameter>();
sb.Append("select * from TabletElement where 1=1 ");
if (!string.IsNullOrEmpty(elementID))
{
sb.Append("and ElementID=@ElementID ");
sp.Append(new SqlParameter("ElementID", elementID));
sp.Add(new SqlParameter("@ElementID", elementID));
}
if (!string.IsNullOrEmpty(name))
{
sb.Append("and Name=@Name ");
sp.Append(new SqlParameter("Name", name));
sp.Add(new SqlParameter("@Name", name));
}
var data = context.Database.SqlQuery<TabletElement>(sb.ToString(), sp).ToList();
var data = context.Database.SqlQuery<TabletElement>(sb.ToString(), sp.ToArray()).ToList();
obj[2] = data;
}
}
@@ -65,20 +131,20 @@ public class StyleDataAccess
using (var context = new ezEntities())
{
StringBuilder sb = new StringBuilder();
SqlParameter[] sp = new SqlParameter[] { };
var sp = new List<SqlParameter>();
sb.Append("select * from TabletStyleDetail where 1=1 ");
if (!string.IsNullOrEmpty(styleID))
{
sb.Append("and StyleID=@StyleID ");
sp.Append(new SqlParameter("StyleID", styleID));
sp.Add(new SqlParameter("@StyleID", styleID));
}
if (!string.IsNullOrEmpty(elementID))
{
sb.Append("and ElementID=@ElementID ");
sp.Append(new SqlParameter("ElementID", elementID));
sp.Add(new SqlParameter("@ElementID", elementID));
}
var data = context.Database.SqlQuery<TabletStyleDetail>(sb.ToString(), sp).ToList();
var data = context.Database.SqlQuery<TabletStyleDetail>(sb.ToString(), sp.ToArray()).ToList();
obj[2] = data;
}
}
@@ -98,20 +164,20 @@ public class StyleDataAccess
using (var context = new ezEntities())
{
StringBuilder sb = new StringBuilder();
SqlParameter[] sp = new SqlParameter[] { };
var sp = new List<SqlParameter>();
sb.Append("select * from TabletStyle where 1=1 ");
if (!string.IsNullOrEmpty(id))
{
sb.Append("and StyleID=@StyleID ");
sp.Append(new SqlParameter( "StyleID",id));
sp.Add(new SqlParameter( "@StyleID",id));
}
if (!string.IsNullOrEmpty(name))
{
sb.Append("and Name=@Name ");
sp.Append(new SqlParameter("Name", name));
sp.Add(new SqlParameter("@Name", name));
}
var data= context.Database.SqlQuery<TabletStyle>(sb.ToString(), sp).ToList();
var data= context.Database.SqlQuery<TabletStyle>(sb.ToString(), sp.ToArray()).ToList();
obj[2]= data;
}
}
@@ -141,6 +207,7 @@ public class StyleDataAccess
new SqlParameter("@PrintMode",ts.PrintMode),
new SqlParameter("@Orientation",ts.Orientation),
new SqlParameter("@PrintPageCount",ts.PrintPageCount),
new SqlParameter("@RosterLimit",ts.RosterLimit),
new SqlParameter("@CUser",""),
new SqlParameter("@CDate",""),
new SqlParameter("@CTime",""),
@@ -149,17 +216,17 @@ public class StyleDataAccess
new SqlParameter("@UTime",""),
};
sb.Append("insert into TabletStyle (StyleID,Name,Descr,PaperSize,BackendImg,PrintSize,PrintMode,Orientation,PrintPageCount");
sb.Append("insert into TabletStyle (StyleID,Name,Descr,PaperSize,BackendImg,PrintSize,PrintMode,Orientation,PrintPageCount,RosterLimit");
sb.Append(",CUser,CDate,CTime,UUser,UDate,UTime ) ");
sb.Append("values(@StyleID,@Name,@Descr,@PaperSize,@BackendImg,@PrintSize,@PrintMode,@Orientation,@PrintPageCount");
sb.Append("values(@StyleID,@Name,@Descr,@PaperSize,@BackendImg,@PrintSize,@PrintMode,@Orientation,@PrintPageCount,@RosterLimit");
sb.Append(",@CUser,@CDate,@CTime,@UUser,@UDate,@UTime ) ");
context.Database.ExecuteSqlCommand(sb.ToString(), sp);
sb.Clear();
sb.Append("insert into TabletStyleDetail(StyleID,Name,Descr,ElementID,StartX,StartY,FontSize,BreakLen,FontFamily,TwoOffset,");
sb.Append("ThreeOffset,FourOffSet,IsActive,Width,CUser,CDate,CTime,UUser,UDate,UTime) ");
sb.Append("ThreeOffset,FourOffSet,IsActive,Width,Height,TextWidth,TextHeight,CUser,CDate,CTime,UUser,UDate,UTime) ");
sb.Append("values (@StyleID,@Name,@Descr,@ElementID,@StartX,@StartY,@FontSize,@BreakLen,@FontFamily,@TwoOffset,");
sb.Append("@ThreeOffset,@FourOffSet,@IsActive,@Width,@CUser,@CDate,@CTime,@UUser,@UDate,@UTime) ");
sb.Append("@ThreeOffset,@FourOffSet,@IsActive,@Width,@Height,@TextWidth,@TextHeight,@CUser,@CDate,@CTime,@UUser,@UDate,@UTime) ");
foreach (var item in list)
{
SqlParameter[] sp1 = new SqlParameter[] {
@@ -177,6 +244,9 @@ public class StyleDataAccess
new SqlParameter("@FourOffset",item.FourOffset),
new SqlParameter("@IsActive",item.IsActive),
new SqlParameter("@Width",item.Width),
new SqlParameter("@Height",item.Height),
new SqlParameter("@TextWidth",item.TextWidth),
new SqlParameter("@TextHeight",item.TextHeight),
new SqlParameter("@CUser",""),
new SqlParameter("@CDate",""),
new SqlParameter("@CTime",""),
@@ -184,7 +254,7 @@ public class StyleDataAccess
new SqlParameter("@UDate",""),
new SqlParameter("@UTime",""),
};
context.Database.ExecuteSqlCommand(sb.ToString(), sp1);
context.Database.ExecuteSqlCommand(sb.ToString(), sp1.ToArray());
}
}
}
@@ -196,4 +266,86 @@ public class StyleDataAccess
}
return obj;
}
public object[] UpdateStyle(TabletStyle ts, List<TabletStyleDetail> list)
{
try
{
using (var context = new ezEntities())
{
StringBuilder sb = new StringBuilder();
SqlParameter[] sp = new SqlParameter[] {
new SqlParameter("@StyleID",ts.StyleID),
new SqlParameter("@Name",ts.Name),
new SqlParameter("@Descr",ts.Descr),
new SqlParameter("@PaperSize",ts.PaperSize),
new SqlParameter("@BackendImg",ts.BackendImg),
new SqlParameter("@PrintSize",ts.PrintSize),
new SqlParameter("@PrintMode",ts.PrintMode),
new SqlParameter("@Orientation",ts.Orientation),
new SqlParameter("@PrintPageCount",ts.PrintPageCount),
new SqlParameter("@RosterLimit",ts.RosterLimit),
new SqlParameter("@CUser",""),
new SqlParameter("@CDate",""),
new SqlParameter("@CTime",""),
new SqlParameter("@UUser",""),
new SqlParameter("@UDate",""),
new SqlParameter("@UTime",""),
};
sb.Append("update TabletStyle set Descr=@Descr,PaperSize=@PaperSize,BackendImg=@BackendImg,PrintSize=@PrintSize,");
sb.Append("PrintMode=@PrintMode,Orientation=@Orientation,PrintPageCount=@PrintPageCount,RosterLimit=@RosterLimit,");
sb.Append("CUser=@CUser,CDate=@CDate,CTime=@CTime,UUser=@UUSer,UDate=@UDate,UTime=@UTime ");
sb.Append("where StyleID=@StyleID ");
context.Database.ExecuteSqlCommand(sb.ToString(), sp.ToArray());
sb.Clear();
sb.Append("update TabletStyleDetail set Descr=@Descr,StartX=@StartX,StartY=@StartY,FontSize=@FontSize,BreakLen=@BreakLen,");
sb.Append("FontFamily=@FontFamily,TwoOffset=@TwoOffset,ThreeOffset=@ThreeOffset,FourOffset=@FourOffset,IsActive=@IsActive,");
sb.Append("Width=@Width,Height=@Height,TextWidth=@TextWidth,TextHeight=@TextHeight,UUser=@UUser,UDate=@UDate,UTime=@UTime ");
sb.Append("where StyleID=@StyleID and ElementID=@ElementID ");
//sb.Append("insert into TabletStyleDetail(StyleID,Name,Descr,ElementID,StartX,StartY,FontSize,BreakLen,FontFamily,TwoOffset,");
//sb.Append("ThreeOffset,FourOffSet,IsActive,Width,Height,TextWidth,TextHeight,CUser,CDate,CTime,UUser,UDate,UTime) ");
//sb.Append("values (@StyleID,@Name,@Descr,@ElementID,@StartX,@StartY,@FontSize,@BreakLen,@FontFamily,@TwoOffset,");
//sb.Append("@ThreeOffset,@FourOffSet,@IsActive,@Width,@Height,@TextWidth,@TextHeight,@CUser,@CDate,@CTime,@UUser,@UDate,@UTime) ");
foreach (var item in list)
{
SqlParameter[] sp1 = new SqlParameter[] {
new SqlParameter("@StyleID",item.StyleID),
new SqlParameter("@Name",item.Name),
new SqlParameter("@Descr",item.Descr),
new SqlParameter("@ElementID",item.ElementID),
new SqlParameter("@StartX",item.StartX),
new SqlParameter("@StartY",item.StartY),
new SqlParameter("@FontSize",item.FontSize),
new SqlParameter("@BreakLen",item.BreakLen),
new SqlParameter("@FontFamily",item.FontFamily),
new SqlParameter("@TwoOffset",item.TwoOffset),
new SqlParameter("@ThreeOffset",item.ThreeOffset),
new SqlParameter("@FourOffset",item.FourOffset),
new SqlParameter("@IsActive",item.IsActive),
new SqlParameter("@Width",item.Width),
new SqlParameter("@Height",item.Height),
new SqlParameter("@TextWidth",item.TextWidth),
new SqlParameter("@TextHeight",item.TextHeight),
new SqlParameter("@CUser",""),
new SqlParameter("@CDate",""),
new SqlParameter("@CTime",""),
new SqlParameter("@UUser",""),
new SqlParameter("@UDate",""),
new SqlParameter("@UTime",""),
};
context.Database.ExecuteSqlCommand(sb.ToString(), sp1.ToArray());
}
}
}
catch (Exception ex)
{
log.writeErrorPath("UpdateStyle:" + ex.Message + ex.StackTrace);
obj[0] = "N";
obj[1] = ex.Message;
}
return obj;
}
}
+19
View File
@@ -24,6 +24,7 @@ public class TabletStyle
public string PrintMode { get; set; }
public string Orientation { get; set; }
public string PrintPageCount { get; set; }
public string RosterLimit { get; set; }
public string CUser { get; set; }
public string CDate { get; set; }
public string CTime { get; set; }
@@ -48,6 +49,9 @@ public class TabletStyleDetail
public string FourOffset { get; set; }
public string IsActive { get; set; }
public string Width { get; set; }
public string Height { get; set; }
public string TextWidth { get; set; }
public string TextHeight { get; set; }
public string BreakLen { get; set; }
public string CUser { get; set; }
public string CDate { get; set; }
@@ -71,3 +75,18 @@ public class TabletElement
public string UDate { get; set; }
public string UTime { get; set; }
}
public class TabletPaperSize
{
public TabletPaperSize() { }
public string PaperID { get; set; }
public string PaperName { get; set; }
public string Width { get; set; }
public string Height { get; set; }
public string CUser { get; set; }
public string CDate { get; set; }
public string CTime { get; set; }
public string UUser { get; set; }
public string UDate { get; set; }
public string UTime { get; set; }
}
+1 -1
View File
@@ -1,4 +1,4 @@
// 已啟用模型 'C:\project\17168ERP\web\App_Code\Model\Model.edmx' 的 T4 程式碼產生。
// 已啟用模型 'D:\17168ERP\web\App_Code\Model\Model.edmx' 的 T4 程式碼產生。
// 若要啟用舊版程式碼產生,請將 [程式碼產生策略] 設計工具屬性的值
//變更為 [舊版 ObjectContext]。當模型在設計工具中開啟時,這個屬性便可
//以在 [屬性] 視窗中使用。
+5
View File
@@ -184,6 +184,10 @@ namespace Model
public string partno { get; set; }
public string print_init { get; set; }
public string is_reconcile { get; set; }
public string pageSize { get; set; }
public string printSize { get; set; }
public string defaultStyle { get; set; }
public Nullable<int> sort_order { get; set; }
public virtual actItem_kind actItem_kind { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
@@ -1389,6 +1393,7 @@ namespace Model
public Nullable<int> parent_num { get; set; }
public string print_id { get; set; }
public Nullable<System.DateTime> UpdateTime { get; set; }
public string style { get; set; }
public virtual actItem actItem { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
+38 -29
View File
@@ -91,6 +91,10 @@
<Property Name="customize_data" Type="nvarchar(max)" />
<Property Name="reg_time" Type="datetime" />
<Property Name="is_reconcile" Type="nvarchar" MaxLength="1" />
<Property Name="pageSize" Type="varchar" MaxLength="50" />
<Property Name="printSize" Type="varchar" MaxLength="50" />
<Property Name="defaultStyle" Type="varchar" MaxLength="50" />
<Property Name="sort_order" Type="int" />
</EntityType>
<EntityType Name="actItem_files">
<Key>
@@ -480,7 +484,7 @@
<Property Name="country" Type="nvarchar" MaxLength="5" />
<Property Name="appellation_id" Type="int" />
<Property Name="follower_hash" Type="nvarchar" MaxLength="100" />
<Property Name="search_keywords" Type="nvarchar(max)" />
<Property Name="search_keywords" Type="varchar(max)" />
</EntityType>
<EntityType Name="followers_tablet">
<Key>
@@ -604,8 +608,8 @@
</Key>
<Property Name="num" Type="int" StoreGeneratedPattern="Identity" Nullable="false" />
<Property Name="kind" Type="nvarchar" MaxLength="100" />
<Property Name="starttime" Type="time" Precision="0" />
<Property Name="offtime" Type="time" Precision="0" />
<Property Name="starttime" Type="time" Precision="7" />
<Property Name="offtime" Type="time" Precision="7" />
<Property Name="resttime" Type="int" />
<Property Name="root" Type="int" />
<Property Name="range" Type="int" />
@@ -724,6 +728,7 @@
<Property Name="customize_data" Type="nvarchar(max)" />
<Property Name="printed_files" Type="nvarchar(max)" />
<Property Name="UpdateTime" Type="datetime2" Precision="7" />
<Property Name="style" Type="varchar" MaxLength="50" />
</EntityType>
<EntityType Name="pro_order_record">
<Key>
@@ -980,7 +985,7 @@
<Property Name="balance_act_item" Type="int" />
<Property Name="balance_pro_order_detail" Type="int" />
</EntityType>
<Association Name="FK__Ancestral__Regis__4DF47A4E">
<Association Name="FK__Ancestral__Regis__1A9EF37A">
<End Role="AncestralTabletRegistrant" Type="Self.AncestralTabletRegistrant" Multiplicity="1" />
<End Role="AncestralTabletPositionRecord" Type="Self.AncestralTabletPositionRecord" Multiplicity="*" />
<ReferentialConstraint>
@@ -1079,7 +1084,9 @@
</ReferentialConstraint>
</Association>
<Association Name="FK_act_bom_actItem1">
<End Role="actItem" Type="Self.actItem" Multiplicity="0..1" />
<End Role="actItem" Type="Self.actItem" Multiplicity="0..1">
<OnDelete Action="Cascade" />
</End>
<End Role="act_bom" Type="Self.act_bom" Multiplicity="*" />
<ReferentialConstraint>
<Principal Role="actItem">
@@ -1128,18 +1135,6 @@
</Dependent>
</ReferentialConstraint>
</Association>
<Association Name="FK_activity_activity_kind">
<End Role="activity_kind" Type="Self.activity_kind" Multiplicity="0..1" />
<End Role="activity" Type="Self.activity" Multiplicity="*" />
<ReferentialConstraint>
<Principal Role="activity_kind">
<PropertyRef Name="num" />
</Principal>
<Dependent Role="activity">
<PropertyRef Name="kind" />
</Dependent>
</ReferentialConstraint>
</Association>
<Association Name="FK_activity_check_activity">
<End Role="activity" Type="Self.activity" Multiplicity="0..1">
<OnDelete Action="Cascade" />
@@ -1211,7 +1206,9 @@
</ReferentialConstraint>
</Association>
<Association Name="FK_activity_relating_activity">
<End Role="activity" Type="Self.activity" Multiplicity="1" />
<End Role="activity" Type="Self.activity" Multiplicity="1">
<OnDelete Action="Cascade" />
</End>
<End Role="activity_relating" Type="Self.activity_relating" Multiplicity="*" />
<ReferentialConstraint>
<Principal Role="activity">
@@ -1637,7 +1634,9 @@
</ReferentialConstraint>
</Association>
<Association Name="FK_pro_order_activity">
<End Role="activity" Type="Self.activity" Multiplicity="0..1" />
<End Role="activity" Type="Self.activity" Multiplicity="0..1">
<OnDelete Action="Cascade" />
</End>
<End Role="pro_order" Type="Self.pro_order" Multiplicity="*" />
<ReferentialConstraint>
<Principal Role="activity">
@@ -1687,7 +1686,9 @@
</ReferentialConstraint>
</Association>
<Association Name="FK_pro_order_detail_pro_order">
<End Role="pro_order" Type="Self.pro_order" Multiplicity="1" />
<End Role="pro_order" Type="Self.pro_order" Multiplicity="1">
<OnDelete Action="Cascade" />
</End>
<End Role="pro_order_detail" Type="Self.pro_order_detail" Multiplicity="*" />
<ReferentialConstraint>
<Principal Role="pro_order">
@@ -1699,7 +1700,9 @@
</ReferentialConstraint>
</Association>
<Association Name="FK_pro_order_followers">
<End Role="followers" Type="Self.followers" Multiplicity="0..1" />
<End Role="followers" Type="Self.followers" Multiplicity="0..1">
<OnDelete Action="Cascade" />
</End>
<End Role="pro_order" Type="Self.pro_order" Multiplicity="*" />
<ReferentialConstraint>
<Principal Role="followers">
@@ -2157,7 +2160,7 @@
<EntitySet Name="supplier" EntityType="Self.supplier" Schema="dbo" store:Type="Tables" />
<EntitySet Name="supplier_kind" EntityType="Self.supplier_kind" Schema="dbo" store:Type="Tables" />
<EntitySet Name="transfer_register" EntityType="Self.transfer_register" Schema="dbo" store:Type="Tables" />
<AssociationSet Name="FK__Ancestral__Regis__4DF47A4E" Association="Self.FK__Ancestral__Regis__4DF47A4E">
<AssociationSet Name="FK__Ancestral__Regis__1A9EF37A" Association="Self.FK__Ancestral__Regis__1A9EF37A">
<End Role="AncestralTabletRegistrant" EntitySet="AncestralTabletRegistrant" />
<End Role="AncestralTabletPositionRecord" EntitySet="AncestralTabletPositionRecord" />
</AssociationSet>
@@ -2205,10 +2208,6 @@
<End Role="activity_category_kind" EntitySet="activity_category_kind" />
<End Role="activity" EntitySet="activity" />
</AssociationSet>
<AssociationSet Name="FK_activity_activity_kind" Association="Self.FK_activity_activity_kind">
<End Role="activity_kind" EntitySet="activity_kind" />
<End Role="activity" EntitySet="activity" />
</AssociationSet>
<AssociationSet Name="FK_activity_check_activity" Association="Self.FK_activity_check_activity">
<End Role="activity" EntitySet="activity" />
<End Role="activity_check" EntitySet="activity_check" />
@@ -2613,6 +2612,10 @@
<Property Name="print_init" Type="String" MaxLength="100" FixedLength="false" Unicode="true" />
<NavigationProperty Name="transfer_register" Relationship="Model.FK_transfer_register_actItem" FromRole="actItem" ToRole="transfer_register" />
<Property Name="is_reconcile" Type="String" MaxLength="1" FixedLength="false" Unicode="true" />
<Property Name="pageSize" Type="String" MaxLength="50" FixedLength="false" Unicode="false" />
<Property Name="printSize" Type="String" MaxLength="50" FixedLength="false" Unicode="false" />
<Property Name="defaultStyle" Type="String" MaxLength="50" FixedLength="false" Unicode="false" />
<Property Name="sort_order" Type="Int32" ConcurrencyMode="None" />
</EntityType>
<EntityType Name="actItem_files">
<Key>
@@ -2972,7 +2975,7 @@
<NavigationProperty Name="transfer_register" Relationship="Model.FK_transfer_register_followers" FromRole="follower" ToRole="transfer_register" />
<NavigationProperty Name="transfer_register1" Relationship="Model.FK_transfer_register_followers_match" FromRole="follower" ToRole="transfer_register" />
<NavigationProperty Name="GuaDanOrder" Relationship="Model.FK_GuaDanOrder_Followers" FromRole="follower" ToRole="GuaDanOrder" />
<Property Name="search_keywords" Type="String" MaxLength="Max" FixedLength="false" Unicode="true" />
<Property Name="search_keywords" Type="String" MaxLength="Max" FixedLength="false" Unicode="false" />
<NavigationProperty Name="GuaDanOrderGuest" Relationship="Model.FK_GuaDanOrderGuest_FOLLOWERS" FromRole="follower" ToRole="GuaDanOrderGuest" />
</EntityType>
<EntityType Name="followers_tablet">
@@ -3062,8 +3065,8 @@
</Key>
<Property Name="num" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
<Property Name="kind" Type="String" MaxLength="100" FixedLength="false" Unicode="true" />
<Property Name="starttime" Type="Time" Precision="0" />
<Property Name="offtime" Type="Time" Precision="0" />
<Property Name="starttime" Type="Time" Precision="7" />
<Property Name="offtime" Type="Time" Precision="7" />
<Property Name="resttime" Type="Int32" />
<Property Name="root" Type="Int32" />
<Property Name="range" Type="Int32" />
@@ -3188,6 +3191,7 @@
<Property Name="UpdateTime" Type="DateTime" Precision="7" />
<NavigationProperty Name="accountings" Relationship="Model.FK_accounting_pro_order_detail" FromRole="pro_order_detail" ToRole="accounting" />
<NavigationProperty Name="transfer_register" Relationship="Model.FK_transfer_register_pro_order_detail" FromRole="pro_order_detail" ToRole="transfer_register" />
<Property Name="style" Type="String" Unicode="false" FixedLength="false" MaxLength="50" Nullable="true" />
</EntityType>
<EntityType Name="pro_order_record">
<Key>
@@ -5334,6 +5338,10 @@
<EntitySetMapping Name="actItems">
<EntityTypeMapping TypeName="Model.actItem">
<MappingFragment StoreEntitySet="actItem">
<ScalarProperty Name="sort_order" ColumnName="sort_order" />
<ScalarProperty Name="defaultStyle" ColumnName="defaultStyle" />
<ScalarProperty Name="printSize" ColumnName="printSize" />
<ScalarProperty Name="pageSize" ColumnName="pageSize" />
<ScalarProperty Name="is_reconcile" ColumnName="is_reconcile" />
<ScalarProperty Name="print_init" ColumnName="print_init" />
<ScalarProperty Name="partno" ColumnName="partno" />
@@ -5863,6 +5871,7 @@
<ScalarProperty Name="demo" ColumnName="demo" />
<ScalarProperty Name="customize_data" ColumnName="customize_data" />
<ScalarProperty Name="printed_files" ColumnName="printed_files" />
<ScalarProperty Name="style" ColumnName="style" />
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
+3 -3
View File
@@ -4,12 +4,12 @@
<edmx:Designer xmlns="http://schemas.microsoft.com/ado/2009/11/edmx">
<!-- Diagram content (shape and connector positions) -->
<edmx:Diagrams>
<Diagram DiagramId="b267a343dc0c4bf0ae194b775754b108" Name="Diagram1" ZoomLevel="78">
<Diagram DiagramId="b267a343dc0c4bf0ae194b775754b108" Name="Diagram1" ZoomLevel="116">
<EntityTypeShape EntityType="Model.accounting" Width="1.5" PointX="22.5" PointY="22.125" IsExpanded="true" />
<EntityTypeShape EntityType="Model.accounting_files" Width="1.5" PointX="15.75" PointY="27.75" IsExpanded="true" />
<EntityTypeShape EntityType="Model.accounting_kind" Width="1.5" PointX="11.25" PointY="27.625" IsExpanded="true" />
<EntityTypeShape EntityType="Model.accounting_kind2" Width="1.5" PointX="13.5" PointY="11.25" IsExpanded="true" />
<EntityTypeShape EntityType="Model.actItem" Width="1.5" PointX="9.25" PointY="7.875" IsExpanded="true" />
<EntityTypeShape EntityType="Model.actItem" Width="1.5" PointX="8.375" PointY="27.25" IsExpanded="true" />
<EntityTypeShape EntityType="Model.actItem_files" Width="1.5" PointX="16.5" PointY="5.875" IsExpanded="true" />
<EntityTypeShape EntityType="Model.actItem_kind" Width="1.5" PointX="6.125" PointY="7.875" IsExpanded="true" />
<EntityTypeShape EntityType="Model.activity" Width="1.5" PointX="3" PointY="8.875" IsExpanded="true" />
@@ -17,7 +17,7 @@
<EntityTypeShape EntityType="Model.activity_check" Width="1.5" PointX="5.25" PointY="18.5" IsExpanded="true" />
<EntityTypeShape EntityType="Model.activity_kind" Width="1.5" PointX="0.75" PointY="11.625" IsExpanded="true" />
<EntityTypeShape EntityType="Model.activity_kind_detail" Width="1.5" PointX="13.5" PointY="3.875" IsExpanded="true" />
<EntityTypeShape EntityType="Model.activity_relating" Width="1.5" PointX="10.5" PointY="9.875" IsExpanded="true" />
<EntityTypeShape EntityType="Model.activity_relating" Width="1.5" PointX="11.25" PointY="9.875" IsExpanded="true" />
<EntityTypeShape EntityType="Model.activity_spares" Width="1.5" PointX="13.5" PointY="7.75" IsExpanded="true" />
<EntityTypeShape EntityType="Model.admin" Width="1.5" PointX="6" PointY="1.375" IsExpanded="true" />
<EntityTypeShape EntityType="Model.admin_group" Width="1.5" PointX="3.75" PointY="3.625" IsExpanded="true" />
+15 -10
View File
@@ -103,17 +103,18 @@ public class FollowerController : ApiController
{
foreach (var item in prod)
{
foreach (var item2 in item.pro_order_detail1)
item2.from_id = null; //清空訂單明細的陽上報恩者from_id //f_num設定串聯刪除
//foreach (var item2 in item.pro_order_detail1)
// item2.from_id = null; //清空訂單明細的陽上報恩者from_id //f_num設定串聯刪除
foreach (var item2 in item.pro_order)
item2.introducer = null;
//foreach (var item2 in item.pro_order)
// item2.introducer = null;
item.leader = null;//清空leader
//item.leader = null;//清空leader
_db.followers.RemoveRange(prod);
}
_db.followers.RemoveRange(prod);
//_db.followers.RemoveRange(prod);
_db.SaveChanges();
Model.admin_log admin_log = new Model.admin_log();
@@ -150,8 +151,10 @@ public class FollowerController : ApiController
qry = qry.Where(o => o.u_name.Contains(q.u_name.Trim()));
if (q.birthday.HasValue)
qry = qry.Where(o => o.birthday >= q.birthday.Value);
if (q.birthday2.HasValue)
qry = qry.Where(o => o.birthday < Convert.ToDateTime(q.birthday2.Value).AddDays(1));
if (q.birthday2.HasValue) {
var tmpBirthday2 = Convert.ToDateTime(q.birthday2.Value).AddDays(1);
qry = qry.Where(o => o.birthday < tmpBirthday2);
}
if (!string.IsNullOrEmpty(q.address))
qry = qry.Where(o => o.address !=null && o.address.Contains(q.address.Trim()));
//if (q.num.HasValue && q.num.Value>0)
@@ -655,8 +658,10 @@ public class FollowerController : ApiController
list = orderrecord.Select(x => new
{
orderno = x.order_no,
startdate = x.reg_time,
endtime = x.up_time,
//startdate = x.reg_time,
//endtime = x.up_time,
startdate = x.activity.startDate_solar,
enddate = x.activity.endDate_solar,
pwcount = x.pro_order_detail.Where(a => a.actItem.act_bom.Where(b => b.item_num == a.actItem_num && b.package_num == null).Count() == 0).Count(),
amount = x.pro_order_detail.Select(o => (float?)o.price).Sum(),
activityname = x.activity.subject,
+69 -15
View File
@@ -1,14 +1,18 @@
using System;
using DocumentFormat.OpenXml.Drawing.Spreadsheet;
using Model;
using Newtonsoft.Json;
using Org.BouncyCastle.Crypto;
using PagedList;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using PagedList;
using Newtonsoft.Json;
using System.Collections;
using System.Web.Services;
using static TreeView;
using System.Data.Entity;
// api/activity
//[ezAuthorize(Roles = "admin")]//群組:*
@@ -126,6 +130,12 @@ public class activityController : ApiController
if (prod != null)
{
////prod.IsDel = true; ////不確定是否新增欄位? 先註解
// 先刪除子項目
var prod2 = _db.act_bom.Where(q => q.package_num == prod.num).ToList();
_db.act_bom.RemoveRange(prod2);
_db.actItems.Remove(prod);
_db.SaveChanges();
Model.admin_log admin_log = new Model.admin_log();
MyWeb.admin admin = new MyWeb.admin();//api裡不可以用MyWeb
@@ -190,12 +200,18 @@ public class activityController : ApiController
if (prod.Count() > 0)
{
//var prod2 = _db.actItem_files.AsEnumerable().Where(q => ids.Contains(Convert.ToInt32(q.actItem_num))).ToList();
var prod2 = _db.actItem_files.Where(q => ids.Contains(q.actItem_num)).ToList();
if (prod2.Count > 0)
{
_db.actItem_files.RemoveRange(prod2);
//_db.SaveChanges();
}
//var prod2 = _db.actItem_files.Where(q => ids.Contains(q.actItem_num)).ToList();
//if (prod2.Count > 0)
//{
// _db.actItem_files.RemoveRange(prod2);
// //_db.SaveChanges();
//}
// 先刪除子項目
var parentBoms = _db.act_bom.Where(q => q.item_num.HasValue && ids.Contains(q.item_num.Value)).ToList();
var parentIds = parentBoms.Select(x => x.num).ToList(); // 取得母件 id
var childBoms = _db.act_bom.Where(q => q.package_num.HasValue && parentIds.Contains(q.package_num.Value)).ToList();
_db.act_bom.RemoveRange(childBoms);
_db.actItems.RemoveRange(prod);
_db.SaveChanges();
@@ -282,6 +298,7 @@ public class activityController : ApiController
var count = qry.Count(); //pageSize = count;//一次取回??
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
var ret = new
{
list = qryList.Select(x => new
@@ -301,9 +318,10 @@ public class activityController : ApiController
startDate_lunar = x.startDate_lunar,
endDate_lunar = x.endDate_lunar,
dueDate = x.dueDate,
orderCounts= _db.pro_order.Where(y => y.activity_num == x.num).Count(),
}),
count = count
count = count,
};
@@ -312,6 +330,36 @@ public class activityController : ApiController
return Ok(ret);
}
public class SortOrderRequest
{
public List<int> ids { get; set; }
}
[HttpPost]
[Route("api/activity/SaveItemList")]
public IHttpActionResult UpdateSortOrder([FromBody] SortOrderRequest request)
{
if (request == null || request.ids == null) return BadRequest();
using (Model.ezEntities _db = new Model.ezEntities())
{
int totalCount = request.ids.Count;
for (int i = 0; i < totalCount; i++)
{
int id = request.ids[i];
var item = _db.actItems.FirstOrDefault(x => x.num == id);
if (item != null)
{
// 改成總數減去索引,這樣第一筆 (i=0) 會拿到最大的數字
item.sort_order = totalCount - i;
}
}
_db.SaveChanges();
}
return Ok();
}
[HttpPost]
[Route("api/activity/GetItemList")]
public IHttpActionResult GetItemList([FromBody] Model.ViewModel.actItem q, int page, int pageSize = 10,
@@ -416,8 +464,14 @@ public class activityController : ApiController
else
qry = qry.OrderBy(o => o.status);
}
else
else if (sortBy.Equals("num"))
{
qry = qry.OrderByDescending(o => o.num);
}
else
{
qry = qry.OrderByDescending(o => o.sort_order);
}
var tdesc = publicFun.enum_desc<Model.activity.category>();
var count = qry.Count(); //pageSize = count;//一次取回??
@@ -1301,7 +1355,7 @@ public class activityController : ApiController
[Route("api/activity/OrderCheckIn")]
public IHttpActionResult OrderCheckIn([FromBody] Model.activity_check item)
{
if (item.f_num.HasValue && item.activity_num.HasValue && item.qty.HasValue && item.status.HasValue)
if (item.f_num.HasValue && item.activity_num.HasValue && item.status.HasValue)
{
//同一天不能簽到兩次以上
Model.activity_check check = _db.activity_check
+172 -3
View File
@@ -1,5 +1,6 @@
using Microsoft.Ajax.Utilities;
using MINOM.COM.Utility;
using Model;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
@@ -14,6 +15,7 @@ using System.Web.Http;
/// </summary>
public class designerController : ApiController
{
private Model.ezEntities _db = new Model.ezEntities();
public designerController()
{
//
@@ -21,6 +23,19 @@ public class designerController:ApiController
//
}
[HttpPost]
[Route("api/tablet/GetActItem")]
public IHttpActionResult GetActItem([FromBody] dynamic data)
{
LogUtility log = new LogUtility();
var json = data;
string itemNum = (json == null || json.itemNum == null) ? "" : (string)json.itemNum;
int num = int.Parse(itemNum);
var item=_db.actItems.AsQueryable().Where(x => x.num == num).FirstOrDefault();
return Ok(new { result = "Y", data =item});
}
[HttpPost]
[Route("api/tablet/GetTabletElement")]
public IHttpActionResult GetTabletElement([FromBody] dynamic data)
@@ -61,6 +76,28 @@ public class designerController:ApiController
//return Ok(data);
}
[HttpPost]
[Route("api/tablet/saveFamily")]
public IHttpActionResult saveFamily([FromBody] family_members familyMember)
{
LogUtility log = new LogUtility();
_db.family_members.Add(familyMember);
_db.SaveChanges();
return Ok(new { result = "Y", data= familyMember });
//object[] obj = new StyleDataAccess().GetStyle("", "");
//if (obj[0].ToString() == "Y")
//{
// return Ok(new { result = "Y", data = obj[2] });
//}
//else
//{
// return Ok(new { result = "N", message = obj[1] });
// //throw new HttpResponseException(HttpStatusCode.NotFound);
//}
//return Ok(data);
}
[HttpPost]
[Route("api/tablet/GetStyleData")]
public IHttpActionResult GetStyleData([FromBody] dynamic data)
@@ -105,6 +142,72 @@ public class designerController:ApiController
ts.Orientation = (json == null || json.orientation == null) ? "" : (string)json.orientation;
ts.PrintPageCount = (json == null || json.printPageCount == null) ? "" : (string)json.printPageCount;
ts.PrintMode = (json == null || json.printMode == null) ? "" : (string)json.printMode;
ts.RosterLimit=(json == null || json.rosterLimit == null) ? "" : (string)json.rosterLimit;
foreach (var item in json.detail.Children<JObject>())
{
TabletStyleDetail tsd = new TabletStyleDetail();
tsd.StyleID = ts.StyleID;
tsd.Name = item.name == null ? "" : (string)item.name;
tsd.Descr = item.descr == null ? "" : (string)item.descr;
tsd.ElementID = item.elementID == null ? "" : (string)item.elementID;
tsd.StartX = item.startX == null ? "" : (string)item.startX;
tsd.StartY = item.startY == null ? "" : (string)item.startY;
tsd.FontSize = item.fontSize == null ? "" : (string)item.fontSize;
tsd.FontFamily = item.fontFamily == null ? "" : (string)item.fontFamily;
tsd.BreakLen = item.breakLen == null ? "" : (string)item.breakLen;
tsd.Width = item.width == null ? "" : (string)item.width;
tsd.Height = item.height == null ? "" : (string)item.height;
tsd.TextWidth = item.textWidth == null ? "" : (string)item.textWidth;
tsd.TextHeight = item.textHeight == null ? "" : (string)item.textHeight;
tsd.TwoOffset = item.twoOffset == null ? "" : (string)item.twoOffset;
tsd.ThreeOffset = item.threeOffset == null ? "" : (string)item.threeOffset;
tsd.FourOffset = item.fourOffset == null ? "" : (string)item.fourOffset;
tsd.IsActive = item.isActive == null ? "" : (string)item.isActive;
list.Add(tsd);
}
if (mode == "add")
{
object[] obj = new StyleDataAccess().AddStyle(ts, list);
if (obj[0].ToString() == "Y")
{
return Ok(new { result = "Y" });
}
else
{
return Ok(new { result = "N" });
}
}
return Ok();
}
[HttpPost]
[Route("api/tablet/UpdateDegignerData")]
public IHttpActionResult UpdateDegignerData([FromBody] dynamic data)
{
LogUtility log = new LogUtility();
var json = data;
//json.detail.Children<JObject>()
log.writeLogPath((string)json.styleName);
TabletStyle ts = new TabletStyle();
List<TabletStyleDetail> list = new List<TabletStyleDetail>();
ts.StyleID = (json == null || json.styleID == null) ? "" : (string)json.styleID;
string mode = "edit";
if (string.IsNullOrEmpty(ts.StyleID))
{
ts.StyleID = DateTime.Now.ToString("yyyyMMddHHmmss");
mode = "add";
}
ts.Name = (json == null || json.styleName == null) ? "" : (string)json.styleName;
ts.Descr = (json == null || json.descr == null) ? "" : (string)json.descr;
ts.PaperSize = (json == null || json.paperSize == null) ? "" : (string)json.paperSize;
ts.BackendImg = (json == null || json.backendImg == null) ? "" : (string)json.backendImg;
ts.PrintSize = (json == null || json.printSize == null) ? "" : (string)json.printSize;
ts.Orientation = (json == null || json.orientation == null) ? "" : (string)json.orientation;
ts.PrintPageCount = (json == null || json.printPageCount == null) ? "" : (string)json.printPageCount;
ts.PrintMode = (json == null || json.printMode == null) ? "" : (string)json.printMode;
ts.RosterLimit = (json == null || json.rosterLimit == null) ? "" : (string)json.rosterLimit;
foreach (var item in json.detail.Children<JObject>())
{
TabletStyleDetail tsd = new TabletStyleDetail();
@@ -122,12 +225,78 @@ public class designerController:ApiController
tsd.ThreeOffset = item.threeOffset == null ? "" : (string)item.threeOffset;
tsd.FourOffset = item.fourOffset == null ? "" : (string)item.fourOffset;
tsd.IsActive = item.isActive == null ? "" : (string)item.isActive;
tsd.Width = item.width == null ? "" : (string)item.width;
tsd.Height = item.height == null ? "" : (string)item.height;
tsd.TextWidth = item.textWidth == null ? "" : (string)item.textWidth;
tsd.TextHeight = item.textHeight == null ? "" : (string)item.textHeight;
list.Add(tsd);
}
if (mode == "add")
object[] obj = new StyleDataAccess().UpdateStyle(ts, list);
if (obj[0].ToString() == "Y")
{
object[] obj= new StyleDataAccess().AddStyle(ts,list);
return Ok(new { result = "Y" });
}
return Ok();
else
{
return Ok(new { result = "N" });
}
}
[HttpPost]
[Route("api/tablet/GetPaperSize")]
public IHttpActionResult GetPaperSize([FromBody] dynamic data)
{
LogUtility log = new LogUtility();
object[] obj = new StyleDataAccess().GetTabletPaper("", "");
if (obj[0].ToString() == "Y")
{
return Ok(new { result = "Y", data = obj[2] });
}
else
{
return Ok(new { result = "N", message = obj[1] });
//throw new HttpResponseException(HttpStatusCode.NotFound);
}
//return Ok(data);
}
[HttpPost]
[Route("api/tablet/SavePaperSize")]
public IHttpActionResult SavePaperSize([FromBody] dynamic data)
{
LogUtility log = new LogUtility();
var json = data;
//json.detail.Children<JObject>()
log.writeLogPath((string)json.styleName);
TabletPaperSize tps = new TabletPaperSize();
tps.PaperID = (json == null || json.paperID == null) ? "" : (string)json.paperID;
if (string.IsNullOrEmpty(tps.PaperID))
{
tps.PaperID = DateTime.Now.ToString("yyyyMMddHHmmss");
}
tps.PaperName = (json == null || json.paperName == null) ? "" : (string)json.paperName;
tps.Width = (json == null || json.width == null) ? "" : (string)json.width;
tps.Height = (json == null || json.height == null) ? "" : (string)json.height;
tps.CUser = "";
tps.CDate = DateTime.Now.ToString("yyyyMMdd");
tps.CTime = DateTime.Now.ToString("HHmmss");
tps.UUser = "";
tps.UDate = DateTime.Now.ToString("yyyyMMdd");
tps.UTime = DateTime.Now.ToString("HHmmss");
object[] obj = new StyleDataAccess().AddTabletPaper(tps);
if (obj[0].ToString()=="Y")
{
return Ok(new { result = "Y" });
}
else
{
return Ok(new { result = "N"});
}
}
}
+26 -10
View File
@@ -1,17 +1,19 @@
using System;
using DocumentFormat.OpenXml.Drawing.Charts;
using Model;
using MyWeb;
using Newtonsoft.Json;
using PagedList;
using System;
using System.Activities.Expressions;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IdentityModel.Metadata;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using PagedList;
using Newtonsoft.Json;
using System.Collections;
using static TreeView;
using Model;
using System.IdentityModel.Metadata;
using MyWeb;
using DocumentFormat.OpenXml.Drawing.Charts;
// api/order
@@ -206,7 +208,7 @@ public class orderController : ApiController
string sortBy = "", bool sortDesc = false)
{
var qry = _db.pro_order.AsQueryable();
var qry = _db.pro_order.Include("activity").Include("activity.activity_check").AsQueryable();
//var aIDt = _db.actItems.AsEnumerable().Where(f => f.subject.Contains(q.actItemTxt.Trim())).Select(f => f.num);//品項
@@ -221,7 +223,10 @@ public class orderController : ApiController
if (q.up_time1.HasValue)
qry = qry.Where(o => o.up_time >= q.up_time1.Value);
if (q.up_time2.HasValue)
qry = qry.Where(o => o.up_time < Convert.ToDateTime(q.up_time2.Value).AddDays(1));
{
var tmp_up_time2 = Convert.ToDateTime(q.up_time2.Value).AddDays(1);
qry = qry.Where(o => o.up_time < tmp_up_time2);
}
if (!string.IsNullOrEmpty(q.address))
qry = qry.Where(o => o.address.Contains(q.address.Trim()));
if (!string.IsNullOrEmpty(q.subject))
@@ -291,6 +296,13 @@ public class orderController : ApiController
else
qry = qry.OrderBy(o => o.activity != null ? o.activity.subject : "");
}
else if(sortBy.Equals("status"))
{
if (sortDesc)
qry = qry.OrderByDescending(o => o.activity.activity_check.FirstOrDefault(a => o.activity_num == a.activity_num && o.f_num == a.f_num).status ?? 0);
else
qry = qry.OrderBy(o => o.activity.activity_check.FirstOrDefault(a => o.activity_num == a.activity_num && o.f_num == a.f_num).status ?? 0);
}
else
qry = qry.OrderByDescending(o => o.reg_time);
@@ -307,6 +319,7 @@ public class orderController : ApiController
keyin1 = x.keyin1,
up_time = x.up_time,
keyin1_txt = Model.pro_order.keyin1_value_to_text(x.keyin1),
status = x.activity.activity_check.FirstOrDefault(a => x.activity_num == a.activity_num && x.f_num == a.f_num)?.status ?? 0,
}),
count = count
};
@@ -447,6 +460,7 @@ public class orderController : ApiController
? x.num.ToString()
: (x.parent_num.ToString() + x.num.ToString())
),
style=x.style??""
//cash_record = x.pro_order_record.Select( c => new {
// c,
// //pay_kind = tdesc2[c.payment.HasValue && x.keyin1.Value > 0 ? x.keyin1.Value : 1],
@@ -712,6 +726,7 @@ public class orderController : ApiController
order.demo = item.demo;
order.customize_data = item.customize_data;
order.UpdateTime = DateTime.Now;
order.style = item.style;
_db.SaveChanges();
var ret = new
{
@@ -765,6 +780,7 @@ public class orderController : ApiController
demo = item.demo,
customize_data = item.customize_data,
UpdateTime = DateTime.Now,
style=item.style
};
_db.pro_order_detail.Add(orderDetail);
_db.SaveChanges();
+44 -5
View File
@@ -1,14 +1,18 @@
using System;
using com.itextpdf.text.pdf;
using Model;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PagedList;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using PagedList;
using Newtonsoft.Json;
using System.Collections;
using static TreeView;
using System.Data.Entity;
/// <summary>
/// orderdetail 的摘要说明
@@ -59,4 +63,39 @@ public class orderdetailController:ApiController
if (ret.list == null) throw new HttpResponseException(HttpStatusCode.NotFound);
return Ok(ret);
}
[HttpPost]
[Route("api/orderdetail/GetDetailToPrint")]
public IHttpActionResult GetDetailToPrint([FromBody] dynamic data)
{
if (data.param is Newtonsoft.Json.Linq.JArray items)
{
string[] details = new string[items.Count];
int i = 0;
foreach (var item in items)
{
details[i] = item["order_no"] + item["num"].ToString();
i++;
}
var parameters = details.Select((s,j)=>"@p"+j).ToArray();
string sql = $"select * from pro_order_detail where order_no+convert(varchar,num) in ({string.Join(",",parameters)}) ";
int l =0;
List<SqlParameter> sqlList = new List<SqlParameter>();
foreach (var item in details)
{
sqlList.Add( new SqlParameter("@p" + l, item));
l++;
}
SqlParameter[] p = sqlList.ToArray();
var ret = _db.Database.SqlQuery<pro_order_detail>(sql, p).ToList();
if (ret == null) throw new HttpResponseException(HttpStatusCode.NotFound);
return Ok(ret);
}
else
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
}
@@ -10,6 +10,7 @@ using System.Collections;
using MyWeb;
using System.Web.WebPages;
using System.Data.Entity;
using Model;
[ezAuthorize]
public class transfer_registerController : ApiController
@@ -269,6 +270,7 @@ public class transfer_registerController : ApiController
public string check_memo { get; set; }
public string draft { get; set; }
public int? acc_kind { get; set; } // 新增關聯欄位
public int? kind { get; set; }
}
[HttpPost]
@@ -315,7 +317,7 @@ public class transfer_registerController : ApiController
{
uptime = dto.check_date,
category = 1, // 收入
kind = 27, // 固定值:法會收入/功德項目
kind = dto.kind,//27, // 固定值:法會收入/功德項目
kind2 = dto.acc_num,
price = (float)(dto.check_amount ?? 0),
tax = 0,
@@ -346,6 +348,7 @@ public class transfer_registerController : ApiController
item.check_memo = dto.check_memo;
item.draft = dto.draft;
item.acc_kind = dto.acc_kind;
}
}
_db.SaveChanges();
@@ -958,7 +961,10 @@ public class transfer_registerController : ApiController
activity_name = x.activity != null ? x.activity.subject : "",
activity_num = x.activity_num,
acc_name = x.acc_num != null ? _db.accounting_kind2.Where(a => a.num == x.acc_num).Select(a => a.kind).FirstOrDefault() : "",
price_totals=_db.pro_order_detail.
Where(a => _db.pro_order.Where (po=>po.f_num==x.f_num&&po.activity_num==x.activity_num).
Select(po => po.order_no).Any(p=>p.Equals(a.order_no))).Sum(a => a.price*a.qty),
pay_totals=_db.transfer_register.Where(a=>a.activity_num==x.activity_num&&a.f_num==x.f_num).Sum(a=>a.check_amount),
// pro_order_record 資訊 (透過 transfer_id 關聯)
pro_order_records = x.pro_order_record.Select(pr => new {
pr.num,
@@ -1275,3 +1281,22 @@ public class transfer_registerController : ApiController
}
}
}
//select ord.order_no, ord.activity_num, ord.f_num, ord.u_name, ord.totals as cost, isnull(reg.totals, 0) totals
//from (
//select o.order_no, o.activity_num, o.f_num, o.u_name, sum(o.totals) as totals from (
//select a.order_no, a.f_num, d.u_name, a.activity_num, b.num, b.f_num_tablet,
//b.price, b.qty, totals = b.price * b.qty, c.kind, c.subject
//from pro_order a
//left join pro_order_detail b on a.order_no=b.order_no
//left join actItem c on b.actItem_num=c.num
//left join followers d on a.f_num=d.num )o
//group by o.order_no, o.activity_num, o.f_num, o.u_name) ord
//left join (
//select a.activity_num, a.f_num, sum(a.amount) totals from transfer_register a
//where status='2' and check_status='99'
//group by a.activity_num, a.f_num
//) reg on ord.activity_num=reg.activity_num and ord.f_num=reg.f_num
@@ -8,7 +8,7 @@
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<PublishProvider>FileSystem</PublishProvider>
<PublishUrl>D:\17168web</PublishUrl>
<PublishUrl>C:\17168web</PublishUrl>
<WebPublishMethod>FileSystem</WebPublishMethod>
<_TargetId>Folder</_TargetId>
<SiteUrlToLaunchAfterPublish />
@@ -16,6 +16,8 @@
<asp:Repeater ID="Repeater2" runat="server" OnItemDataBound="Repeater2_ItemDataBound">
<ItemTemplate>
<a class="nav-link" href="<%#ResolveUrl(ValString(Eval("url"))) %>"
onclick="sessionStorage.removeItem('member_list_cache'); sessionStorage.removeItem('member_query_params');
sessionStorage.removeItem('order_list_cache'); sessionStorage.removeItem('order_query_params');"
target="<%#(ValString(Eval("target"))=="B"?"_blank":"_self") %>">
<%#Eval("title") %></a>
</ItemTemplate>
+111 -10
View File
@@ -7,18 +7,19 @@
<div class="mb-2 mb-sm-0">
<ul class="nav ps-0">
<li class="nav-item pe-3">
<select class="form-select" v-model="search.kind" @change="btn_search">
<select class="form-select" v-model="search.kind" @change="btn_search" :disabled="isEditing">
<option value="">選擇分類</option>
<option v-for="item in itemKindList" :value="item.num">{{item.kind}}</option>
</select>
</li>
<li class="nav-item pe-1">
<a href="item_reg.aspx" class="btn btn-primary">
<a href="item_reg.aspx" class="btn btn-primary" :class="{ 'disabled': isEditing }" >
<i class="mdi mdi-plus"></i>新增
</a>
</li>
<li class="nav-item pe-1">
<a @click="deleteAll" class="btn btn-outline-danger" title="刪除勾選的資料" ><i class="mdi mdi-trash-can"></i> 刪除勾選</a>
<a @click="deleteAll" class="btn btn-outline-danger" title="刪除勾選的資料" :class="{ 'disabled': isEditing }" ><i class="mdi mdi-trash-can"></i> 刪除勾選</a>
</li>
</ul>
<%-- <div class="input-group mb-3" data-search-control="search1" @click="search_show(search_dialog.controls.search1)">
@@ -30,15 +31,19 @@
</button>
</div>--%>
</div>
<div>
<div class="">
<a v-if="!isEditing" @click="editClick" class="btn btn-outline-secondary" title="編輯排列順序"><i class="mdi mdi-swap-vertical"></i> 編輯排列順序</a>
<a v-else @click="editClick" class="btn btn-outline-secondary" title="完成編輯排列順序"><i class="mdi mdi-swap-vertical"></i> 完成編輯</a>
<div :style="isEditing ? 'pointer-events: none; opacity: 0.5;' : ''" style="display:inline-block;">
<asp:LinkButton ID="excel" runat="server" CssClass="btn btn-outline-success" OnClick="excel_Click" ><span class="fa-solid fa-file-excel"></span> 匯出Excel</asp:LinkButton>
</div>
</div> </div>
</asp:Content>
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" runat="Server">
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.14.0/Sortable.min.js"></script>
<script>
Vue.filter('timeString', function (value, myFormat) {
return value == null || value == "" ? "" : moment(value).format(myFormat || 'YYYY-MM-DD, HH:mm:ss');
@@ -49,6 +54,7 @@
vuetify: new Vuetify(vuetify_options),
data() {
return {
isEditing: false,
options: { multiSort: false },
data_table: {
loading: true,
@@ -174,6 +180,23 @@
},
getDefault(clearpage = false) {
if (this.isEditing) {
const { sortBy, sortDesc, page, itemsPerPage } = this.options
const params = {
sortBy: "sort_order", sortDesc: sortDesc[0],
page: clearpage ? '1' : page, pageSize: 0
};
this.data_table.loading = true
axios
.post(HTTP_HOST + 'api/activity/GetItemList', this.search, { params: params })
.then(response => {
this.data_table.list = response.data.list
this.data_table.count = response.data.count;
this.data_table.loading = false
})
.catch(error => console.log(error))
}
else {
const { sortBy, sortDesc, page, itemsPerPage } = this.options
const params = {
sortBy: sortBy[0], sortDesc: sortDesc[0],
@@ -188,6 +211,8 @@
this.data_table.loading = false
})
.catch(error => console.log(error))
}
},
editItem(item) {
console.log("edit", item);
@@ -225,6 +250,29 @@
.catch(error => console.log(error))
}
},
editClick() {
if (this.isEditing) {
this.isEditing = false;
const sortedIds = this.data_table.list.map(item => item.num);
axios.post(HTTP_HOST + 'api/activity/SaveItemList', { ids: sortedIds })
.then(response => {
this.isEditing = false;
this.getDefault();
})
.catch(error => {
alert("儲存排序失敗:" + error);
})
.finally(() => {
this.data_table.loading = false;
});
}
else {
this.isEditing = true;
this.getDefault()
}
},
btn_search() {
this.getDefault(true)
},
@@ -299,19 +347,48 @@
}
this.search_dialog.show = false;
},
saveOrder(event) {
const movedItem = this.data_table.list.splice(event.oldIndex, 1)[0];
this.data_table.list.splice(event.newIndex, 0, movedItem);
},
},
computed: {
pageCount() {
return Math.ceil(this.data_table.count / this.data_table.pageSize)
},
computedHeaders() {
return this.data_table.header.map(h => {
if (h.value === 'slot_btn') {
return { ...h, sortable: false };
}
return {
...h,
sortable: this.isEditing ? false : (h.sortable !== false)
};
});
},
},
filters: {
currency: function (value) {
return value == null || value == "" ? "" :
('$' + parseFloat(value).toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, "$1,").replace(".00", ""));
},
},
directives: {
sortableDataTable: {
bind(el, binding, vnode) {
const options = {
animation: 150,
onUpdate: function (event) {
vnode.child.$emit('sorted', event)
}
}
Sortable.create(el.getElementsByTagName('tbody')[0], options)
}
}
},
})
</script>
</asp:Content>
@@ -319,6 +396,9 @@
<uc1:alert runat="server" ID="L_msg" Text="" />
<div id="content" class="container-fluid">
<v-data-table
v-sortable-data-table
@sorted="saveOrder"
:headers="computedHeaders"
v-model="data_table.selected"
:items="data_table.list"
:search-props="search"
@@ -332,8 +412,29 @@
show-select
hide-default-footer
:page.sync="data_table.page"
:items-per-page.sync="data_table.pageSize"
:items-per-page.sync= "isEditing ? -1 :data_table.pageSize"
class="elevation-1">
<template v-slot:header.data-table-select="{ on, props }">
<v-simple-checkbox
v-if="!isEditing"
v-bind="props"
v-on="on"
></v-simple-checkbox>
<v-icon v-else small>mdi-swap-vertical</v-icon>
</template>
<template v-slot:item.data-table-select="{ item, isSelected, select }">
<v-simple-checkbox
v-if="!isEditing"
:value="isSelected"
@input="select($event)"
></v-simple-checkbox>
<div v-else class="handle" style="cursor: grab;">
<v-icon color="grey darken-1">mdi-drag-vertical</v-icon>
</div>
</template>
<template #item.price="{ item }" >
{{item.price | currency }}
</template>
@@ -353,11 +454,11 @@
<template #item.slot_btn="{ item }" >
<a :href="'item_reg.aspx?num='+item.num" class="btn btn-outline-secondary btn-sm"><i class="mdi mdi-pencil-box-outline"></i>修改</a>
<a @click="deleteItem(item)" class="btn btn-outline-secondary btn-sm"><i class="mdi mdi-trash-can"></i>刪除</a>
<a v-if="!isEditing" :href="'item_reg.aspx?num='+item.num" class="btn btn-outline-secondary btn-sm"><i class="mdi mdi-pencil-box-outline"></i>修改</a>
<a v-if="!isEditing" @click="deleteItem(item)" class="btn btn-outline-secondary btn-sm"><i class="mdi mdi-trash-can"></i>刪除</a>
</template>
</v-data-table>
<v-container>
<v-container v-if="!isEditing">
<v-row class="align-baseline" wrap>
<v-col cols="12" md="9">
<v-pagination
+1 -1
View File
@@ -148,7 +148,7 @@ public partial class admin_activity_index2 : MyWeb.config
}
var tdesc = publicFun.enum_desc<Model.activity.category>();
qry = qry.OrderByDescending(o => o.num);
qry = qry.OrderByDescending(o => o.sort_order);
var list = qry.ToList();
if (list.Count > 0)
{
+76
View File
@@ -23,6 +23,8 @@
data() {
return {
this_id: '<%= Request["num"] %>',
paperlist: [],
stylelist: [],
options: {},
optionsDetail: {
multiSort: false,
@@ -334,6 +336,50 @@
)
}
axios
.post(HTTP_HOST + 'api/tablet/GetPaperSize', {})
.then(response => {
console.log(response);
if (response.status == "200") {
let data = response.data;
if (data.result == "Y") {
data.data.forEach(x => {
this.paperlist.push({ name: x.paperName, id: x.paperID, width: x.width, height: x.height })
$('#<%= ddlPageSize.ClientID %>').append(`<option value="${x.paperID}">${x.paperName}</option>`);
$('#<%= ddlPrintSize.ClientID %>').append(`<option value="${x.paperID}">${x.paperName}</option>`);
});
$('#<%= ddlPageSize.ClientID %>').val($("#<%= hidPageSize.ClientID %>").val())
$('#<%= ddlPrintSize.ClientID %>').val($("#<%= hidPrintSize.ClientID %>").val())
}
}
})
.catch(
error => console.log(error)
)
axios
.post(HTTP_HOST + 'api/tablet/GetStyleData', {})
.then(response => {
console.log(response);
if (response.status == "200") {
let data = response.data;
if (data.result == "Y") {
data.data.forEach(x => {
if (x.styleID != "000001") {
this.stylelist.push({ styleID: x.styleID, name: x.name })
$('#<%= ddlDefaultStyle.ClientID %>').append(`<option value="${x.styleID}">${x.name}</option>`);
//$("#defaultStyle").append(`<option value="${x.styleID}">${x.name}</option>`);
}
});
$('#<%= ddlDefaultStyle.ClientID %>').val($("#<%= hidDefaultStyle.ClientID %>").val())
}
}
})
.catch(
error => console.log(error)
)
},
editItem(item) {
this.editedIndex = this.desserts.indexOf(item);
@@ -525,6 +571,15 @@
}
}
},
changeSel(selType) {
if (selType=="ddlPageSize") {
$("#<%= hidPageSize.ClientID %>").val($("#<%= ddlPageSize.ClientID %>").val())
} else if (selType == "ddlPrintSize") {
$("#<%= hidPrintSize.ClientID %>").val($("#<%=ddlPrintSize.ClientID %>").val())
} else if (selType == "ddlDefaultStyle") {
$("#<%= hidDefaultStyle.ClientID %>").val($("#<%= ddlDefaultStyle.ClientID %>").val())
}
}
},
computed: {
},
@@ -625,6 +680,27 @@
<asp:RegularExpressionValidator ControlToValidate="price" Display="Dynamic" SetFocusOnError="true" ErrorMessage="只能輸入數字" ID="RegularExpressionValidator3" runat="server" ValidationExpression="^(-?\d+)(\.\d+)?$" />
</div>
</div>
<div class="row mb-1 label-sm-right">
<label class="col-sm-2 col-form-label">預設頁面尺寸</label>
<div class="col-sm-4">
<select ID="ddlPageSize" runat="server" onchange="VueApp.changeSel('ddlPageSize')"></select>
<asp:HiddenField ID="hidPageSize" runat="server" />
</div>
<label class="col-sm-2 col-form-label">預設列印尺寸</label>
<div class="col-sm-4">
<select ID="ddlPrintSize" runat="server" onchange="VueApp.changeSel('ddlPrintSize')"></select>
<asp:HiddenField ID="hidPrintSize" runat="server" />
</div>
</div>
<div class="row mb-1 label-sm-right">
<label class="col-sm-2 col-form-label">預設版型</label>
<div class="col-sm-4">
<select ID="ddlDefaultStyle" runat="server" onchange="VueApp.changeSel('ddlDefaultStyle')"></select>
<asp:HiddenField ID="hidDefaultStyle" runat="server" />
</div>
</div>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" class="row mb-1 label-sm-right">
<ContentTemplate>
<label class="col-sm-2 col-form-label"></label>
+53
View File
@@ -44,6 +44,21 @@ public partial class admin_activity_item_reg : MyWeb.config
print_init.Text = prod.print_init;
PARTNO.Text = prod.partno;
//kind.SelectedValue = prod.kind.ToString();
if (!isStrNull(prod.pageSize))
{
ddlPageSize.Value = prod.pageSize.ToString();
hidPageSize.Value = prod.pageSize.ToString();
}
if (!isStrNull(prod.printSize))
{
ddlPrintSize.Value = prod.printSize.ToString();
hidPrintSize.Value = prod.printSize.ToString();
}
if (!isStrNull(prod.defaultStyle))
{
ddlDefaultStyle.Value = prod.defaultStyle.ToString();
hidDefaultStyle.Value = prod.defaultStyle.ToString();
}
if (prod.kind.HasValue)
{
kind_txt.Value = prod.actItem_kind.kind;
@@ -118,9 +133,22 @@ public partial class admin_activity_item_reg : MyWeb.config
L_msg.Text = "";
Model.actItem actItem = new Model.actItem();//新增
int maxSort = _db.actItems.Max(x => (int?)x.sort_order) ?? 0;
actItem.subject = subject.Text;
actItem.print_init = print_init.Text;
actItem.partno = PARTNO.Text;
if (!isStrNull(ddlPageSize.Value))
{
actItem.pageSize = ddlPageSize.Value;
}
if (!isStrNull(ddlPrintSize.Value))
{
actItem.printSize = ddlPrintSize.Value;
}
if (!isStrNull(ddlDefaultStyle.Value))
{
actItem.defaultStyle = (ddlDefaultStyle.Value);
}
//if (!isStrNull(kind.SelectedValue)) { actItem.kind = Val(kind.SelectedValue); } else { actItem.kind = null; }
if (!isStrNull(category.SelectedValue)) { actItem.category = Val(category.SelectedValue); } else { actItem.category = null; }
if (!isStrNull(kind.Value)) { actItem.kind = Val(kind.Value); } else { actItem.kind = null; }
@@ -131,6 +159,7 @@ public partial class admin_activity_item_reg : MyWeb.config
actItem.is_reconcile = is_reconcile_item.Checked ? "Y" : "N";
actItem.demo = demo.Text;
actItem.customize_data = customize_data.Text;
actItem.sort_order = maxSort + 1;
_db.actItems.Add(actItem);
_db.SaveChanges();
@@ -168,6 +197,18 @@ public partial class admin_activity_item_reg : MyWeb.config
actItem.subject = subject.Text;
actItem.print_init = print_init.Text;
actItem.partno = PARTNO.Text;
if (!isStrNull(hidPageSize.Value))
{
actItem.pageSize = hidPageSize.Value;
}
if (!isStrNull(hidPrintSize.Value))
{
actItem.printSize = hidPrintSize.Value;
}
if (!isStrNull(hidDefaultStyle.Value))
{
actItem.defaultStyle = (hidDefaultStyle.Value);
}
//if (!isStrNull(kind.SelectedValue)) { actItem.kind = Val(kind.SelectedValue); } else { actItem.kind = null; }
if (!isStrNull(category.SelectedValue)) { actItem.category = Val(category.SelectedValue); } else { actItem.category = null; }
if (!isStrNull(kind.Value)) { actItem.kind = Val(kind.Value); } else { actItem.kind = null; }
@@ -246,4 +287,16 @@ public partial class admin_activity_item_reg : MyWeb.config
}
}
}
//protected override void Render(HtmlTextWriter writer)
//{
// ClientScript.RegisterForEventValidation(
// ddlDefaultStyle.UniqueID, "ddlDefaultStyle");
// ClientScript.RegisterForEventValidation(
// ddlPageSize.UniqueID, "ddlPageSize");
// ClientScript.RegisterForEventValidation(
// ddlPrintSize.UniqueID, "ddlPrintSize");
// base.Render(writer);
//}
}
+87 -3
View File
@@ -590,7 +590,8 @@
this.data_table.selected.push(this.data_table.editFilesItem[i])
}
}
}, multiPrint() {
},
multiPrintNew() {
var params = {
item: this.thisItemSelected.val,
file: this.thisFilesSelected.val,
@@ -601,9 +602,82 @@
//list = this.data_table.selected.map(x => x.num);
list = this.data_table.selected
.sort((a, b) => a.print_id.localeCompare(b.print_id))
.sort((a, b) => (a.print_id == null ? "" : a.print_id).localeCompare(b.print_id == null ? "" : b.print_id))
.map(x => x.num);
//console.log("what:",list);
if (list.length > 0) {
// 記錄已列印
let _url = HTTP_HOST + 'api/order/printMultiFileLog';
axios.post(_url, list, { params: params })
.then(response => {
for (let i = 0; i < this.data_table.selected.length; i++) {
for (let j = 0; i < this.data_table.editFilesItem.length; j++) {
if (this.data_table.selected[i].num == this.data_table.editFilesItem[j].num) {
this.data_table.editFilesItem[j].isPrinted = true;
break;
}
}
}
})
.catch(error => {
console.log(error)
})
// 送出列印
_url = HTTP_HOST + 'admin/print/print_multi_new.aspx';
var form = document.createElement("form");
form.method = "POST";
form.action = _url;
form.target = "_blank"; // Open the result in a new tab
// Helper function to add hidden fields
const addHiddenField = (name, value) => {
const hiddenField = document.createElement("input");
hiddenField.type = "hidden";
hiddenField.name = name;
hiddenField.value = value;
form.appendChild(hiddenField);
};
// Add form fields
console.log(this.thisItemSelected.val, this.thisFilesSelected.val, JSON.stringify(list));
addHiddenField("item", this.thisItemSelected.val);
addHiddenField("file", this.thisFilesSelected.val);
addHiddenField("list", JSON.stringify(list));
addHiddenField("title", `${this.thisItemSelected.text} / ${this.thisFilesSelected.text}`);
//console.log("底家:",this.data_table.selected);
localStorage.setItem("item", this.thisItemSelected.val);
localStorage.setItem("list", JSON.stringify(this.data_table.selected));
document.body.appendChild(form); // Not entirely sure if this is necessary
form.submit();
document.body.removeChild(form);
}
else {
this.snackbar.text = "未選擇列印項目";
this.snackbar.show = true
}
},
multiPrint() {
var params = {
item: this.thisItemSelected.val,
file: this.thisFilesSelected.val,
//list: this.data_table.selected.map(x => x.num)
};
var list = [];
//list = this.data_table.selected.map(x => x.num);
list = this.data_table.selected
.sort((a, b) => (a.print_id==null?"":a.print_id).localeCompare(b.print_id==null?"":b.print_id))
.map(x => x.num);
//console.log("what:",list);
if (list.length > 0) {
// 記錄已列印
let _url = HTTP_HOST + 'api/order/printMultiFileLog';
@@ -639,10 +713,14 @@
};
// Add form fields
console.log(this.thisItemSelected.val, this.thisFilesSelected.val,JSON.stringify(list));
addHiddenField("item", this.thisItemSelected.val);
addHiddenField("file", this.thisFilesSelected.val);
addHiddenField("list", JSON.stringify(list));
addHiddenField("title", `${this.thisItemSelected.text} / ${this.thisFilesSelected.text}`);
//console.log("底家:",this.data_table.selected);
localStorage.setItem("item", this.thisItemSelected.val);
localStorage.setItem("list", JSON.stringify(this.data_table.selected));
/*
var hiddenField = document.createElement("input");
@@ -827,7 +905,7 @@
<div class="">
<asp:Button ID="add" runat="server" Text="送出" OnClick="add_Click" CssClass="btn btn-primary" />
<asp:Button ID="edit" runat="server" Text="修改" Visible="false" OnClick="edit_Click" CssClass="btn btn-primary" />
<asp:Button ID="goback" runat="server" Text="回列表" Visible="false" CausesValidation="false" OnClick="goback_Click" CssClass="btn btn-outline-secondary" />
<asp:Button ID="goback" runat="server" Text="取消" Visible="true" CausesValidation="false" OnClick="goback_Click" CssClass="btn btn-outline-secondary" />
</div>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
@@ -1199,6 +1277,12 @@
@click="multiPrint">
列印<v-icon dark>mdi-turn-right</v-icon>
</v-btn>
<v-btn
color="primary"
class="ml-2 white--text"
@click="multiPrintNew">
列印(New)<v-icon dark>mdi-turn-right</v-icon>
</v-btn>
</div>
</v-toolbar>
</template>
+868
View File
@@ -0,0 +1,868 @@
<template>
<v-container>
<v-card>
<v-card-title class="bg-warning white--text text-center">
<h5 class="mb-0">餘額核銷 - 處理剩餘金額</h5>
<button class="btn btn-default ms-auto"><i class="mdi mdi-close"></i></button>
</v-card-title>
<v-card-text>
<v-data-table :headers="headers"
:items="items"
:loading="loading"
loading-text="載入中..."
class="elevation-1 balance-reconcile-table"
item-key="id">
<template v-slot:item.follower="{ item }">
<div>
<div class="font-weight-bold">
<a :href="`../follower/reg.aspx?num=${item.f_num}`"
target="_blank"
class="text-decoration-none"
:title="`查看 ${item.follower} 的詳細資料`">
{{ item.follower }}
<v-icon small color="primary" class="ml-1">mdi-open-in-new</v-icon>
</a>
</div>
<div class="caption text--secondary" v-if="item.phone">
{{ item.phone }}
</div>
<div class="caption text--secondary" v-if="item.phone2">
{{ item.phone2 }}
</div>
</div>
</template>
<template v-slot:item.bank_info="{ item }">
<div>
<div class="font-weight-bold">{{ item.acc_name }}</div>
<div class="caption text--secondary">{{ item.check_date | date }}</div>
</div>
</template>
<template v-slot:item.amount_info="{ item }">
<div>
<div class="font-weight-bold text-primary">
已入帳{{ item.check_amount }}
</div>
<div class="text-success">
已沖帳{{ item.check_amount - item.remain_amount }}
</div>
<div class="text-warning font-weight-bold">
待核銷{{ item.remain_amount }}
</div>
</div>
</template>
<template v-slot:item.detail_info="{ item }">
<v-btn color="info"
outlined
@click="showDetailDialog(item)">
<v-icon small class="mr-1">mdi-information-outline</v-icon>
詳細
</v-btn>
</template>
<!-- 選取項目欄位 -->
<template v-slot:item.select_items="{ item }">
<div style="min-width: 200px;">
<v-text-field v-model="item.selected_items_text"
placeholder="項目名稱"
dense
outlined
readonly
hide-details
style="font-size: 12px;">
<template v-slot:append>
<v-btn small
color="primary"
icon
@click="showItemSelectDialog(item)"
style="margin-right: -8px;">
<v-icon small>mdi-table</v-icon>
</v-btn>
</template>
</v-text-field>
</div>
</template>
<!-- 狀態與操作欄位 -->
<template v-slot:item.status_action="{ item }">
<div style="min-width: 280px;">
<v-row no-gutters>
<v-col cols="6" class="pr-1">
<v-select v-model="item.new_status"
:items="statusOptions"
dense
outlined
hide-details
placeholder="狀態"
style="font-size: 12px;"></v-select>
</v-col>
<v-col cols="6" class="pl-1">
<v-btn color="primary"
block
@click="processBalance(item)"
:disabled="!canUpdate(item)">
更新狀態
</v-btn>
</v-col>
</v-row>
<v-row no-gutters class="mt-2">
<v-col cols="12">
<v-text-field v-model="item.verify_note"
dense
outlined
hide-details
placeholder="核對記錄"
style="font-size: 12px;"></v-text-field>
</v-col>
</v-row>
</div>
</template>
</v-data-table>
</v-card-text>
</v-card>
<!-- 餘額處理對話框 -->
<v-dialog v-model="dialog.show" max-width="800px">
<v-card>
<v-card-title class="grey lighten-2">
<v-icon color="warning" class="mr-2">mdi-cash-multiple</v-icon>
餘額處理
<v-spacer></v-spacer>
<v-btn icon @click="dialog.show = false">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<v-card-text class="pb-0">
<div v-if="dialog.selected">
<v-row class="my-3">
<v-col cols="12" md="6">
<div class="mb-2">
<span class="font-weight-bold">信眾</span>
{{ dialog.selected.follower }}
</div>
<div class="mb-2">
<span class="font-weight-bold">入帳銀行</span>
{{ dialog.selected.acc_name }}
</div>
<div class="mb-2">
<span class="font-weight-bold">入帳日期</span>
{{ dialog.selected.check_date | date }}
</div>
</v-col>
<v-col cols="12" md="6">
<div class="mb-2">
<span class="font-weight-bold">入帳金額</span>
<span class="text-primary">{{ dialog.selected.check_amount | currency }}</span>
</div>
<div class="mb-2">
<span class="font-weight-bold">剩餘金額</span>
<span class="text-warning font-weight-bold">{{ dialog.selected.remain_amount | currency }}</span>
</div>
<div class="mb-2">
<span class="font-weight-bold">狀態</span>
<v-chip small color="warning" text-color="white">
{{ getStatusText(dialog.selected.check_status) }}
</v-chip>
</div>
</v-col>
</v-row>
<!-- 歷史沖帳記錄 -->
<v-divider class="my-3"></v-divider>
<h6 class="mb-3">
<v-icon color="info" class="mr-1">mdi-history</v-icon>
歷史沖帳記錄
</h6>
<v-data-table :headers="dialog.historyHeaders"
:items="dialog.historyItems"
class="elevation-1 mb-4"
hide-default-footer
:disable-pagination="true"
dense>
<template v-slot:item.reconcile_amount="{ item }">
<span>{{ item.reconcile_amount | currency }}</span>
</template>
<template v-slot:item.reconcile_date="{ item }">
<span>{{ item.reconcile_date | date }}</span>
</template>
</v-data-table>
<!-- 餘額處理選項 -->
<v-divider class="my-3"></v-divider>
<h6 class="mb-3">
<v-icon color="warning" class="mr-1">mdi-cash-multiple</v-icon>
餘額處理方式
</h6>
<v-radio-group v-model="dialog.balanceAction" class="mt-0">
<v-radio label="轉入下次活動"
value="transfer"
color="primary"></v-radio>
<v-radio label="現金退費"
value="refund_cash"
color="success"></v-radio>
<v-radio label="銀行轉帳退費"
value="refund_bank"
color="success"></v-radio>
<v-radio label="結餘處理"
value="balance_off"
color="grey"></v-radio>
</v-radio-group>
<!-- 處理說明 -->
<v-textarea v-model="dialog.memo"
label="處理說明"
outlined
rows="3"
placeholder="請輸入處理說明..."
class="mt-3"></v-textarea>
</div>
</v-card-text>
<v-card-actions class="pa-4">
<div v-if="dialog.errorMessage" class="text-danger">
{{ dialog.errorMessage }}
</div>
<v-spacer></v-spacer>
<v-btn color="grey" text @click="dialog.show = false">取消</v-btn>
<v-btn color="warning"
@click="confirmBalance"
:disabled="!dialog.balanceAction || dialog.loading"
:loading="dialog.loading">
確認處理
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- 詳細資訊對話框 -->
<v-dialog v-model="detailDialog.show" max-width="900px">
<v-card>
<v-card-title class="grey lighten-2">
<v-icon color="info" class="mr-2">mdi-information-outline</v-icon>
詳細資訊
<v-spacer></v-spacer>
<v-btn icon @click="detailDialog.show = false">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<v-tabs v-model="detailDialog.tab" background-color="grey lighten-4">
<v-tab>
<v-icon small class="mr-2">mdi-information</v-icon>
基本資訊
</v-tab>
<v-tab>
<v-icon small class="mr-2">mdi-table</v-icon>
沖帳明細
</v-tab>
<v-tab>
<v-icon small class="mr-2">mdi-image</v-icon>
證明圖片
</v-tab>
</v-tabs>
<v-tabs-items v-model="detailDialog.tab">
<!-- Tab 1: 基本資訊 -->
<v-tab-item>
<v-card-text>
<div v-if="detailDialog.selected">
<v-row>
<v-col cols="12" md="6">
<h6 class="mb-3 text-primary">
<v-icon color="primary" small class="mr-1">mdi-account</v-icon>
匯款人資訊
</h6>
<div class="mb-2">
<span class="font-weight-bold">姓名</span>
{{ detailDialog.selected.name }}
</div>
<div class="mb-2">
<span class="font-weight-bold">支付方式</span>
{{ payTypeText[detailDialog.selected.pay_type] || detailDialog.selected.pay_type }}
</div>
<div class="mb-2">
<span class="font-weight-bold">帳號後5碼</span>
{{ detailDialog.selected.account_last5 || '-' }}
</div>
<div class="mb-2">
<span class="font-weight-bold">支付型態</span>
{{ detailDialog.selected.pay_mode }}
</div>
</v-col>
<v-col cols="12" md="6">
<h6 class="mb-3 text-success">
<v-icon color="success" small class="mr-1">mdi-cash</v-icon>
入帳資訊
</h6>
<div class="mb-2">
<div class="font-weight-bold">{{ detailDialog.selected.acc_name }}</div>
<div class="caption text--secondary">{{ detailDialog.selected.check_date | date }}</div>
</div>
<div class="mb-2">
<span class="font-weight-bold text-primary">已入帳{{ detailDialog.selected.check_amount }}</span>
</div>
<div class="mb-2">
<span class="text-success">已沖帳{{ detailDialog.selected.check_amount - detailDialog.selected.remain_amount }}</span>
</div>
<div class="mb-2">
<span class="text-warning font-weight-bold">待核銷{{ detailDialog.selected.remain_amount }}</span>
</div>
</v-col>
</v-row>
<v-divider class="my-4"></v-divider>
<v-row>
<v-col cols="12" md="6">
<h6 class="mb-3 text-purple">
<v-icon color="purple" small class="mr-1">mdi-calendar-check</v-icon>
活動資訊
</h6>
<div class="mb-2">
<span class="font-weight-bold">活動名稱</span>
{{ detailDialog.selected.activity_name || '-' }}
</div>
<div class="mb-2">
<span class="font-weight-bold">開始日期</span>
{{ detailDialog.selected.activity_start_date | date }}
</div>
</v-col>
<v-col cols="12" md="6">
<h6 class="mb-3 text-info">
<v-icon color="info" small class="mr-1">mdi-clipboard-check</v-icon>
核對記錄
</h6>
<div class="mb-2">
<span class="font-weight-bold">核對記錄</span>
{{ detailDialog.selected.verify_note || '-' }}
</div>
<div class="mb-2">
<span class="font-weight-bold">帳簿備註</span>
{{ detailDialog.selected.check_memo || '-' }}
</div>
</v-col>
</v-row>
</div>
</v-card-text>
</v-tab-item>
<!-- Tab 2: 沖帳明細表格 -->
<v-tab-item>
<v-card-text>
<div v-if="detailDialog.selected">
<v-data-table :headers="detailDialog.reconcileHeaders"
:items="detailDialog.reconcileItems"
class="elevation-1"
hide-default-footer
:disable-pagination="true">
<template v-slot:item.reconcile="{ item }">
<span class="font-weight-bold text-success">{{ item.reconcile | currency }}</span>
</template>
<template v-slot:item.register_date="{ item }">
<span>{{ item.register_date | date }}</span>
</template>
<template v-slot:item.price="{ item }">
<span>{{ item.price | currency }}</span>
</template>
</v-data-table>
</div>
</v-card-text>
</v-tab-item>
<!-- Tab 3: 證明圖片 -->
<v-tab-item>
<v-card-text>
<div v-if="detailDialog.selected">
<div v-if="detailDialog.selected.proof_img">
<h6 class="mb-3 text-orange">
<v-icon color="orange" small class="mr-1">mdi-image</v-icon>
證明圖片
</h6>
<div class="text-center">
<img :src="detailDialog.selected.proof_img"
alt="證明圖片"
style="max-width: 100%; max-height: 500px;"
class="elevation-3" />
</div>
</div>
<div v-else class="text-center py-5">
<v-icon size="64" color="grey lighten-2">mdi-image-off</v-icon>
<div class="mt-3 text--secondary">無證明圖片</div>
</div>
</div>
</v-card-text>
</v-tab-item>
</v-tabs-items>
</v-card>
</v-dialog>
<!-- 活動品項選擇對話框 -->
<v-dialog v-model="search_dialog.show" max-width="700px">
<v-card>
<v-card-title class="justify-space-between grey lighten-2">
查詢:{{search_dialog.current.title}}
<v-btn icon @click="search_dialog.show=false"><v-icon>mdi-close</v-icon></v-btn>
</v-card-title>
<v-card-text>
<v-row>
<v-col v-for="item in search_dialog.current.keys"
:cols="search_dialog.current.keys.length>1?6:12">
<v-text-field v-model="item.value" :label="item.title" v-if="item.visible===undefined || item.visible==true "></v-text-field>
</v-col>
<v-col cols="12" sm="4" md="3">
<v-checkbox v-model="search_is_reconcile"
label="核銷項目"
:true-value="'Y'"
:false-value="''"
hide-details
@change="search_get"></v-checkbox>
</v-col>
<v-col cols="12" class="text-end">
<v-btn color="primary" elevation="0" @click="search_get()">查詢</v-btn>
<v-btn elevation="0" @click="search_clear()">清除條件</v-btn>
</v-col>
</v-row>
<v-data-table :headers="search_headers()"
:items="search_dialog.list"
:footer-props="search_dialog.footer"
:items-per-page="10"
:server-items-length="search_dialog.count"
:page.sync="search_dialog.page"
:options.sync="options"
@click:row="search_select"
:loading="search_dialog.loading"></v-data-table>
</v-card-text>
<v-card-actions>
</v-card-actions>
</v-card>
</v-dialog>
</v-container>
</template>
<script>
module.exports = {
data() {
return {
loading: false,
headers: [
{ text: '信眾', value: 'follower' },
{ text: '入帳帳戶/日期', value: 'bank_info' },
{ text: '金額', value: 'amount_info' },
{ text: '詳細資訊', value: 'detail_info', sortable: false },
{ text: '選取項目', value: 'select_items', sortable: false, width: '200px' },
{ text: '狀態 | 核對記錄', value: 'status_action', sortable: false, width: '280px' }
],
items: [],
dialog: {
show: false,
selected: null,
balanceAction: null,
memo: '',
loading: false,
errorMessage: '',
historyHeaders: [
{ text: '法會', value: 'activity_name' },
{ text: '項目', value: 'item_name' },
{ text: '沖帳金額', value: 'reconcile_amount' },
{ text: '沖帳日期', value: 'reconcile_date' }
],
historyItems: [
{
activity_name: '2025新春法會',
item_name: '護持金',
reconcile_amount: 12000,
reconcile_date: '2025-01-15T00:00:00'
}
]
},
detailDialog: {
show: false,
selected: null,
tab: 0,
reconcileHeaders: [
{ text: '法會活動', value: 'activity_name' },
{ text: '報名項目', value: 'actitem_name' },
{ text: '原始金額', value: 'price' },
{ text: '沖帳金額', value: 'reconcile' },
{ text: '報名日期', value: 'register_date' },
{ text: '訂單編號', value: 'order_no' }
],
reconcileItems: []
},
statusOptions: [
{ text: '沖帳有剩餘', value: '90' },
{ text: '未聯絡', value: '91' },
{ text: '已聯絡', value: '92' },
{ text: '餘額核銷', value: '95' }
],
search_dialog: {
controls: {
search5: {
id: 'search5',
title: '活動品項',
text_prop: 'subject',
value_prop: 'num',
keys: [
{ id: 'subject', title: '項目名稱', value: '' },
{ id: 'kindTxt', title: '項目分類' },
{ id: 'num', visible: false },
],
api_url: '../../api/activity/GetOrderList',
columns: [
{ id: 'subject', title: '項目名稱' },
{ id: 'kindTxt', title: '項目分類' },
{ id: 'price', title: '價格' },
],
selected: {},
currentRow: null, //
select(vueInstance, selectedItem) {
//
if (this.currentRow) {
// actItem num balance_act_item
this.currentRow.balance_act_item = selectedItem.num;
//
this.currentRow.selected_items_text = selectedItem.subject;
//
if (selectedItem.price) {
this.currentRow.selected_items_text += ` (NT$${Number(selectedItem.price).toLocaleString()})`;
}
console.log('已選擇項目:', selectedItem.subject, '項目編號:', selectedItem.num);
}
}
}
},
show: false,
current: {},
list: [],
count: 0,
page: 1,
loading: false,
footer: {
showFirstLastPage: true,
disableItemsPerPage: true,
itemsPerPageAllText: '',
itemsPerPageText: '',
},
},
options: {},
payTypeText: {
1: '現金',
2: '匯款',
3: '支票'
},
search_is_reconcile: "Y",
}
},
mounted() {
this.loadTableData();
this.search_dialog.current = this.search_dialog.controls.search5; //
},
filters: {
currency(val) {
if (!val) return '0';
return Number(val).toLocaleString();
},
date(val) {
if (!val) return '';
const date = new Date(val);
return date.toLocaleDateString();
}
},
methods: {
// 使 DraftUtils
loadTableData() {
this.loading = true;
axios.get('../../api/transfer_register/balance_reconcile_list')
.then(res => {
this.items = res.data.map(item => ({
...item,
//
selected_items_text: item.balance_act_item ? (item.balance_actitem_name || '已選擇項目') : '', //
new_status: item.check_status,
balance_act_item: item.balance_act_item, //
verify_note: item.verify_note || '' //
}));
})
.catch(err => {
console.error('載入資料失敗:', err);
alert('載入資料失敗,請重新整理頁面');
this.items = [];
})
.finally(() => {
this.loading = false;
});
},
getStatusColor(status) {
switch (status) {
case '90': return 'warning';
case '99': return 'success';
default: return 'grey';
}
},
getStatusText(status) {
switch (status) {
case '90': return '沖帳有剩餘';
case '91': return '未聯絡';
case '92': return '已聯絡';
case '95': return '餘額核銷';
case '99': return '沖帳完成';
default: return '未知狀態';
}
},
showBalanceDialog(item) {
this.dialog.selected = item;
this.dialog.balanceAction = null;
this.dialog.memo = '';
this.dialog.errorMessage = '';
this.dialog.show = true;
//
if (item.draft) {
const detailItems = window.DraftUtils.getDraftField(item.draft, 'pro_order_detail_items');
if (detailItems && Array.isArray(detailItems)) {
this.dialog.historyItems = detailItems.map(item => ({
activity_name: item.activity_name || '未知活動',
item_name: item.actitem_name || '未知項目',
reconcile_amount: item.reconcile || 0,
reconcile_date: item.register_date || '2025-01-15T00:00:00'
}));
} else {
this.dialog.historyItems = [];
}
}
},
confirmBalance() {
if (!this.dialog.balanceAction) {
this.dialog.errorMessage = '請選擇處理方式';
return;
}
if (!this.dialog.memo.trim()) {
this.dialog.errorMessage = '請輸入處理說明';
return;
}
this.dialog.loading = true;
this.dialog.errorMessage = '';
// API 調
setTimeout(() => {
alert(`餘額處理完成:${this.getActionText(this.dialog.balanceAction)}`);
this.dialog.show = false;
this.dialog.loading = false;
//
}, 1500);
},
getActionText(action) {
switch (action) {
case 'transfer': return '轉入下次活動';
case 'refund_cash': return '現金退費';
case 'refund_bank': return '銀行轉帳退費';
case 'balance_off': return '結餘處理';
default: return '未知操作';
}
},
showDetailDialog(item) {
this.detailDialog.selected = item;
this.detailDialog.tab = 0; // tab
// JSON
this.loadReconcileItems(item.draft, item.id);
this.detailDialog.show = true;
},
async loadReconcileItems(draft, transferRegisterId) {
this.detailDialog.reconcileItems = [];
if (!draft) return;
const detailItems = window.DraftUtils.getDraftField(draft, 'pro_order_detail_items');
if (detailItems && Array.isArray(detailItems)) {
// 使 pro_order_detail_items
this.detailDialog.reconcileItems = detailItems.map((item, index) => {
return {
pro_order_detail_num: item.pro_order_detail_num,
activity_name: item.activity_name || '未知活動',
actitem_name: item.actitem_name || '未知項目',
price: item.price || 0,
reconcile: item.reconcile,
register_date: item.register_date,
order_no: item.order_no || ''
};
});
} else {
// 使 API
try {
const response = await axios.get(`../../api/transfer_register/reconcile_detail?transfer_register_id=${transferRegisterId}`);
this.detailDialog.reconcileItems = response.data;
} catch (error) {
console.error('載入沖帳明細失敗:', error);
}
}
},
search_show(curr) {
this.search_dialog.current = curr;
this.search_clear();
this.search_dialog.show = true;
},
search_clear() {
if (!this.search_dialog.current.keys) return;
this.search_dialog.current.keys.forEach((t, i) => { t.value = '' });
this.search_get();
},
search_get() {
if (!this.search_dialog.current.keys) return;
let api_url = this.search_dialog.current.api_url;
let keys = this.search_dialog.current.keys;
this.search_dialog.page = this.options.page ?? 1;
let params = { page: this.search_dialog.page, pageSize: 10 };
var search = {};
keys.forEach((t, i) => {
search[t.id] = t.value;
});
// Dialog is_reconcile
if (this.search_dialog.current.id === 'search5' && this.search_is_reconcile === 'Y') {
search.is_reconcile = 'Y';
}
console.log("search_get", api_url, search, params, this.options);
this.search_dialog.loading = true;
axios.post(api_url, search, { params: params })
.then(response => {
this.search_dialog.list = response.data.list;
this.search_dialog.count = response.data.count;
this.search_dialog.loading = false;
})
.catch(error => {
console.log(error);
this.search_dialog.list = [];
this.search_dialog.count = 0;
this.search_dialog.loading = false;
alert("錯誤:" + error);
});
},
search_headers() {
if (!this.search_dialog.current.columns) return;
let r = [];
this.search_dialog.current.columns.forEach((t, i) => {
r.push({
text: t.title,
width: t.width,
align: 'start',
sortable: false,
value: t.id,
});
});
return r;
},
search_select(row) {
let curr = this.search_dialog.current;
curr.selected = row;
if (curr.select instanceof Function) {
curr.select(this, row);
}
this.search_dialog.show = false;
console.log('Selected row:', row);
},
showItemSelectDialog(item) {
//
this.search_dialog.controls.search5.currentRow = item;
this.search_dialog.current = this.search_dialog.controls.search5;
this.search_is_reconcile = "Y"; //
this.search_clear();
this.search_get(); // Dialog
this.search_dialog.show = true;
},
processBalance(item) {
if (!item.new_status) {
alert('請選擇狀態');
return;
}
if (!item.balance_act_item) {
alert('請先選擇項目');
return;
}
//
const updateData = {
id: item.id,
check_status: item.new_status,
balance_act_item: item.balance_act_item,
verify_note: item.verify_note || ''
};
//
axios.post('../../api/transfer_register/update_balance', updateData)
.then(response => {
const statusText = this.statusOptions.find(opt => opt.value === item.new_status)?.text || '';
alert(`核銷餘額處理完成\n信眾:${item.follower}\n狀態:${statusText}\n項目:${item.selected_items_text}`);
// (95)
if (item.new_status === '95') {
const index = this.items.findIndex(i => i.id === item.id);
if (index !== -1) {
this.items.splice(index, 1);
}
} else {
//
const index = this.items.findIndex(i => i.id === item.id);
if (index !== -1) {
this.items[index].check_status = item.new_status;
this.items[index].verify_note = item.verify_note || '';
this.items[index].balance_act_item = item.balance_act_item;
// selected_items_text
this.items[index].selected_items_text = item.selected_items_text;
}
}
})
.catch(error => {
console.error('更新失敗:', error);
alert('更新失敗,請重試');
});
},
canUpdate(item) {
//
if (!item.balance_act_item) {
return false;
}
//
if (item.new_status === '95') {
return true;
}
//
if (item.new_status === '91' || item.new_status === '92') {
return true;
}
//
return false;
},
}
};
</script>
<style>
.code-textarea textarea {
font-family: 'Courier New', monospace !important;
font-size: 12px !important;
}
/* 增加表格每列高度,讓內容不擁擠 */
.v-data-table.balance-reconcile-table .v-data-table__wrapper tr {
}
.v-data-table.balance-reconcile-table .v-data-table__wrapper td {
min-height: 110px !important;
height: 110px !important;
vertical-align: middle !important;
}
</style>
+300
View File
@@ -0,0 +1,300 @@
<template>
<v-container>
<v-card>
<v-card-title class="bg-info white--text text-center">
<h5 class="mb-0">餘額核銷查詢</h5>
<button class="btn btn-default ms-auto"><i class="mdi mdi-close"></i></button>
</v-card-title>
<v-card-text>
<v-row class="mb-0 mt-4">
<v-col cols="12" md="2">
<v-text-field v-model="query.start_date" label="起始日" type="date" dense outlined></v-text-field>
</v-col>
<v-col cols="12" md="2">
<v-text-field v-model="query.end_date" label="結束日" type="date" dense outlined></v-text-field>
</v-col>
<v-col cols="12" md="3">
<v-text-field v-model="query.activity_name" label="法會" dense outlined readonly>
<template v-slot:append>
<v-btn icon @click="showActivityDialog"><v-icon>mdi-magnify</v-icon></v-btn>
</template>
</v-text-field>
</v-col>
<v-col cols="12" md="3">
<v-text-field v-model="query.follower_name" label="信眾" dense outlined readonly>
<template v-slot:append>
<v-btn icon @click="showFollowerDialog"><v-icon>mdi-magnify</v-icon></v-btn>
</template>
</v-text-field>
</v-col>
<v-col cols="12" md="2" class="d-flex justify-end">
<v-btn color="primary" class="mr-2" @click="search">查詢</v-btn>
<v-btn color="grey" @click="reset">重設</v-btn>
</v-col>
</v-row>
<v-data-table :headers="headers"
:items="items"
:loading="loading"
loading-text="載入中..."
class="elevation-1 balance-reconcile-table"
item-key="id"
:footer-props="{ 'items-per-page-options': [10, 20, 50] }">
<template v-slot:item.follower="{ item }">
<div>
<div class="font-weight-bold">{{ item.follower }}</div>
<div class="caption text--secondary" v-if="item.phone">{{ item.phone }}</div>
<div class="caption text--secondary" v-if="item.phone2">{{ item.phone2 }}</div>
</div>
</template>
<template v-slot:item.bank_info="{ item }">
<div>
<div class="font-weight-bold">{{ item.acc_name }}</div>
<div class="caption text--secondary">{{ item.check_date | date }}</div>
</div>
</template>
<template v-slot:item.amount_info="{ item }">
<div>
<div class="font-weight-bold text-primary">入帳金額{{ item.check_amount || 0 }}</div>
<div class="text-success">核銷金額{{ (item.remain_amount || 0) }}</div>
<!-- 狀態95不會有待核銷不顯示這一行 -->
</div>
</template>
<template v-slot:item.remain_amount="{ item }">
<div class="text-success">{{ item.remain_amount || 0 }}</div>
</template>
<template v-slot:item.select_items="{ item }">
<div style="min-width: 120px;">
{{ item.balance_actitem_name || '未選擇項目' }}
</div>
</template>
<template v-slot:item.detail_info="{ item }">
<v-btn color="info" outlined @click="showDetailDialog(item)">
<v-icon small class="mr-1">mdi-information-outline</v-icon> 詳細
</v-btn>
</template>
<template v-slot:item.verify_note="{ item }">
<div style="white-space: pre-line;">{{ item.verify_note }}</div>
</template>
<template v-slot:item.check_date="{ item }">
<span>{{ item.check_date | date }}</span>
</template>
</v-data-table>
</v-card-text>
</v-card>
<!-- 法會選取 Dialog -->
<v-dialog v-model="activityDialog.show" max-width="700px">
<v-card>
<v-card-title class="grey lighten-2">
<v-icon color="primary" class="mr-2">mdi-table</v-icon>
選擇法會
<v-spacer></v-spacer>
<v-btn icon @click="activityDialog.show = false"><v-icon>mdi-close</v-icon></v-btn>
</v-card-title>
<v-card-text class="mt-4">
<v-text-field v-model="activityDialog.search" label="搜尋法會" dense outlined @keyup.enter="searchActivity"></v-text-field>
<v-data-table :headers="activityDialog.headers"
:items="activityDialog.items"
:loading="activityDialog.loading"
item-key="num"
class="elevation-1 mt-2"
@click:row="selectActivity"
hide-default-footer></v-data-table>
</v-card-text>
</v-card>
</v-dialog>
<!-- 信眾選取 Dialog -->
<v-dialog v-model="followerDialog.show" max-width="700px">
<v-card>
<v-card-title class="grey lighten-2">
<v-icon color="primary" class="mr-2">mdi-account</v-icon>
選擇信眾
<v-spacer></v-spacer>
<v-btn icon @click="followerDialog.show = false"><v-icon>mdi-close</v-icon></v-btn>
</v-card-title>
<v-card-text class="mt-4">
<v-text-field v-model="followerDialog.search" label="搜尋信眾" dense outlined @keyup.enter="searchFollower"></v-text-field>
<v-data-table :headers="followerDialog.headers"
:items="followerDialog.items"
:loading="followerDialog.loading"
item-key="num"
class="elevation-1 mt-2"
@click:row="selectFollower"
hide-default-footer></v-data-table>
</v-card-text>
</v-card>
</v-dialog>
<!-- 詳細資訊對話框 -->
<v-dialog v-model="dialog.show" max-width="900px">
<v-card>
<v-card-title class="grey lighten-2">
<v-icon color="info" class="mr-2">mdi-information-outline</v-icon>
詳細資訊
<v-spacer></v-spacer>
<v-btn icon @click="dialog.show = false">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<v-card-text>
<div v-if="dialog.selected">
<v-row>
<v-col cols="12" md="6">
<h6 class="mb-3 text-primary">匯款人資訊</h6>
<div class="mb-2"><span class="font-weight-bold">姓名</span>{{ dialog.selected.name }}</div>
<div class="mb-2"><span class="font-weight-bold">電話</span>{{ dialog.selected.phone }}</div>
</v-col>
<v-col cols="12" md="6">
<h6 class="mb-3 text-success">入帳資訊</h6>
<div class="mb-2"><span class="font-weight-bold">入帳帳戶</span>{{ dialog.selected.acc_name }}</div>
<div class="mb-2"><span class="font-weight-bold">入帳日期</span>{{ dialog.selected.check_date | date }}</div>
<div class="mb-2"><span class="font-weight-bold">入帳金額</span>{{ dialog.selected.check_amount }}</div>
</v-col>
</v-row>
<v-divider class="my-4"></v-divider>
<v-row>
<v-col cols="12" md="6">
<h6 class="mb-3 text-purple">活動資訊</h6>
<div class="mb-2"><span class="font-weight-bold">活動名稱</span>{{ dialog.selected.activity_name || '-' }}</div>
</v-col>
<v-col cols="12" md="6">
<h6 class="mb-3 text-info">核對記錄</h6>
<div class="mb-2"><span class="font-weight-bold">核對記錄</span>{{ dialog.selected.verify_note || '-' }}</div>
</v-col>
</v-row>
</div>
</v-card-text>
</v-card>
</v-dialog>
</v-container>
</template>
<style>
.v-data-table.balance-reconcile-table .v-data-table__wrapper tbody tr {
min-height: 90px !important;
height: 90px !important;
}
.v-data-table.balance-reconcile-table .v-data-table__wrapper tbody td {
min-height: 90px !important;
height: 90px !important;
vertical-align: middle !important;
}
</style>
<script>
module.exports = {
data() {
return {
loading: false,
query: {
start_date: '',
end_date: '',
activity_num: '',
activity_name: '',
follower_num: '',
follower_name: ''
},
headers: [
{ text: '信眾', value: 'follower' },
{ text: '入帳帳戶/日期', value: 'bank_info' },
{ text: '核銷日期', value: 'check_date', sortable: true, width: '120px' },
{ text: '核銷項目', value: 'select_items', sortable: false, width: '120px' },
{ text: '核銷金額', value: 'reconcile_amount', sortable: false, width: '120px' },
{ text: '詳細資訊', value: 'detail_info', sortable: false },
// { text: '', value: 'status', sortable: false, width: '100px' }, //
{ text: '核對記錄', value: 'verify_note', sortable: false, width: '180px' },
],
items: [],
dialog: {
show: false,
selected: null
},
activityDialog: {
show: false,
search: '',
loading: false,
items: [],
headers: [
{ text: '編號', value: 'num' },
{ text: '名稱', value: 'subject' }
]
},
followerDialog: {
show: false,
search: '',
loading: false,
items: [],
headers: [
{ text: '編號', value: 'num' },
{ text: '姓名', value: 'u_name' }
]
}
}
},
filters: {
date(val) {
if (!val) return '';
const date = new Date(val);
return date.toLocaleDateString();
}
},
methods: {
// 使 DraftUtils
search() {
this.loading = true;
// API
axios.get('../../api/transfer_register/balance_reconcile_query', { params: this.query })
.then(res => { this.items = res.data; })
.catch(() => { this.items = []; })
.finally(() => { this.loading = false; });
},
reset() {
this.query.start_date = '';
this.query.end_date = '';
this.query.activity_num = '';
this.query.activity_name = '';
this.query.follower_num = '';
this.query.follower_name = '';
this.items = [];
},
showDetailDialog(item) {
this.dialog.selected = item;
this.dialog.show = true;
},
showActivityDialog() {
this.activityDialog.show = true;
this.searchActivity();
},
searchActivity() {
this.activityDialog.loading = true;
axios.get('../../api/activity', { params: { keyword: this.activityDialog.search } })
.then(res => { this.activityDialog.items = res.data; })
.catch(() => { this.activityDialog.items = []; })
.finally(() => { this.activityDialog.loading = false; });
},
selectActivity(row) {
this.query.activity_num = row.num;
this.query.activity_name = row.subject;
this.activityDialog.show = false;
},
showFollowerDialog() {
this.followerDialog.show = true;
this.searchFollower();
},
searchFollower() {
this.followerDialog.loading = true;
axios.post('../../api/follower/GetList', { u_name: this.followerDialog.search }, { params: { page: 1, pageSize: 10 } })
.then(res => { this.followerDialog.items = res.data.list; })
.catch(() => { this.followerDialog.items = []; })
.finally(() => { this.followerDialog.loading = false; });
},
selectFollower(row) {
this.query.follower_num = row.num;
this.query.follower_name = row.u_name;
this.followerDialog.show = false;
}
}
};
</script>
+657
View File
@@ -0,0 +1,657 @@
<template>
<v-container>
<v-card>
<v-card-title class="bg-primary white--text text-center">
<h5 class="mb-0">共同 - 沖帳流程</h5>
<button class="btn btn-default ms-auto"><i class="mdi mdi-close"></i></button>
</v-card-title>
<v-card-text>
<v-data-table :headers="headers"
:items="items"
:loading="loading"
loading-text="載入中..."
class="elevation-1"
item-key="id">
<template v-slot:item.follower="{ item }">
<span :title="item.f_num">{{ item.follower }}</span>
</template>
<template v-slot:item.activity_info="{ item }">
<div>
<div class="font-weight-bold">{{ item.activity_name }}</div>
<div class="caption text--secondary">
<span v-if="hasFollowerList(item.draft)" style="margin-right: 4px;">👥</span>
{{ item.acc_name }}
</div>
</div>
</template>
<template v-slot:item.check_date="{ item }">
<span>{{ item.check_date | date }}</span>
</template>
<template v-slot:item.check_memo="{ item }">
<span>{{ item.check_memo }}</span>
</template>
<template v-slot:item.verify_note="{ item }">
<span>{{ item.verify_note }}</span>
</template>
<template v-slot:item.follower_selection="{ item }">
<div>
<v-btn small
color="primary"
outlined
@click="showFollowerSelection(item)"
class="mb-1">
<v-icon left small>mdi-account-multiple</v-icon>
選擇支付人
</v-btn>
<div v-if="hasFollowerList(item.draft)" class="caption text-success mt-1">
<v-icon small color="success">mdi-check-circle</v-icon>
已選擇 {{ getFollowerCount(item.draft) }}
</div>
</div>
</template>
<template v-slot:item.actions="{ item }">
<v-btn small
color="success"
@click="showGroupReconcileDialog(item)"
:disabled="!hasFollowerList(item.draft)">
<v-icon left small>mdi-receipt</v-icon>
{{ hasFollowerList(item.draft) ? '共同沖帳' : '請先選擇支付人' }}
</v-btn>
</template>
</v-data-table>
</v-card-text>
</v-card>
<!-- 選擇共同支付人對話框 -->
<v-dialog v-model="followerDialog.show" max-width="800px">
<v-card>
<v-card-title class="grey lighten-2">
<v-icon color="primary" class="mr-2">mdi-account-multiple</v-icon>
選擇共同支付人
<v-spacer></v-spacer>
<v-btn icon @click="followerDialog.show = false">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<v-card-text class="mt-4">
<div v-if="followerDialog.selected">
<h6 class="mb-3">法會{{ followerDialog.selected.activity_name }}</h6>
<v-text-field v-model="followerDialog.search"
label="搜尋信眾"
dense
outlined
prepend-inner-icon="mdi-magnify"
@input="searchActivityFollowers"></v-text-field>
<v-data-table :headers="followerDialog.headers"
:items="followerDialog.items"
:loading="followerDialog.loading"
item-key="f_num"
class="elevation-1 mt-2"
show-select
v-model="followerDialog.selectedFollowers"
hide-default-footer
:disable-pagination="true">
<template v-slot:item.follower_name="{ item }">
<div>
<div class="font-weight-bold">{{ item.follower_name }}</div>
<div class="caption text--secondary">編號: {{ item.f_num }}</div>
</div>
</template>
<template v-slot:item.total_due="{ item }">
<span class="text-danger">{{ item.total_due | currency }}</span>
</template>
<template v-slot:item.item_count="{ item }">
<span class="text-info">{{ item.item_count }} </span>
</template>
</v-data-table>
</div>
</v-card-text>
<v-card-actions class="pa-4">
<v-spacer></v-spacer>
<v-btn color="grey" @click="followerDialog.show = false">取消</v-btn>
<v-btn color="primary" @click="confirmFollowerSelection" :disabled="followerDialog.selectedFollowers.length === 0">
確認選擇 ({{ followerDialog.selectedFollowers.length }})
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- 共同沖帳明細對話框 -->
<v-dialog v-model="reconcileDialog.show" max-width="1200px">
<v-card>
<v-card-title class="grey lighten-2">
<v-icon color="success" class="mr-2">mdi-receipt</v-icon>
共同沖帳明細
<v-spacer></v-spacer>
<v-btn icon @click="reconcileDialog.show = false">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<v-card-text class="mb-0 pb-0">
<div v-if="reconcileDialog.selected">
<div class="row my-2">
<h6 class="col">共同支付人{{ getSelectedFollowersText() }}</h6>
<div class="col">
<span class="font-weight-bold">入帳金額</span>
<span class="text-primary">{{ reconcileDialog.selected.check_amount | currency }}</span>
</div>
<div class="col">
<span class="font-weight-bold">已沖金額</span>
<span :class="{'text-danger': isOverPaid, 'text-dark': !isOverPaid}">{{ sumReconcile | currency }}</span>
</div>
<div class="col">
<span class="font-weight-bold">未繳餘款</span>
<span class="text-danger">{{ remainDue | currency }}</span>
</div>
<div class="col">
<span class="font-weight-bold">入帳後餘額</span>
<span class="text-success">{{ overPaid | currency }}</span>
</div>
</div>
<v-data-table :headers="reconcileDialog.headers"
:items="reconcileDialog.items"
class="elevation-1 mt-3"
hide-default-footer
:disable-pagination="true">
<template v-slot:item.follower_info="{ item }">
<div>
<div class="font-weight-bold text-primary">{{ item.follower_name }}</div>
<div class="text-muted" style="font-size:12px;">{{ item.order_no }}</div>
</div>
</template>
<template v-slot:item.activity_name="{ item }">
<div>
<div>{{ item.activity_name }}</div>
<div class="text-muted" style="font-size:12px;">{{ item.reg_time | date }}</div>
</div>
</template>
<template v-slot:item.paid="{ item }">
<span>{{ item.paid | currency }}</span>
</template>
<template v-slot:item.due="{ item }">
<span>{{ item.due | currency }}</span>
</template>
<template v-slot:item.reconcile="{ item, index }">
<v-text-field v-model="item.reconcile"
type="number"
dense
outlined
hide-details="auto"
:rules="[
v=>
!isNaN(Number(v)) || '請輸入數字',
v => Number(v) >= 0 || '不可小於 0',
v => Number(v) <= Number(item.due) || `不可大於待繳金額 ${item.due}`
]"
@blur="validateAndUpdateReconcile($event.target.value, item, index)"
>
</v-text-field>
</template>
</v-data-table>
</div>
</v-card-text>
<v-card-actions class="pa-4">
<div>
<div v-if="hasUnallocated && remainDue > 0" class="text-dark mb-2">
尚有未分配的入帳金額請確認是否全部分配
</div>
<div v-if="hasUnallocated && remainDue === 0" class="text-info mb-2">
已無未繳項目剩餘入帳金額將成為餘額
</div>
<div v-if="!canConfirm && buttonErrorMessage" class="text-danger">
{{ buttonErrorMessage }}
</div>
</div>
<v-spacer></v-spacer>
<v-btn color="info" @click="redistributeReconcile" class="mr-2">重新分配</v-btn>
<v-btn color="orange" @click="saveDraft" class="mr-2">暫存</v-btn>
<v-btn color="primary" @click="confirmGroupReconcile" :disabled="!canConfirm">確認沖帳</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-container>
</template>
<script>
if (typeof window.DraftUtils === 'undefined') {
console.warn('DraftUtils 未載入,使用備用方案');
window.DraftUtils = {
hasFollowerList: function (draft) { return false; },
getFollowerList: function (draft) { return []; },
updateFollowerList: function (draft, list) {
return { follower_list: list };
},
getDraftField: function (draft, field) { return null; },
updateDraftField: function (draft, field, value) {
return { [field]: value };
}
};
}
module.exports = {
data() {
return {
loading: false,
headers: [
{ text: '匯款人', value: 'follower' },
{ text: '法會/入帳帳戶', value: 'activity_info' },
{ text: '入帳日期', value: 'check_date' },
{ text: '帳簿備註', value: 'check_memo' },
{ text: '入帳金額', value: 'check_amount' },
{ text: '核對記錄', value: 'verify_note' },
{ text: '選擇共同支付人', value: 'follower_selection', sortable: false },
{ text: '共同沖帳', value: 'actions', sortable: false }
],
items: [],
followerDialog: {
show: false,
selected: null,
search: '',
loading: false,
items: [],
selectedFollowers: [],
headers: [
{ text: '信眾', value: 'follower_name' },
{ text: '待繳金額', value: 'total_due' },
{ text: '項目數', value: 'item_count' }
]
},
reconcileDialog: {
show: false,
selected: null,
headers: [
{ text: '信眾/報名單號', value: 'follower_info' },
{ text: '法會/報名日期', value: 'activity_name' },
{ text: '項目', value: 'actitem_name' },
{ text: '應繳金額', value: 'price', sortable: false },
{ text: '已繳金額', value: 'paid', sortable: false },
{ text: '待繳金額', value: 'due', sortable: false },
{ text: '沖帳金額', value: 'reconcile', sortable: false }
],
items: [],
loading: false,
errorMessage: ''
},
hasUnallocated: false,
draftDataChanged: false
}
},
computed: {
sumReconcile() {
return this.reconcileDialog.items.reduce((sum, item) => sum + (Number(item.reconcile) || 0), 0);
},
remainDue() {
const totalDue = this.reconcileDialog.items.reduce((sum, item) => sum + (Number(item.due) || 0), 0);
return totalDue - this.sumReconcile;
},
overPaid() {
if (!this.reconcileDialog.selected) return 0;
return this.reconcileDialog.selected.check_amount - this.sumReconcile;
},
isOverPaid() {
if (!this.reconcileDialog.selected) return false;
return this.sumReconcile > this.reconcileDialog.selected.check_amount;
},
canConfirm() {
if (!this.reconcileDialog.selected) return false;
const hasReconcile = this.reconcileDialog.items.some(item => Number(item.reconcile) > 0);
if (!hasReconcile) return false;
const validAmounts = this.reconcileDialog.items.every(item => {
const amount = Number(item.reconcile) || 0;
return amount >= 0 && amount <= Number(item.due);
});
if (!validAmounts) return false;
if (this.sumReconcile > this.reconcileDialog.selected.check_amount) return false;
if (this.hasUnallocated && this.remainDue > 0) return false;
return true;
},
buttonErrorMessage() {
if (!this.reconcileDialog.selected) return '';
const hasReconcile = this.reconcileDialog.items.some(item => Number(item.reconcile) > 0);
if (!hasReconcile) return '請至少輸入一筆沖帳金額';
const invalidItem = this.reconcileDialog.items.find(item => {
const amount = Number(item.reconcile) || 0;
return amount < 0 || amount > Number(item.due);
});
if (invalidItem) return '沖帳金額超出可沖帳範圍';
if (this.sumReconcile > this.reconcileDialog.selected.check_amount) {
return '已沖金額不可大於入帳金額';
}
if (this.hasUnallocated && this.remainDue > 0) {
return '尚有未繳項目,請將入帳金額完全分配';
}
return '';
}
},
mounted() {
this.loadTableData();
},
filters: {
currency(val) {
if (!val) return '0';
return Number(val).toLocaleString();
},
date(val) {
if (!val) return '';
const date = new Date(val);
return date.toLocaleDateString();
}
},
methods: {
// follower_list
hasFollowerList(draft) {
return window.DraftUtils && window.DraftUtils.hasFollowerList && window.DraftUtils.hasFollowerList(draft);
},
//
getFollowerCount(draft) {
if (!window.DraftUtils || !window.DraftUtils.getFollowerList) return 0;
const followerList = window.DraftUtils.getFollowerList(draft);
return followerList ? followerList.length : 0;
},
loadTableData() {
this.loading = true;
axios.get('../../api/transfer_register/group_reconcile_list')
.then(res => {
this.items = res.data;
})
.catch(() => {
this.items = [];
})
.finally(() => {
this.loading = false;
});
},
showGroupReconcileDialog(item) {
//
const followerList = window.DraftUtils.getFollowerList(item.draft);
if (followerList && followerList.length > 0) {
//
this.showReconcileDetail(item, followerList);
} else {
//
this.showFollowerSelection(item);
}
},
showFollowerSelection(item) {
this.followerDialog.selected = item;
this.followerDialog.selectedFollowers = [];
this.followerDialog.items = [];
this.followerDialog.show = true;
this.searchActivityFollowers();
},
searchActivityFollowers() {
if (!this.followerDialog.selected || !this.followerDialog.selected.activity_num) return;
this.followerDialog.loading = true;
axios.get('../../api/transfer_register/activity_followers', {
params: { activity_num: this.followerDialog.selected.activity_num }
})
.then(res => {
let items = res.data;
//
if (this.followerDialog.search && this.followerDialog.search.trim()) {
const keyword = this.followerDialog.search.trim().toLowerCase();
items = items.filter(item =>
item.follower_name.toLowerCase().includes(keyword)
);
}
this.followerDialog.items = items;
})
.catch(() => {
this.followerDialog.items = [];
})
.finally(() => {
this.followerDialog.loading = false;
});
},
confirmFollowerSelection() {
if (this.followerDialog.selectedFollowers.length === 0) {
alert('請選擇至少一位共同支付人');
return;
}
if (!this.followerDialog.selected) {
alert('系統錯誤:未選擇記錄');
return;
}
// draft
const followerList = this.followerDialog.selectedFollowers.map(f => ({
f_num: f.f_num,
f_name: f.follower_name,
activity_num: this.followerDialog.selected.activity_num
}));
const draftData = window.DraftUtils.updateFollowerList(this.followerDialog.selected.draft, followerList);
this.updateFollowerDraftToDB(this.followerDialog.selected.id, draftData)
.then(() => {
this.followerDialog.selected.draft = JSON.stringify(draftData);
this.followerDialog.show = false;
//
this.loadTableData();
//
this.showReconcileDetail(this.followerDialog.selected, followerList);
})
.catch(err => {
alert('儲存失敗,請重試');
console.error(err);
});
},
showReconcileDetail(item, followerList) {
this.reconcileDialog.selected = item;
this.reconcileDialog.items = [];
this.reconcileDialog.show = true;
//
const fNums = followerList.map(f => f.f_num).join(',');
axios.get('../../api/transfer_register/group_follower_orders', {
params: {
activity_num: item.activity_num,
f_nums: fNums
}
})
.then(res => {
this.reconcileDialog.items = res.data.map(item => ({
...item,
reconcile: 0 //
}));
this.autoDistributeReconcile();
})
.catch(() => {
this.reconcileDialog.items = [];
this.updateSumReconcile();
});
},
getSelectedFollowersText() {
if (!this.reconcileDialog.selected) return '';
const followerList = window.DraftUtils.getFollowerList(this.reconcileDialog.selected.draft);
return followerList.map(f => f.f_name).join('、');
},
autoDistributeReconcile() {
//
let remainAmount = this.reconcileDialog.selected ? this.reconcileDialog.selected.check_amount : 0;
// reconcile 0
this.reconcileDialog.items.forEach(item => {
this.$set(item, 'reconcile', 0);
});
//
const sortedItems = [...this.reconcileDialog.items].sort((a, b) =>
new Date(a.reg_time) - new Date(b.reg_time)
);
//
sortedItems.forEach(item => {
if (remainAmount > 0) {
const canPay = Math.min(item.due, remainAmount);
const originalItem = this.reconcileDialog.items.find(i => i === item);
if (originalItem) {
this.$set(originalItem, 'reconcile', canPay);
}
remainAmount -= canPay;
}
});
this.updateSumReconcile();
},
redistributeReconcile() {
this.autoDistributeReconcile();
},
updateSumReconcile() {
const maxTotal = this.reconcileDialog.selected ? (this.reconcileDialog.selected.check_amount || 0) : 0;
this.hasUnallocated = maxTotal > this.sumReconcile;
},
saveDraft() {
try {
//
const followerList = window.DraftUtils.getFollowerList(this.reconcileDialog.selected.draft);
const reconcileData = this.reconcileDialog.items
.filter(item => Number(item.reconcile) > 0)
.map(item => ({
f_num: item.f_num,
follower_name: item.follower_name,
pro_order_detail_num: item.num,
reconcile: Number(item.reconcile)
}));
const draftData = {
transfer_draft: [],
pro_order_detail_items: reconcileData,
follower_list: followerList
};
this.updateDraftToDB(this.reconcileDialog.selected.id, draftData)
.then(() => {
alert('暫存成功!');
this.reconcileDialog.selected.draft = JSON.stringify(draftData);
});
} catch (e) {
alert('暫存失敗:資料格式錯誤');
}
},
updateFollowerDraftToDB(id, draftData) {
const selectedItem = this.followerDialog.selected;
const updateData = {
id: id,
activity_num: selectedItem.activity_num,
name: selectedItem.name,
phone: selectedItem.phone,
pay_type: selectedItem.pay_type,
account_last5: selectedItem.account_last5,
amount: selectedItem.amount,
pay_mode: selectedItem.pay_mode,
note: selectedItem.note,
proof_img: selectedItem.proof_img,
status: selectedItem.status,
f_num_match: selectedItem.f_num_match,
f_num: selectedItem.f_num,
acc_num: selectedItem.acc_num,
check_date: selectedItem.check_date,
check_amount: selectedItem.check_amount,
check_memo: selectedItem.check_memo,
check_status: selectedItem.check_status,
acc_kind: selectedItem.acc_kind,
member_num: selectedItem.member_num,
verify_time: selectedItem.verify_time,
verify_note: selectedItem.verify_note,
draft: JSON.stringify(draftData)
};
return axios.put(`../../api/transfer_register/${id}`, updateData);
},
updateDraftToDB(id, draftData) {
const updateData = {
id: id,
activity_num: this.reconcileDialog.selected.activity_num,
name: this.reconcileDialog.selected.name,
phone: this.reconcileDialog.selected.phone,
pay_type: this.reconcileDialog.selected.pay_type,
account_last5: this.reconcileDialog.selected.account_last5,
amount: this.reconcileDialog.selected.amount,
pay_mode: this.reconcileDialog.selected.pay_mode,
note: this.reconcileDialog.selected.note,
proof_img: this.reconcileDialog.selected.proof_img,
status: this.reconcileDialog.selected.status,
f_num_match: this.reconcileDialog.selected.f_num_match,
f_num: this.reconcileDialog.selected.f_num,
acc_num: this.reconcileDialog.selected.acc_num,
check_date: this.reconcileDialog.selected.check_date,
check_amount: this.reconcileDialog.selected.check_amount,
check_memo: this.reconcileDialog.selected.check_memo,
check_status: this.reconcileDialog.selected.check_status,
acc_kind: this.reconcileDialog.selected.acc_kind,
member_num: this.reconcileDialog.selected.member_num,
verify_time: this.reconcileDialog.selected.verify_time,
verify_note: this.reconcileDialog.selected.verify_note,
draft: JSON.stringify(draftData)
};
return axios.put(`../../api/transfer_register/${id}`, updateData);
},
confirmGroupReconcile() {
if (!this.canConfirm) return;
this.reconcileDialog.loading = true;
const overPayment = this.reconcileDialog.selected.check_amount - this.sumReconcile;
const postData = {
transfer_register_id: this.reconcileDialog.selected.id,
details: this.reconcileDialog.items
.filter(item => item.reconcile > 0)
.map(item => ({
f_num: item.f_num,
pro_order_detail_num: item.num,
amount: Number(item.reconcile),
reg_time: new Date().toISOString()
})),
over_payment: overPayment
};
axios.post('../../api/transfer_register/group_reconcile', postData)
.then(res => {
const message = res.data && res.data.message ? res.data.message : '共同沖帳完成';
alert(message);
this.reconcileDialog.show = false;
this.loadTableData(); //
})
.catch(err => {
let errorMessage = '沖帳失敗,請聯繫系統管理員';
if (err.response && err.response.data) {
if (typeof err.response.data === 'string') {
errorMessage = err.response.data;
} else if (err.response.data.message) {
errorMessage = err.response.data.message;
}
}
alert(errorMessage);
})
.finally(() => {
this.reconcileDialog.loading = false;
});
},
validateAndUpdateReconcile(value, item, index) {
let numValue = Number(value);
if (isNaN(numValue)) {
numValue = 0;
}
numValue = Math.round(numValue);
this.$set(item, 'reconcile', numValue);
this.updateSumReconcile();
}
}
};
</script>
+295
View File
@@ -0,0 +1,295 @@
<%@ Page Title="匯款/沖帳管理" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" EnableEventValidation="false" CodeFile="index.aspx.cs" Inherits="admin_bill_index" %>
<asp:Content ID="Content1" ContentPlaceHolderID="page_header" runat="Server">
<link rel="stylesheet" href="../../js/_bootstrap-icons-1.8.1/bootstrap-icons.css">
<style>
.function-icon {
font-size: 2em;
line-height: 1;
align-content: center;
}
.external-link-icon {
font-size: 0.8em;
}
.modify_modal{
width:calc(100vw-20%);
background-color:white;
opacity:0;
}
</style>
<script src="/js//httpVueLoader.js"></script>
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="page_nav" runat="Server">
<h2 class="mb-3">匯款/沖帳管理</h2>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
<v-container>
<div id="content" class="container py-4">
<div class="row">
<!-- 第一欄:匯款登錄與核對 -->
<div class="col-lg-4 mb-4">
<h5 class="text-primary mb-3">
<i class="bi bi-upload"></i> 匯款登錄與核對
</h5>
<div class="list-group">
<a @click="show_register()" class="list-group-item list-group-item-action" >
<div class="d-flex justify-content-between align-items-start">
<div class="d-flex">
<i class="bi bi-plus-circle text-success me-3 function-icon"></i>
<div>
<div>
登錄匯款資料
<i class="bi bi-box-arrow-up-right text-muted ms-1 external-link-icon"></i>
</div>
<small class="text-muted">報名者自行填寫匯款相關資訊</small>
</div>
</div>
<span class="badge bg-primary">報名者</span>
</div>
</a>
<a @click="show_verify()" class="list-group-item list-group-item-action d-none">
<div class="d-flex justify-content-between align-items-start">
<div class="d-flex">
<i class="bi bi-person-check text-info me-3 function-icon"></i>
<div>
<div>出納核對匯款人</div>
<small class="text-muted">核對匯款人身份與報名資料</small>
</div>
</div>
<span class="badge bg-info">出納</span>
</div>
</a>
<a @click="show_verify()" class="list-group-item list-group-item-action">
<div class="d-flex justify-content-between align-items-start">
<div class="d-flex">
<i class="bi bi-person-check text-info me-3 function-icon"></i>
<div>
<div>出納核對匯款人</div>
<small class="text-muted">初步核對匯款人身份資料</small>
</div>
</div>
<span class="badge bg-info">出納</span>
</div>
</a>
<%-- <a href="verify2.aspx" class="list-group-item list-group-item-action">
<div class="d-flex justify-content-between align-items-start">
<div class="d-flex">
<i class="bi bi-currency-dollar text-warning me-3 function-icon"></i>
<div>
<div>出納核對金額(階段2</div>
<small class="text-muted">核對匯款金額與入帳資料</small>
</div>
</div>
<span class="badge bg-warning text-dark">出納</span>
</div>
</a>--%>
</div>
</div>
<!-- 第二欄:沖帳流程 -->
<div class="col-lg-4 mb-4">
<h5 class="text-primary mb-3">
<i class="bi bi-receipt"></i> 沖帳流程
</h5>
<div class="list-group">
<a @click="personal_reconcile()" class="list-group-item list-group-item-action">
<div class="d-flex justify-content-between align-items-start">
<div class="d-flex">
<i class="bi bi-person text-primary me-3 function-icon"></i>
<div>
<div>個人-沖帳流程</div>
<small class="text-muted">處理個人匯款的沖帳作業</small>
</div>
</div>
<span class="badge bg-success">會計</span>
</div>
</a>
<a @click="group_reconcile()" class="list-group-item list-group-item-action">
<div class="d-flex justify-content-between align-items-start">
<div class="d-flex">
<i class="bi bi-people text-success me-3 function-icon"></i>
<div>
<div>共同-沖帳流程</div>
<small class="text-muted">處理多人共同支付的沖帳作業</small>
</div>
</div>
<span class="badge bg-success">會計</span>
</div>
</a>
<a @click="balance_reconcile()" class="list-group-item list-group-item-action">
<div class="d-flex justify-content-between align-items-start">
<div class="d-flex">
<i class="bi bi-calculator text-danger me-3 function-icon"></i>
<div>
<div>餘額核銷</div>
<small class="text-muted">處理沖帳後剩餘金額的核銷</small>
</div>
</div>
<span class="badge bg-danger">會計</span>
</div>
</a>
</div>
</div>
<!-- 第三欄:查詢功能 -->
<div class="col-lg-4 mb-4">
<h5 class="text-primary mb-3">
<i class="bi bi-search"></i> 查詢功能
</h5>
<div class="list-group">
<a @click="verify_query()" class="list-group-item list-group-item-action">
<div class="d-flex justify-content-between align-items-start">
<div class="d-flex">
<i class="bi bi-journal-check text-info me-3 function-icon"></i>
<div>
<div>沖帳查詢</div>
<small class="text-muted">查詢所有沖帳記錄與明細</small>
</div>
</div>
<span class="badge bg-info">會計</span>
</div>
</a>
<a @click="balance_query()" class="list-group-item list-group-item-action">
<div class="d-flex justify-content-between align-items-start">
<div class="d-flex">
<i class="bi bi-file-text text-secondary me-3 function-icon"></i>
<div>
<div>餘額核銷查詢</div>
<small class="text-muted">查詢已完成的餘額核銷記錄</small>
</div>
</div>
<span class="badge bg-secondary">會計</span>
</div>
</a>
<a @click="balance_query()" class="list-group-item list-group-item-action">
<div class="d-flex justify-content-between align-items-start">
<div class="d-flex">
<i class="bi bi-file-spreadsheet text-secondary me-3 function-icon"></i>
<div>
<div>應收應付(依活動)</div>
<small class="text-muted"></small>
</div>
</div>
<span class="badge bg-secondary">會計</span>
</div>
</a>
<a @click="balance_query()" class="list-group-item list-group-item-action">
<div class="d-flex justify-content-between align-items-start">
<div class="d-flex">
<i class="bi bi-file-spreadsheet text-secondary me-3 function-icon"></i>
<div>
<div>應收應付(依信眾)</div>
<small class="text-muted"></small>
</div>
</div>
<span class="badge bg-secondary">會計</span>
</div>
</a>
</div>
</div>
</div>
<!-- 統計資訊 -->
<div class="row mt-4">
<div class="col-12">
<div class="alert alert-info">
<h6 class="alert-heading">
<i class="bi bi-info-circle"></i> 系統說明
</h6>
<ul class="mb-0">
<li><strong>匯款登錄與核對</strong>:處理報名者匯款資料的登錄與出納核對作業</li>
<li><strong>沖帳流程</strong>:處理個人與共同支付的沖帳作業,以及剩餘金額的核銷</li>
<li><strong>查詢功能</strong>:提供各類沖帳記錄的查詢與統計功能</li>
</ul>
</div>
</div>
</div>
</div>
<v-dialog v-model="modify_dialog.show" class="modify_modal">
<template>
<keep-alive>
<component :is="currentView" @close-dialog="modify_dialog.show=false"></component>
</keep-alive>
</template>
</v-dialog>
</v-container>
</asp:Content>
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" runat="Server">
<script src="../transfer/draft-utils.js"></script>
<script>
let VueApp = new Vue({
el: '#app',
vuetify: new Vuetify(vuetify_options),
data() {
return {
modify_dialog: {
show:false
},
externalHtml: "",
currentView:null
};
},
created() {
//this.loadActivities();
},
components: {
'register-component': httpVueLoader('./register.vue'),
'verify-component': httpVueLoader('./verify.vue'),
'group-component': httpVueLoader('./group_reconcile.vue'),
'personal-component': httpVueLoader('./personal_reconcile.vue'),
'balance-component': httpVueLoader('./balance_reconcile.vue'),
'verify_query-component': httpVueLoader('./verify_order_record_query.vue'),
'balance_query-component': httpVueLoader('./balance_reconcile_query.vue')
},
methods: {
async balance_query() {
this.modify_dialog.show = true
this.currentView = 'balance_query-component'
},
async verify_query(){
this.modify_dialog.show = true
this.currentView = 'verify_query-component'
},
async balance_reconcile() {
this.modify_dialog.show = true
this.currentView = 'balance-component'
},
async personal_reconcile() {
this.modify_dialog.show = true
this.currentView = 'personal-component'
},
async group_reconcile() {
this.modify_dialog.show = true
this.currentView = 'group-component'
},
async show_verify() {
this.modify_dialog.show = true
this.currentView = 'verify-component'
},
async show_register() {
this.modify_dialog.show = true
this.currentView ='register-component'
},
loadActivities() {
const today = new Date().toISOString().split('T')[0];
axios.get(`../../api/activity?endDate<=${today}`)
.then(response => {
this.activities = response.data;
})
.catch(error => {
console.error('載入活動列表失敗:', error);
alert('載入活動列表失敗,請重新整理頁面');
});
},
}
})
</script>
</asp:Content>
+15
View File
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class admin_bill_index : MyWeb.config
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
+510
View File
@@ -0,0 +1,510 @@
<template>
<v-container>
<v-card>
<v-card-title class="bg-primary white--text text-center">
<h5 class="mb-0">個人 - 沖帳流程</h5>
<button class="btn btn-default ms-auto" ><i class="mdi mdi-close"></i></button>
</v-card-title>
<v-card-text>
<v-data-table :headers="headers"
:items="items"
:loading="loading"
loading-text="載入中..."
class="elevation-1"
item-key="id">
<template v-slot:item.follower="{ item }">
<span :title="item.f_num">{{ item.follower }}</span>
</template>
<template v-slot:item.acc_name="{ item }">
<span>
<span v-if="hasTransferDraft(item.draft)" style="margin-right: 4px;">📝</span>{{ item.acc_name }}
</span>
</template>
<template v-slot:item.check_date="{ item }">
<span>{{ item.check_date | date }}</span>
</template>
<template v-slot:item.check_memo="{ item }">
<span>{{ item.check_memo }}</span>
</template>
<template v-slot:item.check_status="{ item }">
<span>{{ item.check_status }}</span>
</template>
<template v-slot:item.verify_note="{ item }">
<span>{{ item.verify_note }}</span>
</template>
<template v-slot:item.actions="{ item }">
<v-btn small
color="success"
@click="showReconcileDialog(item)">
沖帳
</v-btn>
</template>
</v-data-table>
</v-card-text>
</v-card>
<!-- 沖帳明細對話框 -->
<v-dialog v-model="dialog.show" max-width="960px">
<v-card>
<v-card-title class="grey lighten-2">
<span v-if="dialog.selected && hasTransferDraft(dialog.selected.draft)" style="margin-right: 8px;">📝</span>沖帳明細
<v-spacer></v-spacer>
<v-btn icon @click="dialog.show = false">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<v-card-text class="mb-0 pb-0">
<div v-if="dialog.selected">
<div class="row my-2">
<h6 class="col">信眾{{ dialog.selected.follower }}</h6>
<div class="col">
<span class="font-weight-bold">入帳金額</span>
<span class="text-primary">{{ dialog.selected.check_amount | currency }}</span>
</div>
<div class="col">
<span class="font-weight-bold">已沖金額</span>
<span :class="{'text-danger': isOverPaid, 'text-dark': !isOverPaid}">{{ sumReconcile | currency }}</span>
</div>
<div class="col">
<span class="font-weight-bold">未繳餘款</span>
<span class="text-danger">{{ remainDue | currency }}</span>
</div>
<div class="col">
<span class="font-weight-bold">入帳後餘額</span>
<span class="text-success">{{ overPaid | currency }}</span>
</div>
</div>
<v-data-table :headers="dialog.headers"
:items="dialog.items"
class="elevation-1 mt-3"
hide-default-footer
:disable-pagination="true">
<template v-slot:item.activity_name="{ item }">
<div>
<div>{{ item.activity_name }}</div>
<div class="text-muted" style="font-size:12px;">{{ item.order_no }}</div>
</div>
</template>
<template v-slot:item.paid="{ item }">
<span>{{ item.paid | currency }}</span>
</template>
<template v-slot:item.due="{ item }">
<span>{{ item.due | currency }}</span>
</template>
<template v-slot:item.reg_time="{ item }">
<span>{{ item.reg_time | date }}</span>
</template>
<template v-slot:item.reconcile="{ item, index }">
<v-text-field v-model="item.reconcile"
type="number"
dense
outlined
hide-details="auto"
:rules="[
v=>
!isNaN(Number(v)) || '請輸入數字',
v => Number(v) >= 0 || '不可小於 0',
v => Number(v) <= Number(item.due) || `不可大於待繳金額 ${item.due}`
]"
@blur="validateAndUpdateReconcile($event.target.value, item, index)"
>
</v-text-field>
</template>
</v-data-table>
</div>
</v-card-text>
<v-card-actions class="pa-4">
<div>
<div v-if="hasUnallocated && remainDue > 0" class="text-dark mb-2">
尚有未分配的入帳金額請確認是否全部分配
</div>
<div v-if="hasUnallocated && remainDue === 0" class="text-info mb-2">
已無未繳項目剩餘入帳金額將成為餘額
</div>
<div v-if="!canConfirm && buttonErrorMessage" class="text-danger">
{{ buttonErrorMessage }}
</div>
</div>
<v-spacer></v-spacer>
<v-btn color="info" @click="redistributeReconcile" class="mr-2">重新分配</v-btn>
<v-btn color="orange" @click="saveDraft" class="mr-2">暫存</v-btn>
<v-btn color="primary" @click="confirmReconcile" :disabled="!canConfirm">確認沖帳</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-container>
</template>
<script>
if (typeof window.DraftUtils === 'undefined') {
console.warn('DraftUtils 未載入,使用備用方案');
window.DraftUtils = {
hasTransferDraft: function (draft) { return false; },
getDraftField: function (draft, field) { return null; },
updateDraftField: function (draft, field, value) {
return { [field]: value };
}
};
}
module.exports = {
data() {
return {
loading: false,
headers: [
//{ text: '#', value: 'f_num' },
{ text: '信眾', value: 'follower' },
{ text: '入帳銀行/帳戶', value: 'acc_name' },
{ text: '入帳日期', value: 'check_date' },
{ text: '帳簿備註', value: 'check_memo' },
{ text: '入帳金額', value: 'check_amount' },
//{ text: '', value: 'check_status' },
{ text: '核對記錄', value: 'verify_note' },
{ text: '沖帳', value: 'actions', sortable: false }
],
items: [],
dialog: {
show: false,
selected: null,
headers: [
{ text: '法會/報名單號', value: 'activity_name' },
{ text: '報名日期', value: 'reg_time' },
{ text: '項目', value: 'actitem_name' },
{ text: '應繳金額', value: 'price', sortable: false },
{ text: '已繳金額', value: 'paid', sortable: false },
{ text: '待繳金額', value: 'due', sortable: false },
{ text: '沖帳金額', value: 'reconcile', sortable: false }
],
items: [],
loading: false,
errorMessage: ''
},
hasUnallocated: false,
draftDataChanged: false
}
},
computed: {
sumReconcile() {
return this.dialog.items.reduce((sum, item) => sum + (Number(item.reconcile) || 0), 0);
},
remainDue() {
const totalDue = this.dialog.items.reduce((sum, item) => sum + (Number(item.due) || 0), 0);
return totalDue - this.sumReconcile;
},
overPaid() {
if (!this.dialog.selected) return 0;
return this.dialog.selected.check_amount - this.sumReconcile;
},
isOverPaid() {
if (!this.dialog.selected) return false;
return this.sumReconcile > this.dialog.selected.check_amount;
},
canConfirm() {
if (!this.dialog.selected) return false;
const hasReconcile = this.dialog.items.some(item => Number(item.reconcile) > 0);
if (!hasReconcile) return false;
const validAmounts = this.dialog.items.every(item => {
const amount = Number(item.reconcile) || 0;
return amount >= 0 && amount <= Number(item.due);
});
if (!validAmounts) return false;
if (this.sumReconcile > this.dialog.selected.check_amount) return false;
//
// 0
if (this.hasUnallocated && this.remainDue > 0) return false;
return true;
},
buttonErrorMessage() {
if (!this.dialog.selected) return '';
const hasReconcile = this.dialog.items.some(item => Number(item.reconcile) > 0);
if (!hasReconcile) return '請至少輸入一筆沖帳金額';
const invalidItem = this.dialog.items.find(item => {
const amount = Number(item.reconcile) || 0;
return amount < 0 || amount > Number(item.due);
});
if (invalidItem) return '沖帳金額超出可沖帳範圍';
if (this.sumReconcile > this.dialog.selected.check_amount) {
return '已沖金額不可大於入帳金額';
}
if (this.hasUnallocated && this.remainDue > 0) {
return '尚有未繳項目,請將入帳金額完全分配';
}
return '';
}
},
mounted() {
this.loadTableData();
},
filters: {
currency(val) {
if (!val) return '0';
return Number(val).toLocaleString();
},
date(val) {
if (!val) return '';
const date = new Date(val);
return date.toLocaleDateString();
}
},
methods: {
// DraftUtils
hasTransferDraft(draft) {
return window.DraftUtils && window.DraftUtils.hasTransferDraft && window.DraftUtils.hasTransferDraft(draft);
},
// 使 DraftUtils
showError(message) {
this.dialog.errorMessage = message;
},
clearError() {
this.dialog.errorMessage = '';
},
loadTableData() {
this.loading = true;
axios.get('../../api/transfer_register/personal_reconcile_list')
.then(res => {
this.items = res.data;
})
.catch(() => {
this.items = [];
})
.finally(() => {
this.loading = false;
});
},
showReconcileDialog(item) {
this.dialog.selected = item;
this.dialog.items = [];
this.dialog.show = true;
// f_num API
if (item.f_num) {
axios.get('../../api/transfer_register/follower_orders', { params: { f_num: item.f_num } })
.then(res => {
this.dialog.items = res.data;
this.loadFromDraftOrAutoDistribute();
})
.catch(() => {
this.dialog.items = [];
this.updateSumReconcile();
});
} else {
this.dialog.items = [];
this.updateSumReconcile();
}
},
autoDistributeReconcile() {
//
let remainAmount = this.dialog.selected ? this.dialog.selected.check_amount : 0;
// reconcile 0
this.dialog.items.forEach(item => {
this.$set(item, 'reconcile', 0);
});
//
const sortedItems = [...this.dialog.items].sort((a, b) =>
new Date(a.reg_time) - new Date(b.reg_time)
);
//
sortedItems.forEach(item => {
if (remainAmount > 0) {
const canPay = Math.min(item.due, remainAmount);
const originalItem = this.dialog.items.find(i => i === item);
if (originalItem) {
this.$set(originalItem, 'reconcile', canPay);
}
remainAmount -= canPay;
}
});
this.updateSumReconcile();
},
redistributeReconcile() {
//
this.autoDistributeReconcile();
},
updateSumReconcile() {
// hasUnallocated
const maxTotal = this.dialog.selected ? (this.dialog.selected.check_amount || 0) : 0;
this.hasUnallocated = maxTotal > this.sumReconcile;
},
loadFromDraftOrAutoDistribute() {
const draft = this.dialog.selected ? this.dialog.selected.draft : null;
if (draft && draft.trim() && window.DraftUtils && window.DraftUtils.getDraftField) {
const transferDraft = window.DraftUtils.getDraftField(draft, 'transfer_draft');
if (transferDraft && Array.isArray(transferDraft)) {
this.loadFromDraft(transferDraft);
} else {
this.autoDistributeReconcile();
}
} else {
this.autoDistributeReconcile();
}
},
loadFromDraft(draftData) {
this.draftDataChanged = false;
// reconcile 0
this.dialog.items.forEach(item => {
this.$set(item, 'reconcile', 0);
});
// draft
draftData.forEach(draftItem => {
const matchedItem = this.dialog.items.find(item =>
item.num === draftItem.pro_order_detail_num
);
if (matchedItem) {
this.$set(matchedItem, 'reconcile', draftItem.reconcile || 0);
} else {
//
this.draftDataChanged = true;
}
});
this.updateSumReconcile();
//
if (this.draftDataChanged) {
setTimeout(() => {
alert('資料已改動,請注意金額一致性');
}, 100);
}
},
saveDraft() {
try {
// transfer_draft
const transferDraftData = this.dialog.items
.filter(item => Number(item.reconcile) > 0)
.map(item => ({
pro_order_detail_num: item.num,
reconcile: Number(item.reconcile)
}));
// 使 draft
const currentDraft = this.dialog.selected.draft || '';
let draftJson = '';
if (window.DraftUtils && window.DraftUtils.updateDraftField) {
const newDraftObj = window.DraftUtils.updateDraftField(currentDraft, 'transfer_draft', transferDraftData);
draftJson = JSON.stringify(newDraftObj);
} else {
// DraftUtils 使
draftJson = JSON.stringify({ transfer_draft: transferDraftData });
}
// draft
const updateData = {
id: this.dialog.selected.id,
activity_num: this.dialog.selected.activity_num,
name: this.dialog.selected.name,
phone: this.dialog.selected.phone,
pay_type: this.dialog.selected.pay_type,
account_last5: this.dialog.selected.account_last5,
amount: this.dialog.selected.amount,
pay_mode: this.dialog.selected.pay_mode,
note: this.dialog.selected.note,
proof_img: this.dialog.selected.proof_img,
status: this.dialog.selected.status,
f_num_match: this.dialog.selected.f_num_match,
f_num: this.dialog.selected.f_num,
acc_num: this.dialog.selected.acc_num,
check_date: this.dialog.selected.check_date,
check_amount: this.dialog.selected.check_amount,
check_memo: this.dialog.selected.check_memo,
check_status: this.dialog.selected.check_status,
acc_kind: this.dialog.selected.acc_kind,
member_num: this.dialog.selected.member_num,
verify_time: this.dialog.selected.verify_time,
verify_note: this.dialog.selected.verify_note,
draft: draftJson // draft
};
axios.put(`../../api/transfer_register/${this.dialog.selected.id}`, updateData)
.then(() => {
alert('暫存成功!');
//
this.dialog.selected.draft = draftJson;
})
.catch(err => {
alert('暫存失敗:' + (err.response?.data?.message || err.message));
});
} catch (e) {
alert('暫存失敗:資料格式錯誤');
}
},
confirmReconcile() {
if (!this.canConfirm) {
this.showError(this.buttonErrorMessage);
return;
}
this.dialog.loading = true;
const over_payment = this.dialog.selected.check_amount - this.sumReconcile;
const postData = {
transfer_register_id: this.dialog.selected.id,
details: this.dialog.items
.filter(item => item.reconcile > 0)
.map(item => ({
pro_order_detail_num: item.num,
amount: Number(item.reconcile),
reg_time: new Date().toISOString(),
demo: `${this.dialog.selected.check_memo || ''}`
})),
over_payment: over_payment
};
axios.post('../../api/transfer_register/reconcile', postData)
.then(res => {
//
const message = res.data && res.data.message ? res.data.message : '沖帳完成';
msgtop(message, 'success');
this.dialog.show = false;
this.loadTableData(); //
})
.catch(err => {
let errorMessage = '沖帳失敗,請聯繫系統管理員';
if (err.response && err.response.data) {
if (typeof err.response.data === 'string') {
errorMessage = err.response.data;
} else if (err.response.data.message) {
errorMessage = err.response.data.message;
if (err.response.data.exceptionMessage) {
errorMessage += `\\n${err.response.data.exceptionMessage}`;
}
}
}
alert(errorMessage);
})
.finally(() => {
this.dialog.loading = false;
});
},
validateAndUpdateReconcile(value, item, index) {
let numValue = Number(value);
if (isNaN(numValue)) {
numValue = 0;
}
numValue = Math.round(numValue);
this.$set(item, 'reconcile', numValue);
this.updateSumReconcile();
}
}
};
</script>
+193
View File
@@ -0,0 +1,193 @@
<template>
<div class="row justify-content-center">
<div class="col-12 col-md-8 col-lg-6">
<div class="card shadow">
<div class="card-header bg-primary text-white text-center">
<h4 class="mb-0">登錄匯款資料</h4>
</div>
<div class="card-body">
<form id="transferForm" @submit.prevent="submitForm" enctype="multipart/form-data" autocomplete="off">
<!-- 法會名稱 -->
<div class="mb-3">
<label for="activity_num" class="form-label">法會名稱 <span class="text-danger">*</span></label>
<select class="form-select" id="activity_num" v-model="formData.activity_num" required>
<option value="">請選擇</option>
<option v-for="activity in activities" :key="activity.num" :value="activity.num">
{{activity.subject}}
</option>
</select>
</div>
<!-- 姓名 -->
<div class="mb-3">
<label for="name" class="form-label">姓名 <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="name" v-model="formData.name" required maxlength="50" placeholder="請輸入姓名" @blur="onNameBlur">
</div>
<!-- 電話 -->
<div class="mb-3">
<label for="phone" class="form-label">電話 <span class="text-danger">*</span></label>
<input type="tel" class="form-control" id="phone" v-model="formData.phone" required maxlength="30" placeholder="請輸入聯絡電話">
</div>
<!-- 支付方式 -->
<div class="mb-3">
<label for="pay_type" class="form-label">支付方式 <span class="text-danger">*</span></label>
<select class="form-select" id="pay_type" v-model="formData.pay_type" required>
<option value="">請選擇</option>
<option v-for="(desc, value) in payTypes" :key="value" :value="value">
{{desc}}
</option>
</select>
</div>
<!-- 帳號後五碼 -->
<div class="mb-3">
<label for="account_last5" class="form-label">帳號後五碼(若無免填)</label>
<input type="text" class="form-control" id="account_last5" v-model="formData.account_last5" maxlength="10" placeholder="如有匯款請填寫">
</div>
<!-- 支付金額 -->
<div class="mb-3">
<label for="amount" class="form-label">支付金額 <span class="text-danger">*</span></label>
<input type="number" class="form-control" id="amount" v-model="formData.amount" required min="1" step="1" placeholder="請輸入金額">
</div>
<!-- 支付型態 -->
<div class="mb-3">
<label class="form-label">支付型態 <span class="text-danger">*</span></label>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="pay_mode" id="pay_mode1" value="個人" v-model="formData.pay_mode" checked>
<label class="form-check-label" for="pay_mode1">個人支付</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="pay_mode" id="pay_mode2" value="共同" v-model="formData.pay_mode">
<label class="form-check-label" for="pay_mode2">共同支付</label>
</div>
</div>
<!-- 備註 -->
<div class="mb-3">
<label for="note" class="form-label">備註</label>
<textarea class="form-control" id="note" v-model="formData.note" rows="2" maxlength="200" placeholder="如有分攤人名、金額、項目等請說明"></textarea>
</div>
<!-- 憑證上傳 -->
<div class="mb-3">
<label for="proof_img" class="form-label">上傳匯款憑證可拍照</label>
<input class="form-control" type="file" id="proof_img" @change="handleFileUpload" accept="image/*" capture="environment">
</div>
<!-- 送出/關閉 -->
<div class="d-grid gap-2">
<button type="submit" class="btn btn-primary btn-lg" :disabled="isSubmitting || !canSubmit">
{{ isSubmitting ? '處理中...' : '送出資料' }}
</button>
<button type="button" class="btn btn-outline-secondary" @click="closeWindow">離開</button>
</div>
</form>
<div class="mt-3 text-muted small">
<ul>
<li>如一位組頭幫多人匯款請在備註欄分拆明細人名金額項目等</li>
<li>送出後直接新增記錄不顯示查核</li>
<li>如無姓名/電話資料系統會提示</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
module.exports = {
// 1. el: '#register'
// 2. data function
data() {
return {
activities: [],
formData: {
activity_num: '',
name: '',
phone: '',
pay_type: '',
account_last5: '',
amount: '',
pay_mode: '個人',
note: '',
proof_img: null
},
payTypes: {
'1': '現金',
'2': '匯款',
'3': '支票'
},
isSubmitting: false,
canSubmit: true
};
},
created() {
this.loadActivities();
},
methods: {
loadActivities() {
const today = new Date().toISOString().split('T')[0];
axios.get(`../../api/activity?endDate=${today}`)
.then(response => {
this.activities = response.data;
})
.catch(error => {
console.error('載入活動列表失敗:', error);
alert('載入活動列表失敗,請重新整理頁面');
});
},
handleFileUpload(event) {
this.formData.proof_img = event.target.files[0];
},
submitForm() {
if (this.isSubmitting || !this.canSubmit) return;
this.isSubmitting = true;
const formData = new FormData();
Object.keys(this.formData).forEach(key => {
if (this.formData[key] !== null) {
formData.append(key, this.formData[key]);
}
});
axios.post('../../api/transfer_register', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(response => {
alert('資料已成功送出!');
this.formData = {
activity_num: '',
name: '',
phone: '',
pay_type: '',
account_last5: '',
amount: '',
pay_mode: '個人',
note: '',
proof_img: null
};
this.canSubmit = false;
})
.catch(error => {
console.error('送出失敗:', error);
// response.data.message
const errorMsg = error.response && error.response.data && error.response.data.message
? error.response.data.message
: '請檢查網路連線或系統狀態';
alert('送出失敗 :' + errorMsg);
})
.finally(() => {
this.isSubmitting = false;
});
},
closeWindow() {
// 3. Dialog window.close()
// (index.aspx)
this.$emit('close-dialog');
},
onNameBlur() {
this.canSubmit = !!this.formData.name.trim();
}
}
};
</script>
+461
View File
@@ -0,0 +1,461 @@
<template>
<v-container>
<v-card>
<v-card-title class="bg-success white--text text-center">
<h5 class="mb-0">出納核對匯款人</h5>
<v-spacer></v-spacer>
<v-btn color="primary" @click="submitData">確認送出</v-btn>
<v-btn color="primary" class="ml-2" @click="closeWindow">關閉</v-btn>
</v-card-title>
<v-card-text>
<v-data-table :headers="headers"
:items="items"
:loading="loading"
loading-text="載入中..."
class="elevation-1 mt-3"
item-key="id"
:expanded.sync="expanded"
show-expand>
<template v-slot:item.info="{ item }">
<div>
<div><span class="text-muted">姓名</span>{{ item.name }}</div>
<div><span class="text-muted">電話</span>{{ item.phone }}</div>
<div><span class="text-muted">法會</span>{{ getActivityName(item.activity_num) }}</div>
</div>
</template>
<template v-slot:item.f_num="{ item }">
<span v-if="item.f_num && item.follower">
<a :href="'/admin/follower/reg.aspx?num=' + item.follower.num"
class="text-success"
target="_blank">
{{ item.follower.u_name }}F{{ item.f_num }}
</a>
<div class="small text-muted">
電話{{ item.follower.phone }}<br>
手機{{ item.follower.cellphone }}
</div>
</span>
<span v-else class="text-danger">未自動比對</span>
</template>
<template v-slot:expanded-item="{ headers, item }">
<td :colspan="headers.length">
<div class="pa-4">
<h6 class="mb-3 text-primary">
<v-icon color="primary" small class="mr-1">mdi-receipt</v-icon>
沖帳明細
</h6>
<v-container>
<v-row class="font-weight-bold grey--text text--darken-2">
<v-col>*入帳銀行/帳戶 | 支付資訊/帳號後5碼</v-col>
<v-col>*入帳日期</v-col>
<v-col>*入帳金額</v-col>
<v-col>*收支項目</v-col>
<!--<v-col>備註/狀態 | 核對記錄</v-col>-->
</v-row>
<v-row>
<v-col>
<div class="mb-2">
<span class="badge bg-primary me-1" title="支付方式">{{ payTypeText[item.pay_type] || item.pay_type }}</span>
<span class="badge bg-secondary" title="型態:個人/共同">{{ item.pay_mode }}</span>
<span class="font-weight-bold text-primary" title="帳號後5碼">{{ item.account_last5 }}</span>
</div>
<div>
<v-select :items="bankOptions"
v-model="item.acc_num"
dense
outlined
hide-details
style="max-width: 200px"></v-select>
</div>
</v-col>
<v-col>
<div class="mb-2">
<span class="text-muted small">登記日期</span>
<span class="font-weight-bold error--text"
style="cursor:pointer"
@click="$set(item, 'check_date', item.create_time ? item.create_time.split('T')[0] : '')"
title="點擊帶入日期">
{{ item.create_time | date }}
</span>
</div>
<div class="mb-2">
<v-text-field v-model="item.check_date"
type="date"
dense
outlined
hide-details
style="max-width: 140px"></v-text-field>
</div>
</v-col>
<v-col>
<div class="mb-2">
<span class="text-muted small">金額</span>
<span class="font-weight-bold error--text"
style="cursor:pointer"
@click="$set(item, 'check_amount', item.amount)"
title="點擊帶入金額">
{{ item.amount | currency }}
</span>
</div>
<div>
<v-text-field v-model="item.check_amount"
type="number"
dense
outlined
hide-details
style="max-width: 100px"></v-text-field>
</div>
</v-col>
<v-col>
<div class="mb-2">
<span class="badge bg-primary me-1" title="支付方式">收支項目</span>
</div>
<div>
<v-select :items="accountingKinds"
v-model="item.kind"
dense
outlined
hide-details
style="max-width: 200px"></v-select>
</div>
</v-col>
</v-row>
</v-container>
</div>
</td>
</template>
<template v-slot:item.actions="{ item }">
<v-btn small outlined color="primary" @click="openFollowerDialog(item)">選擇信眾</v-btn>
</template>
<template v-slot:item.check_memo="{ item }">
<div class="d-flex align-center my-2" style="min-width: 300px">
<v-text-field v-model="item.check_memo"
dense
outlined
hide-details
class="mr-2"
style="width: 180px"
placeholder="帳簿備註"></v-text-field>
<v-select :items="checkStatusOptions"
v-model="item.check_status"
item-text="text"
item-value="value"
dense
outlined
hide-details
style="width: 110px"
:menu-props="{ contentClass: 'mini-dropdown', maxHeight: 200 }"></v-select>
</div>
</template>
</v-data-table>
</v-card-text>
</v-card>
<v-dialog v-model="follower_dialog.show" max-width="800px">
<v-card>
<v-card-title class="grey lighten-2">
選擇信眾
<v-spacer></v-spacer>
<v-btn icon @click="follower_dialog.show = false">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<v-card-text class="pt-4">
<v-row>
<v-col cols="12">
<v-text-field v-model="follower_dialog.search"
label="搜尋信眾 (按 Enter 搜尋)"
prepend-icon="mdi-magnify"
@keyup.enter="searchFollowers"
clearable></v-text-field>
</v-col>
</v-row>
<v-data-table :headers="follower_dialog.headers"
:items="follower_dialog.items"
:loading="follower_dialog.loading"
item-key="num"
class="elevation-1"
@click:row="selectFollower">
<template v-slot:item.actions="{ item }">
<v-btn small color="primary" @click.stop="selectFollower(item)">
選擇
</v-btn>
</template>
</v-data-table>
</v-card-text>
</v-card>
</v-dialog>
<v-snackbar v-model="snackbar.show" :timeout="3000" top color="error">
{{ snackbar.text }}
<template v-slot:action="{ attrs }">
<v-btn dark text v-bind="attrs" @click="snackbar.show = false">關閉</v-btn>
</template>
</v-snackbar>
</v-container>
</template>
<script>
module.exports = {
data() {
return {
// 3 snackbar
snackbar: {
show: false,
text: ''
},
headers: [
{ text: '匯款人資訊', value: 'info' },
{ text: '對應信眾', value: 'f_num' },
{ text: '選擇信眾', value: 'actions', sortable: false },
{ text: '備註/狀態 | 核對記錄', value: 'check_memo' }
//{ text: ' | ', value: 'status' },
],
// detailHeaders expanded
detailHeaders: [
{ text: '匯款人資訊', value: 'info' },
{ text: '匯款備註/相片', value: 'note' },
{ text: '*入帳銀行/帳戶 | 支付資訊/帳號後5碼', value: 'acc_num' },
{ text: '*入帳日期', value: 'check_date' },
{ text: '*入帳金額', value: 'check_amount' },
{ text: '*收支項目', value: 'kind' },
{ text: '備註/狀態 | 核對記錄', value: 'check_memo' }
],
items: [],
bankOptions: [],
accountingKinds: [],
checkStatusOptions: [
{ text: '', value: '' },
{ text: '未核對', value: '1' },
{ text: '核對', value: '2' },
{ text: '金額不符', value: '3' },
{ text: '其他問題', value: '4' },
{ text: '作廢', value: '5' }
],
payTypeText: {
1: '現金',
2: '匯款',
3: '支票'
},
activities: [],
expanded: [],
loading: false,
statusOptions: [
{ text: '', value: '' },
{ text: '待確認', value: '1' },
{ text: '確認', value: '2' },
{ text: '作廢', value: '3' }
],
follower_dialog: {
show: false,
loading: false,
search: '',
headers: [
{ text: '編號', value: 'num' },
{ text: '姓名', value: 'u_name' },
{ text: '地址', value: 'address' },
// 2
{ text: '操作', value: 'actions', sortable: false }
],
items: [],
selected: null,
current_item: null
}
};
},
filters: {
currency(val) {
if (!val) return '';
return Number(val).toLocaleString();
},
date(val) {
if (!val) return '';
return val.split('T')[0];
}
},
methods: {
getActivityName(num) {
const act = this.activities.find(a => a.num === num);
return act ? act.subject : '';
},
openFollowerDialog(item) {
this.follower_dialog.current_item = item;
this.follower_dialog.show = true;
//
// this.searchFollowers();
},
async searchFollowers() {
if (!this.follower_dialog.search) return;
this.follower_dialog.loading = true;
try {
const response = await axios.post(HTTP_HOST + 'api/follower/GetList', {
f_number: this.follower_dialog.search,
u_name: this.follower_dialog.search
}, {
params: {
page: 1,
pageSize: 10
}
});
this.follower_dialog.items = response.data.list || [];
} catch (error) {
console.error('Error fetching followers:', error);
this.snackbar.text = "查詢信眾失敗,請確認網路或 API 狀態";
this.snackbar.show = true;
} finally {
this.follower_dialog.loading = false;
}
},
async selectFollower(follower) {
if (this.follower_dialog.current_item) {
try {
this.follower_dialog.show = false;
const selectedFollower = this.follower_dialog.items.find(item => item.num === follower.num);
if (selectedFollower) {
this.follower_dialog.current_item.f_num = follower.num;
this.follower_dialog.current_item.follower = {
num: selectedFollower.num,
u_name: selectedFollower.u_name,
address: selectedFollower.address || '',
phone: selectedFollower.phoneDes || '',
cellphone: selectedFollower.cellphoneDes || ''
};
} else {
throw new Error('找不到信眾詳細資料');
}
} catch (error) {
console.error('取得信眾詳細資料失敗:', error);
this.snackbar.text = '取得信眾詳細資料失敗,請重試';
this.snackbar.show = true;
this.follower_dialog.current_item.f_num = follower.num;
this.follower_dialog.current_item.follower = {
num: follower.num,
u_name: follower.u_name,
address: follower.address || '',
phone: '',
cellphone: ''
};
}
}
},
async loadData() {
this.loading = true;
try {
const actRes = await axios.get('../../api/activity');
this.activities = actRes.data;
const res = await axios.get('../../api/transfer_register/pending');
this.items = res.data.map(item => ({
...item,
status: item.status ? String(item.status) : ''
}));
const bankRes = await axios.post('../../api/accounting/GetAccountKindList', {}, { params: { page: 1, pageSize: 1000 } });
this.bankOptions = bankRes.data.list.map(x => ({
text: x.kind + (x.bank_name ? ' - ' + x.bank_name : '') + (x.bank_id ? ' (' + x.bank_id + ')' : ''),
value: x.num
}));
const kindRes = await axios.post('../../api/accounting/GetTitleKindList', {}, { params: { page: 1, pageSize: 1000 } });
this.accountingKinds = kindRes.data.list.map(x => ({
text: x.kind,
value: x.num
}));
} catch (e) {
console.error('載入資料失敗:', e);
this.snackbar.text = '載入資料失敗';
this.snackbar.show = true;
} finally {
this.loading = false;
}
},
async saveData() {
const updateList = this.items.map(item => ({
id: item.id,
f_num: item.f_num,
status: item.status ? String(item.status) : '',
verify_note: item.verify_note
// check_date, check_amount API
}));
try {
const res = await axios.post('../../api/transfer_register/batch_update', updateList);
if (res.data && res.data.success) {
alert('儲存成功!');
await this.loadData();
} else {
alert('儲存失敗,請重試!!');
}
} catch (e) {
alert('儲存失敗,請重試:' + e.message);
}
},
async submitData() {
// - /
const missingAccNum = this.items.filter(item => !item.acc_num);
if (missingAccNum.length > 0) {
alert('請選擇入帳銀行/帳戶!有 ' + missingAccNum.length + ' 筆資料未選擇。');
return;
}
// -
const missingCheckDate = this.items.filter(item => !item.check_date);
if (missingCheckDate.length > 0) {
alert('請填寫入帳日期!有 ' + missingCheckDate.length + ' 筆資料未填寫。');
return;
}
// -
const missingCheckAmount = this.items.filter(item => !item.check_amount || item.check_amount <= 0);
if (missingCheckAmount.length > 0) {
alert('請填寫入帳金額!有 ' + missingCheckAmount.length + ' 筆資料未填寫或金額無效。');
return;
}
//
const updateList = this.items.map(item => ({
id: item.id,
f_num: item.f_num,
status: '2',
check_status: item.check_status ? String(item.check_status) : '',
verify_note: item.verify_note,
acc_num: item.acc_num,
check_date: item.check_date,
check_amount: item.check_amount,
check_memo: item.check_memo,
kind: item.kind,
verify_note: item.verify_note
}));
try {
const res = await axios.post('../../api/transfer_register/batch_update', updateList);
if (res.data && res.data.success) {
alert('送出成功!');
//
await this.loadData();
} else {
alert('送出失敗,請重試 :' + res.data.message);
}
} catch (e) {
console.error('送出失敗:', e);
alert('送出失敗,請再試一次!');
}
},
closeWindow() {
this.$emit('close-dialog');
},
},
created() {
this.loadData();
}
}
</script>
@@ -0,0 +1,382 @@
<template>
<v-container>
<v-card>
<v-card-title class="bg-primary white--text text-center">
<h5 class="mb-0">沖帳查詢</h5>
<button class="btn btn-default ms-auto"><i class="mdi mdi-close"></i></button>
</v-card-title>
<v-card-text>
<v-row class="mb-0 mt-4">
<v-col cols="12" md="2">
<v-text-field v-model="query.start_date" label="起始日" type="date" dense outlined></v-text-field>
</v-col>
<v-col cols="12" md="2">
<v-text-field v-model="query.end_date" label="結束日" type="date" dense outlined></v-text-field>
</v-col>
<v-col cols="12" md="3">
<v-text-field v-model="query.activity_name" label="法會" dense outlined readonly>
<template v-slot:append>
<v-btn icon @click="showActivityDialog"><v-icon>mdi-magnify</v-icon></v-btn>
</template>
</v-text-field>
</v-col>
<v-col cols="12" md="3">
<v-text-field v-model="query.follower_name" label="信眾" dense outlined readonly>
<template v-slot:append>
<v-btn icon @click="showFollowerDialog"><v-icon>mdi-magnify</v-icon></v-btn>
</template>
</v-text-field>
</v-col>
<v-col cols="12" md="2" class="d-flex justify-end">
<v-btn color="primary" class="mr-2" @click="search">查詢</v-btn>
<v-btn color="grey" @click="reset">重設</v-btn>
</v-col>
</v-row>
<v-data-table :headers="headers"
:items="items"
:loading="loading"
loading-text="載入中..."
class="elevation-1 verify-query-table"
item-key="transfer_id"
:footer-props="{ 'items-per-page-options': [10, 20, 50] }"
:expanded.sync="expanded"
show-expand>
<template v-slot:item.follower="{ item }">
<div>
<div class="font-weight-bold">{{ item.follower }}</div>
<div class="caption text--secondary">{{ item.transfer_name }}</div>
<div class="caption text--secondary">{{ item.transfer_phone }}</div>
</div>
</template>
<template v-slot:item.activity_info="{ item }">
<div>
<div class="font-weight-bold">{{ item.activity_name }}</div>
<div class="caption text--secondary">{{ item.acc_name }}</div>
</div>
</template>
<template v-slot:item.transfer_info="{ item }">
<div>
<div class="font-weight-bold text-primary">應收總額{{ item.price_totals | currency }}</div>
<div class="font-weight-bold text-primary">入帳金額{{ item.transfer_check_amount | currency }}</div>
<div class="text-success">沖帳日期{{ item.transfer_check_date | date }}</div>
<div v-if="item.transfer_remain_amount > 0" class="text-warning">
剩餘金額{{ item.transfer_remain_amount | currency }}
</div>
</div>
</template>
<template v-slot:item.status_info="{ item }">
<div>
<v-chip small :color="getStatusColor(item.transfer_check_status)" text-color="white">
{{ getStatusText(item.transfer_check_status) }}
</v-chip>
<div class="caption text--secondary mt-1">{{ item.transfer_check_memo }}</div>
</div>
</template>
<template v-slot:item.actions="{ item }">
<v-btn color="info" outlined small @click="showDetailDialog(item)">
<v-icon small class="mr-1">mdi-information-outline</v-icon> 詳細
</v-btn>
</template>
<template v-slot:expanded-item="{ headers, item }">
<td :colspan="headers.length">
<div class="pa-4">
<h6 class="mb-3 text-primary">
<v-icon color="primary" small class="mr-1">mdi-receipt</v-icon>
沖帳明細
</h6>
<v-data-table :headers="detailHeaders"
:items="item.pro_order_records"
class="elevation-1"
hide-default-footer
:disable-pagination="true"
dense>
<template v-slot:item.order_info="{ item }">
<div>
<div class="font-weight-bold">{{ item.pro_order_detail?.pro_order?.order_no }}</div>
<div class="caption text--secondary">{{ item.pro_order_detail?.actitem_name }}</div>
</div>
</template>
<template v-slot:item.payment_info="{ item }">
<div>
<div class="font-weight-bold">{{ item.payment_name }}</div>
<div class="caption text--secondary">{{ item.bank_code }}</div>
</div>
</template>
<template v-slot:item.amount_info="{ item }">
<div>
<div class="font-weight-bold text-success">{{ item.price | currency }}</div>
<div class="caption text--secondary">{{ item.pay_date | date }}</div>
</div>
</template>
<template v-slot:item.memo="{ item }">
<div style="white-space: pre-line;">{{ item.reconcile_memo }}</div>
</template>
</v-data-table>
</div>
</td>
</template>
</v-data-table>
</v-card-text>
</v-card>
<!-- 法會選取 Dialog -->
<v-dialog v-model="activityDialog.show" max-width="700px">
<v-card>
<v-card-title class="grey lighten-2">
<v-icon color="primary" class="mr-2">mdi-table</v-icon>
選擇法會
<v-spacer></v-spacer>
<v-btn icon @click="activityDialog.show = false"><v-icon>mdi-close</v-icon></v-btn>
</v-card-title>
<v-card-text class="mt-4">
<v-text-field v-model="activityDialog.search" label="搜尋法會" dense outlined @keyup.enter="searchActivity"></v-text-field>
<v-data-table :headers="activityDialog.headers"
:items="activityDialog.items"
:loading="activityDialog.loading"
item-key="num"
class="elevation-1 mt-2"
@click:row="selectActivity"
hide-default-footer></v-data-table>
</v-card-text>
</v-card>
</v-dialog>
<!-- 信眾選取 Dialog -->
<v-dialog v-model="followerDialog.show" max-width="700px">
<v-card>
<v-card-title class="grey lighten-2">
<v-icon color="primary" class="mr-2">mdi-account</v-icon>
選擇信眾
<v-spacer></v-spacer>
<v-btn icon @click="followerDialog.show = false"><v-icon>mdi-close</v-icon></v-btn>
</v-card-title>
<v-card-text class="mt-4">
<v-text-field v-model="followerDialog.search" label="搜尋信眾" dense outlined @keyup.enter="searchFollower"></v-text-field>
<v-data-table :headers="followerDialog.headers"
:items="followerDialog.items"
:loading="followerDialog.loading"
item-key="num"
class="elevation-1 mt-2"
@click:row="selectFollower"
hide-default-footer></v-data-table>
</v-card-text>
</v-card>
</v-dialog>
<!-- 詳細資訊對話框 -->
<v-dialog v-model="dialog.show" max-width="900px">
<v-card>
<v-card-title class="grey lighten-2">
<v-icon color="info" class="mr-2">mdi-information-outline</v-icon>
詳細資訊
<v-spacer></v-spacer>
<v-btn icon @click="dialog.show = false">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<v-card-text>
<div v-if="dialog.selected">
<v-row>
<v-col cols="12" md="6">
<h6 class="mb-3 text-primary">匯款人資訊</h6>
<div class="mb-2"><span class="font-weight-bold">姓名</span>{{ dialog.selected.transfer_name }}</div>
<div class="mb-2"><span class="font-weight-bold">電話</span>{{ dialog.selected.transfer_phone }}</div>
<div class="mb-2"><span class="font-weight-bold">信眾</span>{{ dialog.selected.follower }}</div>
</v-col>
<v-col cols="12" md="6">
<h6 class="mb-3 text-success">入帳資訊</h6>
<div class="mb-2"><span class="font-weight-bold">入帳帳戶</span>{{ dialog.selected.acc_name }}</div>
<div class="mb-2"><span class="font-weight-bold">入帳日期</span>{{ dialog.selected.transfer_check_date | date }}</div>
<div class="mb-2"><span class="font-weight-bold">入帳金額</span>{{ dialog.selected.transfer_check_amount | currency }}</div>
<div class="mb-2"><span class="font-weight-bold">應收總額</span>{{ dialog.selected.price_totals | currency }}</div>
</v-col>
</v-row>
<v-divider class="my-4"></v-divider>
<v-row>
<v-col cols="12" md="6">
<h6 class="mb-3 text-purple">活動資訊</h6>
<div class="mb-2"><span class="font-weight-bold">活動名稱</span>{{ dialog.selected.activity_name || '-' }}</div>
<div class="mb-2"><span class="font-weight-bold">支付方式</span>{{ payTypeText[dialog.selected.transfer_pay_type] || dialog.selected.transfer_pay_type }}</div>
<div class="mb-2"><span class="font-weight-bold">帳號後5碼</span>{{ dialog.selected.transfer_account_last5 || '-' }}</div>
</v-col>
<v-col cols="12" md="6">
<h6 class="mb-3 text-info">核對記錄</h6>
<div class="mb-2"><span class="font-weight-bold">核對記錄</span>{{ dialog.selected.transfer_verify_note || '-' }}</div>
<div class="mb-2"><span class="font-weight-bold">帳簿備註</span>{{ dialog.selected.transfer_check_memo || '-' }}</div>
<div v-if="dialog.selected.transfer_proof_img" class="mb-2">
<span class="font-weight-bold">證明圖片</span>
<a :href="'../../upload/transfer_proof/' + dialog.selected.transfer_proof_img" target="_blank">查看相片</a>
</div>
</v-col>
</v-row>
</div>
</v-card-text>
</v-card>
</v-dialog>
</v-container>
</template>
<script>
module.exports = {
data() {
return {
loading: false,
expanded: [],
query: {
start_date: '',
end_date: '',
activity_num: '',
activity_name: '',
follower_num: '',
follower_name: ''
},
headers: [
{ text: '信眾/匯款人', value: 'follower' },
{ text: '法會/入帳帳戶', value: 'activity_info' },
{ text: '入帳資訊', value: 'transfer_info' },
{ text: '狀態/備註', value: 'status_info' },
{ text: '操作', value: 'actions', sortable: false }
],
detailHeaders: [
{ text: '訂單/項目', value: 'order_info' },
{ text: '付款機構', value: 'payment_info' },
{ text: '沖帳金額/日期', value: 'amount_info' },
{ text: '備註', value: 'memo' }
],
items: [],
dialog: {
show: false,
selected: null
},
activityDialog: {
show: false,
search: '',
loading: false,
items: [],
headers: [
{ text: '編號', value: 'num' },
{ text: '名稱', value: 'subject' }
]
},
followerDialog: {
show: false,
search: '',
loading: false,
items: [],
headers: [
{ text: '編號', value: 'num' },
{ text: '姓名', value: 'u_name' }
]
},
payTypeText: {
1: '現金',
2: '匯款',
3: '支票'
}
}
},
filters: {
currency(val) {
if (!val) return '0';
return Number(val).toLocaleString();
},
date(val) {
if (!val) return '';
const date = new Date(val);
return date.toLocaleDateString();
}
},
methods: {
search() {
this.loading = true;
// API
axios.get('../../api/transfer_register/verify_order_record_query', { params: this.query })
.then(res => {
this.items = res.data;
this.expanded = []; //
})
.catch(() => {
this.items = [];
this.expanded = [];
})
.finally(() => {
this.loading = false;
});
},
reset() {
this.query.start_date = '';
this.query.end_date = '';
this.query.activity_num = '';
this.query.activity_name = '';
this.query.follower_num = '';
this.query.follower_name = '';
this.items = [];
this.expanded = [];
},
showDetailDialog(item) {
this.dialog.selected = item;
this.dialog.show = true;
},
showActivityDialog() {
this.activityDialog.show = true;
this.searchActivity();
},
searchActivity() {
this.activityDialog.loading = true;
axios.get('../../api/activity', { params: { keyword: this.activityDialog.search } })
.then(res => { this.activityDialog.items = res.data; })
.catch(() => { this.activityDialog.items = []; })
.finally(() => { this.activityDialog.loading = false; });
},
selectActivity(row) {
this.query.activity_num = row.num;
this.query.activity_name = row.subject;
this.activityDialog.show = false;
},
showFollowerDialog() {
this.followerDialog.show = true;
this.searchFollower();
},
searchFollower() {
this.followerDialog.loading = true;
axios.post('../..../..../../api/follower/GetList', { u_name: this.followerDialog.search }, { params: { page: 1, pageSize: 10 } })
.then(res => { this.followerDialog.items = res.data.list; })
.catch(() => { this.followerDialog.items = []; })
.finally(() => { this.followerDialog.loading = false; });
},
selectFollower(row) {
this.query.follower_num = row.num;
this.query.follower_name = row.u_name;
this.followerDialog.show = false;
},
getStatusColor(status) {
switch (status) {
case '90': return 'warning';
case '99': return 'success';
default: return 'grey';
}
},
getStatusText(status) {
switch (status) {
case '90': return '沖帳有剩餘';
case '99': return '沖帳完成';
default: return '未知狀態';
}
}
}
};
</script>
<style>
.v-data-table.verify-query-table .v-data-table__wrapper tbody tr {
min-height: 90px !important;
height: 90px !important;
}
.v-data-table.verify-query-table .v-data-table__wrapper tbody td {
min-height: 90px !important;
height: 90px !important;
vertical-align: middle !important;
}
</style>
+133 -7
View File
@@ -13,10 +13,12 @@
<a @click="print_dialog.show=true" class="btn btn-outline-primary btn-print" target="_blank">
<i class="mdi mdi-printer"></i>列印管理報表
</a>
<a @click="goPrint" class="btn btn-outline-primary btn-print" target="_blank">
<a @click="goPrint" class="btn btn-outline-primary btn-print" :class="{ 'disabled': data_table.list.length === 0 }" target="_blank">
<i class="mdi mdi-printer"></i>列印查詢資料
</a>
<asp:LinkButton ID="excel" runat="server" CssClass="btn btn-outline-success" OnClick="excel_Click"><span class="fa-solid fa-file-excel"></span> 匯出Excel</asp:LinkButton>
<div :style="data_table.list.length === 0 ? 'pointer-events: none; opacity: 0.5;' : ''" style="display:inline-block;">
<asp:LinkButton ID="excel" runat="server" CssClass="btn btn-outline-success" OnClick="export_Click"><span class="fa-solid fa-file-excel"></span> 匯出查詢資料(Excel</asp:LinkButton>
</div>
</div>
</asp:Content>
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" runat="Server">
@@ -29,6 +31,8 @@
vuetify: new Vuetify(vuetify_options),
data() {
return {
isSearched: false,
print_error_msg: '',
options: { multiSort: false },
search_options: { multiSort: false },
data_table: {
@@ -132,7 +136,12 @@
watch: {
options: {
handler() {
if (this.isSearched) {
this.getList()
}
else {
this.data_table.loading = false;
}
},
deep: true,
},
@@ -141,23 +150,101 @@
this.search_get()
},
deep: true,
},
}
}, mounted() {
const printResult = document.getElementById('<%= hid_err_msg.ClientID %>').value;
document.getElementById('<%= hid_err_msg.ClientID %>').value = '';
window._printResult = printResult
this.search_dialog.current = this.search_dialog.controls.search1 ///default
this.initPrintSearch();
const navEntries = performance.getEntriesByType("navigation");
const isReload = navEntries.length > 0 && navEntries[0].type === "reload";
const url = new URL(window.location.href);
let params = url.searchParams;
if (params.get('dirty') === '1') { // 資料有更新時執行 getlist
this.search = JSON.parse(sessionStorage.getItem("member_query_params"));
this.getList();
params.delete('dirty');
window.history.replaceState({}, '', url.pathname + url.search);
}
if (isReload) {
sessionStorage.removeItem("followerpage");
sessionStorage.removeItem("member_list_cache");
sessionStorage.removeItem("member_query_params");
}
else if ("<%=lastAddedID%>" !== "") {
const newQuery = { f_number: '<%=lastAddedID%>' };
sessionStorage.setItem('member_query_params', JSON.stringify(newQuery));
this.search = newQuery;
this.isSearched = true;
}
else {
const savedPage = parseInt(sessionStorage.getItem('followerpage'));
const savedData = sessionStorage.getItem("member_list_cache");
const savedQuery = JSON.parse(sessionStorage.getItem("member_query_params"));
if (savedQuery) {
this.search = savedQuery;
this.isSearched = true;
}
if (savedPage) {
this.options.page = savedPage;
}
if (savedData && savedData !== "undefined") {
this.data_table = JSON.parse(savedData);
this.isSearched = true;
}
}
if (printResult === 'nodata' || printResult === 'success') {
this.$nextTick(() => {
this.print_search.year = parseInt(document.getElementById('<%= hid_print_year.ClientID %>').value) || this.print_search.year;
this.print_search.month = parseInt(document.getElementById('<%= hid_print_month.ClientID %>').value) || this.print_search.month;
this.print_search.season = parseInt(document.getElementById('<%= hid_print_season.ClientID %>').value) || this.print_search.season;
this.print_conditions = document.getElementById('<%= hid_print_mode.ClientID %>').value || 'yy';
this.print_dialog.show = true;
if (printResult === 'nodata') {
this.print_error_msg = "查無資料,請重新選擇區間";
}
});
}
this.$nextTick(() => {
setTimeout(() => {
// 清空 URL
const cleanUrl = window.location.protocol + "//" + window.location.host + window.location.pathname;
window.history.replaceState({}, '', cleanUrl);
}, 100);
});
},
methods: {
triggerManagementExport(mode) {
this.print_dialog.show = false;
this.print_error_msg = "";
if (this.print_search.year == '') {
msgbox('請輸入年份');
return;
}
document.getElementById('<%= hid_print_mode.ClientID %>').value = this.print_conditions;
document.getElementById('<%= hid_print_year.ClientID %>').value = this.print_search.year;
if (this.print_conditions == 'mm') {
document.getElementById('<%= hid_print_month.ClientID %>').value = this.print_search.month;
}
else if (this.print_conditions == 'ss') {
document.getElementById('<%= hid_print_season.ClientID %>').value = this.print_search.season;
}
if (mode === 'print') {
document.getElementById('<%= print_management.ClientID %>').click();
}
else if (mode === "excel") {
document.getElementById('<%= excel_management.ClientID %>').click();
}
},
search_show(curr) {
//console.log("btn_click:", curr, curr.api_url);
this.search_dialog.current = curr;
@@ -228,6 +315,7 @@
//console.log(row, row["u_name"], row["f_number"], curr.id, target);
},
getList(clearpage = false) {
console.log("do getlist")
const { sortBy, sortDesc, page, itemsPerPage } = this.options
const params = {
sortBy: sortBy[0], sortDesc: sortDesc[0],
@@ -241,6 +329,9 @@
this.data_table.list = response.data.list
this.data_table.count = response.data.count;
this.data_table.loading = false
const dataToStore = JSON.stringify(this.data_table);
sessionStorage.setItem("member_list_cache", dataToStore);
})
.catch(
error => console.log(error)
@@ -262,7 +353,7 @@
const index = this.data_table.list.indexOf(item)
if (index != -1) {
axios
.delete(HTTP_HOST + 'api/follower/' + item.num)
.delete(HTTP_HOST + 'api/follower/Delete/' + item.num)
.then(response => {
this.getList();
})
@@ -282,18 +373,23 @@
//}
//this.data_table.selected = [];
//this.data_table.count = this.data_table.list.length
location.reload();
//location.reload();
this.getList();
})
.catch(error => console.log(error))
}
},
btn_search() {
this.isSearched = true;
sessionStorage.setItem("member_query_params", JSON.stringify(this.search));
this.getList(true)
bootstrap.Offcanvas.getInstance(document.getElementById("offcanvasRight")).hide()
},
btn_all() {
this.isSearched = false;
clearObjProps(this.search);
this.btn_search()
sessionStorage.setItem("member_query_params", JSON.stringify(this.search));
//this.btn_search()
},
goPrint() {
//debugger;
@@ -309,6 +405,7 @@
//列印管理報表
print_close() {
this.print_dialog.show = false;
this.print_error_msg = "";
}
,
initPrintSearch() {
@@ -391,10 +488,31 @@
$('#country2').val('');
VueApp.search.country2 = '';
});
$(document).ready(function () {
// 判斷是否彈出 search dialog
let hasSearchResult = sessionStorage.getItem("member_list_cache") !== null;
if (!hasSearchResult && window._printResult === '') {
let $btn = $("a[data-bs-target='#offcanvasRight'][href='#search_panel']");
$btn.click();
let el = document.getElementById('offcanvasRight');
let offcanvas = bootstrap.Offcanvas.getOrCreateInstance(el);
offcanvas.show();
}
});
</script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
<uc1:alert runat="server" ID="L_msg" Text="" />
<asp:HiddenField ID="hid_err_msg" runat="server" />
<asp:HiddenField ID="hid_print_year" runat="server" />
<asp:HiddenField ID="hid_print_month" runat="server" />
<asp:HiddenField ID="hid_print_season" runat="server" />
<asp:HiddenField ID="hid_print_mode" runat="server" />
<asp:HiddenField ID="hid_qry" runat="server" />
<asp:LinkButton ID="excel_management" runat="server" OnClick="export_Click" style="display:none;" />
<asp:LinkButton ID="print_management" runat="server" OnClick="export_Click" style="display:none;" />
<div id="content" class="container-fluid">
<v-data-table
v-model="data_table.selected"
@@ -508,9 +626,17 @@
</v-col>
</v-row>
<v-row>
<v-col>
<div v-if="print_error_msg" class="red--text mt-2 text-center" style="font-weight: bold;">
{{ print_error_msg }}
</div>
</v-col>
</v-row>
<v-row densee class="pt-3" >
<v-col :cols="12" class="pt-3 text-center" >
<v-btn class="ma-2" color="primary" dark @click="goPrint2" > 列印 </v-btn>
<v-btn class="ma-2" color="primary" dark @click="triggerManagementExport('print')" > 列印 </v-btn>
<v-btn class="ma-2" color="primary" dark @click="triggerManagementExport('excel')"> 匯出 Excel </v-btn>
<v-btn class="ma-2" color="green" dark @click="print_close" > 取消 </v-btn>
</v-col>
</v-row>
+137 -26
View File
@@ -1,17 +1,20 @@
using System;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.OleDb;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Configuration;
using System.IO;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Spreadsheet;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Interop;
using static TreeView;
@@ -19,11 +22,17 @@ public partial class admin_follower_index : MyWeb.config
{
public int page = 1;
private Model.ezEntities _db = new Model.ezEntities();
protected string lastAddedID;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
if (Session["LastAddedID"] != null)
{
lastAddedID = Session["LastAddedID"].ToString();
Session.Remove("LastAddedID");
}
BuildKind();
}
else
@@ -68,11 +77,26 @@ public partial class admin_follower_index : MyWeb.config
#endregion
#region Excel
#region
protected void excel_Click(object sender, EventArgs e)
protected void export_Click(object sender, EventArgs e)
{
var memoryStream = new MemoryStream();
LinkButton btn = sender as LinkButton;
if (btn == null) return;
bool isPrintMode = (btn.ID == "print_management");
bool isExcelMode = (btn.ID == "excel_management" || btn.ID == "excel");
bool isManagementMode = (btn.ID == "excel_management" || btn.ID == "print_management");
//查詢要匯出的資料
string _query = ""; // 紀錄匯出條件
var list = searchData(ref _query, isManagementMode);
if (isExcelMode)
{
if (list.Count > 0)
{
using (var doc = SpreadsheetDocument.Create(memoryStream, SpreadsheetDocumentType.Workbook))
{
var wb = doc.AddWorkbookPart();
@@ -134,14 +158,7 @@ public partial class admin_follower_index : MyWeb.config
);
sd.AppendChild(tr);
//查詢要匯出的資料
//紀錄匯出條件
string _query = "";
var list = searchData(ref _query);
if (list.Count > 0)
{
MyWeb.encrypt encrypt = new MyWeb.encrypt();
Model.country country = new Model.country();
var tdesc = publicFun.enum_desc<Model.follower.type>();
@@ -204,26 +221,117 @@ public partial class admin_follower_index : MyWeb.config
Model.admin_log admin_log = new Model.admin_log();
admin_log.writeLog(admin.info.u_id, (int)Model.admin_log.Systems.Follower, (int)Model.admin_log.Status.Excel, admin_log.LogViewBtn(list.Select(x => x.f_number + x.u_name).ToList()));
}
else
{
ScriptMsg2("查無資料");
}
}
}
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.AddHeader("content-disposition", "attachment; filename=信眾_data.xlsx");
HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
HttpContext.Current.Response.BinaryWrite(memoryStream.ToArray());
HttpContext.Current.Response.End();
hid_err_msg.Value = "success";
}
protected List<Model.follower> searchData(ref string _query)
else
{
//ScriptMsg2("查無資料");
hid_err_msg.Value = "nodata";
}
}
else if (isPrintMode)
{
string urlParams = "";
int selYear = !string.IsNullOrEmpty(hid_print_year.Value) ? int.Parse(hid_print_year.Value) : 0;
int selMonth = !string.IsNullOrEmpty(hid_print_month.Value) ? int.Parse(hid_print_month.Value) : 0;
int selSeason = !string.IsNullOrEmpty(hid_print_season.Value) ? int.Parse(hid_print_season.Value) : 0;
string selMode = !string.IsNullOrEmpty(hid_print_mode.Value) ? hid_print_mode.Value : "";
var qry = _db.followers.AsQueryable();
if (selYear > 0)
{
urlParams += "&year=" + selYear;
}
if (selMode == "mm" && selMonth > 0)
{
urlParams += "&month=" + selMonth;
}
else if (selMode == "ss" && selSeason > 0)
{
urlParams += "&season=" + selSeason;
}
if (list.Count > 0)
{
hid_err_msg.Value = "success";
hid_print_year.Value = selYear.ToString();
hid_print_month.Value = selMonth.ToString();
hid_print_season.Value = selSeason.ToString();
hid_print_mode.Value = selMode;
string script = $@"window.open('print.aspx?{urlParams}&mode={selMode}', '列印信眾資料', 'noopener,noreferrer');";
ScriptManager.RegisterStartupScript(this, GetType(), "ExecutePrint", script, true);
}
else
{
hid_err_msg.Value = "nodata";
}
}
}
protected List<Model.follower> searchData(ref string _query, bool isManagementMode = false)
{
//查詢要匯出的資料
var qry = _db.followers.AsQueryable();
// 管理報表
if (isManagementMode)
{
int selYear = !string.IsNullOrEmpty(hid_print_year.Value) ? int.Parse(hid_print_year.Value) : 0;
int selMonth = !string.IsNullOrEmpty(hid_print_month.Value) ? int.Parse(hid_print_month.Value) : 0;
int selSeason = !string.IsNullOrEmpty(hid_print_season.Value) ? int.Parse(hid_print_season.Value) : 0;
string selMode = !string.IsNullOrEmpty(hid_print_mode.Value) ? hid_print_mode.Value : "";
if (selYear > 0)
{
qry = qry.Where(o => o.join_date.HasValue && o.join_date.Value.Year == selYear);
_query += "年份:" + selYear + "\n";
}
if (selMode == "mm" && selMonth > 0)
{
qry = qry.Where(o => o.join_date.HasValue && o.join_date.Value.Month == selMonth);
_query += "月份:" + selMonth + "\n";
}
else if (selMode == "ss" && selSeason > 0)
{
if (selSeason == 1)
{
qry = qry.Where(o => o.join_date.HasValue)
.Where(o => o.join_date.Value.Month == 1 || o.join_date.Value.Month == 2 || o.join_date.Value.Month == 3);
}
else if (selSeason == 2)
{
qry = qry.Where(o => o.join_date.HasValue)
.Where(o => o.join_date.Value.Month == 4 || o.join_date.Value.Month == 5 || o.join_date.Value.Month == 6);
}
else if (selSeason == 3)
{
qry = qry.Where(o => o.join_date.HasValue)
.Where(o => o.join_date.Value.Month == 7 || o.join_date.Value.Month == 8 || o.join_date.Value.Month == 9);
}
else if (selSeason == 4)
{
qry = qry.Where(o => o.join_date.HasValue)
.Where(o => o.join_date.Value.Month == 10 || o.join_date.Value.Month == 11 || o.join_date.Value.Month == 12);
}
_query += "季度:" + selSeason + "\n";
}
qry = qry.OrderByDescending(o => o.num);
return qry.ToList();
}
else
// 匯出查詢資料
{
//紀錄匯出條件
if (!isStrNull(s_f_number.Value))
{
@@ -243,7 +351,7 @@ public partial class admin_follower_index : MyWeb.config
if (!isStrNull(s_address.Value))
{
qry = qry.Where(o => o.address.Contains(s_address.Value.Trim()));
_query += "地址:" + s_u_name.Value.Trim() + "\n";
_query += "地址:" + s_address.Value.Trim() + "\n";
}
// 電話/證號搜尋 (使用 search_keywords HEX 編碼)
@@ -260,16 +368,19 @@ public partial class admin_follower_index : MyWeb.config
if (!isStrNull(s_birthday.Value) && isDate(s_birthday.Value))
{
qry = qry.Where(o => o.birthday >= ValDate(s_birthday.Value));
var tmp_s_birthday = ValDate(s_birthday.Value);
qry = qry.Where(o => o.birthday >= tmp_s_birthday);
_query += "生日(起):" + s_birthday.Value.Trim() + "\n";
}
if (!isStrNull(s_birthday2.Value) && isDate(s_birthday2.Value))
{
qry = qry.Where(o => o.birthday < Convert.ToDateTime(s_birthday2.Value).AddDays(1));
var tmp_s_birthday2 = Convert.ToDateTime(s_birthday2.Value).AddDays(1);
qry = qry.Where(o => o.birthday < tmp_s_birthday2);
_query += "生日(訖):" + s_birthday2.Value.Trim() + "\n";
}
qry = qry.OrderByDescending(o => o.num);
return qry.ToList();
}
}
+1
View File
@@ -8,6 +8,7 @@
<span>信眾姓名:</span><asp:Literal runat="server" ID="username"></asp:Literal>
</div>
</div>
<a href="index.aspx" class="btn btn-outline-secondary">返回</a>
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<div class="container-fluid">
@@ -8,6 +8,7 @@
<span>信眾姓名:</span><asp:Literal runat="server" ID="username"></asp:Literal>
</div>
</div>
<a href="order_record.aspx?userid=<%=Request["userid"] %>" class="btn btn-outline-secondary">返回</a>
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<div class="container-fluid">
+15 -1
View File
@@ -3,6 +3,7 @@ using DocumentFormat.OpenXml.Vml.Office;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Web;
using System.Web.UI;
@@ -60,7 +61,8 @@ public partial class admin_follower_print_ : System.Web.UI.Page
if (!string.IsNullOrEmpty(Request["birthday2"]))
{
DateTime birthday2Param = Convert.ToDateTime(Request["birthday2"].Trim());
qry = qry.Where(o => o.birthday < birthday2Param.AddDays(1));
var tmpBirthday2Param = birthday2Param.AddDays(1);
qry = qry.Where(o => o.birthday < tmpBirthday2Param);
_query += "生日(訖):" + birthday2Param.ToString("yyyy/MM/dd") + "\n";
}
// ❌ 錯誤寫法: _db.countries.Where(x => x.ID == Request["country"].ToString())
@@ -86,6 +88,18 @@ public partial class admin_follower_print_ : System.Web.UI.Page
_query += "國家:" + (_db.countries.Where(x => x.ID == country2Id).Select(x => x.name_zh).FirstOrDefault() ?? "") + "\n";
}
string phone_ipcode = Request["phone_idcode"]?.ToString();
if (!string.IsNullOrEmpty(phone_ipcode) && GlobalVariables.UseSearchKeywords)
{
MyWeb.encrypt encrypt = new MyWeb.encrypt();
string hexSearch = encrypt.ConvertToHex(phone_ipcode.Trim());
if (!string.IsNullOrEmpty(hexSearch))
{
qry = qry.Where(o => o.search_keywords != null && o.search_keywords.Contains(hexSearch));
_query += "電話/證號:" + phone_ipcode.Trim() + "\n";
}
}
//管理報表
if (!string.IsNullOrEmpty(Request["year"]))
{
+25 -5
View File
@@ -585,7 +585,7 @@
this.search_dialog.list = response.data.list
this.search_dialog.count = response.data.count
this.search_dialog.loading = false
console.log(this.search_dialog.list)
})
.catch(error => {
console.log(error)
@@ -1318,13 +1318,32 @@
$('.tab-pane,.edit_Click').removeClass('pe-none'); // 移除 pe-none 類,允許編輯
}
});
let isComposing = false;
const cellphoneInput = document.querySelector('[id$="cellphone"]');
if (cellphoneInput) {
cellphoneInput.addEventListener('compositionstart', () => {
isComposing = true;
});
cellphoneInput.addEventListener('compositionend', (e) => {
isComposing = false;
formatCellphone(e.target);
});
cellphoneInput.addEventListener('input', (e) => {
if (!isComposing) {
formatCellphone(e.target);
}
});
}
</script>
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="page_nav" runat="Server">
<div class="scroll-nav nav nav-tabs mb-2 mb-sm-0 d-none d-sm-flex">
<template v-if="follower_id !='' "> {{titleword()}} </template>
</div>
<div class="d-flex align-items-center">
<div class="">
<div class="form-check me-3 d-none" id="editCheckboxContainer">
<input class="form-check-input" type="checkbox" id="editCheckbox">
<label class="form-check-label" for="editCheckbox">
@@ -1332,8 +1351,8 @@
</label>
</div>
<asp:Button ID="add" runat="server" Text="送出" OnClick="add_Click" CssClass="btn btn-primary edit_Click noedit" />
<asp:Button ID="edit" runat="server" Text="修改" Visible="false" OnClick="edit_Click" CssClass="btn btn-primary edit_Click noedit" />
<asp:Button ID="goback" runat="server" Text="回列表" Visible="false" CausesValidation="false" OnClick="goback_Click" CssClass="btn btn-outline-secondary" />
<asp:Button ID="edit" runat="server" Text="儲存" Visible="false" OnClick="edit_Click" CssClass="btn btn-primary edit_Click noedit" />
<asp:Button ID="goback" runat="server" Text="取消" Visible="true" CausesValidation="false" OnClick="goback_Click" CssClass="btn btn-outline-secondary" />
</div>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
@@ -1412,7 +1431,7 @@
</div>
<label class="col-sm-2 col-lg-1 col-form-label">手機號碼<asp:Literal ID="cellphoneReqStar" runat="server" Text=" *"></asp:Literal></label>
<div class="col-sm-10 col-lg-3">
<asp:TextBox ID="cellphone" MaxLength="12" runat="server" CssClass="form-control" data-encrypt="Y" placeholder="聯絡電話與手機號碼請至少填寫一項" oninput="formatCellphone(this)"></asp:TextBox>
<asp:TextBox ID="cellphone" MaxLength="12" runat="server" CssClass="form-control" data-encrypt="Y" placeholder="聯絡電話與手機號碼請至少填寫一項"></asp:TextBox>
<asp:RegularExpressionValidator ControlToValidate="cellphone" Display="Dynamic" ErrorMessage="格式有誤" ID="RegularExpressionValidator2" runat="server" SetFocusOnError="true" ValidationExpression="^09\d{2}-?\d{3}-?\d{3}$" />
</div>
</div>
@@ -2155,4 +2174,5 @@
</template>
</v-snackbar>
</div>
</asp:Content>
+68 -10
View File
@@ -1,21 +1,26 @@
using System;
using Model;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Entity;
using System.Data.OleDb;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Globalization;
using Model;
public partial class admin_follower_reg : MyWeb.config
{
private Model.ezEntities _db = new Model.ezEntities();
public ArrayList _tmp = new ArrayList();
public bool isDataChanged = false;
public bool isAutoNumbering = ConfigurationManager.AppSettings["IsAutoNumbering"].ToString() == "true" ? true : false;
protected void Page_Load(object sender, EventArgs e)
{
CallAjax();
@@ -29,6 +34,11 @@ public partial class admin_follower_reg : MyWeb.config
if (isStrNull(Request["num"]))
{
if (!isAutoNumbering)
{
f_number.ReadOnly = false;
}
if (!isStrNull(Request["leader"]))
{
int _num = Val(Request["leader"]);
@@ -50,9 +60,14 @@ public partial class admin_follower_reg : MyWeb.config
//預設國籍
country.Value = "158";
country_txt.Value = "中華民國(台灣)";
// 預設加入日期
join_date.Text = DateTime.Now.ToString("yyyy-MM-dd");
}
else
{
f_number.ReadOnly = true;
int _num = Val(Request["num"]);
var prod = qry.Where(q => q.num == _num).FirstOrDefault();
if (prod != null)
@@ -206,8 +221,11 @@ public partial class admin_follower_reg : MyWeb.config
}
}
}
if (isAutoNumbering)
{
// 使用新的 generate_f_number 方法,已內建重號檢查和重試機制
followers.f_number = follower.generate_f_number(sex.SelectedValue);
}
followers.identity_type = Val(identity_type.SelectedValue);
if(!isStrNull(leader.Value)) followers.leader = Val(leader.Value);
if (!isStrNull(country.Value)) followers.country = country.Value;
@@ -240,6 +258,8 @@ public partial class admin_follower_reg : MyWeb.config
Model.admin_log admin_log = new Model.admin_log();
admin_log.writeLog(admin.info.u_id, (int)Model.admin_log.Systems.Follower, (int)Model.admin_log.Status.Insert, f_number.Text + u_name.Text);
Session["LastAddedID"] = followers.f_number;
Response.Redirect("index.aspx");
}
else
@@ -310,7 +330,7 @@ public partial class admin_follower_reg : MyWeb.config
followers.sex = sex.SelectedValue;
followers.blood = blood.SelectedValue;
followers.tab = tab.Value.Trim(',');
followers.admin_log = admin.info.u_id + " " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
//followers.admin_log = admin.info.u_id + " " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
followers.follower_hash = encrypt.followerHash(followers.phone, followers.id_code);
// 如果啟用 search_keywords 功能,生成並更新 search_keywords
@@ -319,13 +339,51 @@ public partial class admin_follower_reg : MyWeb.config
followers.search_keywords = encrypt.GenerateSearchKeywords(followers);
}
_db.SaveChanges();
// 檢查是否有修改資料
var entry = _db.Entry(followers);
this.isDataChanged = entry.CurrentValues.PropertyNames.Any(name =>
{
if (name == "admin_log" || name == "follower_hash")
return false;
var originalVal = entry.OriginalValues[name]?.ToString();
var currentVal = entry.CurrentValues[name]?.ToString();
// 針對加密欄位進行特殊處理
bool isEncryptedField = (name == "phone" || name == "id_code");
if (isEncryptedField)
{
string originalPlain = !string.IsNullOrEmpty(originalVal) ? encrypt.DecryptAutoKey(originalVal) : "";
string currentPlain = !string.IsNullOrEmpty(currentVal) ? encrypt.DecryptAutoKey(currentVal) : "";
return originalPlain.Trim() != currentPlain.Trim();
}
return !object.Equals(originalVal, currentVal);
});
if (this.isDataChanged)
{
followers.admin_log = admin.info.u_id + " " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
}
else
{
entry.State = EntityState.Unchanged;
}
int isDataSaved = _db.SaveChanges();
if (isDataSaved > 0)
{
//L_msg.Type = alert_type.success;
//L_msg.Text = "修改成功";
Model.admin_log admin_log = new Model.admin_log();
admin_log.writeLog(admin.info.u_id, (int)Model.admin_log.Systems.Follower, (int)Model.admin_log.Status.Update, f_number.Text + u_name.Text);
Response.Redirect("index.aspx?dirty=1&page=" + Convert.ToString(Request["page"]));
}
else
{
Response.Redirect("index.aspx?page=" + Convert.ToString(Request["page"]));
}
}
catch (Exception ex)
{
+31
View File
@@ -105,5 +105,36 @@
</div>
</div>
<!-- /.content_box -->
<script>
document.addEventListener('DOMContentLoaded', function () {
var accountInput = document.getElementById('<%= u_id.ClientID %>');
var passwordInput = document.getElementById('<%= u_password.ClientID %>');
var chkInput = document.getElementById('<%= chknum.ClientID %>');
var btn = document.getElementById('<%= Button1.ClientID %>');
accountInput.addEventListener('keypress', function (e){
if (e.keyCode === 13) {
$("#<%= u_password.ClientID %>").focus();
return false;
}
})
passwordInput.addEventListener('keypress', function (e) {
if (e.keyCode === 13) {
$("#<%= chknum.ClientID %>").focus();
return false;
}
})
var triggerLogin = function (e) {
if (e.keyCode === 13) {
btn.click();
e.preventDefault();
return false;
}
};
if (chkInput) chkInput.addEventListener('keypress', triggerLogin);
});
</script>
</asp:Content>
File diff suppressed because it is too large Load Diff
+7 -3
View File
@@ -23,6 +23,9 @@ public class TabletElement
public double? threeOffset { get; set; }
public double? fourOffset { get; set; }
public int? breakLen { get; set; }
public string backendInp { get; set; }
public double? textWidth { get; set; }
public double? textHeight { get; set; }
}
@@ -58,12 +61,13 @@ public partial class admin_item_TabletDesigner :MyWeb.config
{
elements = new List<TabletElement> {
new TabletElement {
id = "address", type = "address", text = "台中市潭子區中山路", x = 160, y = 80,
id = "address", type = "address", text = "台中市潭子區中山路", x = 60, y = 80,
style = new ElementStyle { fontSize = 24, fontFamily = "Kaiti", isVertical = true, letterSpacing = 5, lineHeight = 1.5,visibility="" }
},
new TabletElement {
id = "title1", type = "ancestor", text = "牌位正名", x = 130, y = 80,
style = new ElementStyle { fontSize = 24, fontFamily = "Kaiti", isVertical = true, letterSpacing = 5, lineHeight = 1.5 ,visibility="" }
id = "title1", type = "ancestor", text = "張一\n李二\n陳三\n吳四\n劉五\n趙六\n林七\n徐八", x = 50, y = 80,
width=136,height=600,textWidth=20,textHeight=90,
style = new ElementStyle { fontSize = 16, fontFamily = "Kaiti", isVertical = true, letterSpacing = 1, lineHeight = 1 ,visibility="" }
},
new TabletElement {
id = "lefttitle", type = "ancestor", text = "左正名", x = 10, y = 80,
+20 -8
View File
@@ -1,7 +1,7 @@
:host {
display: block;
width: 100%;
height: 100%;
width: auto;
height: auto;
--canvas-bg: #f8f9fa;
--canvas-grid: #dee2e6;
--paper-bg: #fffbf0;
@@ -16,6 +16,17 @@
/* 紙張保持米黃,因為它是實物模擬 */
}
/*.yangshang-wrapper {
display: flex !important;
flex-direction: row !important;*/ /* 垂直堆疊 */
/*justify-content: space-between !important;*/ /* 陽上與拜薦各據頂底 */
/*align-items: center !important;*/ /* 水平方向置中 */
/*height: 100% !important;
width: 100% !important;
writing-mode: vertical-rl !important;*/ /* 確保內部文字均為垂直書寫 */
/*text-orientation: upright !important;*/ /* 確保文字方向轉正 */
/*gap: 1px;
}*/
.designer-root {
/* 防止瀏覽器預設捲動影響畫布 */
@@ -27,7 +38,7 @@
background-image: linear-gradient(45deg, var(--canvas-grid) 25%, transparent 25%), linear-gradient(-45deg, var(--canvas-grid) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, var(--canvas-grid) 75%), linear-gradient(-45deg, transparent 75%, var(--canvas-grid) 75%);
background-size: 20px 20px;
transition: background-color 0.3s;
min-height: 100vw;
/* min-height: 100vw;*/
}
@@ -67,10 +78,10 @@
/* 名單金字塔佈局容器 */
.roster-container {
width: 100%; height: 100%;
width: 100%; height: 600px;
writing-mode: vertical-rl; /* 直書 */
display: flex;
//flex-direction: column; /* 雖然是直書,但物理上我們是將「上層區」和「下層區」垂直堆疊 */
/*flex-direction: column;*/ /* 雖然是直書,但物理上我們是將「上層區」和「下層區」垂直堆疊 */
flex-direction: row; /* 上下分層 (Top / Bottom) */
align-items: center; /* 左右置中對齊 */
justify-content: center;
@@ -95,12 +106,13 @@
.roster-name {
text-orientation: upright;
font-weight: bold;
/*font-weight: bold;*/
white-space: nowrap;
line-height: 1.2;
font-family: 'Kaiti', serif;
/* 確保名字本身不會佔據過多寬度導致間距看起來很大 */
/* width: fit-content;*/
width: fit-content;
height:200px;
}
@@ -220,7 +232,7 @@
display: flex;
flex-direction: column;
align-items: center; /* 水平置中 */
justify-content: center;
justify-content: flex-start;
width: fit-content;
}
+13
View File
@@ -0,0 +1,13 @@
<%@ Page Title="" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="detail.aspx.cs" Inherits="admin_order_detail" %>
<asp:Content ID="Content1" ContentPlaceHolderID="page_header" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="page_nav" Runat="Server">
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
</asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server">
</asp:Content>
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" Runat="Server">
</asp:Content>
+14
View File
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class admin_order_detail : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
+205 -33
View File
@@ -14,17 +14,18 @@
<a @click="print_dialog.show=true" class="btn btn-outline-primary btn-print" target="_blank">
<i class="mdi mdi-printer"></i>列印管理報表
</a>
<div :style="data_table.list.length === 0 ? 'pointer-events: none; opacity: 0.5;' : ''" style="display:inline-block;">
<div class="dropdown d-inline-block">
<a class="btn btn-outline-primary btn-print dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false"><i class="mdi mdi-printer"></i>列印報名資料</a>
<a class="btn btn-outline-primary btn-print dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-expanded="false"><i class="mdi mdi-printer"></i>列印查詢資料</a>
<ul class="dropdown-menu ps-0 w-100" aria-labelledby="dropdownPrintLink">
<li><a @click="search.hasPrice='Y';goPrint()" class="dropdown-item"><i class="mdi mdi-printer me-1"></i>有金額</a></li>
<li><a @click="search.hasPrice='N';goPrint()" class="dropdown-item"><i class="mdi mdi-printer me-1"></i>無金額</a></li>
</ul>
</div>
<asp:LinkButton ID="excel" runat="server" CssClass="btn btn-outline-success" OnClick="excel_Click"><span class="fa-solid fa-file-excel"></span> 匯出Excel</asp:LinkButton>
</div>
<div :style="data_table.list.length === 0 ? 'pointer-events: none; opacity: 0.5;' : ''" style="display:inline-block;">
<asp:LinkButton ID="excel" runat="server" CssClass="btn btn-outline-success" OnClick="excel_Click"><span class="fa-solid fa-file-excel"></span> 匯出查詢資料(Excel</asp:LinkButton>
</div>
</div>
</asp:Content>
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" runat="Server">
@@ -39,6 +40,8 @@
vuetify: new Vuetify(vuetify_options),
data() {
return {
print_error_msg: "",
isSearched: false,
this_act : '<%= Request["act_id"]%>',
options: { multiSort: false },
search_options: { multiSort: false },
@@ -56,6 +59,7 @@
{ text: '報名日期', value: 'up_time' },
{ text: '報名活動', value: 'subject', align: 'start' },
{ text: '單據狀態', value: 'keyin1_txt' },
{ text: '報到狀態', value: 'status' },
{ text: '', value: 'slot_btn', sortable: false, align: 'end' }
],
footer:{
@@ -203,6 +207,10 @@
}
},
mounted() {
const printResult = document.getElementById('<%= hid_err_msg.ClientID %>').value;
document.getElementById('<%= hid_err_msg.ClientID %>').value = '';
window._printResult = printResult
this.detalKeyinArray();
this.search_dialog.current = this.search_dialog.controls.search1 ///default
if (this.this_act != '')
@@ -211,20 +219,63 @@
this.initActivity();
const navEntries = performance.getEntriesByType("navigation");
const isReload = navEntries.length > 0 && navEntries[0].type === "reload";
if (isReload) {
sessionStorage.removeItem("orderpage");
sessionStorage.removeItem("order_list_cache");
sessionStorage.removeItem("order_query_params");
}
else if ("<%=lastAddedNo%>" !== "") {
const newQuery = { order_no: '<%=lastAddedNo%>' };
sessionStorage.setItem('order_query_params', JSON.stringify(newQuery));
this.search = newQuery;
this.isSearched = true;
}
else {
const savedPage = parseInt(sessionStorage.getItem('orderpage'));
const savedData = sessionStorage.getItem("order_list_cache");
const savedQuery = JSON.parse(sessionStorage.getItem("order_query_params"));
if (savedQuery) {
this.search = savedQuery;
this.isSearched = true;
}
if (savedPage) {
this.options.page = savedPage;
}
if (savedData && savedData !== "undefined") {
this.data_table = JSON.parse(savedData);
this.isSearched = true;
}
}
if (printResult === 'nodata' || printResult === 'success') {
this.$nextTick(() => {
this.print_dialog.show = true;
if (printResult === 'nodata') {
this.print_error_msg = "查無資料,請重新選擇區間";
}
});
}
this.$nextTick(() => {
setTimeout(() => {
// 清空 URL
const cleanUrl = window.location.protocol + "//" + window.location.host + window.location.pathname;
window.history.replaceState({}, '', cleanUrl);
}, 100);
});
},
watch: {
options: {
handler() {
if (this.isSearched) {
this.getDefault()
}
else {
this.data_table.loading = false;
}
},
deep: true,
},
@@ -236,6 +287,57 @@
},
},
methods: {
triggerManagementExport(mode) {
this.print_error_msg = "";
if (this.print_search.year == '') {
msgbox('請輸入年份');
return;
}
if (!this.print_search.chk_noact && !this.print_search.chk_hasact) {
msgbox('活動/非活動至少勾選一項');
return;
}
// 將 Vue 狀態同步至 ASP.NET HiddenField,供後端 PostBack 讀取參數
document.getElementById('<%= hid_print_mode.ClientID %>').value = this.print_conditions;
document.getElementById('<%= hid_print_year.ClientID %>').value = this.print_search.year;
if (this.print_conditions == 'mm')
document.getElementById('<%= hid_print_month.ClientID %>').value = this.print_search.month;
else if (this.print_conditions == 'ss')
document.getElementById('<%= hid_print_season.ClientID %>').value = this.print_search.season;
document.getElementById('<%= hid_select_act.ClientID %>').value = this.print_search.select_act;
document.getElementById('<%= hid_select_actitem.ClientID %>').value = this.print_search.select_actitem;
document.getElementById('<%= hid_chk_hasact.ClientID %>').value = this.print_search.chk_hasact;
document.getElementById('<%= hid_chk_noact.ClientID %>').value = this.print_search.chk_noact;
let qry = "";
Object.keys(this.print_search).forEach(key => {
if (this.print_search[key] != undefined && this.print_search[key] != null && this.print_search[key] != '') {
if (key == 'month' ) {
if (this.print_conditions == 'mm') {
qry += "&month=" + this.print_search.month;
}
} else if ( key == 'season')
{
if (this.print_conditions == 'ss') {
qry += "&season=" + this.print_search.season;
}
}
else {
qry += (qry != '' ? '&' : '?') + (key + '=' + this.print_search[key]);
}
}
});
document.getElementById('<%= hid_qry.ClientID %>').value = qry;
if (mode === 'print') {
document.getElementById('<%= print_management.ClientID %>').click();
}
else if (mode === "excel") {
document.getElementById('<%= excel_management.ClientID %>').click();
}
},
search_show(curr) {
//console.log("btn_click:", curr, curr.api_url);
this.search_dialog.current = curr;
@@ -321,11 +423,15 @@
this.data_table.list = response.data.list
this.data_table.count = response.data.count;
this.data_table.loading = false
const dataToStore = JSON.stringify(this.data_table);
sessionStorage.setItem("order_list_cache", dataToStore);
})
.catch(error => console.log(error))
},
detalKeyinArray() {
var getArray = <%=Newtonsoft.Json.JsonConvert.SerializeObject(_keyin1Item, Newtonsoft.Json.Formatting.Indented) %>;
if (getArray !== null) {
var keys = Object.keys(getArray);
for (let i = 0; i < keys.length; i++) {
//console.log(`${keys[i]}:${getArray[keys[i]]}`); //value : text
@@ -335,6 +441,7 @@
}
this.keyin1_items.push(_tmp);
}
}
},
editItem(item) {
@@ -368,22 +475,28 @@
//}
//this.data_table.selected = [];
//this.data_table.count = this.data_table.list.length
location.reload();
//location.reload();
this.getDefault();
})
.catch(error => console.log(error))
}
},
btn_search() {
this.isSearched = true;
sessionStorage.setItem("order_query_params", JSON.stringify(this.search));
this.this_act = '';
this.search.activity_num = '';
this.getDefault(true)
bootstrap.Offcanvas.getInstance(document.getElementById("offcanvasRight")).hide()
},
btn_all() {
this.isSearched = false;
this.this_act = '';
this.search.activity_num = '';
clearObjProps(this.search);
this.btn_search()
sessionStorage.setItem("order_query_params", JSON.stringify(this.search));
//this.btn_search()
},
checkInMsg(item) {
this.check_data.f_num = item.f_num;
@@ -392,29 +505,20 @@
this.check_data.activity_name = item.subject;
this.check_dialog.show = true;
},
checkIn() {
if (this.check_data.qty > 0 && this.check_data.status.val > 0) {
var chechdata =
checkIn(item) {
var checkdata =
{
f_num: this.check_data.f_num,
activity_num: this.check_data.activity_num,
status: this.check_data.status.val,
qty: this.check_data.qty,
f_num: item.f_num,
activity_num: item.activity_num,
status: 1,
qty: 1,
}
console.log(checkdata)
axios
.post(HTTP_HOST + 'api/activity/OrderCheckIn', chechdata)
.post(HTTP_HOST + 'api/activity/OrderCheckIn', checkdata)
.then(response => {
//清空
this.check_data.f_num = 0;
this.check_data.u_name = '';
this.check_data.activity_num = 0;
this.check_data.activity_name = '';
this.check_data.qty = 1;
this.check_data.status.text = '';
this.check_data.status.val = 1;
this.check_dialog.show = false;
msgtop('簽到成功')
msgtop('簽到成功');
this.getDefault();
})
.catch(
error => {
@@ -422,9 +526,38 @@
msgtop('簽到失敗', 'error')
}
)
} else {
msgbox('報到資訊請填寫完整');
}
//if (this.check_data.qty > 0 && this.check_data.status.val > 0) {
// var chechdata =
// {
// f_num: this.check_data.f_num,
// activity_num: this.check_data.activity_num,
// status: this.check_data.status.val,
// qty: this.check_data.qty,
// }
// axios
// .post(HTTP_HOST + 'api/activity/OrderCheckIn', chechdata)
// .then(response => {
// //清空
// this.check_data.f_num = 0;
// this.check_data.u_name = '';
// this.check_data.activity_num = 0;
// this.check_data.activity_name = '';
// this.check_data.qty = 1;
// this.check_data.status.text = '';
// this.check_data.status.val = 1;
// this.check_dialog.show = false;
// msgtop('簽到成功')
// })
// .catch(
// error => {
// console.log(error)
// msgtop('簽到失敗', 'error')
// }
// )
//} else {
// msgbox('報到資訊請填寫完整');
//}
}, goPrint() {
let _qry = "";
Object.keys(this.search).forEach(key => {
@@ -442,6 +575,7 @@
//列印管理報表
print_close() {
this.print_dialog.show = false;
this.print_error_msg = "";
}
,
initPrintSearch() {
@@ -504,9 +638,9 @@
}
}
});
console.log(_qry);
this.print_dialog.show = false;
window.open("print.aspx" + _qry, '_blank');
//window.open("print.aspx" + _qry, '_blank');
} else {
msgbox('活動/非活動至少勾選一項');
}
@@ -556,10 +690,35 @@
$('#country2').val('');
VueApp.search.country2 = '';
});
$(document).ready(function () {
// 判斷是否彈出 search dialog
let hasSearchResult = sessionStorage.getItem("order_list_cache") !== null;
if (!hasSearchResult && window._printResult === '') {
let $btn = $("a[data-bs-target='#offcanvasRight'][href='#search_panel']");
$btn.click();
let el = document.getElementById('offcanvasRight');
let offcanvas = bootstrap.Offcanvas.getOrCreateInstance(el);
offcanvas.show();
}
});
</script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
<uc1:alert runat="server" ID="L_msg" Text="" />
<asp:HiddenField ID="hid_err_msg" runat="server" />
<asp:HiddenField ID="hid_print_year" runat="server" />
<asp:HiddenField ID="hid_print_month" runat="server" />
<asp:HiddenField ID="hid_print_season" runat="server" />
<asp:HiddenField ID="hid_print_mode" runat="server" />
<asp:HiddenField ID="hid_chk_hasact" runat="server" />
<asp:HiddenField ID="hid_chk_noact" runat="server" />
<asp:HiddenField ID="hid_select_act" runat="server" />
<asp:HiddenField ID="hid_select_actitem" runat="server" />
<asp:HiddenField ID="hid_qry" runat="server" />
<asp:LinkButton ID="print_management" runat="server" OnClick="export_Click" style="display:none;" />
<asp:LinkButton ID="excel_management" runat="server" OnClick="export_Click" style="display:none;" />
<div id="content" class="container-fluid">
<v-data-table
v-model="data_table.selected"
@@ -581,9 +740,12 @@
{{ item.up_time|timeString('YYYY/MM/DD') }}
</template>
<template #item.u_name="{ item }" >
<a v-if="item.f_num != null && item.activity_num != null" @click="checkInMsg(item)" class="btn btn-outline-secondary btn-sm"><i class="mdi mdi-account-check"></i>報到</a>
{{ item.u_name }}
</template>
<template #item.status="{ item }" >
<a v-if="item.f_num != null && item.activity_num != null && item.status == 0" @click="checkIn(item)" class="btn btn-outline-secondary btn-sm"><i class="mdi mdi-account"></i>報到</a>
<a v-if="item.f_num != null && item.activity_num != null && item.status == 1" class="btn btn-outline-secondary btn-sm opacity-50" style="pointer-events: none" ><i class="mdi mdi-account-check"></i>已報到</a>
</template>
<template #item.slot_btn="{ item }">
<a :href="'reg.aspx?order_no='+item.order_no" class="btn btn-outline-secondary btn-sm"><i class="mdi mdi-pencil-box-outline"></i>修改</a>
<a @click="deleteItem(item)" class="btn btn-outline-secondary btn-sm"><i class="mdi mdi-trash-can"></i>刪除</a>
@@ -693,6 +855,7 @@
item-value="val"
v-model="print_search.month"
:items="select_items.month"
eager
></v-select>
</v-col>
<v-col :cols="2" class="pt-5" v-if="print_conditions=='ss' ">
@@ -704,6 +867,7 @@
item-value="val"
v-model="print_search.season"
:items="select_items.season"
eager
></v-select>
</v-col>
@@ -764,9 +928,17 @@
</v-row>
</v-col>--%>
</v-row>
<v-row>
<v-col>
<div v-if="print_error_msg" class="red--text mt-2 text-center" style="font-weight: bold;">
{{ print_error_msg }}
</div>
</v-col>
</v-row>
<v-row densee class="pt-3" >
<v-col :cols="12" class="pt-3 text-center" >
<v-btn class="ma-2" color="primary" dark @click="goPrint2" > 列印 </v-btn>
<v-btn class="ma-2" color="primary" dark @click="triggerManagementExport('print')" > 列印 </v-btn>
<v-btn class="ma-2" color="primary" dark @click="triggerManagementExport('excel')"> 匯出 Excel </v-btn>
<v-btn class="ma-2" color="green" dark @click="print_close" > 取消 </v-btn>
</v-col>
</v-row>
+561 -22
View File
@@ -1,22 +1,28 @@
using System;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.OleDb;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Configuration;
using System.IO;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Spreadsheet;
using System.Linq;
using static Model.admin_log;
using static regionController;
public partial class admin_order_index : MyWeb.config
{
private Model.ezEntities _db = new Model.ezEntities();
public Dictionary<int, string> _keyin1Item = null;
protected string lastAddedNo;
protected void Page_Load(object sender, EventArgs e)
{
@@ -33,6 +39,13 @@ public partial class admin_order_index : MyWeb.config
}
_keyin1Item = publicFun.enum_desc<Model.activity_check.keyin1>(); //狀態
if (Session["LastAddedNo"] != null)
{
lastAddedNo = Session["LastAddedNo"].ToString();
Session.Remove("LastAddedNo");
}
BuildKind();
}
@@ -58,6 +71,452 @@ public partial class admin_order_index : MyWeb.config
#endregion
#region Excel
protected void export_Click(object sender, EventArgs e)
{
LinkButton btn = sender as LinkButton;
if (btn == null) return;
bool isPrintMode = (btn.ID == "print_management");
bool isExcelMode = (btn.ID == "excel_management" || btn.ID == "excel");
//查詢要匯出的資料
string _query = ""; // 紀錄匯出條件
//var list = searchData(ref _query, isManagementMode);
if (isExcelMode)
{
int selYear = !string.IsNullOrEmpty(hid_print_year.Value) ? int.Parse(hid_print_year.Value) : 0;
int selMonth = !string.IsNullOrEmpty(hid_print_month.Value) ? int.Parse(hid_print_month.Value) : 0;
int selSeason = !string.IsNullOrEmpty(hid_print_season.Value) ? int.Parse(hid_print_season.Value) : 0;
string selMode = !string.IsNullOrEmpty(hid_print_mode.Value) ? hid_print_mode.Value : "";
bool chkHasAct = !string.IsNullOrEmpty(hid_chk_hasact.Value) && Convert.ToBoolean(hid_chk_hasact.Value);
bool chkNoAct = !string.IsNullOrEmpty(hid_chk_noact.Value) && Convert.ToBoolean(hid_chk_noact.Value);
int selAct = !string.IsNullOrEmpty(hid_select_act.Value) ? int.Parse(hid_select_act.Value) : 0;
int selActItem = !string.IsNullOrEmpty(hid_select_actitem.Value) ? int.Parse(hid_select_actitem.Value) : 0;
var qry = _db.pro_order.AsQueryable();
if (selYear > 0)
{
qry = qry.Where(o => o.up_time.HasValue && o.up_time.Value.Year == selYear);
_query += "年份:" + selYear + "\n";
}
if (selMode == "mm" && selMonth > 0)
{
qry = qry.Where(o => o.up_time.HasValue && o.up_time.Value.Month == selMonth);
_query += "月份:" + selMonth + "\n";
}
if (selMode == "ss" && selSeason > 0)
{
if (selSeason == 1)
{
qry = qry.Where(o => o.up_time.HasValue)
.Where(o => o.up_time.Value.Month == 1 || o.up_time.Value.Month == 2 || o.up_time.Value.Month == 3);
}
else if (selSeason == 2)
{
qry = qry.Where(o => o.up_time.HasValue)
.Where(o => o.up_time.Value.Month == 4 || o.up_time.Value.Month == 5 || o.up_time.Value.Month == 6);
}
else if (selSeason == 3)
{
qry = qry.Where(o => o.up_time.HasValue)
.Where(o => o.up_time.Value.Month == 7 || o.up_time.Value.Month == 8 || o.up_time.Value.Month == 9);
}
else if (selSeason == 4)
{
qry = qry.Where(o => o.up_time.HasValue)
.Where(o => o.up_time.Value.Month == 10 || o.up_time.Value.Month == 11 || o.up_time.Value.Month == 12);
}
_query += "季度:" + selSeason + "\n";
}
if (chkHasAct)
{
if(selAct > 0)
{
var actSubject = _db.activities.Where(a => a.num == selAct).Select(a => a.subject).FirstOrDefault();
_query += $"活動報名: {actSubject}\n";
}
else
{
_query += $"活動報名\n";
}
if (chkNoAct)
{
_query += "非活動報名\n";
if (selAct > 0)
qry = qry.Where(o => o.activity_num.HasValue && o.activity_num.Value == selAct);
}
else
{
qry = qry.Where(o => o.activity_num.HasValue);
if (selAct > 0)
qry = qry.Where(o => o.activity_num.Value == selAct);
}
}
else
{
if (chkNoAct)
{
qry = qry.Where(o => o.activity_num == null);
_query += "非活動報名\n";
}
}
if (selActItem > 0)
qry = qry.Where(o => o.pro_order_detail.Where(f2 => f2.actItem_num.HasValue && f2.actItem_num.Value == selActItem).Count() > 0);
if (selYear > 0)
qry = qry.OrderByDescending(o => o.activity != null ? o.activity.startDate_solar : null).ThenByDescending(o => o.up_time).ThenByDescending(o => o.order_no);
else
qry = qry.OrderByDescending(o => o.order_no);
MyWeb.encrypt encrypt = new MyWeb.encrypt();
var tdesc = publicFun.enum_desc<Model.pro_order.detailKeyin1>();
var bedDt = _db.bed_order_detail.AsQueryable();//掛單明細
//紀錄匯出條件
//var list = qry.ToList();
var list = qry.GroupJoin(
_db.pro_order_detail, o => o.order_no, p => p.order_no, (o, c) =>
new
{
//訂單資料
order_no = o.order_no,
up_time = o.up_time,
keyin1 = o.keyin1,
f_num = o.follower != null ? o.follower.u_name : "", //姓名/名稱
phone = o.phone,
activity_num = o.activity_num.HasValue ? o.activity.subject : "",
address = o.address,
demo = o.demo,
c
}).SelectMany(o => o.c.DefaultIfEmpty(), (o, d) => //SelectMany 展開
new
{
//訂單資料
order_no = o.order_no,
up_time = o.up_time,
keyin1 = o.keyin1,
f_num = o.f_num, //姓名/名稱
phone = o.phone,
activity_num = o.activity_num,
address = o.address,
demo = o.demo,
//訂單明細
//使用DefaultIfEmpty 因匿名型別無法輸出NULL(無法轉換成強型別),需特別注意Null的處理
d_actItem_num = d == null ? "" : (d.actItem_num.HasValue ? d.actItem.subject : ""), //項目名稱
d_category = d == null ? "" : (d.actItem_num.HasValue ? d.actItem.category.ToString() : ""),
d_f_num = d == null ? "" : (d.f_num.HasValue ? d.follower.u_name : ""), //姓名
d_address = d == null ? "" : d.address,
d_from_id = d == null ? "" : (d.from_id.HasValue ? d.follower1.u_name : ""), //陽上/報恩者
d_f_num_tablet = d == null ? "" : d.f_num_tablet,
d_start_date = d == null ? (DateTime?)null : d.start_date, //開始日期
d_due_date = d == null ? (DateTime?)null : d.due_date, //期滿日期
d_extend_date = d == null ? (DateTime?)null : d.extend_date, //應續約日
d_price = d == null ? (float?)null : d.price, //預設金額
d_qty = d == null ? "" : (d.qty.HasValue ? d.qty.Value.ToString() : "0"), //數量
d_writeBedQty = d == null ? 0 : bedDt.Where(b => (b.bed_order.o_detail_id.Value == d.num) && b.checkIn_date.HasValue && b.bed_kind_detail_id.HasValue).Count(), //已劃數量
d_notBedQty = d == null ? 0 : bedDt.Where(b => b.bed_order.o_detail_id.Value == d.num && (!b.checkIn_date.HasValue || !b.bed_kind_detail_id.HasValue)).Count(), //未劃數量
d_pay = d == null ? "" : (d.pay.HasValue ? d.pay.Value.ToString() : "0"), //已收金額
d_pay_date = d == null ? (DateTime?)null : d.start_date, //付款期限
d_keyin1 = d == null ? (int?)null : d.keyin1,
d_demo = d == null ? "" : d.demo, //狀態備註
}).ToList();
var memoryStream = new MemoryStream();
if (list.Count > 0)
{
using (var doc = SpreadsheetDocument.Create(memoryStream, SpreadsheetDocumentType.Workbook))
{
var wb = doc.AddWorkbookPart();
wb.Workbook = new Workbook();
var sheets = wb.Workbook.AppendChild(new Sheets());
//建立第一個頁籤
var ws = wb.AddNewPart<WorksheetPart>();
ws.Worksheet = new Worksheet();
sheets.Append(new Sheet()
{
Id = wb.GetIdOfPart(ws),
SheetId = 1,
Name = "報名"
});
//設定欄寬
var cu = new Columns();
cu.Append(
new Column { Min = 1, Max = 1, Width = 15, CustomWidth = true },
new Column { Min = 2, Max = 4, Width = 10, CustomWidth = true },
new Column { Min = 5, Max = 5, Width = 15, CustomWidth = true },
new Column { Min = 6, Max = 8, Width = 25, CustomWidth = true },
new Column { Min = 9, Max = 9, Width = 15, CustomWidth = true },
new Column { Min = 10, Max = 10, Width = 10, CustomWidth = true },
new Column { Min = 11, Max = 11, Width = 25, CustomWidth = true },
new Column { Min = 12, Max = 16, Width = 10, CustomWidth = true },
new Column { Min = 17, Max = 20, Width = 10, CustomWidth = true }
);
ws.Worksheet.Append(cu);
//建立資料頁
var sd = new SheetData();
ws.Worksheet.AppendChild(sd);
//第一列資料
var tr = new Row();
tr.Append(
new Cell() { CellValue = new CellValue("單號"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("報名日期"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("單據狀態"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("姓名/名稱"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("聯絡電話"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("報名活動"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("收件地址"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("備註"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("項目名稱"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("姓名"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("代表地址"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("標題"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("陽上/報恩者"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("開始日期"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("期滿日期"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("應續約日"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("劃位狀態"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("預設金額"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("數量"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("小計"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("已收金額"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("未收金額"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("付款期限"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("報名狀態"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("狀態備註"), DataType = CellValues.String }
);
sd.AppendChild(tr);
foreach (var item in list)
{
string midNamesResult = "";
string leftNamesResult = "";
string jsonString = item.d_f_num_tablet?.ToString() ?? "";
try
{
var jo = JObject.Parse(jsonString);
// 標題
var midList = jo["mid_items"]?
.Select(i => (string)i["fam_name"])
.Where(name => !string.IsNullOrEmpty(name))
.ToList();
if (midList != null && midList.Any())
{
midNamesResult = string.Join(", ", midList);
}
// 陽上
var leftList = jo["left_items"]?
.Select(i => (string)i["fam_name"])
.Where(name => !string.IsNullOrEmpty(name))
.ToList();
if (leftList != null && leftList.Any())
{
leftNamesResult = string.Join(", ", leftList);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"JSON 解析失敗 (訂單:{item.order_no}): {ex.Message}");
}
//新增資料列
tr = new Row();
tr.Append(
new Cell() { CellValue = new CellValue(item.order_no), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.up_time?.ToString("yyyy/MM/dd") ?? ""), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(Model.pro_order.keyin1_value_to_text(item.keyin1)), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.f_num), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(encrypt.DecryptAutoKey(item.phone)), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.activity_num), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.address), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.demo), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_actItem_num), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_f_num), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_address), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(midNamesResult), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(leftNamesResult), DataType = CellValues.String },
//new Cell() { CellValue = new CellValue(item.d_from_id), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_start_date?.ToString("yyyy/MM/dd") ?? ""), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_due_date?.ToString("yyyy/MM/dd") ?? ""), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_extend_date?.ToString("yyyy/MM/dd") ?? ""), DataType = CellValues.String },
new Cell() { CellValue = new CellValue((Val(item.d_category) == (int)Model.activity.category.Order) ? (item.d_notBedQty + "/" + item.d_writeBedQty) : ""), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("$" + ValMoney(item.d_price)), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_qty), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("$" + ValMoney(ValFloat(item.d_price) * Val(item.d_qty))), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("$" + ValMoney(item.d_pay)), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("$" + ValMoney(ValFloat(item.d_price) * Val(item.d_qty) - ValFloat(item.d_pay))), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_pay_date?.ToString("yyyy/MM/dd") ?? ""), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_keyin1.HasValue ? tdesc[item.d_keyin1.Value] : ""), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_demo), DataType = CellValues.String }
);
sd.AppendChild(tr);
}
//空一列
tr = new Row();
sd.AppendChild(tr);
//匯出資訊
string _data = "匯出時間 : " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
_data += " " + admin.info.u_id;
tr = new Row();
tr.Append(
new Cell() { CellValue = new CellValue(_data), DataType = CellValues.String }
);
sd.AppendChild(tr);
_data = "匯出條件 : " + (!isStrNull(_query) ? _query : "-");
tr = new Row();
tr.Append(
new Cell() { CellValue = new CellValue(_data), DataType = CellValues.String }
);
sd.AppendChild(tr);
Model.admin_log admin_log = new Model.admin_log();
admin_log.writeLog(admin.info.u_id, (int)Model.admin_log.Systems.Order, (int)Model.admin_log.Status.Excel, admin_log.LogViewBtn(list.Select(x => x.order_no).ToList()));
}
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.AddHeader("content-disposition", "attachment; filename=報名.xlsx");
HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
HttpContext.Current.Response.BinaryWrite(memoryStream.ToArray());
HttpContext.Current.Response.End();
hid_err_msg.Value = "success";
}
else
{
hid_err_msg.Value = "nodata";
}
}
else if (isPrintMode)
{
int selYear = !string.IsNullOrEmpty(hid_print_year.Value) ? int.Parse(hid_print_year.Value) : 0;
int selMonth = !string.IsNullOrEmpty(hid_print_month.Value) ? int.Parse(hid_print_month.Value) : 0;
int selSeason = !string.IsNullOrEmpty(hid_print_season.Value) ? int.Parse(hid_print_season.Value) : 0;
string selMode = !string.IsNullOrEmpty(hid_print_mode.Value) ? hid_print_mode.Value : "";
bool chkHasAct = !string.IsNullOrEmpty(hid_chk_hasact.Value) && Convert.ToBoolean(hid_chk_hasact.Value);
bool chkNoAct = !string.IsNullOrEmpty(hid_chk_noact.Value) && Convert.ToBoolean(hid_chk_noact.Value);
int selAct = !string.IsNullOrEmpty(hid_select_act.Value) ? int.Parse(hid_select_act.Value) : -1;
int selActItem = !string.IsNullOrEmpty(hid_select_actitem.Value) ? int.Parse(hid_select_actitem.Value) : -1;
string urlParams = !string.IsNullOrEmpty(hid_qry.Value) ? hid_qry.Value : "";
var qry = _db.pro_order.AsQueryable();
if (selYear > 0)
qry = qry.Where(o => o.up_time.HasValue && o.up_time.Value.Year == selYear);
if (selMode == "mm" && selMonth > 0)
qry = qry.Where(o => o.up_time.HasValue && o.up_time.Value.Month == selMonth);
else if (selMode == "ss" && selSeason > 0)
{
if (selSeason == 1)
qry = qry.Where(o => o.up_time.HasValue)
.Where(o => o.up_time.Value.Month == 1 || o.up_time.Value.Month == 2 || o.up_time.Value.Month == 3);
else if (selSeason == 2)
qry = qry.Where(o => o.up_time.HasValue)
.Where(o => o.up_time.Value.Month == 4 || o.up_time.Value.Month == 5 || o.up_time.Value.Month == 6);
else if (selSeason == 3)
qry = qry.Where(o => o.up_time.HasValue)
.Where(o => o.up_time.Value.Month == 7 || o.up_time.Value.Month == 8 || o.up_time.Value.Month == 9);
else if (selSeason == 4)
qry = qry.Where(o => o.up_time.HasValue)
.Where(o => o.up_time.Value.Month == 10 || o.up_time.Value.Month == 11 || o.up_time.Value.Month == 12);
}
if (chkHasAct)
{
if (chkNoAct)
{
if (selAct >= 0)
qry = qry.Where(o => o.activity_num.HasValue && o.activity_num.Value == selAct);
}
else
{
qry = qry.Where(o => o.activity_num.HasValue);
if (selAct >= 0)
qry = qry.Where(o => o.activity_num.Value == selAct);
}
}
else
{
if (chkNoAct)
qry = qry.Where(o => o.activity_num == null);
}
if (selActItem >= 0)
{
qry = qry.Where(o => o.pro_order_detail.Where(f2 => f2.actItem_num.HasValue && f2.actItem_num.Value == selActItem).Count() > 0);
}
var count = qry.Count();
if (count > 0)
{
hid_err_msg.Value = "success";
string script = $@"var otherWin = window.open('print.aspx{urlParams}', '列印報名資料', 'noopener,noreferrer');";
ScriptManager.RegisterStartupScript(this, GetType(), "ExecutePrint", script, true);
}
else
{
hid_err_msg.Value = "nodata";
}
//var qry = _db.followers.AsQueryable();
//if (selYear > 0)
//{
// urlParams += "&year=" + selYear;
//}
//if (selMode == "mm" && selMonth > 0)
//{
// urlParams += "&month=" + selMonth;
//}
//else if (selMode == "ss" && selSeason > 0)
//{
// urlParams += "&season=" + selSeason;
//}
//if (list.Count > 0)
//{
// hid_err_msg.Value = "success";
// hid_print_year.Value = selYear.ToString();
// hid_print_month.Value = selMonth.ToString();
// hid_print_season.Value = selSeason.ToString();
// hid_print_mode.Value = selMode;
// string script = $@"window.open('print.aspx?{urlParams}&mode={selMode}', '列印信眾資料');";
// ScriptManager.RegisterStartupScript(this, GetType(), "ExecutePrint", script, true);
//}
//else
//{
// hid_err_msg.Value = "nodata";
// string script = $@"
// var win = window.open('', '列印信眾資料');
// if (win) win.close()";
// ScriptManager.RegisterStartupScript(this, GetType(), "CancelPrint", script, true);
//}
}
}
protected void excel_Click(object sender, EventArgs e)
{
@@ -111,6 +570,7 @@ public partial class admin_order_index : MyWeb.config
new Cell() { CellValue = new CellValue("項目名稱"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("姓名"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("代表地址"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("標題"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("陽上/報恩者"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("開始日期"), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("期滿日期"), DataType = CellValues.String },
@@ -132,31 +592,56 @@ public partial class admin_order_index : MyWeb.config
// 改為整數陣列,避免後續查詢中使用 .ToString()
var aIDt = _db.actItems.Where(f => f.subject.Contains(s_actItemTxt.Value.Trim())).Select(f => f.num).ToArray();//品項
var qry = _db.pro_order.AsQueryable();
string _query = ""; // 紀錄匯出條件
if (!isStrNull(s_order_no.Value))
{
_query += "單號:" + s_order_no.Value + "\n";
qry = qry.Where(o => o.order_no.Contains(s_order_no.Value.Trim()));
}
if (!isStrNull(s_u_name.Value))
{
_query += "姓名/名稱:" + s_u_name.Value + "\n";
qry = qry.Where(o => o.f_num.HasValue && o.follower.u_name.Contains(s_u_name.Value.Trim()));
}
if (!isStrNull(s_introducerTxt.Value))
{
_query += "介紹人:" + s_introducerTxt.Value + "\n";
qry = qry.Where(o => o.f_num.HasValue && o.follower1.u_name.Contains(s_introducerTxt.Value.Trim()));
}
if (!isStrNull(s_subject.Value))
{
_query += "報名活動:" + s_subject.Value + "\n";
qry = qry.Where(o => o.activity_num.HasValue && o.activity.subject.Contains(s_subject.Value.Trim()));
}
if (!isStrNull(s_actItemTxt.Value))
{
// ❌ 錯誤寫法: qry = qry.Where(o => o.pro_order_detail.Where(f2 => f2.order_no == o.order_no && aIDt.ToArray().Contains(f2.actItem_num.ToString())).Count() > 0);
// ✅ 實際比較:僅在 actItem_num 有值時才與整數陣列比對
_query += "品項:" + s_actItemTxt.Value + "\n";
qry = qry.Where(o => o.pro_order_detail.Any(f2 =>
f2.order_no == o.order_no &&
f2.actItem_num.HasValue &&
aIDt.Contains(f2.actItem_num.Value)));
}
if (!isStrNull(s_keyin1.SelectedValue))
{
_query += $"單據狀態:{Model.pro_order.keyin1_value_to_text(s_keyin1.SelectedValue)}\n";
qry = qry.Where(o => o.keyin1 == s_keyin1.SelectedValue);
}
if (!isStrNull(s_up_time1.Value) && isDate(s_up_time1.Value))
qry = qry.Where(o => o.up_time >= ValDate(s_up_time1.Value));
{
_query += "報名日期(起):" + s_up_time1.Value.Trim() + "\n";
var tmp_s_up_time1 = ValDate(s_up_time1.Value);
qry = qry.Where(o => o.up_time >= tmp_s_up_time1);
}
if (!isStrNull(s_up_time2.Value) && isDate(s_up_time2.Value))
qry = qry.Where(o => o.up_time < Convert.ToDateTime(s_up_time2.Value).AddDays(1));
{
_query += "報名日期(訖):" + s_up_time2.Value.Trim() + "\n";
var tmp_s_up_time2 = Convert.ToDateTime(s_up_time2.Value).AddDays(1);
qry = qry.Where(o => o.up_time < tmp_s_up_time2);
}
qry = qry.OrderByDescending(o => o.reg_time);
@@ -202,16 +687,17 @@ public partial class admin_order_index : MyWeb.config
d_f_num = d == null ? "" : (d.f_num.HasValue ? d.follower.u_name : ""), //姓名
d_address = d == null ? "" : d.address,
d_from_id = d == null ? "" : (d.from_id.HasValue ? d.follower1.u_name : ""), //陽上/報恩者
d_start_date = d == null ? "" : (d.start_date.HasValue ? d.start_date.Value.ToString("yyyy/MM/dd") : ""), //開始日期
d_due_date = d == null ? "" : (d.due_date.HasValue ? d.due_date.Value.ToString("yyyy/MM/dd") : ""), //期滿日期
d_extend_date = d == null ? "" : (d.extend_date.HasValue ? d.extend_date.Value.ToString("yyyy/MM/dd") : ""), //應續約日
d_price = d == null ? "" : (d.price.HasValue ? d.price.Value.ToString() : "0"), //預設金額
d_f_num_tablet = d == null ? "" : d.f_num_tablet,
d_start_date = d == null ? (DateTime?)null : d.start_date, //開始日期
d_due_date = d == null ? (DateTime?)null : d.due_date, //期滿日期
d_extend_date = d == null ? (DateTime?)null : d.extend_date, //應續約日
d_price = d == null ? (float?)null : d.price, //預設金額
d_qty = d == null ? "" : (d.qty.HasValue ? d.qty.Value.ToString() : "0"), //數量
d_writeBedQty = d == null ? 0 : bedDt.Where(b => (b.bed_order.o_detail_id.Value == d.num) && b.checkIn_date.HasValue && b.bed_kind_detail_id.HasValue).Count(), //已劃數量
d_notBedQty = d == null ? 0 : bedDt.Where(b => b.bed_order.o_detail_id.Value == d.num && (!b.checkIn_date.HasValue || !b.bed_kind_detail_id.HasValue)).Count(), //未劃數量
d_pay = d == null ? "" : (d.pay.HasValue ? d.pay.Value.ToString() : "0"), //已收金額
d_pay_date = d == null ? "" : (d.pay_date.HasValue ? d.pay_date.Value.ToString("yyyy/MM/dd") : ""), //付款期限
d_keyin1 = d == null ? "" : (d.keyin1.HasValue&& d.keyin1.Value>0 ? tdesc[d.keyin1 ?? 1] : ""), //報名狀態
d_pay_date = d == null ? (DateTime?)null : d.start_date, //付款期限
d_keyin1 = d == null ? (int?)null : d.keyin1,
d_demo = d == null ? "" : d.demo, //狀態備註
}).ToList();
@@ -259,11 +745,43 @@ public partial class admin_order_index : MyWeb.config
{
foreach (var item in list)
{
string midNamesResult = "";
string leftNamesResult = "";
string jsonString = item.d_f_num_tablet?.ToString() ?? "";
try
{
var jo = JObject.Parse(jsonString);
// 標題
var midList = jo["mid_items"]?
.Select(i => (string)i["fam_name"])
.Where(name => !string.IsNullOrEmpty(name))
.ToList();
if (midList != null && midList.Any())
{
midNamesResult = string.Join(", ", midList);
}
// 陽上
var leftList = jo["left_items"]?
.Select(i => (string)i["fam_name"])
.Where(name => !string.IsNullOrEmpty(name))
.ToList();
if (leftList != null && leftList.Any())
{
leftNamesResult = string.Join(", ", leftList);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"JSON 解析失敗 (訂單:{item.order_no}): {ex.Message}");
}
//新增資料列
tr = new Row();
tr.Append(
new Cell() { CellValue = new CellValue(item.order_no), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.up_time.Value.ToString("yyyy/MM/dd")), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.up_time?.ToString("yyyy/MM/dd") ?? ""), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(Model.pro_order.keyin1_value_to_text(item.keyin1)), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.f_num), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(encrypt.DecryptAutoKey(item.phone)), DataType = CellValues.String },
@@ -274,23 +792,44 @@ public partial class admin_order_index : MyWeb.config
new Cell() { CellValue = new CellValue(item.d_actItem_num), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_f_num), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_address), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_from_id), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_start_date), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_due_date), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_extend_date), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(midNamesResult), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(leftNamesResult), DataType = CellValues.String },
//new Cell() { CellValue = new CellValue(item.d_from_id), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_start_date?.ToString("yyyy/MM/dd") ?? ""), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_due_date?.ToString("yyyy/MM/dd") ?? ""), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_extend_date?.ToString("yyyy/MM/dd") ?? ""), DataType = CellValues.String },
new Cell() { CellValue = new CellValue((Val(item.d_category) == (int)Model.activity.category.Order) ? (item.d_notBedQty + "/" + item.d_writeBedQty) : ""), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("$" + ValMoney(item.d_price)), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_qty), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("$" + ValMoney(ValFloat(item.d_price) * Val(item.d_qty))), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("$" + ValMoney(item.d_pay)), DataType = CellValues.String },
new Cell() { CellValue = new CellValue("$" + ValMoney(ValFloat(item.d_price) * Val(item.d_qty) - ValFloat(item.d_pay))), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_pay_date), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_keyin1), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_pay_date?.ToString("yyyy/MM/dd") ?? ""), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_keyin1.HasValue ? tdesc[item.d_keyin1.Value] : ""), DataType = CellValues.String },
new Cell() { CellValue = new CellValue(item.d_demo), DataType = CellValues.String }
);
sd.AppendChild(tr);
}
//空一列
tr = new Row();
sd.AppendChild(tr);
//匯出資訊
string _data = "匯出時間 : " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
_data += " " + admin.info.u_id;
tr = new Row();
tr.Append(
new Cell() { CellValue = new CellValue(_data), DataType = CellValues.String }
);
sd.AppendChild(tr);
_data = "匯出條件 : " + (!isStrNull(_query) ? _query : "-");
tr = new Row();
tr.Append(
new Cell() { CellValue = new CellValue(_data), DataType = CellValues.String }
);
sd.AppendChild(tr);
Model.admin_log admin_log = new Model.admin_log();
admin_log.writeLog(admin.info.u_id, (int)Model.admin_log.Systems.Order, (int)Model.admin_log.Status.Excel, admin_log.LogViewBtn(list.Select(x => x.order_no).ToList()));
+2 -2
View File
@@ -41,7 +41,7 @@
{ text: '活動名稱​', value: 'subject', },
{ text: '報到日期​', value: 'reg_time_date', },
{ text: '報到時間​', value: 'reg_time_time' },
{ text: '姓名(人數)', value: 'qty' },
{ text: '姓名', value: 'qty' },
{ text: '狀態', value: 'statusTxt' },
{ text: '', value: 'slot_btn', sortable: false, align: 'end' }
@@ -199,7 +199,7 @@
{{item.reg_time |timeString('HH:mm:ss') }}
</template>
<template #item.qty="{ item }" >
{{item.u_name }}({{item.qty }})
{{item.u_name }}
</template>
+861
View File
@@ -0,0 +1,861 @@
<%@ Page Title="" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="index3.aspx.cs" Inherits="admin_order_index3" %>
<%@ Register Src="~/admin/_uc/alert.ascx" TagPrefix="uc1" TagName="alert" %>
<asp:Content ID="Content1" ContentPlaceHolderID="page_header" runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="page_nav" runat="Server">
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
<uc1:alert runat="server" ID="L_msg" Text="" />
<keep-alive>
<component
:is="currentView" :form-data="$data">
</component>
</keep-alive>
<div id="print_data">
</div>
</asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" runat="Server">
</asp:Content>
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" runat="Server">
<script>
Vue.filter('timeString', function (value, myFormat) {
return value == null || value == "" ? "" : moment(value).format(myFormat || 'YYYY-MM-DD, HH:mm:ss');
});
Vue.component('step-one', {
template: `
<div class="container-fluid">
<v-data-table
v-model="data_table.selected"
:items="data_table.list"
:search-props="search"
item-key="order_no"
:options.sync="options"
:headers="data_table.header"
:footer-props="data_table.footer"
:server-items-length="data_table.count"
:loading="data_table.loading"
:single-select="data_table.singleSelect"
show-select
hide-default-footer
:page.sync="data_table.page"
:items-per-page.sync="data_table.pageSize"
class="elevation-1">
<template #item.up_time="{ item }" >
{{ item.up_time|timeString('YYYY/MM/DD') }}
</template>
<template #item.u_name="{ item }" >
<a v-if="item.f_num != null && item.activity_num != null" @click="checkInMsg(item)" class="btn btn-outline-secondary btn-sm"><i class="mdi mdi-account-check"></i>報到</a>
{{ item.u_name }}
</template>
<template #item.slot_btn="{ item }">
<a @click="$root.currentView='step-two';$root.selected_act=item.num" class="btn btn-outline-secondary btn-sm">明細</a>
<a @click="deleteItem(item)" class="btn btn-outline-secondary btn-sm"><i class="mdi mdi-trash-can"></i>刪除</a>
</template>
</v-data-table>
<v-container>
<v-row class="align-baseline" wrap>
<v-col cols="12" md="9">
<v-pagination
v-model="data_table.page"
:length="pageCount">
</v-pagination>
</v-col>
<v-col class="text-truncate text-right" cols="12" md="2">
共 {{ data_table.count }} 筆, 頁數:
</v-col>
<v-col cols="6" md="1">
<v-text-field
v-model="data_table.page"
type="number"
hide-details
dense
min="1"
:max="pageCount"
@input="data_table.page = parseInt($event, 10)"
></v-text-field>
</v-col>
</v-row>
</v-container>
</div>`,
props: ['formData'],
data() {
return {
this_act: '<%= Request["act_id"]%>',
options: { multiSort: false },
search_options: { multiSort: false },
data_table: {
loading: true,
list: [],
selected: [],
singleSelect: false,
count: 0,
page: 1,
pageSize: 10,
header: [
{ text: '活動分類', value: 'kindsTxt' },
{ text: '活動名稱', value: 'subject' },
{ text: '開始日期', value: 'startDate_solar' },
{ text: '結束日期', value: 'endDate_solar', align: 'start' },
{ text: '報名人數', value: 'orderCounts' },
{ text: '', value: 'slot_btn', sortable: false, align: 'end' }
],
footer: {
showFirstLastPage: true,
itemsPerPageOptions: [5, 10, 20, 30],
},
},
//列印管理報表
print_conditions: 'yy',
print_search: {
year: '',
month: '',
season: '',
chk_hasact: false,
chk_noact: false,
select_act: '',
select_actitem: '',
},
select_act_list: [],
select_items: {
month: [{
text: "請選擇",
val: 0
},],
season: [{
text: "請選擇",
val: 0
},],
},
print_dialog: {
show: false,
},
search_dialog: {
controls: {
search1: {
id: 'search1',
title: '國籍',
text_prop: 'name_zh',
value_prop: 'id',
keys: [
{ id: 'keyword', title: '關鍵字' },
],
api_url: HTTP_HOST + 'api/country/GetList',
columns: [
{ id: 'id', title: '代碼' },
{ id: 'name_en', title: '英文短名稱' },
{ id: 'name_zh', title: '中文名稱' },
],
selected: {},
select(item, t) {
//console.log("select search1", t);
t.search.country = item.id;
t.search.country2 = '';
}
},
search2: {
id: 'search2',
title: '報名活動',
text_prop: 'subject',
value_prop: 'num',
keys: [
{ id: 'subject', title: '活動名稱', value: '' },
{ id: 'kindTxt', title: '活動分類' },
],
api_url: HTTP_HOST + 'api/activity/GetList',
columns: [
{ id: 'subject', title: '活動名稱' },
{ id: 'kindTxt', title: '活動分類' },
],
selected: {},
select(item, t) {
t.print_search.select_act = item.num;
}
},
search3: {
id: 'search3',
title: '活動品項',
text_prop: 'subject',
value_prop: 'num',
keys: [
{ id: 'subject', title: '項目名稱', value: '' },
{ id: 'kindTxt', title: '項目分類' },
{ id: 'num', visible: false },
],
api_url: HTTP_HOST + 'api/activity/GetOrderList',
columns: [
{ id: 'subject', title: '項目名稱' },
{ id: 'kindTxt', title: '項目分類' },
],
selected: {},
select(item, t) {
t.print_search.select_actitem = item.num;
}
}
}, show: false,
current: {},
list: [],
count: 0,
page: 1,
loading: false,
footer: {
showFirstLastPage: true,
disableItemsPerPage: true,
itemsPerPageAllText: '',
itemsPerPageText: '',
},
},
search: {
keyin1: '',
order_no: '',
subject: '',
u_name: '',
up_time1: '',
up_time2: '',
actItemTxt: '',
introducerTxt: '',
activity_num: '',
country: '',
country2: '',
hasPrice: '',
}
//報到
, check_dialog: {
show: false,
},
check_data: {
f_num: 0,
u_name: '',
activity_num: 0,
activity_name: '',
qty: 1,
status: {
text: '',
val: 1
},
},
keyin1_items: [//狀態
//{
//text: "請選擇",
//val: 0
//},
],
};
},
mounted() {
this.detalKeyinArray();
this.search_dialog.current = this.search_dialog.controls.search1 ///default
if (this.this_act != '')
this.search.activity_num = this.this_act;
//this.initPrintSearch();
//this.initActivity();
const navEntries = performance.getEntriesByType("navigation");
const isReload = navEntries.length > 0 && navEntries[0].type === "reload";
if (isReload) {
sessionStorage.removeItem("orderpage");
}
else {
const savedPage = parseInt(sessionStorage.getItem('orderpage'));
if (savedPage) {
this.options.page = savedPage;
}
}
},
watch: {
options: {
handler() {
this.getDefault()
},
deep: true,
},
search_options: {
handler() {
this.search_get()
},
deep: true,
},
},
methods: {
search_show(curr) {
//console.log("btn_click:", curr, curr.api_url);
this.search_dialog.current = curr;
this.search_clear()
//this.search_get()//清除完自動會重抓, 故取消
this.search_dialog.show = true;
},
search_clear() {
if (!this.search_dialog.current.keys) return;
this.search_dialog.current.keys.forEach((t, i) => { t.value = '' })
this.search_get()
},
search_get() {
if (!this.search_dialog.current.keys) return;
let api_url = this.search_dialog.current.api_url;
let keys = this.search_dialog.current.keys;
//const { page, itemsPerPage } = this.options
//const { sortBy, sortDesc, page, itemsPerPage } = this.options
this.search_dialog.page = this.search_options.page ?? 1
let params = { page: this.search_dialog.page, pageSize: 10 };//url params
var search = {};//post body
keys.forEach((t, i) => {
search[t.id] = t.value;
});
//necessary parameter===
if (this.search_dialog.current.id == 'search2') {
params = { sortBy: 'startDate_solar', sortDesc: true, page: this.search_dialog.page, pageSize: 10 };//url params
}
console.log("search_get", api_url, search, params, this.search_options);
this.search_dialog.loading = true
axios.post(api_url, search, { params: params })
.then(response => {
this.search_dialog.list = response.data.list
this.search_dialog.count = response.data.count
this.search_dialog.loading = false
})
.catch(error => {
console.log(error)
this.search_dialog.list = []
this.search_dialog.count = 0
this.search_dialog.loading = false
this.snackbar.text = "錯誤:" + error
this.snackbar.show = true
})
},
search_headers() {
if (!this.search_dialog.current.columns) return;
r = [];
this.search_dialog.current.columns.forEach((t, i) => {
r.push({
text: t.title,
align: 'start',
sortable: false,
value: t.id,
})
})
return r
},
search_select(row) {
let curr = this.search_dialog.current;
let target = $(`[data-search-control=${curr.id}]`);
curr.selected = row;
target.children("input.search-text").val(curr.selected[curr.text_prop])//text
target.children("input:hidden").val(curr.selected[curr.value_prop])//value
if (curr.select instanceof Function) {
curr.select(row, this);
}
this.search_dialog.show = false;
//console.log(row, row["u_name"], row["f_number"], curr.id, target);
},
getDetail(clearpage = false) {
console.log("test");
const { sortBy, sortDesc, page, itemsPerPage } = this.options
const params = {
sortBy: sortBy[0], sortDesc: sortDesc[0],
page: clearpage ? '1' : page, pageSize: itemsPerPage
};
this.detail_table.loading = true
sessionStorage.setItem('orderpage', clearpage ? '1' : page);
axios
//.post(HTTP_HOST + 'api/order/GetList', this.search, { params: params })
.post(HTTP_HOST + 'api/order/GetList', this.search, { params: params })
.then(response => {
this.detail_table.list = response.data.list
this.detail_table.count = response.data.count;
this.detail_table.loading = false
})
.catch(error => console.log(error))
},
getDefault(clearpage = false) {
const { sortBy, sortDesc, page, itemsPerPage } = this.options
const params = {
sortBy: sortBy[0], sortDesc: sortDesc[0],
page: clearpage ? '1' : page, pageSize: itemsPerPage
};
this.data_table.loading = true
sessionStorage.setItem('orderpage', clearpage ? '1' : page);
axios
//.post(HTTP_HOST + 'api/order/GetList', this.search, { params: params })
.post(HTTP_HOST + 'api/activity/GetList', this.search, { params: params })
.then(response => {
this.data_table.list = response.data.list
this.data_table.count = response.data.count;
this.data_table.loading = false
})
.catch(error => console.log(error))
},
detalKeyinArray() {
var getArray = <%=Newtonsoft.Json.JsonConvert.SerializeObject(_keyin1Item, Newtonsoft.Json.Formatting.Indented) %>;
var keys = Object.keys(getArray);
for (let i = 0; i < keys.length; i++) {
//console.log(`${keys[i]}:${getArray[keys[i]]}`); //value : text
var _tmp = {
text: getArray[keys[i]],
val: parseInt(keys[i]),
}
this.keyin1_items.push(_tmp);
}
},
editItem(item) {
console.log("edit", item);
},
deleteItem(item) {
if (confirm('是否確定刪除此筆資料?')) {
const index = this.data_table.list.indexOf(item)
if (index != -1) {
axios
.delete(HTTP_HOST + 'api/order/' + item.order_no)
.then(response => {
console.log("del", item);
this.data_table.list.splice(index, 1);
this.data_table.count = this.data_table.list.length
})
.catch(error => console.log(error))
}
}
},
deleteAll() {
if (confirm('是否確定刪除已勾選的資料?')) {
axios
.delete(HTTP_HOST + 'api/order/DeleteAll/' + this.data_table.selected.map(x => x.order_no))
.then(response => {
//console.log("delAll");
//for (var i = 0; i < this.data_table.selected.length; i++) {
// const index = this.data_table.list.indexOf(this.data_table.selected[i]);
// this.data_table.list.splice(index, 1);
//}
//this.data_table.selected = [];
//this.data_table.count = this.data_table.list.length
location.reload();
})
.catch(error => console.log(error))
}
},
btn_search() {
this.this_act = '';
this.search.activity_num = '';
this.getDefault(true)
},
btn_all() {
this.this_act = '';
this.search.activity_num = '';
clearObjProps(this.search);
this.btn_search()
},
checkInMsg(item) {
this.check_data.f_num = item.f_num;
this.check_data.u_name = item.u_name;
this.check_data.activity_num = item.activity_num;
this.check_data.activity_name = item.subject;
this.check_dialog.show = true;
},
checkIn() {
if (this.check_data.qty > 0 && this.check_data.status.val > 0) {
var chechdata =
{
f_num: this.check_data.f_num,
activity_num: this.check_data.activity_num,
status: this.check_data.status.val,
qty: this.check_data.qty,
}
axios
.post(HTTP_HOST + 'api/activity/OrderCheckIn', chechdata)
.then(response => {
//清空
this.check_data.f_num = 0;
this.check_data.u_name = '';
this.check_data.activity_num = 0;
this.check_data.activity_name = '';
this.check_data.qty = 1;
this.check_data.status.text = '';
this.check_data.status.val = 1;
this.check_dialog.show = false;
msgtop('簽到成功')
})
.catch(
error => {
console.log(error)
msgtop('簽到失敗', 'error')
}
)
} else {
msgbox('報到資訊請填寫完整');
}
}, goPrint() {
let _qry = "";
Object.keys(this.search).forEach(key => {
//console.log(`${key}: ${this.search[key]}`);
if (this.search[key] != undefined && this.search[key] != null && this.search[key] != '') {
_qry += (_qry != '' ? '&' : '?') + (key + '=' + this.search[key]);
}
});
window.open("print.aspx" + _qry, '_blank');
},
countryChange() {
this.search.country = '';
$('#country_txt').val('')
},
//列印管理報表
print_close() {
this.print_dialog.show = false;
}
,
initPrintSearch() {
//下拉選單
for (let i = 1; i <= 12; i++) {
var _tmp = {
text: i,
val: i,
}
this.select_items.month.push(_tmp);
}
for (let i = 1; i <= 4; i++) {
var _tmp = {
text: i,
val: i,
}
this.select_items.season.push(_tmp);
}
//預設值
const Today = new Date();//現在日期時間
const first_date = new Date(Today.getFullYear(), Today.getMonth(), 1); //本月第一天
const last_month_date = new Date(first_date - 1); //上個月最後一天
this.print_search.year = last_month_date.getFullYear();
this.print_search.month = last_month_date.getMonth() + 1 //預設上個月的年份
let _season = 1;
const _month = first_date.getMonth() + 1; //本月
if (_month >= 1 && _month <= 3) {
_season = 4;
} else if (_month >= 4 && _month <= 6) {
_season = 1;
} else if (_month >= 7 && _month <= 9) {
_season = 2;
} else if (_month >= 10 && _month <= 12) {
_season = 3;
}
this.print_search.season = _season; //預設上一季
},
goPrint2() {
if (this.print_search.year != '') {
if (this.print_search.chk_noact || this.print_search.chk_hasact) {
let _qry = "";
Object.keys(this.print_search).forEach(key => {
if (this.print_search[key] != undefined && this.print_search[key] != null && this.print_search[key] != '') {
if (key == 'month') {
if (this.print_conditions == 'mm') {
_qry += "&month=" + this.print_search.month;
}
} else if (key == 'season') {
if (this.print_conditions == 'ss') {
_qry += "&season=" + this.print_search.season;
}
}
else {
_qry += (_qry != '' ? '&' : '?') + (key + '=' + this.print_search[key]);
}
}
});
this.print_dialog.show = false;
window.open("print.aspx" + _qry, '_blank');
} else {
msgbox('活動/非活動至少勾選一項');
}
} else {
msgbox('請輸入年份');
}
}, chk_hasact_change() {
if (!this.print_search.chk_hasact) {
//$('#activity_num_txt').val('')
//this.print_search.select_act = '';
this.clear_select_act();
$('#activity_num_txt').attr("placeholder", "可選擇單一活動(需先勾選活動報名)");
} else {
$('#activity_num_txt').attr("placeholder", "可選擇單一活動");
}
},
clear_select_act() {
$('#activity_num_txt').val('')
this.print_search.select_act = '';
}, clear_select_actitem() {
$('#actItem_num_txt').val('')
this.print_search.select_actitem = '';
},
initActivity() {
axios.get(HTTP_HOST + 'api/activity')
.then(response => {
this.select_act_list = response.data
})
.catch(error => {
console.log(error)
})
}
},
computed: {
pageCount() {
return Math.ceil(this.data_table.count / this.data_table.pageSize)
},
}
});
Vue.component('step-two', {
template: `
<div class="container-fluid">
<v-data-table
v-model="detail_table.selected"
:items="detail_table.list"
:search-props="search"
item-key="order_no"
:options.sync="options"
:headers="detail_table.header"
:footer-props="detail_table.footer"
:server-items-length="detail_table.count"
:loading="detail_table.loading"
:single-select="detail_table.singleSelect"
show-select
hide-default-footer
:page.sync="detail_table.page"
:items-per-page.sync="detail_table.pageSize"
class="elevation-1">
<template #item.slot_btn="{ item }">
<a :href="'reg.aspx?order_no='+item.order_no" class="btn btn-outline-secondary btn-sm"><i class="mdi mdi-pencil-box-outline"></i>修改</a>
<a @click="$root.currentView='step-three';$root.selected_order=item.order_no" class="btn btn-outline-secondary btn-sm">明細</a>
<a @click="deleteItem(item)" class="btn btn-outline-secondary btn-sm"><i class="mdi mdi-trash-can"></i>刪除</a>
</template>
</v-data-table>
<v-container>
<v-row class="align-baseline" wrap>
<v-col cols="12" md="9">
<v-pagination
v-model="detail_table.page"
:length="pageCount">
</v-pagination>
</v-col>
<v-col class="text-truncate text-right" cols="12" md="2">
共 {{ detail_table.count }} 筆, 頁數:
</v-col>
<v-col cols="6" md="1">
<v-text-field
v-model="detail_table.page"
type="number"
hide-details
dense
min="1"
:max="pageCount"
@input="detail_table.page = parseInt($event, 10)"
></v-text-field>
</v-col>
</v-row>
</v-container>
</div>`,
props: ['twoData'],
activated() {
console.log("yes ,go go");
this.getDetail();
},
data() {
return {
options: { multiSort: false },
search_options: { multiSort: false },
detail_table: {
loading: true,
list: [],
selected: [],
singleSelect: false,
count: 0,
page: 1,
pageSize: 10,
header: [
{ text: '單號', value: 'order_no' },
{ text: '姓名', value: 'u_name' },
{ text: '報名日期', value: 'up_time' },
{ text: '單據狀態', value: 'keyin1_txt', align: 'start' },
{ text: '', value: 'slot_btn', sortable: false, align: 'end' }
],
footer: {
showFirstLastPage: true,
itemsPerPageOptions: [5, 10, 20, 30],
},
},
search: {
keyin1: '',
order_no: '',
subject: '',
u_name: '',
up_time1: '',
up_time2: '',
actItemTxt: '',
introducerTxt: '',
activity_num: '',
country: '',
country2: '',
hasPrice: '',
}
};
},
watch: {
options: {
handler() {
this.getDetail()
},
deep: true,
},
},
methods: {
getDetail() {
const { sortBy, sortDesc, page, itemsPerPage } = this.options
const params = {
//sortBy: sortBy == undefined ? "order_no" : sortBy[0],
//sortDesc: sortDesc == undefined ? "" : sortDesc[0],
//page: clearpage ? '1' : page, pageSize: itemsPerPage,
page:'1',pageSize:10,
};
this.search = { activity_num: this.$root.selected_act }
this.detail_table.loading = true
sessionStorage.setItem('orderpage','1');// clearpage ? '1' : page
axios
.post(HTTP_HOST + 'api/order/GetList', this.search, { params: params })
.then(response => {
this.detail_table.list = response.data.list
this.detail_table.count = response.data.count;
this.detail_table.loading = false
})
.catch(error => console.log(error))
},
},
computed: {
pageCount() {
return Math.ceil(this.detail_table.count / this.detail_table.pageSize)
},
}
});
Vue.component('step-three', {
template: `<div>放報名資料</div>`,
props:['signData']
});
let VueApp = new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
currentView: 'step-one',
selected_act: '',
selected_order:'',
};
},activated() {
console.log("yes ,go go");
this.getDetail();
},
data() {
return {
options: { multiSort: false },
search_options: { multiSort: false },
sign_table: {
loading: true,
list: [],
selected: [],
singleSelect: false,
count: 0,
page: 1,
pageSize: 10,
header: [
{ text: '單號', value: 'order_no' },
{ text: '姓名', value: 'u_name' },
{ text: '報名日期', value: 'up_time' },
{ text: '單據狀態', value: 'keyin1_txt', align: 'start' },
{ text: '', value: 'slot_btn', sortable: false, align: 'end' }
],
footer: {
showFirstLastPage: true,
itemsPerPageOptions: [5, 10, 20, 30],
},
},
search: {
keyin1: '',
order_no: '',
subject: '',
u_name: '',
up_time1: '',
up_time2: '',
actItemTxt: '',
introducerTxt: '',
activity_num: '',
country: '',
country2: '',
hasPrice: '',
}
};
},
watch: {
options: {
handler() {
this.getDetail()
},
deep: true,
},
},
methods: {
getDetail() {
const { sortBy, sortDesc, page, itemsPerPage } = this.options
const params = {
//sortBy: sortBy == undefined ? "order_no" : sortBy[0],
//sortDesc: sortDesc == undefined ? "" : sortDesc[0],
//page: clearpage ? '1' : page, pageSize: itemsPerPage,
page: '1', pageSize: 10,
};
this.search = { activity_num: this.$root.selected_act }
this.detail_table.loading = true
sessionStorage.setItem('orderpage', '1');// clearpage ? '1' : page
axios
.post(HTTP_HOST + 'api/order/GetList', this.search, { params: params })
.then(response => {
this.detail_table.list = response.data.list
this.detail_table.count = response.data.count;
this.detail_table.loading = false
})
.catch(error => console.log(error))
},
},
computed: {
pageCount() {
return Math.ceil(this.detail_table.count / this.detail_table.pageSize)
},
}
});
</script>
</asp:Content>
+284
View File
@@ -0,0 +1,284 @@
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using static Model.activity_check;
public partial class admin_order_index3 : MyWeb.config
{
private Model.ezEntities _db = new Model.ezEntities();
public Dictionary<int, string> _keyin1Item = null;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Model.pro_order order = new Model.pro_order();
ArrayList options = order.keyin1_list();
foreach (Model.pro_order.keyin optionKey in options)
{
ListItem item = new ListItem(optionKey.Text, optionKey.Value);
item.Attributes.Add("style", "color:" + optionKey.Color);
//s_keyin1.Items.Add(item);
}
_keyin1Item = publicFun.enum_desc<Model.activity_check.keyin1>(); //狀態
BuildKind();
}
}
public void detailButton_click(object sender, EventArgs e)
{
}
public void BuildKind()
{
//國籍
//s_country.Items.Clear();
//s_country.Items.Add(new ListItem("請選擇", ""));
var qry = _db.countries.OrderBy(x => x.range).ThenBy(x => x.name_en).ToList();
if (qry.Count > 0)
{
//foreach (var x in qry)
//s_country.Items.Add(new ListItem(x.name_zh, x.ID));
}
}
protected void excel_Click(object sender, EventArgs e)
{
//var memoryStream = new MemoryStream();
//using (var doc = SpreadsheetDocument.Create(memoryStream, SpreadsheetDocumentType.Workbook))
//{
// var wb = doc.AddWorkbookPart();
// wb.Workbook = new Workbook();
// var sheets = wb.Workbook.AppendChild(new Sheets());
// //建立第一個頁籤
// var ws = wb.AddNewPart<WorksheetPart>();
// ws.Worksheet = new Worksheet();
// sheets.Append(new Sheet()
// {
// Id = wb.GetIdOfPart(ws),
// SheetId = 1,
// Name = "報名"
// });
// //設定欄寬
// var cu = new Columns();
// cu.Append(
// new Column { Min = 1, Max = 1, Width = 15, CustomWidth = true },
// new Column { Min = 2, Max = 4, Width = 10, CustomWidth = true },
// new Column { Min = 5, Max = 5, Width = 15, CustomWidth = true },
// new Column { Min = 6, Max = 8, Width = 25, CustomWidth = true },
// new Column { Min = 9, Max = 9, Width = 15, CustomWidth = true },
// new Column { Min = 10, Max = 10, Width = 10, CustomWidth = true },
// new Column { Min = 11, Max = 11, Width = 25, CustomWidth = true },
// new Column { Min = 12, Max = 16, Width = 10, CustomWidth = true },
// new Column { Min = 17, Max = 20, Width = 10, CustomWidth = true }
// );
// ws.Worksheet.Append(cu);
// //建立資料頁
// var sd = new SheetData();
// ws.Worksheet.AppendChild(sd);
// //第一列資料
// var tr = new Row();
// tr.Append(
// new Cell() { CellValue = new CellValue("單號"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("報名日期"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("單據狀態"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("姓名/名稱"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("聯絡電話"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("報名活動"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("收件地址"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("備註"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("項目名稱"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("姓名"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("代表地址"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("陽上/報恩者"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("開始日期"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("期滿日期"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("應續約日"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("劃位狀態"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("預設金額"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("數量"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("小計"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("已收金額"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("未收金額"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("付款期限"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("報名狀態"), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("狀態備註"), DataType = CellValues.String }
// );
// sd.AppendChild(tr);
// //查詢要匯出的資料
// // ❌ 錯誤寫法: var aIDt = _db.actItems.Where(f => f.subject.Contains(s_actItemTxt.Value.Trim())).Select(f => f.num.ToString());
// // 改為整數陣列,避免後續查詢中使用 .ToString()
// var aIDt = _db.actItems.Where(f => f.subject.Contains(s_actItemTxt.Value.Trim())).Select(f => f.num).ToArray();//品項
// var qry = _db.pro_order.AsQueryable();
// if (!isStrNull(s_order_no.Value))
// qry = qry.Where(o => o.order_no.Contains(s_order_no.Value.Trim()));
// if (!isStrNull(s_u_name.Value))
// qry = qry.Where(o => o.f_num.HasValue && o.follower.u_name.Contains(s_u_name.Value.Trim()));
// if (!isStrNull(s_introducerTxt.Value))
// qry = qry.Where(o => o.f_num.HasValue && o.follower1.u_name.Contains(s_introducerTxt.Value.Trim()));
// if (!isStrNull(s_subject.Value))
// qry = qry.Where(o => o.activity_num.HasValue && o.activity.subject.Contains(s_subject.Value.Trim()));
// if (!isStrNull(s_actItemTxt.Value))
// {
// // ❌ 錯誤寫法: qry = qry.Where(o => o.pro_order_detail.Where(f2 => f2.order_no == o.order_no && aIDt.ToArray().Contains(f2.actItem_num.ToString())).Count() > 0);
// // ✅ 實際比較:僅在 actItem_num 有值時才與整數陣列比對
// qry = qry.Where(o => o.pro_order_detail.Any(f2 =>
// f2.order_no == o.order_no &&
// f2.actItem_num.HasValue &&
// aIDt.Contains(f2.actItem_num.Value)));
// }
// if (!isStrNull(s_keyin1.SelectedValue))
// qry = qry.Where(o => o.keyin1 == s_keyin1.SelectedValue);
// if (!isStrNull(s_up_time1.Value) && isDate(s_up_time1.Value))
// qry = qry.Where(o => o.up_time >= ValDate(s_up_time1.Value));
// if (!isStrNull(s_up_time2.Value) && isDate(s_up_time2.Value))
// qry = qry.Where(o => o.up_time < Convert.ToDateTime(s_up_time2.Value).AddDays(1));
// qry = qry.OrderByDescending(o => o.reg_time);
// MyWeb.encrypt encrypt = new MyWeb.encrypt();
// var tdesc = publicFun.enum_desc<Model.pro_order.detailKeyin1>();
// var bedDt = _db.bed_order_detail.AsQueryable();//掛單明細
// //left join 使用 GroupJoin
// //var list = qry.Join
// var list = qry.GroupJoin(
// _db.pro_order_detail, o => o.order_no, p => p.order_no, (o, c) =>
// new
// {
// //訂單資料
// order_no = o.order_no,
// up_time = o.up_time,
// keyin1 = o.keyin1,
// f_num = o.follower != null ? o.follower.u_name : "", //姓名/名稱
// phone = o.phone,
// activity_num = o.activity_num.HasValue ? o.activity.subject : "",
// address = o.address,
// demo = o.demo,
// c
// }).SelectMany(o => o.c.DefaultIfEmpty(), (o, d) => //SelectMany 展開
// new
// {
// //訂單資料
// order_no = o.order_no,
// up_time = o.up_time,
// keyin1 = o.keyin1,
// f_num = o.f_num, //姓名/名稱
// phone = o.phone,
// activity_num = o.activity_num,
// address = o.address,
// demo = o.demo,
// //訂單明細
// //使用DefaultIfEmpty 因匿名型別無法輸出NULL(無法轉換成強型別),需特別注意Null的處理
// d_actItem_num = d == null ? "" : (d.actItem_num.HasValue ? d.actItem.subject : ""), //項目名稱
// d_category = d == null ? "" : (d.actItem_num.HasValue ? d.actItem.category.ToString() : ""),
// d_f_num = d == null ? "" : (d.f_num.HasValue ? d.follower.u_name : ""), //姓名
// d_address = d == null ? "" : d.address,
// d_from_id = d == null ? "" : (d.from_id.HasValue ? d.follower1.u_name : ""), //陽上/報恩者
// d_start_date = d == null ? "" : (d.start_date.HasValue ? d.start_date.Value.ToString("yyyy/MM/dd") : ""), //開始日期
// d_due_date = d == null ? "" : (d.due_date.HasValue ? d.due_date.Value.ToString("yyyy/MM/dd") : ""), //期滿日期
// d_extend_date = d == null ? "" : (d.extend_date.HasValue ? d.extend_date.Value.ToString("yyyy/MM/dd") : ""), //應續約日
// d_price = d == null ? "" : (d.price.HasValue ? d.price.Value.ToString() : "0"), //預設金額
// d_qty = d == null ? "" : (d.qty.HasValue ? d.qty.Value.ToString() : "0"), //數量
// d_writeBedQty = d == null ? 0 : bedDt.Where(b => (b.bed_order.o_detail_id.Value == d.num) && b.checkIn_date.HasValue && b.bed_kind_detail_id.HasValue).Count(), //已劃數量
// d_notBedQty = d == null ? 0 : bedDt.Where(b => b.bed_order.o_detail_id.Value == d.num && (!b.checkIn_date.HasValue || !b.bed_kind_detail_id.HasValue)).Count(), //未劃數量
// d_pay = d == null ? "" : (d.pay.HasValue ? d.pay.Value.ToString() : "0"), //已收金額
// d_pay_date = d == null ? "" : (d.pay_date.HasValue ? d.pay_date.Value.ToString("yyyy/MM/dd") : ""), //付款期限
// d_keyin1 = d == null ? "" : (d.keyin1.HasValue && d.keyin1.Value > 0 ? tdesc[d.keyin1 ?? 1] : ""), //報名狀態
// d_demo = d == null ? "" : d.demo, //狀態備註
// }).ToList();
// if (list.Count > 0)
// {
// foreach (var item in list)
// {
// //新增資料列
// tr = new Row();
// tr.Append(
// new Cell() { CellValue = new CellValue(item.order_no), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue(item.up_time.Value.ToString("yyyy/MM/dd")), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue(Model.pro_order.keyin1_value_to_text(item.keyin1)), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue(item.f_num), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue(encrypt.DecryptAutoKey(item.phone)), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue(item.activity_num), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue(item.address), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue(item.demo), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue(item.d_actItem_num), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue(item.d_f_num), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue(item.d_address), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue(item.d_from_id), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue(item.d_start_date), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue(item.d_due_date), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue(item.d_extend_date), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue((Val(item.d_category) == (int)Model.activity.category.Order) ? (item.d_notBedQty + "/" + item.d_writeBedQty) : ""), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("$" + ValMoney(item.d_price)), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue(item.d_qty), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("$" + ValMoney(ValFloat(item.d_price) * Val(item.d_qty))), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("$" + ValMoney(item.d_pay)), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue("$" + ValMoney(ValFloat(item.d_price) * Val(item.d_qty) - ValFloat(item.d_pay))), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue(item.d_pay_date), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue(item.d_keyin1), DataType = CellValues.String },
// new Cell() { CellValue = new CellValue(item.d_demo), DataType = CellValues.String }
// );
// sd.AppendChild(tr);
// }
// Model.admin_log admin_log = new Model.admin_log();
// admin_log.writeLog(admin.info.u_id, (int)Model.admin_log.Systems.Order, (int)Model.admin_log.Status.Excel, admin_log.LogViewBtn(list.Select(x => x.order_no).ToList()));
// }
//}
//HttpContext.Current.Response.Clear();
//HttpContext.Current.Response.AddHeader("content-disposition", "attachment; filename=報名.xlsx");
//HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
//HttpContext.Current.Response.BinaryWrite(memoryStream.ToArray());
//HttpContext.Current.Response.End();
}
private string GetCellReference(int column, int row)
{
int dividend = column;
string cellReference = string.Empty;
while (dividend > 0)
{
int modulo = (dividend - 1) % 26;
char columnChar = (char)('A' + modulo);
cellReference = columnChar + cellReference;
dividend = (dividend - modulo) / 26;
}
return cellReference + row.ToString();
}
}
+6 -13
View File
@@ -144,13 +144,10 @@
<tbody>
<tr>
<th>項目名稱</th>
<th class="nowarp">姓名</th>
<th>代表地址</th>
<th class="nowarp">陽上/報恩</th>
<th class="nowarp">陽上</th>
<th class="nowarp">標題</th>
<th class="fit">開始日</th>
<th class="fit">期滿日</th>
<th class="fit">延續日</th>
<th class="fit">劃位</th>
<asp:PlaceHolder ID="PlaceHolder2" runat="server">
<th class="fit">功德金</th>
<th class="fit">數量</th>
@@ -167,18 +164,14 @@
<td>
<asp:Literal ID="actitem_numTxt" runat="server"></asp:Literal></td>
<td class="nowarp">
<asp:Literal ID="f_numTxt" runat="server"></asp:Literal></td>
<td><%# Eval("address") %></td>
<asp:Literal ID="left_nameTxt" runat="server"></asp:Literal></td>
<td class="nowarp">
<asp:Literal ID="from_idTxt" runat="server"></asp:Literal></td>
<asp:Literal ID="mid_nameTxt" runat="server"></asp:Literal></td>
<td class="fit"><%# Eval("start_date") != null? Convert.ToDateTime( Eval("start_date")).ToString("yyyy/MM/dd") : "" %></td>
<td class="fit">
<asp:Literal ID="due_date" runat="server"></asp:Literal></td>
<td class="fit">
<asp:Literal ID="extend_date" runat="server"></asp:Literal></td>
<td class="fit">
<asp:Literal ID="BedQty" runat="server"></asp:Literal></td>
<asp:PlaceHolder ID="PlaceHolder2" runat="server">
<td class="fit text-end">
<asp:Literal ID="item_price" runat="server" Text='<%# Eval("price") %>'></asp:Literal></td>
+78 -20
View File
@@ -1,9 +1,15 @@
using DocumentFormat.OpenXml.Drawing.Charts;
using DocumentFormat.OpenXml.Vml.Office;
using Microsoft.Ajax.Utilities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Web;
using System.Web.Helpers;
using System.Web.UI;
using System.Web.UI.WebControls;
@@ -182,7 +188,19 @@ public partial class admin_follower_print_ : System.Web.UI.Page
if (!string.IsNullOrEmpty(_chkHasAct) && Convert.ToBoolean(_chkHasAct))
{
_query += "活動報名\n";
if (!string.IsNullOrEmpty(_selectAct))
{
int selectAct = Convert.ToInt32(_selectAct);
if (selectAct > 0)
{
var actSubject = _db.activities.Where(a => a.num == selectAct).Select(a => a.subject).FirstOrDefault();
_query += $"活動報名: {actSubject}\n";
}
}
else
{
_query += $"活動報名\n";
}
if (!string.IsNullOrEmpty(_chkNoAct) && Convert.ToBoolean(_chkNoAct))
{
@@ -404,16 +422,56 @@ public partial class admin_follower_print_ : System.Web.UI.Page
actitem_numTxt.Text = row.actItem_num.HasValue && row.actItem != null ? row.actItem.subject : "";
}
Literal fNumTxtLit = (Literal)e.Item.FindControl("f_numTxt");
if (fNumTxtLit != null)
//Literal fNumTxtLit = (Literal)e.Item.FindControl("f_numTxt");
//if (fNumTxtLit != null)
//{
// fNumTxtLit.Text = row.f_num.HasValue && row.follower != null ? row.follower.u_name : "";
//}
string jsonString = row.f_num_tablet?.ToString() ?? "";
if (!string.IsNullOrWhiteSpace(jsonString))
{
fNumTxtLit.Text = row.f_num.HasValue && row.follower != null ? row.follower.u_name : "";
var jo = JObject.Parse(jsonString);
List<string> allMidNames = new List<string>();
List<string> allLeftNames = new List<string>();
// 標題
var midNames = jo["mid_items"]?
.Select(item => (string)item["fam_name"])
.ToList();
if (midNames != null && midNames.Any())
{
allMidNames.AddRange(midNames);
}
Literal fromIdTxtLit = (Literal)e.Item.FindControl("from_idTxt");
if (fromIdTxtLit != null)
if (allMidNames.Any())
{
fromIdTxtLit.Text = row.from_id.HasValue && row.follower1 != null ? row.follower1.u_name : "";
Literal midNameTextLit = (Literal)e.Item.FindControl("mid_nameTxt");
if (midNameTextLit != null)
{
midNameTextLit.Text = string.Join(", ", allMidNames);
}
}
// 陽上
var leftNames = jo["left_items"]?
.Select(item => (string)item["fam_name"])
.ToList();
if (leftNames != null && leftNames.Any())
{
allLeftNames.AddRange(leftNames);
}
if (allLeftNames.Any())
{
Literal leftNameTextLit = (Literal)e.Item.FindControl("left_nameTxt");
if (leftNameTextLit != null)
{
leftNameTextLit.Text = string.Join(", ", allLeftNames);
}
}
}
Literal dueDateLit = (Literal)e.Item.FindControl("due_date");
@@ -422,21 +480,21 @@ public partial class admin_follower_print_ : System.Web.UI.Page
dueDateLit.Text = row.due_date.HasValue ? row.due_date.Value.ToString("yyyy-MM-dd") : "";
}
Literal extendDateLit = (Literal)e.Item.FindControl("extend_date");
if (extendDateLit != null)
{
extendDateLit.Text = row.extend_date.HasValue ? row.extend_date.Value.ToString("yyyy-MM-dd") : "";
}
//Literal extendDateLit = (Literal)e.Item.FindControl("extend_date");
//if (extendDateLit != null)
//{
// extendDateLit.Text = row.extend_date.HasValue ? row.extend_date.Value.ToString("yyyy-MM-dd") : "";
//}
//劃位狀態
int writeBedQty = _bedDt.Where(b => b.bed_order != null && b.bed_order.o_detail_id == row.num && b.checkIn_date.HasValue && b.bed_kind_detail_id.HasValue).Count();
int notBedQty = _bedDt.Where(b => b.bed_order != null && b.bed_order.o_detail_id == row.num && (!b.checkIn_date.HasValue || !b.bed_kind_detail_id.HasValue)).Count();
////劃位狀態
//int writeBedQty = _bedDt.Where(b => b.bed_order != null && b.bed_order.o_detail_id == row.num && b.checkIn_date.HasValue && b.bed_kind_detail_id.HasValue).Count();
//int notBedQty = _bedDt.Where(b => b.bed_order != null && b.bed_order.o_detail_id == row.num && (!b.checkIn_date.HasValue || !b.bed_kind_detail_id.HasValue)).Count();
Literal bedQtyLit = (Literal)e.Item.FindControl("BedQty");
if (bedQtyLit != null)
{
bedQtyLit.Text = (row.actItem != null && row.actItem.category.HasValue && Convert.ToInt32(row.actItem.category.Value) == (int)Model.activity.category.Order) ? (notBedQty + "/" + writeBedQty) : "";
}
//Literal bedQtyLit = (Literal)e.Item.FindControl("BedQty");
//if (bedQtyLit != null)
//{
// bedQtyLit.Text = (row.actItem != null && row.actItem.category.HasValue && Convert.ToInt32(row.actItem.category.Value) == (int)Model.activity.category.Order) ? (notBedQty + "/" + writeBedQty) : "";
//}
Literal keyin1Lit = (Literal)e.Item.FindControl("keyin1");
if (keyin1Lit != null)
+154 -7
View File
@@ -11,9 +11,9 @@
border-bottom: 1px solid #eee;
}
</style>
</asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="footer_script" runat="Server">
<script>
Vue.filter('timeString', function (value, myFormat) {
return value == null || value == "" ? "" : moment(value).format(myFormat || 'YYYY-MM-DD, HH:mm:ss');
@@ -464,6 +464,11 @@
initialized: false,
currentItem: {}
},
tablet_edit_new: {
show: false,
initialized: false,
currentItem: {}
},
//收款註記
cash_dialog: {
show: false,
@@ -538,7 +543,8 @@
//currentItem.f_num_tablet = JSON.stringify(receivedData.tablet_data);
this.editedItem = {
...currentItem,
f_num_tablet: JSON.stringify(receivedData.tablet_data)
f_num_tablet: JSON.stringify(receivedData.tablet_data),
style: receivedData.style
};
// 呼叫 save 方法
await this.save();
@@ -546,10 +552,38 @@
// 關閉編輯對話框
this.tablet_edit.show = false;
this.tablet_edit_new.show = false;
// 顯示成功訊息
this.snackbar.text = '牌位資料已更新';
this.snackbar.show = true;
} else if (event.data.source === 'editorNew.btn.click') {
const receivedData = event.data.data;
// 更新編輯中的項目
//if (receivedData.tabletItem && this.editedIndex > -1) {
if (receivedData.tabletItem) {
// 將 tablet_data 轉換為 JSON 字串
//this.editedItem.f_num_tablet = JSON.stringify(receivedData.tablet_data);
// 確保其他必要欄位保持不變
const currentItem = this.desserts[this.editedIndex];
//currentItem.f_num_tablet = JSON.stringify(receivedData.tablet_data);
this.editedItem = {
...currentItem,
f_num_tablet: JSON.stringify(receivedData.tablet_data),
style: receivedData.style
};
// 呼叫 save 方法
await this.save();
}
this.tablet_edit_new.show = false;
// 顯示成功訊息
this.snackbar.text = '牌位資料已更新';
this.snackbar.show = true;
}
});
@@ -560,6 +594,13 @@
this.tablet_edit.initialized = true;
};
}
const iframe1 = document.querySelector('iframe#tablet_edit_new_iframe');
if (iframe1) {
iframe1.onload = () => {
this.tablet_edit_new.initialized = true;
};
}
},
watch: {
options: {
@@ -571,6 +612,17 @@
'tablet_edit.show': {
handler(newVal) {
if (!newVal && this._savedEditedItem) {
// console.log("三小");
this.editedItem = $.extend(true, {}, this._savedEditedItem);
this._savedEditedItem = null;
}
}
},
'tablet_edit_new.show': {
handler(newVal) {
if (!newVal && this._savedEditedItem) {
//console.log("不合理");
//$("#tablet_edit_new_iframe").src = $("#tablet_edit_new_iframe").src;
this.editedItem = $.extend(true, {}, this._savedEditedItem);
this._savedEditedItem = null;
}
@@ -703,6 +755,7 @@
curr.select(this.editedItem, row);
}
this.search_dialog.show = false;
this.search_dialog.page = 1;
//console.log(row, row["u_name"], row["f_number"], curr.id, target);
},
//報名詳細資料
@@ -807,7 +860,7 @@
isValidDate = Date.parse(item.pay_date);
if (!isNaN(isValidDate))
item.pay_date = new Date(item.pay_date).format("yyyy-MM-dd")
console.log(item);
this.editedItem = $.extend(true, {}, item);
this.data_dialog.show = true;
this.data_dialog.isAddNew = false;
@@ -818,6 +871,34 @@
this.editedItem = $.extend(true, {}, item);
this.file_dialog.show = true;
},
async editTabletNew(item) {
this.editedIndex = this.desserts.indexOf(item);
this.editedItem = $.extend(true, {}, item);
try {
//document.getElementById("tablet_edit_new_iframe").contentWindow.location.reload();
// 如果是新項目,先保存
if (this.editedItem.num <= 0 || this.editedItem.num === null || this.editedItem.num === undefined) {
this.editedItem.qty = 1;
const savedItem = await this.save(false);
if (savedItem) {
this.$set(this.desserts, this.editedIndex, savedItem);
this.editedItem = $.extend(true, {}, savedItem);
}
}
// 先發送消息
await this.sendMessageToIframeNew();
// 保存當前的 editedItem 數據
const currentData = $.extend(true, {}, this.editedItem);
// 顯示對話框
this.tablet_edit_new.show = true;
// 立即恢復數據
this.editedItem = $.extend(true, {}, currentData);
} catch (error) {
console.error('Error in editTablet:', error);
}
},
async editTablet(item) {
this.editedIndex = this.desserts.indexOf(item);
this.editedItem = $.extend(true, {}, item);
@@ -844,6 +925,54 @@
console.error('Error in editTablet:', error);
}
},
async sendMessageToIframeNew() {
const iframe = document.querySelector('iframe#tablet_edit_new_iframe');
// 在這裡深度複製 editedItem,確保數據不會被修改
const itemToSend = $.extend(true, {}, this.editedItem);
if (iframe) {
try {
// 準備要發送的數據
let familyMembers = [];
try {
// 嘗試獲取家族成員數據
const response = await axios.get(HTTP_HOST + 'api/familymembers/follower/' + this.follower_id);
familyMembers = response.data;
} catch (error) {
console.warn('error:', error);
}
// 準備發送的數據
const itemInfo = {
source: 'order.btn.click',
tabletItem: {
...itemToSend,
title: this.titleword() // 確保標題被包含
},
familyMembers: familyMembers,
host: HTTP_HOST,
follower_id:this.follower_id
};
iframe.contentWindow.postMessage(itemInfo, '*');
// 發送後確認數據完整性
// 如果數據被清除,立即恢復
if (!this.editedItem.num && itemToSend.num) {
this.$nextTick(() => {
this.editedItem = $.extend(true, {}, itemToSend);
});
}
} catch (error) {
console.error('Error in sendMessageToIframe:', error);
}
} else {
console.error('iframe not found');
}
},
async sendMessageToIframe() {
const iframe = document.querySelector('iframe#tablet_edit_iframe');
@@ -964,6 +1093,7 @@
async save(shouldClose = true) {
if (this.editedIndex > -1) {
if (this.order_no != '') {
console.log("ok:",this.editedItem);
//chcck necessary params
if (this.editedItem.actitem_num_selected.val != 0 &&
this.editedItem.keyin1_selected.val !=0 &&
@@ -971,9 +1101,11 @@
/* (this.editedItem.category=="1"? this.editedItem.from_id_selected.val != 0 : true) &&*/
this.requireData(this.editedItem.qty, (this.editedItem.num == 0 ? false : true)) ) /* qty為0視為不需要此項目,不儲存此筆資料*/
{
console.log(this.editedItem);
//check price
if (this.editedItem.pay <= this.editedItem.price * this.editedItem.qty) {
console.log(this.editedItem.f_num_selected.val);
console.log(this.editedItem.from_id_selected.val);
//check qty
//數量不可小於掛單明細的數量
if (this.editedItem.qty >= this.editedItem.writeBedQty + this.editedItem.notBedQty) {
@@ -1001,6 +1133,7 @@
pay: this.editedItem.pay,
pay_date: this.editedItem.pay_date,
customize_data: this.editedItem.customize_data,
style: this.editedItem.style
}
await axios
.post(HTTP_HOST + 'api/order/SaveDetailData', pro_order_detail)
@@ -1727,7 +1860,7 @@
<div class="">
<asp:Button ID="add" runat="server" Text="送出" OnClick="add_Click" CssClass="btn btn-primary" />
<asp:Button ID="edit" runat="server" Text="修改" Visible="false" OnClick="edit_Click" CssClass="btn btn-primary" />
<asp:Button ID="goback" runat="server" Text="回列表" Visible="false" CausesValidation="false" OnClick="goback_Click" CssClass="btn btn-outline-secondary" />
<asp:Button ID="goback" runat="server" Text="取消" CausesValidation="false" OnClick="goback_Click" CssClass="btn btn-outline-secondary" />
</div>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
@@ -1999,6 +2132,9 @@
<v-icon title="編輯牌位" color="blue" class="mr-2" @click="editTablet(item);">
mdi-file-document-edit-outline
</v-icon>
<v-icon title="編輯牌位New" color="blue" class="mr-2" @click="editTabletNew(item);">
mdi-file-document-edit-outline
</v-icon>
<v-icon title="列印" color="blue" class="mr-2" @click="printItem(item);" v-if="canPrint || lists.length==0" >
mdi-printer
</v-icon>
@@ -2353,7 +2489,7 @@
<v-card>
<v-card-title class="justify-space-between grey lighten-2">
查詢:{{search_dialog.current.title}}
<v-btn icon @click="search_dialog.show=false"><v-icon>mdi-close</v-icon></v-btn>
<v-btn icon @click="search_dialog.show=false; search_dialog.page = 1;"><v-icon>mdi-close</v-icon></v-btn>
</v-card-title>
<v-card-text >
<v-row>
@@ -2566,6 +2702,17 @@
</v-card>
</v-dialog>
<v-dialog v-model="tablet_edit_new.show" min-width="100vw" min-height="100vh" persistent eager :class="{'d-none': !tablet_edit_new.initialized}">
<v-card>
<v-card-title class="justify-space-between grey lighten-2">
<span class="fs-6 text text-dark">編輯牌位 : {{editedItem.actitem_num_selected.text}} - {{editedItem.print_id}}</span>
<v-btn icon @click="tablet_edit_new.show=false"><v-icon>mdi-close</v-icon></v-btn>
</v-card-title>
<v-card-text>
<iframe id="tablet_edit_new_iframe" src="../print/tablet_edit/editorNewOne.html" style="width: 100%; height: 100%;min-height:100vh;min-width:100vw" frameborder="0"></iframe>
</v-card-text>
</v-card>
</v-dialog>
<v-dialog v-model="tablet_edit.show" max-width="1000px" persistent eager :class="{'d-none': !tablet_edit.initialized}">
<v-card>
<v-card-title class="justify-space-between grey lighten-2">
@@ -2573,7 +2720,7 @@
<v-btn icon @click="tablet_edit.show=false"><v-icon>mdi-close</v-icon></v-btn>
</v-card-title>
<v-card-text>
<iframe id="tablet_edit_iframe" src="../print/tablet_edit/editor.html" style="width: 100%; height: 550px;" frameborder="0"></iframe>
<iframe id="tablet_edit_iframe" src="../print/tablet_edit/editornew.html" style="width: 100%; height: 580px;" frameborder="0"></iframe>
</v-card-text>
</v-card>
</v-dialog>
+19 -5
View File
@@ -1,15 +1,16 @@
using System;
using DocumentFormat.OpenXml.Spreadsheet;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Entity.Infrastructure;
using System.Data.OleDb;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Data.Entity.Infrastructure;
public partial class admin_order_reg : MyWeb.config
{
@@ -186,6 +187,15 @@ public partial class admin_order_reg : MyWeb.config
try
{
if (!isStrNull(pro_order.order_no))
{
bool isRegistered = _db.pro_order.Any(x => x.f_num == pro_order.f_num && x.activity_num == pro_order.activity_num);
if (isRegistered) // 重複報名
{
L_msg.Type = alert_type.warning;
L_msg.Text = "此信眾已報名過本活動";
}
else
{
_db.pro_order.Add(pro_order);
_db.SaveChanges();
@@ -196,8 +206,12 @@ public partial class admin_order_reg : MyWeb.config
string url = "index.aspx";
url = "reg.aspx?order_no=" + pro_order.order_no;
Session["LastAddedNo"] = pro_order.order_no;
Response.Redirect(url);
}
}
else
{
L_msg.Type = alert_type.danger;
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 81 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 99 KiB

File diff suppressed because it is too large Load Diff
+15
View File
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class admin_print_print_multi_new :MyWeb.function
{
private Model.ezEntities _db = new Model.ezEntities();
protected void Page_Load(object sender, EventArgs e)
{
}
}
File diff suppressed because it is too large Load Diff
+835
View File
@@ -0,0 +1,835 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link href="../../../js/vuetify.css" rel="stylesheet" />
<link href="../../../js/mdi-font/css/materialdesignicons.min.css" rel="stylesheet" />
<script src="../../../js/vue.min.js"></script>
<script src="../../../js/vuetify.min.js"></script>
<script src="../../../js/axios.min.js"></script>
<style>
html {
overflow: hidden;
}
.scrollable-list {
max-height: 250px;
height: 220px;
overflow-y: auto;
overflow-x: hidden;
}
.scrollable-list .v-list-item__content {
padding: 4px 0px;
}
.scrollable-list .v-list-item {
min-height: 30px;
padding: 0 8px;
}
.scrollable-list .v-list-item__action {
min-width: 0 !important;
width: auto !important;
margin-right: 0 !important;
}
.scrollable-list .v-btn--icon.v-size--default {
height: 24px;
width: 24px;
}
#app .v-card__subtitle,
#app .v-card__text,
#app .v-card__title {
padding: 12px 16px 0 16px;
}
#app .v-list-item.hover-item .v-list-item__subtitle {
/*display: none !important;*/
display: flex !important;
}
#app .v-list-item.hover-item:hover .v-list-item__subtitle {
display: flex !important;
}
.badge-deceased {
background-color: #ffc904;
color: #300a0a;
padding: 2px 4px;
border-radius: 20px;
font-weight: bold;
font-size: 10px;
display: inline-block;
position: relative;
top: -2px;
}
.badge-zero {
background-color: #CCC;
color: #FFF;
padding: 2px 4px;
border-radius: 20px;
font-weight: bold;
font-size: 10px;
display: inline-block;
position: relative;
top: -2px;
}
.equal-card {
min-height: 280px;
}
.checkbox-narrow {
min-width: 32px;
width: 32px;
padding: 0;
margin-right: 4px;
}
/* num=0 刪除按鈕警示樣式 */
.btn-delete-warning:hover {
background-color: #fff3cd !important;
border-radius: 50%;
}
.btn-delete-warning:hover .v-icon {
color: #856404 !important;
}
</style>
<link rel="stylesheet" href="print.css">
</head>
<body>
<div id="app">
<v-app>
<v-container>
<v-row>
<v-col cols="12" md="12">
選擇版型
<select id="model-select" v-model="selected.style">
<option v-for="c in code.style" :value="c.styleID">{{c.name}}</option>
</select>
</v-col>
</v-row>
<v-row>
<v-col cols="4" md="4">
<v-card class="pa-2" outlined tile>
<div class="docs editor">
<div class="page border" data-body-class="tblt-l a3">
<div class="content">
<div class="bg"><img alt="Alternate Text" :src="'../' + item_type_image"></div>
<div class="text">
<div class="top_text_1"></div>
<div class="top_text_2">{{tabletItem.print_id}}</div>
<div class="top_text_3"></div>
<div class="right_text text-block fit-text vertical text-start border"
style="--lines:0;--line_len:5;"></div>
<div class="mid_text text-block fit-text vertical border"
:style="mid_text_style" v-html="join_mid_text"></div>
<div class="mid_text_2 text-block fit-text vertical border"
style="--lines:0;--line_len:5;"></div>
<div class="left_text text-block fit-text vertical text-start border"
:style="left_text_style" v-html="join_left_text"></div>
<div class="txt_up vertical" v-if="item_type == 'B'">陽上</div>
<div class="txt_down vertical" v-if="item_type == 'B'">拜薦</div>
</div>
</div>
</div>
</div>
</v-card>
<div class="mt-2">
<v-btn color="primary" @click="saveData">儲存牌位</v-btn>
</div>
</v-col>
<v-col cols="4" md="4" id="type_edit_B" v-if="item_type==='B'" class="d-flex flex-column">
<v-card elevation="2" class="mb-2 equal-card">
<v-card-text class="py-2 px-2">
<v-row no-gutters align="center">
<v-col cols="auto">
<v-checkbox v-model="isAllSelected"
@change="toggleSelectAll"
color="primary"
hide-details
label="疏文代表"
class="ma-0"></v-checkbox>
</v-col>
<v-col cols="auto" class="ml-4">
<span class="subtitle-2 grey--text text--darken-1">超渡-已選</span>
</v-col>
<v-spacer></v-spacer>
<v-col cols="auto">
<v-btn color="primary" icon small @click="openAddDialog('Y')">
<v-icon>mdi-plus</v-icon>
</v-btn>
</v-col>
</v-row>
</v-card-text>
<v-list class="scrollable-list">
<v-list-item-group>
<v-list-item v-for="(member, index) in family_deceased_Y_selected" :key="index" class="hover-item">
<v-list-item-action>
<v-checkbox v-model="member.IsShuWen"
color="primary"
class="checkbox-narrow d-inline-flex align-center" />
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>
<span class="badge-zero" v-if="member.num==0">0</span>
<span class="badge-deceased" v-if="member.deceased">{{ member.deceased ? '卍' : '' }}</span>
{{ member.fam_name }}
<v-chip v-if="member.fam_title" small>
{{ member.fam_title }}
</v-chip>
</v-list-item-title>
<v-list-item-subtitle class="d-flex justify-end">
<v-btn v-if="member.num === 0" icon @click="toggleNoSpace(member)" :title="'不加空格'">
<v-icon :color="member.nospace ? 'green' : 'grey lighten-1'">mdi-backspace</v-icon>
</v-btn>
<v-btn icon @click="moveUp(member, 'Y', index)" :disabled="index === 0">
<v-icon color="grey lighten-1">mdi-arrow-up</v-icon>
</v-btn>
<v-btn icon @click="moveDown(member, 'Y', index)" :disabled="index === family_deceased_Y_selected.length - 1">
<v-icon color="grey lighten-1">mdi-arrow-down</v-icon>
</v-btn>
<v-btn icon @click="confirmRemove(member, index, 'Y')" :class="{'btn-delete-warning': member.num === 0}">
<v-icon color="grey lighten-1">mdi-minus</v-icon>
</v-btn>
</v-list-item-subtitle>
</v-list-item-content>
<v-list-item-action class="align-self-start">
<v-btn icon @click="breakAfter(member, 'Y')">
<v-icon :color="member.option_break ? 'blue' : 'grey lighten-1'">
mdi-subdirectory-arrow-left
</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</v-list-item-group>
</v-list>
</v-card>
<v-card elevation="2" class="equal-card">
<v-card-subtitle>超渡-可選</v-card-subtitle>
<v-list class="scrollable-list">
<v-list-item-group>
<v-list-item v-for="member in family_deceased_Y_unselected" :key="member.fam_name">
<v-list-item-content>
<v-list-item-title>
<span class="badge-deceased" v-if="member.deceased">{{ member.deceased ? '卍' : '' }}</span>
{{ member.fam_name }}
<v-chip v-if="member.fam_title" small>
{{ member.fam_title }}
</v-chip>
</v-list-item-title>
</v-list-item-content>
<v-list-item-action>
<v-btn icon @click="addToSelected(member, 'Y')">
<v-icon color="grey lighten-1">mdi-plus</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</v-list-item-group>
</v-list>
</v-card>
</v-col>
<v-col cols="4" md="4" id="type_edit_AB" class="d-flex flex-column">
<v-card elevation="2" class="mb-2 equal-card">
<v-card-text class="py-2 px-2">
<v-row no-gutters align="center">
<v-col cols="auto" v-if="item_type==='A'">
<v-checkbox v-model="isAllSelected"
@change="toggleSelectAll"
color="primary"
hide-details
label="疏文代表"
class="ma-0"></v-checkbox>
</v-col>
<v-col cols="auto" :class="{'ml-4': item_type==='A'}">
<span class="subtitle-2 grey--text text--darken-1">陽上/祈福-已選</span>
</v-col>
<v-spacer></v-spacer>
<v-col cols="auto">
<v-btn color="primary" icon small @click="openAddDialog('N')">
<v-icon>mdi-plus</v-icon>
</v-btn>
</v-col>
</v-row>
</v-card-text>
<v-list class="scrollable-list">
<v-list-item-group>
<v-list-item v-for="(member, index) in family_deceased_N_selected" :key="index" class="hover-item">
<v-list-item-action v-if="item_type==='A'">
<v-checkbox v-model="member.IsShuWen"
color="primary"
class="checkbox-narrow d-inline-flex align-center" />
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>
<span class="badge-zero" v-if="member.num==0">0</span>
<span class="badge-deceased" v-if="member.deceased">{{ member.deceased ? '卍' : '' }}</span>
{{ member.fam_name }}
<v-chip v-if="member.fam_title" small>
{{ member.fam_title }}
</v-chip>
</v-list-item-title>
<v-list-item-subtitle class="d-flex justify-end">
<v-btn v-if="member.num === 0" icon @click="toggleNoSpace(member)" :title="'不加空格'">
<v-icon :color="member.nospace ? 'green' : 'grey lighten-1'">mdi-backspace</v-icon>
</v-btn>
<v-btn icon @click="moveUp(member, 'N', index)" :disabled="index === 0">
<v-icon color="grey lighten-1">mdi-arrow-up</v-icon>
</v-btn>
<v-btn icon @click="moveDown(member, 'N', index)" :disabled="index === family_deceased_N_selected.length - 1">
<v-icon color="grey lighten-1">mdi-arrow-down</v-icon>
</v-btn>
<v-btn icon @click="confirmRemove(member, index, 'N')" :class="{'btn-delete-warning': member.num === 0}">
<v-icon color="grey lighten-1">mdi-minus</v-icon>
</v-btn>
</v-list-item-subtitle>
</v-list-item-content>
<v-list-item-action class="align-self-start">
<v-btn icon @click="breakAfter(member, 'N')">
<v-icon :color="member.option_break ? 'blue' : 'grey lighten-1'">
mdi-subdirectory-arrow-left
</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</v-list-item-group>
</v-list>
</v-card>
<v-card elevation="2" class="equal-card">
<v-card-subtitle>陽上/祈福-可選</v-card-subtitle>
<v-list class="scrollable-list">
<v-list-item-group>
<v-list-item v-for="member in family_deceased_N_unselected" :key="member.fam_name">
<v-list-item-content>
<v-list-item-title>
<span class="badge-deceased" v-if="member.deceased">{{ member.deceased ? '卍' : '' }}</span>
{{ member.fam_name }}
<v-chip v-if="member.fam_title" small>
{{ member.fam_title }}
</v-chip>
</v-list-item-title>
</v-list-item-content>
<v-list-item-action>
<v-btn icon @click="addToSelected(member, 'N')">
<v-icon color="grey lighten-1">mdi-plus</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</v-list-item-group>
</v-list>
</v-card>
</v-col>
</v-row>
</v-container>
<div style="display:block;">
<textarea id="desc_iframe" style="width: 900px; height: 100px;">{{tabletItem}}</textarea>
</div>
<!-- 新增項目對話框 -->
<v-dialog v-model="addDialog" max-width="400">
<v-card>
<v-card-title style="font-size: 1rem;">新增項目</v-card-title>
<v-card-text>
<div class="mb-2">
<v-chip
v-for="(phrase, idx) in phrases"
:key="idx"
small
class="mr-1 mb-1"
:title="phrase.length > 5 ? phrase : ''"
@click="newItemText = (newItemText || '') + phrase"
style="cursor: pointer;"
>{{ phrase.length > 5 ? phrase.slice(0, 5) + '...' : phrase }}</v-chip>
</div>
<v-text-field
v-model="newItemText"
label="請輸入名稱"
outlined
dense
clearable
autofocus
@keyup.enter="confirmAddItem"
></v-text-field>
</v-card-text>
<v-card-actions>
<div class="d-flex align-center">
<v-checkbox
class="pt-0"
v-model="noSpace"
label="不加空格"
dense
hide-details
></v-checkbox>
<v-icon class="ml-2 mt-1">mdi-backspace</v-icon>
</div>
<v-spacer></v-spacer>
<v-btn text @click="addDialog = false">取消</v-btn>
<v-btn color="primary" @click="confirmAddItem">確定</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- 確認刪除對話框 -->
<v-dialog v-model="deleteDialog" max-width="350">
<v-card>
<v-card-title style="font-size: 1rem;">確認刪除</v-card-title>
<v-card-text>
確定要刪除「<strong>{{ deleteMemberName }}</strong>」嗎?<br>
<span class="red--text">此為手動新增項目,刪除後無法復原。</span>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn text @click="deleteDialog = false">取消</v-btn>
<v-btn color="error" @click="doRemove">確定刪除</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-app>
</div>
<script>
var VueApp = new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
code: {
style:[]
},
selected: {
style:""
},
actitem: "",
pageSize: "",
defaultStyle:"",
isAllSelected: false,
dialog: false,
addDialog: false, // 新增項目對話框
addDialogType: '', // 'Y' 或 'N'
newItemText: '', // 新增項目的文字
noSpace: true, // 不加空格 checkbox(預設勾選)
deleteDialog: false, // 確認刪除對話框
deleteIndex: -1, // 要刪除的 index
deleteType: '', // 'Y' 或 'N'
deleteMemberName: '', // 要刪除的名稱(顯示用)
phrases: [], // 常用片語
familyMembers: [], // 親友名單
tabletItem: {}, // 傳入的資料(信眾/牌位資訊)
item: {},
family_deceased_Y_selected: [], // 超渡/超薦/超冤名單
family_deceased_N_selected: [] // 消災/陽上名單
};
},
watch: {
family_deceased_N_selected: {
handler(newValue) {
if (this.item_type === 'A') {
if (Array.isArray(newValue) && newValue.length > 0) {
this.isAllSelected = newValue.every(member => member.IsShuWen === true);
}
}
},
deep: true
},
family_deceased_Y_selected: {
handler(newValue) {
if (this.item_type === 'B') {
if (Array.isArray(newValue) && newValue.length > 0) {
this.isAllSelected = newValue.every(member => member.IsShuWen === true);
}
}
},
deep: true
},
actitem: {
handler() {
this.getActItem();
},
deep: true
}
},
computed: {
family_deceased_Y_unselected() {
return this.familyMembers.filter(member =>
member.deceased === true &&
!this.family_deceased_Y_selected.some(selected => selected.num === member.num));
},
family_deceased_N_unselected() {
return this.familyMembers.filter(member =>
member.deceased === false &&
!this.family_deceased_N_selected.some(selected => selected.num === member.num));
},
item_type() {
return this.tabletItem?.actitem_num_selected?.text?.includes('超') ? 'B' : 'A';
// A:消災, 陽上.....
// B:超渡, 超薦.....
},
item_type_image() {
if (this.item_type === 'B') {
return 'tablet-1.svg';
} else {
return 'tablet-2.svg';
}
},
join_mid_text() {
const target = this.item_type === 'B'
? this.family_deceased_Y_selected
: this.family_deceased_N_selected;
return this.join_text(target);
},
join_left_text() {
let target = '';
if (this.item_type === 'B') {
target = this.join_text(this.family_deceased_N_selected);
}
return target;
},
mid_text_style() {
const text = this.join_mid_text; // Remove function call since join_mid_text is a computed property
return this.calculateTextStyle(text);
},
left_text_style() {
if (this.item_type !== 'B') return '--lines:1;--line_len:5';
return this.calculateTextStyle(this.join_left_text);
}
},
mounted() {
// 載入常用片語
fetch('phrases.json')
.then(res => res.json())
.then(data => { this.phrases = data; })
.catch(err => console.error('載入 phrases.json 失敗:', err));
// 監聽來自父頁面的消息
window.addEventListener('message', (event) => {
this.isAllSelected = false;
console.log('editor.html - received message event');
//console.log('editor.html - event origin:', event.origin);
//console.log('editor.html - parent origin:', window.parent.location.origin);
if (event.origin === window.parent.location.origin) {
//console.log('editor.html - origin check passed');
//console.log('editor.html - received data:', event.data);
const receivedData = event.data;
this.family_deceased_Y_selected = [];
this.family_deceased_N_selected = [];
if (receivedData.tabletItem) {
console.log('editor.html - updating tabletItem:', receivedData.tabletItem);
this.tabletItem = receivedData.tabletItem;
if (receivedData.familyMembers) {
this.familyMembers = receivedData.familyMembers; // 更新 familyMembers
console.log("app mounted, window message: ", this.familyMembers, receivedData);
}
if (receivedData.tabletItem) {
this.tabletItem = receivedData.tabletItem;
}
//console.log("actitem:", receivedData.tabletItem.actitem_num_selected.val);
console.log("receivedData::",receivedData);
if (receivedData.tabletItem.style) {
this.selected.style = receivedData.tabletItem.style;
} else {
this.selected.style = "";
}
//console.log("actitem:", receivedData.tabletItem.actitem_num_selected.val);
this.actitem = receivedData.tabletItem.actitem_num_selected.val;
//console.log("actitem:",receivedData.tabletItem.actitem_num_selected.val);
// 處理 f_num_tablet 資料
if (this.tabletItem.f_num_tablet) {
try {
const data = JSON.parse(this.tabletItem.f_num_tablet);
if (this.item_type === 'B') {
// B類型:超渡、超薦等
this.family_deceased_Y_selected = data.mid_items || [];
this.family_deceased_N_selected = data.left_items || [];
this.family_deceased_Y_selected.forEach(item => {
if (item.IsShuWen === undefined) {
Vue.set(item, 'IsShuWen', false);
}
});
if (this.family_deceased_Y_selected.length > 0) {
this.isAllSelected = this.family_deceased_Y_selected.every(member => member.IsShuWen === true);
} else {
this.isAllSelected = false;
}
} else {
// A類型:消災、陽上等
this.family_deceased_Y_selected = [];
this.family_deceased_N_selected = data.mid_items || [];
this.family_deceased_N_selected.forEach(item => {
if (item.IsShuWen === undefined) {
Vue.set(item, 'IsShuWen', false);
}
});
if (this.family_deceased_Y_selected.length > 0) {
this.isAllSelected = this.family_deceased_N_selected.every(member => member.IsShuWen === true);
} else {
this.isAllSelected = false;
}
console.log(this.family_deceased_N_selected)
}
} catch (e) {
console.error('解析牌位資料時發生錯誤:', e);
}
}
}
}
//this.getActItem();
});
},
methods: {
getActItem() {
axios
.post('/api/tablet/GetActItem', { itemNum: this.actitem })
.then(response => {
console.log(response);
if (response.data.result == "Y" && response.data.data) {
this.pageSize = response.data.data.pageSize;
this.defaultStyle = response.data.data.defaultStyle;
this.selected.style = response.data.data.defaultStyle;
console.log("shit:",this.selected.style);
this.getStyle();
}
}
);
},
getStyle() {
axios
.post('/api/tablet/GetStyleData', {}, {})
.then(response => {
console.log(response);
if (response.data.data) {
response.data.data.forEach(x => {
if (x.styleID != "000001") {
console.log(this.pageSize, x.paperSize);
if (this.pageSize&&this.pageSize==x.paperSize) {
this.code.style.push(x)
}
}
})
}
})
.catch(error => console.log(error))
},
toggleSelectAll(checked) {
this.isAllSelected = checked
if (this.item_type === 'B') {
this.family_deceased_Y_selected.forEach(member => {
member.IsShuWen = checked;
});
}
else if (this.item_type === 'A') {
this.family_deceased_N_selected.forEach(member => {
member.IsShuWen = checked;
});
}
console.log(checked)
console.log(this.family_deceased_N_selected)
console.log(this.family_deceased_Y_selected)
},
openAddDialog(type) {
this.addDialogType = type;
this.newItemText = '';
this.noSpace = true; // 重置為預設勾選
this.addDialog = true;
},
confirmAddItem() {
if (!this.newItemText.trim()) {
return; // 不允許空白
}
const newItem = {
num: 0,
fam_name: this.newItemText.trim(),
fam_gender: '',
deceased: false,
fam_title: '',
option_break: false,
IsShuWen: this.isAllSelected,
nospace: this.noSpace
};
if (this.addDialogType === 'Y') {
this.family_deceased_Y_selected.push(newItem);
} else if (this.addDialogType === 'N') {
this.family_deceased_N_selected.push(newItem);
}
this.addDialog = false;
this.newItemText = '';
},
addToSelected(member, type) {
const selectedMember = {
num: member.num,
fam_name: member.fam_name,
fam_gender: member.fam_gender,
deceased: member.deceased,
fam_title: member.fam_title, // 新增,讓上方顯示稱謂 tag
option_break: false, // 默認為 false,根據需要可以更改
IsShuWen: this.isAllSelected //是否加入疏文名單,默認false
};
console.log(this.isAllSelected)
if (type === 'Y') {
this.family_deceased_Y_selected.push(selectedMember);
console.log(this.family_deceased_Y_selected)
} else if (type === 'N') {
this.family_deceased_N_selected.push(selectedMember);
console.log(this.family_deceased_N_selected)
}
},
confirmRemove(member, index, type) {
if (member.num === 0) {
// num=0 需確認
this.deleteIndex = index;
this.deleteType = type;
this.deleteMemberName = member.fam_name;
this.deleteDialog = true;
} else {
// num!=0 直接刪除
this.removeFromSelected(index, type);
}
},
doRemove() {
this.removeFromSelected(this.deleteIndex, this.deleteType);
this.deleteDialog = false;
},
removeFromSelected(index, type) {
if (type === 'Y') {
this.family_deceased_Y_selected.splice(index, 1);
} else if (type === 'N') {
this.family_deceased_N_selected.splice(index, 1);
}
},
moveUp(member, type, index) {
if (index > 0) {
const array = type === 'Y' ? this.family_deceased_Y_selected : this.family_deceased_N_selected;
const temp = array[index - 1];
this.$set(array, index - 1, member);
this.$set(array, index, temp);
}
},
moveDown(member, type, index) {
if (index < (type === 'Y' ? this.family_deceased_Y_selected : this.family_deceased_N_selected).length - 1) {
const array = type === 'Y' ? this.family_deceased_Y_selected : this.family_deceased_N_selected;
const temp = array[index + 1];
this.$set(array, index + 1, member);
this.$set(array, index, temp);
}
},
breakAfter(member, type) {
console.log("breakAfter", member, type);
member.option_break = !member.option_break;
},
toggleNoSpace(member) {
this.$set(member, 'nospace', !member.nospace);
},
join_text(target) {
let result = '';
target.forEach((member, index) => {
// 每項前面加空格,但例外:
// 1. 第一項前面不加空格 (index === 0)
// 2. nospace === true 的項目前面不加空格
if (index > 0 && !member.nospace) {
result += ' ';
}
result += member.fam_name;
// 處理換行:如果 option_break 為 true 且不是最後一項,加 <br>
if (member.option_break && index < target.length - 1) {
result += '<br>';
}
});
result = result.replace('|', '<br>');
return result;
},
calculateTextStyle(text) {
if (!text) return '--lines:1;--line_len:5';
const lines = text.split('<br>');
const line_len = Math.max(...lines.map(line => {
return Array.from(line).reduce((acc, char) => {
// Full width (Chinese) characters
if (char.match(/[\u4e00-\u9fa5]/)) {
return acc + 1;
}
// Half width (English, numbers, etc.)
return acc + 0.5;
}, 0);
}));
return `--lines:${lines.length};--line_len:${Math.ceil(line_len)}`;
},
saveData() {
// 其它資料欄位, 不應在這裡修改
// 應該在進來的時候, 就已經修改(insert)好了
let tablet_data = {};
if (this.item_type === 'B') {// B:超渡, 超薦.....
tablet_data = {
mid_items: this.family_deceased_Y_selected,
left_items: this.family_deceased_N_selected,
style: this.selected.style
}
}
else {// A:消災, 陽上.....
tablet_data = {
mid_items: this.family_deceased_N_selected,
left_items: null,
style: this.selected.style
}
}
console.log(tablet_data)
const ret = {
source: 'editor.btn.click',
data: {
tabletItem: this.tabletItem,
tablet_data: tablet_data,
style:this.selected.style
}
};
console.log("儲存牌位資料", ret);
window.parent.postMessage(ret, '/');
}
}
});
</script>
<script>
const desc_iframe = document.getElementById('desc_iframe');
const btn = document.getElementById('btn');
//window.addEventListener('message', (event) => {
// if (event.source === window.parent) {
// let data = event.data;
// if (data.source === 'order.btn.click') {
// console.log('editor message', event.source, window.parent);
// app.item = data;
// console.log(app);
// desc_iframe.value = JSON.stringify(data);
// }
// }
//});
/*
btn.addEventListener('click', () => {
const ret = {
source: 'editor.btn.click',
desc: desc_iframe.value,
}
debugger;
console.log("btn click", ret);
window.parent.postMessage(ret, '/');
});
*/
</script>
</body>
</html>
+28 -1
View File
@@ -105,6 +105,23 @@
></v-text-field>
</div>
</template>
<template v-slot:item.kind="{ item }">
<div>
<div class="mb-2">
<span class="badge bg-primary me-1" title="支付方式">收支項目</span>
</div>
</div>
<div>
<v-select
:items="accountingKinds"
v-model="item.kind"
dense
outlined
hide-details
style="max-width: 200px"
></v-select>
</div>
</template>
<template v-slot:item.check_memo="{ item }">
<div class="d-flex align-center my-2" style="min-width: 300px">
<v-text-field
@@ -159,6 +176,7 @@ new Vue({
{ text: '*入帳銀行/帳戶 | 支付資訊/帳號後5碼', value: 'acc_num' },
{ text: '*入帳日期', value: 'check_date' },
{ text: '*入帳金額', value: 'check_amount' },
{ text: '*收支項目', value: 'kind' },
{ text: '備註/狀態 | 核對記錄', value: 'check_memo' }
],
items: [],
@@ -173,6 +191,7 @@ new Vue({
{ text: '作廢', value: '5' }
],
bankOptions: [],
accountingKinds:[],
payTypeText: {
1: '現金',
2: '匯款',
@@ -212,6 +231,13 @@ new Vue({
text: x.kind + (x.bank_name ? ' - ' + x.bank_name : '') + (x.bank_id ? ' (' + x.bank_id + ')' : ''),
value: x.num
}));
const kindRes = await axios.post('../../api/accounting/GetTitleKindList', {}, { params: { page: 1, pageSize: 1000 } });
this.accountingKinds = kindRes.data.list.map(x => ({
text: x.kind ,
value: x.num
}));
this.loading = false;
},
async submitData() {
@@ -246,7 +272,8 @@ new Vue({
acc_num: item.acc_num,
check_date: item.check_date,
check_amount: item.check_amount,
check_memo: item.check_memo
check_memo: item.check_memo,
kind: item.kind
}));
try {
const res = await axios.post('../../api/transfer_register/batch_update', updateList);
@@ -65,6 +65,7 @@
</template>
<template v-slot:item.transfer_info="{ item }">
<div>
<div class="font-weight-bold text-primary">應收總額:{{ item.price_totals | currency }}</div>
<div class="font-weight-bold text-primary">入帳金額:{{ item.transfer_check_amount | currency }}</div>
<div class="text-success">沖帳日期:{{ item.transfer_check_date | date }}</div>
<div v-if="item.transfer_remain_amount > 0" class="text-warning">
@@ -202,6 +203,7 @@
<div class="mb-2"><span class="font-weight-bold">入帳帳戶:</span>{{ dialog.selected.acc_name }}</div>
<div class="mb-2"><span class="font-weight-bold">入帳日期:</span>{{ dialog.selected.transfer_check_date | date }}</div>
<div class="mb-2"><span class="font-weight-bold">入帳金額:</span>{{ dialog.selected.transfer_check_amount | currency }}</div>
<div class="mb-2"><span class="font-weight-bold">應收總額:</span>{{ dialog.selected.price_totals | currency }}</div>
</v-col>
</v-row>
<v-divider class="my-4"></v-divider>
+478
View File
@@ -0,0 +1,478 @@
(function umd(root,factory){
if(typeof module==='object' && typeof exports === 'object' )
module.exports=factory()
else if(typeof define==='function' && define.amd)
define([],factory)
else
root.httpVueLoader=factory()
})(this,function factory() {
'use strict';
var scopeIndex = 0;
StyleContext.prototype = {
withBase: function(callback) {
var tmpBaseElt;
if ( this.component.baseURI ) {
// firefox and chrome need the <base> to be set while inserting or modifying <style> in a document.
tmpBaseElt = document.createElement('base');
tmpBaseElt.href = this.component.baseURI;
var headElt = this.component.getHead();
headElt.insertBefore(tmpBaseElt, headElt.firstChild);
}
callback.call(this);
if ( tmpBaseElt )
this.component.getHead().removeChild(tmpBaseElt);
},
scopeStyles: function(styleElt, scopeName) {
function process() {
var sheet = styleElt.sheet;
var rules = sheet.cssRules;
for ( var i = 0; i < rules.length; ++i ) {
var rule = rules[i];
if ( rule.type !== 1 )
continue;
var scopedSelectors = [];
rule.selectorText.split(/\s*,\s*/).forEach(function(sel) {
scopedSelectors.push(scopeName+' '+sel);
var segments = sel.match(/([^ :]+)(.+)?/);
scopedSelectors.push(segments[1] + scopeName + (segments[2]||''));
});
var scopedRule = scopedSelectors.join(',') + rule.cssText.substr(rule.selectorText.length);
sheet.deleteRule(i);
sheet.insertRule(scopedRule, i);
}
}
try {
// firefox may fail sheet.cssRules with InvalidAccessError
process();
} catch (ex) {
if ( ex instanceof DOMException && ex.code === DOMException.INVALID_ACCESS_ERR ) {
styleElt.sheet.disabled = true;
styleElt.addEventListener('load', function onStyleLoaded() {
styleElt.removeEventListener('load', onStyleLoaded);
// firefox need this timeout otherwise we have to use document.importNode(style, true)
setTimeout(function() {
process();
styleElt.sheet.disabled = false;
});
});
return;
}
throw ex;
}
},
compile: function() {
var hasTemplate = this.template !== null;
var scoped = this.elt.hasAttribute('scoped');
if ( scoped ) {
// no template, no scopable style needed
if ( !hasTemplate )
return;
// firefox does not tolerate this attribute
this.elt.removeAttribute('scoped');
}
this.withBase(function() {
this.component.getHead().appendChild(this.elt);
});
if ( scoped )
this.scopeStyles(this.elt, '['+this.component.getScopeId()+']');
return Promise.resolve();
},
getContent: function() {
return this.elt.textContent;
},
setContent: function(content) {
this.withBase(function() {
this.elt.textContent = content;
});
}
};
function StyleContext(component, elt) {
this.component = component;
this.elt = elt;
}
ScriptContext.prototype = {
getContent: function() {
return this.elt.textContent;
},
setContent: function(content) {
this.elt.textContent = content;
},
compile: function(module) {
var childModuleRequire = function(childURL) {
return httpVueLoader.require(resolveURL(this.component.baseURI, childURL));
}.bind(this);
var childLoader = function(childURL, childName) {
return httpVueLoader(resolveURL(this.component.baseURI, childURL), childName);
}.bind(this);
try {
Function('exports', 'require', 'httpVueLoader', 'module', this.getContent()).call(this.module.exports, this.module.exports, childModuleRequire, childLoader, this.module);
} catch(ex) {
if ( !('lineNumber' in ex) ) {
return Promise.reject(ex);
}
var vueFileData = responseText.replace(/\r?\n/g, '\n');
var lineNumber = vueFileData.substr(0, vueFileData.indexOf(script)).split('\n').length + ex.lineNumber - 1;
throw new (ex.constructor)(ex.message, url, lineNumber);
}
return Promise.resolve(this.module.exports)
.then(httpVueLoader.scriptExportsHandler.bind(this))
.then(function(exports) {
this.module.exports = exports;
}.bind(this));
}
};
function ScriptContext(component, elt) {
this.component = component;
this.elt = elt;
this.module = { exports:{} };
}
TemplateContext.prototype = {
getContent: function() {
return this.elt.innerHTML;
},
setContent: function(content) {
this.elt.innerHTML = content;
},
getRootElt: function() {
var tplElt = this.elt.content || this.elt;
if ( 'firstElementChild' in tplElt )
return tplElt.firstElementChild;
for ( tplElt = tplElt.firstChild; tplElt !== null; tplElt = tplElt.nextSibling )
if ( tplElt.nodeType === Node.ELEMENT_NODE )
return tplElt;
return null;
},
compile: function() {
return Promise.resolve();
}
};
function TemplateContext(component, elt) {
this.component = component;
this.elt = elt;
}
Component.prototype = {
getHead: function() {
return document.head || document.getElementsByTagName('head')[0];
},
getScopeId: function() {
if ( this._scopeId === '' ) {
this._scopeId = 'data-s-' + (scopeIndex++).toString(36);
this.template.getRootElt().setAttribute(this._scopeId, '');
}
return this._scopeId;
},
load: function(componentURL) {
return httpVueLoader.httpRequest(componentURL)
.then(function(responseText) {
this.baseURI = componentURL.substr(0, componentURL.lastIndexOf('/')+1);
var doc = document.implementation.createHTMLDocument('');
// IE requires the <base> to come with <style>
doc.body.innerHTML = (this.baseURI ? '<base href="'+this.baseURI+'">' : '') + responseText;
for ( var it = doc.body.firstChild; it; it = it.nextSibling ) {
switch ( it.nodeName ) {
case 'TEMPLATE':
this.template = new TemplateContext(this, it);
break;
case 'SCRIPT':
this.script = new ScriptContext(this, it);
break;
case 'STYLE':
this.styles.push(new StyleContext(this, it));
break;
}
}
return this;
}.bind(this));
},
_normalizeSection: function(eltCx) {
var p;
if ( eltCx === null || !eltCx.elt.hasAttribute('src') ) {
p = Promise.resolve(null);
} else {
p = httpVueLoader.httpRequest(eltCx.elt.getAttribute('src'))
.then(function(content) {
eltCx.elt.removeAttribute('src');
return content;
});
}
return p
.then(function(content) {
if ( eltCx !== null && eltCx.elt.hasAttribute('lang') ) {
var lang = eltCx.elt.getAttribute('lang');
eltCx.elt.removeAttribute('lang');
return httpVueLoader.langProcessor[lang.toLowerCase()].call(this, content === null ? eltCx.getContent() : content);
}
return content;
}.bind(this))
.then(function(content) {
if ( content !== null )
eltCx.setContent(content);
});
},
normalize: function() {
return Promise.all(Array.prototype.concat(
this._normalizeSection(this.template),
this._normalizeSection(this.script),
this.styles.map(this._normalizeSection)
))
.then(function() {
return this;
}.bind(this));
},
compile: function() {
return Promise.all(Array.prototype.concat(
this.template && this.template.compile(),
this.script && this.script.compile(),
this.styles.map(function(style) { return style.compile(); })
))
.then(function() {
return this;
}.bind(this));
}
};
function Component(name) {
this.name = name;
this.template = null;
this.script = null;
this.styles = [];
this._scopeId = '';
}
function identity(value) {
return value;
}
function parseComponentURL(url) {
var comp = url.match(/(.*?)([^/]+?)\/?(\.vue)?(\?.*|#.*|$)/);
return {
name: comp[2],
url: comp[1] + comp[2] + (comp[3] === undefined ? '/index.vue' : comp[3]) + comp[4]
};
}
function resolveURL(baseURL, url) {
if (url.substr(0, 2) === './' || url.substr(0, 3) === '../') {
return baseURL + url;
}
return url;
}
httpVueLoader.load = function(url, name) {
return function() {
return new Component(name).load(url)
.then(function(component) {
return component.normalize();
})
.then(function(component) {
return component.compile();
})
.then(function(component) {
var exports = component.script !== null ? component.script.module.exports : {};
if ( component.template !== null )
exports.template = component.template.getContent();
if ( exports.name === undefined )
if ( component.name !== undefined )
exports.name = component.name;
exports._baseURI = component.baseURI;
return exports;
});
};
};
httpVueLoader.register = function(Vue, url) {
var comp = parseComponentURL(url);
Vue.component(comp.name, httpVueLoader.load(comp.url));
};
httpVueLoader.install = function(Vue) {
Vue.mixin({
beforeCreate: function () {
var components = this.$options.components;
for ( var componentName in components ) {
if ( typeof(components[componentName]) === 'string' && components[componentName].substr(0, 4) === 'url:' ) {
var comp = parseComponentURL(components[componentName].substr(4));
var componentURL = ('_baseURI' in this.$options) ? resolveURL(this.$options._baseURI, comp.url) : comp.url;
if ( isNaN(componentName) )
components[componentName] = httpVueLoader.load(componentURL, componentName);
else
components[componentName] = Vue.component(comp.name, httpVueLoader.load(componentURL, comp.name));
}
}
}
});
};
httpVueLoader.require = function(moduleName) {
return window[moduleName];
};
httpVueLoader.httpRequest = function(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'text';
xhr.onreadystatechange = function() {
if ( xhr.readyState === 4 ) {
if ( xhr.status >= 200 && xhr.status < 300 )
resolve(xhr.responseText);
else
reject(xhr.status);
}
};
xhr.send(null);
});
};
httpVueLoader.langProcessor = {
html: identity,
js: identity,
css: identity
};
httpVueLoader.scriptExportsHandler = identity;
function httpVueLoader(url, name) {
var comp = parseComponentURL(url);
return httpVueLoader.load(comp.url, name);
}
return httpVueLoader;
});
+7 -3
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
@@ -42,11 +42,14 @@
<add key="UseSearchKeywords" value="true" />
<!--網站的簡稱,用來區別session和cookie-->
<add key="SC" value="erp17168" />
<add key="LogPath" value="C:\\log\\" />
<!--是否啟用信眾自動編號 (true=啟用, false=停用)-->
<add key="IsAutoNumbering" value="true" />
</appSettings>
<connectionStrings>
<!--SQL用-->
<add name="shopConn" providerName="System.Data.SqlClient" connectionString="Data Source=192.168.5.21;Initial Catalog=17168erp_t;User ID=sa;Password=linux@mssql1234;Encrypt=False;TrustServerCertificate=True;Provider=SQLOLEDB;Connection Timeout=10;" />
<add name="ezEntities" providerName="System.Data.EntityClient" connectionString="metadata=res://*/App_Code.Model.Model.csdl|res://*/App_Code.Model.Model.ssdl|res://*/App_Code.Model.Model.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=192.168.5.21;Initial Catalog=17168erp_t;User ID=sa;Password=linux@mssql1234;Encrypt=False;TrustServerCertificate=True;Connection Timeout=10;&quot;" />
<add name="shopConn" providerName="System.Data.SqlClient" connectionString="Data Source=192.168.5.225;Initial Catalog=17168erp_c;User ID=sa;Password=linux@mssql1234;Encrypt=False;TrustServerCertificate=True;Provider=SQLOLEDB;Connection Timeout=10;" />
<add name="ezEntities" providerName="System.Data.EntityClient" connectionString="metadata=res://*/App_Code.Model.Model.csdl|res://*/App_Code.Model.Model.ssdl|res://*/App_Code.Model.Model.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=192.168.5.225;Initial Catalog=17168erp_c;User ID=sa;Password=linux@mssql1234;Encrypt=False;TrustServerCertificate=True;Connection Timeout=10;&quot;" />
<!--
-->
<!--SQL用-->
@@ -222,6 +225,7 @@
<urlCompression doStaticCompression="true" doDynamicCompression="true" />
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="777.00:00:00" />
<mimeMap fileExtension=".vue" mimeType="application/javascript"/>
</staticContent>
</system.webServer>
<runtime>
+8
View File
@@ -0,0 +1,8 @@
FK_act_bom_actItem1 刪除規則設為 cascade
FK_pro_order_followers 刪除規則設為 cascade
FK_pro_order_activity 刪除規則設為 cascade
FK_pro_order_detail_pro_order 刪除規則設為 cascade
FK_pro_order_detail_followers 刪除規則設為 沒有動作
FK_activity_relating_activity 刪除規則設為 cascade
actitem 加上 sort_order(int) 欄位