Compare commits
26 Commits
hkj1003
...
d41ad3e4cc
| Author | SHA1 | Date | |
|---|---|---|---|
| d41ad3e4cc | |||
| ba6e641bac | |||
| 9969417bd8 | |||
| eff3ad778b | |||
| bc1f1422e9 | |||
| 1698b51d19 | |||
| 4e26dd648d | |||
| e20b250944 | |||
| e88821db4b | |||
| 3f63457c5a | |||
| 9a0d5ae700 | |||
| 79b7dd114f | |||
| cd05ad2305 | |||
| 5ae262205c | |||
| 6f5a2e65bd | |||
| 22d283dbe6 | |||
| 3b5d366863 | |||
| c0404b8e70 | |||
| 1a6731e4c6 | |||
| 05ef2e28f3 | |||
| 90ef949ca4 | |||
| 39c9dd29e1 | |||
| a6aa35176c | |||
| 6a43883d08 | |||
| 87a2c35300 | |||
| 7d57e292fe |
176
data/SQL/執行此文件.sql
Normal file
176
data/SQL/執行此文件.sql
Normal file
@@ -0,0 +1,176 @@
|
||||
USE [17168erp_t2]
|
||||
GO
|
||||
/****** Object: Table [dbo].[AncestralTabletArea] Script Date: 2025/10/29 下午 01:32:57 ******/
|
||||
SET ANSI_NULLS ON
|
||||
GO
|
||||
SET QUOTED_IDENTIFIER ON
|
||||
GO
|
||||
CREATE TABLE [dbo].[AncestralTabletArea](
|
||||
[AreaId] [int] IDENTITY(1,1) NOT NULL,
|
||||
[AreaName] [nvarchar](10) NOT NULL,
|
||||
[AreaCode] [nvarchar](20) NOT NULL,
|
||||
[ParentAreaId] [int] NULL,
|
||||
[AreaType] [nvarchar](10) NULL,
|
||||
[Price] [int] NULL,
|
||||
[SortOrder] [int] NULL,
|
||||
[IsDisabled] [bit] NOT NULL,
|
||||
[Description] [nvarchar](200) NULL,
|
||||
PRIMARY KEY CLUSTERED
|
||||
(
|
||||
[AreaId] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
GO
|
||||
/****** Object: Table [dbo].[AncestralTabletPosition] Script Date: 2025/10/29 下午 01:32:57 ******/
|
||||
SET ANSI_NULLS ON
|
||||
GO
|
||||
SET QUOTED_IDENTIFIER ON
|
||||
GO
|
||||
CREATE TABLE [dbo].[AncestralTabletPosition](
|
||||
[PositionId] [int] IDENTITY(1,1) NOT NULL,
|
||||
[AreaId] [int] NOT NULL,
|
||||
[PositionCode] [nvarchar](20) NOT NULL,
|
||||
[PositionName] [nvarchar](50) NULL,
|
||||
[Price] [int] NULL,
|
||||
[StatusCode] [nvarchar](20) NULL,
|
||||
[Description] [nvarchar](200) NULL,
|
||||
[RowNo] [int] NULL,
|
||||
[ColumnNo] [int] NULL,
|
||||
PRIMARY KEY CLUSTERED
|
||||
(
|
||||
[PositionId] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY],
|
||||
CONSTRAINT [UQ_Position_Area_Code] UNIQUE NONCLUSTERED
|
||||
(
|
||||
[AreaId] ASC,
|
||||
[PositionCode] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
GO
|
||||
/****** Object: Table [dbo].[AncestralTabletPositionRecord] Script Date: 2025/10/29 下午 01:32:57 ******/
|
||||
SET ANSI_NULLS ON
|
||||
GO
|
||||
SET QUOTED_IDENTIFIER ON
|
||||
GO
|
||||
CREATE TABLE [dbo].[AncestralTabletPositionRecord](
|
||||
[RecordId] [int] IDENTITY(1,1) NOT NULL,
|
||||
[RegistrantCode] [nvarchar](20) NOT NULL,
|
||||
[NPTitle] [nvarchar](30) NULL,
|
||||
[NPStandDate] [date] NOT NULL,
|
||||
[NPYangShang] [nvarchar](20) NULL,
|
||||
[WPContent] [nvarchar](1000) NULL,
|
||||
[CreatedAt] [datetime] NOT NULL,
|
||||
[UpdatedAt] [datetime] NULL,
|
||||
PRIMARY KEY CLUSTERED
|
||||
(
|
||||
[RecordId] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
GO
|
||||
/****** Object: Table [dbo].[AncestralTabletRegistrant] Script Date: 2025/10/29 下午 01:32:57 ******/
|
||||
SET ANSI_NULLS ON
|
||||
GO
|
||||
SET QUOTED_IDENTIFIER ON
|
||||
GO
|
||||
CREATE TABLE [dbo].[AncestralTabletRegistrant](
|
||||
[RegistrantCode] [nvarchar](20) NOT NULL,
|
||||
[Name] [nvarchar](50) NOT NULL,
|
||||
[Phone] [nvarchar](50) NULL,
|
||||
[Address] [nvarchar](60) NULL,
|
||||
[RegisterDate] [date] NOT NULL,
|
||||
[Price] [int] NULL,
|
||||
[PositionId] [int] NULL,
|
||||
[StartDate] [date] NOT NULL,
|
||||
[EndDate] [date] NULL,
|
||||
[IsLongTerm] [bit] NOT NULL,
|
||||
[IsActive] [bit] NOT NULL,
|
||||
[CreatedAt] [datetime] NOT NULL,
|
||||
[UpdatedAt] [datetime] NULL,
|
||||
[IsEnd] [bit] NOT NULL,
|
||||
PRIMARY KEY CLUSTERED
|
||||
(
|
||||
[RegistrantCode] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
GO
|
||||
/****** Object: Table [dbo].[AncestralTabletStatus] Script Date: 2025/10/29 下午 01:32:57 ******/
|
||||
SET ANSI_NULLS ON
|
||||
GO
|
||||
SET QUOTED_IDENTIFIER ON
|
||||
GO
|
||||
CREATE TABLE [dbo].[AncestralTabletStatus](
|
||||
[StatusCode] [nvarchar](20) NOT NULL,
|
||||
[StatusName] [nvarchar](20) NOT NULL,
|
||||
[StatusType] [nvarchar](20) NOT NULL,
|
||||
PRIMARY KEY CLUSTERED
|
||||
(
|
||||
[StatusCode] ASC
|
||||
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
GO
|
||||
ALTER TABLE [dbo].[AncestralTabletArea] ADD DEFAULT ((0)) FOR [IsDisabled]
|
||||
GO
|
||||
ALTER TABLE [dbo].[AncestralTabletPositionRecord] ADD DEFAULT (getdate()) FOR [CreatedAt]
|
||||
GO
|
||||
ALTER TABLE [dbo].[AncestralTabletRegistrant] ADD DEFAULT ((0)) FOR [IsLongTerm]
|
||||
GO
|
||||
ALTER TABLE [dbo].[AncestralTabletRegistrant] ADD DEFAULT ((1)) FOR [IsActive]
|
||||
GO
|
||||
ALTER TABLE [dbo].[AncestralTabletRegistrant] ADD DEFAULT (getdate()) FOR [CreatedAt]
|
||||
GO
|
||||
ALTER TABLE [dbo].[AncestralTabletRegistrant] ADD DEFAULT ((0)) FOR [IsEnd]
|
||||
GO
|
||||
ALTER TABLE [dbo].[AncestralTabletArea] WITH CHECK ADD CONSTRAINT [FK_AncestralTabletArea_Parent] FOREIGN KEY([ParentAreaId])
|
||||
REFERENCES [dbo].[AncestralTabletArea] ([AreaId])
|
||||
GO
|
||||
ALTER TABLE [dbo].[AncestralTabletArea] CHECK CONSTRAINT [FK_AncestralTabletArea_Parent]
|
||||
GO
|
||||
ALTER TABLE [dbo].[AncestralTabletPosition] WITH CHECK ADD CONSTRAINT [FK_Position_Area] FOREIGN KEY([AreaId])
|
||||
REFERENCES [dbo].[AncestralTabletArea] ([AreaId])
|
||||
GO
|
||||
ALTER TABLE [dbo].[AncestralTabletPosition] CHECK CONSTRAINT [FK_Position_Area]
|
||||
GO
|
||||
ALTER TABLE [dbo].[AncestralTabletPosition] WITH CHECK ADD CONSTRAINT [FK_Position_Status] FOREIGN KEY([StatusCode])
|
||||
REFERENCES [dbo].[AncestralTabletStatus] ([StatusCode])
|
||||
GO
|
||||
ALTER TABLE [dbo].[AncestralTabletPosition] CHECK CONSTRAINT [FK_Position_Status]
|
||||
GO
|
||||
ALTER TABLE [dbo].[AncestralTabletPositionRecord] WITH CHECK ADD FOREIGN KEY([RegistrantCode])
|
||||
REFERENCES [dbo].[AncestralTabletRegistrant] ([RegistrantCode])
|
||||
GO
|
||||
ALTER TABLE [dbo].[AncestralTabletRegistrant] WITH CHECK ADD CONSTRAINT [FK_Registrant_Position] FOREIGN KEY([PositionId])
|
||||
REFERENCES [dbo].[AncestralTabletPosition] ([PositionId])
|
||||
GO
|
||||
ALTER TABLE [dbo].[AncestralTabletRegistrant] CHECK CONSTRAINT [FK_Registrant_Position]
|
||||
GO
|
||||
|
||||
INSERT [dbo].[AncestralTabletStatus] ([StatusCode], [StatusName], [StatusType]) VALUES (N'available', N'可用', N'Position')
|
||||
INSERT [dbo].[AncestralTabletStatus] ([StatusCode], [StatusName], [StatusType]) VALUES (N'maintenance', N'維護中', N'Position')
|
||||
INSERT [dbo].[AncestralTabletStatus] ([StatusCode], [StatusName], [StatusType]) VALUES (N'used', N'已使用', N'Position')
|
||||
GO
|
||||
-- 1. 如果不存在 OrderUuid 栏位,则新增
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM sys.columns
|
||||
WHERE Name = N'OrderUuid'
|
||||
AND Object_ID = Object_ID(N'dbo.GuaDanOrderGuest')
|
||||
)
|
||||
BEGIN
|
||||
ALTER TABLE [dbo].[GuaDanOrderGuest]
|
||||
ADD [OrderUuid] UNIQUEIDENTIFIER NULL;
|
||||
END
|
||||
GO
|
||||
|
||||
-- 2. 如果不存在 FK_GuaDanOrderGuest_Order 外键,则新增
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM sys.foreign_keys
|
||||
WHERE Name = N'FK_GuaDanOrderGuest_Order'
|
||||
AND parent_object_id = OBJECT_ID(N'dbo.GuaDanOrderGuest')
|
||||
)
|
||||
BEGIN
|
||||
ALTER TABLE [dbo].[GuaDanOrderGuest]
|
||||
ADD CONSTRAINT [FK_GuaDanOrderGuest_Order]
|
||||
FOREIGN KEY ([OrderUuid]) REFERENCES [dbo].[GuaDanOrder] ([Uuid]);
|
||||
END
|
||||
GO
|
||||
26
data/memo/report-view.md
Normal file
26
data/memo/report-view.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# 報表系統規劃
|
||||
為每場活動(法會)建立報名到舉辦過程的報表,
|
||||
要涵蓋以下面向的統計分析資訊
|
||||
|
||||
- 以單一場法會為核心
|
||||
- 時間面向: 當前狀況, 指定期間狀況
|
||||
- 維度:
|
||||
- 信眾: 報名數量, 金額, 收款狀態
|
||||
- 牌位型態(活動品項表): 報名數量, 金額, 收款狀態
|
||||
- 收款狀態: 己收/未收 統計明細
|
||||
|
||||
## 法會報表系統查詢規劃**
|
||||
|
||||
### 1. 核心基礎 VIEW
|
||||
1. `vw_activity_registration_base` - 單一活動的完整報名基礎資料
|
||||
2. `vw_activity_payment_detail` - 單一活動的完整收款明細資料
|
||||
### 2. 統計分析 VIEW
|
||||
3. `vw_activity_follower_statistics` - 按信眾統計報名情況
|
||||
4. `vw_activity_item_statistics` - 按品項統計報名情況
|
||||
5. `vw_activity_payment_status` - 收款狀態統計分析
|
||||
### 3. 時間維度分析 VIEW
|
||||
6. `vw_activity_registration_trend` - 按日期統計報名趨勢
|
||||
7. `vw_activity_payment_trend` - 按收款日期統計收款趨勢
|
||||
### 4. 詳細查詢 VIEW
|
||||
8. `vw_activity_unpaid_detail` - 未收款明細清單
|
||||
9. `vw_activity_transfer_reconciliation` - 匯款對帳明細
|
||||
252
data/memo/report-view.sql
Normal file
252
data/memo/report-view.sql
Normal file
@@ -0,0 +1,252 @@
|
||||
drop view if exists vw_activity_registration_base;
|
||||
drop view if exists vw_activity_payment_detail;
|
||||
drop view if exists vw_activity_follower_statistics;
|
||||
drop view if exists vw_activity_item_statistics;
|
||||
drop view if exists vw_activity_payment_status;
|
||||
drop view if exists vw_activity_registration_trend;
|
||||
drop view if exists vw_activity_payment_trend;
|
||||
drop view if exists vw_activity_unpaid_detail;
|
||||
drop view if exists vw_activity_transfer_reconciliation;
|
||||
GO
|
||||
-- 1. 法會報名基礎資料 VIEW
|
||||
CREATE VIEW vw_activity_registration_base AS
|
||||
SELECT
|
||||
a.num AS 活動編號,
|
||||
a.subject AS 活動名稱,
|
||||
a.startDate_solar AS 活動開始日期,
|
||||
a.endDate_solar AS 活動結束日期,
|
||||
po.order_no AS 報名單號,
|
||||
po.up_time AS 報名日期,
|
||||
po.keyin1 AS 報名狀態,
|
||||
f.num AS 信眾編號,
|
||||
f.f_number AS 信眾代號,
|
||||
f.u_name AS 信眾姓名,
|
||||
f.phone AS 聯絡電話,
|
||||
f.identity_type AS 身分別,
|
||||
f.country AS 國籍,
|
||||
pod.num AS 報名明細編號,
|
||||
ai.num AS 品項編號,
|
||||
ai.subject AS 品項名稱,
|
||||
ai.category AS 品項分類,
|
||||
pod.price AS 單價,
|
||||
pod.qty AS 數量,
|
||||
pod.price * pod.qty AS 應繳金額,
|
||||
pod.pay AS 已收金額,
|
||||
(pod.price * pod.qty - ISNULL(pod.pay, 0)) AS 未收金額,
|
||||
pod.pay_date AS 付款期限,
|
||||
pod.start_date AS 開始日期,
|
||||
pod.due_date AS 到期日期,
|
||||
pod.keyin1 AS 明細狀態,
|
||||
pod.demo AS 備註
|
||||
FROM activity a
|
||||
INNER JOIN pro_order po ON a.num = po.activity_num
|
||||
INNER JOIN followers f ON po.f_num = f.num
|
||||
INNER JOIN pro_order_detail pod ON po.order_no = pod.order_no
|
||||
INNER JOIN actItem ai ON pod.actItem_num = ai.num;
|
||||
GO
|
||||
|
||||
-- 2. 收款明細基礎資料 VIEW
|
||||
CREATE VIEW vw_activity_payment_detail AS
|
||||
SELECT
|
||||
a.num AS 活動編號,
|
||||
a.subject AS 活動名稱,
|
||||
po.order_no AS 報名單號,
|
||||
f.u_name AS 信眾姓名,
|
||||
pod.num AS 報名明細編號,
|
||||
ai.subject AS 品項名稱,
|
||||
por.num AS 收款記錄編號,
|
||||
por.price AS 收款金額,
|
||||
por.payment AS 付款方式,
|
||||
por.pay_date AS 收款日期,
|
||||
por.organization AS 收款機構,
|
||||
por.bank_code AS 銀行代碼,
|
||||
por.transfer_id AS 匯款記錄ID,
|
||||
por.reconcile_memo AS 對帳備註,
|
||||
tr.name AS 匯款人姓名,
|
||||
tr.phone AS 匯款人電話,
|
||||
tr.amount AS 匯款金額,
|
||||
tr.check_date AS 入帳日期,
|
||||
tr.status AS 匯款狀態
|
||||
FROM activity a
|
||||
INNER JOIN pro_order po ON a.num = po.activity_num
|
||||
INNER JOIN followers f ON po.f_num = f.num
|
||||
INNER JOIN pro_order_detail pod ON po.order_no = pod.order_no
|
||||
INNER JOIN actItem ai ON pod.actItem_num = ai.num
|
||||
LEFT JOIN pro_order_record por ON pod.num = por.detail_num
|
||||
LEFT JOIN transfer_register tr ON por.transfer_id = tr.id;
|
||||
GO
|
||||
|
||||
-- 3. 信眾報名統計 VIEW
|
||||
CREATE VIEW vw_activity_follower_statistics AS
|
||||
SELECT
|
||||
活動編號,
|
||||
活動名稱,
|
||||
信眾編號,
|
||||
信眾代號,
|
||||
信眾姓名,
|
||||
聯絡電話,
|
||||
身分別,
|
||||
國籍,
|
||||
COUNT(DISTINCT 報名單號) AS 報名單數,
|
||||
COUNT(報名明細編號) AS 報名品項數,
|
||||
SUM(應繳金額) AS 應繳總金額,
|
||||
SUM(已收金額) AS 已收總金額,
|
||||
SUM(未收金額) AS 未收總金額,
|
||||
CASE
|
||||
WHEN SUM(未收金額) = 0 THEN '已繳清'
|
||||
WHEN SUM(未收金額) = SUM(應繳金額) THEN '未繳'
|
||||
ELSE '部分繳款'
|
||||
END AS 繳款狀態
|
||||
FROM vw_activity_registration_base
|
||||
GROUP BY 活動編號, 活動名稱, 信眾編號, 信眾代號, 信眾姓名, 聯絡電話, 身分別, 國籍;
|
||||
GO
|
||||
|
||||
-- 4. 品項報名統計 VIEW
|
||||
CREATE VIEW vw_activity_item_statistics AS
|
||||
SELECT
|
||||
活動編號,
|
||||
活動名稱,
|
||||
品項編號,
|
||||
品項名稱,
|
||||
品項分類,
|
||||
單價,
|
||||
COUNT(報名明細編號) AS 報名數量,
|
||||
SUM(數量) AS 總數量,
|
||||
SUM(應繳金額) AS 應繳總金額,
|
||||
SUM(已收金額) AS 已收總金額,
|
||||
SUM(未收金額) AS 未收總金額,
|
||||
CASE
|
||||
WHEN COUNT(報名明細編號) = 0 THEN 0
|
||||
ELSE AVG(已收金額)
|
||||
END AS 平均已收金額,
|
||||
CASE
|
||||
WHEN SUM(未收金額) = 0 THEN '已收齊'
|
||||
WHEN SUM(未收金額) = SUM(應繳金額) THEN '未收款'
|
||||
ELSE '部分收款'
|
||||
END AS 收款狀態
|
||||
FROM vw_activity_registration_base
|
||||
GROUP BY 活動編號, 活動名稱, 品項編號, 品項名稱, 品項分類, 單價;
|
||||
GO
|
||||
|
||||
-- 5. 收款狀態統計 VIEW
|
||||
CREATE VIEW vw_activity_payment_status AS
|
||||
SELECT
|
||||
活動編號,
|
||||
活動名稱,
|
||||
'總計' AS 統計項目,
|
||||
COUNT(DISTINCT 報名單號) AS 報名單數,
|
||||
COUNT(報名明細編號) AS 報名品項數,
|
||||
SUM(應繳金額) AS 應繳總金額,
|
||||
SUM(已收金額) AS 已收總金額,
|
||||
SUM(未收金額) AS 未收總金額,
|
||||
CASE
|
||||
WHEN SUM(應繳金額) = 0 THEN 0
|
||||
ELSE ROUND(SUM(已收金額) * 100.0 / SUM(應繳金額), 2)
|
||||
END AS 收款率
|
||||
FROM vw_activity_registration_base
|
||||
GROUP BY 活動編號, 活動名稱
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
活動編號,
|
||||
活動名稱,
|
||||
CASE
|
||||
WHEN 未收金額 = 0 THEN '已繳清'
|
||||
WHEN 未收金額 = 應繳金額 THEN '未繳'
|
||||
ELSE '部分繳款'
|
||||
END AS 統計項目,
|
||||
COUNT(DISTINCT 報名單號) AS 報名單數,
|
||||
COUNT(報名明細編號) AS 報名品項數,
|
||||
SUM(應繳金額) AS 應繳總金額,
|
||||
SUM(已收金額) AS 已收總金額,
|
||||
SUM(未收金額) AS 未收總金額,
|
||||
CASE
|
||||
WHEN SUM(應繳金額) = 0 THEN 0
|
||||
ELSE ROUND(SUM(已收金額) * 100.0 / SUM(應繳金額), 2)
|
||||
END AS 收款率
|
||||
FROM vw_activity_registration_base
|
||||
GROUP BY 活動編號, 活動名稱,
|
||||
CASE
|
||||
WHEN 未收金額 = 0 THEN '已繳清'
|
||||
WHEN 未收金額 = 應繳金額 THEN '未繳'
|
||||
ELSE '部分繳款'
|
||||
END;
|
||||
GO
|
||||
|
||||
-- 6. 報名趨勢分析 VIEW
|
||||
CREATE VIEW vw_activity_registration_trend AS
|
||||
SELECT
|
||||
活動編號,
|
||||
活動名稱,
|
||||
CAST(報名日期 AS DATE) AS 報名日期,
|
||||
COUNT(DISTINCT 報名單號) AS 當日報名單數,
|
||||
COUNT(報名明細編號) AS 當日報名品項數,
|
||||
SUM(應繳金額) AS 當日應繳金額,
|
||||
SUM(已收金額) AS 當日已收金額,
|
||||
SUM(未收金額) AS 當日未收金額
|
||||
FROM vw_activity_registration_base
|
||||
GROUP BY 活動編號, 活動名稱, CAST(報名日期 AS DATE);
|
||||
GO
|
||||
|
||||
-- 7. 收款趨勢分析 VIEW
|
||||
CREATE VIEW vw_activity_payment_trend AS
|
||||
SELECT
|
||||
活動編號,
|
||||
活動名稱,
|
||||
CAST(收款日期 AS DATE) AS 收款日期,
|
||||
COUNT(收款記錄編號) AS 當日收款筆數,
|
||||
SUM(收款金額) AS 當日收款金額,
|
||||
COUNT(DISTINCT 報名單號) AS 當日收款單數,
|
||||
CASE
|
||||
WHEN COUNT(收款記錄編號) = 0 THEN 0
|
||||
ELSE AVG(收款金額)
|
||||
END AS 平均收款金額
|
||||
FROM vw_activity_payment_detail
|
||||
WHERE 收款日期 IS NOT NULL
|
||||
GROUP BY 活動編號, 活動名稱, CAST(收款日期 AS DATE);
|
||||
GO
|
||||
|
||||
-- 8. 未收款明細 VIEW
|
||||
CREATE VIEW vw_activity_unpaid_detail AS
|
||||
SELECT
|
||||
活動編號,
|
||||
活動名稱,
|
||||
報名單號,
|
||||
信眾姓名,
|
||||
聯絡電話,
|
||||
品項名稱,
|
||||
應繳金額,
|
||||
已收金額,
|
||||
未收金額,
|
||||
付款期限,
|
||||
CASE
|
||||
WHEN 付款期限 < GETDATE() THEN '已逾期'
|
||||
WHEN 付款期限 <= DATEADD(DAY, 3, GETDATE()) THEN '即將到期'
|
||||
ELSE '未到期'
|
||||
END AS 到期狀態
|
||||
FROM vw_activity_registration_base
|
||||
WHERE 未收金額 > 0;
|
||||
GO
|
||||
|
||||
-- 9. 匯款對帳明細 VIEW
|
||||
CREATE VIEW vw_activity_transfer_reconciliation AS
|
||||
SELECT
|
||||
活動編號,
|
||||
活動名稱,
|
||||
匯款記錄ID,
|
||||
匯款人姓名,
|
||||
匯款人電話,
|
||||
匯款金額,
|
||||
入帳日期,
|
||||
匯款狀態,
|
||||
COUNT(收款記錄編號) AS 關聯收款筆數,
|
||||
SUM(收款金額) AS 已對帳金額,
|
||||
CASE
|
||||
WHEN SUM(收款金額) IS NULL THEN 匯款金額
|
||||
ELSE 匯款金額 - SUM(收款金額)
|
||||
END AS 剩餘金額
|
||||
FROM vw_activity_payment_detail
|
||||
WHERE 匯款記錄ID IS NOT NULL
|
||||
GROUP BY 活動編號, 活動名稱, 匯款記錄ID, 匯款人姓名, 匯款人電話, 匯款金額, 入帳日期, 匯款狀態;
|
||||
GO
|
||||
484
data/memo/report.md
Normal file
484
data/memo/report.md
Normal file
@@ -0,0 +1,484 @@
|
||||
# 相關頁面
|
||||
## 基本功能
|
||||
admin/order/index.aspx
|
||||
admin/activity/index.aspx
|
||||
admin/follower/index.aspx
|
||||
admin/activity/index2.aspx
|
||||
admin/transfer/index.aspx
|
||||
|
||||
## 入帳沖帳
|
||||
D:\dev\ez\17168erp\git_17888\web\admin\transfer\balance_reconcile_query.aspx
|
||||
D:\dev\ez\17168erp\git_17888\web\admin\transfer\balance_reconcile.aspx
|
||||
D:\dev\ez\17168erp\git_17888\web\admin\transfer\group_reconcile.aspx
|
||||
D:\dev\ez\17168erp\git_17888\web\admin\transfer\index.aspx
|
||||
D:\dev\ez\17168erp\git_17888\web\admin\transfer\personal_reconcile.aspx
|
||||
D:\dev\ez\17168erp\git_17888\web\admin\transfer\register.aspx
|
||||
D:\dev\ez\17168erp\git_17888\web\admin\transfer\verify_order_record_query.aspx
|
||||
D:\dev\ez\17168erp\git_17888\web\admin\transfer\verify.aspx
|
||||
D:\dev\ez\17168erp\git_17888\web\admin\transfer\verify1.aspx
|
||||
D:\dev\ez\17168erp\git_17888\web\admin\transfer\verify2.aspx
|
||||
|
||||
# 資料結構
|
||||
|
||||
## 📊 17168ERP 系統使用的資料表架構
|
||||
|
||||
### 🎯 **核心業務資料表**
|
||||
|
||||
#### 1. **報名管理系統** (`order/index.aspx`)
|
||||
**主要資料表:**
|
||||
- **`pro_order`** - 報名主表
|
||||
- `order_no` (單號)、`up_time` (報名日期)、`keyin1` (單據狀態)
|
||||
- `f_num` (信眾編號)、`activity_num` (活動編號)、`phone` (聯絡電話)
|
||||
|
||||
- **`pro_order_detail`** - 報名明細表
|
||||
- `order_no` (關聯主表)、`actItem_num` (活動品項)、`f_num` (報名者)
|
||||
- `price` (金額)、`qty` (數量)、`pay` (已收金額)、`pay_date` (付款期限)
|
||||
|
||||
- **`activity`** - 活動主表
|
||||
- `num`、`subject` (活動名稱)、`start_date` (開始日期)、`end_date` (結束日期)
|
||||
|
||||
- **`actItem`** - 活動品項表
|
||||
- `num`、`subject` (品項名稱)、`category` (品項分類)
|
||||
|
||||
#### 2. **信眾管理系統** (`follower/index.aspx`)
|
||||
**主要資料表:**
|
||||
- **`followers`** - 信眾基本資料表
|
||||
- `num`、`f_number` (信眾編號)、`u_name` (姓名)、`sex` (性別)
|
||||
- `identity_type` (身分別)、`birthday` (生日)、`phone` (電話)
|
||||
- `address` (地址)、`country` (國籍)、`refugedate` (皈依日期)
|
||||
|
||||
- **`countries`** - 國籍資料表
|
||||
- `ID`、`name_zh` (中文名稱)、`name_en` (英文名稱)
|
||||
|
||||
#### 3. **活動管理系統** (`activity/index.aspx`)
|
||||
**主要資料表:**
|
||||
- **`activity`** - 活動主表
|
||||
- `num`、`subject` (活動名稱)、`startDate_solar` (國曆開始日期)
|
||||
- `startDate_lunar` (農曆開始日期)、`endDate_solar` (國曆結束日期)
|
||||
- `endDate_lunar` (農曆結束日期)、`dueDate` (報名截止日期)
|
||||
|
||||
- **`activity_kind`** - 活動分類表
|
||||
- `num`、`subject` (分類名稱)
|
||||
|
||||
#### 4. **匯款沖帳系統** (`transfer/index.aspx`)
|
||||
**主要資料表:**
|
||||
- **`transfer_register`** - 匯款登錄表
|
||||
- `id`、`name` (匯款人姓名)、`phone` (電話)、`amount` (匯款金額)
|
||||
- `pay_type` (付款方式)、`account_last5` (帳號後五碼)
|
||||
- `proof_img` (匯款證明圖片)、`status` (狀態)
|
||||
- `f_num_match` (配對信眾編號)、`check_amount` (核對金額)
|
||||
|
||||
- **`accounting`** - 會計帳務表
|
||||
- `num`、`category` (科目分類)、`kind` (收支類型)
|
||||
- `price` (金額)、`debtor` (債務人)、`activity_num` (關聯活動)
|
||||
|
||||
- **`pro_order_record`** - 報名收款記錄表
|
||||
- `num`、`detail_num` (關聯明細)、`price` (金額)、`payment` (付款方式)
|
||||
- `pay_date` (收款日期)、`transfer_id` (關聯匯款記錄)
|
||||
|
||||
### 🔗 **關聯關係**
|
||||
|
||||
#### **主要外鍵關聯:**
|
||||
```
|
||||
pro_order → followers (f_num)
|
||||
pro_order → activity (activity_num)
|
||||
pro_order_detail → pro_order (order_no)
|
||||
pro_order_detail → actItem (actItem_num)
|
||||
pro_order_detail → followers (f_num)
|
||||
transfer_register → followers (f_num)
|
||||
transfer_register → activity (activity_num)
|
||||
accounting → pro_order_detail (pro_order_detail_num)
|
||||
```
|
||||
|
||||
### 📈 **資料表統計**
|
||||
|
||||
| 功能模組 | 主要資料表數量 | 核心業務表 |
|
||||
|---------|-------------|-----------|
|
||||
| 報名管理 | 5個 | `pro_order`, `pro_order_detail` |
|
||||
| 信眾管理 | 2個 | `followers`, `countries` |
|
||||
| 活動管理 | 2個 | `activity`, `activity_kind` |
|
||||
| 匯款沖帳 | 3個 | `transfer_register`, `accounting`, `pro_order_record` |
|
||||
|
||||
### 🎯 **系統特色**
|
||||
|
||||
1. **模組化設計**:每個功能模組都有獨立的資料表群組
|
||||
2. **關聯完整**:透過外鍵建立完整的業務關聯關係
|
||||
3. **狀態管理**:多個狀態表支援複雜的業務流程
|
||||
4. **UUID設計**:新模組採用UUID作為主鍵,提升擴展性
|
||||
5. **軟刪除機制**:使用`IsDeleted`欄位而非物理刪除
|
||||
|
||||
這個資料表架構支援了一個完整的宗教活動管理ERP系統,涵蓋了從信眾管理、活動報名、床位安排到財務沖帳的全流程管理。
|
||||
|
||||
# 入帳沖帳
|
||||
```
|
||||
報名者匯款 → transfer_register (status: pending)
|
||||
↓
|
||||
出納核對身份 → transfer_register (status: verified, f_num_match)
|
||||
↓
|
||||
出納核對金額 → transfer_register (status: confirmed, check_amount)
|
||||
↓
|
||||
會計個人沖帳 → pro_order_record + accounting
|
||||
↓
|
||||
會計共同沖帳 → pro_order_record + accounting (多筆)
|
||||
↓
|
||||
會計餘額核銷 → transfer_register (remain_amount)
|
||||
↓
|
||||
查詢統計報表 → 各表關聯查詢
|
||||
```
|
||||
|
||||
# DB SCHEMA
|
||||
我來為您使用 Mermaid 語法繪製 17168ERP 系統的 ER 圖,展示各個資料表之間的關聯關係。
|
||||
|
||||
|
||||
[1 tool called]
|
||||
|
||||
我無法直接創建 Mermaid 圖表,但我可以為您提供完整的 Mermaid ER 圖代碼,您可以複製到支援 Mermaid 的工具中查看(如 GitHub、GitLab、或 Mermaid Live Editor)。
|
||||
|
||||
以下是 17168ERP 系統的 ER 圖 Mermaid 代碼:
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
%% 信眾管理系統
|
||||
followers {
|
||||
int num PK
|
||||
string f_number
|
||||
string u_name
|
||||
string sex
|
||||
int identity_type
|
||||
datetime birthday
|
||||
string phone
|
||||
string email
|
||||
datetime refugedate
|
||||
string refuge_name
|
||||
string address
|
||||
string demo
|
||||
int leader
|
||||
string socialid1
|
||||
string socialid2
|
||||
string tab
|
||||
string contactor
|
||||
string contactor_phone
|
||||
string blood
|
||||
string customize_data
|
||||
}
|
||||
|
||||
countries {
|
||||
int ID PK
|
||||
string name_zh
|
||||
string name_en
|
||||
string range
|
||||
}
|
||||
|
||||
%% 活動管理系統
|
||||
activity {
|
||||
int num PK
|
||||
string subject
|
||||
datetime startDate_solar
|
||||
datetime startDate_lunar
|
||||
datetime endDate_solar
|
||||
datetime endDate_lunar
|
||||
datetime dueDate
|
||||
int kind
|
||||
string demo
|
||||
string customize_data
|
||||
}
|
||||
|
||||
activity_kind {
|
||||
int num PK
|
||||
string subject
|
||||
string demo
|
||||
}
|
||||
|
||||
actItem {
|
||||
int num PK
|
||||
int activity_num FK
|
||||
string subject
|
||||
int category
|
||||
string demo
|
||||
string customize_data
|
||||
}
|
||||
|
||||
%% 報名管理系統
|
||||
pro_order {
|
||||
string order_no PK
|
||||
datetime up_time
|
||||
datetime reg_time
|
||||
string keyin1
|
||||
int f_num FK
|
||||
string phone
|
||||
int activity_num FK
|
||||
string address
|
||||
string demo
|
||||
string customize_data
|
||||
int introducer FK
|
||||
boolean send_receipt
|
||||
string receipt_title
|
||||
}
|
||||
|
||||
pro_order_detail {
|
||||
int num PK
|
||||
string order_no FK
|
||||
int actItem_num FK
|
||||
int f_num FK
|
||||
string f_num_tablet
|
||||
string address
|
||||
int from_id FK
|
||||
string from_id_tablet
|
||||
datetime due_date
|
||||
int bed_type
|
||||
float price
|
||||
int qty
|
||||
datetime start_date
|
||||
datetime extend_date
|
||||
float pay
|
||||
datetime pay_date
|
||||
int keyin1
|
||||
string demo
|
||||
datetime UpdateTime
|
||||
}
|
||||
|
||||
%% 匯款沖帳系統
|
||||
transfer_register {
|
||||
int id PK
|
||||
int activity_num FK
|
||||
string name
|
||||
string phone
|
||||
string pay_type
|
||||
string account_last5
|
||||
decimal amount
|
||||
string pay_mode
|
||||
string note
|
||||
string proof_img
|
||||
string status
|
||||
datetime create_time
|
||||
int f_num_match FK
|
||||
int f_num FK
|
||||
int acc_num
|
||||
datetime check_date
|
||||
decimal check_amount
|
||||
string check_memo
|
||||
string check_status
|
||||
int acc_kind
|
||||
int member_num
|
||||
datetime verify_time
|
||||
string verify_note
|
||||
string draft
|
||||
decimal remain_amount
|
||||
int balance_act_item FK
|
||||
int balance_pro_order_detail FK
|
||||
}
|
||||
|
||||
accounting {
|
||||
int num PK
|
||||
datetime uptime
|
||||
int category
|
||||
int kind
|
||||
int kind2
|
||||
float price
|
||||
float tax
|
||||
string demo
|
||||
int mem_num
|
||||
string debtor
|
||||
int activity_num FK
|
||||
string excerpt
|
||||
datetime reg_time
|
||||
int pro_order_detail_num FK
|
||||
}
|
||||
|
||||
pro_order_record {
|
||||
int num PK
|
||||
int detail_num FK
|
||||
float price
|
||||
int payment
|
||||
datetime reg_time
|
||||
datetime pay_date
|
||||
string organization
|
||||
string bank_code
|
||||
int transfer_id FK
|
||||
string reconcile_memo
|
||||
}
|
||||
|
||||
%% 區域床位管理系統
|
||||
Region {
|
||||
Guid Uuid PK
|
||||
string Name
|
||||
boolean Gender
|
||||
boolean IsActive
|
||||
boolean IsDeleted
|
||||
}
|
||||
|
||||
Room {
|
||||
Guid Uuid PK
|
||||
string Name
|
||||
boolean Gender
|
||||
int BedCount
|
||||
boolean IsActive
|
||||
datetime CreatedAt
|
||||
datetime UpdatedAt
|
||||
boolean IsDeleted
|
||||
Guid RegionUuid FK
|
||||
}
|
||||
|
||||
RegionRoomBed {
|
||||
Guid Uuid PK
|
||||
string Name
|
||||
boolean IsActive
|
||||
boolean Gender
|
||||
boolean IsDeleted
|
||||
Guid RoomUuid FK
|
||||
string StatusCode FK
|
||||
}
|
||||
|
||||
RegionRoomBedStatus {
|
||||
string Code PK
|
||||
string Name
|
||||
string Description
|
||||
int Category
|
||||
boolean IsDeleted
|
||||
}
|
||||
|
||||
%% 掛單管理系統
|
||||
GuaDanOrder {
|
||||
Guid Uuid PK
|
||||
datetime StartDate
|
||||
datetime EndDate
|
||||
int CreateUser FK
|
||||
datetime CreatedAt
|
||||
datetime UpdatedAt
|
||||
string Notes
|
||||
string GuaDanOrderNo
|
||||
int BookerFollowerNum FK
|
||||
string BookerName
|
||||
string BookerPhone
|
||||
boolean IsDeleted
|
||||
int ActivityNum FK
|
||||
boolean IsCancel
|
||||
}
|
||||
|
||||
GuaDanOrderGuest {
|
||||
Guid Uuid PK
|
||||
string GuaDanOrderNo FK
|
||||
int FollowerNum FK
|
||||
boolean IsDeleted
|
||||
Guid RoomUuid FK
|
||||
Guid BedUuid FK
|
||||
datetime CheckInAt
|
||||
datetime CheckOutAt
|
||||
string StatusCode FK
|
||||
}
|
||||
|
||||
RegionAndRoomAndBedSchedule {
|
||||
Guid Uuid PK
|
||||
Guid TargetUuid FK
|
||||
string GuaDanOrderNo
|
||||
date ScheduleDate
|
||||
boolean IsCancel
|
||||
boolean IsDeleted
|
||||
int UseType
|
||||
string Title
|
||||
string Description
|
||||
string CreatedBy
|
||||
datetime CreatedAt
|
||||
Guid GuaDanOrderGuestUuid FK
|
||||
}
|
||||
|
||||
%% 關聯關係
|
||||
followers ||--o{ pro_order : "報名"
|
||||
followers ||--o{ pro_order_detail : "報名明細"
|
||||
followers ||--o{ transfer_register : "匯款人"
|
||||
followers ||--o{ GuaDanOrderGuest : "掛單客人"
|
||||
|
||||
activity ||--o{ pro_order : "活動報名"
|
||||
activity ||--o{ actItem : "活動品項"
|
||||
activity ||--o{ transfer_register : "活動匯款"
|
||||
activity ||--o{ GuaDanOrder : "掛單活動"
|
||||
|
||||
pro_order ||--o{ pro_order_detail : "報名明細"
|
||||
pro_order ||--o{ pro_order_record : "收款記錄"
|
||||
|
||||
pro_order_detail ||--o{ pro_order_record : "明細收款"
|
||||
pro_order_detail ||--o{ accounting : "會計分錄"
|
||||
pro_order_detail ||--o{ transfer_register : "沖帳明細"
|
||||
|
||||
transfer_register ||--o{ pro_order_record : "匯款記錄"
|
||||
transfer_register ||--o{ accounting : "會計記錄"
|
||||
|
||||
Region ||--o{ Room : "區域房間"
|
||||
Room ||--o{ RegionRoomBed : "房間床位"
|
||||
RegionRoomBedStatus ||--o{ RegionRoomBed : "床位狀態"
|
||||
RegionRoomBedStatus ||--o{ GuaDanOrderGuest : "客人狀態"
|
||||
|
||||
GuaDanOrder ||--o{ GuaDanOrderGuest : "掛單客人"
|
||||
GuaDanOrderGuest ||--o{ RegionAndRoomAndBedSchedule : "床位排程"
|
||||
|
||||
countries ||--o{ followers : "國籍"
|
||||
activity_kind ||--o{ activity : "活動分類"
|
||||
```
|
||||
|
||||
## 📊 **ER 圖說明**
|
||||
|
||||
### **主要實體群組:**
|
||||
|
||||
1. **信眾管理群組**
|
||||
- `followers` (信眾基本資料)
|
||||
- `countries` (國籍資料)
|
||||
|
||||
2. **活動管理群組**
|
||||
- `activity` (活動主表)
|
||||
- `activity_kind` (活動分類)
|
||||
- `actItem` (活動品項)
|
||||
|
||||
3. **報名管理群組**
|
||||
- `pro_order` (報名主表)
|
||||
- `pro_order_detail` (報名明細)
|
||||
|
||||
4. **財務管理群組**
|
||||
- `transfer_register` (匯款登錄)
|
||||
- `accounting` (會計帳務)
|
||||
- `pro_order_record` (收款記錄)
|
||||
|
||||
5. **床位管理群組**
|
||||
- `Region` (區域)
|
||||
- `Room` (房間)
|
||||
- `RegionRoomBed` (床位)
|
||||
- `RegionRoomBedStatus` (床位狀態)
|
||||
|
||||
6. **掛單管理群組**
|
||||
- `GuaDanOrder` (掛單主表)
|
||||
- `GuaDanOrderGuest` (掛單客人)
|
||||
- `RegionAndRoomAndBedSchedule` (床位排程)
|
||||
|
||||
### **關鍵關聯關係:**
|
||||
|
||||
- **一對多關係**:使用 `||--o{` 表示
|
||||
- **外鍵關聯**:FK 標記顯示主要的外鍵關聯
|
||||
- **業務流程**:從信眾報名 → 匯款 → 沖帳 → 床位安排的完整流程
|
||||
|
||||
您可以将這個 Mermaid 代碼複製到 [Mermaid Live Editor](https://mermaid.live/) 或其他支援 Mermaid 的工具中查看完整的 ER 圖表。
|
||||
|
||||
---
|
||||
# 報表系統規劃
|
||||
為每場活動(法會)建立報名到舉辦過程的報表,
|
||||
要涵蓋以下面向的統計分析資訊
|
||||
|
||||
- 以單一場法會為核心
|
||||
- 時間面向: 當前狀況, 指定期間狀況
|
||||
- 維度:
|
||||
- 信眾: 報名數量, 金額, 收款狀態
|
||||
- 牌位型態(活動品項表): 報名數量, 金額, 收款狀態
|
||||
- 收款狀態: 己收/未收 統計明細
|
||||
|
||||
## 執行方式:
|
||||
- 類似excel, 詳細資料->pivot table
|
||||
- 先建立一個(或數個)最核心的sql view, 包含各項:報名資料, 收款明細
|
||||
- 先以單一活動編號為固定FILTER : activity.num=59
|
||||
- 再依不同面向, 建立第二級的sql view
|
||||
- 再人工將以上:第一, 第二級的SQL VIEW, 以EXCEL查詢, 做資料分析/整理
|
||||
- 相關英文欄名, 在VIEW中以中文別名顯示
|
||||
|
||||
## 相關SQL VIEW
|
||||
- (查詢清單)
|
||||
### (查詢)
|
||||
(說明)
|
||||
```sql
|
||||
```
|
||||
BIN
data/查詢範例.xlsx
Normal file
BIN
data/查詢範例.xlsx
Normal file
Binary file not shown.
12
review_report.txt
Normal file
12
review_report.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
═══════════════════════════════════════════════════════════════
|
||||
🔍 AsEnumerable/AsQueryable/ToList 完整 REVIEW
|
||||
═══════════════════════════════════════════════════════════════
|
||||
|
||||
檢查範圍:Batch 1-3 所有已修改文件
|
||||
檢查標準:
|
||||
✅ 最佳選擇 - 性能和可讀性都最優
|
||||
⚠️ 可優化 - 可以進一步優化
|
||||
❌ 需修正 - 存在明顯問題
|
||||
|
||||
═══════════════════════════════════════════════════════════════
|
||||
|
||||
1
tyme4net/tyme4net
Submodule
1
tyme4net/tyme4net
Submodule
Submodule tyme4net/tyme4net added at 9ee8f71dac
19
web/App_Code/Model/Partial/family_members.cs
Normal file
19
web/App_Code/Model/Partial/family_members.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
/// <summary>
|
||||
/// added
|
||||
/// </summary>
|
||||
namespace Model
|
||||
{
|
||||
[MetadataType(typeof(family_membersMetadata))]
|
||||
public partial class family_members
|
||||
{
|
||||
private class family_membersMetadata
|
||||
{
|
||||
[JsonIgnore]
|
||||
public virtual follower follower { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,19 @@ namespace Model
|
||||
public virtual ICollection<followers_tablet> followers_tablet { get; set; }
|
||||
[JsonIgnore]
|
||||
public virtual appellation appellation { get; set; }
|
||||
/// <summary>
|
||||
/// added
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public virtual ICollection<family_members> family_members { get; set; }
|
||||
[JsonIgnore]
|
||||
public virtual ICollection<transfer_register> transfer_register { get; set; }
|
||||
[JsonIgnore]
|
||||
public virtual ICollection<transfer_register> transfer_register1 { get; set; }
|
||||
[JsonIgnore]
|
||||
public virtual ICollection<GuaDanOrder> GuaDanOrder { get; set; }
|
||||
[JsonIgnore]
|
||||
public virtual ICollection<GuaDanOrderGuest> GuaDanOrderGuest { get; set; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,73 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Data;
|
||||
using System.Configuration;
|
||||
using System.Collections;
|
||||
using Newtonsoft.Json;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Web.UI;
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Net.Mail;
|
||||
using System.Configuration;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using System.Web.UI.WebControls;
|
||||
using System.Data.OleDb;
|
||||
using Microsoft.VisualBasic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web.Security;
|
||||
using System.Security.Cryptography;
|
||||
using System.Web.UI;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.Design;
|
||||
using System.ComponentModel.Design.Serialization;
|
||||
using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Data.OleDb;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Mail;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using System.Web.Caching;
|
||||
using System.Web.ModelBinding;
|
||||
using System.Web.Routing;
|
||||
using System.Web.Security;
|
||||
using System.Web.SessionState;
|
||||
using System.Web.UI;
|
||||
using System.Web.UI.Adapters;
|
||||
using System.Web.UI.HtmlControls;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Collections;
|
||||
using System.Data;
|
||||
using System.Data.OleDb;
|
||||
using System.Configuration;
|
||||
using System.Web.UI;
|
||||
using System.Web.UI.WebControls;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.ComponentModel;
|
||||
using System.Web.UI.WebControls;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
|
||||
namespace Model.ViewModel
|
||||
|
||||
@@ -52,7 +52,7 @@ public class FilesSetController : ApiController
|
||||
// DELETE api/<controller>/5
|
||||
public void Delete(int id)
|
||||
{
|
||||
var prod = _db.files.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.files.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
//var prod2 = _db.actItem_files.AsEnumerable().Where(q => q.files_num == id).ToList(); //刪除品項的相關文件
|
||||
@@ -84,14 +84,14 @@ public class FilesSetController : ApiController
|
||||
{
|
||||
if (!string.IsNullOrEmpty(nums))
|
||||
{
|
||||
var ids = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s));
|
||||
var ids = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s)).ToList();
|
||||
|
||||
var prod = _db.files.AsEnumerable().Where(q => ids.Contains(q.num)).ToList();
|
||||
var prod = _db.files.Where(q => ids.Contains(q.num)).ToList();
|
||||
if (prod.Count() > 0)
|
||||
{
|
||||
//刪除品項的相關文件
|
||||
var prod2 = _db.actItem_files.AsEnumerable().Where(q => ids.Contains(Convert.ToInt32(q.files_num))).ToList();
|
||||
if (prod2.Count > 0)
|
||||
var prod2 = _db.actItem_files.Where(q => ids.Contains(q.files_num)).ToList();
|
||||
if (prod2.Count() > 0)
|
||||
{
|
||||
_db.actItem_files.RemoveRange(prod2);
|
||||
}
|
||||
@@ -123,7 +123,7 @@ public class FilesSetController : ApiController
|
||||
public IHttpActionResult GetList([FromBody] Model.ViewModel.files q, int page, int pageSize = 10,
|
||||
string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.files.AsEnumerable();
|
||||
var qry = _db.files.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(q.subject))
|
||||
qry = qry.Where(o => o.subject.Contains(q.subject));
|
||||
@@ -157,9 +157,12 @@ public class FilesSetController : ApiController
|
||||
else
|
||||
qry = qry.OrderByDescending(o => o.num);
|
||||
|
||||
var count = qry.Count();
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
|
||||
var ret = new
|
||||
{
|
||||
list = qry.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
num = x.num,
|
||||
subject = x.subject,
|
||||
@@ -168,7 +171,7 @@ public class FilesSetController : ApiController
|
||||
word = x.word,
|
||||
|
||||
}),
|
||||
count = qry.Count()
|
||||
count = count
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ public class FollowerController : ApiController
|
||||
// DELETE api/<controller>/5
|
||||
public void Delete(int id)
|
||||
{
|
||||
var prod = _db.followers.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.followers.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
/*if (prod != null)
|
||||
{
|
||||
|
||||
@@ -94,9 +94,9 @@ public class FollowerController : ApiController
|
||||
{
|
||||
if (!string.IsNullOrEmpty(nums))
|
||||
{
|
||||
var getDelItem = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s));
|
||||
var getDelItem = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s)).ToList();
|
||||
|
||||
var prod = _db.followers.AsEnumerable().Where(q => getDelItem.Contains(q.num)).ToList();
|
||||
var prod = _db.followers.Where(q => getDelItem.Contains(q.num)).ToList();
|
||||
if (prod.Count() > 0)
|
||||
{
|
||||
foreach (var item in prod)
|
||||
@@ -139,8 +139,8 @@ public class FollowerController : ApiController
|
||||
public IHttpActionResult GetList([FromBody] Model.ViewModel.follower q,
|
||||
int page, int pageSize = 10, string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
////var qry = _db.followers.Where(a => a.IsDel == false).AsEnumerable();////不確定是否新增欄位? 先註解
|
||||
var qry = _db.followers.AsEnumerable();
|
||||
////var qry = _db.followers.Where(a => a.IsDel == false).AsQueryable();////不確定是否新增欄位? 先註解
|
||||
var qry = _db.followers.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(q.f_number))
|
||||
qry = qry.Where(o => o.f_number.Contains(q.f_number.Trim()));
|
||||
@@ -151,7 +151,7 @@ public class FollowerController : ApiController
|
||||
if (q.birthday2.HasValue)
|
||||
qry = qry.Where(o => o.birthday < Convert.ToDateTime(q.birthday2.Value).AddDays(1));
|
||||
if (!string.IsNullOrEmpty(q.address))
|
||||
qry = qry.Where(o => o.address !=null && o.address.Contains(q.address?.Trim()));
|
||||
qry = qry.Where(o => o.address !=null && o.address.Contains(q.address.Trim()));
|
||||
//if (q.num.HasValue && q.num.Value>0)
|
||||
// qry = qry.Where(o => o.num==q.num.Value);
|
||||
if (q.ept_self.HasValue && q.ept_self.Value )//排除自己
|
||||
@@ -215,9 +215,10 @@ public class FollowerController : ApiController
|
||||
|
||||
var tdesc = publicFun.enum_desc<Model.follower.type>();
|
||||
var count = qry.Count(); //pageSize = count;//一次取回??
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
var ret = new
|
||||
{
|
||||
list = qry.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
num = x.num,
|
||||
f_number = x.f_number,
|
||||
@@ -339,9 +340,9 @@ public class FollowerController : ApiController
|
||||
|
||||
//int ccc = cc.Count();
|
||||
|
||||
|
||||
|
||||
var qry = _db.followers.AsEnumerable().Where(f => cc.Any(x => x == f.num) || cc.Any(x => x == f.leader));
|
||||
// 優化:使用子查詢在數據庫層面執行,避免載入所有家族成員 ID
|
||||
// 生成 SQL: WHERE num IN (SELECT...) OR leader IN (SELECT...)
|
||||
var qry = _db.followers.Where(f => cc.Contains(f.num) || (f.leader.HasValue && cc.Contains(f.leader.Value)));
|
||||
|
||||
|
||||
|
||||
@@ -359,11 +360,12 @@ public class FollowerController : ApiController
|
||||
qry = qry.OrderByDescending(o => o.num);
|
||||
MyWeb.encrypt encrypt = new MyWeb.encrypt();
|
||||
var tdesc = publicFun.enum_desc<Model.follower.type>();
|
||||
int i = 1;
|
||||
var count = qry.Count(); //pageSize = count;//一次取回??
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
int i = 1;
|
||||
var ret = new
|
||||
{
|
||||
list = qry.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
id = i++,
|
||||
num = x.num,
|
||||
@@ -524,13 +526,14 @@ public class FollowerController : ApiController
|
||||
if (_follower > 0)
|
||||
{
|
||||
|
||||
var qry = _db.followers_tablet.AsEnumerable().Where(x=>( x.f_num??0) == _follower);
|
||||
var qry = _db.followers_tablet.Where(x=> x.f_num == _follower);
|
||||
qry = qry.OrderByDescending(o => o.num);
|
||||
var count = qry.Count(); //pageSize = count;//一次取回??
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
int i = 1;
|
||||
var ret = new
|
||||
{
|
||||
list = qry.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
id = i++,
|
||||
num = x.num,
|
||||
@@ -593,7 +596,7 @@ public class FollowerController : ApiController
|
||||
[Route("api/follower/tabletDelete/{id}")]
|
||||
public void tabletDelete(int id)
|
||||
{
|
||||
var prod = _db.followers_tablet.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.followers_tablet.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
_db.followers_tablet.Remove(prod);
|
||||
|
||||
@@ -52,7 +52,7 @@ public class accountingController : BaseApiController
|
||||
// DELETE api/<controller>/5
|
||||
public void Delete(int id)
|
||||
{
|
||||
var prod = _db.accountings.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.accountings.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
var prod2 = prod.accounting_files;
|
||||
@@ -89,12 +89,12 @@ public class accountingController : BaseApiController
|
||||
{
|
||||
if (!string.IsNullOrEmpty(nums))
|
||||
{
|
||||
var getDelItem = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s));
|
||||
var getDelItem = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s)).ToList();
|
||||
|
||||
var prod = _db.accountings.AsEnumerable().Where(q => getDelItem.Contains(q.num)).ToList();
|
||||
var prod = _db.accountings.Where(q => getDelItem.Contains(q.num)).ToList();
|
||||
if (prod.Count() > 0)
|
||||
{
|
||||
var prod2 = _db.accounting_files.AsEnumerable().Where(q => q.accounting_num.HasValue && getDelItem.Contains(q.accounting_num.Value)).ToList();
|
||||
var prod2 = _db.accounting_files.Where(q => q.accounting_num.HasValue && getDelItem.Contains(q.accounting_num.Value)).ToList();
|
||||
if (prod2.Count() > 0)
|
||||
{
|
||||
publicFun publicFun = new publicFun();
|
||||
@@ -126,7 +126,7 @@ public class accountingController : BaseApiController
|
||||
public IHttpActionResult GetList([FromBody] Model.ViewModel.accounting q, int page, int pageSize = 10,
|
||||
string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.accountings.AsEnumerable();
|
||||
var qry = _db.accountings.AsQueryable();
|
||||
|
||||
if (q.category.HasValue)
|
||||
qry = qry.Where(o => o.category == q.category.Value);
|
||||
@@ -215,10 +215,12 @@ public class accountingController : BaseApiController
|
||||
qry = qry.OrderByDescending(o => o.num);
|
||||
|
||||
var tdesc = publicFun.enum_desc<Model.accounting.type>();
|
||||
var count = qry.Count();
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
|
||||
var ret = new
|
||||
{
|
||||
list = qry.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
num = x.num,
|
||||
category = x.category,
|
||||
@@ -245,7 +247,7 @@ public class accountingController : BaseApiController
|
||||
total =(x.price ?? 0)+( x.tax?? 0),
|
||||
|
||||
}),
|
||||
count = qry.Count()
|
||||
count = count
|
||||
|
||||
};
|
||||
|
||||
@@ -259,7 +261,7 @@ public class accountingController : BaseApiController
|
||||
public IHttpActionResult GetTitleKindList([FromBody] Model.ViewModel.accounting_kind q, int page, int pageSize = 10,
|
||||
string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.accounting_kind.AsEnumerable();
|
||||
var qry = _db.accounting_kind.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(q.kind))
|
||||
qry = qry.Where(o => o.kind.Contains(q.kind));
|
||||
@@ -297,7 +299,7 @@ public class accountingController : BaseApiController
|
||||
public IHttpActionResult GetAccountKindList([FromBody] Model.ViewModel.accounting_kind2 q, int page, int pageSize = 10,
|
||||
string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.accounting_kind2.AsEnumerable();
|
||||
var qry = _db.accounting_kind2.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(q.kind))
|
||||
qry = qry.Where(o => o.kind.Contains(q.kind));
|
||||
@@ -341,15 +343,16 @@ public class accountingController : BaseApiController
|
||||
if (q.accounting_num.HasValue && q.accounting_num.Value > 0)
|
||||
{
|
||||
//檢查
|
||||
var qry = _db.accounting_files.AsEnumerable();
|
||||
qry = qry.Where(o => o.accounting_num == q.accounting_num.Value);
|
||||
qry.OrderByDescending(x => x.num);
|
||||
var qry = _db.accounting_files.Where(o => o.accounting_num == q.accounting_num.Value);
|
||||
qry = qry.OrderByDescending(x => x.num);
|
||||
|
||||
var count = qry.Count();
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
int i = 1;
|
||||
//已有值
|
||||
var ret = new
|
||||
{
|
||||
list = qry.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
id = i++,
|
||||
num = x.num,
|
||||
@@ -357,7 +360,7 @@ public class accountingController : BaseApiController
|
||||
pic1 = x.pic1,
|
||||
pic1_name = x.pic1_name,
|
||||
}),
|
||||
count = qry.Count(),
|
||||
count = count,
|
||||
};
|
||||
|
||||
if (ret.list == null) throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
@@ -473,7 +476,7 @@ public class accountingController : BaseApiController
|
||||
[Route("api/accounting/DeleteFilesItem/{id}")]//刪除相關檔案
|
||||
public void DeleteFilesItem(int id)
|
||||
{
|
||||
var prod = _db.accounting_files.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.accounting_files.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(prod.pic1))
|
||||
|
||||
@@ -63,17 +63,17 @@ public class activityController : ApiController
|
||||
// DELETE api/<controller>/5
|
||||
public void Delete(int id)
|
||||
{
|
||||
var prod = _db.activities.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.activities.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
//刪除相關資料
|
||||
var prod2 = _db.activity_relating.AsEnumerable().Where(q => q.activity_num == id).ToList(); //相關項目
|
||||
var prod2 = _db.activity_relating.Where(q => q.activity_num == id).ToList(); //相關項目
|
||||
if (prod2.Count > 0)
|
||||
{
|
||||
//查詢結果全部刪除
|
||||
_db.activity_relating.RemoveRange(prod2);
|
||||
}
|
||||
var prod3 = _db.activity_spares.AsEnumerable().Where(q => q.activity_num == id).ToList(); //備品項目
|
||||
var prod3 = _db.activity_spares.Where(q => q.activity_num == id).ToList(); //備品項目
|
||||
if (prod3.Count > 0)
|
||||
{
|
||||
_db.activity_spares.RemoveRange(prod3);
|
||||
@@ -98,7 +98,7 @@ public class activityController : ApiController
|
||||
[Route("api/activity/DeleteItem/{id}")]
|
||||
public void DeleteItem(int id)
|
||||
{
|
||||
var prod = _db.actItems.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.actItems.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
/*if (prod != null)
|
||||
{
|
||||
//var prod2 = _db.actItem_files.AsEnumerable().Where(q => q.actItem_num == id).ToList(); //相關項目
|
||||
@@ -144,11 +144,11 @@ public class activityController : ApiController
|
||||
{
|
||||
var ids = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s));
|
||||
|
||||
var prod = _db.activities.AsEnumerable().Where(q => ids.Contains(q.num)).ToList();
|
||||
var prod = _db.activities.Where(q => ids.Contains(q.num)).ToList();
|
||||
if (prod.Count() > 0)
|
||||
{
|
||||
//var prod2 = _db.activity_relating.AsEnumerable().Where(q => ids.Contains(Convert.ToInt32(q.activity_num))).ToList();
|
||||
var prod2 = _db.activity_relating.AsEnumerable().Where(q => ids.Any(x => x == q.activity_num)).ToList();
|
||||
var prod2 = _db.activity_relating.Where(q => ids.Contains(q.activity_num)).ToList();
|
||||
if (prod2.Count > 0)
|
||||
{
|
||||
_db.activity_relating.RemoveRange(prod2);
|
||||
@@ -156,7 +156,7 @@ public class activityController : ApiController
|
||||
}
|
||||
|
||||
//var prod3 = _db.activity_spares.AsEnumerable().Where(q => ids.Contains(Convert.ToInt32(q.activity_num))).ToList();
|
||||
var prod3 = _db.activity_spares.AsEnumerable().Where(q => ids.Any(x => x == q.activity_num)).ToList();
|
||||
var prod3 = _db.activity_spares.Where(q => ids.Contains(q.activity_num)).ToList();
|
||||
if (prod3.Count > 0)
|
||||
{
|
||||
_db.activity_spares.RemoveRange(prod3);
|
||||
@@ -186,11 +186,11 @@ public class activityController : ApiController
|
||||
if (!string.IsNullOrEmpty(nums))
|
||||
{
|
||||
var ids = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s));
|
||||
var prod = _db.actItems.AsEnumerable().Where(q => ids.Contains(q.num)).ToList();
|
||||
var prod = _db.actItems.Where(q => ids.Contains(q.num)).ToList();
|
||||
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.AsEnumerable().Where(q => ids.Any(x => x == 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);
|
||||
@@ -281,10 +281,10 @@ public class activityController : ApiController
|
||||
qry = qry.OrderByDescending(o => o.num);
|
||||
|
||||
var count = qry.Count(); //pageSize = count;//一次取回??
|
||||
if (pageSize > 0) qry = qry.ToPagedList(page, pageSize);
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
var ret = new
|
||||
{
|
||||
list = qry.Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
num = x.num,
|
||||
subject = x.subject,
|
||||
@@ -319,7 +319,7 @@ public class activityController : ApiController
|
||||
{
|
||||
|
||||
//var stockDt = _db.stocks.AsEnumerable(); ;//庫存
|
||||
var fileDt = _db.files.AsEnumerable().Where(f => f.subject.Contains(q.fileTxt)).Select(f => f.num.ToString());//文件
|
||||
var fileDt = _db.files.Where(f => f.subject.Contains(q.fileTxt)).Select(f => f.num.ToString());//文件
|
||||
|
||||
//每個品項在每個倉庫的結餘量
|
||||
var stockDt = (
|
||||
@@ -364,7 +364,7 @@ public class activityController : ApiController
|
||||
|
||||
}
|
||||
if (!string.IsNullOrEmpty(q.kindTxt))
|
||||
qry = qry.Where(o => o.actItem_kind?.kind != null && o.actItem_kind.kind.Contains(q.kindTxt));
|
||||
qry = qry.Where(o => o.actItem_kind != null && o.actItem_kind.kind != null && o.actItem_kind.kind.Contains(q.kindTxt));
|
||||
if (q.category.HasValue && q.category.Value > 0)
|
||||
qry = qry.Where(o => o.category == q.category.Value);
|
||||
if (!string.IsNullOrEmpty(q.categorys))
|
||||
@@ -410,10 +410,10 @@ public class activityController : ApiController
|
||||
|
||||
var tdesc = publicFun.enum_desc<Model.activity.category>();
|
||||
var count = qry.Count(); //pageSize = count;//一次取回??
|
||||
if (pageSize > 0) qry = qry.ToPagedList(page, pageSize);
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
var ret = new
|
||||
{
|
||||
list = qry.Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
num = x.num,
|
||||
subject = x.subject,
|
||||
@@ -711,7 +711,7 @@ public class activityController : ApiController
|
||||
[Route("api/activity/DeleteFilesItem/{id}")]//刪除品項的相關文件
|
||||
public void DeleteFilesItem(int id)
|
||||
{
|
||||
var prod = _db.actItem_files.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.actItem_files.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
|
||||
@@ -731,16 +731,15 @@ public class activityController : ApiController
|
||||
if (this_id > 0)
|
||||
{
|
||||
//檢查
|
||||
var qry = _db.activity_kind_detail.AsEnumerable();
|
||||
qry = qry.Where(o => o.activity_kind_num == this_id);
|
||||
var qry = _db.activity_kind_detail.Where(o => o.activity_kind_num == this_id);
|
||||
int i = 1;
|
||||
|
||||
//已有值
|
||||
var count = qry.Count(); //pageSize = count;//一次取回??
|
||||
if (pageSize > 0) qry = qry.ToPagedList(page, pageSize);
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
var ret = new
|
||||
{
|
||||
list = qry.Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
id = i++,
|
||||
num = x.num,
|
||||
@@ -830,7 +829,7 @@ public class activityController : ApiController
|
||||
[Route("api/activity/DeleteActKindDetail/{id}")]//刪除活動分類的detail
|
||||
public void DeleteActKindDetail(int id)
|
||||
{
|
||||
var prod = _db.activity_kind_detail.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.activity_kind_detail.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
|
||||
@@ -849,7 +848,7 @@ public class activityController : ApiController
|
||||
if (this_act_id > 0)
|
||||
{
|
||||
//檢查
|
||||
var prod = _db.activities.AsEnumerable().Where(o => o.num == this_act_id).FirstOrDefault();
|
||||
var prod = _db.activities.Where(o => o.num == this_act_id).FirstOrDefault();
|
||||
if (prod != null)
|
||||
{
|
||||
int kind = prod.kind ?? 0; //分類
|
||||
@@ -927,13 +926,12 @@ public class activityController : ApiController
|
||||
if (kind > 0)
|
||||
{
|
||||
int i = 1;
|
||||
var qry2 = _db.activity_kind_detail.AsEnumerable();
|
||||
qry2 = qry2.Where(o => o.activity_kind_num == kind);
|
||||
var qry2 = _db.activity_kind_detail.Where(o => o.activity_kind_num == kind);
|
||||
var count2 = qry2.Count(); //pageSize = count2;//一次取回??
|
||||
if (pageSize > 0) qry2 = qry2.ToPagedList(page, pageSize);
|
||||
var qry2List = (pageSize > 0) ? qry2.ToPagedList(page, pageSize).ToList() : qry2.ToList();
|
||||
var ret = new
|
||||
{
|
||||
list = qry2.Select(x => new
|
||||
list = qry2List.Select(x => new
|
||||
{
|
||||
id = i++,
|
||||
num = 0,
|
||||
@@ -992,7 +990,7 @@ public class activityController : ApiController
|
||||
public IHttpActionResult GetKindList([FromBody] Model.ViewModel.activity_kind q,
|
||||
int page, int pageSize = 10, string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.activity_kind.AsEnumerable();
|
||||
var qry = _db.activity_kind.AsQueryable();
|
||||
if (q.num.HasValue && q.num > 0)
|
||||
qry = qry.Where(o => o.num == q.num);
|
||||
if (!string.IsNullOrEmpty(q.kind))
|
||||
@@ -1031,7 +1029,7 @@ public class activityController : ApiController
|
||||
{
|
||||
if (id > 0)
|
||||
{
|
||||
var qry = _db.activity_kind.AsEnumerable();
|
||||
var qry = _db.activity_kind.AsQueryable();
|
||||
qry = qry.Where(o => o.num == id);
|
||||
var prop3 = qry.FirstOrDefault();
|
||||
if (prop3 != null)
|
||||
@@ -1151,7 +1149,7 @@ public class activityController : ApiController
|
||||
[Route("api/activity/DeleteRelatingData/{id}")]//刪除活動的相關資料
|
||||
public void DeleteRelatingData(int id)
|
||||
{
|
||||
var prod = _db.activity_relating.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.activity_relating.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
|
||||
@@ -1169,25 +1167,22 @@ public class activityController : ApiController
|
||||
if (this_act_id > 0)
|
||||
{
|
||||
//檢查
|
||||
var prod = _db.activities.AsEnumerable().Where(o => o.num == this_act_id).FirstOrDefault();
|
||||
var prod = _db.activities.Where(o => o.num == this_act_id).FirstOrDefault();
|
||||
if (prod != null)
|
||||
{
|
||||
|
||||
|
||||
int kind = prod.kind ?? 0; //分類
|
||||
|
||||
var qry1 = _db.activity_spares.AsEnumerable();
|
||||
qry1 = qry1.Where(o => o.activity_num == this_act_id);
|
||||
|
||||
qry1 = qry1.OrderBy(o => o.num);
|
||||
var qry1 = _db.activity_spares.Where(o => o.activity_num == this_act_id).OrderBy(o => o.num);
|
||||
|
||||
|
||||
var count = qry1.Count(); //pageSize = count;//一次取回??
|
||||
int i = 1;
|
||||
if (pageSize > 0) qry1 = qry1.ToPagedList(page, pageSize);
|
||||
var qry1List = (pageSize > 0) ? qry1.ToPagedList(page, pageSize).ToList() : qry1.ToList();
|
||||
var ret = new
|
||||
{
|
||||
list = qry1.Select(x => new
|
||||
list = qry1List.Select(x => new
|
||||
{
|
||||
id = i++,
|
||||
num = x.num,
|
||||
@@ -1278,7 +1273,7 @@ public class activityController : ApiController
|
||||
[Route("api/activity/DeleteSparesData/{id}")]//刪除活動的備品資料
|
||||
public void DeleteSparesData(int id)
|
||||
{
|
||||
var prod = _db.activity_spares.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.activity_spares.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
|
||||
@@ -1388,10 +1383,10 @@ public class activityController : ApiController
|
||||
|
||||
var tdesc = publicFun.enum_desc<Model.activity_check.keyin1>();
|
||||
var count = qry.Count(); //pageSize = count;//一次取回??
|
||||
if (pageSize > 0) qry = qry.ToPagedList(page, pageSize);
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
var ret = new
|
||||
{
|
||||
list = qry.Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
num = x.num,
|
||||
subject = x.activity?.subject,
|
||||
@@ -1416,7 +1411,7 @@ public class activityController : ApiController
|
||||
[Route("api/activity/DeleteCheck/{id}")]
|
||||
public void DeleteCheck(int id)
|
||||
{
|
||||
var prod = _db.activity_check.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.activity_check.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
|
||||
@@ -1439,7 +1434,7 @@ public class activityController : ApiController
|
||||
if (!string.IsNullOrEmpty(num[i]))
|
||||
ids[i] = Convert.ToInt32(num[i]);
|
||||
}
|
||||
var prod = _db.activity_check.AsEnumerable().Where(q => ids.Contains(q.num)).ToList();
|
||||
var prod = _db.activity_check.Where(q => ids.Contains(q.num)).ToList();
|
||||
if (prod.Count() > 0)
|
||||
{
|
||||
|
||||
@@ -1458,7 +1453,7 @@ public class activityController : ApiController
|
||||
{
|
||||
DateTime _now = DateTime.Now;
|
||||
|
||||
var qry = _db.activities.AsEnumerable();
|
||||
var qry = _db.activities.AsQueryable();
|
||||
|
||||
if (q.reg_time1.HasValue)
|
||||
qry = qry.Where(o => o.reg_time >= q.reg_time1.Value);
|
||||
@@ -1466,7 +1461,7 @@ public class activityController : ApiController
|
||||
qry = qry.Where(o => o.reg_time < Convert.ToDateTime(q.reg_time2.Value).AddDays(1));
|
||||
|
||||
|
||||
qry = qry.Where(o => (_now >= o.startDate_solar && _now < o.endDate_lunar) || (_now < o.startDate_solar && o.dueDate?.Date.CompareTo(_now) <= 180));
|
||||
qry = qry.Where(o => (_now >= o.startDate_solar && _now < o.endDate_lunar) || (_now < o.startDate_solar && o.dueDate.HasValue && o.dueDate.Value.Date.CompareTo(_now) <= 180));
|
||||
|
||||
qry = qry.OrderByDescending(o => o.num);
|
||||
|
||||
@@ -1510,7 +1505,7 @@ public class activityController : ApiController
|
||||
public IHttpActionResult GetCategoryKindList([FromBody] Model.ViewModel.activity_category_kind q,
|
||||
int page, int pageSize = 10, string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.activity_category_kind.AsEnumerable();
|
||||
var qry = _db.activity_category_kind.AsQueryable();
|
||||
if (q.num.HasValue && q.num > 0)
|
||||
qry = qry.Where(o => o.num == q.num);
|
||||
if (!string.IsNullOrEmpty(q.kind))
|
||||
@@ -1518,10 +1513,10 @@ public class activityController : ApiController
|
||||
qry = qry.OrderBy(O => O.kind).ThenBy(o => o.num);
|
||||
|
||||
var count = qry.Count(); //pageSize = count;//一次取回??
|
||||
if (pageSize > 0) qry = qry.ToPagedList(page, pageSize);
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
var ret = new
|
||||
{
|
||||
list = qry.Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
num = x.num,
|
||||
kind = x.kind,
|
||||
|
||||
@@ -54,7 +54,7 @@ public class activity_kindController : ApiController
|
||||
public IHttpActionResult GetList([FromBody] Model.ViewModel.actItem_kind q,
|
||||
int page, int pageSize = 10, string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.actItem_kind.AsEnumerable();
|
||||
var qry = _db.actItem_kind.AsQueryable();
|
||||
if (!string.IsNullOrEmpty(q.kind))
|
||||
qry = qry.Where(o => o.kind.Contains(q.kind));
|
||||
if (!string.IsNullOrEmpty(q.status))
|
||||
|
||||
@@ -52,7 +52,7 @@ public class adminUserController : ApiController
|
||||
// DELETE api/<controller>/5
|
||||
public void Delete(int id)
|
||||
{
|
||||
var prod = _db.admins.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.admins.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
|
||||
@@ -76,7 +76,7 @@ public class adminUserController : ApiController
|
||||
public IHttpActionResult GetList([FromBody] Model.ViewModel.admin q, int page, int pageSize = 10,
|
||||
string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.admins.AsEnumerable();
|
||||
var qry = _db.admins.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(q.u_id))
|
||||
qry = qry.Where(o => o.u_id.Contains(q.u_id));
|
||||
@@ -90,17 +90,15 @@ public class adminUserController : ApiController
|
||||
|
||||
if(q.removeExist.HasValue && q.removeExist.Value)
|
||||
{
|
||||
// 優化:使用子查詢在數據庫層面執行,避免載入所有會員的 admin_num
|
||||
var usedAdminNums = _db.members.Select(b => b.admin_num);
|
||||
if (q.num.HasValue && q.num.Value > 0)
|
||||
{
|
||||
qry = qry.Where(o => (!(from b in _db.members.AsEnumerable()
|
||||
select b.admin_num)
|
||||
.Contains(o.num)) || o.num == Convert.ToInt32(q.num.Value));
|
||||
qry = qry.Where(o => !usedAdminNums.Contains(o.num) || o.num == q.num.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
qry = qry.Where(o => (!(from b in _db.members.AsEnumerable()
|
||||
select b.admin_num)
|
||||
.Contains(o.num)));
|
||||
qry = qry.Where(o => !usedAdminNums.Contains(o.num));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,9 +112,12 @@ public class adminUserController : ApiController
|
||||
else
|
||||
qry = qry.OrderByDescending(o => o.num);
|
||||
|
||||
var count = qry.Count();
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
|
||||
var ret = new
|
||||
{
|
||||
list = qry.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
num = x.num,
|
||||
u_id = x.u_id,
|
||||
@@ -124,7 +125,7 @@ public class adminUserController : ApiController
|
||||
power = x.power,
|
||||
|
||||
}),
|
||||
count = qry.Count()
|
||||
count = count
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -44,19 +44,22 @@ public class appellationController : BaseApiController
|
||||
public IHttpActionResult GetList([FromBody] Model.appellation q,
|
||||
int page, int pageSize = 10, string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.appellations.AsEnumerable();
|
||||
var qry = _db.appellations.AsQueryable();
|
||||
|
||||
|
||||
qry = qry.OrderBy(o => o.num);
|
||||
|
||||
var count = qry.Count();
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
|
||||
var ret = new
|
||||
{
|
||||
list = qry.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
num = x.num,
|
||||
title = x.title,
|
||||
}),
|
||||
count = qry.Count()
|
||||
count = count
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ public class bedController : BaseApiController
|
||||
// DELETE api/<controller>/5
|
||||
public void Delete(string id)
|
||||
{
|
||||
var prod = _db.bed_order.AsEnumerable().Where(q => q.bed_order_no == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.bed_order.Where(q => q.bed_order_no == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
//刪除訂單明細
|
||||
@@ -80,7 +80,7 @@ public class bedController : BaseApiController
|
||||
{
|
||||
order_no = "ED" + DateTime.Now.ToString("yyMMdd");
|
||||
|
||||
var qry = _db.companies.AsEnumerable();
|
||||
var qry = _db.companies.AsQueryable();
|
||||
var prod = qry.Where(q => q.num == 1).FirstOrDefault();
|
||||
if (prod != null)
|
||||
{
|
||||
@@ -157,16 +157,18 @@ public class bedController : BaseApiController
|
||||
public IHttpActionResult GetDetailList([FromBody] Model.bed_order q,
|
||||
int page, int pageSize = 10, string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.bed_order_detail.AsEnumerable();
|
||||
qry = qry.Where(o => o.bed_order_no == q.bed_order_no);
|
||||
var qry = _db.bed_order_detail.Where(o => o.bed_order_no == q.bed_order_no);
|
||||
|
||||
qry = qry.OrderBy(o => o.checkIn_date ).ThenBy(o => o.num);
|
||||
|
||||
int i = 1;
|
||||
var tdesc = publicFun.enum_desc<Model.bed_kind.bed_type>();
|
||||
var count = qry.Count();
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
|
||||
var ret = new
|
||||
{
|
||||
list = qry.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
id = i++,
|
||||
num = x.num,
|
||||
@@ -197,7 +199,7 @@ public class bedController : BaseApiController
|
||||
},
|
||||
license = x.license,
|
||||
}),
|
||||
count = qry.Count()
|
||||
count = count
|
||||
|
||||
};
|
||||
return Ok(ret);
|
||||
@@ -250,7 +252,7 @@ public class bedController : BaseApiController
|
||||
[Route("api/bed/DeleteBedDetail/{id}")]//刪除detail
|
||||
public void DeleteBedDetail(int id)
|
||||
{
|
||||
var prod = _db.bed_order_detail.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.bed_order_detail.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ public class bed_kindController : ApiController
|
||||
public IHttpActionResult GetList([FromBody] Model.ViewModel.bed_kind q,
|
||||
int page, int pageSize = 10, string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.bed_kind.AsEnumerable();
|
||||
var qry = _db.bed_kind.AsQueryable();
|
||||
if (!string.IsNullOrEmpty(q.kind))
|
||||
qry = qry.Where(o => o.kind.Contains(q.kind));
|
||||
if (!string.IsNullOrEmpty(q.sex))
|
||||
@@ -60,16 +60,20 @@ public class bed_kindController : ApiController
|
||||
if (q.root.HasValue)
|
||||
qry = qry.Where(o => o.root.Value == q.root.Value);
|
||||
qry = qry.OrderBy(o => o.range).ThenBy(o => o.num);
|
||||
|
||||
var count = qry.Count();
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
|
||||
var ret = new
|
||||
{
|
||||
list = qry.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
num = x.num,
|
||||
kind = x.kind,
|
||||
sex = x.sex,
|
||||
|
||||
}),
|
||||
count = qry.Count()
|
||||
count = count
|
||||
|
||||
};
|
||||
return Ok(ret);
|
||||
@@ -83,7 +87,7 @@ public class bed_kindController : ApiController
|
||||
var tdesc = publicFun.enum_desc<Model.bed_kind.bed_type>();
|
||||
//var tdesc2 = tdesc.ToArray().Select(x=>x.Value); //[0]單人床,[1]雙人床
|
||||
//var tdesc3 = tdesc.ToArray().Select(x=>x.Key); //[0]1,[1]2
|
||||
var qry = _db.bed_kind_detail.AsEnumerable();
|
||||
var qry = _db.bed_kind_detail.AsQueryable();
|
||||
if (q.bed_kind_id.HasValue)
|
||||
qry = qry.Where(o => o.bed_kind_id == q.bed_kind_id);
|
||||
if (!string.IsNullOrEmpty(q.bed_name))
|
||||
@@ -103,17 +107,19 @@ public class bed_kindController : ApiController
|
||||
if (q.inTime.HasValue )
|
||||
{
|
||||
//判斷日期沒庫存不能選
|
||||
var bedDt = _db.bed_order_detail.AsEnumerable().Where(f => f.checkIn_date.HasValue && f.checkIn_date ==q.inTime.Value ).Select(f => f.bed_kind_detail_id.ToString());//掛單表單明細
|
||||
qry = qry.Where(o => !bedDt.ToArray().Contains(o.num.ToString()));
|
||||
var bedDt = _db.bed_order_detail.Where(f => f.checkIn_date.HasValue && f.checkIn_date ==q.inTime.Value && f.bed_kind_detail_id.HasValue).Select(f => f.bed_kind_detail_id.Value).ToList();//掛單表單明細
|
||||
qry = qry.Where(o => !bedDt.Contains(o.num));
|
||||
|
||||
}
|
||||
qry = qry.OrderBy(o => o.bed_name);
|
||||
int i = 1;
|
||||
|
||||
if (pageSize > 0) qry = qry.ToPagedList(page, pageSize);
|
||||
var count = qry.Count();
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
|
||||
var ret = new
|
||||
{
|
||||
list = qry.Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
id = i++,
|
||||
num = x.num,
|
||||
@@ -122,7 +128,7 @@ public class bed_kindController : ApiController
|
||||
bed_type_txt = x.bed_type.HasValue? tdesc[x.bed_type ?? 1] : "",
|
||||
demo = x.demo,
|
||||
}),
|
||||
count = qry.Count()
|
||||
count = count
|
||||
|
||||
};
|
||||
return Ok(ret);
|
||||
@@ -186,7 +192,7 @@ public class bed_kindController : ApiController
|
||||
[Route("api/bed_kind/DeleteBedKindDetail/{id}")]//刪除分類的detail
|
||||
public void DeleteActKindDetail(int id)
|
||||
{
|
||||
var prod = _db.bed_kind_detail.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.bed_kind_detail.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
|
||||
|
||||
@@ -44,22 +44,25 @@ public class countryController : BaseApiController
|
||||
public IHttpActionResult GetList([FromBody] Model.ViewModel.country q,
|
||||
int page, int pageSize = 10, string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.countries.AsEnumerable();
|
||||
var qry = _db.countries.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(q.keyword))
|
||||
qry = qry.Where(o => o.ID.Contains(q.keyword.Trim()) || o.name_en.Contains(q.keyword.Trim()) || o.name_zh.Contains(q.keyword.Trim()));
|
||||
|
||||
qry = qry.OrderBy(o => o.range).ThenBy(o => o.name_en);
|
||||
|
||||
var count = qry.Count();
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
|
||||
var ret = new
|
||||
{
|
||||
list = qry.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
id = x.ID,
|
||||
name_en = x.name_en,
|
||||
name_zh = x.name_zh,
|
||||
}),
|
||||
count = qry.Count()
|
||||
count = count
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -98,7 +98,17 @@ public class familyMembersController : ApiController
|
||||
[Route("api/familymembers/follower/{followerId}")]
|
||||
public IHttpActionResult GetByFollower(int followerId)
|
||||
{
|
||||
//var originalLazyLoading = _db.Configuration.LazyLoadingEnabled;
|
||||
//var originalProxyCreation = _db.Configuration.ProxyCreationEnabled;
|
||||
//
|
||||
//_db.Configuration.LazyLoadingEnabled = false;
|
||||
//_db.Configuration.ProxyCreationEnabled = false;
|
||||
|
||||
var familyMembers = _db.family_members.Where(fm => fm.follower_num == followerId).ToList();
|
||||
|
||||
//_db.Configuration.LazyLoadingEnabled = originalLazyLoading;
|
||||
//_db.Configuration.ProxyCreationEnabled = originalProxyCreation;
|
||||
|
||||
return Ok(familyMembers);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public class memberController : BaseApiController
|
||||
// DELETE api/<controller>/5
|
||||
public void Delete(int id)
|
||||
{
|
||||
var prod = _db.members.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.members.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
if(!string.IsNullOrEmpty(prod.pic1))
|
||||
@@ -79,7 +79,7 @@ public class memberController : BaseApiController
|
||||
[Route("api/member/DeleteCheck/{id}")]
|
||||
public void DeleteCheck(int id) //刪除考勤資料
|
||||
{
|
||||
var prod = _db.member_check.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.member_check.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
_db.member_check.Remove(prod);
|
||||
@@ -93,9 +93,9 @@ public class memberController : BaseApiController
|
||||
{
|
||||
if (!string.IsNullOrEmpty(nums))
|
||||
{
|
||||
var getDelItem = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s));
|
||||
var getDelItem = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s)).ToList();
|
||||
|
||||
var prod = _db.members.AsEnumerable().Where(q => getDelItem.Contains(q.num)).ToList();
|
||||
var prod = _db.members.Where(q => getDelItem.Contains(q.num)).ToList();
|
||||
if (prod.Count() > 0)
|
||||
{
|
||||
publicFun publicFun = new publicFun();
|
||||
@@ -107,8 +107,8 @@ public class memberController : BaseApiController
|
||||
}
|
||||
}
|
||||
|
||||
var prod2 = _db.member_check.AsEnumerable().Where(q => getDelItem.Contains(Convert.ToInt32(q.mem_num))).ToList();
|
||||
if (prod2.Count > 0)
|
||||
var prod2 = _db.member_check.Where(q => q.mem_num.HasValue && getDelItem.Contains(q.mem_num.Value)).ToList();
|
||||
if (prod2.Count() > 0)
|
||||
{
|
||||
_db.member_check.RemoveRange(prod2);
|
||||
//_db.SaveChanges();
|
||||
@@ -135,8 +135,8 @@ public class memberController : BaseApiController
|
||||
{
|
||||
if (!string.IsNullOrEmpty(nums))
|
||||
{
|
||||
var ids = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s));
|
||||
var prod = _db.member_check.AsEnumerable().Where(q => ids.Contains(q.num)).ToList();
|
||||
var ids = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s)).ToList();
|
||||
var prod = _db.member_check.Where(q => ids.Contains(q.num)).ToList();
|
||||
if (prod.Count() > 0)
|
||||
{
|
||||
_db.member_check.RemoveRange(prod);
|
||||
@@ -150,7 +150,7 @@ public class memberController : BaseApiController
|
||||
public IHttpActionResult GetList([FromBody] Model.ViewModel.member q, int page, int pageSize = 10,
|
||||
string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.members.AsEnumerable();
|
||||
var qry = _db.members.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(q.u_name))
|
||||
qry = qry.Where(o => o.u_name.Contains(q.u_name.Trim()));
|
||||
@@ -220,10 +220,11 @@ public class memberController : BaseApiController
|
||||
else
|
||||
qry = qry.OrderByDescending(o => o.num);
|
||||
|
||||
|
||||
var count = qry.Count();
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
var ret = new
|
||||
{
|
||||
list = qry.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
num = x.num,
|
||||
m_number = x.m_number,
|
||||
@@ -242,7 +243,7 @@ public class memberController : BaseApiController
|
||||
starttime = x.group_kind.HasValue ? x.member_group.starttime : (object)null,
|
||||
demo = x.demo,
|
||||
}),
|
||||
count = qry.Count()
|
||||
count = count
|
||||
};
|
||||
|
||||
|
||||
@@ -256,7 +257,7 @@ public class memberController : BaseApiController
|
||||
public IHttpActionResult GetCheckList([FromBody] Model.ViewModel.member_check q, int page, int pageSize = 10,
|
||||
string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.member_check.AsEnumerable();
|
||||
var qry = _db.member_check.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(q.u_name))
|
||||
qry = qry.Where(o => o.member.u_name.Contains(q.u_name));
|
||||
@@ -317,9 +318,11 @@ public class memberController : BaseApiController
|
||||
|
||||
var tdesc = publicFun.enum_desc<Model.member.attendances.type>();
|
||||
var tdesc2 = publicFun.enum_desc<Model.member.attendances.login>();
|
||||
var count = qry.Count();
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
var ret = new
|
||||
{
|
||||
list = qry.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
num = x.num,
|
||||
m_number = x.member.m_number,
|
||||
@@ -332,7 +335,7 @@ public class memberController : BaseApiController
|
||||
login_type_desc = tdesc2[x.login_type ?? 1]
|
||||
|
||||
}),
|
||||
count = qry.Count()
|
||||
count = count
|
||||
};
|
||||
|
||||
|
||||
@@ -346,7 +349,7 @@ public class memberController : BaseApiController
|
||||
public IHttpActionResult GetGroupList([FromBody] Model.ViewModel.member_group q, int page, int pageSize = 10,
|
||||
string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.member_group.AsEnumerable();
|
||||
var qry = _db.member_group.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(q.kind))
|
||||
qry = qry.Where(o => o.kind.Contains(q.kind));
|
||||
@@ -394,7 +397,7 @@ public class memberController : BaseApiController
|
||||
public IHttpActionResult GetTitleList([FromBody] Model.ViewModel.member_title q, int page, int pageSize = 10,
|
||||
string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.member_title.AsEnumerable();
|
||||
var qry = _db.member_title.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(q.kind))
|
||||
qry = qry.Where(o => o.kind.Contains(q.kind));
|
||||
|
||||
@@ -52,7 +52,7 @@ public class member_titleController : ApiController
|
||||
public IHttpActionResult GetList([FromBody] Model.ViewModel.member_title q,
|
||||
int page, int pageSize = 10, string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.member_title.AsEnumerable();
|
||||
var qry = _db.member_title.AsQueryable();
|
||||
var ret = new { list = "", count = 0 };
|
||||
return Ok(ret);
|
||||
}
|
||||
|
||||
@@ -49,11 +49,11 @@ public class newsController : BaseApiController
|
||||
// DELETE api/<controller>/5
|
||||
public void Delete(int id)
|
||||
{
|
||||
var prod = _db.news.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.news.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
//刪除檔案
|
||||
var prod2 = _db.news_files.AsEnumerable().Where(q => q.news_id == id).ToList();
|
||||
var prod2 = _db.news_files.Where(q => q.news_id == id).ToList();
|
||||
if (prod2.Count > 0)
|
||||
{
|
||||
foreach (var item in prod2)
|
||||
@@ -91,12 +91,12 @@ public class newsController : BaseApiController
|
||||
{
|
||||
if (!string.IsNullOrEmpty(nums))
|
||||
{
|
||||
var getDelItem = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s));
|
||||
var getDelItem = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s)).ToList();
|
||||
|
||||
var prod = _db.news.AsEnumerable().Where(q => getDelItem.Contains(q.num)).ToList();
|
||||
var prod = _db.news.Where(q => getDelItem.Contains(q.num)).ToList();
|
||||
if (prod.Count() > 0)
|
||||
{
|
||||
var prod2 = _db.news_files.AsEnumerable().Where(q => getDelItem.Contains(q.news_id)).ToList();
|
||||
var prod2 = _db.news_files.Where(q => getDelItem.Contains(q.news_id)).ToList();
|
||||
if (prod2.Count > 0)
|
||||
{
|
||||
publicFun publicFun = new publicFun();
|
||||
@@ -139,7 +139,7 @@ public class newsController : BaseApiController
|
||||
public IHttpActionResult GetList([FromBody] Model.ViewModel.news q, int page, int pageSize = 10,
|
||||
string sortBy = "", bool sortDesc = false, bool top = false)
|
||||
{
|
||||
var qry = _db.news.AsEnumerable();
|
||||
var qry = _db.news.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(q.subject))
|
||||
qry = qry.Where(o => o.subject.Contains(q.subject.Trim()));
|
||||
@@ -258,10 +258,13 @@ public class newsController : BaseApiController
|
||||
else
|
||||
qry = qry.OrderByDescending(o => o.topping).ThenByDescending(o => o.num);
|
||||
}
|
||||
|
||||
var count = qry.Count();
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
|
||||
var ret = new
|
||||
{
|
||||
list = qry.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
num = x.num,
|
||||
subject = x.subject,
|
||||
@@ -282,7 +285,7 @@ public class newsController : BaseApiController
|
||||
topping = x.topping
|
||||
|
||||
}),
|
||||
count = qry.Count()
|
||||
count = count
|
||||
|
||||
};
|
||||
|
||||
@@ -298,7 +301,7 @@ public class newsController : BaseApiController
|
||||
{
|
||||
|
||||
|
||||
var qry = _db.news_kind.AsEnumerable();
|
||||
var qry = _db.news_kind.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(q.kind))
|
||||
qry = qry.Where(o => o.kind.Contains(q.kind));
|
||||
@@ -319,17 +322,18 @@ public class newsController : BaseApiController
|
||||
range = o.range,
|
||||
}).OrderBy(x => x.root).ThenBy(x => x.kind).ToList(), 0, 0);
|
||||
|
||||
|
||||
var count = qry.Count();
|
||||
var qry2List = (pageSize > 0) ? qry2.ToPagedList(page, pageSize).ToList() : qry2.ToList();
|
||||
|
||||
var ret = new
|
||||
{
|
||||
list = qry2.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qry2List.Select(x => new
|
||||
{
|
||||
num = x.num,
|
||||
kind = new TreeView().RptDash(x.Level) + x.kind,
|
||||
|
||||
}),
|
||||
count = qry.Count()
|
||||
count = count
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ public class orderController : ApiController
|
||||
{
|
||||
if (id > 0)
|
||||
{
|
||||
var prod = _db.pro_order_detail.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.pro_order_detail.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
//刪除掛單表單
|
||||
@@ -134,7 +134,7 @@ public class orderController : ApiController
|
||||
{
|
||||
var ids = nums.TrimEnd(',').Split(',');
|
||||
|
||||
var prod = _db.pro_order.AsEnumerable().Where(q => ids.Contains(q.order_no)).ToList();
|
||||
var prod = _db.pro_order.Where(q => ids.Contains(q.order_no)).ToList();
|
||||
if (prod.Count() > 0)
|
||||
{
|
||||
var prod2 = _db.pro_order_detail.AsEnumerable().Where(q => ids.Contains(Convert.ToString(q.order_no))).ToList();
|
||||
@@ -201,7 +201,7 @@ public class orderController : ApiController
|
||||
string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
|
||||
var qry = _db.pro_order.AsEnumerable();
|
||||
var qry = _db.pro_order.AsQueryable();
|
||||
//var aIDt = _db.actItems.AsEnumerable().Where(f => f.subject.Contains(q.actItemTxt.Trim())).Select(f => f.num);//品項
|
||||
|
||||
|
||||
@@ -220,32 +220,32 @@ public class orderController : ApiController
|
||||
if (!string.IsNullOrEmpty(q.address))
|
||||
qry = qry.Where(o => o.address.Contains(q.address.Trim()));
|
||||
if (!string.IsNullOrEmpty(q.subject))
|
||||
qry = qry.Where(o => o.activity_num.HasValue && o.activity.subject.Contains(q.subject?.Trim()));
|
||||
qry = qry.Where(o => o.activity_num.HasValue && o.activity.subject.Contains(q.subject.Trim()));
|
||||
if (!string.IsNullOrEmpty(q.u_name))
|
||||
qry = qry.Where(o => o.f_num.HasValue && o.follower.u_name.Contains(q.u_name?.Trim()));
|
||||
qry = qry.Where(o => o.f_num.HasValue && o.follower.u_name.Contains(q.u_name.Trim()));
|
||||
if (!string.IsNullOrEmpty(q.introducerTxt))
|
||||
qry = qry.Where(o => o.introducer.HasValue && o.follower1.u_name.Contains(q.introducerTxt?.Trim()));
|
||||
qry = qry.Where(o => o.introducer.HasValue && o.follower1.u_name.Contains(q.introducerTxt.Trim()));
|
||||
|
||||
if (!string.IsNullOrEmpty(q.actItemTxt))
|
||||
{
|
||||
//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);
|
||||
// qry = qry.Where(o => o.pro_order_detail.Where(f2 => f2.order_no == o.order_no && aIDt.Any(x => x == f2.actItem_num)).Count() > 0);
|
||||
|
||||
qry = qry.Where(o => o.pro_order_detail.Where(f2 => f2.actItem_num.HasValue && f2.actItem.subject.Contains(q.actItemTxt?.Trim())).Count() > 0);
|
||||
qry = qry.Where(o => o.pro_order_detail.Where(f2 => f2.actItem_num.HasValue && f2.actItem.subject.Contains(q.actItemTxt.Trim())).Count() > 0);
|
||||
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(q.country))
|
||||
qry = qry.Where(o => o.f_num != null && o.follower?.country == q.country);
|
||||
qry = qry.Where(o => o.f_num != null && o.follower != null && o.follower.country == q.country);
|
||||
if (!string.IsNullOrEmpty(q.country2))
|
||||
{
|
||||
if (q.country2 == "1")
|
||||
{
|
||||
qry = qry.Where(o => o.f_num != null && o.follower?.country == "158");
|
||||
qry = qry.Where(o => o.f_num != null && o.follower != null && o.follower.country == "158");
|
||||
}
|
||||
else if (q.country2 == "2")
|
||||
{
|
||||
qry = qry.Where(o => o.f_num != null && o.follower?.country != "158");
|
||||
qry = qry.Where(o => o.f_num != null && o.follower != null && o.follower.country != "158");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -275,16 +275,16 @@ public class orderController : ApiController
|
||||
else if (sortBy.Equals("u_name"))
|
||||
{
|
||||
if (sortDesc)
|
||||
qry = qry.OrderByDescending(o => o.follower?.u_name);
|
||||
qry = qry.OrderByDescending(o => o.follower != null ? o.follower.u_name : "");
|
||||
else
|
||||
qry = qry.OrderBy(o => o.follower?.u_name);
|
||||
qry = qry.OrderBy(o => o.follower != null ? o.follower.u_name : "");
|
||||
}
|
||||
else if (sortBy.Equals("subject"))
|
||||
{
|
||||
if (sortDesc)
|
||||
qry = qry.OrderByDescending(o => o.activity?.subject);
|
||||
qry = qry.OrderByDescending(o => o.activity != null ? o.activity.subject : "");
|
||||
else
|
||||
qry = qry.OrderBy(o => o.activity?.subject);
|
||||
qry = qry.OrderBy(o => o.activity != null ? o.activity.subject : "");
|
||||
}
|
||||
else
|
||||
qry = qry.OrderByDescending(o => o.reg_time);
|
||||
@@ -801,15 +801,15 @@ public class orderController : ApiController
|
||||
{
|
||||
|
||||
//家族 : 家長是我的人,跟我同家長的人,我的家長本人,我本人
|
||||
var cc = _db.followers.Where(x => x.num == _follower || x.leader == _follower).Select(x => x.num);
|
||||
var qry = _db.followers.AsEnumerable().Where(f => cc.Any(x => x == f.num) || cc.Any(x => x == f.leader));
|
||||
var ccList = _db.followers.Where(x => x.num == _follower || x.leader == _follower).Select(x => x.num).ToList();
|
||||
var qry = _db.followers.Where(f => ccList.Contains(f.num) || (f.leader.HasValue && ccList.Contains(f.leader.Value)));
|
||||
|
||||
//未付款資料
|
||||
var unpayDt = _db.pro_order_detail.AsEnumerable();
|
||||
var unpayDt = _db.pro_order_detail.AsQueryable();
|
||||
var coDt = unpayDt.Where(x => x.keyin1 == (int)Model.pro_order.detailKeyin1.Collection);//只列出報名狀態為"收款中"的項目
|
||||
|
||||
//未付款訂單
|
||||
var orderDt = _db.pro_order.AsEnumerable();
|
||||
var orderDt = _db.pro_order.AsQueryable();
|
||||
if (!string.IsNullOrEmpty(order_no))
|
||||
orderDt = orderDt.Where(x => x.order_no == order_no);
|
||||
orderDt = orderDt.Where(x => coDt.Select(d => d.order_no).Contains(x.order_no));
|
||||
@@ -855,7 +855,7 @@ public class orderController : ApiController
|
||||
{
|
||||
|
||||
//未付款資料
|
||||
var unpayDt = _db.pro_order_detail.AsEnumerable();
|
||||
var unpayDt = _db.pro_order_detail.AsQueryable();
|
||||
unpayDt = unpayDt.Where(x => x.keyin1 == (int)Model.pro_order.detailKeyin1.Collection);//只列出報名狀態為"收款中"的項目
|
||||
|
||||
if (!string.IsNullOrEmpty(q.order_no))
|
||||
@@ -1118,7 +1118,7 @@ public class orderController : ApiController
|
||||
[Route("api/order/DeleteRecordDetail/{id}")]//刪除收款註記
|
||||
public void DeleteRecordDetail(int id)
|
||||
{
|
||||
var prod = _db.pro_order_record.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.pro_order_record.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
|
||||
|
||||
@@ -27,14 +27,14 @@ public class orderdetailController:ApiController
|
||||
//var OrderList = _db.pro_order.Where(u => u.activity_num == activity_num).Select(j => j.order_no).ToList();
|
||||
//var gdzOrderList = _db.pro_order_detail.Where(o => OrderList.Contains(o.order_no) && o.print_id.Contains("主")).Select(o => o.order_no).Distinct().ToList();
|
||||
//var qry = _db.pro_order.Where(u => gdzOrderList.Contains(u.order_no)).AsEnumerable();
|
||||
var qry = _db.pro_order.Where( u => u.activity_num == activity_num).AsEnumerable();
|
||||
|
||||
qry = qry.OrderByDescending(o => o.reg_time);
|
||||
var qry = _db.pro_order.Where( u => u.activity_num == activity_num).OrderByDescending(o => o.reg_time);
|
||||
|
||||
var count = qry.Count(); //pageSize = count;//一次取回??
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
|
||||
var ret = new
|
||||
{
|
||||
list = qry.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
order_no = x.order_no,
|
||||
f_num = x.f_num,
|
||||
@@ -50,7 +50,7 @@ public class orderdetailController:ApiController
|
||||
|| u.actItem.subject.Contains("牌")
|
||||
|| !string.IsNullOrEmpty(u.f_num_tablet))
|
||||
.Count(),
|
||||
actItem = x.pro_order_detail.Where(u => u.printed_files != null).FirstOrDefault()?.print_id }
|
||||
actItem = x.pro_order_detail.Where(u => u.printed_files != null).Select(u => u.print_id).FirstOrDefault() }
|
||||
}),
|
||||
count = count
|
||||
};
|
||||
|
||||
250
web/App_Code/api/pivot01Controller.cs
Normal file
250
web/App_Code/api/pivot01Controller.cs
Normal file
@@ -0,0 +1,250 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Web.Http;
|
||||
using System.Configuration;
|
||||
|
||||
/// <summary>
|
||||
/// pivot01Controller - 法會報名統計分析 API
|
||||
/// 設計理念:直接查詢 SQL VIEW,保持彈性與簡潔
|
||||
/// </summary>
|
||||
[ezAuthorize]
|
||||
public class pivot01Controller : ApiController
|
||||
{
|
||||
// 連線字串
|
||||
private readonly string _connectionString;
|
||||
|
||||
public pivot01Controller()
|
||||
{
|
||||
// 優先使用 shopConn 連線字串(純 SQL Server 連線字串)
|
||||
var shopConnectionString = ConfigurationManager.ConnectionStrings["shopConn"]?.ConnectionString;
|
||||
if (!string.IsNullOrEmpty(shopConnectionString))
|
||||
{
|
||||
// 移除不相容的 Provider 參數(包含 SQLOLEDB 和 SQLNCLI11)
|
||||
_connectionString = shopConnectionString
|
||||
.Replace("Provider=SQLOLEDB;", "")
|
||||
.Replace("Provider=SQLNCLI11;", "")
|
||||
.Replace(" Provider=SQLOLEDB", "")
|
||||
.Replace(" Provider=SQLNCLI11", "");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 備用方案:從 Entity Framework 連線字串中提取 SQL Server 連線字串
|
||||
var efConnectionString = ConfigurationManager.ConnectionStrings["ezEntities"]?.ConnectionString;
|
||||
if (!string.IsNullOrEmpty(efConnectionString))
|
||||
{
|
||||
// 解析 EF 連線字串,提取 provider connection string 部分
|
||||
var startIndex = efConnectionString.IndexOf("provider connection string="") + "provider connection string="".Length;
|
||||
var endIndex = efConnectionString.LastIndexOf(""");
|
||||
if (startIndex > 0 && endIndex > startIndex)
|
||||
{
|
||||
_connectionString = efConnectionString.Substring(startIndex, endIndex - startIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("無法解析 Entity Framework 連線字串");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("找不到可用的資料庫連線字串");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region 通用 VIEW 查詢方法
|
||||
|
||||
/// <summary>
|
||||
/// 執行 SQL 查詢並回傳 DataTable
|
||||
/// </summary>
|
||||
/// <param name="sql">SQL 查詢語句</param>
|
||||
/// <param name="parameters">參數陣列</param>
|
||||
/// <returns>查詢結果 DataTable</returns>
|
||||
private DataTable ExecuteSqlQuery(string sql, SqlParameter[] parameters = null)
|
||||
{
|
||||
var dataTable = new DataTable();
|
||||
|
||||
try
|
||||
{
|
||||
using (var connection = new SqlConnection(_connectionString))
|
||||
using (var command = new SqlCommand(sql, connection))
|
||||
{
|
||||
// 設定逾時時間為 60 秒
|
||||
command.CommandTimeout = 60;
|
||||
|
||||
// 加入參數
|
||||
if (parameters != null && parameters.Length > 0)
|
||||
{
|
||||
command.Parameters.AddRange(parameters);
|
||||
}
|
||||
|
||||
// 開啟連線並執行查詢
|
||||
connection.Open();
|
||||
using (var adapter = new SqlDataAdapter(command))
|
||||
{
|
||||
adapter.Fill(dataTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SqlException ex)
|
||||
{
|
||||
throw new Exception($"SQL 查詢錯誤: {ex.Message}", ex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"執行查詢時發生錯誤: {ex.Message}", ex);
|
||||
}
|
||||
|
||||
return dataTable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DataTable 轉換為動態物件列表(保留中文欄位名)
|
||||
/// </summary>
|
||||
/// <param name="dt">DataTable</param>
|
||||
/// <returns>Dictionary 列表</returns>
|
||||
private List<Dictionary<string, object>> DataTableToDictionary(DataTable dt)
|
||||
{
|
||||
var list = new List<Dictionary<string, object>>();
|
||||
|
||||
foreach (DataRow row in dt.Rows)
|
||||
{
|
||||
var dict = new Dictionary<string, object>();
|
||||
foreach (DataColumn col in dt.Columns)
|
||||
{
|
||||
// 保留原始欄位名稱(包含中文)
|
||||
dict[col.ColumnName] = row[col] == DBNull.Value ? null : row[col];
|
||||
}
|
||||
list.Add(dict);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region API 端點
|
||||
|
||||
/// <summary>
|
||||
/// GET /api/pivot01/activity_stats
|
||||
/// 查詢法會統計(對應「法會統計」VIEW)
|
||||
/// </summary>
|
||||
/// <param name="year">查詢年份</param>
|
||||
/// <returns>法會統計資料</returns>
|
||||
[HttpGet]
|
||||
[Route("api/pivot01/activity_stats")]
|
||||
public IHttpActionResult GetActivityStats(int year)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 驗證年份參數
|
||||
if (year < 1900 || year > 2100)
|
||||
{
|
||||
return BadRequest("年份參數不正確,請輸入 1900 ~ 2100 之間的年份");
|
||||
}
|
||||
|
||||
// 建立 SQL 查詢(包含當年度及無日期的法會)
|
||||
string sql = @"
|
||||
SELECT * FROM [法會統計]
|
||||
WHERE (YEAR(開始日期) = @year OR 開始日期 IS NULL)
|
||||
ORDER BY
|
||||
CASE WHEN 開始日期 IS NULL THEN 1 ELSE 0 END,
|
||||
開始日期 DESC,
|
||||
結束日期 DESC
|
||||
";
|
||||
|
||||
// 建立參數
|
||||
var parameters = new[]
|
||||
{
|
||||
new SqlParameter("@year", SqlDbType.Int) { Value = year }
|
||||
};
|
||||
|
||||
// 執行查詢
|
||||
var dataTable = ExecuteSqlQuery(sql, parameters);
|
||||
var data = DataTableToDictionary(dataTable);
|
||||
|
||||
// 回應結果
|
||||
var result = new
|
||||
{
|
||||
success = true,
|
||||
data = data,
|
||||
message = "查詢成功",
|
||||
rowCount = data.Count
|
||||
};
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errorResponse = new
|
||||
{
|
||||
success = false,
|
||||
message = $"查詢失敗:{ex.Message}",
|
||||
error = ex.ToString()
|
||||
};
|
||||
return Content(System.Net.HttpStatusCode.BadRequest, errorResponse);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GET /api/pivot01/registration_details
|
||||
/// 查詢報名明細(對應「報名明細查詢」VIEW)
|
||||
/// </summary>
|
||||
/// <param name="activityNum">法會編號(必填)</param>
|
||||
/// <returns>報名明細資料</returns>
|
||||
[HttpGet]
|
||||
[Route("api/pivot01/registration_details")]
|
||||
public IHttpActionResult GetRegistrationDetails(int? activityNum = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 驗證參數
|
||||
if (!activityNum.HasValue || activityNum.Value <= 0)
|
||||
{
|
||||
return BadRequest("請提供有效的法會編號(activityNum)");
|
||||
}
|
||||
|
||||
// 建立查詢 SQL
|
||||
string sql = @"
|
||||
SELECT * FROM [報名明細查詢]
|
||||
WHERE 法會ID = @activityNum
|
||||
ORDER BY 報名日期 DESC, 報名編號 DESC
|
||||
";
|
||||
|
||||
// 建立參數
|
||||
var parameters = new[]
|
||||
{
|
||||
new SqlParameter("@activityNum", SqlDbType.Int) { Value = activityNum.Value }
|
||||
};
|
||||
|
||||
// 執行查詢
|
||||
var dataTable = ExecuteSqlQuery(sql, parameters);
|
||||
var data = DataTableToDictionary(dataTable);
|
||||
|
||||
// 回應結果
|
||||
var result = new
|
||||
{
|
||||
success = true,
|
||||
data = data,
|
||||
message = "查詢成功",
|
||||
rowCount = data.Count
|
||||
};
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var errorResponse = new
|
||||
{
|
||||
success = false,
|
||||
message = $"查詢失敗:{ex.Message}",
|
||||
error = ex.ToString()
|
||||
};
|
||||
return Content(System.Net.HttpStatusCode.BadRequest, errorResponse);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
1142
web/App_Code/api/pivotController.cs
Normal file
1142
web/App_Code/api/pivotController.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -48,7 +48,7 @@ public class projectController : BaseApiController
|
||||
// DELETE api/<controller>/5
|
||||
public void Delete(int id)
|
||||
{
|
||||
var prod = _db.projects.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.projects.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
_db.project_sub.RemoveRange(prod.project_sub); //刪除活動資料
|
||||
@@ -75,7 +75,7 @@ public class projectController : BaseApiController
|
||||
if (!string.IsNullOrEmpty(nums))
|
||||
{
|
||||
var ids = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s));
|
||||
var prod = _db.projects.AsEnumerable().Where(q => ids.Contains(q.num)).ToList();
|
||||
var prod = _db.projects.Where(q => ids.Contains(q.num)).ToList();
|
||||
if (prod.Count() > 0)
|
||||
{
|
||||
foreach (var item in prod)
|
||||
@@ -103,7 +103,7 @@ public class projectController : BaseApiController
|
||||
{
|
||||
if (id > 0)
|
||||
{
|
||||
var prod = _db.project_sub.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.project_sub.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
_db.project_sub.Remove(prod);
|
||||
@@ -117,7 +117,7 @@ public class projectController : BaseApiController
|
||||
public IHttpActionResult GetList([FromBody] Model.ViewModel.project q, int page, int pageSize = 10,
|
||||
string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.projects.AsEnumerable();
|
||||
var qry = _db.projects.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(q.subject))
|
||||
qry = qry.Where(o => o.subject.Contains(q.subject.Trim()));
|
||||
@@ -192,7 +192,7 @@ public class projectController : BaseApiController
|
||||
public IHttpActionResult GetKindList([FromBody] Model.ViewModel.project_kind q, int page, int pageSize = 10,
|
||||
string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.project_kind.AsEnumerable();
|
||||
var qry = _db.project_kind.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(q.kind))
|
||||
qry = qry.Where(o => o.kind.Contains(q.kind));
|
||||
@@ -247,7 +247,7 @@ public class projectController : BaseApiController
|
||||
|
||||
if (q.num.HasValue)
|
||||
{
|
||||
var qry = _db.project_sub.AsEnumerable();
|
||||
var qry = _db.project_sub.AsQueryable();
|
||||
|
||||
qry = qry.Where(o => o.pro_id == q.num.Value);
|
||||
|
||||
@@ -337,11 +337,11 @@ public class projectController : BaseApiController
|
||||
public IHttpActionResult GetPatronizeList([FromBody] Model.ViewModel.pro_order_detail q, int page, int pageSize = 10,
|
||||
string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var projectDt = _db.projects.AsEnumerable(); ;//專案
|
||||
var projectDt = _db.projects.AsQueryable(); ;//專案
|
||||
|
||||
try
|
||||
{
|
||||
var qry = _db.pro_order_detail.AsEnumerable();
|
||||
var qry = _db.pro_order_detail.AsQueryable();
|
||||
qry = qry.Where(o => (int?)o.actItem.category == (int)Model.activity.category.Patronize);
|
||||
|
||||
if (q.f_num.HasValue)
|
||||
|
||||
@@ -54,7 +54,7 @@ public class stockController : BaseApiController
|
||||
// DELETE api/<controller>/5
|
||||
public void Delete(int id)
|
||||
{
|
||||
var prod = _db.stocks.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.stocks.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
var prod2 = prod.stock_files;
|
||||
@@ -85,11 +85,11 @@ public class stockController : BaseApiController
|
||||
{
|
||||
if (!string.IsNullOrEmpty(nums))
|
||||
{
|
||||
var getDelItem = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s));
|
||||
var prod = _db.stocks.AsEnumerable().Where(q => getDelItem.Contains(q.num)).ToList();
|
||||
var getDelItem = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s)).ToList();
|
||||
var prod = _db.stocks.Where(q => getDelItem.Contains(q.num)).ToList();
|
||||
if (prod.Count() > 0)
|
||||
{
|
||||
var prod2 = _db.stock_files.AsEnumerable().Where(q => q.stock_num.HasValue && getDelItem.Contains(q.stock_num.Value)).ToList();
|
||||
var prod2 = _db.stock_files.Where(q => q.stock_num.HasValue && getDelItem.Contains(q.stock_num.Value)).ToList();
|
||||
if (prod2.Count() > 0)
|
||||
{
|
||||
publicFun publicFun = new publicFun();
|
||||
@@ -114,7 +114,7 @@ public class stockController : BaseApiController
|
||||
public IHttpActionResult GetList([FromBody] Model.ViewModel.stock q, int page, int pageSize = 10,
|
||||
string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.stocks.AsEnumerable();
|
||||
var qry = _db.stocks.AsQueryable();
|
||||
|
||||
if (q.category.HasValue)
|
||||
qry = qry.Where(o => o.category == q.category.Value);
|
||||
@@ -198,10 +198,12 @@ public class stockController : BaseApiController
|
||||
qry = qry.OrderByDescending(o => o.num);
|
||||
|
||||
var tdesc = publicFun.enum_desc<Model.stock.type>();
|
||||
var count = qry.Count();
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
|
||||
var ret = new
|
||||
{
|
||||
list = qry.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
num = x.num,
|
||||
category = x.category,
|
||||
@@ -230,7 +232,7 @@ public class stockController : BaseApiController
|
||||
price = x.price,
|
||||
|
||||
}),
|
||||
count = qry.Count()
|
||||
count = count
|
||||
|
||||
};
|
||||
|
||||
@@ -244,7 +246,7 @@ public class stockController : BaseApiController
|
||||
public IHttpActionResult GetKindList([FromBody] Model.ViewModel.stock_kind q, int page, int pageSize = 10,
|
||||
string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.stock_kind.AsEnumerable();
|
||||
var qry = _db.stock_kind.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(q.kind))
|
||||
qry = qry.Where(o => o.kind.Contains(q.kind));
|
||||
@@ -293,7 +295,7 @@ public class stockController : BaseApiController
|
||||
public IHttpActionResult GetReasonList([FromBody] Model.ViewModel.stock_reason q, int page, int pageSize = 10,
|
||||
string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.stock_reason.AsEnumerable();
|
||||
var qry = _db.stock_reason.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(q.kind))
|
||||
qry = qry.Where(o => o.kind.Contains(q.kind));
|
||||
@@ -335,15 +337,16 @@ public class stockController : BaseApiController
|
||||
if (q.stock_num.HasValue && q.stock_num.Value>0)
|
||||
{
|
||||
//檢查
|
||||
var qry = _db.stock_files.AsEnumerable();
|
||||
qry = qry.Where(o => o.stock_num == q.stock_num.Value);
|
||||
qry.OrderByDescending(x => x.num);
|
||||
var qry = _db.stock_files.Where(o => o.stock_num == q.stock_num.Value);
|
||||
qry = qry.OrderByDescending(x => x.num);
|
||||
|
||||
var count = qry.Count();
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
int i = 1;
|
||||
//已有值
|
||||
var ret = new
|
||||
{
|
||||
list = qry.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
id = i++,
|
||||
num = x.num,
|
||||
@@ -351,7 +354,7 @@ public class stockController : BaseApiController
|
||||
pic1 = x.pic1,
|
||||
pic1_name = x.pic1_name,
|
||||
}),
|
||||
count = qry.Count(),
|
||||
count = count,
|
||||
};
|
||||
|
||||
if (ret.list == null) throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
@@ -466,7 +469,7 @@ public class stockController : BaseApiController
|
||||
[Route("api/stock/DeleteFilesItem/{id}")]//刪除相關檔案
|
||||
public void DeleteFilesItem(int id)
|
||||
{
|
||||
var prod = _db.stock_files.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.stock_files.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(prod.pic1))
|
||||
|
||||
@@ -50,7 +50,7 @@ public class supplierController : BaseApiController
|
||||
// DELETE api/<controller>/5
|
||||
public void Delete(int id)
|
||||
{
|
||||
var prod = _db.suppliers.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.suppliers.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(prod.pic1))
|
||||
@@ -80,8 +80,8 @@ public class supplierController : BaseApiController
|
||||
{
|
||||
if (!string.IsNullOrEmpty(nums))
|
||||
{
|
||||
var ids = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s));
|
||||
var prod = _db.suppliers.AsEnumerable().Where(q => ids.Contains(q.num)).ToList();
|
||||
var ids = nums.TrimEnd(',').Split(',').Select(s => int.Parse(s)).ToList();
|
||||
var prod = _db.suppliers.Where(q => ids.Contains(q.num)).ToList();
|
||||
if (prod.Count() > 0)
|
||||
{
|
||||
publicFun publicFun = new publicFun();
|
||||
@@ -113,7 +113,7 @@ public class supplierController : BaseApiController
|
||||
public IHttpActionResult GetList([FromBody] Model.ViewModel.supplier q, int page, int pageSize = 10,
|
||||
string sortBy = "", bool sortDesc = false)
|
||||
{
|
||||
var qry = _db.suppliers.AsEnumerable();
|
||||
var qry = _db.suppliers.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(q.u_name))
|
||||
qry = qry.Where(o => o.u_name.Contains(q.u_name.Trim()));
|
||||
@@ -159,9 +159,12 @@ public class supplierController : BaseApiController
|
||||
else
|
||||
qry = qry.OrderByDescending(o => o.num);
|
||||
|
||||
var count = qry.Count();
|
||||
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
|
||||
|
||||
var ret = new
|
||||
{
|
||||
list = qry.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qryList.Select(x => new
|
||||
{
|
||||
num = x.num,
|
||||
u_name = x.u_name,
|
||||
@@ -176,7 +179,7 @@ public class supplierController : BaseApiController
|
||||
}).ToList(), x.kind) : "",
|
||||
|
||||
}),
|
||||
count = qry.Count()
|
||||
count = count
|
||||
|
||||
};
|
||||
|
||||
@@ -192,7 +195,7 @@ public class supplierController : BaseApiController
|
||||
{
|
||||
|
||||
|
||||
var qry = _db.supplier_kind.AsEnumerable();
|
||||
var qry = _db.supplier_kind.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(q.kind))
|
||||
qry = qry.Where(o => o.kind.Contains(q.kind));
|
||||
@@ -205,17 +208,18 @@ public class supplierController : BaseApiController
|
||||
range = o.range,
|
||||
}).OrderBy(x => x.root).ThenBy(x => x.kind).ToList(), 0, 0);
|
||||
|
||||
|
||||
var count = qry.Count();
|
||||
var qry2List = (pageSize > 0) ? qry2.ToPagedList(page, pageSize).ToList() : qry2.ToList();
|
||||
|
||||
var ret = new
|
||||
{
|
||||
list = qry2.ToPagedList(page, pageSize).Select(x => new
|
||||
list = qry2List.Select(x => new
|
||||
{
|
||||
num = x.num,
|
||||
kind = new TreeView().RptDash(x.Level) + x.kind,
|
||||
|
||||
}),
|
||||
count = qry.Count()
|
||||
count = count
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -237,7 +237,7 @@ public class transfer_registerController : ApiController
|
||||
x.draft,
|
||||
follower = x.f_num != null ? _db.followers
|
||||
.Where(f => f.num == x.f_num)
|
||||
.AsEnumerable()
|
||||
.ToList()
|
||||
.Select(f => new {
|
||||
f.num,
|
||||
f.u_name,
|
||||
@@ -399,6 +399,7 @@ public class transfer_registerController : ApiController
|
||||
[Route("api/transfer_register/follower_orders")]
|
||||
public IHttpActionResult GetFollowerOrders(int f_num)
|
||||
{
|
||||
// TODO: 優化建議 - 考慮加入分頁或日期範圍限制,避免單一信眾訂單過多時載入大量數據
|
||||
// 取得該信眾的所有訂單及明細,並關聯活動名稱與品項名稱
|
||||
var details = _db.pro_order
|
||||
.Where(o => o.f_num == f_num)
|
||||
@@ -417,7 +418,7 @@ public class transfer_registerController : ApiController
|
||||
d.demo,
|
||||
reg_time = o.reg_time // 報名日期
|
||||
}))
|
||||
.AsEnumerable()
|
||||
.AsEnumerable() // 只在需要內存計算前轉換
|
||||
.Select(x => new {
|
||||
x.order_no,
|
||||
x.activity_num,
|
||||
@@ -481,7 +482,7 @@ public class transfer_registerController : ApiController
|
||||
x.draft,
|
||||
follower = x.f_num != null ? _db.followers
|
||||
.Where(f => f.num == x.f_num)
|
||||
.AsEnumerable()
|
||||
.ToList()
|
||||
.Select(f => new {
|
||||
f.num,
|
||||
f.u_name,
|
||||
@@ -817,7 +818,7 @@ public class transfer_registerController : ApiController
|
||||
tr.balance_act_item,
|
||||
balance_actitem_name = tr.balance_act_item != null ? _db.actItems.Where(a => a.num == tr.balance_act_item).Select(a => a.subject).FirstOrDefault() : ""
|
||||
})
|
||||
.AsEnumerable()
|
||||
.ToList()
|
||||
.Select(tr => new
|
||||
{
|
||||
tr.id,
|
||||
@@ -1044,6 +1045,9 @@ public class transfer_registerController : ApiController
|
||||
[Route("api/transfer_register/activity_followers")]
|
||||
public IHttpActionResult GetActivityFollowers(int activity_num)
|
||||
{
|
||||
// TODO: 性能優化 - 大型活動可能有數千筆訂單,建議:
|
||||
// 1. 在數據庫層面先過濾出未完成沖帳項目(避免載入所有訂單)
|
||||
// 2. 考慮加入 Take() 限制返回數量,或實作分頁
|
||||
// 查詢該法會中有報名單且有未完成沖帳項目的信眾
|
||||
var followers = _db.pro_order
|
||||
.Where(o => o.activity_num == activity_num)
|
||||
@@ -1054,7 +1058,7 @@ public class transfer_registerController : ApiController
|
||||
d.price,
|
||||
paid = d.pro_order_record.Select(r => r.price).DefaultIfEmpty(0).Sum()
|
||||
}))
|
||||
.AsEnumerable()
|
||||
.AsEnumerable() // 只在需要內存計算前轉換
|
||||
.Select(x => new {
|
||||
x.f_num,
|
||||
x.follower_name,
|
||||
@@ -1104,7 +1108,7 @@ public class transfer_registerController : ApiController
|
||||
d.demo,
|
||||
reg_time = o.reg_time // 報名日期
|
||||
}))
|
||||
.AsEnumerable()
|
||||
.ToList()
|
||||
.Select(x => new {
|
||||
x.order_no,
|
||||
x.activity_num,
|
||||
|
||||
@@ -55,17 +55,17 @@ public class apporderController : ApiController
|
||||
// DELETE api/<controller>/5
|
||||
public void Delete(string id)
|
||||
{
|
||||
var prod = _db.pro_order.AsEnumerable().Where(q => q.order_no == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.pro_order.Where(q => q.order_no == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
//刪除掛單表單
|
||||
var prod3 = _db.bed_order.AsEnumerable().Where(q => q.order_no == id).ToList();
|
||||
var prod3 = _db.bed_order.Where(q => q.order_no == id).ToList();
|
||||
if (prod3.Count > 0)
|
||||
{
|
||||
//刪除掛單明細
|
||||
foreach (var item3 in prod3)
|
||||
{
|
||||
var prod4 = _db.bed_order_detail.AsEnumerable().Where(q => q.bed_order_no == item3.bed_order_no).ToList();
|
||||
var prod4 = _db.bed_order_detail.Where(q => q.bed_order_no == item3.bed_order_no).ToList();
|
||||
if (prod4.Count > 0)
|
||||
{
|
||||
_db.bed_order_detail.RemoveRange(prod4); //查詢結果全部刪除
|
||||
@@ -97,17 +97,17 @@ public class apporderController : ApiController
|
||||
{
|
||||
if (id > 0)
|
||||
{
|
||||
var prod = _db.pro_order_detail.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.pro_order_detail.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
//刪除掛單表單
|
||||
var prod3 = _db.bed_order.AsEnumerable().Where(q => q.order_no == prod.order_no).ToList();
|
||||
var prod3 = _db.bed_order.Where(q => q.order_no == prod.order_no).ToList();
|
||||
if (prod3.Count > 0) //count = 1
|
||||
{
|
||||
//刪除掛單明細
|
||||
foreach (var item3 in prod3)
|
||||
{
|
||||
var prod4 = _db.bed_order_detail.AsEnumerable().Where(q => q.bed_order_no == item3.bed_order_no).ToList();
|
||||
var prod4 = _db.bed_order_detail.Where(q => q.bed_order_no == item3.bed_order_no).ToList();
|
||||
if (prod4.Count > 0)
|
||||
{
|
||||
_db.bed_order_detail.RemoveRange(prod4); //查詢結果全部刪除
|
||||
@@ -132,20 +132,20 @@ public class apporderController : ApiController
|
||||
{
|
||||
var ids = nums.TrimEnd(',').Split(',');
|
||||
|
||||
var prod = _db.pro_order.AsEnumerable().Where(q => ids.Contains(q.order_no)).ToList();
|
||||
var prod = _db.pro_order.Where(q => ids.Contains(q.order_no)).ToList();
|
||||
if (prod.Count() > 0)
|
||||
{
|
||||
var prod2 = _db.pro_order_detail.AsEnumerable().Where(q => ids.Contains(Convert.ToString(q.order_no))).ToList();
|
||||
var prod2 = _db.pro_order_detail.Where(q => ids.Contains(Convert.ToString(q.order_no))).ToList();
|
||||
if (prod2.Count > 0)
|
||||
{
|
||||
foreach (var item2 in prod2)
|
||||
{
|
||||
var prod3 = _db.bed_order.AsEnumerable().Where(q => q.order_no == item2.order_no && q.o_detail_id == item2.num).ToList();
|
||||
var prod3 = _db.bed_order.Where(q => q.order_no == item2.order_no && q.o_detail_id == item2.num).ToList();
|
||||
if (prod3.Count > 0)
|
||||
{
|
||||
foreach (var item3 in prod3)
|
||||
{
|
||||
var prod4 = _db.bed_order_detail.AsEnumerable().Where(q => q.bed_order_no == item3.bed_order_no).ToList();
|
||||
var prod4 = _db.bed_order_detail.Where(q => q.bed_order_no == item3.bed_order_no).ToList();
|
||||
if (prod4.Count > 0)
|
||||
{
|
||||
_db.bed_order_detail.RemoveRange(prod4);
|
||||
@@ -156,8 +156,8 @@ public class apporderController : ApiController
|
||||
}
|
||||
|
||||
|
||||
//var prod32 = _db.bed_order.AsEnumerable().Where(q => q.order_no == item2.order_no && q.o_detail_id == item2.num).ToList();
|
||||
//var prod42 = _db.bed_order_detail.AsEnumerable().Where(q => prod32.Select(qf => qf.order_no).ToArray().Contains(q.bed_order_no)).ToList();
|
||||
//var prod32 = _db.bed_order.Where(q => q.order_no == item2.order_no && q.o_detail_id == item2.num).ToList();
|
||||
//var prod42 = _db.bed_order_detail.Where(q => prod32.Select(qf => qf.order_no).ToArray().Contains(q.bed_order_no)).ToList();
|
||||
//_db.bed_order_detail.RemoveRange(prod42);
|
||||
//_db.bed_order.RemoveRange(prod32);
|
||||
|
||||
@@ -200,7 +200,7 @@ public class apporderController : ApiController
|
||||
{
|
||||
|
||||
var qry = _db.pro_order.AsEnumerable();
|
||||
//var aIDt = _db.actItems.AsEnumerable().Where(f => f.subject.Contains(q.actItemTxt.Trim())).Select(f => f.num);//品項
|
||||
//var aIDt = _db.actItems.Where(f => f.subject.Contains(q.actItemTxt.Trim())).Select(f => f.num);//品項
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(q.order_no))
|
||||
@@ -218,32 +218,32 @@ public class apporderController : ApiController
|
||||
if (!string.IsNullOrEmpty(q.address))
|
||||
qry = qry.Where(o => o.address.Contains(q.address.Trim()));
|
||||
if (!string.IsNullOrEmpty(q.subject))
|
||||
qry = qry.Where(o => o.activity_num.HasValue && o.activity.subject.Contains(q.subject?.Trim()));
|
||||
qry = qry.Where(o => o.activity_num.HasValue && o.activity.subject.Contains(q.subject.Trim()));
|
||||
if (!string.IsNullOrEmpty(q.u_name))
|
||||
qry = qry.Where(o => o.f_num.HasValue && o.follower.u_name.Contains(q.u_name?.Trim()));
|
||||
qry = qry.Where(o => o.f_num.HasValue && o.follower.u_name.Contains(q.u_name.Trim()));
|
||||
if (!string.IsNullOrEmpty(q.introducerTxt))
|
||||
qry = qry.Where(o => o.introducer.HasValue && o.follower1.u_name.Contains(q.introducerTxt?.Trim()));
|
||||
qry = qry.Where(o => o.introducer.HasValue && o.follower1.u_name.Contains(q.introducerTxt.Trim()));
|
||||
|
||||
if (!string.IsNullOrEmpty(q.actItemTxt))
|
||||
{
|
||||
//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);
|
||||
// qry = qry.Where(o => o.pro_order_detail.Where(f2 => f2.order_no == o.order_no && aIDt.Any(x => x == f2.actItem_num)).Count() > 0);
|
||||
|
||||
qry = qry.Where(o => o.pro_order_detail.Where(f2 => f2.actItem_num.HasValue && f2.actItem.subject.Contains(q.actItemTxt?.Trim())).Count() > 0);
|
||||
qry = qry.Where(o => o.pro_order_detail.Where(f2 => f2.actItem_num.HasValue && f2.actItem.subject.Contains(q.actItemTxt.Trim())).Count() > 0);
|
||||
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(q.country))
|
||||
qry = qry.Where(o => o.f_num != null && o.follower?.country == q.country);
|
||||
qry = qry.Where(o => o.f_num != null && o.follower != null && o.follower.country == q.country);
|
||||
if (!string.IsNullOrEmpty(q.country2))
|
||||
{
|
||||
if (q.country2 == "1")
|
||||
{
|
||||
qry = qry.Where(o => o.f_num != null && o.follower?.country == "158");
|
||||
qry = qry.Where(o => o.f_num != null && o.follower != null && o.follower.country == "158");
|
||||
}
|
||||
else if (q.country2 == "2")
|
||||
{
|
||||
qry = qry.Where(o => o.f_num != null && o.follower?.country != "158");
|
||||
qry = qry.Where(o => o.f_num != null && o.follower != null && o.follower.country != "158");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -317,11 +317,11 @@ public class apporderController : ApiController
|
||||
if (!string.IsNullOrEmpty( order_no ))
|
||||
{
|
||||
//檢查
|
||||
var prod = _db.pro_order.AsEnumerable().Where(o => o.order_no == order_no).FirstOrDefault();
|
||||
var prod = _db.pro_order.Where(o => o.order_no == order_no).FirstOrDefault();
|
||||
if (prod != null)
|
||||
{
|
||||
int activity = prod.activity_num.HasValue ? prod.activity_num.Value : 0; //活動
|
||||
var bedDt = _db.bed_order_detail.AsEnumerable().Where(b=>b.bed_order.order_no== order_no ); ;//掛單明細
|
||||
var bedDt = _db.bed_order_detail.Where(b=>b.bed_order.order_no== order_no ); ;//掛單明細
|
||||
|
||||
|
||||
//var qry1 = _db.pro_order_detail.AsEnumerable();
|
||||
@@ -435,7 +435,7 @@ public class apporderController : ApiController
|
||||
if (activity > 0)
|
||||
{
|
||||
i = 1;
|
||||
var qry2 = _db.activity_relating.AsEnumerable();
|
||||
var qry2 = _db.activity_relating.AsQueryable();
|
||||
qry2 = qry2.Where(o => o.activity_num == activity);
|
||||
|
||||
if (q.actItem_kind_num.HasValue)
|
||||
@@ -690,14 +690,14 @@ public class apporderController : ApiController
|
||||
|
||||
//家族 : 家長是我的人,跟我同家長的人,我的家長本人,我本人
|
||||
var cc = _db.followers.Where(x => x.num == _follower || x.leader == _follower).Select(x => x.num);
|
||||
var qry = _db.followers.AsEnumerable().Where(f => cc.Any(x => x == f.num) || cc.Any(x => x == f.leader));
|
||||
var qry = _db.followers.Where(f => cc.Any(x => x == f.num) || cc.Any(x => x == f.leader));
|
||||
|
||||
//未付款資料
|
||||
var unpayDt = _db.pro_order_detail.AsEnumerable();
|
||||
var unpayDt = _db.pro_order_detail.AsQueryable();
|
||||
var coDt = unpayDt.Where(x => x.keyin1 == (int)Model.pro_order.detailKeyin1.Collection);//只列出報名狀態為"收款中"的項目
|
||||
|
||||
//未付款訂單
|
||||
var orderDt = _db.pro_order.AsEnumerable();
|
||||
var orderDt = _db.pro_order.AsQueryable();
|
||||
if (!string.IsNullOrEmpty(order_no))
|
||||
orderDt = orderDt.Where(x => x.order_no == order_no);
|
||||
orderDt = orderDt.Where(x => coDt.Select(d => d.order_no).Contains(x.order_no));
|
||||
@@ -737,7 +737,7 @@ public class apporderController : ApiController
|
||||
{
|
||||
|
||||
//未付款資料
|
||||
var unpayDt = _db.pro_order_detail.AsEnumerable();
|
||||
var unpayDt = _db.pro_order_detail.AsQueryable();
|
||||
unpayDt = unpayDt.Where(x => x.keyin1 == (int)Model.pro_order.detailKeyin1.Collection);//只列出報名狀態為"收款中"的項目
|
||||
|
||||
if (!string.IsNullOrEmpty(q.order_no))
|
||||
@@ -865,10 +865,10 @@ public class apporderController : ApiController
|
||||
if (u_name >0 && (!string.IsNullOrEmpty(q.order_no)))
|
||||
{
|
||||
//檢查
|
||||
var prod = _db.pro_order.AsEnumerable().Where(o => o.f_num == u_name && o.order_no != q.order_no).ToList();
|
||||
var prod = _db.pro_order.Where(o => o.f_num == u_name && o.order_no != q.order_no).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
var qry = _db.pro_order_detail.AsEnumerable().Where(o => prod.Any(x => x.order_no==o.order_no) );
|
||||
var qry = _db.pro_order_detail.Where(o => prod.Any(x => x.order_no==o.order_no) );
|
||||
int i = 1;
|
||||
var ret = new
|
||||
{
|
||||
@@ -942,7 +942,7 @@ public class apporderController : ApiController
|
||||
if (detail_num > 0 )
|
||||
{
|
||||
//檢查
|
||||
var prod = _db.pro_order_record.AsEnumerable().Where(o => o.detail_num == detail_num )
|
||||
var prod = _db.pro_order_record.Where(o => o.detail_num == detail_num )
|
||||
.OrderByDescending(o=>o.pay_date).ToList();
|
||||
int i = 1;
|
||||
var ret = new
|
||||
@@ -979,7 +979,7 @@ public class apporderController : ApiController
|
||||
[Route("api/apporder/DeleteRecordDetail/{id}")]//刪除收款註記
|
||||
public void DeleteRecordDetail(int id)
|
||||
{
|
||||
var prod = _db.pro_order_record.AsEnumerable().Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.pro_order_record.Where(q => q.num == id).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
|
||||
@@ -995,8 +995,8 @@ public class apporderController : ApiController
|
||||
{
|
||||
if (item.detail_num > 0)
|
||||
{
|
||||
float total = _db.pro_order_detail.AsEnumerable().Where(x => x.num == item.detail_num).Select(x => x.price.Value * x.qty.Value).Sum();
|
||||
float pay = _db.pro_order_record.AsEnumerable().Where(x => x.detail_num == item.detail_num).Select(x => x.price.Value).Sum();
|
||||
float total = _db.pro_order_detail.Where(x => x.num == item.detail_num).Select(x => x.price.Value * x.qty.Value).Sum();
|
||||
float pay = _db.pro_order_record.Where(x => x.detail_num == item.detail_num).Select(x => x.price.Value).Sum();
|
||||
|
||||
if (pay + item.price.Value <= total)
|
||||
{
|
||||
|
||||
@@ -130,7 +130,8 @@ public partial class admin_hr_import : MyWeb.config
|
||||
);
|
||||
sd2.AppendChild(tr);
|
||||
//查詢要匯出的資料
|
||||
var list = _db.member_group.AsEnumerable().ToList();
|
||||
// TODO: REVIEW - member_group 為固定少量資料表,ToList() 可接受
|
||||
var list = _db.member_group.ToList();
|
||||
if (list.Count > 0)
|
||||
{
|
||||
foreach (var item in list)
|
||||
@@ -178,7 +179,8 @@ public partial class admin_hr_import : MyWeb.config
|
||||
);
|
||||
sd3.AppendChild(tr);
|
||||
//查詢要匯出的資料
|
||||
var list2 = _db.member_title.AsEnumerable().ToList();
|
||||
// TODO: REVIEW - member_title 為固定少量資料表,ToList() 可接受
|
||||
var list2 = _db.member_title.ToList();
|
||||
if (list2.Count > 0)
|
||||
{
|
||||
foreach (var item in list2)
|
||||
@@ -229,10 +231,16 @@ public partial class admin_hr_import : MyWeb.config
|
||||
startRowNumber += 1;
|
||||
}
|
||||
|
||||
var fDt = _db.followers.AsEnumerable().ToList(); //信眾
|
||||
var aDt = _db.admins.AsEnumerable().ToList(); //後台系統
|
||||
var gDt = _db.member_group.AsEnumerable().Select(x => x.num).ToList(); //組別
|
||||
var tDt = _db.member_title.AsEnumerable().Select(x => x.num).ToList(); //職稱
|
||||
// TODO: REVIEW - 整表載入性能評估:
|
||||
// - followers (信眾) ⚠️ 會成長!若超過 1000 筆需優化為按需載入(先掃描 Excel 收集編號)
|
||||
// - admins (管理員) ✓ 通常少量,ToList() 可接受
|
||||
// - member_group (組別) ✓ 固定少量,可接受
|
||||
// - member_title (職稱) ✓ 固定少量,可接受
|
||||
// 優化方案:先掃描 Excel → 只載入需要的編號 → 使用 Dictionary 加速查找(O(1) vs O(n))
|
||||
var fDt = _db.followers.ToList(); //信眾
|
||||
var aDt = _db.admins.ToList(); //後台系統
|
||||
var gDt = _db.member_group.Select(x => x.num).ToList(); //組別
|
||||
var tDt = _db.member_title.Select(x => x.num).ToList(); //職稱
|
||||
MyWeb.encrypt encrypt = new MyWeb.encrypt();
|
||||
|
||||
for (int currentRow = startRowNumber; currentRow <= endRowNumber; currentRow++)
|
||||
|
||||
@@ -27,7 +27,6 @@ public partial class admin_hr_kind_reg : MyWeb.config
|
||||
if (!isStrNull(Request["num"]))
|
||||
{
|
||||
int _num = Val(Request["num"]);
|
||||
var qry = _db.member_group.AsEnumerable();
|
||||
var prod = _db.member_group.Where(q => q.num == _num).OrderBy(q => q.kind).FirstOrDefault();
|
||||
if (prod != null)
|
||||
{
|
||||
@@ -70,7 +69,6 @@ public partial class admin_hr_kind_reg : MyWeb.config
|
||||
|
||||
protected void TreeTopology()
|
||||
{
|
||||
var qry = _db.member_group.AsEnumerable();
|
||||
var prod = _db.member_group.ToList();
|
||||
//treeDt = prod.CopyToDataTable();
|
||||
|
||||
@@ -235,7 +233,7 @@ public partial class admin_hr_kind_reg : MyWeb.config
|
||||
|
||||
try
|
||||
{
|
||||
var prod = _db.member_group.AsEnumerable().Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
var prod = _db.member_group.Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
if (prod != null)
|
||||
if (prod.range.HasValue)
|
||||
range = prod.range.Value + 1;
|
||||
@@ -281,7 +279,7 @@ public partial class admin_hr_kind_reg : MyWeb.config
|
||||
del_product(num);
|
||||
|
||||
|
||||
var prod = _db.member_group.AsEnumerable().Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.member_group.Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
_db.member_group.Remove(prod);
|
||||
@@ -302,7 +300,7 @@ public partial class admin_hr_kind_reg : MyWeb.config
|
||||
|
||||
public void Del_Ohter_Items(int d_num)
|
||||
{
|
||||
var prod = _db.member_group.AsEnumerable().Where(q => q.root == d_num).ToList();
|
||||
var prod = _db.member_group.Where(q => q.root == d_num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
foreach (var row in prod)
|
||||
@@ -319,7 +317,7 @@ public partial class admin_hr_kind_reg : MyWeb.config
|
||||
}
|
||||
public void del_product(int num)
|
||||
{
|
||||
var prod = _db.members.AsEnumerable().Where(q => q.group_kind == num).ToList();
|
||||
var prod = _db.members.Where(q => q.group_kind == num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
//清空組別分類
|
||||
|
||||
@@ -22,7 +22,6 @@ public partial class admin_hr_kind_reg : MyWeb.config
|
||||
if (!isStrNull(Request["num"]))
|
||||
{
|
||||
int _num = Val(Request["num"]);
|
||||
var qry = _db.member_title.AsEnumerable();
|
||||
var prod = _db.member_title.Where(q => q.num == _num).OrderBy(q => q.kind).FirstOrDefault();
|
||||
if (prod != null)
|
||||
{
|
||||
@@ -207,7 +206,7 @@ public partial class admin_hr_kind_reg : MyWeb.config
|
||||
}
|
||||
try
|
||||
{
|
||||
var prod = _db.member_title.AsEnumerable().Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
var prod = _db.member_title.Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
if (prod != null)
|
||||
if (prod.range.HasValue)
|
||||
range = prod.range.Value + 1;
|
||||
@@ -248,7 +247,7 @@ public partial class admin_hr_kind_reg : MyWeb.config
|
||||
int num = Val(Request["num"]);
|
||||
del_product(num);
|
||||
|
||||
var prod = _db.member_title.AsEnumerable().Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.member_title.Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
_db.member_title.Remove(prod);
|
||||
@@ -269,7 +268,7 @@ public partial class admin_hr_kind_reg : MyWeb.config
|
||||
|
||||
public void Del_Ohter_Items(int d_num)
|
||||
{
|
||||
var prod = _db.member_title.AsEnumerable().Where(q => q.root == d_num).ToList();
|
||||
var prod = _db.member_title.Where(q => q.root == d_num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
foreach (var row in prod)
|
||||
@@ -286,7 +285,7 @@ public partial class admin_hr_kind_reg : MyWeb.config
|
||||
|
||||
public void del_product(int num)
|
||||
{
|
||||
var prod = _db.members.AsEnumerable().Where(q => q.title_kind == num).ToList();
|
||||
var prod = _db.members.Where(q => q.title_kind == num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
//清空分類
|
||||
|
||||
@@ -21,7 +21,7 @@ public partial class admin_accounting_kind_reg : MyWeb.config
|
||||
if (!isStrNull(Request["num"]))
|
||||
{
|
||||
int _num = Val(Request["num"]);
|
||||
var prod = _db.accounting_kind.AsEnumerable().Where(q => q.num == _num).OrderBy(q => q.kind).FirstOrDefault();
|
||||
var prod = _db.accounting_kind.Where(q => q.num == _num).OrderBy(q => q.kind).FirstOrDefault();
|
||||
|
||||
if (prod != null)
|
||||
{
|
||||
@@ -215,7 +215,7 @@ public partial class admin_accounting_kind_reg : MyWeb.config
|
||||
|
||||
try
|
||||
{
|
||||
var prod = _db.accounting_kind.AsEnumerable().Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
var prod = _db.accounting_kind.Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
if (prod != null)
|
||||
if (prod.range.HasValue)
|
||||
range = prod.range.Value + 1;
|
||||
@@ -254,7 +254,7 @@ public partial class admin_accounting_kind_reg : MyWeb.config
|
||||
int num = Val(Request["num"]);
|
||||
del_product(num);
|
||||
|
||||
var prod = _db.accounting_kind.AsEnumerable().Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.accounting_kind.Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
_db.accounting_kind.Remove(prod);
|
||||
@@ -272,7 +272,7 @@ public partial class admin_accounting_kind_reg : MyWeb.config
|
||||
|
||||
public void Del_Ohter_Items(int d_num)
|
||||
{
|
||||
var prod = _db.accounting_kind.AsEnumerable().Where(q => q.root == d_num).ToList();
|
||||
var prod = _db.accounting_kind.Where(q => q.root == d_num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
foreach (var row in prod)
|
||||
@@ -291,7 +291,7 @@ public partial class admin_accounting_kind_reg : MyWeb.config
|
||||
public void del_product(int num)
|
||||
{
|
||||
|
||||
var prod = _db.accountings.AsEnumerable().Where(q => q.kind == num).ToList();
|
||||
var prod = _db.accountings.Where(q => q.kind == num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
////查詢結果全部刪除
|
||||
|
||||
@@ -21,7 +21,7 @@ public partial class admin_accounting_kind_reg2 : MyWeb.config
|
||||
if (!isStrNull(Request["num"]))
|
||||
{
|
||||
int _num = Val(Request["num"]);
|
||||
var prod = _db.accounting_kind2.AsEnumerable().Where(q => q.num == _num).FirstOrDefault();
|
||||
var prod = _db.accounting_kind2.Where(q => q.num == _num).FirstOrDefault();
|
||||
|
||||
if (prod != null)
|
||||
{
|
||||
@@ -228,7 +228,7 @@ public partial class admin_accounting_kind_reg2 : MyWeb.config
|
||||
|
||||
try
|
||||
{
|
||||
var prod = _db.accounting_kind2.AsEnumerable().Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
var prod = _db.accounting_kind2.Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
if (prod != null)
|
||||
if (prod.range.HasValue)
|
||||
range = prod.range.Value + 1;
|
||||
@@ -271,7 +271,7 @@ public partial class admin_accounting_kind_reg2 : MyWeb.config
|
||||
int num = Val(Request["num"]);
|
||||
del_product(num);
|
||||
|
||||
var prod = _db.accounting_kind2.AsEnumerable().Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.accounting_kind2.Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
_db.accounting_kind2.Remove(prod);
|
||||
@@ -288,7 +288,7 @@ public partial class admin_accounting_kind_reg2 : MyWeb.config
|
||||
|
||||
public void Del_Ohter_Items(int d_num)
|
||||
{
|
||||
var prod = _db.accounting_kind2.AsEnumerable().Where(q => q.root == d_num).ToList();
|
||||
var prod = _db.accounting_kind2.Where(q => q.root == d_num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
foreach (var row in prod)
|
||||
@@ -306,7 +306,7 @@ public partial class admin_accounting_kind_reg2 : MyWeb.config
|
||||
|
||||
public void del_product(int num)
|
||||
{
|
||||
var prod = _db.accountings.AsEnumerable().Where(q => q.kind2 == num).ToList();
|
||||
var prod = _db.accountings.Where(q => q.kind2 == num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
////查詢結果全部刪除
|
||||
|
||||
@@ -21,7 +21,7 @@ public partial class admin_activity_itemKind : MyWeb.config
|
||||
if (!isStrNull(Request["num"]))
|
||||
{
|
||||
int _num = Val(Request["num"]);
|
||||
var prod = _db.actItem_kind.AsEnumerable().Where(q => q.num == _num).OrderBy(q => q.kind).FirstOrDefault();
|
||||
var prod = _db.actItem_kind.Where(q => q.num == _num).OrderBy(q => q.kind).FirstOrDefault();
|
||||
|
||||
if (prod != null)
|
||||
{
|
||||
@@ -214,7 +214,7 @@ public partial class admin_activity_itemKind : MyWeb.config
|
||||
|
||||
try
|
||||
{
|
||||
var prod = _db.actItem_kind.AsEnumerable().Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
var prod = _db.actItem_kind.Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
if (prod != null)
|
||||
if (prod.range.HasValue)
|
||||
range = prod.range.Value + 1;
|
||||
@@ -252,7 +252,7 @@ public partial class admin_activity_itemKind : MyWeb.config
|
||||
|
||||
int num = Val(Request["num"]);
|
||||
del_product(num);
|
||||
var prod = _db.actItem_kind.AsEnumerable().Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.actItem_kind.Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
|
||||
@@ -271,7 +271,7 @@ public partial class admin_activity_itemKind : MyWeb.config
|
||||
|
||||
public void Del_Ohter_Items(int d_num)
|
||||
{
|
||||
var prod = _db.actItem_kind.AsEnumerable().Where(q => q.root == d_num).ToList();
|
||||
var prod = _db.actItem_kind.Where(q => q.root == d_num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
foreach (var row in prod)
|
||||
@@ -289,7 +289,7 @@ public partial class admin_activity_itemKind : MyWeb.config
|
||||
|
||||
public void del_product(int num)
|
||||
{
|
||||
var prod = _db.actItems.AsEnumerable().Where(q => q.kind == num).ToList();
|
||||
var prod = _db.actItems.Where(q => q.kind == num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
//清空分類
|
||||
|
||||
@@ -24,7 +24,7 @@ public partial class admin_activity_kind_reg : MyWeb.config
|
||||
{
|
||||
_this_id = ValString(Request["num"]);
|
||||
int _num = Val(Request["num"]);
|
||||
var prod = _db.activity_kind.AsEnumerable().Where(q => q.num == _num).OrderBy(q=>q.kind).FirstOrDefault();
|
||||
var prod = _db.activity_kind.Where(q => q.num == _num).OrderBy(q=>q.kind).FirstOrDefault();
|
||||
|
||||
if (prod != null)
|
||||
{
|
||||
@@ -230,7 +230,7 @@ public partial class admin_activity_kind_reg : MyWeb.config
|
||||
|
||||
try
|
||||
{
|
||||
var prod = _db.activity_kind.AsEnumerable().Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
var prod = _db.activity_kind.Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
if (prod != null)
|
||||
if (prod.range.HasValue)
|
||||
range = prod.range.Value + 1;
|
||||
@@ -284,7 +284,7 @@ public partial class admin_activity_kind_reg : MyWeb.config
|
||||
{
|
||||
int num = Val(Request["num"]);
|
||||
del_product(num);
|
||||
var prod = _db.activity_kind.AsEnumerable().Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.activity_kind.Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
_db.activity_kind.Remove(prod);
|
||||
@@ -301,7 +301,7 @@ public partial class admin_activity_kind_reg : MyWeb.config
|
||||
|
||||
public void Del_Ohter_Items(int d_num)
|
||||
{
|
||||
var prod = _db.activity_kind.AsEnumerable().Where(q => q.root == d_num).ToList();
|
||||
var prod = _db.activity_kind.Where(q => q.root == d_num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
foreach (var row in prod)
|
||||
@@ -317,7 +317,7 @@ public partial class admin_activity_kind_reg : MyWeb.config
|
||||
}
|
||||
public void del_product(int num)
|
||||
{
|
||||
var prod = _db.activities.AsEnumerable().Where(q => q.kind == num).ToList();
|
||||
var prod = _db.activities.Where(q => q.kind == num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
//清空分類
|
||||
|
||||
@@ -21,7 +21,7 @@ public partial class admin_activity_kind_reg2 : MyWeb.config
|
||||
if (!isStrNull(Request["num"]))
|
||||
{
|
||||
int _num = Val(Request["num"]);
|
||||
var prod = _db.activity_category_kind.AsEnumerable().Where(q => q.num == _num).Where(q => q.num == _num).FirstOrDefault();
|
||||
var prod = _db.activity_category_kind.Where(q => q.num == _num).FirstOrDefault();
|
||||
|
||||
if (prod != null)
|
||||
{
|
||||
@@ -208,7 +208,7 @@ public partial class admin_activity_kind_reg2 : MyWeb.config
|
||||
|
||||
try
|
||||
{
|
||||
var prod = _db.activity_category_kind.AsEnumerable().Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
var prod = _db.activity_category_kind.Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
if (prod != null)
|
||||
if (prod.range.HasValue)
|
||||
range = prod.range.Value + 1;
|
||||
@@ -247,7 +247,7 @@ public partial class admin_activity_kind_reg2 : MyWeb.config
|
||||
|
||||
del_product(num);
|
||||
|
||||
var prod = _db.activity_category_kind.AsEnumerable().Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.activity_category_kind.Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
_db.activity_category_kind.Remove(prod);
|
||||
@@ -265,7 +265,7 @@ public partial class admin_activity_kind_reg2 : MyWeb.config
|
||||
|
||||
public void Del_Ohter_Items(int d_num)
|
||||
{
|
||||
var prod = _db.activity_category_kind.AsEnumerable().Where(q => q.root == d_num).ToList();
|
||||
var prod = _db.activity_category_kind.Where(q => q.root == d_num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
foreach (var row in prod)
|
||||
@@ -284,7 +284,7 @@ public partial class admin_activity_kind_reg2 : MyWeb.config
|
||||
public void del_product(int num) //刪除訊息
|
||||
{
|
||||
//EF Model 資料庫拉關聯 , 故刪除類型前,一定要先刪除訊息,否則關聯會出錯
|
||||
var prod = _db.activities.AsEnumerable().Where(q => q.category_kind == num).ToList();
|
||||
var prod = _db.activities.Where(q => q.category_kind == num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ public partial class admin_bed_kind_reg : MyWeb.config
|
||||
{
|
||||
_this_id = ValString(Request["num"]);
|
||||
int _num = Val(Request["num"]);
|
||||
var prod = _db.bed_kind.AsEnumerable().Where(q => q.num == _num).FirstOrDefault();
|
||||
var prod = _db.bed_kind.Where(q => q.num == _num).FirstOrDefault();
|
||||
|
||||
if (prod != null)
|
||||
{
|
||||
@@ -250,7 +250,7 @@ public partial class admin_bed_kind_reg : MyWeb.config
|
||||
|
||||
try
|
||||
{
|
||||
var prod = _db.bed_kind.AsEnumerable().Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
var prod = _db.bed_kind.Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
if (prod != null)
|
||||
if (prod.range.HasValue)
|
||||
range = prod.range.Value + 1;
|
||||
@@ -293,7 +293,7 @@ public partial class admin_bed_kind_reg : MyWeb.config
|
||||
{
|
||||
int num = Val(Request["num"]);
|
||||
del_product(num);
|
||||
var prod = _db.bed_kind.AsEnumerable().Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.bed_kind.Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
_db.bed_kind.Remove(prod);
|
||||
@@ -310,7 +310,7 @@ public partial class admin_bed_kind_reg : MyWeb.config
|
||||
|
||||
public void Del_Ohter_Items(int d_num)
|
||||
{
|
||||
var prod = _db.bed_kind.AsEnumerable().Where(q => q.root == d_num).ToList();
|
||||
var prod = _db.bed_kind.Where(q => q.root == d_num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
foreach (var row in prod)
|
||||
@@ -327,14 +327,14 @@ public partial class admin_bed_kind_reg : MyWeb.config
|
||||
public void del_product(int num)
|
||||
{
|
||||
//床位資料
|
||||
var prod = _db.bed_kind_detail.AsEnumerable().Where(q => q.bed_kind_id == num).ToList();
|
||||
var prod = _db.bed_kind_detail.Where(q => q.bed_kind_id == num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
//清空分類
|
||||
foreach (var item in prod)
|
||||
{
|
||||
//掛單資料
|
||||
var prod2 = _db.bed_order_detail.AsEnumerable().Where(q => q.bed_kind_detail_id == item.num).ToList();
|
||||
var prod2 = _db.bed_order_detail.Where(q => q.bed_kind_detail_id == item.num).ToList();
|
||||
if (prod2.Count > 0)
|
||||
{
|
||||
//清空分類
|
||||
@@ -349,7 +349,7 @@ public partial class admin_bed_kind_reg : MyWeb.config
|
||||
}
|
||||
|
||||
//掛單資料
|
||||
var prod3 = _db.bed_order_detail.AsEnumerable().Where(q => q.bed_kind1 == num || q.bed_kind2 == num).ToList();
|
||||
var prod3 = _db.bed_order_detail.Where(q => q.bed_kind1 == num || q.bed_kind2 == num).ToList();
|
||||
if (prod3.Count > 0)
|
||||
{
|
||||
//清空分類
|
||||
|
||||
@@ -42,7 +42,7 @@ public partial class admin_follower_index : MyWeb.config
|
||||
//國籍
|
||||
s_country.Items.Clear();
|
||||
s_country.Items.Add(new ListItem("請選擇", ""));
|
||||
var qry =_db.countries.AsEnumerable().OrderBy(x => x.range).ThenBy(x => x.name_en).ToList();
|
||||
var qry =_db.countries.OrderBy(x => x.range).ThenBy(x => x.name_en).ToList();
|
||||
if (qry.Count > 0)
|
||||
{
|
||||
foreach(var x in qry)
|
||||
@@ -222,7 +222,7 @@ public partial class admin_follower_index : MyWeb.config
|
||||
{
|
||||
|
||||
//查詢要匯出的資料
|
||||
var qry = _db.followers.AsEnumerable();
|
||||
var qry = _db.followers.AsQueryable();
|
||||
|
||||
//紀錄匯出條件
|
||||
if (!isStrNull(s_f_number.Value))
|
||||
|
||||
@@ -25,7 +25,7 @@ public partial class admin_follower_print_ : System.Web.UI.Page
|
||||
|
||||
//紀錄匯出條件
|
||||
string _query = "";
|
||||
var qry = _db.followers.AsEnumerable();
|
||||
var qry = _db.followers.AsQueryable();
|
||||
if (!string.IsNullOrEmpty(Request["f_number"]))
|
||||
{
|
||||
qry = qry.Where(o => o.f_number.Contains(Request["f_number"].Trim()));
|
||||
@@ -57,7 +57,7 @@ public partial class admin_follower_print_ : System.Web.UI.Page
|
||||
if (!string.IsNullOrEmpty(Request["country"]))
|
||||
{
|
||||
qry = qry.Where(o => o.country == Request["country"]);
|
||||
_query += "國家:" + (_db.countries.AsEnumerable().Where(x => x.ID == Request["country"].ToString()).Select(x => x.name_zh).FirstOrDefault()??"" )+ "\n";
|
||||
_query += "國家:" + (_db.countries.Where(x => x.ID == Request["country"].ToString()).Select(x => x.name_zh).FirstOrDefault()??"" )+ "\n";
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Request["country2"]))
|
||||
{
|
||||
@@ -70,7 +70,7 @@ public partial class admin_follower_print_ : System.Web.UI.Page
|
||||
qry = qry.Where(o => o.country != "158");
|
||||
|
||||
}
|
||||
_query += "國家:" + (_db.countries.AsEnumerable().Where(x => x.ID == Request["country2"].ToString()).Select(x => x.name_zh).FirstOrDefault()??"") + "\n";
|
||||
_query += "國家:" + (_db.countries.Where(x => x.ID == Request["country2"].ToString()).Select(x => x.name_zh).FirstOrDefault()??"") + "\n";
|
||||
}
|
||||
|
||||
//管理報表
|
||||
|
||||
@@ -1393,7 +1393,7 @@
|
||||
message: `確定要將 ${guest.follower.u_name || ''} 退房嗎?`,
|
||||
onConfirm: async () => {
|
||||
try {
|
||||
const response = await axios.post(`/api/guadanorderguest/checkout`, null, {
|
||||
const response = await axios.post(HTTP_HOST + HTTP_HOST + `api/guadanorderguest/checkout`, null, {
|
||||
params: { uuid: guest.uuid }
|
||||
});
|
||||
|
||||
@@ -1594,7 +1594,7 @@
|
||||
onConfirm: async () => {
|
||||
try {
|
||||
// 發送請求到後端 API
|
||||
const response = await axios.post(`/api/guadanorderguest/checkin`, null, {
|
||||
const response = await axios.post(HTTP_HOST + `api/guadanorderguest/checkin`, null, {
|
||||
params: { uuid: guest.uuid }
|
||||
});
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ public partial class admin_news_kind_reg : MyWeb.config
|
||||
if (!isStrNull(Request["num"]))
|
||||
{
|
||||
int _num = Val(Request["num"]);
|
||||
var prod = _db.news_kind.AsEnumerable().Where(q => q.num == _num).OrderBy(q=>q.kind).FirstOrDefault();
|
||||
var prod = _db.news_kind.Where(q => q.num == _num).OrderBy(q=>q.kind).FirstOrDefault();
|
||||
|
||||
if (prod != null)
|
||||
{
|
||||
@@ -214,7 +214,7 @@ public partial class admin_news_kind_reg : MyWeb.config
|
||||
|
||||
try
|
||||
{
|
||||
var prod = _db.news_kind.AsEnumerable().Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
var prod = _db.news_kind.Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
if (prod != null)
|
||||
if (prod.range.HasValue)
|
||||
range = prod.range.Value + 1;
|
||||
@@ -255,7 +255,7 @@ public partial class admin_news_kind_reg : MyWeb.config
|
||||
|
||||
del_product(num);
|
||||
|
||||
var prod = _db.news_kind.AsEnumerable().Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.news_kind.Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
_db.news_kind.Remove(prod);
|
||||
@@ -273,7 +273,7 @@ public partial class admin_news_kind_reg : MyWeb.config
|
||||
|
||||
public void Del_Ohter_Items(int d_num)
|
||||
{
|
||||
var prod = _db.news_kind.AsEnumerable().Where(q => q.root == d_num).ToList();
|
||||
var prod = _db.news_kind.Where(q => q.root == d_num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
foreach (var row in prod)
|
||||
@@ -292,7 +292,7 @@ public partial class admin_news_kind_reg : MyWeb.config
|
||||
public void del_product(int num) //刪除訊息
|
||||
{
|
||||
//EF Model 資料庫拉關聯 , 故刪除分類前,一定要先刪除訊息,否則關聯會出錯
|
||||
var prod = _db.news.AsEnumerable().Where(q => q.kind == num).ToList();
|
||||
var prod = _db.news.Where(q => q.kind == num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
////刪除檔案
|
||||
|
||||
@@ -27,7 +27,7 @@ public partial class admin_news_news_reg : MyWeb.config
|
||||
else
|
||||
{
|
||||
int _num = Val(Request["num"]);
|
||||
var qry = _db.news.AsEnumerable();
|
||||
var qry = _db.news.AsQueryable();
|
||||
//var prod = _db.news.Where(q => q.num == _num).ToList();
|
||||
var prod = qry.Where(q => q.num == _num).FirstOrDefault();
|
||||
|
||||
@@ -410,13 +410,11 @@ public partial class admin_news_news_reg : MyWeb.config
|
||||
#region 載入
|
||||
protected void initNewsFiles(int num = 0)
|
||||
{
|
||||
var qry = _db.news_files.AsEnumerable();
|
||||
var qry = _db.news_files.AsQueryable();
|
||||
if (num > 0)
|
||||
qry = qry.Where(q => q.news_id == num).ToList();
|
||||
else
|
||||
qry = qry.ToList();
|
||||
qry = qry.Where(q => q.news_id == num);
|
||||
|
||||
fileRepeater.DataSource = qry;
|
||||
fileRepeater.DataSource = qry.ToList();
|
||||
fileRepeater.DataBind();
|
||||
}
|
||||
protected void fileRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
|
||||
|
||||
@@ -47,7 +47,7 @@ public partial class admin_order_index : MyWeb.config
|
||||
//國籍
|
||||
s_country.Items.Clear();
|
||||
s_country.Items.Add(new ListItem("請選擇", ""));
|
||||
var qry = _db.countries.AsEnumerable().OrderBy(x => x.range).ThenBy(x => x.name_en).ToList();
|
||||
var qry = _db.countries.OrderBy(x => x.range).ThenBy(x => x.name_en).ToList();
|
||||
if (qry.Count > 0)
|
||||
{
|
||||
foreach (var x in qry)
|
||||
@@ -128,8 +128,8 @@ public partial class admin_order_index : MyWeb.config
|
||||
sd.AppendChild(tr);
|
||||
|
||||
//查詢要匯出的資料
|
||||
var aIDt = _db.actItems.AsEnumerable().Where(f => f.subject.Contains(s_actItemTxt.Value.Trim())).Select(f => f.num.ToString());//品項
|
||||
var qry = _db.pro_order.AsEnumerable();
|
||||
var aIDt = _db.actItems.Where(f => f.subject.Contains(s_actItemTxt.Value.Trim())).Select(f => f.num.ToString());//品項
|
||||
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()));
|
||||
@@ -154,7 +154,7 @@ public partial class admin_order_index : MyWeb.config
|
||||
MyWeb.encrypt encrypt = new MyWeb.encrypt();
|
||||
var tdesc = publicFun.enum_desc<Model.pro_order.detailKeyin1>();
|
||||
|
||||
var bedDt = _db.bed_order_detail.AsEnumerable();//掛單明細
|
||||
var bedDt = _db.bed_order_detail.AsQueryable();//掛單明細
|
||||
|
||||
|
||||
//left join 使用 GroupJoin
|
||||
@@ -167,7 +167,7 @@ public partial class admin_order_index : MyWeb.config
|
||||
order_no = o.order_no,
|
||||
up_time = o.up_time,
|
||||
keyin1 = o.keyin1,
|
||||
f_num = o.follower?.u_name, //姓名/名稱
|
||||
f_num = o.follower != null ? o.follower.u_name : "", //姓名/名稱
|
||||
phone = o.phone,
|
||||
activity_num = o.activity_num.HasValue ? o.activity.subject : "",
|
||||
address = o.address,
|
||||
|
||||
@@ -25,7 +25,7 @@ public partial class admin_follower_print_ : System.Web.UI.Page
|
||||
|
||||
//紀錄匯出條件
|
||||
string _query = "";
|
||||
var qry = _db.pro_order.AsEnumerable();
|
||||
var qry = _db.pro_order.AsQueryable();
|
||||
if (!string.IsNullOrEmpty(Request["order_no"]))
|
||||
{
|
||||
qry = qry.Where(o => o.order_no.Contains(Request["order_no"].Trim()));
|
||||
@@ -73,21 +73,21 @@ public partial class admin_follower_print_ : System.Web.UI.Page
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Request["country"]))
|
||||
{
|
||||
qry = qry.Where(o => o.f_num != null && o.follower?.country == Request["country"]);
|
||||
_query += "國家:" + (_db.countries.AsEnumerable().Where(x => x.ID == Request["country"]).Select(x => x.name_zh).FirstOrDefault()??"") + "\n";
|
||||
qry = qry.Where(o => o.f_num != null && o.follower.country == Request["country"]);
|
||||
_query += "國家:" + (_db.countries.Where(x => x.ID == Request["country"]).Select(x => x.name_zh).FirstOrDefault()??"") + "\n";
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Request["country2"]))
|
||||
{
|
||||
if (Request["country2"] == "1")
|
||||
{
|
||||
qry = qry.Where(o => o.f_num != null && o.follower?.country == "158");
|
||||
qry = qry.Where(o => o.f_num != null && o.follower.country == "158");
|
||||
}
|
||||
else if (Request["country2"] == "2")
|
||||
{
|
||||
qry = qry.Where(o => o.f_num != null && o.follower?.country != "158");
|
||||
qry = qry.Where(o => o.f_num != null && o.follower.country != "158");
|
||||
|
||||
}
|
||||
_query += "國家:" + (_db.countries.AsEnumerable().Where(x => x.ID == Request["country2"]).Select(x => x.name_zh).FirstOrDefault()??"") + "\n";
|
||||
_query += "國家:" + (_db.countries.Where(x => x.ID == Request["country2"]).Select(x => x.name_zh).FirstOrDefault()??"") + "\n";
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Request["hasPrice"]))
|
||||
{
|
||||
@@ -175,7 +175,7 @@ public partial class admin_follower_print_ : System.Web.UI.Page
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Request["year"]))
|
||||
qry = qry.OrderByDescending(o => o.activity?.startDate_solar).ThenByDescending(o=>o.up_time).ThenByDescending(o=>o.order_no);
|
||||
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);
|
||||
|
||||
@@ -186,8 +186,9 @@ public partial class admin_follower_print_ : System.Web.UI.Page
|
||||
tdesc = publicFun.enum_desc<Model.pro_order.detailKeyin1>();
|
||||
|
||||
//明細
|
||||
_detail = _db.pro_order_detail.AsEnumerable().Where(x => prod.Select(o => o.order_no).Contains( x.order_no)).ToList();
|
||||
_bedDt = _db.bed_order_detail.AsEnumerable().Where(x => prod.Select(o => o.order_no).Contains( x.bed_order.order_no)).ToList();
|
||||
var orderNos = prod.Select(o => o.order_no).ToList();
|
||||
_detail = _db.pro_order_detail.Where(x => orderNos.Contains(x.order_no)).ToList();
|
||||
_bedDt = _db.bed_order_detail.Where(x => orderNos.Contains(x.bed_order.order_no)).ToList();
|
||||
|
||||
Repeater1.DataSource = prod;
|
||||
Repeater1.DataBind();
|
||||
|
||||
1401
web/admin/pivot/README-pivot-01.md
Normal file
1401
web/admin/pivot/README-pivot-01.md
Normal file
File diff suppressed because it is too large
Load Diff
768
web/admin/pivot/README.md
Normal file
768
web/admin/pivot/README.md
Normal file
@@ -0,0 +1,768 @@
|
||||
# Pivot Module 執行計劃
|
||||
|
||||
## 概述
|
||||
建立多頁籤數據透視查詢模組,參考 transfer 模組的設計架構,使用相同的技術棧與 UI/UX 模式,實現法會報名資料的多維度分析與展示。
|
||||
|
||||
---
|
||||
|
||||
## 技術架構
|
||||
|
||||
### 前端技術
|
||||
- **框架**: Vue.js 2.x + Vuetify 2.x(與 transfer 模組一致)
|
||||
- **表格元件**: v-data-table(Vuetify 內建表格元件)
|
||||
- **頁籤元件**: v-tabs / v-tab / v-tab-item(Vuetify 頁籤)
|
||||
- **UI 框架**: Bootstrap 5 + Bootstrap Icons(MasterPage)
|
||||
- **樣式**: 與 transfer 模組保持一致的視覺風格
|
||||
|
||||
### 後端 API
|
||||
- **框架**: ASP.NET Web API(C#)
|
||||
- **ORM**: Entity Framework + LINQ
|
||||
- **控制器**: `App_Code/api/pivotController.cs`(已建立)
|
||||
- **資料庫視圖**: `報名明細查詢`(SQL View)
|
||||
|
||||
### 資料流架構(重要)★
|
||||
```
|
||||
查詢流程:
|
||||
┌─────────────┐
|
||||
│ Tab 1 │ → 選擇法會 → API 查詢一次 →
|
||||
│ 查詢條件 │ (完整資料集)
|
||||
└─────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Vue Data (存於前端 this.rawData) │
|
||||
│ - 完整報名明細 │
|
||||
│ - 一次性載入,不重複查詢 │
|
||||
└─────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────┬──────┬──────┬──────┬──────┐
|
||||
│Tab 2 │Tab 3 │Tab 4 │Tab 5 │Tab 6 │
|
||||
│明細 │信眾 │收入 │趨勢 │對比 │
|
||||
│ │ │ │ │ │
|
||||
│ 純前端計算 / 過濾 / 分組 / 統計 │
|
||||
│ 使用 computed / methods / filters │
|
||||
└──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**優點**:
|
||||
1. ✅ **效能優化**: API 只查詢一次,減少伺服器負載
|
||||
2. ✅ **即時響應**: 切換頁籤無延遲,使用者體驗佳
|
||||
3. ✅ **離線分析**: 資料載入後可離線操作(過濾、排序、統計)
|
||||
4. ✅ **減少流量**: 不重複傳輸相同資料
|
||||
5. ✅ **一致性**: 所有頁籤基於同一份資料,確保一致性
|
||||
|
||||
**技術實現**:
|
||||
- `this.rawData`: 原始完整資料(Tab 1 查詢後存入)
|
||||
- `computed properties`: 各頁籤的資料來源(動態計算)
|
||||
- `methods`: 過濾、分組、統計邏輯
|
||||
- `watch`: 監聽過濾條件變化
|
||||
|
||||
### 元件規格
|
||||
1. **日期選擇器**: `v-date-picker` 或 `<input type="date">`
|
||||
2. **下拉選單**: `v-select`(年份、月份、法會選擇)
|
||||
3. **資料表格**: `v-data-table`(分頁、排序、過濾)
|
||||
4. **頁籤切換**: `v-tabs`(Tab 1~N)
|
||||
5. **按鈕群組**: `v-btn`(查詢、匯出、重設)
|
||||
6. **載入狀態**: `:loading="loading"`
|
||||
7. **視覺標記**: Bootstrap Badge(橙、藍、綠、紫色標籤)
|
||||
|
||||
---
|
||||
|
||||
## 頁籤設計
|
||||
|
||||
### Tab 1: 查詢條件設定
|
||||
**功能目標**: 提供查詢條件,篩選法會並選擇目標法會
|
||||
|
||||
#### UI 布局
|
||||
```
|
||||
+--------------------------------------------------------------+
|
||||
| [查詢條件] |
|
||||
|--------------------------------------------------------------|
|
||||
| 時間範圍: [年份 ▼] [月份 ▼] [查詢法會] |
|
||||
|--------------------------------------------------------------|
|
||||
| 法會清單: |
|
||||
| +----------------------------------------------------------+ |
|
||||
| | 序號 | 法會名稱 | 開始日期 | 結束日期 | 報名人數 | 操作 | |
|
||||
| +----------------------------------------------------------+ |
|
||||
| | 1 | 2025春季法會 | 2025-03-01 | 2025-03-15 | 120 | [選擇] | |
|
||||
| | 2 | 2025夏季法會 | 2025-06-01 | 2025-06-20 | 85 | [選擇] | |
|
||||
| +----------------------------------------------------------+ |
|
||||
+--------------------------------------------------------------+
|
||||
```
|
||||
|
||||
#### 查詢流程
|
||||
1. 選擇年份(2020~2025)或月份(1~12)
|
||||
2. 點擊「查詢法會」按鈕
|
||||
3. API 回傳該期間的法會清單(`api/pivot/activity_stats`)
|
||||
4. 表格呈現法會清單(法會名稱、日期、統計)
|
||||
5. 點擊「選擇」按鈕,載入該法會的詳細資料
|
||||
6. 自動切換到 Tab 2(詳細資料頁籤)
|
||||
|
||||
#### API 整合
|
||||
- **端點**: `GET api/pivot/activity_stats?startDate={start}&endDate={end}`
|
||||
- **回傳**: 法會清單(含報名統計)
|
||||
|
||||
#### 資料查詢策略
|
||||
```javascript
|
||||
// 選擇法會後,一次性載入完整資料
|
||||
selectActivity(item) {
|
||||
this.loading = true;
|
||||
this.selectedActivity = item;
|
||||
|
||||
// 一次性查詢完整報名明細(不分頁)
|
||||
axios.get('/api/pivot/registration_details', {
|
||||
params: {
|
||||
activityNum: item.法會ID,
|
||||
pageSize: 9999 // 取得全部資料
|
||||
}
|
||||
}).then(response => {
|
||||
// 存入原始資料(供所有頁籤使用)
|
||||
this.rawData = response.data.data.list;
|
||||
|
||||
// 自動切換到 Tab 2
|
||||
this.activeTab = 1;
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
#### 元件範例
|
||||
```html
|
||||
<v-select
|
||||
:items="yearOptions"
|
||||
v-model="selectedYear"
|
||||
label="年份"
|
||||
dense
|
||||
outlined
|
||||
></v-select>
|
||||
<v-select
|
||||
:items="monthOptions"
|
||||
v-model="selectedMonth"
|
||||
label="月份"
|
||||
dense
|
||||
outlined
|
||||
clearable
|
||||
></v-select>
|
||||
<v-btn color="primary" @click="loadActivities">查詢法會</v-btn>
|
||||
|
||||
<v-data-table
|
||||
:headers="activityHeaders"
|
||||
:items="activities"
|
||||
:loading="loading"
|
||||
item-key="法會ID"
|
||||
>
|
||||
<template v-slot:item.actions="{ item }">
|
||||
<v-btn small color="success" @click="selectActivity(item)">選擇</v-btn>
|
||||
</template>
|
||||
</v-data-table>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Tab 2: 報名明細資料
|
||||
**功能目標**: 完整呈現該場法會的所有報名明細
|
||||
|
||||
#### UI 布局
|
||||
```
|
||||
+--------------------------------------------------------------+
|
||||
| [報名明細] 法會: 2025春季法會 (2025-03-01 ~ 2025-03-15) |
|
||||
|--------------------------------------------------------------|
|
||||
| 過濾: [信眾姓名] [功德類型 ▼] [狀態 ▼] [查詢] [匯出Excel] |
|
||||
|--------------------------------------------------------------|
|
||||
| +----------------------------------------------------------+ |
|
||||
| | 報名編號 | 報名日期 | 信眾姓名 | 功德名稱 | 數量 | 金額 | |
|
||||
| +----------------------------------------------------------+ |
|
||||
| | 20250301001 | 2025-03-01 | 張三 | 點燈 | 1 | 500 | |
|
||||
| | 20250301002 | 2025-03-01 | 李四 | 安太歲 | 1 | 300 | |
|
||||
| +----------------------------------------------------------+ |
|
||||
| 第 1 頁,共 10 頁(共 200 筆) |
|
||||
+--------------------------------------------------------------+
|
||||
```
|
||||
|
||||
#### 功能特性
|
||||
1. **欄位顯示**: 報名編號、報名日期、信眾姓名、功德名稱、數量、金額、已收、未收
|
||||
2. **過濾條件**: 信眾姓名(模糊搜尋)、功德類型(下拉選單)、功德主(是/否)
|
||||
3. **排序**: 可依任意欄位排序(升序/降序)
|
||||
4. **分頁**: 預設每頁 50 筆,可調整(10/20/50/100)
|
||||
5. **匯出**: 匯出 Excel/CSV
|
||||
|
||||
#### 欄位色彩標記(參考 Excel 視圖)
|
||||
- **橙色(法會資料)**: 法會ID、法會名稱、開始日期、結束日期
|
||||
- **藍色(信眾資料)**: 信眾編號、信眾姓名
|
||||
- **綠色(功德資訊)**: 報名編號、報名日期、功德主、功德類型、功德名稱
|
||||
- **紫色(計算欄位)**: 數量、金額、已收、未收
|
||||
|
||||
使用 Bootstrap Badge 或背景色區隔:
|
||||
```html
|
||||
<span class="badge bg-warning text-dark">法會</span>
|
||||
<span class="badge bg-info">信眾</span>
|
||||
<span class="badge bg-success">功德</span>
|
||||
<span class="badge bg-secondary">計算</span>
|
||||
```
|
||||
|
||||
#### 資料來源(前端計算)
|
||||
```javascript
|
||||
computed: {
|
||||
// Tab 2: 報名明細(前端分頁、過濾)
|
||||
filteredRegistrations() {
|
||||
let data = this.rawData;
|
||||
|
||||
// 過濾:信眾姓名
|
||||
if (this.filter.followerName) {
|
||||
data = data.filter(x => x.信眾姓名.includes(this.filter.followerName));
|
||||
}
|
||||
|
||||
// 過濾:功德類型
|
||||
if (this.filter.itemKind) {
|
||||
data = data.filter(x => x.功德類型 === this.filter.itemKind);
|
||||
}
|
||||
|
||||
// 過濾:功德主
|
||||
if (this.filter.isParent !== null) {
|
||||
data = data.filter(x => x.功德主 === (this.filter.isParent ? '是' : '否'));
|
||||
}
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
// 前端分頁
|
||||
paginatedRegistrations() {
|
||||
const start = (this.currentPage - 1) * this.pageSize;
|
||||
const end = start + this.pageSize;
|
||||
return this.filteredRegistrations.slice(start, end);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 元件範例
|
||||
```html
|
||||
<v-data-table
|
||||
:headers="detailHeaders"
|
||||
:items="registrations"
|
||||
:loading="loading"
|
||||
:server-items-length="totalCount"
|
||||
:options.sync="options"
|
||||
item-key="報名編號"
|
||||
class="elevation-1"
|
||||
>
|
||||
<template v-slot:item.信眾姓名="{ item }">
|
||||
<span class="badge bg-info me-1">信</span>{{ item.信眾姓名 }}
|
||||
</template>
|
||||
<template v-slot:item.金額="{ item }">
|
||||
<span class="badge bg-secondary me-1">計</span>{{ item.金額 | currency }}
|
||||
</template>
|
||||
</v-data-table>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Tab 3: 信眾參與分析
|
||||
**功能目標**: 統計信眾的參與情況(參與次數、金額、最近參與)
|
||||
|
||||
#### UI 布局
|
||||
```
|
||||
+--------------------------------------------------------------+
|
||||
| [信眾參與分析] |
|
||||
|--------------------------------------------------------------|
|
||||
| 過濾: [信眾編號] [參與次數 ≥] [總金額 ≥] [查詢] |
|
||||
|--------------------------------------------------------------|
|
||||
| +----------------------------------------------------------+ |
|
||||
| | 信眾編號 | 姓名 | 參與次數 | 總金額 | 最近參與日期 | |
|
||||
| +----------------------------------------------------------+ |
|
||||
| | F001 | 張三 | 5 | 2500 | 2025-03-01 | |
|
||||
| | F002 | 李四 | 3 | 1500 | 2025-02-15 | |
|
||||
| +----------------------------------------------------------+ |
|
||||
+--------------------------------------------------------------+
|
||||
```
|
||||
|
||||
#### 功能特性
|
||||
1. **統計欄位**: 參與次數、總金額、平均金額、最近參與日期
|
||||
2. **過濾條件**: 信眾編號、參與次數閾值、總金額閾值
|
||||
3. **排序**: 預設依參與次數降序
|
||||
4. **分頁**: 預設每頁 50 筆
|
||||
|
||||
#### 資料來源(前端計算)
|
||||
```javascript
|
||||
computed: {
|
||||
// Tab 3: 信眾參與分析(從 rawData 計算)
|
||||
followerAnalysis() {
|
||||
const followerMap = {};
|
||||
|
||||
this.rawData.forEach(item => {
|
||||
const fNum = item.信眾編號;
|
||||
if (!followerMap[fNum]) {
|
||||
followerMap[fNum] = {
|
||||
信眾編號: fNum,
|
||||
姓名: item.信眾姓名,
|
||||
參與次數: 0,
|
||||
總金額: 0,
|
||||
最近參與日期: item.報名日期
|
||||
};
|
||||
}
|
||||
|
||||
followerMap[fNum].參與次數++;
|
||||
followerMap[fNum].總金額 += (item.金額 * item.數量);
|
||||
|
||||
// 更新最近參與日期
|
||||
if (new Date(item.報名日期) > new Date(followerMap[fNum].最近參與日期)) {
|
||||
followerMap[fNum].最近參與日期 = item.報名日期;
|
||||
}
|
||||
});
|
||||
|
||||
// 轉換為陣列,並計算平均金額
|
||||
return Object.values(followerMap).map(f => ({
|
||||
...f,
|
||||
平均金額: Math.round(f.總金額 / f.參與次數)
|
||||
})).sort((a, b) => b.參與次數 - a.參與次數); // 依參與次數降序
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Tab 4: 收入統計分析
|
||||
**功能目標**: 依時間、法會、功德類型統計收入
|
||||
|
||||
#### UI 布局
|
||||
```
|
||||
+--------------------------------------------------------------+
|
||||
| [收入統計分析] |
|
||||
|--------------------------------------------------------------|
|
||||
| 分組方式: ( ) 月份 ( ) 年度 (•) 法會 ( ) 功德類型 |
|
||||
|--------------------------------------------------------------|
|
||||
| +----------------------------------------------------------+ |
|
||||
| | 分組名稱 | 報名人數 | 總金額 | 已收 | 未收 | 收款率 | |
|
||||
| +----------------------------------------------------------+ |
|
||||
| | 2025春季法會 | 120 | 60000 | 50000 | 10000 | 83.3% | |
|
||||
| | 2025夏季法會 | 85 | 45000 | 40000 | 5000 | 88.9% | |
|
||||
| +----------------------------------------------------------+ |
|
||||
+--------------------------------------------------------------+
|
||||
```
|
||||
|
||||
#### 功能特性
|
||||
1. **分組方式**: 月份、年度、法會、功德類型
|
||||
2. **統計欄位**: 報名人數、總金額、已收、未收、收款率
|
||||
3. **圖表呈現**: 可加入 CanvasJS 長條圖/圓餅圖(選配)
|
||||
4. **匯出**: 支援 Excel/CSV
|
||||
|
||||
#### 資料來源(前端計算)
|
||||
```javascript
|
||||
computed: {
|
||||
// Tab 4: 收入統計分析(從 rawData 計算)
|
||||
incomeStats() {
|
||||
const statsMap = {};
|
||||
const groupBy = this.groupBy; // 'monthly', 'yearly', 'activity', 'itemKind'
|
||||
|
||||
this.rawData.forEach(item => {
|
||||
let key;
|
||||
switch(groupBy) {
|
||||
case 'monthly':
|
||||
key = item.報名日期.substring(0, 7); // YYYY-MM
|
||||
break;
|
||||
case 'yearly':
|
||||
key = item.報名日期.substring(0, 4); // YYYY
|
||||
break;
|
||||
case 'activity':
|
||||
key = item.法會名稱;
|
||||
break;
|
||||
case 'itemKind':
|
||||
key = item.功德類型;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!statsMap[key]) {
|
||||
statsMap[key] = {
|
||||
分組名稱: key,
|
||||
報名人數: 0,
|
||||
總金額: 0,
|
||||
已收: 0,
|
||||
未收: 0
|
||||
};
|
||||
}
|
||||
|
||||
statsMap[key].報名人數++;
|
||||
const amount = item.金額 * item.數量;
|
||||
statsMap[key].總金額 += amount;
|
||||
statsMap[key].已收 += item.已收 || 0;
|
||||
statsMap[key].未收 += item.未收 || amount;
|
||||
});
|
||||
|
||||
// 計算收款率
|
||||
return Object.values(statsMap).map(s => ({
|
||||
...s,
|
||||
收款率: s.總金額 > 0 ? ((s.已收 / s.總金額) * 100).toFixed(1) + '%' : '0%'
|
||||
}));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Tab 5: 趨勢分析
|
||||
**功能目標**: 顯示時間序列趨勢(收入、參與人數、法會數量)
|
||||
|
||||
#### UI 布局
|
||||
```
|
||||
+--------------------------------------------------------------+
|
||||
| [趨勢分析] |
|
||||
|--------------------------------------------------------------|
|
||||
| 指標: ( ) 收入 (•) 參與人數 ( ) 法會數量 |
|
||||
| 時間間隔: ( ) 月份 (•) 季度 ( ) 年度 |
|
||||
|--------------------------------------------------------------|
|
||||
| [折線圖] |
|
||||
| |
|
||||
| +----------------------------------------------------------+ |
|
||||
| | 時間 | 數值 | 成長率 | |
|
||||
| +----------------------------------------------------------+ |
|
||||
| | 2025-01 | 120 | +10% | |
|
||||
| | 2025-02 | 132 | +10% | |
|
||||
| +----------------------------------------------------------+ |
|
||||
+--------------------------------------------------------------+
|
||||
```
|
||||
|
||||
#### 功能特性
|
||||
1. **指標選擇**: 收入、參與人數、法會數量
|
||||
2. **時間間隔**: 月份、季度、年度
|
||||
3. **成長率計算**: 較前期成長率
|
||||
4. **圖表**: CanvasJS 折線圖(選配)
|
||||
|
||||
#### 資料來源(前端計算)
|
||||
```javascript
|
||||
computed: {
|
||||
// Tab 5: 趨勢分析(從 rawData 計算)
|
||||
trendAnalysis() {
|
||||
const metric = this.trendMetric; // 'income', 'followers', 'count'
|
||||
const interval = this.trendInterval; // 'monthly', 'quarterly', 'yearly'
|
||||
const trendMap = {};
|
||||
|
||||
this.rawData.forEach(item => {
|
||||
let key;
|
||||
switch(interval) {
|
||||
case 'monthly':
|
||||
key = item.報名日期.substring(0, 7); // YYYY-MM
|
||||
break;
|
||||
case 'quarterly':
|
||||
const month = parseInt(item.報名日期.substring(5, 7));
|
||||
const quarter = Math.ceil(month / 3);
|
||||
key = `${item.報名日期.substring(0, 4)}-Q${quarter}`;
|
||||
break;
|
||||
case 'yearly':
|
||||
key = item.報名日期.substring(0, 4); // YYYY
|
||||
break;
|
||||
}
|
||||
|
||||
if (!trendMap[key]) {
|
||||
trendMap[key] = { 時間: key, 收入: 0, 人數: 0, 次數: 0 };
|
||||
}
|
||||
|
||||
trendMap[key].收入 += (item.金額 * item.數量);
|
||||
trendMap[key].人數++; // 簡化計算,實際可用 Set 去重
|
||||
trendMap[key].次數++;
|
||||
});
|
||||
|
||||
// 轉換為陣列並排序
|
||||
const result = Object.values(trendMap).sort((a, b) => a.時間.localeCompare(b.時間));
|
||||
|
||||
// 計算成長率
|
||||
return result.map((item, index) => {
|
||||
if (index === 0) {
|
||||
return { ...item, 數值: item[metric === 'income' ? '收入' : metric === 'followers' ? '人數' : '次數'], 成長率: '-' };
|
||||
}
|
||||
const prev = result[index - 1];
|
||||
const currentValue = item[metric === 'income' ? '收入' : metric === 'followers' ? '人數' : '次數'];
|
||||
const prevValue = prev[metric === 'income' ? '收入' : metric === 'followers' ? '人數' : '次數'];
|
||||
const growthRate = prevValue > 0 ? (((currentValue - prevValue) / prevValue) * 100).toFixed(1) : '0';
|
||||
return { ...item, 數值: currentValue, 成長率: growthRate + '%' };
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Tab 6: 對比分析(選配)
|
||||
**功能目標**: 不同時期、法會的對比分析
|
||||
|
||||
#### UI 布局
|
||||
```
|
||||
+--------------------------------------------------------------+
|
||||
| [對比分析] |
|
||||
|--------------------------------------------------------------|
|
||||
| 對比類型: (•) 法會對比 ( ) 年度對比 |
|
||||
| 期間1: [2025春季法會 ▼] 期間2: [2024春季法會 ▼] |
|
||||
|--------------------------------------------------------------|
|
||||
| +----------------------------------------------------------+ |
|
||||
| | 指標 | 期間1 | 期間2 | 差異 | 差異率 | |
|
||||
| +----------------------------------------------------------+ |
|
||||
| | 報名人數 | 120 | 100 | +20 | +20% | |
|
||||
| | 總金額 | 60000 | 50000 | +10000 | +20% | |
|
||||
| +----------------------------------------------------------+ |
|
||||
+--------------------------------------------------------------+
|
||||
```
|
||||
|
||||
#### 資料來源(前端計算)
|
||||
```javascript
|
||||
computed: {
|
||||
// Tab 6: 對比分析(從 rawData 計算)
|
||||
// 注意:對比分析可能需要跨法會資料,如需要可額外查詢
|
||||
comparativeAnalysis() {
|
||||
// 如果只在單一法會內對比(如月份對比),可用 rawData
|
||||
// 如果需要跨法會對比,建議另外查詢或在 Tab 1 時一併載入多場法會資料
|
||||
const period1Data = this.rawData.filter(x => {
|
||||
// 依 period1 條件過濾
|
||||
return this.isPeriod1(x);
|
||||
});
|
||||
|
||||
const period2Data = this.rawData.filter(x => {
|
||||
// 依 period2 條件過濾
|
||||
return this.isPeriod2(x);
|
||||
});
|
||||
|
||||
const stats1 = this.calculateStats(period1Data);
|
||||
const stats2 = this.calculateStats(period2Data);
|
||||
|
||||
return [
|
||||
{ 指標: '報名人數', 期間1: stats1.count, 期間2: stats2.count, 差異: stats1.count - stats2.count },
|
||||
{ 指標: '總金額', 期間1: stats1.amount, 期間2: stats2.amount, 差異: stats1.amount - stats2.amount },
|
||||
// ... 其他指標
|
||||
];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 視覺設計規範
|
||||
|
||||
### 色彩系統(參考 transfer)
|
||||
- **主色調**: Bootstrap 5 預設配色
|
||||
- **成功/確認**: `bg-success` / `text-success`
|
||||
- **警告**: `bg-warning` / `text-warning`
|
||||
- **危險/錯誤**: `bg-danger` / `text-danger`
|
||||
- **資訊**: `bg-info` / `text-info`
|
||||
- **次要**: `bg-secondary` / `text-muted`
|
||||
|
||||
### 欄位色彩標記(對應 Excel)
|
||||
```html
|
||||
<!-- 橙色:法會資料 -->
|
||||
<span class="badge bg-warning text-dark">法</span>
|
||||
|
||||
<!-- 藍色:信眾資料 -->
|
||||
<span class="badge bg-info">信</span>
|
||||
|
||||
<!-- 綠色:功德資訊 -->
|
||||
<span class="badge bg-success">功德</span>
|
||||
|
||||
<!-- 紫色:計算欄位 -->
|
||||
<span class="badge bg-secondary">計</span>
|
||||
```
|
||||
|
||||
### 表格樣式
|
||||
```css
|
||||
/* 與 transfer 保持一致 */
|
||||
.v-data-table th {
|
||||
background-color: #f5f5f5 !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.v-data-table tbody tr:hover {
|
||||
background-color: #f0f8ff !important;
|
||||
}
|
||||
|
||||
/* 欄位色彩標記 */
|
||||
.field-activity { border-left: 3px solid #ffc107; } /* 橙 */
|
||||
.field-follower { border-left: 3px solid #17a2b8; } /* 藍 */
|
||||
.field-merit { border-left: 3px solid #28a745; } /* 綠 */
|
||||
.field-calculated { border-left: 3px solid #6c757d; } /* 紫 */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API 端點總覽
|
||||
|
||||
| 端點 | 方法 | 功能 | 對應頁籤 | 使用時機 |
|
||||
|------|------|------|----------|----------|
|
||||
| `/api/pivot/activity_stats` | GET | 查詢法會清單與統計 | Tab 1 | 選擇查詢條件時 |
|
||||
| `/api/pivot/registration_details` | GET | 報名明細查詢(**完整資料**) | Tab 1 | **選擇法會後一次性載入** ★ |
|
||||
| `/api/pivot/registration_details_export` | GET | 報名明細匯出 | Tab 2 | 匯出 Excel 時(選配) |
|
||||
| `/api/pivot/excel_data_structured` | GET | Excel 數據連接 | 外部 | Power Query/Power Pivot |
|
||||
|
||||
**重要說明**:
|
||||
- ✅ **Tab 2~6 不呼叫 API**,全部使用前端 `computed` 計算
|
||||
- ✅ `registration_details` 查詢時使用 `pageSize=9999` 取得完整資料
|
||||
- ✅ 原 `follower_analysis`, `income_stats`, `trend_analysis`, `comparative_analysis` 端點**保留備用**,但前端優先使用 computed
|
||||
- ✅ 如資料量過大(>5000 筆),可調整策略改用分頁查詢
|
||||
|
||||
---
|
||||
|
||||
## 檔案結構
|
||||
|
||||
```
|
||||
admin/pivot/
|
||||
├── index.aspx # 首頁(已完成)
|
||||
├── index.aspx.cs # 首頁邏輯(已完成)
|
||||
├── query.aspx # 多頁籤查詢頁面(待建立)★
|
||||
├── query.aspx.cs # 查詢頁面邏輯(待建立)★
|
||||
└── README.md # 本文件
|
||||
|
||||
App_Code/api/
|
||||
└── pivotController.cs # API 控制器(已完成)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 實作步驟
|
||||
|
||||
### Phase 1: 建立查詢頁面骨架
|
||||
1. ✅ 建立 `query.aspx`(參考 transfer/verify.aspx)
|
||||
2. ✅ 建立 `query.aspx.cs`(參考 transfer/verify.aspx.cs)
|
||||
3. ✅ 引入 Vue.js + Vuetify
|
||||
4. ✅ 建立頁籤結構(v-tabs)
|
||||
|
||||
### Phase 2: 實作 Tab 1(查詢條件)
|
||||
1. ✅ 年份/月份選擇器
|
||||
2. ✅ 查詢法會按鈕與 API 整合(`activity_stats`)
|
||||
3. ✅ 法會清單表格(v-data-table)
|
||||
4. ✅ 選擇法會邏輯(一次性載入完整資料)
|
||||
5. ✅ `this.rawData` 資料結構設計
|
||||
|
||||
### Phase 3: 實作 Tab 2(報名明細)
|
||||
1. ✅ 報名明細表格(前端分頁、排序、過濾)
|
||||
2. ✅ `computed: filteredRegistrations` 實作
|
||||
3. ✅ 欄位色彩標記(badge)
|
||||
4. ✅ 匯出功能(選配)
|
||||
|
||||
### Phase 4: 實作 Tab 3~6(分析頁籤)
|
||||
1. ✅ 信眾參與分析(Tab 3)- `computed: followerAnalysis`
|
||||
2. ✅ 收入統計分析(Tab 4)- `computed: incomeStats`
|
||||
3. ✅ 趨勢分析(Tab 5)- `computed: trendAnalysis`
|
||||
4. ✅ 對比分析(Tab 6,選配)- `computed: comparativeAnalysis`
|
||||
|
||||
### Phase 5: 優化與測試
|
||||
1. ✅ UI/UX 調整(與 transfer 保持一致)
|
||||
2. ✅ 效能優化(分頁、快取)
|
||||
3. ✅ 瀏覽器相容性測試
|
||||
4. ✅ 權限控制(ezAuthorize)
|
||||
|
||||
---
|
||||
|
||||
## 參考範例
|
||||
|
||||
### 1. transfer/verify.aspx
|
||||
- 多階段流程設計(程序1、程序2)
|
||||
- v-data-table 表格元件使用
|
||||
- 信眾選擇對話框(v-dialog)
|
||||
- 狀態選擇(v-select)
|
||||
|
||||
### 2. transfer/verify1.aspx
|
||||
- 單階段流程設計
|
||||
- 簡潔的查詢與確認流程
|
||||
|
||||
### 3. transfer/index.aspx
|
||||
- 功能入口頁面設計
|
||||
- Bootstrap Icons + Badge
|
||||
- 三欄式布局
|
||||
|
||||
---
|
||||
|
||||
## 注意事項
|
||||
|
||||
1. **元件一致性**: 所有元件、樣式、命名均與 transfer 模組保持一致
|
||||
2. **API 規範**: 遵循 RESTful 設計,統一回傳格式
|
||||
3. **權限控制**: 所有 API 加上 `[ezAuthorize]`
|
||||
4. **效能考量**:
|
||||
- ✅ **前端計算策略**: Tab 1 查詢一次,Tab 2~6 使用 Vue computed 計算
|
||||
- ✅ **資料量控制**: 單一法會報名明細預估 <5000 筆,適合前端處理
|
||||
- ⚠️ **大資料處理**: 若單場法會 >5000 筆,可改用 API 分頁查詢
|
||||
- ✅ **記憶體管理**: 切換法會時清除舊資料(`this.rawData = []`)
|
||||
5. **視覺區隔**: 使用 Badge、邊框色、背景色標記欄位類型
|
||||
6. **使用者體驗**: 載入狀態(loading)、錯誤提示(alert)、空資料提示
|
||||
7. **前端效能優化**:
|
||||
- 使用 `computed` 而非 `methods`(自動快取)
|
||||
- 大型陣列操作使用 `Object.freeze()` 凍結原始資料
|
||||
- v-data-table 啟用虛擬滾動(`:virtual-scroll="true"`,資料量 >1000 時)
|
||||
|
||||
---
|
||||
|
||||
## SQL View 參考
|
||||
|
||||
```SQL
|
||||
CREATE VIEW [dbo].[報名明細查詢]
|
||||
AS
|
||||
SELECT dbo.activity.num AS 法會ID, dbo.activity.subject AS 法會名稱, dbo.activity.startDate_solar AS 開始日期, dbo.activity.endDate_solar AS 結束日期,
|
||||
dbo.followers.f_number AS 信眾編號, dbo.followers.u_name AS 信眾姓名, dbo.pro_order.order_no AS 報名編號, dbo.pro_order.up_time AS 報名日期,
|
||||
CASE WHEN parent_num IS NOT NULL THEN '是' ELSE '否' END AS 功德主, dbo.actItem_kind.kind AS 功德類型, dbo.actItem.subject AS 功德名稱,
|
||||
dbo.pro_order_detail.qty AS 數量, dbo.pro_order_detail.price AS 金額, 0 AS 已收, dbo.pro_order_detail.price * dbo.pro_order_detail.qty - 0 AS 未收
|
||||
FROM dbo.pro_order_detail INNER JOIN
|
||||
dbo.pro_order ON dbo.pro_order_detail.order_no = dbo.pro_order.order_no INNER JOIN
|
||||
dbo.actItem ON dbo.pro_order_detail.actItem_num = dbo.actItem.num INNER JOIN
|
||||
dbo.activity ON dbo.pro_order.activity_num = dbo.activity.num INNER JOIN
|
||||
dbo.followers ON dbo.pro_order.f_num = dbo.followers.num INNER JOIN
|
||||
dbo.actItem_kind ON dbo.actItem.kind = dbo.actItem_kind.num
|
||||
GO
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 資料結構範例
|
||||
|
||||
```javascript
|
||||
// Vue data 結構
|
||||
data() {
|
||||
return {
|
||||
// 原始完整資料(Tab 1 查詢後存入,供所有頁籤使用)
|
||||
rawData: [], // Array<報名明細物件>
|
||||
|
||||
// 選中的法會
|
||||
selectedActivity: null,
|
||||
|
||||
// 當前頁籤索引
|
||||
activeTab: 0, // 0=Tab1, 1=Tab2, 2=Tab3...
|
||||
|
||||
// Tab 2 過濾條件
|
||||
filter: {
|
||||
followerName: '',
|
||||
itemKind: null,
|
||||
isParent: null
|
||||
},
|
||||
|
||||
// Tab 4 分組方式
|
||||
groupBy: 'activity', // 'monthly', 'yearly', 'activity', 'itemKind'
|
||||
|
||||
// Tab 5 趨勢設定
|
||||
trendMetric: 'income', // 'income', 'followers', 'count'
|
||||
trendInterval: 'monthly', // 'monthly', 'quarterly', 'yearly'
|
||||
|
||||
// 載入狀態
|
||||
loading: false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Vue Computed 效能考量
|
||||
|
||||
```javascript
|
||||
computed: {
|
||||
// 使用 Object.freeze() 凍結大型陣列,提升效能
|
||||
frozenRawData() {
|
||||
return Object.freeze(this.rawData);
|
||||
},
|
||||
|
||||
// 各頁籤 computed 基於 frozenRawData
|
||||
filteredRegistrations() {
|
||||
return this.frozenRawData.filter(/* 過濾邏輯 */);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 執行確認
|
||||
|
||||
請檢視以上計劃,確認以下事項:
|
||||
|
||||
1. ✅ 頁籤設計(Tab 1~6)符合需求
|
||||
2. ✅ 查詢流程(年/月 → 法會清單 → 明細資料)清晰
|
||||
3. ✅ 視覺區隔(色彩標記、Badge)符合 Excel 概念
|
||||
4. ✅ 技術架構(Vue + Vuetify + API)與 transfer 一致
|
||||
5. ✅ 功能完整性(查詢、過濾、排序、匯出)
|
||||
6. ✅ **資料流架構(一次查詢 + 前端計算)**合理且高效 ★
|
||||
|
||||
**確認後即開始實作 Phase 1(建立查詢頁面骨架)。**
|
||||
185
web/admin/pivot/index.aspx
Normal file
185
web/admin/pivot/index.aspx
Normal file
@@ -0,0 +1,185 @@
|
||||
<%@ Page Title="數據透視管理" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" EnableEventValidation="false" CodeFile="index.aspx.cs" Inherits="admin_pivot_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;
|
||||
}
|
||||
</style>
|
||||
</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">
|
||||
<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-graph-up"></i> 報表查詢
|
||||
</h5>
|
||||
<div class="list-group">
|
||||
<a href="activity_report.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-bar-chart text-success me-3 function-icon"></i>
|
||||
<div>
|
||||
<div>法會報名統計</div>
|
||||
<small class="text-muted">各法會報名人數與金額統計</small>
|
||||
</div>
|
||||
</div>
|
||||
<span class="badge bg-primary">管理員</span>
|
||||
</div>
|
||||
</a>
|
||||
<a href="follower_report.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-people 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="income_report.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>收入統計報表</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-pie-chart"></i> 數據分析
|
||||
</h5>
|
||||
<div class="list-group">
|
||||
<a href="query.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-diagram-3 text-primary me-3 function-icon"></i>
|
||||
<div>
|
||||
<div>數據透視查詢</div>
|
||||
<small class="text-muted">多維度數據透視分析(完整版)</small>
|
||||
</div>
|
||||
</div>
|
||||
<span class="badge bg-success">NEW</span>
|
||||
</div>
|
||||
</a>
|
||||
<a href="pivot_analysis.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-diagram-3 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 href="trend_analysis.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-graph-up-arrow 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 href="comparative_analysis.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-graph-down 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-file-earmark-text"></i> 報表管理
|
||||
</h5>
|
||||
<div class="list-group">
|
||||
<a href="custom_report.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-file-plus 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="report_schedule.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-clock 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 href="export_center.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-download 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>
|
||||
</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>
|
||||
</asp:Content>
|
||||
10
web/admin/pivot/index.aspx.cs
Normal file
10
web/admin/pivot/index.aspx.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Web.UI;
|
||||
|
||||
public partial class admin_pivot_index : MyWeb.config
|
||||
{
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
// 頁面初始化(暫無邏輯)
|
||||
}
|
||||
}
|
||||
1374
web/admin/pivot/pivot-01.aspx
Normal file
1374
web/admin/pivot/pivot-01.aspx
Normal file
File diff suppressed because it is too large
Load Diff
11
web/admin/pivot/pivot-01.aspx.cs
Normal file
11
web/admin/pivot/pivot-01.aspx.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Web.UI;
|
||||
|
||||
public partial class admin_pivot_pivot01 : MyWeb.config
|
||||
{
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
// 頁面初始化(暫無邏輯)
|
||||
// 前端直接呼叫 API
|
||||
}
|
||||
}
|
||||
1128
web/admin/pivot/query.aspx
Normal file
1128
web/admin/pivot/query.aspx
Normal file
File diff suppressed because it is too large
Load Diff
10
web/admin/pivot/query.aspx.cs
Normal file
10
web/admin/pivot/query.aspx.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Web.UI;
|
||||
|
||||
public partial class admin_pivot_query : MyWeb.config
|
||||
{
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
// 頁面初始化(暫無邏輯)
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ public partial class admin_project_kind_reg : MyWeb.config
|
||||
if (!isStrNull(Request["num"]))
|
||||
{
|
||||
int _num = Val(Request["num"]);
|
||||
var prod = _db.project_kind.AsEnumerable().Where(q => q.num == _num).OrderBy(q => q.kind).FirstOrDefault();
|
||||
var prod = _db.project_kind.Where(q => q.num == _num).OrderBy(q => q.kind).FirstOrDefault();
|
||||
|
||||
if (prod != null)
|
||||
{
|
||||
@@ -210,7 +210,7 @@ public partial class admin_project_kind_reg : MyWeb.config
|
||||
|
||||
try
|
||||
{
|
||||
var prod = _db.project_kind.AsEnumerable().Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
var prod = _db.project_kind.Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
if (prod != null)
|
||||
if (prod.range.HasValue)
|
||||
range = prod.range.Value + 1;
|
||||
@@ -248,7 +248,7 @@ public partial class admin_project_kind_reg : MyWeb.config
|
||||
int num = Val(Request["num"]);
|
||||
del_product(num);
|
||||
|
||||
var prod = _db.project_kind.AsEnumerable().Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.project_kind.Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
_db.project_kind.Remove(prod);
|
||||
@@ -265,7 +265,7 @@ public partial class admin_project_kind_reg : MyWeb.config
|
||||
|
||||
public void Del_Ohter_Items(int d_num)
|
||||
{
|
||||
var prod = _db.project_kind.AsEnumerable().Where(q => q.root == d_num).ToList();
|
||||
var prod = _db.project_kind.Where(q => q.root == d_num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
foreach (var row in prod)
|
||||
@@ -283,7 +283,7 @@ public partial class admin_project_kind_reg : MyWeb.config
|
||||
|
||||
public void del_product(int num)
|
||||
{
|
||||
var prod = _db.projects.AsEnumerable().Where(q => q.kind == num).ToList();
|
||||
var prod = _db.projects.Where(q => q.kind == num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
////查詢結果全部刪除
|
||||
|
||||
@@ -39,9 +39,8 @@ public partial class admin_project_list : MyWeb.config
|
||||
//品項
|
||||
s_actItem_num.Items.Clear();
|
||||
s_actItem_num.Items.Add(new ListItem("請選擇", ""));
|
||||
var qry = _db.actItems.AsEnumerable();
|
||||
qry = qry.Where(o => (int?)o.category==(int)Model.activity.category.Patronize);//贊助項目
|
||||
qry = qry.OrderByDescending(o => o.num).ToList();
|
||||
var qry = _db.actItems.Where(o => (int?)o.category==(int)Model.activity.category.Patronize);//贊助項目
|
||||
qry = qry.OrderByDescending(o => o.num);
|
||||
if(qry.Count() > 0)
|
||||
foreach(var qq in qry)
|
||||
s_actItem_num.Items.Add(new ListItem(qq.subject, qq.num.ToString()));
|
||||
@@ -99,7 +98,7 @@ public partial class admin_project_list : MyWeb.config
|
||||
sd.AppendChild(tr);
|
||||
|
||||
//查詢要匯出的資料
|
||||
var qry = _db.pro_order_detail.AsEnumerable();
|
||||
var qry = _db.pro_order_detail.AsQueryable();
|
||||
qry = qry.Where(o => (int?)o.actItem.category == (int)Model.activity.category.Patronize);
|
||||
|
||||
if (!string.IsNullOrEmpty(s_f_num.Value))
|
||||
@@ -111,7 +110,8 @@ public partial class admin_project_list : MyWeb.config
|
||||
var list = qry.ToList();
|
||||
if (list.Count > 0)
|
||||
{
|
||||
var projectDt = _db.projects.AsEnumerable(); //專案
|
||||
// TODO: REVIEW - projects 資料量可能成長,若超過數千筆需優化為按需查詢
|
||||
var projectDt = _db.projects.ToList(); //專案
|
||||
foreach (var item in list)
|
||||
{
|
||||
var projects = from s in projectDt
|
||||
|
||||
@@ -21,7 +21,7 @@ public partial class admin_stock_kind_reg : MyWeb.config
|
||||
if (!isStrNull(Request["num"]))
|
||||
{
|
||||
int _num = Val(Request["num"]);
|
||||
var prod = _db.stock_kind.AsEnumerable().Where(q => q.num == _num).OrderBy(q => q.kind).FirstOrDefault();
|
||||
var prod = _db.stock_kind.Where(q => q.num == _num).OrderBy(q => q.kind).FirstOrDefault();
|
||||
|
||||
if (prod != null)
|
||||
{
|
||||
@@ -210,7 +210,7 @@ public partial class admin_stock_kind_reg : MyWeb.config
|
||||
|
||||
try
|
||||
{
|
||||
var prod = _db.stock_kind.AsEnumerable().Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
var prod = _db.stock_kind.Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
if (prod != null)
|
||||
if (prod.range.HasValue)
|
||||
range = prod.range.Value + 1;
|
||||
@@ -248,7 +248,7 @@ public partial class admin_stock_kind_reg : MyWeb.config
|
||||
|
||||
int num = Val(Request["num"]);
|
||||
del_product(num);
|
||||
var prod = _db.stock_kind.AsEnumerable().Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.stock_kind.Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
_db.stock_kind.Remove(prod);
|
||||
@@ -266,7 +266,7 @@ public partial class admin_stock_kind_reg : MyWeb.config
|
||||
|
||||
public void Del_Ohter_Items(int d_num)
|
||||
{
|
||||
var prod = _db.stock_kind.AsEnumerable().Where(q => q.root == d_num).ToList();
|
||||
var prod = _db.stock_kind.Where(q => q.root == d_num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
foreach (var row in prod)
|
||||
@@ -285,7 +285,7 @@ public partial class admin_stock_kind_reg : MyWeb.config
|
||||
public void del_product(int num)
|
||||
{
|
||||
|
||||
var prod = _db.stocks.AsEnumerable().Where(q => q.kind == num).ToList();
|
||||
var prod = _db.stocks.Where(q => q.kind == num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
////查詢結果全部刪除
|
||||
|
||||
@@ -22,7 +22,7 @@ public partial class admin_stock_reason_reg : MyWeb.config
|
||||
if (!isStrNull(Request["num"]))
|
||||
{
|
||||
int _num = Val(Request["num"]);
|
||||
var prod = _db.stock_reason.AsEnumerable().Where(q => q.num == _num).OrderBy(q => q.kind).FirstOrDefault();
|
||||
var prod = _db.stock_reason.Where(q => q.num == _num).OrderBy(q => q.kind).FirstOrDefault();
|
||||
|
||||
if (prod != null)
|
||||
{
|
||||
@@ -221,7 +221,7 @@ public partial class admin_stock_reason_reg : MyWeb.config
|
||||
|
||||
try
|
||||
{
|
||||
var prod = _db.stock_reason.AsEnumerable().Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
var prod = _db.stock_reason.Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
if (prod != null)
|
||||
if (prod.range.HasValue)
|
||||
range = prod.range.Value + 1;
|
||||
@@ -257,7 +257,7 @@ public partial class admin_stock_reason_reg : MyWeb.config
|
||||
{
|
||||
|
||||
int num = Val(Request["num"]);
|
||||
var prod = _db.stock_reason.AsEnumerable().Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.stock_reason.Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
_db.stock_reason.Remove(prod);
|
||||
@@ -275,7 +275,7 @@ public partial class admin_stock_reason_reg : MyWeb.config
|
||||
|
||||
public void Del_Ohter_Items(int d_num)
|
||||
{
|
||||
var prod = _db.stock_reason.AsEnumerable().Where(q => q.root == d_num).ToList();
|
||||
var prod = _db.stock_reason.Where(q => q.root == d_num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
foreach (var row in prod)
|
||||
|
||||
@@ -21,7 +21,7 @@ public partial class admin_supplier_kind_reg : MyWeb.config
|
||||
if (!isStrNull(Request["num"]))
|
||||
{
|
||||
int _num = Val(Request["num"]);
|
||||
var prod = _db.supplier_kind.AsEnumerable().Where(q => q.num == _num).OrderBy(q => q.kind).FirstOrDefault();
|
||||
var prod = _db.supplier_kind.Where(q => q.num == _num).OrderBy(q => q.kind).FirstOrDefault();
|
||||
|
||||
if (prod != null)
|
||||
{
|
||||
@@ -210,7 +210,7 @@ public partial class admin_supplier_kind_reg : MyWeb.config
|
||||
|
||||
try
|
||||
{
|
||||
var prod = _db.supplier_kind.AsEnumerable().Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
var prod = _db.supplier_kind.Where(q => q.root == root).OrderByDescending(q => q.range).FirstOrDefault();
|
||||
if (prod != null)
|
||||
if (prod.range.HasValue)
|
||||
range = prod.range.Value + 1;
|
||||
@@ -248,7 +248,7 @@ public partial class admin_supplier_kind_reg : MyWeb.config
|
||||
|
||||
int num = Val(Request["num"]);
|
||||
//del_product(num);
|
||||
var prod = _db.supplier_kind.AsEnumerable().Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
var prod = _db.supplier_kind.Where(q => q.num == num).FirstOrDefault(); //刪除該筆資料
|
||||
if (prod != null)
|
||||
{
|
||||
_db.supplier_kind.Remove(prod);
|
||||
@@ -266,7 +266,7 @@ public partial class admin_supplier_kind_reg : MyWeb.config
|
||||
|
||||
public void Del_Ohter_Items(int d_num)
|
||||
{
|
||||
var prod = _db.supplier_kind.AsEnumerable().Where(q => q.root == d_num).ToList();
|
||||
var prod = _db.supplier_kind.Where(q => q.root == d_num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
foreach (var row in prod)
|
||||
@@ -285,7 +285,7 @@ public partial class admin_supplier_kind_reg : MyWeb.config
|
||||
public void del_product(int num)
|
||||
{
|
||||
|
||||
var prod = _db.suppliers.AsEnumerable().Where(q => q.kind == num).ToList();
|
||||
var prod = _db.suppliers.Where(q => q.kind == num).ToList();
|
||||
if (prod.Count > 0)
|
||||
{
|
||||
////查詢結果全部刪除
|
||||
|
||||
28
web/test_asenumerable_check.aspx
Normal file
28
web/test_asenumerable_check.aspx
Normal file
@@ -0,0 +1,28 @@
|
||||
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="test_asenumerable_check.aspx.cs" Inherits="test_asenumerable_check" %>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>AsEnumerable 修改檢測工具</title>
|
||||
<style>
|
||||
body { font-family: 'Consolas', monospace; margin: 20px; background: #1e1e1e; color: #d4d4d4; }
|
||||
.success { color: #4ec9b0; font-weight: bold; }
|
||||
.error { color: #f48771; font-weight: bold; }
|
||||
.warning { color: #dcdcaa; font-weight: bold; }
|
||||
.sql-box { background: #252526; padding: 15px; margin: 10px 0; border-left: 4px solid #007acc; }
|
||||
.test-item { margin: 20px 0; padding: 15px; background: #2d2d30; border-radius: 4px; }
|
||||
h2 { color: #4ec9b0; }
|
||||
h3 { color: #dcdcaa; margin-top: 20px; }
|
||||
pre { white-space: pre-wrap; word-wrap: break-word; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>🔍 AsEnumerable 修改檢測報告</h1>
|
||||
<form runat="server">
|
||||
<asp:Button ID="btnRunTest" runat="server" Text="▶ 執行檢測" OnClick="btnRunTest_Click"
|
||||
style="padding: 10px 20px; font-size: 16px; cursor: pointer;" />
|
||||
<hr />
|
||||
<asp:Literal ID="litResult" runat="server"></asp:Literal>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
346
web/test_asenumerable_check.aspx.cs
Normal file
346
web/test_asenumerable_check.aspx.cs
Normal file
@@ -0,0 +1,346 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Model;
|
||||
|
||||
public partial class test_asenumerable_check : System.Web.UI.Page
|
||||
{
|
||||
private StringBuilder output = new StringBuilder();
|
||||
private int passCount = 0;
|
||||
private int failCount = 0;
|
||||
private int warnCount = 0;
|
||||
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
if (!IsPostBack)
|
||||
{
|
||||
litResult.Text = "<p style='color:#888;'>點擊「執行檢測」開始測試修改結果</p>";
|
||||
}
|
||||
}
|
||||
|
||||
protected void btnRunTest_Click(object sender, EventArgs e)
|
||||
{
|
||||
output.Clear();
|
||||
passCount = 0;
|
||||
failCount = 0;
|
||||
warnCount = 0;
|
||||
|
||||
output.AppendLine("<div style='margin-bottom: 20px;'>");
|
||||
output.AppendLine($"<p>測試時間: {DateTime.Now:yyyy-MM-dd HH:mm:ss}</p>");
|
||||
output.AppendLine("</div>");
|
||||
|
||||
// 執行所有測試
|
||||
TestAccountingKind();
|
||||
TestActivityKind();
|
||||
TestFollowers();
|
||||
TestMembers();
|
||||
TestOrders();
|
||||
|
||||
// 顯示總結
|
||||
output.AppendLine("<hr />");
|
||||
output.AppendLine("<h2>📊 測試總結</h2>");
|
||||
output.AppendLine($"<p class='success'>✅ 通過: {passCount} 項</p>");
|
||||
output.AppendLine($"<p class='error'>❌ 失敗: {failCount} 項</p>");
|
||||
output.AppendLine($"<p class='warning'>⚠️ 警告: {warnCount} 項</p>");
|
||||
|
||||
if (failCount == 0)
|
||||
{
|
||||
output.AppendLine("<h3 class='success'>🎉 所有測試通過!修改成功!</h3>");
|
||||
}
|
||||
else
|
||||
{
|
||||
output.AppendLine("<h3 class='error'>⚠️ 發現問題,請檢查失敗的項目</h3>");
|
||||
}
|
||||
|
||||
litResult.Text = output.ToString();
|
||||
}
|
||||
|
||||
private void TestAccountingKind()
|
||||
{
|
||||
output.AppendLine("<h3>測試 1: accounting_kind 查詢優化</h3>");
|
||||
|
||||
using (var db = new ezEntities())
|
||||
{
|
||||
var sqlLog = new StringBuilder();
|
||||
db.Database.Log = sql => sqlLog.AppendLine(sql);
|
||||
|
||||
try
|
||||
{
|
||||
// 測試 1.1: 單筆查詢
|
||||
sqlLog.Clear();
|
||||
var sw = Stopwatch.StartNew();
|
||||
var result = db.accounting_kind.Where(q => q.num == 1).FirstOrDefault();
|
||||
sw.Stop();
|
||||
|
||||
CheckQuery("單筆查詢 (Where + FirstOrDefault)",
|
||||
sqlLog.ToString(),
|
||||
sw.ElapsedMilliseconds,
|
||||
shouldHaveWhere: true,
|
||||
shouldHaveSelectAll: false,
|
||||
maxTime: 50);
|
||||
|
||||
// 測試 1.2: 檢查子資料 (應該用 Any)
|
||||
sqlLog.Clear();
|
||||
sw.Restart();
|
||||
var hasChildren = db.accounting_kind.Any(q => q.root == 1);
|
||||
sw.Stop();
|
||||
|
||||
CheckQuery("檢查子資料存在 (Any)",
|
||||
sqlLog.ToString(),
|
||||
sw.ElapsedMilliseconds,
|
||||
shouldHaveWhere: true,
|
||||
shouldHaveExists: true,
|
||||
maxTime: 30);
|
||||
|
||||
// 測試 1.3: 取得子資料清單
|
||||
sqlLog.Clear();
|
||||
sw.Restart();
|
||||
var children = db.accounting_kind.Where(q => q.root == 1).ToList();
|
||||
sw.Stop();
|
||||
|
||||
CheckQuery("取得子資料清單 (Where + ToList)",
|
||||
sqlLog.ToString(),
|
||||
sw.ElapsedMilliseconds,
|
||||
shouldHaveWhere: true,
|
||||
shouldHaveSelectAll: false,
|
||||
maxTime: 100);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogError($"accounting_kind 測試失敗: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TestActivityKind()
|
||||
{
|
||||
output.AppendLine("<h3>測試 2: activity_kind 查詢優化</h3>");
|
||||
|
||||
using (var db = new ezEntities())
|
||||
{
|
||||
var sqlLog = new StringBuilder();
|
||||
db.Database.Log = sql => sqlLog.AppendLine(sql);
|
||||
|
||||
try
|
||||
{
|
||||
// 單筆查詢 + 排序
|
||||
sqlLog.Clear();
|
||||
var sw = Stopwatch.StartNew();
|
||||
var result = db.activity_kind
|
||||
.Where(q => q.num == 1)
|
||||
.OrderBy(q => q.kind)
|
||||
.FirstOrDefault();
|
||||
sw.Stop();
|
||||
|
||||
CheckQuery("單筆查詢 + 排序 (Where + OrderBy + FirstOrDefault)",
|
||||
sqlLog.ToString(),
|
||||
sw.ElapsedMilliseconds,
|
||||
shouldHaveWhere: true,
|
||||
shouldHaveOrderBy: true,
|
||||
maxTime: 50);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogError($"activity_kind 測試失敗: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TestFollowers()
|
||||
{
|
||||
output.AppendLine("<h3>測試 3: followers 查詢優化</h3>");
|
||||
|
||||
using (var db = new ezEntities())
|
||||
{
|
||||
var sqlLog = new StringBuilder();
|
||||
db.Database.Log = sql => sqlLog.AppendLine(sql);
|
||||
|
||||
try
|
||||
{
|
||||
// 測試字串查詢 (Contains)
|
||||
sqlLog.Clear();
|
||||
var sw = Stopwatch.StartNew();
|
||||
var result = db.followers
|
||||
.Where(q => q.f_number.Contains("A"))
|
||||
.Take(10)
|
||||
.ToList();
|
||||
sw.Stop();
|
||||
|
||||
CheckQuery("字串查詢 (Contains)",
|
||||
sqlLog.ToString(),
|
||||
sw.ElapsedMilliseconds,
|
||||
shouldHaveWhere: true,
|
||||
shouldHaveLike: true,
|
||||
maxTime: 100);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogError($"followers 測試失敗: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TestMembers()
|
||||
{
|
||||
output.AppendLine("<h3>測試 4: members 查詢優化</h3>");
|
||||
|
||||
using (var db = new ezEntities())
|
||||
{
|
||||
var sqlLog = new StringBuilder();
|
||||
db.Database.Log = sql => sqlLog.AppendLine(sql);
|
||||
|
||||
try
|
||||
{
|
||||
// 測試批次查詢
|
||||
var ids = new[] { 1, 2, 3 };
|
||||
sqlLog.Clear();
|
||||
var sw = Stopwatch.StartNew();
|
||||
var result = db.members.Where(q => ids.Contains(q.num)).ToList();
|
||||
sw.Stop();
|
||||
|
||||
CheckQuery("批次 ID 查詢 (Contains)",
|
||||
sqlLog.ToString(),
|
||||
sw.ElapsedMilliseconds,
|
||||
shouldHaveWhere: true,
|
||||
shouldHaveIn: true,
|
||||
maxTime: 100);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogError($"members 測試失敗: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TestOrders()
|
||||
{
|
||||
output.AppendLine("<h3>測試 5: pro_order_detail 聚合查詢</h3>");
|
||||
|
||||
using (var db = new ezEntities())
|
||||
{
|
||||
var sqlLog = new StringBuilder();
|
||||
db.Database.Log = sql => sqlLog.AppendLine(sql);
|
||||
|
||||
try
|
||||
{
|
||||
// 測試 Count
|
||||
sqlLog.Clear();
|
||||
var sw = Stopwatch.StartNew();
|
||||
var count = db.pro_order_detail.Count(q => q.num > 0);
|
||||
sw.Stop();
|
||||
|
||||
CheckQuery("Count 查詢",
|
||||
sqlLog.ToString(),
|
||||
sw.ElapsedMilliseconds,
|
||||
shouldHaveWhere: true,
|
||||
shouldHaveCount: true,
|
||||
maxTime: 50);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogError($"pro_order_detail 測試失敗: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckQuery(string testName, string sql, long milliseconds,
|
||||
bool shouldHaveWhere = false,
|
||||
bool shouldHaveSelectAll = false,
|
||||
bool shouldHaveExists = false,
|
||||
bool shouldHaveOrderBy = false,
|
||||
bool shouldHaveLike = false,
|
||||
bool shouldHaveIn = false,
|
||||
bool shouldHaveCount = false,
|
||||
long maxTime = 100)
|
||||
{
|
||||
output.AppendLine("<div class='test-item'>");
|
||||
output.AppendLine($"<h4>🔸 {testName}</h4>");
|
||||
output.AppendLine($"<p>執行時間: {milliseconds}ms</p>");
|
||||
|
||||
bool passed = true;
|
||||
var issues = new StringBuilder();
|
||||
|
||||
// 檢查是否有 WHERE 條件
|
||||
if (shouldHaveWhere && !sql.Contains("WHERE"))
|
||||
{
|
||||
issues.AppendLine("❌ 缺少 WHERE 條件(可能載入整表)<br/>");
|
||||
passed = false;
|
||||
}
|
||||
|
||||
// 檢查是否有不當的 SELECT *
|
||||
if (!shouldHaveSelectAll && sql.Contains("SELECT") && !sql.Contains("WHERE") && !sql.Contains("TOP"))
|
||||
{
|
||||
issues.AppendLine("❌ SELECT 沒有條件限制(載入整表)<br/>");
|
||||
passed = false;
|
||||
}
|
||||
|
||||
// 檢查是否使用 EXISTS(Any 應該產生)
|
||||
if (shouldHaveExists && !sql.Contains("EXISTS"))
|
||||
{
|
||||
issues.AppendLine("⚠️ 建議使用 EXISTS 而非載入資料<br/>");
|
||||
warnCount++;
|
||||
}
|
||||
|
||||
// 檢查是否有 ORDER BY
|
||||
if (shouldHaveOrderBy && !sql.Contains("ORDER BY"))
|
||||
{
|
||||
issues.AppendLine("❌ 缺少 ORDER BY(排序應該在資料庫執行)<br/>");
|
||||
passed = false;
|
||||
}
|
||||
|
||||
// 檢查是否有 LIKE(Contains 應該產生)
|
||||
if (shouldHaveLike && !sql.Contains("LIKE"))
|
||||
{
|
||||
issues.AppendLine("❌ 字串查詢未轉為 LIKE<br/>");
|
||||
passed = false;
|
||||
}
|
||||
|
||||
// 檢查是否有 IN(批次查詢應該產生)
|
||||
if (shouldHaveIn && !sql.Contains("IN"))
|
||||
{
|
||||
issues.AppendLine("❌ 批次查詢未轉為 IN<br/>");
|
||||
passed = false;
|
||||
}
|
||||
|
||||
// 檢查是否有 COUNT(聚合函數應該在資料庫執行)
|
||||
if (shouldHaveCount && !sql.Contains("COUNT"))
|
||||
{
|
||||
issues.AppendLine("❌ COUNT 未在資料庫執行<br/>");
|
||||
passed = false;
|
||||
}
|
||||
|
||||
// 檢查執行時間
|
||||
if (milliseconds > maxTime)
|
||||
{
|
||||
issues.AppendLine($"⚠️ 執行時間較長 (>{maxTime}ms),可能仍有優化空間<br/>");
|
||||
warnCount++;
|
||||
}
|
||||
|
||||
if (passed)
|
||||
{
|
||||
output.AppendLine("<p class='success'>✅ 測試通過</p>");
|
||||
passCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
output.AppendLine("<p class='error'>❌ 測試失敗</p>");
|
||||
output.AppendLine($"<div style='color:#f48771;'>{issues}</div>");
|
||||
failCount++;
|
||||
}
|
||||
|
||||
// 顯示 SQL
|
||||
output.AppendLine("<div class='sql-box'>");
|
||||
output.AppendLine("<strong>產生的 SQL:</strong><br/>");
|
||||
output.AppendLine($"<pre>{System.Web.HttpUtility.HtmlEncode(sql)}</pre>");
|
||||
output.AppendLine("</div>");
|
||||
output.AppendLine("</div>");
|
||||
}
|
||||
|
||||
private void LogError(string message)
|
||||
{
|
||||
output.AppendLine($"<p class='error'>❌ {message}</p>");
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user