Compare commits
14 Commits
63cab37c87
...
1106
| Author | SHA1 | Date | |
|---|---|---|---|
| c0404b8e70 | |||
| 1a6731e4c6 | |||
| b776b411b4 | |||
| e9f17a5037 | |||
| 05ef2e28f3 | |||
| 90ef949ca4 | |||
| 39c9dd29e1 | |||
| a6aa35176c | |||
| 6a43883d08 | |||
| 7d36d6b0a6 | |||
| 87a2c35300 | |||
| 7d57e292fe | |||
| 6fc82510cc | |||
| 4a36ce9c1c |
BIN
data/SQL/AncestralTabletStatus_script.sql
Normal file
BIN
data/SQL/AncestralTabletStatus_script.sql
Normal file
Binary file not shown.
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
|
||||
BIN
data/SQL/完整資料結構(僅限本地,不包含其它分支更新)_script_1029.sql
Normal file
BIN
data/SQL/完整資料結構(僅限本地,不包含其它分支更新)_script_1029.sql
Normal file
Binary file not shown.
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
|
||||
```
|
||||
11
data/memo/新增 文字文件.md
Normal file
11
data/memo/新增 文字文件.md
Normal file
@@ -0,0 +1,11 @@
|
||||
資料字典:
|
||||
USE [17168erp_t]
|
||||
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
|
||||
代碼中會用到上面表中的狀態,所以必須在該表中插入上面的數據
|
||||
AncestralTabletStatus_script.sql文件中的表是神祖牌位功能模組需要用到的表,再運行之前需要先執行該文件
|
||||
|
||||
執行AncestralTabletStatus_script.sql後要把在item表中新增的URL權限添加到相應的管理員帳號
|
||||
BIN
data/查詢範例.xlsx
Normal file
BIN
data/查詢範例.xlsx
Normal file
Binary file not shown.
BIN
data/神主牌管理系統資料字典設計.docx
Normal file
BIN
data/神主牌管理系統資料字典設計.docx
Normal file
Binary file not shown.
@@ -89,6 +89,11 @@ namespace Model
|
||||
public virtual DbSet<RegionRoomBedStatus> RegionRoomBedStatus { get; set; }
|
||||
public virtual DbSet<RegionType> RegionType { get; set; }
|
||||
public virtual DbSet<Room> Room { get; set; }
|
||||
public virtual DbSet<AncestralTabletArea> AncestralTabletArea { get; set; }
|
||||
public virtual DbSet<AncestralTabletPosition> AncestralTabletPosition { get; set; }
|
||||
public virtual DbSet<AncestralTabletPositionRecord> AncestralTabletPositionRecord { get; set; }
|
||||
public virtual DbSet<AncestralTabletRegistrant> AncestralTabletRegistrant { get; set; }
|
||||
public virtual DbSet<AncestralTabletStatus> AncestralTabletStatus { get; set; }
|
||||
|
||||
public virtual int pager_eztrust(Nullable<int> startRowIndex, Nullable<int> pageSize, string tableName, string columnName, string sqlWhere, string orderBy, ObjectParameter rowCount)
|
||||
{
|
||||
|
||||
@@ -523,6 +523,139 @@ namespace Model
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public partial class AncestralTabletArea
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
|
||||
public AncestralTabletArea()
|
||||
{
|
||||
this.AncestralTabletArea1 = new HashSet<AncestralTabletArea>();
|
||||
this.AncestralTabletPosition = new HashSet<AncestralTabletPosition>();
|
||||
}
|
||||
|
||||
public int AreaId { get; set; }
|
||||
public string AreaName { get; set; }
|
||||
public string AreaCode { get; set; }
|
||||
public Nullable<int> ParentAreaId { get; set; }
|
||||
public string AreaType { get; set; }
|
||||
public Nullable<int> Price { get; set; }
|
||||
public Nullable<int> SortOrder { get; set; }
|
||||
public bool IsDisabled { get; set; }
|
||||
public string Description { get; set; }
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||
public virtual ICollection<AncestralTabletArea> AncestralTabletArea1 { get; set; }
|
||||
public virtual AncestralTabletArea AncestralTabletArea2 { get; set; }
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||
public virtual ICollection<AncestralTabletPosition> AncestralTabletPosition { get; set; }
|
||||
}
|
||||
}
|
||||
namespace Model
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public partial class AncestralTabletPosition
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
|
||||
public AncestralTabletPosition()
|
||||
{
|
||||
this.AncestralTabletRegistrant = new HashSet<AncestralTabletRegistrant>();
|
||||
}
|
||||
|
||||
public int PositionId { get; set; }
|
||||
public int AreaId { get; set; }
|
||||
public string PositionCode { get; set; }
|
||||
public string PositionName { get; set; }
|
||||
public Nullable<int> Price { get; set; }
|
||||
public string StatusCode { get; set; }
|
||||
public string Description { get; set; }
|
||||
public Nullable<int> RowNo { get; set; }
|
||||
public Nullable<int> ColumnNo { get; set; }
|
||||
|
||||
public virtual AncestralTabletArea AncestralTabletArea { get; set; }
|
||||
public virtual AncestralTabletStatus AncestralTabletStatus { get; set; }
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||
public virtual ICollection<AncestralTabletRegistrant> AncestralTabletRegistrant { get; set; }
|
||||
}
|
||||
}
|
||||
namespace Model
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public partial class AncestralTabletPositionRecord
|
||||
{
|
||||
public int RecordId { get; set; }
|
||||
public string RegistrantCode { get; set; }
|
||||
public string NPTitle { get; set; }
|
||||
public System.DateTime NPStandDate { get; set; }
|
||||
public string NPYangShang { get; set; }
|
||||
public string WPContent { get; set; }
|
||||
public System.DateTime CreatedAt { get; set; }
|
||||
public Nullable<System.DateTime> UpdatedAt { get; set; }
|
||||
|
||||
public virtual AncestralTabletRegistrant AncestralTabletRegistrant { get; set; }
|
||||
}
|
||||
}
|
||||
namespace Model
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public partial class AncestralTabletRegistrant
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
|
||||
public AncestralTabletRegistrant()
|
||||
{
|
||||
this.AncestralTabletPositionRecord = new HashSet<AncestralTabletPositionRecord>();
|
||||
}
|
||||
|
||||
public string RegistrantCode { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Phone { get; set; }
|
||||
public string Address { get; set; }
|
||||
public System.DateTime RegisterDate { get; set; }
|
||||
public Nullable<int> Price { get; set; }
|
||||
public Nullable<int> PositionId { get; set; }
|
||||
public System.DateTime StartDate { get; set; }
|
||||
public Nullable<System.DateTime> EndDate { get; set; }
|
||||
public bool IsLongTerm { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public System.DateTime CreatedAt { get; set; }
|
||||
public Nullable<System.DateTime> UpdatedAt { get; set; }
|
||||
public bool IsEnd { get; set; }
|
||||
|
||||
public virtual AncestralTabletPosition AncestralTabletPosition { get; set; }
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||
public virtual ICollection<AncestralTabletPositionRecord> AncestralTabletPositionRecord { get; set; }
|
||||
}
|
||||
}
|
||||
namespace Model
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public partial class AncestralTabletStatus
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
|
||||
public AncestralTabletStatus()
|
||||
{
|
||||
this.AncestralTabletPosition = new HashSet<AncestralTabletPosition>();
|
||||
}
|
||||
|
||||
public string StatusCode { get; set; }
|
||||
public string StatusName { get; set; }
|
||||
public string StatusType { get; set; }
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||
public virtual ICollection<AncestralTabletPosition> AncestralTabletPosition { get; set; }
|
||||
}
|
||||
}
|
||||
namespace Model
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public partial class appellation
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
|
||||
@@ -857,6 +990,12 @@ namespace Model
|
||||
|
||||
public partial class GuaDanOrder
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
|
||||
public GuaDanOrder()
|
||||
{
|
||||
this.GuaDanOrderGuest = new HashSet<GuaDanOrderGuest>();
|
||||
}
|
||||
|
||||
public Nullable<System.DateTime> StartDate { get; set; }
|
||||
public Nullable<System.DateTime> EndDate { get; set; }
|
||||
public Nullable<int> CreateUser { get; set; }
|
||||
@@ -874,6 +1013,8 @@ namespace Model
|
||||
|
||||
public virtual admin admin { get; set; }
|
||||
public virtual follower followers { get; set; }
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||
public virtual ICollection<GuaDanOrderGuest> GuaDanOrderGuest { get; set; }
|
||||
}
|
||||
}
|
||||
namespace Model
|
||||
@@ -898,6 +1039,7 @@ namespace Model
|
||||
public Nullable<System.DateTime> CheckInAt { get; set; }
|
||||
public Nullable<System.DateTime> CheckOutAt { get; set; }
|
||||
public string StatusCode { get; set; }
|
||||
public Nullable<System.Guid> OrderUuid { get; set; }
|
||||
|
||||
public virtual follower followers { get; set; }
|
||||
public virtual RegionRoomBed RegionRoomBed { get; set; }
|
||||
@@ -905,6 +1047,7 @@ namespace Model
|
||||
public virtual RegionRoomBedStatus RegionRoomBedStatus { get; set; }
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
|
||||
public virtual ICollection<RegionAndRoomAndBedSchedule> RegionAndRoomAndBedSchedule { get; set; }
|
||||
public virtual GuaDanOrder GuaDanOrder { get; set; }
|
||||
}
|
||||
}
|
||||
namespace Model
|
||||
|
||||
@@ -254,6 +254,74 @@
|
||||
<Property Name="word" Type="nvarchar(max)" />
|
||||
<Property Name="systems" Type="int" />
|
||||
</EntityType>
|
||||
<EntityType Name="AncestralTabletArea">
|
||||
<Key>
|
||||
<PropertyRef Name="AreaId" />
|
||||
</Key>
|
||||
<Property Name="AreaId" Type="int" StoreGeneratedPattern="Identity" Nullable="false" />
|
||||
<Property Name="AreaName" Type="nvarchar" MaxLength="10" Nullable="false" />
|
||||
<Property Name="AreaCode" Type="nvarchar" MaxLength="20" Nullable="false" />
|
||||
<Property Name="ParentAreaId" Type="int" />
|
||||
<Property Name="AreaType" Type="nvarchar" MaxLength="10" />
|
||||
<Property Name="Price" Type="int" />
|
||||
<Property Name="SortOrder" Type="int" />
|
||||
<Property Name="IsDisabled" Type="bit" Nullable="false" />
|
||||
<Property Name="Description" Type="nvarchar" MaxLength="200" />
|
||||
</EntityType>
|
||||
<EntityType Name="AncestralTabletPosition">
|
||||
<Key>
|
||||
<PropertyRef Name="PositionId" />
|
||||
</Key>
|
||||
<Property Name="PositionId" Type="int" StoreGeneratedPattern="Identity" Nullable="false" />
|
||||
<Property Name="AreaId" Type="int" Nullable="false" />
|
||||
<Property Name="PositionCode" Type="nvarchar" MaxLength="20" Nullable="false" />
|
||||
<Property Name="PositionName" Type="nvarchar" MaxLength="50" />
|
||||
<Property Name="Price" Type="int" />
|
||||
<Property Name="StatusCode" Type="nvarchar" MaxLength="20" />
|
||||
<Property Name="Description" Type="nvarchar" MaxLength="200" />
|
||||
<Property Name="RowNo" Type="int" />
|
||||
<Property Name="ColumnNo" Type="int" />
|
||||
</EntityType>
|
||||
<EntityType Name="AncestralTabletPositionRecord">
|
||||
<Key>
|
||||
<PropertyRef Name="RecordId" />
|
||||
</Key>
|
||||
<Property Name="RecordId" Type="int" StoreGeneratedPattern="Identity" Nullable="false" />
|
||||
<Property Name="RegistrantCode" Type="nvarchar" MaxLength="20" Nullable="false" />
|
||||
<Property Name="NPTitle" Type="nvarchar" MaxLength="30" />
|
||||
<Property Name="NPStandDate" Type="date" Nullable="false" />
|
||||
<Property Name="NPYangShang" Type="nvarchar" MaxLength="20" />
|
||||
<Property Name="WPContent" Type="nvarchar" MaxLength="1000" />
|
||||
<Property Name="CreatedAt" Type="datetime" Nullable="false" />
|
||||
<Property Name="UpdatedAt" Type="datetime" />
|
||||
</EntityType>
|
||||
<EntityType Name="AncestralTabletRegistrant">
|
||||
<Key>
|
||||
<PropertyRef Name="RegistrantCode" />
|
||||
</Key>
|
||||
<Property Name="RegistrantCode" Type="nvarchar" MaxLength="20" Nullable="false" />
|
||||
<Property Name="Name" Type="nvarchar" MaxLength="50" Nullable="false" />
|
||||
<Property Name="Phone" Type="nvarchar" MaxLength="50" />
|
||||
<Property Name="Address" Type="nvarchar" MaxLength="60" />
|
||||
<Property Name="RegisterDate" Type="date" Nullable="false" />
|
||||
<Property Name="Price" Type="int" />
|
||||
<Property Name="PositionId" Type="int" />
|
||||
<Property Name="StartDate" Type="date" Nullable="false" />
|
||||
<Property Name="EndDate" Type="date" />
|
||||
<Property Name="IsLongTerm" Type="bit" Nullable="false" />
|
||||
<Property Name="IsActive" Type="bit" Nullable="false" />
|
||||
<Property Name="CreatedAt" Type="datetime" Nullable="false" />
|
||||
<Property Name="UpdatedAt" Type="datetime" />
|
||||
<Property Name="IsEnd" Type="bit" Nullable="false" />
|
||||
</EntityType>
|
||||
<EntityType Name="AncestralTabletStatus">
|
||||
<Key>
|
||||
<PropertyRef Name="StatusCode" />
|
||||
</Key>
|
||||
<Property Name="StatusCode" Type="nvarchar" MaxLength="20" Nullable="false" />
|
||||
<Property Name="StatusName" Type="nvarchar" MaxLength="20" Nullable="false" />
|
||||
<Property Name="StatusType" Type="nvarchar" MaxLength="20" Nullable="false" />
|
||||
</EntityType>
|
||||
<EntityType Name="appellation">
|
||||
<Key>
|
||||
<PropertyRef Name="num" />
|
||||
@@ -454,6 +522,7 @@
|
||||
<Property Name="CheckInAt" Type="date" />
|
||||
<Property Name="CheckOutAt" Type="date" />
|
||||
<Property Name="StatusCode" Type="nvarchar" MaxLength="20" Nullable="false" />
|
||||
<Property Name="OrderUuid" Type="uniqueidentifier" />
|
||||
</EntityType>
|
||||
<EntityType Name="GuadanTimeSetting">
|
||||
<Key>
|
||||
@@ -910,6 +979,18 @@
|
||||
<Property Name="balance_act_item" Type="int" />
|
||||
<Property Name="balance_pro_order_detail" Type="int" />
|
||||
</EntityType>
|
||||
<Association Name="FK__Ancestral__Regis__5A1A5A11">
|
||||
<End Role="AncestralTabletRegistrant" Type="Self.AncestralTabletRegistrant" Multiplicity="1" />
|
||||
<End Role="AncestralTabletPositionRecord" Type="Self.AncestralTabletPositionRecord" Multiplicity="*" />
|
||||
<ReferentialConstraint>
|
||||
<Principal Role="AncestralTabletRegistrant">
|
||||
<PropertyRef Name="RegistrantCode" />
|
||||
</Principal>
|
||||
<Dependent Role="AncestralTabletPositionRecord">
|
||||
<PropertyRef Name="RegistrantCode" />
|
||||
</Dependent>
|
||||
</ReferentialConstraint>
|
||||
</Association>
|
||||
<Association Name="FK_accounting_accounting_kind">
|
||||
<End Role="accounting_kind" Type="Self.accounting_kind" Multiplicity="0..1" />
|
||||
<End Role="accounting" Type="Self.accounting" Multiplicity="*" />
|
||||
@@ -1178,6 +1259,18 @@
|
||||
</Dependent>
|
||||
</ReferentialConstraint>
|
||||
</Association>
|
||||
<Association Name="FK_AncestralTabletArea_Parent">
|
||||
<End Role="AncestralTabletArea" Type="Self.AncestralTabletArea" Multiplicity="0..1" />
|
||||
<End Role="AncestralTabletArea1" Type="Self.AncestralTabletArea" Multiplicity="*" />
|
||||
<ReferentialConstraint>
|
||||
<Principal Role="AncestralTabletArea">
|
||||
<PropertyRef Name="AreaId" />
|
||||
</Principal>
|
||||
<Dependent Role="AncestralTabletArea1">
|
||||
<PropertyRef Name="ParentAreaId" />
|
||||
</Dependent>
|
||||
</ReferentialConstraint>
|
||||
</Association>
|
||||
<Association Name="FK_bed_kind_detail_bed_kind">
|
||||
<End Role="bed_kind" Type="Self.bed_kind" Multiplicity="0..1" />
|
||||
<End Role="bed_kind_detail" Type="Self.bed_kind_detail" Multiplicity="*" />
|
||||
@@ -1372,6 +1465,18 @@
|
||||
</Dependent>
|
||||
</ReferentialConstraint>
|
||||
</Association>
|
||||
<Association Name="FK_GuaDanOrderGuest_Order">
|
||||
<End Role="GuaDanOrder" Type="Self.GuaDanOrder" Multiplicity="0..1" />
|
||||
<End Role="GuaDanOrderGuest" Type="Self.GuaDanOrderGuest" Multiplicity="*" />
|
||||
<ReferentialConstraint>
|
||||
<Principal Role="GuaDanOrder">
|
||||
<PropertyRef Name="Uuid" />
|
||||
</Principal>
|
||||
<Dependent Role="GuaDanOrderGuest">
|
||||
<PropertyRef Name="OrderUuid" />
|
||||
</Dependent>
|
||||
</ReferentialConstraint>
|
||||
</Association>
|
||||
<Association Name="FK_GuaDanOrderGuest_RoomUuid">
|
||||
<End Role="Room" Type="Self.Room" Multiplicity="0..1" />
|
||||
<End Role="GuaDanOrderGuest" Type="Self.GuaDanOrderGuest" Multiplicity="*" />
|
||||
@@ -1506,6 +1611,30 @@
|
||||
</Dependent>
|
||||
</ReferentialConstraint>
|
||||
</Association>
|
||||
<Association Name="FK_Position_Area">
|
||||
<End Role="AncestralTabletArea" Type="Self.AncestralTabletArea" Multiplicity="1" />
|
||||
<End Role="AncestralTabletPosition" Type="Self.AncestralTabletPosition" Multiplicity="*" />
|
||||
<ReferentialConstraint>
|
||||
<Principal Role="AncestralTabletArea">
|
||||
<PropertyRef Name="AreaId" />
|
||||
</Principal>
|
||||
<Dependent Role="AncestralTabletPosition">
|
||||
<PropertyRef Name="AreaId" />
|
||||
</Dependent>
|
||||
</ReferentialConstraint>
|
||||
</Association>
|
||||
<Association Name="FK_Position_Status">
|
||||
<End Role="AncestralTabletStatus" Type="Self.AncestralTabletStatus" Multiplicity="0..1" />
|
||||
<End Role="AncestralTabletPosition" Type="Self.AncestralTabletPosition" Multiplicity="*" />
|
||||
<ReferentialConstraint>
|
||||
<Principal Role="AncestralTabletStatus">
|
||||
<PropertyRef Name="StatusCode" />
|
||||
</Principal>
|
||||
<Dependent Role="AncestralTabletPosition">
|
||||
<PropertyRef Name="StatusCode" />
|
||||
</Dependent>
|
||||
</ReferentialConstraint>
|
||||
</Association>
|
||||
<Association Name="FK_pro_order_activity">
|
||||
<End Role="activity" Type="Self.activity" Multiplicity="0..1" />
|
||||
<End Role="pro_order" Type="Self.pro_order" Multiplicity="*" />
|
||||
@@ -1718,6 +1847,18 @@
|
||||
</Dependent>
|
||||
</ReferentialConstraint>
|
||||
</Association>
|
||||
<Association Name="FK_Registrant_Position">
|
||||
<End Role="AncestralTabletPosition" Type="Self.AncestralTabletPosition" Multiplicity="0..1" />
|
||||
<End Role="AncestralTabletRegistrant" Type="Self.AncestralTabletRegistrant" Multiplicity="*" />
|
||||
<ReferentialConstraint>
|
||||
<Principal Role="AncestralTabletPosition">
|
||||
<PropertyRef Name="PositionId" />
|
||||
</Principal>
|
||||
<Dependent Role="AncestralTabletRegistrant">
|
||||
<PropertyRef Name="PositionId" />
|
||||
</Dependent>
|
||||
</ReferentialConstraint>
|
||||
</Association>
|
||||
<Association Name="FK_Room_Region">
|
||||
<End Role="Region" Type="Self.Region" Multiplicity="1" />
|
||||
<End Role="Room" Type="Self.Room" Multiplicity="*" />
|
||||
@@ -1966,6 +2107,11 @@
|
||||
<EntitySet Name="admin" EntityType="Self.admin" Schema="dbo" store:Type="Tables" />
|
||||
<EntitySet Name="admin_group" EntityType="Self.admin_group" Schema="dbo" store:Type="Tables" />
|
||||
<EntitySet Name="admin_log" EntityType="Self.admin_log" Schema="dbo" store:Type="Tables" />
|
||||
<EntitySet Name="AncestralTabletArea" EntityType="Self.AncestralTabletArea" Schema="dbo" store:Type="Tables" />
|
||||
<EntitySet Name="AncestralTabletPosition" EntityType="Self.AncestralTabletPosition" Schema="dbo" store:Type="Tables" />
|
||||
<EntitySet Name="AncestralTabletPositionRecord" EntityType="Self.AncestralTabletPositionRecord" Schema="dbo" store:Type="Tables" />
|
||||
<EntitySet Name="AncestralTabletRegistrant" EntityType="Self.AncestralTabletRegistrant" Schema="dbo" store:Type="Tables" />
|
||||
<EntitySet Name="AncestralTabletStatus" EntityType="Self.AncestralTabletStatus" Schema="dbo" store:Type="Tables" />
|
||||
<EntitySet Name="appellation" EntityType="Self.appellation" Schema="dbo" store:Type="Tables" />
|
||||
<EntitySet Name="bed_kind" EntityType="Self.bed_kind" Schema="dbo" store:Type="Tables" />
|
||||
<EntitySet Name="bed_kind_detail" EntityType="Self.bed_kind_detail" Schema="dbo" store:Type="Tables" />
|
||||
@@ -2010,6 +2156,10 @@
|
||||
<EntitySet Name="supplier" EntityType="Self.supplier" Schema="dbo" store:Type="Tables" />
|
||||
<EntitySet Name="supplier_kind" EntityType="Self.supplier_kind" Schema="dbo" store:Type="Tables" />
|
||||
<EntitySet Name="transfer_register" EntityType="Self.transfer_register" Schema="dbo" store:Type="Tables" />
|
||||
<AssociationSet Name="FK__Ancestral__Regis__5A1A5A11" Association="Self.FK__Ancestral__Regis__5A1A5A11">
|
||||
<End Role="AncestralTabletRegistrant" EntitySet="AncestralTabletRegistrant" />
|
||||
<End Role="AncestralTabletPositionRecord" EntitySet="AncestralTabletPositionRecord" />
|
||||
</AssociationSet>
|
||||
<AssociationSet Name="FK_accounting_accounting_kind" Association="Self.FK_accounting_accounting_kind">
|
||||
<End Role="accounting_kind" EntitySet="accounting_kind" />
|
||||
<End Role="accounting" EntitySet="accounting" />
|
||||
@@ -2094,6 +2244,10 @@
|
||||
<End Role="admin_group" EntitySet="admin_group" />
|
||||
<End Role="admin" EntitySet="admin" />
|
||||
</AssociationSet>
|
||||
<AssociationSet Name="FK_AncestralTabletArea_Parent" Association="Self.FK_AncestralTabletArea_Parent">
|
||||
<End Role="AncestralTabletArea" EntitySet="AncestralTabletArea" />
|
||||
<End Role="AncestralTabletArea1" EntitySet="AncestralTabletArea" />
|
||||
</AssociationSet>
|
||||
<AssociationSet Name="FK_bed_kind_detail_bed_kind" Association="Self.FK_bed_kind_detail_bed_kind">
|
||||
<End Role="bed_kind" EntitySet="bed_kind" />
|
||||
<End Role="bed_kind_detail" EntitySet="bed_kind_detail" />
|
||||
@@ -2158,6 +2312,10 @@
|
||||
<End Role="followers" EntitySet="followers" />
|
||||
<End Role="GuaDanOrderGuest" EntitySet="GuaDanOrderGuest" />
|
||||
</AssociationSet>
|
||||
<AssociationSet Name="FK_GuaDanOrderGuest_Order" Association="Self.FK_GuaDanOrderGuest_Order">
|
||||
<End Role="GuaDanOrder" EntitySet="GuaDanOrder" />
|
||||
<End Role="GuaDanOrderGuest" EntitySet="GuaDanOrderGuest" />
|
||||
</AssociationSet>
|
||||
<AssociationSet Name="FK_GuaDanOrderGuest_RoomUuid" Association="Self.FK_GuaDanOrderGuest_RoomUuid">
|
||||
<End Role="Room" EntitySet="Room" />
|
||||
<End Role="GuaDanOrderGuest" EntitySet="GuaDanOrderGuest" />
|
||||
@@ -2202,6 +2360,14 @@
|
||||
<End Role="news_kind" EntitySet="news_kind" />
|
||||
<End Role="news" EntitySet="news" />
|
||||
</AssociationSet>
|
||||
<AssociationSet Name="FK_Position_Area" Association="Self.FK_Position_Area">
|
||||
<End Role="AncestralTabletArea" EntitySet="AncestralTabletArea" />
|
||||
<End Role="AncestralTabletPosition" EntitySet="AncestralTabletPosition" />
|
||||
</AssociationSet>
|
||||
<AssociationSet Name="FK_Position_Status" Association="Self.FK_Position_Status">
|
||||
<End Role="AncestralTabletStatus" EntitySet="AncestralTabletStatus" />
|
||||
<End Role="AncestralTabletPosition" EntitySet="AncestralTabletPosition" />
|
||||
</AssociationSet>
|
||||
<AssociationSet Name="FK_pro_order_activity" Association="Self.FK_pro_order_activity">
|
||||
<End Role="activity" EntitySet="activity" />
|
||||
<End Role="pro_order" EntitySet="pro_order" />
|
||||
@@ -2270,6 +2436,10 @@
|
||||
<End Role="RegionRoomBedStatus" EntitySet="RegionRoomBedStatus" />
|
||||
<End Role="RegionRoomBed" EntitySet="RegionRoomBed" />
|
||||
</AssociationSet>
|
||||
<AssociationSet Name="FK_Registrant_Position" Association="Self.FK_Registrant_Position">
|
||||
<End Role="AncestralTabletPosition" EntitySet="AncestralTabletPosition" />
|
||||
<End Role="AncestralTabletRegistrant" EntitySet="AncestralTabletRegistrant" />
|
||||
</AssociationSet>
|
||||
<AssociationSet Name="FK_Room_Region" Association="Self.FK_Room_Region">
|
||||
<End Role="Region" EntitySet="Region" />
|
||||
<End Role="Room" EntitySet="Room" />
|
||||
@@ -4348,6 +4518,35 @@
|
||||
<End Role="RegionRoomBedStatus" EntitySet="RegionRoomBedStatus" />
|
||||
<End Role="RegionRoomBed" EntitySet="RegionRoomBed" />
|
||||
</AssociationSet>
|
||||
<EntitySet Name="AncestralTabletArea" EntityType="Model.AncestralTabletArea" />
|
||||
<EntitySet Name="AncestralTabletPosition" EntityType="Model.AncestralTabletPosition" />
|
||||
<EntitySet Name="AncestralTabletPositionRecord" EntityType="Model.AncestralTabletPositionRecord" />
|
||||
<EntitySet Name="AncestralTabletRegistrant" EntityType="Model.AncestralTabletRegistrant" />
|
||||
<EntitySet Name="AncestralTabletStatus" EntityType="Model.AncestralTabletStatus" />
|
||||
<AssociationSet Name="FK_AncestralTabletArea_Parent" Association="Model.FK_AncestralTabletArea_Parent">
|
||||
<End Role="AncestralTabletArea" EntitySet="AncestralTabletArea" />
|
||||
<End Role="AncestralTabletArea1" EntitySet="AncestralTabletArea" />
|
||||
</AssociationSet>
|
||||
<AssociationSet Name="FK_Position_Area" Association="Model.FK_Position_Area">
|
||||
<End Role="AncestralTabletArea" EntitySet="AncestralTabletArea" />
|
||||
<End Role="AncestralTabletPosition" EntitySet="AncestralTabletPosition" />
|
||||
</AssociationSet>
|
||||
<AssociationSet Name="FK_Position_Status" Association="Model.FK_Position_Status">
|
||||
<End Role="AncestralTabletStatus" EntitySet="AncestralTabletStatus" />
|
||||
<End Role="AncestralTabletPosition" EntitySet="AncestralTabletPosition" />
|
||||
</AssociationSet>
|
||||
<AssociationSet Name="FK_Registrant_Position" Association="Model.FK_Registrant_Position">
|
||||
<End Role="AncestralTabletPosition" EntitySet="AncestralTabletPosition" />
|
||||
<End Role="AncestralTabletRegistrant" EntitySet="AncestralTabletRegistrant" />
|
||||
</AssociationSet>
|
||||
<AssociationSet Name="FK__Ancestral__Regis__5A1A5A11" Association="Model.FK__Ancestral__Regis__5A1A5A11">
|
||||
<End Role="AncestralTabletRegistrant" EntitySet="AncestralTabletRegistrant" />
|
||||
<End Role="AncestralTabletPositionRecord" EntitySet="AncestralTabletPositionRecord" />
|
||||
</AssociationSet>
|
||||
<AssociationSet Name="FK_GuaDanOrderGuest_Order" Association="Model.FK_GuaDanOrderGuest_Order">
|
||||
<End Role="GuaDanOrder" EntitySet="GuaDanOrder" />
|
||||
<End Role="GuaDanOrderGuest" EntitySet="GuaDanOrderGuest" />
|
||||
</AssociationSet>
|
||||
</EntityContainer>
|
||||
<ComplexType Name="sp_helpdiagramdefinition_Result">
|
||||
<Property Type="Int32" Name="version" Nullable="true" />
|
||||
@@ -4641,6 +4840,7 @@
|
||||
<Property Name="IsCancel" Type="Boolean" Nullable="false" />
|
||||
<NavigationProperty Name="admin" Relationship="Model.FK_GuaDanOrder_Admin_CreateUser" FromRole="GuaDanOrder" ToRole="admin" />
|
||||
<NavigationProperty Name="followers" Relationship="Model.FK_GuaDanOrder_Followers" FromRole="GuaDanOrder" ToRole="follower" />
|
||||
<NavigationProperty Name="GuaDanOrderGuest" Relationship="Model.FK_GuaDanOrderGuest_Order" FromRole="GuaDanOrder" ToRole="GuaDanOrderGuest" />
|
||||
</EntityType>
|
||||
<EntityType Name="GuaDanOrderGuest">
|
||||
<Key>
|
||||
@@ -4660,6 +4860,8 @@
|
||||
<NavigationProperty Name="Room" Relationship="Model.FK_GuaDanOrderGuest_RoomUuid" FromRole="GuaDanOrderGuest" ToRole="Room" />
|
||||
<NavigationProperty Name="RegionRoomBedStatus" Relationship="Model.FK_GuaDanOrderGuest_StatusCode" FromRole="GuaDanOrderGuest" ToRole="RegionRoomBedStatus" />
|
||||
<NavigationProperty Name="RegionAndRoomAndBedSchedule" Relationship="Model.FK_Schedule_GuaDanOrderGuest" FromRole="GuaDanOrderGuest" ToRole="RegionAndRoomAndBedSchedule" />
|
||||
<Property Name="OrderUuid" Type="Guid" />
|
||||
<NavigationProperty Name="GuaDanOrder" Relationship="Model.FK_GuaDanOrderGuest_Order" FromRole="GuaDanOrderGuest" ToRole="GuaDanOrder" />
|
||||
</EntityType>
|
||||
<EntityType Name="GuadanTimeSetting">
|
||||
<Key>
|
||||
@@ -4912,6 +5114,156 @@
|
||||
</Dependent>
|
||||
</ReferentialConstraint>
|
||||
</Association>
|
||||
<EntityType Name="AncestralTabletArea">
|
||||
<Key>
|
||||
<PropertyRef Name="AreaId" />
|
||||
</Key>
|
||||
<Property Name="AreaId" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
|
||||
<Property Name="AreaName" Type="String" Nullable="false" MaxLength="10" FixedLength="false" Unicode="true" />
|
||||
<Property Name="AreaCode" Type="String" Nullable="false" MaxLength="20" FixedLength="false" Unicode="true" />
|
||||
<Property Name="ParentAreaId" Type="Int32" />
|
||||
<Property Name="AreaType" Type="String" MaxLength="10" FixedLength="false" Unicode="true" />
|
||||
<Property Name="Price" Type="Int32" />
|
||||
<Property Name="SortOrder" Type="Int32" />
|
||||
<Property Name="IsDisabled" Type="Boolean" Nullable="false" />
|
||||
<Property Name="Description" Type="String" MaxLength="200" FixedLength="false" Unicode="true" />
|
||||
<NavigationProperty Name="AncestralTabletArea1" Relationship="Model.FK_AncestralTabletArea_Parent" FromRole="AncestralTabletArea" ToRole="AncestralTabletArea1" />
|
||||
<NavigationProperty Name="AncestralTabletArea2" Relationship="Model.FK_AncestralTabletArea_Parent" FromRole="AncestralTabletArea1" ToRole="AncestralTabletArea" />
|
||||
<NavigationProperty Name="AncestralTabletPosition" Relationship="Model.FK_Position_Area" FromRole="AncestralTabletArea" ToRole="AncestralTabletPosition" />
|
||||
</EntityType>
|
||||
<EntityType Name="AncestralTabletPosition">
|
||||
<Key>
|
||||
<PropertyRef Name="PositionId" />
|
||||
</Key>
|
||||
<Property Name="PositionId" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
|
||||
<Property Name="AreaId" Type="Int32" Nullable="false" />
|
||||
<Property Name="PositionCode" Type="String" Nullable="false" MaxLength="20" FixedLength="false" Unicode="true" />
|
||||
<Property Name="PositionName" Type="String" MaxLength="50" FixedLength="false" Unicode="true" />
|
||||
<Property Name="Price" Type="Int32" />
|
||||
<Property Name="StatusCode" Type="String" MaxLength="20" FixedLength="false" Unicode="true" />
|
||||
<Property Name="Description" Type="String" MaxLength="200" FixedLength="false" Unicode="true" />
|
||||
<Property Name="RowNo" Type="Int32" />
|
||||
<Property Name="ColumnNo" Type="Int32" />
|
||||
<NavigationProperty Name="AncestralTabletArea" Relationship="Model.FK_Position_Area" FromRole="AncestralTabletPosition" ToRole="AncestralTabletArea" />
|
||||
<NavigationProperty Name="AncestralTabletStatus" Relationship="Model.FK_Position_Status" FromRole="AncestralTabletPosition" ToRole="AncestralTabletStatus" />
|
||||
<NavigationProperty Name="AncestralTabletRegistrant" Relationship="Model.FK_Registrant_Position" FromRole="AncestralTabletPosition" ToRole="AncestralTabletRegistrant" />
|
||||
</EntityType>
|
||||
<EntityType Name="AncestralTabletPositionRecord">
|
||||
<Key>
|
||||
<PropertyRef Name="RecordId" />
|
||||
</Key>
|
||||
<Property Name="RecordId" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
|
||||
<Property Name="RegistrantCode" Type="String" Nullable="false" MaxLength="20" FixedLength="false" Unicode="true" />
|
||||
<Property Name="NPTitle" Type="String" MaxLength="30" FixedLength="false" Unicode="true" />
|
||||
<Property Name="NPStandDate" Type="DateTime" Nullable="false" Precision="0" />
|
||||
<Property Name="NPYangShang" Type="String" MaxLength="20" FixedLength="false" Unicode="true" />
|
||||
<Property Name="WPContent" Type="String" MaxLength="1000" FixedLength="false" Unicode="true" />
|
||||
<Property Name="CreatedAt" Type="DateTime" Nullable="false" Precision="3" />
|
||||
<Property Name="UpdatedAt" Type="DateTime" Precision="3" />
|
||||
<NavigationProperty Name="AncestralTabletRegistrant" Relationship="Model.FK__Ancestral__Regis__5A1A5A11" FromRole="AncestralTabletPositionRecord" ToRole="AncestralTabletRegistrant" />
|
||||
</EntityType>
|
||||
<EntityType Name="AncestralTabletRegistrant">
|
||||
<Key>
|
||||
<PropertyRef Name="RegistrantCode" />
|
||||
</Key>
|
||||
<Property Name="RegistrantCode" Type="String" Nullable="false" MaxLength="20" FixedLength="false" Unicode="true" />
|
||||
<Property Name="Name" Type="String" Nullable="false" MaxLength="50" FixedLength="false" Unicode="true" />
|
||||
<Property Name="Phone" Type="String" MaxLength="50" FixedLength="false" Unicode="true" />
|
||||
<Property Name="Address" Type="String" MaxLength="60" FixedLength="false" Unicode="true" />
|
||||
<Property Name="RegisterDate" Type="DateTime" Nullable="false" Precision="0" />
|
||||
<Property Name="Price" Type="Int32" />
|
||||
<Property Name="PositionId" Type="Int32" />
|
||||
<Property Name="StartDate" Type="DateTime" Nullable="false" Precision="0" />
|
||||
<Property Name="EndDate" Type="DateTime" Precision="0" />
|
||||
<Property Name="IsLongTerm" Type="Boolean" Nullable="false" />
|
||||
<Property Name="IsActive" Type="Boolean" Nullable="false" />
|
||||
<Property Name="CreatedAt" Type="DateTime" Nullable="false" Precision="3" />
|
||||
<Property Name="UpdatedAt" Type="DateTime" Precision="3" />
|
||||
<Property Name="IsEnd" Type="Boolean" Nullable="false" />
|
||||
<NavigationProperty Name="AncestralTabletPosition" Relationship="Model.FK_Registrant_Position" FromRole="AncestralTabletRegistrant" ToRole="AncestralTabletPosition" />
|
||||
<NavigationProperty Name="AncestralTabletPositionRecord" Relationship="Model.FK__Ancestral__Regis__5A1A5A11" FromRole="AncestralTabletRegistrant" ToRole="AncestralTabletPositionRecord" />
|
||||
</EntityType>
|
||||
<EntityType Name="AncestralTabletStatus">
|
||||
<Key>
|
||||
<PropertyRef Name="StatusCode" />
|
||||
</Key>
|
||||
<Property Name="StatusCode" Type="String" Nullable="false" MaxLength="20" FixedLength="false" Unicode="true" />
|
||||
<Property Name="StatusName" Type="String" Nullable="false" MaxLength="20" FixedLength="false" Unicode="true" />
|
||||
<Property Name="StatusType" Type="String" Nullable="false" MaxLength="20" FixedLength="false" Unicode="true" />
|
||||
<NavigationProperty Name="AncestralTabletPosition" Relationship="Model.FK_Position_Status" FromRole="AncestralTabletStatus" ToRole="AncestralTabletPosition" />
|
||||
</EntityType>
|
||||
<Association Name="FK_AncestralTabletArea_Parent">
|
||||
<End Type="Model.AncestralTabletArea" Role="AncestralTabletArea" Multiplicity="0..1" />
|
||||
<End Type="Model.AncestralTabletArea" Role="AncestralTabletArea1" Multiplicity="*" />
|
||||
<ReferentialConstraint>
|
||||
<Principal Role="AncestralTabletArea">
|
||||
<PropertyRef Name="AreaId" />
|
||||
</Principal>
|
||||
<Dependent Role="AncestralTabletArea1">
|
||||
<PropertyRef Name="ParentAreaId" />
|
||||
</Dependent>
|
||||
</ReferentialConstraint>
|
||||
</Association>
|
||||
<Association Name="FK_Position_Area">
|
||||
<End Type="Model.AncestralTabletArea" Role="AncestralTabletArea" Multiplicity="1" />
|
||||
<End Type="Model.AncestralTabletPosition" Role="AncestralTabletPosition" Multiplicity="*" />
|
||||
<ReferentialConstraint>
|
||||
<Principal Role="AncestralTabletArea">
|
||||
<PropertyRef Name="AreaId" />
|
||||
</Principal>
|
||||
<Dependent Role="AncestralTabletPosition">
|
||||
<PropertyRef Name="AreaId" />
|
||||
</Dependent>
|
||||
</ReferentialConstraint>
|
||||
</Association>
|
||||
<Association Name="FK_Position_Status">
|
||||
<End Type="Model.AncestralTabletStatus" Role="AncestralTabletStatus" Multiplicity="0..1" />
|
||||
<End Type="Model.AncestralTabletPosition" Role="AncestralTabletPosition" Multiplicity="*" />
|
||||
<ReferentialConstraint>
|
||||
<Principal Role="AncestralTabletStatus">
|
||||
<PropertyRef Name="StatusCode" />
|
||||
</Principal>
|
||||
<Dependent Role="AncestralTabletPosition">
|
||||
<PropertyRef Name="StatusCode" />
|
||||
</Dependent>
|
||||
</ReferentialConstraint>
|
||||
</Association>
|
||||
<Association Name="FK_Registrant_Position">
|
||||
<End Type="Model.AncestralTabletPosition" Role="AncestralTabletPosition" Multiplicity="0..1" />
|
||||
<End Type="Model.AncestralTabletRegistrant" Role="AncestralTabletRegistrant" Multiplicity="*" />
|
||||
<ReferentialConstraint>
|
||||
<Principal Role="AncestralTabletPosition">
|
||||
<PropertyRef Name="PositionId" />
|
||||
</Principal>
|
||||
<Dependent Role="AncestralTabletRegistrant">
|
||||
<PropertyRef Name="PositionId" />
|
||||
</Dependent>
|
||||
</ReferentialConstraint>
|
||||
</Association>
|
||||
<Association Name="FK__Ancestral__Regis__5A1A5A11">
|
||||
<End Type="Model.AncestralTabletRegistrant" Role="AncestralTabletRegistrant" Multiplicity="1" />
|
||||
<End Type="Model.AncestralTabletPositionRecord" Role="AncestralTabletPositionRecord" Multiplicity="*" />
|
||||
<ReferentialConstraint>
|
||||
<Principal Role="AncestralTabletRegistrant">
|
||||
<PropertyRef Name="RegistrantCode" />
|
||||
</Principal>
|
||||
<Dependent Role="AncestralTabletPositionRecord">
|
||||
<PropertyRef Name="RegistrantCode" />
|
||||
</Dependent>
|
||||
</ReferentialConstraint>
|
||||
</Association>
|
||||
<Association Name="FK_GuaDanOrderGuest_Order">
|
||||
<End Type="Model.GuaDanOrder" Role="GuaDanOrder" Multiplicity="0..1" />
|
||||
<End Type="Model.GuaDanOrderGuest" Role="GuaDanOrderGuest" Multiplicity="*" />
|
||||
<ReferentialConstraint>
|
||||
<Principal Role="GuaDanOrder">
|
||||
<PropertyRef Name="Uuid" />
|
||||
</Principal>
|
||||
<Dependent Role="GuaDanOrderGuest">
|
||||
<PropertyRef Name="OrderUuid" />
|
||||
</Dependent>
|
||||
</ReferentialConstraint>
|
||||
</Association>
|
||||
</Schema>
|
||||
</edmx:ConceptualModels>
|
||||
<!-- C-S mapping content -->
|
||||
@@ -5773,6 +6125,7 @@
|
||||
<EntitySetMapping Name="GuaDanOrderGuest">
|
||||
<EntityTypeMapping TypeName="Model.GuaDanOrderGuest">
|
||||
<MappingFragment StoreEntitySet="GuaDanOrderGuest">
|
||||
<ScalarProperty Name="OrderUuid" ColumnName="OrderUuid" />
|
||||
<ScalarProperty Name="StatusCode" ColumnName="StatusCode" />
|
||||
<ScalarProperty Name="CheckOutAt" ColumnName="CheckOutAt" />
|
||||
<ScalarProperty Name="CheckInAt" ColumnName="CheckInAt" />
|
||||
@@ -5885,6 +6238,79 @@
|
||||
</MappingFragment>
|
||||
</EntityTypeMapping>
|
||||
</EntitySetMapping>
|
||||
<EntitySetMapping Name="AncestralTabletArea">
|
||||
<EntityTypeMapping TypeName="Model.AncestralTabletArea">
|
||||
<MappingFragment StoreEntitySet="AncestralTabletArea">
|
||||
<ScalarProperty Name="Description" ColumnName="Description" />
|
||||
<ScalarProperty Name="IsDisabled" ColumnName="IsDisabled" />
|
||||
<ScalarProperty Name="SortOrder" ColumnName="SortOrder" />
|
||||
<ScalarProperty Name="Price" ColumnName="Price" />
|
||||
<ScalarProperty Name="AreaType" ColumnName="AreaType" />
|
||||
<ScalarProperty Name="ParentAreaId" ColumnName="ParentAreaId" />
|
||||
<ScalarProperty Name="AreaCode" ColumnName="AreaCode" />
|
||||
<ScalarProperty Name="AreaName" ColumnName="AreaName" />
|
||||
<ScalarProperty Name="AreaId" ColumnName="AreaId" />
|
||||
</MappingFragment>
|
||||
</EntityTypeMapping>
|
||||
</EntitySetMapping>
|
||||
<EntitySetMapping Name="AncestralTabletPosition">
|
||||
<EntityTypeMapping TypeName="Model.AncestralTabletPosition">
|
||||
<MappingFragment StoreEntitySet="AncestralTabletPosition">
|
||||
<ScalarProperty Name="ColumnNo" ColumnName="ColumnNo" />
|
||||
<ScalarProperty Name="RowNo" ColumnName="RowNo" />
|
||||
<ScalarProperty Name="Description" ColumnName="Description" />
|
||||
<ScalarProperty Name="StatusCode" ColumnName="StatusCode" />
|
||||
<ScalarProperty Name="Price" ColumnName="Price" />
|
||||
<ScalarProperty Name="PositionName" ColumnName="PositionName" />
|
||||
<ScalarProperty Name="PositionCode" ColumnName="PositionCode" />
|
||||
<ScalarProperty Name="AreaId" ColumnName="AreaId" />
|
||||
<ScalarProperty Name="PositionId" ColumnName="PositionId" />
|
||||
</MappingFragment>
|
||||
</EntityTypeMapping>
|
||||
</EntitySetMapping>
|
||||
<EntitySetMapping Name="AncestralTabletPositionRecord">
|
||||
<EntityTypeMapping TypeName="Model.AncestralTabletPositionRecord">
|
||||
<MappingFragment StoreEntitySet="AncestralTabletPositionRecord">
|
||||
<ScalarProperty Name="UpdatedAt" ColumnName="UpdatedAt" />
|
||||
<ScalarProperty Name="CreatedAt" ColumnName="CreatedAt" />
|
||||
<ScalarProperty Name="WPContent" ColumnName="WPContent" />
|
||||
<ScalarProperty Name="NPYangShang" ColumnName="NPYangShang" />
|
||||
<ScalarProperty Name="NPStandDate" ColumnName="NPStandDate" />
|
||||
<ScalarProperty Name="NPTitle" ColumnName="NPTitle" />
|
||||
<ScalarProperty Name="RegistrantCode" ColumnName="RegistrantCode" />
|
||||
<ScalarProperty Name="RecordId" ColumnName="RecordId" />
|
||||
</MappingFragment>
|
||||
</EntityTypeMapping>
|
||||
</EntitySetMapping>
|
||||
<EntitySetMapping Name="AncestralTabletRegistrant">
|
||||
<EntityTypeMapping TypeName="Model.AncestralTabletRegistrant">
|
||||
<MappingFragment StoreEntitySet="AncestralTabletRegistrant">
|
||||
<ScalarProperty Name="IsEnd" ColumnName="IsEnd" />
|
||||
<ScalarProperty Name="UpdatedAt" ColumnName="UpdatedAt" />
|
||||
<ScalarProperty Name="CreatedAt" ColumnName="CreatedAt" />
|
||||
<ScalarProperty Name="IsActive" ColumnName="IsActive" />
|
||||
<ScalarProperty Name="IsLongTerm" ColumnName="IsLongTerm" />
|
||||
<ScalarProperty Name="EndDate" ColumnName="EndDate" />
|
||||
<ScalarProperty Name="StartDate" ColumnName="StartDate" />
|
||||
<ScalarProperty Name="PositionId" ColumnName="PositionId" />
|
||||
<ScalarProperty Name="Price" ColumnName="Price" />
|
||||
<ScalarProperty Name="RegisterDate" ColumnName="RegisterDate" />
|
||||
<ScalarProperty Name="Address" ColumnName="Address" />
|
||||
<ScalarProperty Name="Phone" ColumnName="Phone" />
|
||||
<ScalarProperty Name="Name" ColumnName="Name" />
|
||||
<ScalarProperty Name="RegistrantCode" ColumnName="RegistrantCode" />
|
||||
</MappingFragment>
|
||||
</EntityTypeMapping>
|
||||
</EntitySetMapping>
|
||||
<EntitySetMapping Name="AncestralTabletStatus">
|
||||
<EntityTypeMapping TypeName="Model.AncestralTabletStatus">
|
||||
<MappingFragment StoreEntitySet="AncestralTabletStatus">
|
||||
<ScalarProperty Name="StatusType" ColumnName="StatusType" />
|
||||
<ScalarProperty Name="StatusName" ColumnName="StatusName" />
|
||||
<ScalarProperty Name="StatusCode" ColumnName="StatusCode" />
|
||||
</MappingFragment>
|
||||
</EntityTypeMapping>
|
||||
</EntitySetMapping>
|
||||
</EntityContainerMapping>
|
||||
</Mapping>
|
||||
</edmx:Mappings>
|
||||
|
||||
@@ -151,6 +151,17 @@
|
||||
<AssociationConnector Association="Model.FK_Room_Region" />
|
||||
<AssociationConnector Association="Model.FK_RegionRoomBed_RoomUuid" />
|
||||
<AssociationConnector Association="Model.FK_RegionRoomBed_StatusCode" />
|
||||
<EntityTypeShape EntityType="Model.AncestralTabletArea" Width="1.5" PointX="25.375" PointY="22.375" />
|
||||
<EntityTypeShape EntityType="Model.AncestralTabletPosition" Width="1.5" PointX="27.625" PointY="18.375" />
|
||||
<EntityTypeShape EntityType="Model.AncestralTabletPositionRecord" Width="1.5" PointX="32.125" PointY="18.625" />
|
||||
<EntityTypeShape EntityType="Model.AncestralTabletRegistrant" Width="1.5" PointX="29.875" PointY="18" />
|
||||
<EntityTypeShape EntityType="Model.AncestralTabletStatus" Width="1.5" PointX="25.375" PointY="19.125" />
|
||||
<AssociationConnector Association="Model.FK_AncestralTabletArea_Parent" />
|
||||
<AssociationConnector Association="Model.FK_Position_Area" />
|
||||
<AssociationConnector Association="Model.FK_Position_Status" />
|
||||
<AssociationConnector Association="Model.FK_Registrant_Position" />
|
||||
<AssociationConnector Association="Model.FK__Ancestral__Regis__5A1A5A11" />
|
||||
<AssociationConnector Association="Model.FK_GuaDanOrderGuest_Order" />
|
||||
</Diagram>
|
||||
</edmx:Diagrams>
|
||||
</edmx:Designer>
|
||||
|
||||
@@ -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
|
||||
|
||||
180
web/App_Code/api/AncestralTabletAreaController.cs
Normal file
180
web/App_Code/api/AncestralTabletAreaController.cs
Normal file
@@ -0,0 +1,180 @@
|
||||
using Model;
|
||||
using PagedList;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Data.Entity;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Web.Http;
|
||||
using static AncestralTabletPositionController;
|
||||
using static regionController;
|
||||
|
||||
/// <summary>
|
||||
/// AncestralTabletController 的摘要描述
|
||||
/// </summary>
|
||||
public class AncestralTabletAreaController: ApiController
|
||||
{
|
||||
private Model.ezEntities _db = new Model.ezEntities();
|
||||
public class AreaViewModel
|
||||
{
|
||||
public int? AreaId { get; set; }
|
||||
public string AreaName { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "區域編號為必填")]
|
||||
public string AreaCode { get; set; }
|
||||
public int? ParentAreaId { get; set; }
|
||||
public string AreaType { get; set; }
|
||||
public int? Price { get; set; }
|
||||
public int? SortOrder { get; set; }
|
||||
public bool IsDisabled { get; set; } = false;
|
||||
public string Description { get; set; }
|
||||
}
|
||||
public class RegionDto
|
||||
{
|
||||
public int AreaId { get; set; }
|
||||
public string AreaName { get; set; }
|
||||
public string AreaCode { get; set; }
|
||||
public int? SortOrder { get; set; }
|
||||
public int? ParentAreaId { get; set; }
|
||||
public string AreaType { get; set; }
|
||||
public bool IsDisabled { get; set; }
|
||||
public string Description { get; set; }
|
||||
public int? Price { set; get; }
|
||||
|
||||
public List<RegionDto> Children { get; set; } = new List<RegionDto>();
|
||||
}
|
||||
[HttpGet]
|
||||
[Route("api/ancestraltablet/area/getlist")]
|
||||
public IHttpActionResult GetList()
|
||||
{
|
||||
var allArea = _db.AncestralTabletArea.ToList();
|
||||
|
||||
var rootRegions = allArea
|
||||
.Where(r => r.ParentAreaId == null)
|
||||
.OrderBy(r => r.SortOrder)
|
||||
.ToList();
|
||||
|
||||
var tree = rootRegions
|
||||
.Select(r => BuildRegionDto(r, allArea))
|
||||
.ToList();
|
||||
return Ok(tree);
|
||||
|
||||
}
|
||||
[HttpGet]
|
||||
[Route("api/ancestraltablet/area/getereawithposition")]
|
||||
public IHttpActionResult GetEreaWithPosition()
|
||||
{
|
||||
//获取有神位位置的区域
|
||||
var allArea = _db.AncestralTabletArea
|
||||
.Where(a => a.AncestralTabletPosition.Count()>0)
|
||||
.Select(a => new
|
||||
{
|
||||
a.AreaId,
|
||||
a.AreaName,
|
||||
})
|
||||
.ToList();
|
||||
return Ok(allArea);
|
||||
|
||||
}
|
||||
private RegionDto BuildRegionDto(AncestralTabletArea area, List<AncestralTabletArea> allArea)
|
||||
{
|
||||
return new RegionDto
|
||||
{
|
||||
AreaId = area.AreaId,
|
||||
AreaName = area.AreaName,
|
||||
AreaCode = area.AreaCode,
|
||||
SortOrder = area.SortOrder,
|
||||
ParentAreaId = area.ParentAreaId,
|
||||
AreaType = area.AreaType,
|
||||
IsDisabled = area.IsDisabled,
|
||||
Description = area.Description,
|
||||
Price = area.Price,
|
||||
Children = allArea
|
||||
.Where(r => r.ParentAreaId == area.AreaId)
|
||||
.OrderBy(r => r.SortOrder)
|
||||
.Select(child => BuildRegionDto(child, allArea))
|
||||
.ToList(),
|
||||
};
|
||||
}
|
||||
[HttpPost]
|
||||
[Route("api/ancestraltablet/area/create")]
|
||||
public async Task<IHttpActionResult> CreateArea([FromBody] AreaViewModel tabletArea)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
return BadRequest(ModelState);
|
||||
try
|
||||
{
|
||||
var area = new AncestralTabletArea
|
||||
{
|
||||
AreaName = tabletArea.AreaName,
|
||||
AreaCode = tabletArea.AreaCode,
|
||||
ParentAreaId = tabletArea.ParentAreaId,
|
||||
AreaType = tabletArea.AreaType,
|
||||
Price = tabletArea.Price,
|
||||
SortOrder = tabletArea.SortOrder,
|
||||
IsDisabled = tabletArea.IsDisabled,
|
||||
Description = tabletArea.Description
|
||||
};
|
||||
_db.AncestralTabletArea.Add(area);
|
||||
await _db.SaveChangesAsync();
|
||||
tabletArea.AreaId = area.AreaId;
|
||||
return Ok(new { message = "區域建立成功", area = tabletArea });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return InternalServerError(ex);
|
||||
}
|
||||
}
|
||||
[HttpPost]
|
||||
[Route("api/ancestraltablet/area/edit")]
|
||||
public async Task<IHttpActionResult> EditArea([FromBody] AreaViewModel tabletArea)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
return BadRequest(ModelState);
|
||||
try
|
||||
{
|
||||
var oldArea = _db.AncestralTabletArea.Find(tabletArea.AreaId);
|
||||
if (oldArea == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
oldArea.AreaName = tabletArea.AreaName;
|
||||
oldArea.AreaCode = tabletArea.AreaCode;
|
||||
oldArea.ParentAreaId = tabletArea.ParentAreaId;
|
||||
oldArea.Price = tabletArea.Price;
|
||||
oldArea.SortOrder = tabletArea.SortOrder;
|
||||
oldArea.Description = tabletArea.Description;
|
||||
oldArea.IsDisabled = tabletArea.IsDisabled;
|
||||
await _db.SaveChangesAsync();
|
||||
return Ok(new { message = "區域修改成功", area = tabletArea });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return InternalServerError(ex);
|
||||
}
|
||||
}
|
||||
[HttpGet]
|
||||
[Route("api/ancestraltablet/area/position/getlist")]
|
||||
public IHttpActionResult GetPositionList([FromUri] int areaId)
|
||||
{
|
||||
var positions = _db.AncestralTabletPosition
|
||||
.Where(p => p.AreaId == areaId)
|
||||
.Select(p => new AncestralTabletPositionDto
|
||||
{
|
||||
PositionId = p.PositionId,
|
||||
AreaId = p.AreaId,
|
||||
PositionCode = p.PositionCode,
|
||||
PositionName = p.PositionName,
|
||||
Price = p.Price,
|
||||
StatusCode = p.StatusCode,
|
||||
Description = p.Description,
|
||||
RowNo = p.RowNo,
|
||||
ColumnNo = p.ColumnNo
|
||||
})
|
||||
.ToList();
|
||||
|
||||
return Ok(positions);
|
||||
}
|
||||
}
|
||||
184
web/App_Code/api/AncestralTabletPositionController.cs
Normal file
184
web/App_Code/api/AncestralTabletPositionController.cs
Normal file
@@ -0,0 +1,184 @@
|
||||
using Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Web;
|
||||
using System.Web.Http;
|
||||
|
||||
/// <summary>
|
||||
/// AncestralTabletPositionController 的摘要描述
|
||||
/// </summary>
|
||||
public class AncestralTabletPositionController: ApiController
|
||||
{
|
||||
private Model.ezEntities _db = new Model.ezEntities();
|
||||
|
||||
[HttpGet]
|
||||
[Route("api/ancestraltablet/position/getlist")]
|
||||
public IHttpActionResult GetList([FromUri] int areaId)
|
||||
{
|
||||
var positions = _db.AncestralTabletPosition
|
||||
.Where(p => p.AreaId == areaId)
|
||||
.Select(p => new
|
||||
{
|
||||
PositionId = p.PositionId,
|
||||
AreaId = p.AreaId,
|
||||
PositionCode = p.PositionCode,
|
||||
PositionName = p.PositionName,
|
||||
Price = p.Price,
|
||||
StatusCode = p.StatusCode,
|
||||
Description = p.Description,
|
||||
RowNo = p.RowNo,
|
||||
ColumnNo = p.ColumnNo,
|
||||
AncestralTabletRegistrant = _db.AncestralTabletRegistrant
|
||||
.Where(r => r.PositionId == p.PositionId && r.IsActive == true)
|
||||
.Select(r => new
|
||||
{
|
||||
r.RegistrantCode,
|
||||
r.Name,
|
||||
r.Phone,
|
||||
r.Address,
|
||||
r.RegisterDate,
|
||||
r.Price,
|
||||
r.StartDate,
|
||||
r.EndDate,
|
||||
r.IsLongTerm,
|
||||
r.IsActive,
|
||||
|
||||
// 嵌套查询牌位记录(PositionRecord)
|
||||
TabletRecord = r.AncestralTabletPositionRecord
|
||||
.Select(pr => new
|
||||
{
|
||||
pr.RecordId,
|
||||
pr.RegistrantCode,
|
||||
pr.NPTitle,
|
||||
pr.NPStandDate,
|
||||
pr.NPYangShang,
|
||||
pr.WPContent
|
||||
})
|
||||
.FirstOrDefault()
|
||||
})
|
||||
.FirstOrDefault()
|
||||
})
|
||||
.ToList();
|
||||
|
||||
return Ok(positions);
|
||||
}
|
||||
[HttpGet]
|
||||
[Route("api/ancestraltablet/position/shortlist")]
|
||||
public IHttpActionResult GetListWithShort([FromUri] int areaId)
|
||||
{
|
||||
//获取位置列表,简单信息
|
||||
var positions = _db.AncestralTabletPosition
|
||||
.Where(p => p.AreaId == areaId)
|
||||
.Select(p => new
|
||||
{
|
||||
PositionId = p.PositionId,
|
||||
AreaId = p.AreaId,
|
||||
PositionCode = p.PositionCode,
|
||||
PositionName = p.PositionName,
|
||||
Price = p.Price,
|
||||
StatusCode = p.StatusCode,
|
||||
Description = p.Description,
|
||||
RowNo = p.RowNo,
|
||||
ColumnNo = p.ColumnNo,
|
||||
isCanUse = p.StatusCode == "available" ? true : false,
|
||||
})
|
||||
.ToList();
|
||||
|
||||
return Ok(positions);
|
||||
}
|
||||
[HttpPost]
|
||||
[Route("api/ancestraltablet/position/batchcreate")]
|
||||
public IHttpActionResult BatchCreatePosition([FromBody] List<AncestralTabletPositionDto> positions)
|
||||
{
|
||||
if (positions == null || positions.Count == 0)
|
||||
return BadRequest("未接收到任何位置数据");
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var dto in positions)
|
||||
{
|
||||
var entity = new AncestralTabletPosition
|
||||
{
|
||||
AreaId = dto.AreaId,
|
||||
PositionCode = dto.PositionCode,
|
||||
PositionName = dto.PositionName,
|
||||
Price = dto.Price,
|
||||
StatusCode = dto.StatusCode,
|
||||
Description = dto.Description,
|
||||
RowNo = dto.RowNo,
|
||||
ColumnNo = dto.ColumnNo
|
||||
};
|
||||
|
||||
_db.AncestralTabletPosition.Add(entity);
|
||||
}
|
||||
|
||||
_db.SaveChanges();
|
||||
|
||||
return Ok(new { message = "批量新增成功", count = positions.Count });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string message = ex.InnerException?.InnerException?.Message ?? ex.Message;
|
||||
|
||||
return Content(HttpStatusCode.InternalServerError, new
|
||||
{
|
||||
message = "批量新增失败",
|
||||
exceptionMessage = message
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("api/ancestraltablet/position/edit")]
|
||||
public IHttpActionResult EditPosition([FromBody] AncestralTabletPositionDto pos)
|
||||
{
|
||||
var oldPos = _db.AncestralTabletPosition
|
||||
.FirstOrDefault(p => p.AreaId == pos.AreaId && p.PositionCode == pos.PositionCode);
|
||||
if(oldPos == null) return NotFound();
|
||||
try
|
||||
{
|
||||
oldPos.PositionName = pos.PositionName;
|
||||
oldPos.Price = pos.Price;
|
||||
oldPos.StatusCode = pos.StatusCode;
|
||||
|
||||
// 保存到数据库
|
||||
_db.SaveChanges();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return InternalServerError(ex);
|
||||
}
|
||||
return Ok(new { message="更新成功", code=200});
|
||||
}
|
||||
[HttpDelete]
|
||||
[Route("api/ancestraltablet/position/delete/{positionId}")]
|
||||
public IHttpActionResult DeletePosition(int positionId)
|
||||
{
|
||||
var pos = _db.AncestralTabletPosition.FirstOrDefault(p => p.PositionId == positionId);
|
||||
|
||||
if (pos == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
_db.AncestralTabletPosition.Remove(pos);
|
||||
_db.SaveChanges();
|
||||
|
||||
return Ok("删除成功");
|
||||
}
|
||||
public class AncestralTabletPositionDto
|
||||
{
|
||||
public int PositionId { get; set; }
|
||||
public int AreaId { get; set; }
|
||||
public string PositionCode { get; set; }
|
||||
public string PositionName { get; set; }
|
||||
public int? Price { get; set; }
|
||||
public string StatusCode { get; set; }
|
||||
public string Description { get; set; }
|
||||
public int? RowNo { get; set; }
|
||||
public int? ColumnNo { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
361
web/App_Code/api/AncestralTabletRecordController.cs
Normal file
361
web/App_Code/api/AncestralTabletRecordController.cs
Normal file
@@ -0,0 +1,361 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Http;
|
||||
using System.Web.UI.WebControls;
|
||||
|
||||
/// <summary>
|
||||
/// AncestralTabletRecordController 的摘要描述
|
||||
/// </summary>
|
||||
public class AncestralTabletRecordController: ApiController
|
||||
{
|
||||
private Model.ezEntities _db = new Model.ezEntities();
|
||||
[HttpGet]
|
||||
[Route("api/ancestraltablet/registrant/getlist")]
|
||||
public IHttpActionResult GetRegistrantList()
|
||||
{
|
||||
//获取登记人列表
|
||||
var data = _db.AncestralTabletRegistrant.Select(x => new
|
||||
{
|
||||
x.RegistrantCode,
|
||||
x.Name,
|
||||
x.Phone,
|
||||
x.Address,
|
||||
x.RegisterDate,
|
||||
x.Price,
|
||||
x.PositionId,
|
||||
x.StartDate,
|
||||
x.EndDate,
|
||||
x.IsLongTerm,
|
||||
x.IsActive,
|
||||
x.CreatedAt,
|
||||
x.UpdatedAt
|
||||
})
|
||||
.Take(1000) // 取前1000条
|
||||
.ToList(); ;
|
||||
return Ok(data);
|
||||
}
|
||||
[HttpPost]
|
||||
[Route("api/ancestraltablet/registrant/getlistbypage")]
|
||||
public IHttpActionResult GetRegistrantListByPage([FromBody] RegistrantSearchDto searchDto)
|
||||
{
|
||||
//获取登记人列表
|
||||
var query = _db.AncestralTabletRegistrant.AsQueryable();
|
||||
if( !string.IsNullOrEmpty(searchDto.searchName))
|
||||
{
|
||||
query = query.Where(r => r.Name == searchDto.searchName);
|
||||
}
|
||||
var tatol = query.Count();
|
||||
var data = query.Select(x => new
|
||||
{
|
||||
x.RegistrantCode,
|
||||
x.Name,
|
||||
x.Phone,
|
||||
x.Address,
|
||||
x.RegisterDate,
|
||||
x.Price,
|
||||
x.PositionId,
|
||||
x.StartDate,
|
||||
x.EndDate,
|
||||
x.IsLongTerm,
|
||||
x.IsActive,
|
||||
x.CreatedAt,
|
||||
x.UpdatedAt
|
||||
})
|
||||
.OrderByDescending(a => a.CreatedAt)
|
||||
.Skip((searchDto.page - 1) * searchDto.pageSize)
|
||||
.Take(searchDto.pageSize) // 取前1000条
|
||||
.ToList();
|
||||
return Ok(new
|
||||
{
|
||||
data = data,
|
||||
total = tatol
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("api/ancestraltablet/registrant/getbycode")]
|
||||
public IHttpActionResult GetRegistrantByCode([FromUri] string registrantCode)
|
||||
{
|
||||
var r = _db.AncestralTabletRegistrant.Find(registrantCode);
|
||||
if (r == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
var rDto = new
|
||||
{
|
||||
r.RegistrantCode,
|
||||
r.Name,
|
||||
r.Phone,
|
||||
r.Address,
|
||||
r.RegisterDate,
|
||||
r.Price,
|
||||
r.StartDate,
|
||||
r.EndDate,
|
||||
r.IsLongTerm,
|
||||
r.IsActive,
|
||||
r.PositionId,
|
||||
positionName = r.AncestralTabletPosition?.PositionName,
|
||||
|
||||
|
||||
// 嵌套查询牌位记录(PositionRecord)
|
||||
TabletRecord = r.AncestralTabletPositionRecord
|
||||
.Select(pr => new
|
||||
{
|
||||
pr.RecordId,
|
||||
pr.RegistrantCode,
|
||||
pr.NPTitle,
|
||||
pr.NPStandDate,
|
||||
pr.NPYangShang,
|
||||
pr.WPContent,
|
||||
})
|
||||
.FirstOrDefault()
|
||||
};
|
||||
return Ok(rDto);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("api/ancestraltablet/registrant/create")]
|
||||
public IHttpActionResult CreateRegistrant([FromBody] AncestralTabletRegistrantDto dto)
|
||||
{
|
||||
//新增登记人api
|
||||
if (dto == null)
|
||||
{
|
||||
return BadRequest("请求体不能为空");
|
||||
}
|
||||
if(!string.IsNullOrEmpty(dto.RegistrantCode))
|
||||
{
|
||||
return BadRequest("RegistrantCode 应传递空");
|
||||
}
|
||||
try
|
||||
{
|
||||
dto.RegistrantCode = GenerateRegistrantCode();
|
||||
|
||||
// 设置默认创建时间
|
||||
dto.CreatedAt = DateTime.Now;
|
||||
var entity = new Model.AncestralTabletRegistrant
|
||||
{
|
||||
RegistrantCode = dto.RegistrantCode,
|
||||
Name = dto.Name,
|
||||
Phone = dto.Phone,
|
||||
Address = dto.Address,
|
||||
RegisterDate = dto.RegisterDate,
|
||||
Price = dto.Price,
|
||||
PositionId = dto.PositionId,
|
||||
StartDate = dto.startDate,
|
||||
EndDate = dto.endDate,
|
||||
IsLongTerm = dto.isLongTerm,
|
||||
IsActive = dto.isActive,
|
||||
CreatedAt = dto.CreatedAt,
|
||||
UpdatedAt = dto.UpdatedAt
|
||||
};
|
||||
|
||||
// 假设你有一个 EF DbContext(如 _db)
|
||||
_db.AncestralTabletRegistrant.Add(entity);
|
||||
if (dto.PositionId != null)
|
||||
{
|
||||
var position = _db.AncestralTabletPosition
|
||||
.FirstOrDefault(p => p.PositionId == dto.PositionId);
|
||||
|
||||
if (position != null)
|
||||
{
|
||||
position.StatusCode = "used"; // 或者根据你的枚举/字段设置
|
||||
}
|
||||
}
|
||||
|
||||
_db.SaveChanges();
|
||||
|
||||
return Ok(new { message = "登记成功", registrantCode = entity.RegistrantCode });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return InternalServerError(ex);
|
||||
}
|
||||
}
|
||||
[HttpPost]
|
||||
[Route("api/ancestraltablet/registrant/update")]
|
||||
public IHttpActionResult UpdateRegistrant([FromBody] AncestralTabletRegistrantDto dto)
|
||||
{
|
||||
if (dto == null)
|
||||
{
|
||||
return BadRequest("请求体不能为空");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(dto.RegistrantCode))
|
||||
{
|
||||
return BadRequest("缺少 RegistrantCode,无法进行更新操作");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 查找原始资料
|
||||
var entity = _db.AncestralTabletRegistrant
|
||||
.FirstOrDefault(r => r.RegistrantCode == dto.RegistrantCode);
|
||||
|
||||
if (entity == null)
|
||||
{
|
||||
return NotFound(); // 没有对应记录
|
||||
}
|
||||
|
||||
// ===== 处理安位状态 =====
|
||||
if (entity.PositionId != dto.PositionId)
|
||||
{
|
||||
// 1. 原来的安位设置为可用
|
||||
if (entity.PositionId != null)
|
||||
{
|
||||
var oldPosition = _db.AncestralTabletPosition
|
||||
.FirstOrDefault(p => p.PositionId == entity.PositionId);
|
||||
|
||||
if (oldPosition != null)
|
||||
{
|
||||
oldPosition.StatusCode = "available"; // 可用
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 新的安位设置为已使用
|
||||
if (dto.PositionId != null)
|
||||
{
|
||||
var newPosition = _db.AncestralTabletPosition
|
||||
.FirstOrDefault(p => p.PositionId == dto.PositionId);
|
||||
|
||||
if (newPosition != null)
|
||||
{
|
||||
newPosition.StatusCode = "used"; // 已使用
|
||||
}
|
||||
}
|
||||
|
||||
// 更新登记人安位
|
||||
entity.PositionId = dto.PositionId;
|
||||
}
|
||||
|
||||
// 更新其它字段
|
||||
entity.Name = dto.Name;
|
||||
entity.Phone = dto.Phone;
|
||||
entity.Address = dto.Address;
|
||||
entity.RegisterDate = dto.RegisterDate;
|
||||
entity.Price = dto.Price;
|
||||
entity.StartDate = dto.startDate;
|
||||
entity.EndDate = dto.endDate;
|
||||
entity.IsLongTerm = dto.isLongTerm;
|
||||
entity.IsActive = dto.isActive;
|
||||
entity.UpdatedAt = DateTime.Now;
|
||||
|
||||
_db.SaveChanges();
|
||||
|
||||
return Ok(new { message = "登记人更新成功", registrantCode = entity.RegistrantCode });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return InternalServerError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("api/ancestraltablet/pw/create")]
|
||||
public IHttpActionResult CreatePW([FromBody] AncestralTabletPositionRecordDto dto)
|
||||
{
|
||||
if (dto == null)
|
||||
return BadRequest("请求体不能为空");
|
||||
|
||||
if (string.IsNullOrEmpty(dto.RegistrantCode))
|
||||
return BadRequest("登记人编号(RegistrantCode)不能为空");
|
||||
|
||||
try
|
||||
{
|
||||
// 映射到数据库实体
|
||||
var entity = new Model.AncestralTabletPositionRecord
|
||||
{
|
||||
RegistrantCode = dto.RegistrantCode,
|
||||
NPTitle = dto.NPTitle,
|
||||
NPStandDate = dto.NPStandDate,
|
||||
NPYangShang = dto.NPYangShang,
|
||||
WPContent = dto.WPContent,
|
||||
CreatedAt = DateTime.Now,
|
||||
UpdatedAt = null
|
||||
};
|
||||
|
||||
_db.AncestralTabletPositionRecord.Add(entity);
|
||||
_db.SaveChanges();
|
||||
|
||||
return Ok(new { message = "牌位登记成功", recordId = entity.RecordId });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return InternalServerError(ex);
|
||||
}
|
||||
}
|
||||
[HttpPost]
|
||||
[Route("api/ancestraltablet/pw/update")]
|
||||
public IHttpActionResult UpdatePW([FromBody] AncestralTabletPositionRecordDto dto)
|
||||
{
|
||||
if (dto == null)
|
||||
return BadRequest("请求体不能为空");
|
||||
try
|
||||
{
|
||||
var entity = _db.AncestralTabletPositionRecord.Find(dto.RecordId);
|
||||
// 映射到数据库实体
|
||||
if (entity == null)
|
||||
return BadRequest("牌位不存在,更新失败");
|
||||
entity.RegistrantCode = dto.RegistrantCode;
|
||||
entity.NPTitle = dto.NPTitle;
|
||||
entity.NPStandDate = dto.NPStandDate;
|
||||
entity.NPYangShang = dto.NPYangShang;
|
||||
entity.WPContent = dto.WPContent;
|
||||
entity.UpdatedAt = DateTime.Now;
|
||||
_db.SaveChanges();
|
||||
|
||||
return Ok(new { message = "牌位更新成功", recordId = entity.RecordId });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return InternalServerError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public string GenerateRegistrantCode(string prefix = "REG", int randomLength = 6)
|
||||
{
|
||||
string datePart = DateTime.Now.ToString("yyyyMMdd");
|
||||
|
||||
string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
var random = new Random();
|
||||
var suffix = new string(Enumerable.Repeat(chars, randomLength)
|
||||
.Select(s => s[random.Next(s.Length)]).ToArray());
|
||||
|
||||
return $"{prefix}{datePart}{suffix}";
|
||||
}
|
||||
public class AncestralTabletRegistrantDto
|
||||
{
|
||||
public string RegistrantCode { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Phone { get; set; }
|
||||
public string Address { get; set; }
|
||||
public DateTime RegisterDate { get; set; }
|
||||
public int? Price { get; set; }
|
||||
public int? PositionId { get; set; }
|
||||
public DateTime startDate { get; set; }
|
||||
public DateTime? endDate { get; set; }
|
||||
public bool isLongTerm { get; set; } = false;
|
||||
public bool isActive { get; set; } = true;
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public DateTime? UpdatedAt { get; set; }
|
||||
}
|
||||
public class AncestralTabletPositionRecordDto
|
||||
{
|
||||
public int? RecordId { get; set; }
|
||||
public string RegistrantCode { get; set; }
|
||||
public string NPTitle { get; set; }
|
||||
public DateTime NPStandDate { get; set; }
|
||||
public string NPYangShang { get; set; }
|
||||
public string WPContent { get; set; }
|
||||
}
|
||||
public class RegistrantSearchDto
|
||||
{
|
||||
public int page { get; set; } = 1;
|
||||
public int pageSize { get; set; } = 10;
|
||||
public string searchName { get; set; }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
38
web/App_Code/api/AncestralTabletStatisticsController.cs
Normal file
38
web/App_Code/api/AncestralTabletStatisticsController.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Http;
|
||||
|
||||
/// <summary>
|
||||
/// AncestralTabletStatisticsController 的摘要描述
|
||||
/// </summary>
|
||||
public class AncestralTabletStatisticsController:ApiController
|
||||
{
|
||||
private Model.ezEntities db = new Model.ezEntities();
|
||||
[HttpGet]
|
||||
[Route("api/ancestraltablet/statistics/positions/availablepositions")]
|
||||
public IHttpActionResult GetAvailablePositions()
|
||||
{
|
||||
var query =
|
||||
from a in db.AncestralTabletArea // 区域表
|
||||
join p in db.AncestralTabletPosition
|
||||
on a.AreaId equals p.AreaId into ap
|
||||
from p in ap.DefaultIfEmpty()
|
||||
join r in db.AncestralTabletRegistrant
|
||||
on p.PositionId equals r.PositionId into pr
|
||||
from r in pr.DefaultIfEmpty()
|
||||
group new { a, p, r } by new { a.AreaId, a.AreaName } into g
|
||||
select new
|
||||
{
|
||||
AreaId = g.Key.AreaId,
|
||||
AreaName = g.Key.AreaName,
|
||||
TotalPositions = g.Count(x => x.p != null), // 总位置数
|
||||
AvailableCount = g.Count(x => x.p != null && x.r == null) // 可用位置数(未登记)
|
||||
};
|
||||
|
||||
var result = query.ToList();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
}
|
||||
29
web/App_Code/api/AncestralTabletStatusController.cs
Normal file
29
web/App_Code/api/AncestralTabletStatusController.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Http;
|
||||
|
||||
/// <summary>
|
||||
/// AncestralTabletStatusController 的摘要描述
|
||||
/// </summary>
|
||||
public class AncestralTabletStatusController:ApiController
|
||||
{
|
||||
private Model.ezEntities _db = new Model.ezEntities();
|
||||
[HttpGet]
|
||||
[Route("api/ancestraltablet/status/list")]
|
||||
public IHttpActionResult GetStatusList()
|
||||
{
|
||||
var statusList = _db.AncestralTabletStatus
|
||||
.Select(s => new
|
||||
{
|
||||
s.StatusCode,
|
||||
s.StatusName,
|
||||
s.StatusType
|
||||
})
|
||||
.ToList();
|
||||
|
||||
return Ok(statusList);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -66,6 +66,7 @@ public class guadanGuestQueryController: ApiController
|
||||
checkoutdate = a.CheckOutAt,
|
||||
guadanorderno = a.GuaDanOrderNo,
|
||||
roomName = GetRoomAndBedString(a.RegionRoomBed),
|
||||
statusName = a.RegionRoomBedStatus.Name
|
||||
}).ToList();
|
||||
return Ok(new
|
||||
{
|
||||
|
||||
@@ -7,8 +7,6 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Web.Http;
|
||||
using static regionController;
|
||||
|
||||
/// <summary>
|
||||
/// guadanOderController 的摘要描述
|
||||
/// </summary>
|
||||
@@ -20,10 +18,19 @@ public class guadanOrderController : ApiController
|
||||
[Route("api/guadan/list")]
|
||||
public async Task<IHttpActionResult> getGuadanList([FromBody] guadan_order_search_dto search)
|
||||
{
|
||||
|
||||
var lastCheckoutTime = _db.GuadanTimeSetting.FirstOrDefault();
|
||||
string lastCheckoutTimeStr = null;
|
||||
if (lastCheckoutTime != null)
|
||||
{
|
||||
lastCheckoutTimeStr = lastCheckoutTime.LatestCheckOut;
|
||||
}
|
||||
var query = _db.GuaDanOrder
|
||||
.Where(a => a.IsCancel == false)
|
||||
.Where(a => a.IsDeleted == false);
|
||||
if(!string.IsNullOrEmpty(search.guaDanOrderNo))
|
||||
{
|
||||
query = query.Where(order => order.GuaDanOrderNo == search.guaDanOrderNo);
|
||||
}
|
||||
if (search.guadanUser != null)
|
||||
{
|
||||
query = query.Where(order => order.BookerName == search.guadanUser);
|
||||
@@ -45,7 +52,8 @@ public class guadanOrderController : ApiController
|
||||
}
|
||||
}
|
||||
var total = query.Count();
|
||||
var data = await query
|
||||
var data1 = await query.ToListAsync();
|
||||
var data = data1
|
||||
.OrderByDescending(b => b.CreatedAt)
|
||||
.Select(a => new
|
||||
{
|
||||
@@ -56,6 +64,14 @@ public class guadanOrderController : ApiController
|
||||
created_at = a.CreatedAt,
|
||||
updated_at = a.UpdatedAt,
|
||||
notes = a.Notes,
|
||||
is_timeout = !string.IsNullOrEmpty(lastCheckoutTimeStr) &&
|
||||
_db.GuaDanOrderGuest
|
||||
.Where(g => g.GuaDanOrderNo == a.GuaDanOrderNo && !g.IsDeleted && g.StatusCode == GuaDanOrderGuest.STATUS_CHECKED_IN)
|
||||
.ToList()
|
||||
.Any(g =>
|
||||
g.CheckOutAt.HasValue &&
|
||||
DateTime.Parse(g.CheckOutAt.Value.ToString("yyyy-MM-dd") + " " + lastCheckoutTimeStr) < DateTime.Now
|
||||
),
|
||||
activity = _db.activities
|
||||
.Where(act => act.num == a.ActivityNum)
|
||||
.Select(act => new
|
||||
@@ -68,23 +84,23 @@ public class guadanOrderController : ApiController
|
||||
.Where(c => c.GuaDanOrderNo == a.GuaDanOrderNo && c.IsDeleted == false)
|
||||
.Where(c => c.RegionRoomBedStatus.Code != GuaDanOrderGuest.STATUS_CANCELLED)
|
||||
.Count(),
|
||||
statusName = _db.GuaDanOrderGuest
|
||||
guadan_status = _db.GuaDanOrderGuest
|
||||
.Where(g => g.GuaDanOrderNo == a.GuaDanOrderNo && a.IsDeleted == false)
|
||||
.Where(g => g.StatusCode != GuaDanOrderGuest.STATUS_CANCELLED)
|
||||
.All(g => g.StatusCode == "401") ? "預約" :
|
||||
.All(g => g.StatusCode == "401") ? new { code=501, name="預約" }:
|
||||
_db.GuaDanOrderGuest
|
||||
.Where(g => g.GuaDanOrderNo == a.GuaDanOrderNo && a.IsDeleted == false)
|
||||
.Where(g => g.StatusCode != GuaDanOrderGuest.STATUS_CANCELLED)
|
||||
.All(g => g.StatusCode == "403") ? "全部退房" :
|
||||
.All(g => g.StatusCode == "403") ? new { code = 502, name = "全部退房" } :
|
||||
_db.GuaDanOrderGuest
|
||||
.Where(g => g.GuaDanOrderNo == a.GuaDanOrderNo && a.IsDeleted == false)
|
||||
.Where(g => g.StatusCode != GuaDanOrderGuest.STATUS_CANCELLED)
|
||||
.Any(g => g.StatusCode == "402" && a.IsCancel == false) ? "正在入住" :
|
||||
"部分退房"
|
||||
.Any(g => g.StatusCode == "402" && a.IsCancel == false) ? new { code = 503, name = "正在入住" } :
|
||||
new { code = 504, name = "部分退房" }
|
||||
})
|
||||
.Skip((search.page - 1) * search.pageSize)
|
||||
.Take(search.pageSize)
|
||||
.ToListAsync();
|
||||
.ToList();
|
||||
return Ok(new
|
||||
{
|
||||
total,
|
||||
@@ -214,7 +230,7 @@ public class guadanOrderController : ApiController
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (_db.GuaDanOrderGuest.Any(a => a.GuaDanOrderNo == guadan.GuaDanOrderNo))
|
||||
if (_db.GuaDanOrderGuest.Any(a => (a.GuaDanOrderNo == guadan.GuaDanOrderNo) && a.StatusCode != "404"))
|
||||
{
|
||||
return BadRequest($"該掛單已經存在掛單蓮友,不能取消!");
|
||||
}
|
||||
@@ -280,6 +296,7 @@ public class guadanOrderController : ApiController
|
||||
public string guadanUser { get; set; }
|
||||
public int page { get; set; } = 1;
|
||||
public int pageSize { get; set; } = 10;
|
||||
public string guaDanOrderNo { get; set; } = null;
|
||||
}
|
||||
|
||||
}
|
||||
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
908
web/admin/ancestraltablet/ancestraltabletarea/index.aspx
Normal file
908
web/admin/ancestraltablet/ancestraltabletarea/index.aspx
Normal file
@@ -0,0 +1,908 @@
|
||||
<%@ Page Title="" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="index.aspx.cs" Inherits="admin_ancestraltablet_ancestraltabletarea_index" %>
|
||||
|
||||
<asp:Content ID="Content1" ContentPlaceHolderID="page_header" Runat="Server">
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content2" ContentPlaceHolderID="page_nav" Runat="Server">
|
||||
<nav class="mb-2 ps-3">
|
||||
<button class="btn btn-primary me-2" type="button" @click="showNewtAreadialogMethod">
|
||||
<i class="mdi mdi-plus"></i> 新增區域
|
||||
</button>
|
||||
<button class="btn btn-secondary me-2" @click="expandAll" type="button">
|
||||
<i class="mdi mdi-arrow-expand-all"></i> 全部展開
|
||||
</button>
|
||||
<button class="btn btn-secondary" @click="collapseAll" type="button">
|
||||
<i class="mdi mdi-arrow-collapse-all"></i> 全部收起
|
||||
</button>
|
||||
</nav>
|
||||
<nav>
|
||||
<button type="button" class="btn btn-primary" @click="toggleAreaData">
|
||||
{{ showAreaDataFlag ? '隱藏區域資料' : '顯示區域資料' }}
|
||||
</button>
|
||||
</nav>
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 col-lg-3">
|
||||
<div class="card shadow-sm my-2">
|
||||
<div class="card-header">神主牌區域列表</div>
|
||||
<div class="card-body">
|
||||
<ul class="tree">
|
||||
<li v-for="area in ancestral_tablet_areas" :key="area.AreaId">
|
||||
<region-item
|
||||
:item="area"
|
||||
:selected-id="currentSelectAreaId"
|
||||
@select-area="selectAreaMethod"
|
||||
:expand-all="expandAllFlag"
|
||||
:collapse-all="collapseAllFlag"
|
||||
@clear-expand-all="expandAllFlag = false"
|
||||
@clear-collapse-all="collapseAllFlag = false"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4 col-lg-9" v-if="currentSelectArea && showAreaDataFlag">
|
||||
<div class="card shadow-sm my-2"style="position: sticky; top: 20px;">
|
||||
<div class="card-header" style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<div>
|
||||
<span class="fw-bold">
|
||||
{{ ' ' + currentSelectArea?.areaName + ' ' }}
|
||||
</span>
|
||||
<span>
|
||||
資料
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button class="btn btn-primary" type="button" @click="showEidtAreadialogMethod">
|
||||
編輯
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-6">
|
||||
<label>區域名稱</label>
|
||||
<input v-model="currentSelectArea.areaName" type="text" class="form-control" readonly/>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<label>區域編號</label>
|
||||
<input v-model="currentSelectArea.areaCode" type="text" class="form-control" readonly/>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<label>上層區域(可選)</label>
|
||||
<input v-model="currentSelectArea.parentAreaId" type="text" class="form-control" readonly />
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<label>區域類型(可空)</label>
|
||||
<input v-model="currentSelectArea.areaType" type="text" class="form-control" readonly/>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<label>價格</label>
|
||||
<input v-model="currentSelectArea.price" class="form-control" readonly/>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<label>排序</label>
|
||||
<input v-model="currentSelectArea.sortOrder" class="form-control" readonly/>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<div style="display: flex; align-items: center; height: 100%; margin-top: 8px;">
|
||||
<input
|
||||
v-model="currentSelectArea.isDisabled"
|
||||
type="checkbox"
|
||||
disabled
|
||||
id="disabledToggle"
|
||||
style="width: 20px; height: 20px; margin-right: 8px; cursor: pointer;"
|
||||
/>
|
||||
<label
|
||||
for="disabledToggle"
|
||||
style="font-weight: bold; font-size: 14px; color: #333; margin: 0;"
|
||||
>
|
||||
是否停用
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 mt-3">
|
||||
<label>描述</label>
|
||||
<textarea v-model="currentSelectArea.description" rows="3" class="form-control" readonly></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4 col-lg-9" v-if="currentSelectArea">
|
||||
<div class="card shadow-sm my-2" style="flex: 1 1 auto; min-height: 0; overflow: auto;">
|
||||
<div class="card-header" style="display: flex; justify-content: space-between; align-items: center;background-color: #ffc107;">
|
||||
<div>
|
||||
{{currentSelectArea.areaName + ' - ' + '神主牌位置'}}
|
||||
</div>
|
||||
<div>
|
||||
<v-btn color="primary" @click="openNewPositionDialogMethod">批次新增神主牌位置</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid-container">
|
||||
<div
|
||||
v-for="pos in positions"
|
||||
:key="pos.positionCode"
|
||||
class="grid-item"
|
||||
:class="'status-' + pos.statusCode"
|
||||
:style="{ gridRow: pos.rowNo, gridColumn: pos.columnNo }"
|
||||
>
|
||||
<div class="position-name">{{ pos.positionName }}</div>
|
||||
<div class="position-content">
|
||||
<!-- 這裡可以放更多資訊,比如價格或狀態 -->
|
||||
<!-- 例如:價格: {{ pos.price }} -->
|
||||
<v-btn small @click="editPositionMethod(pos)">修改</v-btn>
|
||||
<v-btn small @click="deletePositionMethod(pos)">刪除</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 新增區域彈出視窗 -->
|
||||
<div>
|
||||
<v-dialog v-model="showNewAreadialogFlag" max-width="1200px">
|
||||
<v-card
|
||||
style="min-height: 50vh; max-height: 80vh; overflow-y: auto;"
|
||||
>
|
||||
<v-card-title>
|
||||
<span class="headline">新增區域</span>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-6">
|
||||
<label>區域名稱</label>
|
||||
<input v-model="newArea.areaName" type="text" class="form-control" />
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<label>區域編號</label>
|
||||
<input v-model="newArea.areaCode" type="text" class="form-control" />
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<label>上層區域(可選)</label>
|
||||
<select v-model="newArea.parentAreaId" class="form-control" >
|
||||
<option value="">請選擇</option>
|
||||
<!-- 手動添加選項 -->
|
||||
<option v-for="r in flatAreas"
|
||||
:value="r.areaId"
|
||||
:disabled="disabledParentOptions.includes(r.areaId)">{{ r.areaName }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<label>區域類型(可空)</label>
|
||||
<input type="text" class="form-control" />
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<label>價格</label>
|
||||
<input v-model="newArea.price" class="form-control" />
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<label>排序</label>
|
||||
<input v-model="newArea.sortOrder" class="form-control" />
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<div style="display: flex; align-items: center; height: 100%; margin-top: 8px;">
|
||||
<input
|
||||
v-model="newArea.isDisabled"
|
||||
type="checkbox"
|
||||
style="width: 20px; height: 20px; margin-right: 8px; cursor: pointer;"
|
||||
/>
|
||||
<label
|
||||
for="disabledToggle"
|
||||
style="font-weight: bold; font-size: 14px; color: #333; margin: 0;"
|
||||
>
|
||||
是否停用
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 mt-3">
|
||||
<label>描述</label>
|
||||
<textarea v-model="newArea.description" rows="3" class="form-control" ></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="grey" text @click="closeNewAreadialogMethod">取消</v-btn>
|
||||
<v-btn color="primary" @click="createNewAreaMethod">確定新增</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
<!-- 編輯區域彈出視窗 -->
|
||||
<div>
|
||||
<v-dialog v-model="showEidtAreadialogFlag" max-width="1200px">
|
||||
<v-card
|
||||
style="min-height: 50vh; max-height: 80vh; overflow-y: auto;"
|
||||
>
|
||||
<v-card-title>
|
||||
<span class="headline">編輯區域</span>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12 col-sm-6">
|
||||
<label>區域名稱</label>
|
||||
<input v-model="editArea.areaName" type="text" class="form-control" required />
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<label>區域編號</label>
|
||||
<input v-model="editArea.areaCode" type="text" class="form-control" required />
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<label>上層區域(可選)</label>
|
||||
<select v-model="editArea.parentAreaId" class="form-control" >
|
||||
<option value="">請選擇</option>
|
||||
<!-- 手動添加選項 -->
|
||||
<option v-for="r in flatAreas"
|
||||
:value="r.areaId"
|
||||
:disabled="disabledParentOptions.includes(r.areaId)">{{ r.areaName }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<label>區域類型(可空)</label>
|
||||
<input v-model="editArea.areaType" type="text" class="form-control" />
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<label>價格</label>
|
||||
<input v-model="editArea.price" class="form-control" />
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<label>排序</label>
|
||||
<input v-model="editArea.sortOrder" class="form-control" />
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<div style="display: flex; align-items: center; height: 100%; margin-top: 8px;">
|
||||
<input
|
||||
v-model="editArea.isDisabled"
|
||||
type="checkbox"
|
||||
id="disabledToggle1"
|
||||
style="width: 20px; height: 20px; margin-right: 8px; cursor: pointer;"
|
||||
/>
|
||||
<label
|
||||
for="disabledToggle"
|
||||
style="font-weight: bold; font-size: 14px; color: #333; margin: 0;"
|
||||
>
|
||||
是否停用
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 mt-3">
|
||||
<label>描述</label>
|
||||
<textarea v-model="editArea.description" rows="3" class="form-control" ></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="grey" text @click="closeEidtAreadialogMethod">取消</v-btn>
|
||||
<v-btn color="primary" @click="editAreaMethod">送出修改</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
<!-- 批次新增神主牌彈出視窗 -->
|
||||
<div>
|
||||
<!-- 彈出視窗組件 -->
|
||||
<v-dialog v-model="showNewPositionDialogFlag" max-width="800px">
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
批次新增神主牌位置
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn icon @click="closeNewPositionDialogMethod">
|
||||
<v-icon>mdi-close</v-icon>
|
||||
</v-btn>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<div class="card p-3 mt-4">
|
||||
<div class="row mb-2">
|
||||
<div class="col">
|
||||
<label>起始行</label>
|
||||
<input v-model.number="batchPositionForm.startRow" type="number" class="form-control" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<label>起始列</label>
|
||||
<input v-model.number="batchPositionForm.startCol" type="number" class="form-control" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<label>行數</label>
|
||||
<input v-model.number="batchPositionForm.rows" type="number" class="form-control" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<label>列數</label>
|
||||
<input v-model.number="batchPositionForm.cols" type="number" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-2">
|
||||
<div class="col">
|
||||
<label>價格</label>
|
||||
<input v-model.number="batchPositionForm.price" type="number" class="form-control" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<label>狀態</label>
|
||||
<select v-model="batchPositionForm.status" class="form-control">
|
||||
<option v-for="s in statusList" :key="s.statusCode" :value="s.statusCode">
|
||||
{{ s.statusName }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<label>Name模板</label>
|
||||
<input v-model="batchPositionForm.nameTemplate" class="form-control" placeholder="如:神位編號{code}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col">
|
||||
<label>Code起始值</label>
|
||||
<input v-model.number="batchPositionForm.startCode" type="number" class="form-control" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<label>Code長度</label>
|
||||
<input v-model.number="batchPositionForm.codeLength" type="number" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="previewPositions.length">
|
||||
<h3>預覽新增位置</h3>
|
||||
<ul>
|
||||
<li v-for="pos in previewPositions" :key="pos.PositionCode">
|
||||
{{ pos.PositionCode }} - {{ pos.PositionName }} (行: {{ pos.RowNo }}, 列: {{ pos.ColumnNo }})
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions class="justify-end">
|
||||
<v-btn color="primary" @click="generatePositionsMethod">生成預覽</v-btn>
|
||||
<v-btn color="pirmary" @click="clearPreviewPositionsMethod">清除預覽</v-btn>
|
||||
<v-btn color="primary" @click="confirmAddPositionsMethod">確認新增</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
<!-- 編輯牌位位置彈出視窗 -->
|
||||
<div v-if="currentEditPosition">
|
||||
<v-dialog v-model="editPositionFormVisible" max-width="500">
|
||||
<v-card>
|
||||
<v-card-title class="text-h6">
|
||||
編輯位置:{{ currentEditPosition?.positionName || '未選擇' }}
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<div class="form-row">
|
||||
<label>位置名稱:</label>
|
||||
<input v-model="currentEditPosition.positionName" class="form-control" />
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label>價格:</label>
|
||||
<input v-model="currentEditPosition.price" type="number" class="form-control" />
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<label>狀態:</label>
|
||||
<select v-model="currentEditPosition.statusCode" class="form-control">
|
||||
<option v-for="s in statusList" :key="s.statusCode" :value="s.statusCode">
|
||||
{{ s.statusName }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="primary" @click="saveEditPositionMethod">保存</v-btn>
|
||||
<v-btn text @click="editPositionFormVisible = false">取消</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
</div>
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server">
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" Runat="Server">
|
||||
<script>
|
||||
Vue.component('region-item', {
|
||||
props: ['item', 'selectedId', 'expandAll', 'collapseAll'],
|
||||
data() {
|
||||
return {
|
||||
expanded: false, // 預設全部收起
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
expandAll(newVal) {
|
||||
if (newVal) {
|
||||
this.expanded = true;
|
||||
// 執行完後發事件通知父組件清除標誌
|
||||
this.$nextTick(() => this.$emit('clear-expand-all'));
|
||||
}
|
||||
},
|
||||
collapseAll(newVal) {
|
||||
if (newVal) {
|
||||
this.expanded = false;
|
||||
this.$nextTick(() => this.$emit('clear-collapse-all'));
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasChildren() {
|
||||
return this.item.children && this.item.children.length > 0;
|
||||
},
|
||||
icon() {
|
||||
// 無論有無子節點,皆可點擊展開/收起
|
||||
return this.expanded ? '▼' : '▶';
|
||||
},
|
||||
isSelected() {
|
||||
return this.item.areaId === this.selectedId;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggle() {
|
||||
this.expanded = !this.expanded;
|
||||
},
|
||||
select() {
|
||||
this.$emit('select-area', this.item);
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<div>
|
||||
<span class="toggle-icon" @click="toggle">{{ icon }}</span>
|
||||
<span @click="select"
|
||||
class="region-item-label"
|
||||
:class="{ 'selected': isSelected }">
|
||||
{{ item.areaName }}
|
||||
</span>
|
||||
|
||||
<!-- 子區域列表 -->
|
||||
<ul v-if="hasChildren && expanded">
|
||||
<li v-for="child in item.children" :key="child.areaId">
|
||||
<region-item
|
||||
:item="child"
|
||||
:selected-id="selectedId"
|
||||
:expand-all="expandAll"
|
||||
:collapse-all="collapseAll"
|
||||
@select-area="$emit('select-area', $event)"
|
||||
@clear-expand-all="$emit('clear-expand-all')"
|
||||
@clear-collapse-all="$emit('clear-collapse-all')"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`
|
||||
});
|
||||
new Vue({
|
||||
el: '#app',
|
||||
vuetify: new Vuetify(vuetify_options),
|
||||
data() {
|
||||
return {
|
||||
expandAllFlag: false, // 控制全部展開
|
||||
collapseAllFlag: false, // 控制全部收起
|
||||
ancestral_tablet_areas: [], //神主牌區域列表
|
||||
currentSelectArea: null,
|
||||
currentSelectAreaId: null,
|
||||
showEidtAreadialogFlag: false,
|
||||
showNewAreadialogFlag: false,
|
||||
showAreaDataFlag: false,//是否顯示區域資料
|
||||
flatAreas: [],//所有區域展平
|
||||
disabledParentOptions: [],//某個區域禁止選擇作為父區域的函數
|
||||
newArea: {
|
||||
areaId: null, // 自增主鍵,新增時通常為 null
|
||||
areaName: null, // 區域名稱,必填
|
||||
areaCode: null, // 區域編號,必填
|
||||
parentAreaId: null, // 上層區域 ID,可為 null
|
||||
areaType: null, // 區域類型,可空
|
||||
price: null, // 價格,可空
|
||||
sortOrder: null, // 排序,可空
|
||||
description: null, // 區域描述
|
||||
isDisabled: null
|
||||
},
|
||||
editArea: {
|
||||
areaId: null, // 自增主鍵,新增時通常為 null
|
||||
areaName: null, // 區域名稱,必填
|
||||
areaCode: null, // 區域編號,必填
|
||||
parentAreaId: null, // 上層區域 ID,可為 null
|
||||
areaType: null, // 區域類型,可空
|
||||
price: null, // 價格,可空
|
||||
sortOrder: null, // 排序,可空
|
||||
description: null, // 區域描述
|
||||
isDisabled: null
|
||||
},
|
||||
statusList: [],
|
||||
//--------------------------------神主牌位置變數
|
||||
showNewPositionDialogFlag: false,//控制是否顯示批次新增神主牌彈出視窗
|
||||
editPositionFormVisible: false, // 控制是否顯示編輯彈出視窗
|
||||
currentEditPosition: null, // 儲存當前正在編輯的位置資訊
|
||||
batchPositionForm: {
|
||||
startRow: 1,
|
||||
startCol: 1,
|
||||
rows: 5,
|
||||
cols: 10,
|
||||
price: 0,
|
||||
status: 'available',
|
||||
nameTemplate: '神位{code}',
|
||||
startCode: 1,
|
||||
codeLength: 3
|
||||
},
|
||||
positions: [],
|
||||
// 預覽數據
|
||||
previewPositions: [],
|
||||
//--------------------------------神主牌位置變數
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
selectAreaMethod(area) {
|
||||
this.currentSelectAreaId = area.areaId;
|
||||
this.currentSelectArea = area;
|
||||
const node = this.findRegionById(this.ancestral_tablet_areas, area.areaId);
|
||||
this.disabledParentOptions = this.getAllDescendants(node);
|
||||
this.loadTabletPositionsMethod(area.areaId);
|
||||
},
|
||||
showEidtAreadialogMethod() {
|
||||
this.showEidtAreadialogFlag = true;
|
||||
if (this.currentSelectArea) {
|
||||
this.editArea = {
|
||||
areaId: this.currentSelectArea?.areaId,
|
||||
areaName: this.currentSelectArea?.areaName,
|
||||
areaCode: this.currentSelectArea?.areaCode,
|
||||
parentAreaId: this.currentSelectArea?.parentAreaId ?? null,
|
||||
areaType: this.currentSelectArea?.areaType ?? null,
|
||||
price: this.currentSelectArea?.price ?? null,
|
||||
sortOrder: this.currentSelectArea?.sortOrder ?? null,
|
||||
description: this.currentSelectArea?.description ?? null,
|
||||
isDisabled: this.currentSelectArea?.isDisabled ?? true
|
||||
};
|
||||
}
|
||||
|
||||
},
|
||||
closeEidtAreadialogMethod() {
|
||||
this.showEidtAreadialogFlag = false;
|
||||
this.resetEditArea();
|
||||
},
|
||||
showNewtAreadialogMethod() {
|
||||
this.showNewAreadialogFlag = true;
|
||||
},
|
||||
closeNewAreadialogMethod() {
|
||||
this.showNewAreadialogFlag = false;
|
||||
this.resetNewArea();
|
||||
},
|
||||
createNewAreaMethod() {
|
||||
//新建區域
|
||||
axios.post(HTTP_HOST + 'api/ancestraltablet/area/create', this.newArea)
|
||||
.then(response => {
|
||||
this.closeEidtAreadialogMethod();
|
||||
this.getAreaListMethod();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('失敗:', error);
|
||||
});
|
||||
|
||||
},
|
||||
editAreaMethod() {
|
||||
//修改區域資料
|
||||
axios.post(HTTP_HOST + 'api/ancestraltablet/area/edit', this.editArea)
|
||||
.then(response => {
|
||||
this.currentSelectArea = response.data.area;
|
||||
this.getAreaListMethod();
|
||||
this.closeEidtAreadialogMethod();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('失敗:', error);
|
||||
});
|
||||
|
||||
},
|
||||
resetNewArea() {
|
||||
this.newArea = {
|
||||
areaId: null,
|
||||
areaName: null,
|
||||
areaCode: null,
|
||||
parentAreaId: null,
|
||||
areaType: null,
|
||||
price: null,
|
||||
sortOrder: null,
|
||||
description: null,
|
||||
isDisabled: false
|
||||
};
|
||||
},
|
||||
resetEditArea() {
|
||||
this.editArea = {
|
||||
areaId: null,
|
||||
areaName: null,
|
||||
areaCode: null,
|
||||
parentAreaId: null,
|
||||
areaType: null,
|
||||
price: null,
|
||||
sortOrder: null,
|
||||
description: null,
|
||||
isDisabled: false
|
||||
};
|
||||
},
|
||||
getAreaListMethod() {
|
||||
//獲取區域列表
|
||||
axios.get(HTTP_HOST + 'api/ancestraltablet/area/getlist')
|
||||
.then(res => {
|
||||
this.ancestral_tablet_areas = res.data
|
||||
this.flatAreas = this.flattenAreas(res.data);
|
||||
})
|
||||
},
|
||||
expandAll() {
|
||||
this.expandAllFlag = true;
|
||||
this.collapseAllFlag = false;
|
||||
},
|
||||
collapseAll() {
|
||||
this.collapseAllFlag = true;
|
||||
this.expandAllFlag = false;
|
||||
},
|
||||
|
||||
//區域展開是否可以被選擇作為上級區域相關函數
|
||||
flattenAreas(data, list = []) {
|
||||
data.forEach(item => {
|
||||
list.push({ areaId: item.areaId, areaName: item.areaName });
|
||||
if (item.children && item.children.length) {
|
||||
this.flattenAreas(item.children, list);
|
||||
}
|
||||
});
|
||||
return list;
|
||||
},
|
||||
findRegionById(list, areaId) {
|
||||
for (const item of list) {
|
||||
if (item.areaId === areaId) return item;
|
||||
if (item.children) {
|
||||
const found = this.findRegionById(item.children, areaId);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
getAllDescendants(node) {
|
||||
//尋找某個區域的所有子區域
|
||||
const ids = [];
|
||||
const dfs = (n) => {
|
||||
ids.push(n.areaId);
|
||||
if (n.children) {
|
||||
n.children.forEach(child => dfs(child));
|
||||
}
|
||||
};
|
||||
dfs(node);
|
||||
return ids;
|
||||
},
|
||||
toggleAreaData() {
|
||||
this.showAreaDataFlag = !this.showAreaDataFlag;
|
||||
},
|
||||
//--------------------------------神主牌位置相關函數
|
||||
padCodeMethod(codeNum, length) {
|
||||
return codeNum.toString().padStart(length, '0');
|
||||
},
|
||||
loadTabletPositionsMethod(areaId) {
|
||||
axios.get(HTTP_HOST + 'api/ancestraltablet/area/position/getlist', {
|
||||
params: {
|
||||
areaId: areaId
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
this.positions = response.data;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('失敗:', error);
|
||||
});
|
||||
},
|
||||
generatePositionsMethod() {
|
||||
const form = this.batchPositionForm;
|
||||
const positions = [];
|
||||
let codeCounter = form.startCode;
|
||||
|
||||
for (let i = 0; i < form.rows; i++) {
|
||||
for (let j = 0; j < form.cols; j++) {
|
||||
const row = form.startRow + i;
|
||||
const col = form.startCol + j;
|
||||
const paddedCode = this.padCodeMethod(codeCounter, form.codeLength);
|
||||
const positionCode = paddedCode;
|
||||
const positionName = form.nameTemplate.replace('{code}', paddedCode);
|
||||
|
||||
positions.push({
|
||||
AreaId: this.currentSelectArea.areaId,
|
||||
RowNo: row,
|
||||
ColumnNo: col,
|
||||
PositionCode: positionCode,
|
||||
PositionName: positionName,
|
||||
Price: form.price,
|
||||
StatusCode: form.status,
|
||||
Description: ''
|
||||
});
|
||||
|
||||
codeCounter++;
|
||||
}
|
||||
}
|
||||
this.previewPositions = positions; // 先賦值預覽,不發請求
|
||||
},
|
||||
async confirmAddPositionsMethod() {
|
||||
if (this.previewPositions.length === 0) {
|
||||
alert('請先生成預覽數據');
|
||||
return;
|
||||
}
|
||||
// 調用後端批次新增介面
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${HTTP_HOST}api/ancestraltablet/position/batchcreate`,
|
||||
this.previewPositions
|
||||
);
|
||||
|
||||
// 如果後端成功響應(HTTP 200/201)
|
||||
alert('批次新增成功');
|
||||
this.loadTabletPositionsMethod(this.currentSelectArea.areaId); // 刷新數據
|
||||
} catch (error) {
|
||||
// 捕獲錯誤響應(如500、400等)
|
||||
console.error('批次新增失敗', error);
|
||||
|
||||
let msg = '批次新增失敗';
|
||||
if (error.response && error.response.data && error.response.data.exceptionMessage) {
|
||||
msg += `:${error.response.data.exceptionMessage}`;
|
||||
}
|
||||
|
||||
alert(msg);
|
||||
}
|
||||
this.previewPositions = []; // 清空預覽
|
||||
},
|
||||
clearPreviewPositionsMethod() {
|
||||
this.previewPositions = [];
|
||||
},
|
||||
openNewPositionDialogMethod() {
|
||||
this.showNewPositionDialogFlag = true;
|
||||
this.batchPositionForm.price = this.currentSelectArea.price
|
||||
},
|
||||
closeNewPositionDialogMethod() {
|
||||
this.showNewPositionDialogFlag = false;
|
||||
this.previewPositions = [];
|
||||
},
|
||||
editPositionMethod(position) {
|
||||
// 彈出編輯表單、打開模態框或跳轉到編輯頁面
|
||||
this.currentEditPosition = position;
|
||||
this.editPositionFormVisible = true;
|
||||
},
|
||||
async saveEditPositionMethod() {
|
||||
try {
|
||||
await axios.post(`${HTTP_HOST}api/ancestraltablet/position/edit`, this.currentEditPosition);
|
||||
this.$message?.success?.('保存成功') || alert('保存成功');
|
||||
this.editPositionFormVisible = false;
|
||||
this.loadTabletPositionsMethod(this.currentSelectArea.areaId);
|
||||
this.currentEditPosition = null
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
this.$message?.error?.('保存失敗') || alert('保存失敗');
|
||||
}
|
||||
},
|
||||
async deletePositionMethod(position) {
|
||||
if (confirm(`確定要刪除【${position.positionName}】嗎?`)) {
|
||||
try {
|
||||
await axios.delete(`${HTTP_HOST}api/ancestraltablet/position/delete/${position.positionId}`);
|
||||
this.$message?.success?.('刪除成功'); // 如果用的是 Element Plus 或其他 UI 框架
|
||||
this.loadTabletPositionsMethod(this.currentSelectArea.areaId); // 刷新數據
|
||||
} catch (error) {
|
||||
console.error('刪除失敗', error);
|
||||
this.$message?.error?.('刪除失敗,請檢查網路或稍後再試');
|
||||
}
|
||||
}
|
||||
},
|
||||
//--------------------------------神主牌位置相關函數
|
||||
async loadStatusList() {
|
||||
//獲取狀態列表
|
||||
try {
|
||||
const response = await axios.get(`${HTTP_HOST}api/ancestraltablet/status/list`);
|
||||
this.statusList = response.data;
|
||||
} catch (err) {
|
||||
console.error('獲取狀態列表失敗', err);
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
watch: {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
this.getAreaListMethod();
|
||||
this.loadStatusList();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
.tree, .tree ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
.toggle-icon {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
width: 1rem;
|
||||
display: inline-block;
|
||||
color: #007bff;
|
||||
}
|
||||
.region-item-label {
|
||||
cursor: pointer;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
.region-item-label.selected {
|
||||
background-color: #eaf4ff;
|
||||
color: #0d6efd;
|
||||
font-weight: bold;
|
||||
}
|
||||
.grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(10, 120px); /* 6列 */
|
||||
grid-auto-rows: 100px; /* 行高 */
|
||||
gap: 10px;
|
||||
}
|
||||
/* 可用(綠色) */
|
||||
.status-available {
|
||||
background-color: #d4edda;
|
||||
border-color: #28a745;
|
||||
}
|
||||
|
||||
/* 維護中(黃色) */
|
||||
.status-maintenance {
|
||||
background-color: #fff3cd;
|
||||
border-color: #ffc107;
|
||||
}
|
||||
|
||||
/* 預訂中(藍色) */
|
||||
.status-reserved {
|
||||
background-color: #cce5ff;
|
||||
border-color: #007bff;
|
||||
}
|
||||
|
||||
/* 已使用(灰色) */
|
||||
.status-used {
|
||||
background-color: #e2e3e5;
|
||||
border-color: #6c757d;
|
||||
}
|
||||
.grid-item {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-shadow: 1px 1px 3px rgba(0,0,0,0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.position-name {
|
||||
background-color: #f0f0f0;
|
||||
padding: 4px 8px;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.position-content {
|
||||
flex-grow: 1;
|
||||
padding: 3px;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
</asp:Content>
|
||||
14
web/admin/ancestraltablet/ancestraltabletarea/index.aspx.cs
Normal file
14
web/admin/ancestraltablet/ancestraltabletarea/index.aspx.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using System.Web.UI.WebControls;
|
||||
|
||||
public partial class admin_ancestraltablet_ancestraltabletarea_index : MyWeb.config
|
||||
{
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
569
web/admin/ancestraltablet/ancestraltabletposition/index.aspx
Normal file
569
web/admin/ancestraltablet/ancestraltabletposition/index.aspx
Normal file
@@ -0,0 +1,569 @@
|
||||
<%@ Page Title="" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="index.aspx.cs" Inherits="admin_ancestraltablet_ancestraltabletposition_index" %>
|
||||
<asp:Content ID="Content1" ContentPlaceHolderID="page_header" Runat="Server">
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content2" ContentPlaceHolderID="page_nav" Runat="Server">
|
||||
<nav class="mb-2 ps-3">
|
||||
<button class="btn btn-secondary me-2" @click="expandAll" type="button">
|
||||
<i class="mdi mdi-arrow-expand-all"></i> 全部展開
|
||||
</button>
|
||||
<button class="btn btn-secondary" @click="collapseAll" type="button">
|
||||
<i class="mdi mdi-arrow-collapse-all"></i> 全部收起
|
||||
</button>
|
||||
</nav>
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 col-lg-2">
|
||||
<div class="card shadow-sm my-2">
|
||||
<div class="card-header">神主牌區域列表</div>
|
||||
<div class="card-body">
|
||||
<ul class="tree">
|
||||
<li v-for="area in ancestral_tablet_areas" :key="area.AreaId">
|
||||
<region-item
|
||||
:item="area"
|
||||
:selected-id="currentSelectAreaId"
|
||||
@select-area="selectAreaMethod"
|
||||
:expand-all="expandAllFlag"
|
||||
:collapse-all="collapseAllFlag"
|
||||
@clear-expand-all="expandAllFlag = false"
|
||||
@clear-collapse-all="collapseAllFlag = false"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4 col-lg-10" v-if="currentSelectArea">
|
||||
<div class="card shadow-sm my-2" style="position: sticky; top: 20px; display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0;">
|
||||
<div class="card-header" style="display: flex; justify-content: space-between; align-items: center;background-color: #ffc107;">
|
||||
<div>
|
||||
{{currentSelectArea.areaName + ' - ' + '神主牌位置'}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body" style="flex: 1 1 auto; min-height: 0; overflow: auto;">
|
||||
<div class="grid-container">
|
||||
<div
|
||||
v-for="pos in positions"
|
||||
:key="pos.positionCode"
|
||||
class="grid-item"
|
||||
:class="'status-' + pos.statusCode"
|
||||
:style="{ gridRow: pos.rowNo, gridColumn: pos.columnNo }"
|
||||
>
|
||||
<div class="position-name">{{ pos.positionName }}</div>
|
||||
<div class="position-content">
|
||||
<span v-if="pos.statusCode == 'maintenance'">維護中</span>
|
||||
<v-btn v-else-if="!pos.ancestralTabletRegistrant" @click="showCreatePWMethod(pos)">登記</v-btn>
|
||||
<!-- 已預訂 -->
|
||||
<div v-else>
|
||||
<div>登記人:{{ pos.ancestralTabletRegistrant?.name }}</div>
|
||||
<div>登記日期:{{ pos.ancestralTabletRegistrant?.registerDate|timeString('YYYY/MM/DD') }}</div>
|
||||
<v-btn small color="btn-primary" @click="showEditPWMethod(pos)">
|
||||
詳細資訊
|
||||
</v-btn>
|
||||
|
||||
</>
|
||||
</div>
|
||||
|
||||
<!-- 已使用 -->
|
||||
<div v-else-if="pos.statusCode === 'used'">
|
||||
<div>已使用</div>
|
||||
<div v-if="pos.usedBy">使用人:{{ pos.usedBy }}</div>
|
||||
<div v-if="pos.usedDate">使用日期:{{ pos.usedDate|timeString('YYYY/MM/DD') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 登記資料彈出視窗 -->
|
||||
<div>
|
||||
<v-dialog v-model="showCreatePWFlag" max-width="800">
|
||||
<v-card>
|
||||
<v-card-title class="headline">登記資料({{'位置: ' + selectedPos?.positionName}})</v-card-title>
|
||||
<v-card-text>
|
||||
<!-- 登記人資料 -->
|
||||
<hr />
|
||||
<h5>登記人資料</h5>
|
||||
<label>姓名:
|
||||
<input class="form-control" type="text" v-model="form.createRegister.name" />
|
||||
</label><br />
|
||||
<label>電話:
|
||||
<input class="form-control" type="text" v-model="form.createRegister.phone" />
|
||||
</label><br />
|
||||
<label>住址:
|
||||
<input class="form-control" type="text" v-model="form.createRegister.address" />
|
||||
</label><br />
|
||||
<label>費用:
|
||||
<input class="form-control" v-model="form.createRegister.price" />
|
||||
</label><br />
|
||||
<label>登記時間:
|
||||
<input class="form-control" type="date" v-model="form.createRegister.registerDate" />
|
||||
</label><br />
|
||||
<label>開始時間:
|
||||
<input class="form-control" type="date" v-model="form.createRegister.startDate" />
|
||||
</label><br />
|
||||
<label>結束時間:
|
||||
<input class="form-control" type="date" v-model="form.createRegister.endDate" />
|
||||
</label><br />
|
||||
<label>長期有效:
|
||||
<input type="checkbox" v-model="form.createRegister.isLongTerm" />
|
||||
</label><br />
|
||||
<label>是否啟用:
|
||||
<input type="checkbox" v-model="form.createRegister.isActive" />
|
||||
</label><br />
|
||||
<div class="mt-2 mb-4">
|
||||
<button
|
||||
v-if="!form.createRegister.registrantCode"
|
||||
class="btn btn-primary"
|
||||
type="button"
|
||||
@click="saveRegistrantMethod">
|
||||
保存登記人
|
||||
</button>
|
||||
<button
|
||||
v-else
|
||||
class="btn btn-primary"
|
||||
type="button"
|
||||
@click="updateRegistrantMethod">
|
||||
送出修改
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 牌位資料 -->
|
||||
<hr />
|
||||
<h5>牌位資料</h5>
|
||||
<label>牌位標題:
|
||||
<input class="form-control" type="text" v-model="form.createPositionRecord.npTitle" />
|
||||
</label><br />
|
||||
<label>立牌時間:
|
||||
<input class="form-control" type="date" v-model="form.createPositionRecord.npStandDate" />
|
||||
</label><br />
|
||||
<label>陽上:
|
||||
<input class="form-control" type="text" v-model="form.createPositionRecord.npYangShang" />
|
||||
</label><br />
|
||||
<label>內牌內容:</label>
|
||||
<textarea
|
||||
class="form-control"
|
||||
rows="4"
|
||||
v-model="form.createPositionRecord.wpContent"
|
||||
style="width: 100%; box-sizing: border-box;"
|
||||
></textarea><br />
|
||||
<div class="mt-2 mb-2">
|
||||
<button v-if="form.createPositionRecord.recordId == null" class="btn btn-primary" type="button" @click="saveCreatePositionRecordMethod">保存牌位</button>
|
||||
<button v-else type="button" class="btn btn-primary" @click="updateCreatePositionRecordMethod">
|
||||
送出修改
|
||||
</button>
|
||||
</div>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<button class="btn btn-secondary" type="button" @click="closePWDialogMethod">關閉</button>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server">
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" Runat="Server">
|
||||
<script>
|
||||
Vue.component('region-item', {
|
||||
props: ['item', 'selectedId', 'expandAll', 'collapseAll'],
|
||||
data() {
|
||||
return {
|
||||
expanded: false, // 預設全部收起
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
expandAll(newVal) {
|
||||
if (newVal) {
|
||||
this.expanded = true;
|
||||
// 執行完後發事件通知父組件清除標誌
|
||||
this.$nextTick(() => this.$emit('clear-expand-all'));
|
||||
}
|
||||
},
|
||||
collapseAll(newVal) {
|
||||
if (newVal) {
|
||||
this.expanded = false;
|
||||
this.$nextTick(() => this.$emit('clear-collapse-all'));
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasChildren() {
|
||||
return this.item.children && this.item.children.length > 0;
|
||||
},
|
||||
icon() {
|
||||
// 無論有無子節點,皆可點擊展開/收起
|
||||
return this.expanded ? '▼' : '▶';
|
||||
},
|
||||
isSelected() {
|
||||
return this.item.areaId === this.selectedId;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggle() {
|
||||
this.expanded = !this.expanded;
|
||||
},
|
||||
select() {
|
||||
this.$emit('select-area', this.item);
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<div>
|
||||
<span class="toggle-icon" @click="toggle">{{ icon }}</span>
|
||||
<span @click="select"
|
||||
class="region-item-label"
|
||||
:class="{ 'selected': isSelected }">
|
||||
{{ item.areaName }}
|
||||
</span>
|
||||
|
||||
<!-- 子區域列表 -->
|
||||
<ul v-if="hasChildren && expanded">
|
||||
<li v-for="child in item.children" :key="child.areaId">
|
||||
<region-item
|
||||
:item="child"
|
||||
:selected-id="selectedId"
|
||||
:expand-all="expandAll"
|
||||
:collapse-all="collapseAll"
|
||||
@select-area="$emit('select-area', $event)"
|
||||
@clear-expand-all="$emit('clear-expand-all')"
|
||||
@clear-collapse-all="$emit('clear-collapse-all')"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`
|
||||
});
|
||||
Vue.filter('timeString', function (value, myFormat) {
|
||||
return value == null || value == "" ? "" : moment(value).format(myFormat || 'YYYY-MM-DD, HH:mm:ss');
|
||||
});
|
||||
new Vue({
|
||||
el: '#app',
|
||||
vuetify: new Vuetify(vuetify_options),
|
||||
data() {
|
||||
return {
|
||||
expandAllFlag: false, // 控制全部展開
|
||||
collapseAllFlag: false, // 控制全部收起
|
||||
ancestral_tablet_areas: [], //神主牌區域列表
|
||||
currentSelectArea: null,
|
||||
currentSelectAreaId: null,
|
||||
statusList: [],
|
||||
//--------------------------------神主牌位置變數
|
||||
positions: [],
|
||||
selectedPos: null, //點擊登記的的pos
|
||||
showCreatePWFlag: false, //控制是否打開登記神主牌位資料彈出視窗
|
||||
form: {
|
||||
createRegister: {
|
||||
//新增登記人form
|
||||
registrantCode: null, // 登記編號
|
||||
positionId: null,
|
||||
name: null,
|
||||
phone: null,
|
||||
address: null,
|
||||
registerDate: null,
|
||||
price: null,
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
isLongTerm: false,
|
||||
isActive: true,
|
||||
|
||||
|
||||
},
|
||||
createPositionRecord: {
|
||||
//新增牌位登記form
|
||||
recordId: null, // 自增主鍵,前端一般不用填
|
||||
registrantCode: null, // 外鍵,關聯登記人編號
|
||||
npTitle: null,
|
||||
npStandDate: null,
|
||||
npYangShang: null,
|
||||
wpContent: null,
|
||||
},
|
||||
},
|
||||
//--------------------------------神主牌位置變數
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
selectAreaMethod(area) {
|
||||
this.currentSelectAreaId = area.areaId;
|
||||
this.currentSelectArea = area;
|
||||
this.loadTabletPositionsMethod(area.areaId);
|
||||
},
|
||||
getAreaListMethod() {
|
||||
//獲取區域列表
|
||||
axios.get(HTTP_HOST + 'api/ancestraltablet/area/getlist')
|
||||
.then(res => {
|
||||
this.ancestral_tablet_areas = res.data
|
||||
})
|
||||
},
|
||||
expandAll() {
|
||||
this.expandAllFlag = true;
|
||||
this.collapseAllFlag = false;
|
||||
},
|
||||
collapseAll() {
|
||||
this.collapseAllFlag = true;
|
||||
this.expandAllFlag = false;
|
||||
},
|
||||
//--------------------------------神主牌位置相關函數
|
||||
loadTabletPositionsMethod(areaId) {
|
||||
axios.get(HTTP_HOST + 'api/ancestraltablet/position/getlist', {
|
||||
params: {
|
||||
areaId: areaId
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
this.positions = response.data;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('失敗:', error);
|
||||
});
|
||||
},
|
||||
showCreatePWMethod(pos) {
|
||||
//打開新增彈出視窗
|
||||
this.selectedPos = pos;
|
||||
this.showCreatePWFlag = true;
|
||||
this.form.createRegister.positionId = pos.positionId
|
||||
this.form.createRegister.price = pos.price
|
||||
},
|
||||
showEditPWMethod(pos) {
|
||||
//打開編輯彈出視窗
|
||||
this.selectedPos = pos;
|
||||
const registrant = pos.ancestralTabletRegistrant;
|
||||
|
||||
if (registrant) {
|
||||
this.form.createRegister.registrantCode = registrant.registrantCode;
|
||||
this.form.createRegister.positionId = pos.positionId;
|
||||
this.form.createRegister.name = registrant.name;
|
||||
this.form.createRegister.phone = registrant.phone;
|
||||
this.form.createRegister.address = registrant.address;
|
||||
this.form.createRegister.registerDate = registrant.registerDate
|
||||
? registrant.registerDate?.split('T')[0]
|
||||
: '';
|
||||
this.form.createRegister.price = registrant.price;
|
||||
this.form.createRegister.startDate = registrant.startDate ? registrant.startDate?.split('T')[0]
|
||||
: '';
|
||||
this.form.createRegister.endDate = registrant.endDate ? registrant.endDate?.split('T')[0]
|
||||
: '';
|
||||
this.form.createRegister.isLongTerm = registrant.isLongTerm;
|
||||
this.form.createRegister.isActive = registrant.isActive;
|
||||
this.form.createPositionRecord.registrantCode = registrant.registrantCode;
|
||||
this.showCreatePWFlag = true;
|
||||
if (registrant.tabletRecord) {
|
||||
this.form.createPositionRecord.recordId = registrant.tabletRecord.recordId;
|
||||
this.form.createPositionRecord.registrantCode = registrant.tabletRecord.registrantCode;
|
||||
this.form.createPositionRecord.npTitle = registrant.tabletRecord.npTitle;
|
||||
this.form.createPositionRecord.npStandDate = registrant.tabletRecord.npStandDate ? registrant.tabletRecord.npStandDate.split('T')[0]
|
||||
: '';
|
||||
this.form.createPositionRecord.npYangShang = registrant.tabletRecord.npYangShang;
|
||||
this.form.createPositionRecord.wpContent = registrant.tabletRecord.wpContent;
|
||||
}
|
||||
}
|
||||
},
|
||||
closePWDialogMethod(pos) {
|
||||
//關閉編輯彈出視窗
|
||||
this.selectedPos = null;
|
||||
|
||||
// 重設登記人欄位
|
||||
this.form.createRegister = {
|
||||
registrantCode: null,
|
||||
positionId: null,
|
||||
name: null,
|
||||
phone: null,
|
||||
address: null,
|
||||
registerDate: null,
|
||||
price: null,
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
isLongTerm: false,
|
||||
isActive: false
|
||||
};
|
||||
|
||||
// 清空牌位記錄
|
||||
this.form.createPositionRecord = {
|
||||
recordId: null,
|
||||
registrantCode: null,
|
||||
npTitle: null,
|
||||
npStandDate: null,
|
||||
npYangShang: null,
|
||||
wpContent: null
|
||||
};
|
||||
|
||||
this.showCreatePWFlag = false;
|
||||
},
|
||||
//--------------------------------神主牌位置相關函數
|
||||
//--------------------------------登記人相關函數 start
|
||||
async saveRegistrantMethod() {
|
||||
try {
|
||||
const response = await axios.post(HTTP_HOST + 'api/ancestraltablet/registrant/create', this.form.createRegister);
|
||||
console.log('保存成功', response.data);
|
||||
|
||||
// 可選:提示用戶、關閉對話框、刷新數據等
|
||||
this.$toast?.success('登記人保存成功'); // 取決於你是否使用 toast 插件
|
||||
this.form.createRegister.registrantCode = response.data.registrantCode
|
||||
this.form.createPositionRecord.registrantCode = response.data.registrantCode
|
||||
this.loadTabletPositionsMethod(this.selectedPos.areaId)
|
||||
alert("修改成功")
|
||||
} catch (error) {
|
||||
console.error('保存失敗', error);
|
||||
this.$toast?.error('登記人保存失敗');
|
||||
}
|
||||
},
|
||||
updateRegistrantMethod() {
|
||||
axios.post(HTTP_HOST + 'api/ancestraltablet/registrant/update', this.form.createRegister)
|
||||
.then(response => {
|
||||
console.log('登記人更新成功:', response.data);
|
||||
this.$toast?.success?.('登記人更新成功'); // 可選:使用 toast 彈出提示
|
||||
//this.showCreatePWFlag = false; // 關閉彈出視窗
|
||||
// 可選:刷新列表等
|
||||
this.loadTabletPositionsMethod(this.selectedPos.areaId)
|
||||
alert("修改成功")
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('更新登記人失敗:', error);
|
||||
this.$toast?.error?.('更新失敗,請檢查數據');
|
||||
});
|
||||
},
|
||||
//--------------------------------登記人相關函數 end
|
||||
|
||||
//--------------------------------牌位資料相關函數 Start
|
||||
saveCreatePositionRecordMethod() {
|
||||
// 校驗必須欄位
|
||||
if (!this.form.createPositionRecord.registrantCode) {
|
||||
alert('請先填寫登記人資料並且送出保存!');
|
||||
return;
|
||||
}
|
||||
|
||||
axios.post(HTTP_HOST + 'api/ancestraltablet/pw/create', this.form.createPositionRecord)
|
||||
.then(res => {
|
||||
if (res.data && res.data.message) {
|
||||
alert(res.data.message);
|
||||
} else {
|
||||
alert('保存成功');
|
||||
}
|
||||
// 成功後可以關閉彈出視窗或清空表單
|
||||
//this.showCreatePWFlag = false;
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('保存失敗:', err);
|
||||
alert('保存失敗,請檢查伺服器日誌');
|
||||
});
|
||||
},
|
||||
updateCreatePositionRecordMethod() {
|
||||
// 校驗必須欄位
|
||||
if (!this.form.createPositionRecord.recordId) {
|
||||
alert('不存在牌位資料,無法更新');
|
||||
return;
|
||||
}
|
||||
|
||||
axios.post(HTTP_HOST + 'api/ancestraltablet/pw/update', this.form.createPositionRecord)
|
||||
.then(res => {
|
||||
if (res.data && res.data.message) {
|
||||
alert(res.data.message);
|
||||
} else {
|
||||
alert('牌位資料更新成功');
|
||||
}
|
||||
// 成功後可以關閉彈出視窗或清空表單
|
||||
//this.showCreatePWFlag = false;
|
||||
})
|
||||
.catch(err => {
|
||||
alert('更新失敗:', err);
|
||||
});
|
||||
},
|
||||
//--------------------------------牌位資料相關函數 end
|
||||
async loadStatusList() {
|
||||
//獲取狀態列表
|
||||
try {
|
||||
const response = await axios.get(`${HTTP_HOST}api/ancestraltablet/status/list`);
|
||||
this.statusList = response.data;
|
||||
} catch (err) {
|
||||
console.error('獲取狀態列表失敗', err);
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
watch: {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
this.getAreaListMethod();
|
||||
this.loadStatusList();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
.tree, .tree ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
.toggle-icon {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
width: 1rem;
|
||||
display: inline-block;
|
||||
color: #007bff;
|
||||
}
|
||||
.region-item-label {
|
||||
cursor: pointer;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
.region-item-label.selected {
|
||||
background-color: #eaf4ff;
|
||||
color: #0d6efd;
|
||||
font-weight: bold;
|
||||
}
|
||||
.grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(10, 150px); /* 6列 */
|
||||
grid-auto-rows: 150px; /* 行高 */
|
||||
gap: 10px;
|
||||
}
|
||||
/* 可用(綠色) */
|
||||
.status-available {
|
||||
background-color: #d4edda;
|
||||
border-color: #28a745;
|
||||
}
|
||||
|
||||
/* 維護中(黃色) */
|
||||
.status-maintenance {
|
||||
background-color: #fff3cd;
|
||||
border-color: #ffc107;
|
||||
}
|
||||
|
||||
/* 已使用(灰色) */
|
||||
.status-used {
|
||||
background-color: #e2e3e5;
|
||||
border-color: #6c757d;
|
||||
}
|
||||
.grid-item {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-shadow: 1px 1px 3px rgba(0,0,0,0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.position-name {
|
||||
background-color: #f0f0f0;
|
||||
padding: 4px 8px;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.position-content {
|
||||
flex-grow: 1;
|
||||
padding: 3px;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
</asp:Content>
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using System.Web.UI.WebControls;
|
||||
|
||||
public partial class admin_ancestraltablet_ancestraltabletposition_index : MyWeb.config
|
||||
{
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
126
web/admin/ancestraltablet/ancestraltabletstatistics/index.aspx
Normal file
126
web/admin/ancestraltablet/ancestraltabletstatistics/index.aspx
Normal file
@@ -0,0 +1,126 @@
|
||||
<%@ Page Title="" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="index.aspx.cs" Inherits="admin_ancestraltablet_ancestraltabletstatistics_index" %>
|
||||
|
||||
<asp:Content ID="Content1" ContentPlaceHolderID="page_header" Runat="Server">
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content2" ContentPlaceHolderID="page_nav" Runat="Server">
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
|
||||
<div class="container">
|
||||
<h2 class="title">區域牌位統計</h2>
|
||||
<table class="stats-table" border="1" cellspacing="0" cellpadding="5">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>區域編號</th>
|
||||
<th>區域名稱</th>
|
||||
<th>總位置數</th>
|
||||
<th>可用位置數</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="area in areas" :key="area.areaId">
|
||||
<td>{{ area.areaId }}</td>
|
||||
<td>{{ area.areaName }}</td>
|
||||
<td>{{ area.totalPositions }}</td>
|
||||
<td>{{ area.availableCount }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server">
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" Runat="Server">
|
||||
<script>
|
||||
new Vue({
|
||||
el: '#app',
|
||||
vuetify: new Vuetify(vuetify_options),
|
||||
data() {
|
||||
return {
|
||||
areas: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getAncestralTabletPositionsStatisticsMethod() {
|
||||
axios.get(HTTP_HOST + 'api/ancestraltablet/statistics/positions/availablepositions')
|
||||
.then((res) => {
|
||||
this.areas = res.data
|
||||
})
|
||||
.catch((error) => {
|
||||
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getAncestralTabletPositionsStatisticsMethod()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style>
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 50px auto;
|
||||
background: #ffffff;
|
||||
padding: 25px 30px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
||||
font-family: "Microsoft YaHei", sans-serif;
|
||||
}
|
||||
|
||||
.title {
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 25px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.stats-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 15px;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.stats-table th {
|
||||
background-color: #1976d2;
|
||||
color: #fff;
|
||||
padding: 12px;
|
||||
font-weight: 600;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.stats-table td {
|
||||
padding: 10px;
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
/* 奇偶行區分 */
|
||||
.stats-table tbody tr:nth-child(odd) {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
/* 滑鼠懸停高亮 */
|
||||
.stats-table tbody tr:hover {
|
||||
background-color: #e3f2fd;
|
||||
transition: 0.3s ease;
|
||||
}
|
||||
|
||||
/* 響應式支持 */
|
||||
@media (max-width: 600px) {
|
||||
.container {
|
||||
padding: 15px;
|
||||
}
|
||||
.title {
|
||||
font-size: 18px;
|
||||
}
|
||||
.stats-table th, .stats-table td {
|
||||
padding: 8px;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
</asp:Content>
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using System.Web.UI.WebControls;
|
||||
|
||||
public partial class admin_ancestraltablet_ancestraltabletstatistics_index : MyWeb.config
|
||||
{
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
15
web/admin/ancestraltablet/ancestraltabletuselist/create.aspx
Normal file
15
web/admin/ancestraltablet/ancestraltabletuselist/create.aspx
Normal file
@@ -0,0 +1,15 @@
|
||||
<%@ Page Title="" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="create.aspx.cs" Inherits="admin_ancestraltablet_ancestraltabletuselist_create" %>
|
||||
|
||||
<asp:Content ID="Content1" ContentPlaceHolderID="page_header" Runat="Server">
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content2" ContentPlaceHolderID="page_nav" Runat="Server">
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
|
||||
<div>
|
||||
這是新增頁面
|
||||
</div>
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server">
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" Runat="Server">
|
||||
</asp:Content>
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using System.Web.UI.WebControls;
|
||||
|
||||
public partial class admin_ancestraltablet_ancestraltabletuselist_create : MyWeb.config
|
||||
{
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
99
web/admin/ancestraltablet/ancestraltabletuselist/detail.aspx
Normal file
99
web/admin/ancestraltablet/ancestraltabletuselist/detail.aspx
Normal file
@@ -0,0 +1,99 @@
|
||||
<%@ Page Title="" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="detail.aspx.cs" Inherits="admin_ancestraltablet_ancestraltabletuselist_detail" %>
|
||||
|
||||
<asp:Content ID="Content1" ContentPlaceHolderID="page_header" Runat="Server">
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content2" ContentPlaceHolderID="page_nav" Runat="Server">
|
||||
<nav>
|
||||
<a :href="'edit.aspx?registrantCode=' + registrantCode" class="btn btn-primary">修改資料</a>
|
||||
</nav>
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
|
||||
<div>
|
||||
{{registrantCode}}
|
||||
</div>
|
||||
<div>
|
||||
<div class="card">
|
||||
<h2>登記人資訊</h2>
|
||||
<p><strong>登記編碼:</strong> {{ registrant.registrantCode }}</p>
|
||||
<p><strong>姓名:</strong> {{ registrant.name }}</p>
|
||||
<p><strong>電話:</strong> {{ registrant.phone }}</p>
|
||||
<p><strong>地址:</strong> {{ registrant.address }}</p>
|
||||
<p><strong>登記日期:</strong> {{ formatDate(registrant.registerDate) }}</p>
|
||||
<div style="border: 1px solid #007bff; background-color: #f0f8ff; padding: 10px 15px; border-radius: 5px; display: flex; flex-direction: column; gap: 5px; max-width: 400px; margin-bottom: 10px;">
|
||||
<div>
|
||||
<label style="font-weight: bold; margin-right: 5px;">已選擇位置:</label>
|
||||
<span>{{ registrant?.positionName || '未選擇' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<p><strong>價格:</strong> {{ registrant.price }}</p>
|
||||
<p><strong>開始日期:</strong> {{ formatDate(registrant.startDate) }}</p>
|
||||
<p><strong>結束日期:</strong> {{ formatDate(registrant.endDate) }}</p>
|
||||
<p><strong>是否長期:</strong> {{ registrant.isLongTerm ? '是' : '否' }}</p>
|
||||
<p><strong>是否啟用:</strong> {{ registrant.isActive ? '是' : '否' }}</p>
|
||||
</div>
|
||||
|
||||
<div class="card" v-if="registrant.tabletRecord">
|
||||
<h2>牌位資料</h2>
|
||||
<p><strong>記錄ID:</strong> {{ registrant.tabletRecord.recordId }}</p>
|
||||
<p><strong>登記編碼:</strong> {{ registrant.tabletRecord.registrantCode }}</p>
|
||||
|
||||
<p><strong>牌位標題:</strong> {{ registrant.tabletRecord.npTitle }}</p>
|
||||
<p><strong>立牌日期:</strong> {{ formatDate(registrant.tabletRecord.npStandDate) }}</p>
|
||||
<p><strong>陽上:</strong> {{ registrant.tabletRecord.npYangShang }}</p>
|
||||
<p><strong>內牌內容:</strong> {{ registrant.tabletRecord.wpContent }}</p>
|
||||
</div>
|
||||
|
||||
<div class="card" v-else>
|
||||
<h2>牌位資料</h2>
|
||||
<p>暫無牌位資料</p>
|
||||
</div>
|
||||
</div>
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server">
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" Runat="Server">
|
||||
<script>
|
||||
new Vue({
|
||||
el: '#app',
|
||||
vuetify: new Vuetify(vuetify_options),
|
||||
data() {
|
||||
return {
|
||||
registrantCode: '<%=Request.QueryString["registrantCode"]%>',
|
||||
registrant: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatDate(dateStr) {
|
||||
if (!dateStr) return "";
|
||||
const date = new Date(dateStr);
|
||||
return date.toLocaleDateString();
|
||||
},
|
||||
getRegistrantByCodeMethod(code) {
|
||||
axios.get(HTTP_HOST + 'api/ancestraltablet/registrant/getbycode', {
|
||||
params: {
|
||||
registrantCode: code
|
||||
}
|
||||
})
|
||||
.then((res => {
|
||||
this.registrant = res.data
|
||||
}))
|
||||
.catch((error => {
|
||||
|
||||
}))
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getRegistrantByCodeMethod(this.registrantCode);
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style>
|
||||
.card {
|
||||
border: 1px solid #ccc;
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 5px;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
</style>
|
||||
</asp:Content>
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using System.Web.UI.WebControls;
|
||||
|
||||
public partial class admin_ancestraltablet_ancestraltabletuselist_detail : MyWeb.config
|
||||
{
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
419
web/admin/ancestraltablet/ancestraltabletuselist/edit.aspx
Normal file
419
web/admin/ancestraltablet/ancestraltabletuselist/edit.aspx
Normal file
@@ -0,0 +1,419 @@
|
||||
<%@ Page Title="" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="edit.aspx.cs" Inherits="admin_ancestraltablet_ancestraltabletuselist_edit" %>
|
||||
|
||||
<asp:Content ID="Content1" ContentPlaceHolderID="page_header" Runat="Server">
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content2" ContentPlaceHolderID="page_nav" Runat="Server">
|
||||
<nav>
|
||||
<a :href="'detail.aspx?registrantCode=' + registrantCode" class="btn btn-secondary">返回詳情</a>
|
||||
</nav>
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
|
||||
<div>
|
||||
<!-- 登記人資料編輯區域 -->
|
||||
<div class="card">
|
||||
<h2>編輯登記人資訊</h2>
|
||||
<label>登記編碼:</label>
|
||||
<input type="text" v-model="registrant.registrantCode" class="form-control" disabled />
|
||||
|
||||
<label>姓名:</label>
|
||||
<input type="text" v-model="registrant.name" class="form-control" />
|
||||
|
||||
<label>電話:</label>
|
||||
<input type="text" v-model="registrant.phone" class="form-control" />
|
||||
|
||||
<label>地址:</label>
|
||||
<input type="text" v-model="registrant.address" class="form-control" />
|
||||
|
||||
<label>登記日期:</label>
|
||||
<input type="date" v-model="registrant.registerDate" class="form-control" />
|
||||
<div class="mt-4" style="border: 1px solid #007bff; background-color: #f0f8ff; padding: 10px 15px; border-radius: 5px; display: flex; flex-direction: column; gap: 5px; max-width: 400px; margin-bottom: 10px;">
|
||||
<div>
|
||||
<label style="font-weight: bold; margin-right: 5px;">已選擇位置:</label>
|
||||
<span>{{ registrant?.positionName || '未選擇' }}</span>
|
||||
</div>
|
||||
<div v-if="newPositionId">
|
||||
<label style="font-weight: bold; margin-right: 5px;">新選擇位置:</label>
|
||||
<span>{{ this.newPositionEntity?.positionName }}</span>
|
||||
</div>
|
||||
<button type="button" @click="isShowPositionDialog=true"
|
||||
style="align-self: flex-start; padding: 5px 10px; background-color: #007bff; color: #fff; border: none; border-radius: 3px; cursor: pointer;"
|
||||
>
|
||||
{{registrant?.positionId ? '更換位置' : '選擇位置'}}
|
||||
</button>
|
||||
</div>
|
||||
<label>價格:</label>
|
||||
<input type="number" v-model="registrant.price" class="form-control" />
|
||||
|
||||
<label>開始日期:</label>
|
||||
<input type="date" v-model="registrant.startDate" class="form-control" />
|
||||
|
||||
<label>結束日期:</label>
|
||||
<input type="date" v-model="registrant.endDate" class="form-control" />
|
||||
|
||||
<div class="mt-3" style="display:flex; align-items:center; gap:15px; margin-bottom:10px; font-family:Arial, sans-serif;">
|
||||
<label style="font-weight:500;">是否長期:</label>
|
||||
<input type="checkbox" v-model="registrant.isLongTerm" style="width:16px; height:16px; cursor:pointer;" />
|
||||
<span>是</span>
|
||||
</div>
|
||||
|
||||
<div style="display:flex; align-items:center; gap:15px; margin-bottom:10px; font-family:Arial, sans-serif;">
|
||||
<label style="font-weight:500;">是否啟用:</label>
|
||||
<input type="checkbox" v-model="registrant.isActive" style="width:16px; height:16px; cursor:pointer;" />
|
||||
<span>是</span>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-primary mt-2" @click="updateRegistrant">保存登記資料</button>
|
||||
</div>
|
||||
|
||||
<!-- 牌位資料區域 -->
|
||||
<div class="card" v-if="registrant.tabletRecord">
|
||||
<h2>編輯牌位資料</h2>
|
||||
<label>記錄ID:</label>
|
||||
<input type="text" v-model="registrant.tabletRecord.recordId" class="form-control" disabled />
|
||||
|
||||
<label>登記編碼 (外鍵):</label>
|
||||
<input type="text" v-model="registrant.tabletRecord.registrantCode" class="form-control" disabled />
|
||||
|
||||
|
||||
<label>牌位標題:</label>
|
||||
<input type="text" v-model="registrant.tabletRecord.npTitle" class="form-control" />
|
||||
|
||||
<label>立牌日期:</label>
|
||||
<input type="date" v-model="registrant.tabletRecord.npStandDate" class="form-control" />
|
||||
|
||||
<label>陽上:</label>
|
||||
<input type="text" v-model="registrant.tabletRecord.npYangShang" class="form-control" />
|
||||
|
||||
<label>內牌內容:</label>
|
||||
<textarea v-model="registrant.tabletRecord.wpContent" class="form-control"></textarea>
|
||||
|
||||
<button type="button" class="btn btn-success mt-2" @click="updateTabletRecord">保存牌位資料</button>
|
||||
</div>
|
||||
|
||||
<div class="card" v-else>
|
||||
<h2>牌位資料</h2>
|
||||
<p>暫無牌位資料</p>
|
||||
<button type="button" class="btn btn-primary" @click="createTabletRecordForm">新增牌位資料</button>
|
||||
|
||||
<div v-if="creatingTablet" class="mt-3">
|
||||
<label>牌位標題:</label>
|
||||
<input type="text" v-model="newTablet.npTitle" class="form-control" />
|
||||
|
||||
<label>立牌日期:</label>
|
||||
<input type="date" v-model="newTablet.npStandDate" class="form-control" />
|
||||
|
||||
<label>陽上:</label>
|
||||
<input type="text" v-model="newTablet.npYangShang" class="form-control" />
|
||||
|
||||
<label>牌位內容:</label>
|
||||
<textarea v-model="newTablet.wpContent" class="form-control"></textarea>
|
||||
|
||||
<button type="button" class="btn btn-success mt-2" @click="createTabletRecord">保存新增</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<v-dialog v-model="isShowPositionDialog" persistent
|
||||
width="80%"
|
||||
height="80%">
|
||||
<v-card style="
|
||||
width: 80vw;
|
||||
height: 80vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
">
|
||||
<v-card-title
|
||||
style="display: flex; align-items: center; font-weight: 600; font-size: 18px;"
|
||||
>
|
||||
<span>選擇位置:</span>
|
||||
|
||||
<select
|
||||
class="form-control"
|
||||
style="
|
||||
flex: 0 0 200px;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
transition: border-color 0.2s;
|
||||
"
|
||||
v-model="selectedArea"
|
||||
@focus="e => e.target.style.borderColor = '#007bff'"
|
||||
@blur="e => e.target.style.borderColor = '#ccc'"
|
||||
@change="onAreaChange"
|
||||
>
|
||||
<option value="">請選擇區域</option>
|
||||
<option v-for="area in areaList" :value="area.areaId" :key="area.areaId">{{area.areaName}}</option>
|
||||
</select>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text style="flex: 1; overflow: auto;">
|
||||
<div class="grid-container">
|
||||
<div
|
||||
v-for="pos in positionList"
|
||||
:key="pos.positionId"
|
||||
class="grid-item"
|
||||
:class="'status-' + (pos.isCanUse? 'canuse':'cannotuse')"
|
||||
:style="{ gridRow: pos.rowNo, gridColumn: pos.columnNo }"
|
||||
>
|
||||
<div class="position-name">{{ pos.positionName }}</div>
|
||||
<div class="position-content">
|
||||
<button type="button" v-if="pos.isCanUse"
|
||||
class="btn btn-primary"
|
||||
@click="chooseNewPositionMethod(pos)"
|
||||
>選擇</button>
|
||||
<span v-else>已被使用</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<div class="me-5">新位置:{{newPositionEntity?.positionName}}</div>
|
||||
<v-btn color="primary" @click="saveChoosePositionMethod">確定</v-btn>
|
||||
<v-btn color="grey" @click="cancelChoosePositionMethod">取消</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server">
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" Runat="Server">
|
||||
<script>
|
||||
new Vue({
|
||||
el: '#app',
|
||||
vuetify: new Vuetify(vuetify_options),
|
||||
data() {
|
||||
return {
|
||||
registrantCode: '<%=Request.QueryString["registrantCode"]%>',
|
||||
registrant: {},
|
||||
creatingTablet: false,
|
||||
newPositionId: null,
|
||||
newPositionEntity: null,
|
||||
newTablet: {
|
||||
//新增牌位登記form
|
||||
recordId: null, // 自增主鍵,前端一般不用填
|
||||
registrantCode: null, // 外鍵,關聯登記人編號
|
||||
npTitle: null,
|
||||
npStandDate: null,
|
||||
npYangShang: null,
|
||||
wpContent: null,
|
||||
},
|
||||
positionList: [],//選擇神位位置的時候獲取的位置列表
|
||||
isShowPositionDialog: false,
|
||||
selectedArea: "",
|
||||
areaList: [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatDate(dateStr) {
|
||||
if (!dateStr) return "";
|
||||
return dateStr.split('T')[0];
|
||||
},
|
||||
getRegistrantByCodeMethod(code) {
|
||||
axios.get(HTTP_HOST + 'api/ancestraltablet/registrant/getbycode', {
|
||||
params: {
|
||||
registrantCode: code
|
||||
}
|
||||
})
|
||||
.then((res => {
|
||||
const data = res.data;
|
||||
|
||||
// 格式化登記日期欄位
|
||||
if (data.registerDate) data.registerDate = this.formatDate(data.registerDate);
|
||||
if (data.startDate) data.startDate = this.formatDate(data.startDate);
|
||||
if (data.endDate) data.endDate = this.formatDate(data.endDate);
|
||||
|
||||
// 格式化牌位日期欄位
|
||||
if (data.tabletRecord && data.tabletRecord.npStandDate)
|
||||
data.tabletRecord.npStandDate = this.formatDate(data.tabletRecord.npStandDate);
|
||||
|
||||
this.registrant = data;
|
||||
}))
|
||||
.catch((error => {
|
||||
|
||||
}))
|
||||
},
|
||||
// 更新登記資料
|
||||
updateRegistrant() {
|
||||
const newPositionId = this.newPositionId; // 假設 newPositionId 存在組件裡
|
||||
|
||||
// 如果 newPositionId 不為空,則更新 registrant.PositionId
|
||||
if (newPositionId != null && newPositionId !== '') {
|
||||
this.registrant.PositionId = newPositionId;
|
||||
}
|
||||
axios.post(HTTP_HOST + 'api/ancestraltablet/registrant/update', this.registrant)
|
||||
.then(() => {
|
||||
alert('登記資料已保存!')
|
||||
this.getRegistrantByCodeMethod(this.registrantCode);
|
||||
this.newPositionId = null;
|
||||
}
|
||||
)
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
alert('保存失敗!');
|
||||
});
|
||||
},
|
||||
|
||||
// 更新牌位資料
|
||||
updateTabletRecord() {
|
||||
axios.post(HTTP_HOST + 'api/ancestraltablet/pw/update', this.registrant.tabletRecord)
|
||||
.then(() => alert('牌位資料已更新!'))
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
alert('保存失敗!');
|
||||
});
|
||||
},
|
||||
|
||||
// 顯示新增牌位表單
|
||||
createTabletRecordForm() {
|
||||
this.creatingTablet = true;
|
||||
},
|
||||
|
||||
// 新增牌位資料
|
||||
createTabletRecord() {
|
||||
const data = {
|
||||
...this.newTablet,
|
||||
registrantCode: this.registrant.registrantCode,
|
||||
};
|
||||
axios.post(HTTP_HOST + 'api/ancestraltablet/pw/create', data)
|
||||
.then(() => {
|
||||
alert('牌位資料已新增!');
|
||||
this.creatingTablet = false;
|
||||
this.getRegistrantByCodeMethod(this.registrantCode);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
alert('新增失敗!');
|
||||
});
|
||||
},
|
||||
getPositionList(areaId) {
|
||||
axios.get(HTTP_HOST + 'api/ancestraltablet/position/shortlist',
|
||||
{
|
||||
params: {
|
||||
areaId: areaId
|
||||
}
|
||||
})
|
||||
.then((res) => {
|
||||
this.positionList = res.data
|
||||
})
|
||||
.catch((error) => {
|
||||
|
||||
});
|
||||
},
|
||||
getArea() {
|
||||
axios.get(HTTP_HOST + 'api/ancestraltablet/area/getereawithposition')
|
||||
.then((res) => {
|
||||
this.areaList = res.data;
|
||||
})
|
||||
.catch();
|
||||
},
|
||||
onAreaChange() {
|
||||
//獲取有神位的區域
|
||||
if (!this.selectedArea) {
|
||||
this.positionList = [];
|
||||
return; // 如果沒有選擇,不請求
|
||||
}
|
||||
this.getPositionList(this.selectedArea)
|
||||
|
||||
},
|
||||
chooseNewPositionMethod(newPos) {
|
||||
this.newPositionEntity = newPos
|
||||
},
|
||||
closeChoosePositionDialogMethod() {
|
||||
this.isShowPositionDialog = false;
|
||||
this.selectedArea = "";
|
||||
this.positionList = [];
|
||||
},
|
||||
cancelChoosePositionMethod() {
|
||||
this.newPositionEntity = null;
|
||||
this.closeChoosePositionDialogMethod()
|
||||
},
|
||||
saveChoosePositionMethod() {
|
||||
this.newPositionId = this.newPositionEntity.positionId
|
||||
this.closeChoosePositionDialogMethod()
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getRegistrantByCodeMethod(this.registrantCode);
|
||||
this.getArea()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style>
|
||||
.card {
|
||||
border: 1px solid #ccc;
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 5px;
|
||||
background-color: #fafafa;
|
||||
width: 90%;
|
||||
max-width: 900px;
|
||||
min-width: 300px; /* 最小寬度防止太窄 */
|
||||
margin: 0 auto; /* 居中 */
|
||||
}
|
||||
.grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(10, 150px); /* 6列 */
|
||||
grid-auto-rows: 150px; /* 行高 */
|
||||
gap: 10px;
|
||||
}
|
||||
.status-available {
|
||||
background-color: #d4edda;
|
||||
border-color: #28a745;
|
||||
}
|
||||
|
||||
/* 維護中(黃色) */
|
||||
.status-maintenance {
|
||||
background-color: #fff3cd;
|
||||
border-color: #ffc107;
|
||||
}
|
||||
|
||||
/* 已使用(灰色) */
|
||||
.status-used {
|
||||
background-color: #e2e3e5;
|
||||
border-color: #6c757d;
|
||||
}
|
||||
/* 可以使用(綠色) */
|
||||
.status-canuse {
|
||||
background-color: #d4edda; /* 淺綠色背景 */
|
||||
border-color: #28a745; /* 綠色邊框 */
|
||||
color: #155724; /* 深綠色文字 */
|
||||
}
|
||||
|
||||
/* 不能使用(紅色) */
|
||||
.status-cannotuse {
|
||||
background-color: #f8d7da; /* 淺紅色背景 */
|
||||
border-color: #dc3545; /* 紅色邊框 */
|
||||
color: #721c24; /* 深紅文字 */
|
||||
}
|
||||
.grid-item {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-shadow: 1px 1px 3px rgba(0,0,0,0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.position-name {
|
||||
background-color: #f0f0f0;
|
||||
padding: 4px 8px;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.position-content {
|
||||
flex-grow: 1;
|
||||
padding: 3px;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
</asp:Content>
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using System.Web.UI.WebControls;
|
||||
|
||||
public partial class admin_ancestraltablet_ancestraltabletuselist_edit : MyWeb.config
|
||||
{
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
192
web/admin/ancestraltablet/ancestraltabletuselist/index.aspx
Normal file
192
web/admin/ancestraltablet/ancestraltabletuselist/index.aspx
Normal file
@@ -0,0 +1,192 @@
|
||||
<%@ Page Title="" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="index.aspx.cs" Inherits="admin_ancestraltablet_ancestraltabletuselist_index" %>
|
||||
|
||||
<asp:Content ID="Content1" ContentPlaceHolderID="page_header" Runat="Server">
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content2" ContentPlaceHolderID="page_nav" Runat="Server">
|
||||
<nav>
|
||||
<!--
|
||||
<a :href="'create.aspx'" class="btn btn-primary">
|
||||
新增使用申請
|
||||
</a>
|
||||
-->
|
||||
<div style="display: inline">
|
||||
<span>
|
||||
查詢條件 :
|
||||
</span>
|
||||
<input v-model="search.registrantUserName" class="form-control" style="display:inline-block; width: auto;"
|
||||
placeholder="請輸入登記人"
|
||||
/>
|
||||
<button type="button" class="btn btn-primary" @click="handleSearch">搜尋</button>
|
||||
<button type="button" class="btn btn-primary" @click="clearSearch">清除條件</button>
|
||||
</div>
|
||||
</nav>
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
|
||||
神主牌使用記錄
|
||||
<div>
|
||||
<v-data-table
|
||||
:items="registrantList"
|
||||
:headers="headers"
|
||||
hide-default-footer>
|
||||
<template #item.registerdate="{item}">
|
||||
{{item.registerDate |timeString('YYYY-MM-DD')}}
|
||||
</template>
|
||||
<template #item.startdate="{item}">
|
||||
{{item.startDate |timeString('YYYY-MM-DD')}}
|
||||
</template>
|
||||
<template #item.enddate="{item}">
|
||||
{{item.endDate |timeString('YYYY-MM-DD')}}
|
||||
</template>
|
||||
<template #item.createdat="{item}">
|
||||
{{item.createdAt |timeString('YYYY-MM-DD HH:MM')}}
|
||||
</template>
|
||||
<template #item.islongterm="{item}">
|
||||
{{item.isLongTerm ? "是": "否"}}
|
||||
</template>
|
||||
<template #item.isactive="{item}">
|
||||
{{item.isActive ? "是" : "否"}}
|
||||
</template>
|
||||
<template #item.actions="{item}">
|
||||
<a :href="'detail.aspx?registrantCode=' + item.registrantCode" class="btn btn-primary">詳細資訊</a>
|
||||
</template>
|
||||
</v-data-table>
|
||||
<v-container>
|
||||
<v-row class="align-baseline" wrap="false">
|
||||
<v-col cols="12" md="8">
|
||||
<v-pagination
|
||||
v-model="options.page"
|
||||
:length="pageCount">
|
||||
</v-pagination>
|
||||
</v-col>
|
||||
<v-col class="text-truncate text-right" cols="12" md="2">
|
||||
共 {{ total }} 筆, 頁數:
|
||||
</v-col>
|
||||
<v-col cols="6" md="1">
|
||||
<v-text-field
|
||||
v-model="options.page"
|
||||
type="number"
|
||||
hide-details
|
||||
dense
|
||||
min="1"
|
||||
:max="pageCount"
|
||||
@input="options.page = parseInt($event, 10)"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<!-- 每頁條數選擇 -->
|
||||
<v-col cols="12" md="1">
|
||||
<v-select
|
||||
v-model="options.itemsPerPage"
|
||||
:items="[5, 10, 20, 50]"
|
||||
label="每頁條數"
|
||||
dense
|
||||
hide-details
|
||||
style="width: 100px;"
|
||||
></v-select>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</div>
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server">
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" Runat="Server">
|
||||
<script>
|
||||
Vue.filter('timeString', function (value, myFormat) {
|
||||
return value == null || value == "" ? "" : moment(value).format(myFormat || 'YYYY-MM-DD, HH:mm:ss');
|
||||
});
|
||||
new Vue({
|
||||
el: "#app",
|
||||
vuetify: new Vuetify(vuetify_options),
|
||||
data() {
|
||||
return {
|
||||
registrantList: [],
|
||||
headers: [
|
||||
{ text: '登記編號', value: 'registrantCode' },
|
||||
{ text: '姓名', value: 'name' },
|
||||
{ text: '電話', value: 'phone' },
|
||||
{ text: '住址', value: 'address' },
|
||||
{ text: '登記日期', value: 'registerdate' },
|
||||
{ text: '費用', value: 'price' },
|
||||
{ text: '牌位編號', value: 'positionId' },
|
||||
{ text: '開始時間', value: 'startdate' },
|
||||
{ text: '結束時間', value: 'enddate' },
|
||||
{ text: '是否長期', value: 'islongterm' },
|
||||
{ text: '是否有效', value: 'isactive' },
|
||||
{ text: '創建時間', value: 'createdat' },
|
||||
{ text: '', value: 'actions' },
|
||||
],
|
||||
options: {
|
||||
page: 1, // 當前頁
|
||||
itemsPerPage: 10, // 每頁條數
|
||||
sortBy: [],
|
||||
sortDesc: []
|
||||
},
|
||||
search: {
|
||||
registrantUserName: null,
|
||||
},
|
||||
total: 0,
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getRegistrantListMethod() {
|
||||
axios.get(HTTP_HOST + 'api/ancestraltablet/registrant/getlist')
|
||||
.then((res) => {
|
||||
this.registrantList = res.data;
|
||||
}).catch((error) => {
|
||||
alert("載入失敗")
|
||||
})
|
||||
},
|
||||
getRegistrantListByPageMethod() {
|
||||
if (this.loading) return;
|
||||
this.loading = true;
|
||||
axios.post(HTTP_HOST + 'api/ancestraltablet/registrant/getlistbypage', {
|
||||
page: this.options.page,
|
||||
pageSize: this.options.itemsPerPage,
|
||||
searchName: this.search.registrantUserName
|
||||
})
|
||||
.then((res) => {
|
||||
this.registrantList = res.data.data;
|
||||
this.total = res.data.total;
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
resetTableOptions() {
|
||||
this.options = {
|
||||
page: 1,
|
||||
itemsPerPage: 10,
|
||||
sortBy: [],
|
||||
sortDesc: []
|
||||
};
|
||||
},
|
||||
clearSearch() {
|
||||
this.search.registrantUserName = null;
|
||||
this.resetTableOptions();
|
||||
},
|
||||
handleSearch() {
|
||||
this.resetTableOptions();
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
options: {
|
||||
handler() {
|
||||
this.getRegistrantListByPageMethod();
|
||||
},
|
||||
deep: true,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getRegistrantListByPageMethod()
|
||||
},
|
||||
computed: {
|
||||
pageCount() {
|
||||
return Math.ceil(this.total / this.options.itemsPerPage)
|
||||
},
|
||||
}
|
||||
|
||||
})
|
||||
</script>
|
||||
</asp:Content>
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using System.Web.UI.WebControls;
|
||||
|
||||
public partial class admin_ancestraltablet_ancestraltabletuselist_index : MyWeb.config
|
||||
{
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1084,7 +1084,7 @@
|
||||
newCheckoutDate: this.guadanguest.xuzhu.newCheckoutDate
|
||||
};
|
||||
|
||||
axios.post('/api/guadanorderguest/xuzhu', payload)
|
||||
axios.post(HTTP_HOST + 'api/guadanorderguest/xuzhu', payload)
|
||||
.then((res) => {
|
||||
this.$refs.messageModal.open({
|
||||
title: '续住成功',
|
||||
@@ -1113,13 +1113,13 @@
|
||||
},
|
||||
//续住相關方法--------------------end
|
||||
getActivityList() {
|
||||
axios.post('/api/activity/GetList?page=1&pageSize=500', { kind: 0, subject: "" })
|
||||
axios.post(HTTP_HOST + 'api/activity/GetList?page=1&pageSize=500', { kind: 0, subject: "" })
|
||||
.then((res) => {
|
||||
this.activityList = res.data.list
|
||||
})
|
||||
},
|
||||
getavailablebedcountbytime(startTime, endTime) {
|
||||
axios.get('/api/region/bed/getavailablebedcountbytime', {
|
||||
axios.get(HTTP_HOST + 'api/region/bed/getavailablebedcountbytime', {
|
||||
params: {
|
||||
startTime: startTime,
|
||||
endTime: endTime
|
||||
@@ -1141,7 +1141,7 @@
|
||||
},
|
||||
confirmAllocation() {
|
||||
//確認分配
|
||||
axios.post('/api/region/bed/confirmallocation', {
|
||||
axios.post(HTTP_HOST + 'api/region/bed/confirmallocation', {
|
||||
preBeds: this.automaticBedAllocation.preBeds,
|
||||
orderNo: this.guadanorder.order_form.orderNo,
|
||||
checkInAt: this.guadanorder.order_form.startdate,
|
||||
@@ -1169,7 +1169,7 @@
|
||||
CheckInAt: this.guadanorder.order_form.startdate || new Date(), // 入住時間
|
||||
CheckOutAt: this.guadanorder.order_form.enddate || null // 退房時間,可為空
|
||||
};
|
||||
axios.post('/api/region/bed/preallocation', payload)
|
||||
axios.post(HTTP_HOST + 'api/region/bed/preallocation', payload)
|
||||
.then(res => {
|
||||
this.automaticBedAllocation.preBeds = res.data.data;
|
||||
})
|
||||
@@ -1217,7 +1217,7 @@
|
||||
getMultiSelectFollowers: function () {
|
||||
var fm = this.automaticBedAllocation.followerModal;
|
||||
var self = this;
|
||||
axios.post('/api/lianyou/getfollowers', null, {
|
||||
axios.post(HTTP_HOST + 'api/lianyou/getfollowers', null, {
|
||||
params: {
|
||||
page: fm.page,
|
||||
pageSize: fm.pageSize,
|
||||
@@ -1288,7 +1288,7 @@
|
||||
},
|
||||
getGuadanOrderById() {
|
||||
if (this.guadanorder.order_form.uuid) {
|
||||
axios.get('/api/guadan/getorderbyid', {
|
||||
axios.get(HTTP_HOST + 'api/guadan/getorderbyid', {
|
||||
params: {
|
||||
orderId: this.guadanorder.order_form.uuid
|
||||
}
|
||||
@@ -1307,7 +1307,7 @@
|
||||
},
|
||||
getGuadanOrderGuestByOrderNo() {
|
||||
if (this.guadanorder.order_form.orderNo) {
|
||||
axios.get('/api/guadanorderguest/getbyorderno', {
|
||||
axios.get(HTTP_HOST + 'api/guadanorderguest/getbyorderno', {
|
||||
params: {
|
||||
orderNo: this.guadanorder.order_form.orderNo
|
||||
}
|
||||
@@ -1317,7 +1317,7 @@
|
||||
}
|
||||
},
|
||||
getGuadanOrderStatus() {
|
||||
axios.get('/api/region/guadan/status/list')
|
||||
axios.get(HTTP_HOST + 'api/region/guadan/status/list')
|
||||
.then((res) => {
|
||||
this.guadanorder.status_items = res.data;
|
||||
})
|
||||
@@ -1326,7 +1326,7 @@
|
||||
if (!this.validateOrderForm()) {
|
||||
return;
|
||||
}
|
||||
axios.post('/api/guadan/create', this.guadanorder.order_form)
|
||||
axios.post(HTTP_HOST + 'api/guadan/create', this.guadanorder.order_form)
|
||||
.then((res => {
|
||||
this.$refs.messageModal.open({
|
||||
title: '掛單提示',
|
||||
@@ -1350,7 +1350,7 @@
|
||||
if (!this.validateOrderForm()) {
|
||||
return;
|
||||
}
|
||||
axios.post('/api/guadan/update', this.guadanorder.order_form)
|
||||
axios.post(HTTP_HOST + 'api/guadan/update', this.guadanorder.order_form)
|
||||
.then((res => {
|
||||
this.$refs.messageModal.open({
|
||||
title: '掛單提示',
|
||||
@@ -1495,13 +1495,13 @@
|
||||
|
||||
},
|
||||
createCheckInGuest() {
|
||||
return axios.post('/api/guadanorderguest/create', this.checkInGuest.inGuest)
|
||||
return axios.post(HTTP_HOST + 'api/guadanorderguest/create', this.checkInGuest.inGuest)
|
||||
},
|
||||
checkBedAndFollower() {
|
||||
this.checkInGuest.inGuest
|
||||
},
|
||||
getGuadanGuestStatus() {
|
||||
axios.get('/api/region/bed/status/list')
|
||||
axios.get(HTTP_HOST + 'api/region/bed/status/list')
|
||||
.then((res) => {
|
||||
this.checkInGuest.status = res.data.filter(item => item.category === 4 && item.code != '404');
|
||||
})
|
||||
@@ -1524,7 +1524,7 @@
|
||||
pageSize: itemsPerPage,
|
||||
searchName: this.selectGuestModal.searchNameOrPhone
|
||||
};
|
||||
axios.post('/api/lianyou/getfollowers', null, {
|
||||
axios.post(HTTP_HOST + 'api/lianyou/getfollowers', null, {
|
||||
params: params
|
||||
}).then((res) => {
|
||||
this.selectGuestModal.items = res.data.data
|
||||
@@ -1559,7 +1559,7 @@
|
||||
},
|
||||
async saveEditGuadanOrderGuest() {
|
||||
try {
|
||||
const res = await axios.post('/api/guadanorderguest/update', this.checkInGuest.inGuest)
|
||||
const res = await axios.post(HTTP_HOST + 'api/guadanorderguest/update', this.checkInGuest.inGuest)
|
||||
this.getGuadanOrderGuestByOrderNo();
|
||||
this.closeCheckInModal();
|
||||
} catch (error) {
|
||||
@@ -1570,7 +1570,7 @@
|
||||
|
||||
},
|
||||
deleteGuadanOrderGuest(guest) {
|
||||
axios.post('/api/guadanorderguest/cancel?uuid=' + guest.uuid)
|
||||
axios.post(HTTP_HOST + 'api/guadanorderguest/cancel?uuid=' + guest.uuid)
|
||||
.then((res) => {
|
||||
this.guadanguest.items = this.guadanguest.items.filter(i => i.uuid != guest.uuid);
|
||||
}).catch((error) => {
|
||||
@@ -1628,7 +1628,7 @@
|
||||
|
||||
//床位選擇相關方法----------------start
|
||||
async loadRegions() {
|
||||
const res = await axios.post('/api/region/getRegionList');
|
||||
const res = await axios.post(HTTP_HOST + 'api/region/getRegionList');
|
||||
this.region_modal.regions = res.data;
|
||||
},
|
||||
async loadRegionsByGender() {
|
||||
@@ -1643,7 +1643,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
const res = await axios.post('/api/region/getRegionListByGender', {
|
||||
const res = await axios.post(HTTP_HOST + 'api/region/getRegionListByGender', {
|
||||
IsMale: isMale
|
||||
});
|
||||
|
||||
@@ -1660,7 +1660,7 @@
|
||||
this.region_modal.selectedType = 'room';
|
||||
this.region_modal.currentSelectBeds = room.beds;
|
||||
if (this.checkInGuest.inGuest.checkInAt && this.checkInGuest.inGuest.checkOutAt) {
|
||||
axios.get('/api/region/room/bed/list', {
|
||||
axios.get(HTTP_HOST + 'api/region/room/bed/list', {
|
||||
params: {
|
||||
roomUuid: room.uuid,
|
||||
StartTime: this.checkInGuest.inGuest.checkInAt,
|
||||
@@ -1678,7 +1678,7 @@
|
||||
},
|
||||
GetRegionRoomBedListByRoomId(roomUuid) {
|
||||
if (this.checkInGuest.inGuest.checkInAt && this.checkInGuest.inGuest.checkOutAt) {
|
||||
axios.get('/api/region/bed/list')
|
||||
axios.get(HTTP_HOST + 'api/region/bed/list')
|
||||
.then((res) => {
|
||||
|
||||
})
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
</v-pagination>
|
||||
</v-col>
|
||||
<v-col class="text-truncate text-right" cols="12" md="2">
|
||||
共 {{ }} 筆, 頁數:
|
||||
共 {{ total }} 筆, 頁數:
|
||||
</v-col>
|
||||
<v-col cols="6" md="1">
|
||||
<v-text-field
|
||||
@@ -162,6 +162,7 @@ button:hover {
|
||||
{ text: '入住日期', value: 'checkindate' },
|
||||
{ text: '退房日期', value: 'checkoutdate' },
|
||||
{ text: '房間號', value: 'roomName' },
|
||||
{ text: '狀態', value: 'statusName'},
|
||||
|
||||
],
|
||||
guests: [], // 表格數據
|
||||
@@ -197,7 +198,7 @@ button:hover {
|
||||
}
|
||||
if (this.loading) return;
|
||||
this.loading = true;
|
||||
axios.post('/api/guadan/guest/query/list',
|
||||
axios.post(HTTP_HOST + 'api/guadan/guest/query/list',
|
||||
{
|
||||
page: this.options.page,
|
||||
pageSize: this.options.itemsPerPage,
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
<a href="create.aspx" class="btn btn-primary" >新建掛單</a>
|
||||
</nav>
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<label class="mb-0">掛單單號</label>
|
||||
<input class="form-control w-auto" style="width:150px;" v-model="search.guaDanOrderNo" />
|
||||
<label class="mb-0">掛單登記人</label>
|
||||
<input class="form-control w-auto" style="width:150px;" v-model="search.guadanUser" />
|
||||
|
||||
@@ -28,10 +30,21 @@
|
||||
<v-data-table
|
||||
:items="items"
|
||||
:headers="headers"
|
||||
:item-class="item => item.is_timeout ? 'row-timeout' : ''"
|
||||
hide-default-footer>
|
||||
<template #item.actions="{item}">
|
||||
<a :href="'create.aspx?orderId='+item.guaDanOrderNo" class="btn btn-secondary">編輯</a>
|
||||
<a class="btn btn-outline-danger" @click="deleteGuadanOrder(item)">取消</a>
|
||||
<a :href="'view.aspx?orderId='+item.guaDanOrderNo" class="btn btn-primary">查看</a>
|
||||
<a :href="'create.aspx?orderId='+item.guaDanOrderNo" class="btn btn-secondary"
|
||||
:style="item.guadan_status?.code == 502 ? 'pointer-events: none; opacity: 0.5; cursor: not-allowed;' : ''">編輯</a>
|
||||
<a
|
||||
class="btn btn-outline-danger"
|
||||
href="#"
|
||||
:style="item.guest_count != 0 ? 'pointer-events: none; opacity: 0.5; cursor: not-allowed;' : ''"
|
||||
@click.prevent="item.guest_count != 0 ? null : deleteGuadanOrder(item)"
|
||||
>
|
||||
取消
|
||||
</a>
|
||||
|
||||
</template>
|
||||
<template #item.room="{item}">
|
||||
{{item.room.name}}
|
||||
@@ -39,8 +52,8 @@
|
||||
<template #item.bed="{item}">
|
||||
{{item.bed.name}}
|
||||
</template>
|
||||
<template #item.status="{item}">
|
||||
{{item.status}}
|
||||
<template #item.guadan_status="{item}">
|
||||
{{item.guadan_status?.name}}
|
||||
</template>
|
||||
<template #item.start_date="{item}">
|
||||
{{item.start_date | timeString('YYYY/MM/DD')}}
|
||||
@@ -54,6 +67,9 @@
|
||||
<template #item.activity="{item}">
|
||||
{{item.activity?.subject}}
|
||||
</template>
|
||||
<template #item.is_timeout="{item}">
|
||||
{{item.is_timeout ? '已超時': '否'}}
|
||||
</template>
|
||||
</v-data-table>
|
||||
<v-container>
|
||||
<v-row class="align-baseline" wrap="false">
|
||||
@@ -77,7 +93,7 @@
|
||||
@input="options.page = parseInt($event, 10)"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<!-- 每页条数选择 -->
|
||||
<!-- 每頁條數選擇 -->
|
||||
<v-col cols="12" md="1">
|
||||
<v-select
|
||||
v-model="options.itemsPerPage"
|
||||
@@ -89,7 +105,7 @@
|
||||
></v-select>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-container>
|
||||
</div>
|
||||
<!-- 更新修改確認彈出視窗 -->
|
||||
<message-modal ref="messageModal"></message-modal>
|
||||
@@ -97,7 +113,6 @@
|
||||
<confirm-modal ref="confirmModal"></confirm-modal>
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server">
|
||||
<div>test</div>
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" Runat="Server">
|
||||
<script>
|
||||
@@ -111,13 +126,15 @@
|
||||
return {
|
||||
items: [],
|
||||
headers: [
|
||||
{ text: '登记挂单莲友', value: 'bookerName' },
|
||||
{ text: '登記掛單蓮友', value: 'bookerName' },
|
||||
{ text: '掛單單號', value: 'guaDanOrderNo'},
|
||||
{ text: '起始日期', value: 'start_date', align: 'center' },
|
||||
{ text: '結束日期', value: 'end_date', align: 'center' },
|
||||
{ text: '掛單人數', value: 'guest_count' },
|
||||
{ text: '狀態', value: 'statusName', align: 'center' },
|
||||
{ text: '狀態', value: 'guadan_status', align: 'center' },
|
||||
{ text: '建立時間', value: 'created_at', align: 'center' },
|
||||
{ text: '關聯活動', value: 'activity', align: 'center' },
|
||||
{ text: '超時退房', value: 'is_timeout', align: 'center' },
|
||||
{ text: '操作', value: 'actions', align: 'center' }
|
||||
],
|
||||
options: {
|
||||
@@ -130,6 +147,7 @@
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
guadanUser: null,
|
||||
guaDanOrderNo: null,
|
||||
},
|
||||
total: 0,
|
||||
loading: false,
|
||||
@@ -146,6 +164,12 @@
|
||||
};
|
||||
},
|
||||
handleSearch() {
|
||||
|
||||
let orderNo = this.search.guaDanOrderNo;
|
||||
if (orderNo) {
|
||||
orderNo = orderNo.replace(/\s+/g, '');
|
||||
this.search.guaDanOrderNo = orderNo;
|
||||
}
|
||||
const val = this.search.guadanUser;
|
||||
|
||||
// 驗證是否包含空格
|
||||
@@ -169,14 +193,16 @@
|
||||
this.search.startDate = null;
|
||||
this.search.endDate = null;
|
||||
this.search.guadanUser = null;
|
||||
this.search.guaDanOrderNo = null;
|
||||
this.resetTableOptions();
|
||||
},
|
||||
getGuadanOrder() {
|
||||
if (this.loading) return;
|
||||
axios.post('/api/guadan/list', {
|
||||
axios.post(HTTP_HOST + 'api/guadan/list', {
|
||||
startDate: this.search.startDate,
|
||||
endDate: this.search.endDate,
|
||||
guadanUser: this.search.guadanUser,
|
||||
guaDanOrderNo: this.search.guaDanOrderNo,
|
||||
page: this.options.page,
|
||||
pageSize: this.options.itemsPerPage
|
||||
})
|
||||
@@ -193,7 +219,7 @@
|
||||
this.$refs.confirmModal.open({
|
||||
message: '確認取消掛單?',
|
||||
onConfirm: () => {
|
||||
axios.post('/api/guadan/cancel', null, {
|
||||
axios.post(HTTP_HOST + 'api/guadan/cancel', null, {
|
||||
params: {
|
||||
uuid: order.uuid
|
||||
}
|
||||
@@ -230,5 +256,10 @@
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</asp:Content>
|
||||
<style>
|
||||
.row-timeout {
|
||||
background-color: #ffdddd !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
</asp:Content>
|
||||
@@ -326,7 +326,7 @@
|
||||
saveAs(new Blob([wbout], { type: "application/octet-stream" }), "statistics.xlsx");
|
||||
},
|
||||
GetGuadanStatistics() {
|
||||
axios.get('/api/guadanStatistics/GetGuadanStatistics')
|
||||
axios.get(HTTP_HOST + 'api/guadanStatistics/GetGuadanStatistics')
|
||||
.then((res) => {
|
||||
this.guadanStatistics = res.data.guadanStatistics;
|
||||
})
|
||||
|
||||
539
web/admin/guadan/view.aspx
Normal file
539
web/admin/guadan/view.aspx
Normal file
@@ -0,0 +1,539 @@
|
||||
<%@ Page Title="" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="view.aspx.cs" Inherits="admin_guadan_view" %>
|
||||
|
||||
<asp:Content ID="Content1" ContentPlaceHolderID="page_header" Runat="Server">
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content2" ContentPlaceHolderID="page_nav" Runat="Server">
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
|
||||
<fieldset class="border rounded p-4 mb-5 shadow-sm bg-white">
|
||||
<legend class="w-auto px-3 font-weight-bold text-primary">掛單資訊</legend>
|
||||
<!-- 🟢 區塊一:掛單資訊 -->
|
||||
<div class="border rounded p-3 bg-white shadow-sm" style="pointer-events: none; user-select: none; background: #1c5bd9; padding: 5px;">
|
||||
<h6 class="text-secondary mb-3">📝掛單資訊</h6>
|
||||
<div class="form-group row mt-3">
|
||||
<label class="col-sm-2 col-form-label text-center">掛單單號(不可修改)</label>
|
||||
<div class="col-sm-4 text-left">
|
||||
<input class="form-control" v-model="guadanorder.order_form.orderNo" readonly />
|
||||
</div>
|
||||
<label class="col-sm-2 col-form-label text-center">關聯活動</label>
|
||||
<div class="col-sm-4">
|
||||
<select class="form-control" v-model="guadanorder.order_form.activityNum" >
|
||||
<option :value="null">未關聯</option>
|
||||
<option v-for="activity in activityList" :key="activity.num" :value="activity.num">
|
||||
{{activity.subject}}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row mt-3">
|
||||
<label class="col-sm-2 col-form-label text-center">
|
||||
預約開始日期
|
||||
</label>
|
||||
<div class="col-sm-4 text-left">
|
||||
<input class="form-control" type="date" v-model="guadanorder.order_form.startdate" />
|
||||
</div>
|
||||
<label class="col-sm-2 col-form-label text-center">
|
||||
預約結束日期
|
||||
</label>
|
||||
<div class="col-sm-4">
|
||||
<input class="form-control" type="date" v-model="guadanorder.order_form.enddate" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row mt-3">
|
||||
<label class="col-sm-2 col-form-label text-center">預定人姓名</label>
|
||||
<div class="col-sm-4">
|
||||
<input class="form-control" v-model="guadanorder.order_form.bookerName" />
|
||||
</div>
|
||||
<label class="col-sm-2 col-form-label text-center">預定人電話</label>
|
||||
<div class="col-sm-4">
|
||||
<input class="form-control" v-model="guadanorder.order_form.bookerPhone" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row mt-3">
|
||||
<label class="col-sm-2 col-form-label text-center">備註</label>
|
||||
<div class="col-sm-4">
|
||||
<textarea class="form-control" v-model="guadanorder.order_form.note"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
<fieldset class="border rounded p-4 mb-5 shadow-sm bg-white">
|
||||
<!-- 表格標題緊貼表格上方,居中 -->
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<!-- 中間標題(flex-grow撐開居中) -->
|
||||
<div class="flex-grow-1 text-center">
|
||||
<h5 class="text-primary fw-bold mb-0">
|
||||
<i class="bi bi-people-fill me-2"></i>掛單蓮友
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- v-data-table 表格 -->
|
||||
<v-data-table :headers="guadanguest.headers" :items="guadanguest.items" class="elevation-1 rounded" dense>
|
||||
<template #item.checkinat="{item}">
|
||||
{{item.checkinat |timeString('YYYY-MM-DD')}}
|
||||
</template>
|
||||
<template #item.checkoutat="{item}">
|
||||
{{item.checkoutat |timeString('YYYY-MM-DD')}}
|
||||
</template>
|
||||
<template v-slot:item.name="{item}">
|
||||
{{item.follower?.u_name}}
|
||||
</template>
|
||||
<template v-slot:item.sex="{item}">
|
||||
{{item.follower?.sex}}
|
||||
</template>
|
||||
</v-data-table>
|
||||
</fieldset>
|
||||
</asp:Content>
|
||||
|
||||
<asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server">
|
||||
</asp:Content>
|
||||
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" Runat="Server">
|
||||
<style>
|
||||
/* 調整 fieldset 風格 */
|
||||
fieldset {
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 0.5rem;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
legend {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
color: #0d6efd;
|
||||
width: auto;
|
||||
padding: 0 0.75rem;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 按鈕置右 */
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* 選擇床位相關 */
|
||||
.tree,
|
||||
.tree ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
.toggle-icon {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
width: 1rem;
|
||||
display: inline-block;
|
||||
color: #007bff;
|
||||
}
|
||||
|
||||
.region-item-label {
|
||||
cursor: pointer;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.region-item-label.selected {
|
||||
background-color: #eaf4ff;
|
||||
color: #0d6efd;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.selected-room {
|
||||
background-color: #cce5ff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 選擇床位相關 */
|
||||
</style>
|
||||
<script>
|
||||
Vue.component('region-item', {
|
||||
props: ['item', 'selectedId', 'selectedType', 'expandAll', 'collapseAll'],
|
||||
data() {
|
||||
return {
|
||||
expanded: false, // 預設全部收起
|
||||
selectedRoomId: null,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
expandAll(newVal) {
|
||||
if (newVal) {
|
||||
this.expanded = true;
|
||||
// 執行完後發事件通知父組件清除標誌
|
||||
this.$nextTick(() => this.$emit('clear-expand-all'));
|
||||
}
|
||||
},
|
||||
collapseAll(newVal) {
|
||||
if (newVal) {
|
||||
this.expanded = false;
|
||||
this.$nextTick(() => this.$emit('clear-collapse-all'));
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasChildren() {
|
||||
return this.item.children && this.item.children.length > 0;
|
||||
},
|
||||
icon() {
|
||||
// 無論有無子節點,皆可點擊展開/收起
|
||||
return this.expanded ? '▼' : '▶';
|
||||
},
|
||||
isSelected() {
|
||||
return this.selectedType === 'region' && this.item.uuid === this.selectedId;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggle() {
|
||||
this.expanded = !this.expanded;
|
||||
},
|
||||
select() {
|
||||
this.$emit('select-region', this.item);
|
||||
},
|
||||
selectRoom(room) {
|
||||
this.selectedRoomId = room.uuid;
|
||||
this.$emit('select-room', room); // 可以發事件給父組件
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div>
|
||||
<span class="toggle-icon" @click="toggle">{{ icon }}</span>
|
||||
<span @click="select"
|
||||
class="region-item-label"
|
||||
:class="{ 'selected': isSelected }">
|
||||
{{ item.rooms.length>0 ? (item.name + '(' + item.rooms.length + '房)'): item.name }}
|
||||
</span>
|
||||
|
||||
<!-- 子區域列表 -->
|
||||
<ul v-if="hasChildren && expanded">
|
||||
<li v-for="(child, index) in item.children" :key="child.id + '-' + index">
|
||||
<region-item
|
||||
:item="child"
|
||||
:selected-id="selectedId"
|
||||
:selected-type="selectedType"
|
||||
:expand-all="expandAll"
|
||||
:collapse-all="collapseAll"
|
||||
@select-region="$emit('select-region', $event)"
|
||||
@select-room="$emit('select-room', $event)"
|
||||
@clear-expand-all="$emit('clear-expand-all')"
|
||||
@clear-collapse-all="$emit('clear-collapse-all')"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- 客房列表:無論是否有子區域,只要展開就顯示 -->
|
||||
<ul v-if="item.rooms && item.rooms.length > 0 && expanded">
|
||||
<li v-for="room in item.rooms" :key="'room-' + room.uuid"
|
||||
@click="selectRoom(room)"
|
||||
:class="{ 'selected-room': selectedType === 'room' && selectedId === room.uuid }"
|
||||
style="cursor: pointer;">
|
||||
<span class="bed-label">
|
||||
🛏️ {{ room.name + ' (' + room.beds.length + '床) ' + (room.gender === true ? '(男客房)' : room.gender === false ? '(女客房)' : '') }}
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`
|
||||
});
|
||||
Vue.filter('timeString', function (value, myFormat) {
|
||||
return value == null || value == "" ? "" : moment(value).format(myFormat || 'YYYY-MM-DD, HH:mm:ss');
|
||||
});
|
||||
new Vue({
|
||||
el: '#app',
|
||||
vuetify: new Vuetify(vuetify_options),
|
||||
data() {
|
||||
return {
|
||||
activityList: [],
|
||||
availableBedCount: {
|
||||
male: 0,
|
||||
female: 0,
|
||||
},
|
||||
guadanorder: {
|
||||
order_form: {
|
||||
uuid: '<%= Request.QueryString["orderid"] %>' || null,
|
||||
startdate: null,
|
||||
enddate: null,
|
||||
note: null,
|
||||
orderNo: null,
|
||||
bookerName: null,
|
||||
bookerPhone: null,
|
||||
bookerFollowerNum: null,
|
||||
activityNum: null,
|
||||
},
|
||||
status_items: [],
|
||||
},
|
||||
guadanguest: {
|
||||
guest: {
|
||||
uuid: null, // int?
|
||||
fullName: '', // string
|
||||
gender: null, // int?
|
||||
phone: '', // string
|
||||
idNumber: '', // string
|
||||
birthday: null, // Date (建議用 date picker)
|
||||
email: '', // string
|
||||
address: '', // string
|
||||
emergencyContact: '', // string
|
||||
emergencyPhone: '', // string
|
||||
status: null, // int?
|
||||
notes: '' // string
|
||||
},
|
||||
headers: [{
|
||||
text: '姓名',
|
||||
value: 'name'
|
||||
},
|
||||
{
|
||||
text: '性別',
|
||||
value: 'sex'
|
||||
},
|
||||
{
|
||||
text: '掛單開始時間',
|
||||
value: 'checkinat'
|
||||
},
|
||||
{
|
||||
text: '掛單結束時間',
|
||||
value: 'checkoutat'
|
||||
},
|
||||
{
|
||||
text: '床位',
|
||||
value: 'bedName'
|
||||
},
|
||||
{
|
||||
text: '狀態',
|
||||
value: 'statusName'
|
||||
},
|
||||
{
|
||||
text: '備註',
|
||||
value: 'note'
|
||||
},
|
||||
{
|
||||
text: '',
|
||||
value: 'actions'
|
||||
},
|
||||
],
|
||||
items: [],
|
||||
showCreateGuestModal: false,
|
||||
xuzhu: {
|
||||
showXuzhuGuestModal: false,
|
||||
currentCheckoutDate: null,
|
||||
newCheckoutDate: null,
|
||||
guestUuid: null,
|
||||
guestBedUuid: null,
|
||||
}
|
||||
},
|
||||
checkInGuest: {
|
||||
showSelectGuadanOrderGuest: false,
|
||||
isEdit: false,
|
||||
|
||||
inGuest: {
|
||||
uuid: null,
|
||||
orderNo: null,
|
||||
followerNum: null,
|
||||
roomUuid: null,
|
||||
bedUuid: null,
|
||||
checkInAt: null,
|
||||
checkOutAt: null,
|
||||
statuscode: null,
|
||||
},
|
||||
status: [],
|
||||
},
|
||||
region_modal: {
|
||||
regions: [],
|
||||
currentSelectRegion: null,
|
||||
currentSelectRoom: null,
|
||||
currentSelectBeds: [],
|
||||
currentSelectBed: null,
|
||||
showSelectBedModal: false,
|
||||
selectedId: null, // 被選中項目ID
|
||||
selectedType: null, // 'region' 或 'room'
|
||||
expandAllFlag: false, // 控制全部展開
|
||||
collapseAllFlag: false, // 控制全部收起
|
||||
currentSelectBedText: null,
|
||||
},
|
||||
selectGuestModal: {
|
||||
showSelectGuestModal: false,
|
||||
currentSelectedGuest: null,
|
||||
fullNameText: null,
|
||||
|
||||
headers: [{
|
||||
text: '姓名',
|
||||
value: 'u_name'
|
||||
},
|
||||
{
|
||||
text: '電話',
|
||||
value: 'phone'
|
||||
},
|
||||
{
|
||||
text: '',
|
||||
value: 'actions'
|
||||
},
|
||||
],
|
||||
items: [],
|
||||
|
||||
options: { //v-data-table參數
|
||||
page: 1,
|
||||
itemsPerPage: 10,
|
||||
sortBy: [],
|
||||
sortDesc: [],
|
||||
multiSort: false,
|
||||
},
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
count: 0,
|
||||
footer: {
|
||||
showFirstLastPage: true,
|
||||
disableItemsPerPage: true,
|
||||
itemsPerPageAllText: '',
|
||||
itemsPerPageText: '',
|
||||
},
|
||||
searchNameOrPhone: null,
|
||||
},
|
||||
automaticBedAllocation: {
|
||||
showModal: false,
|
||||
|
||||
// 蓮友選擇彈出視窗
|
||||
followerModal: {
|
||||
showModal: false,
|
||||
followerList: [],
|
||||
selectedFollowerItems: [],
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
searchNameOrPhone: '',
|
||||
headers: [
|
||||
{ text: '姓名', value: 'u_name' },
|
||||
{ text: '電話', value: 'phone' },
|
||||
{ text: '操作', value: 'actions', sortable: false }
|
||||
],
|
||||
},
|
||||
|
||||
// 已選擇的待分配列表
|
||||
selectedFollowers: [],
|
||||
preBeds: [],
|
||||
headers: [
|
||||
{ text: '姓名', value: 'u_name' },
|
||||
{ text: '電話', value: 'phone' },
|
||||
{ text: '性別', value: 'sex' },
|
||||
{ text: '預分配床位', value: 'prebed' },
|
||||
{ text: '', value: 'actions' }
|
||||
],
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getActivityList() {
|
||||
axios.post(HTTP_HOST + 'api/activity/GetList?page=1&pageSize=500', { kind: 0, subject: "" })
|
||||
.then((res) => {
|
||||
this.activityList = res.data.list
|
||||
})
|
||||
},
|
||||
|
||||
//掛單相關方法-------------------start
|
||||
validateOrderForm() {
|
||||
if (!this.guadanorder.order_form.startdate) {
|
||||
this.$refs.messageModal.open({
|
||||
message: '請輸入必填資訊'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (!this.guadanorder.order_form.enddate) {
|
||||
this.$refs.messageModal.open({
|
||||
message: '請輸入必填資訊'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (!this.guadanorder.order_form.bookerName) {
|
||||
this.$refs.messageModal.open({
|
||||
message: '請輸入姓名'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (this.guadanorder.order_form.bookerPhone && !/^\d{2,4}-?\d{3,4}-?\d{3,4}$/.test(this.guadanorder.order_form.bookerPhone)) {
|
||||
this.$refs.messageModal.open({
|
||||
message: '電話輸入有誤'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
},
|
||||
getGuadanOrderById() {
|
||||
if (this.guadanorder.order_form.uuid) {
|
||||
axios.get(HTTP_HOST + 'api/guadan/getorderbyid', {
|
||||
params: {
|
||||
orderId: this.guadanorder.order_form.uuid
|
||||
}
|
||||
}).then((res) => {
|
||||
this.guadanorder.order_form.note = res.data.notes;
|
||||
this.guadanorder.order_form.startdate = res.data.startDate;
|
||||
this.guadanorder.order_form.enddate = res.data.endDate;
|
||||
this.guadanorder.order_form.orderNo = res.data.guaDanOrderNo;
|
||||
this.guadanorder.order_form.bookerName = res.data.bookerName;
|
||||
this.guadanorder.order_form.bookerPhone = res.data.bookerPhone;
|
||||
this.guadanorder.order_form.bookerFollowerNum = res.data.bookerFollowerNum;
|
||||
this.guadanorder.order_form.uuid = res.data.uuid;
|
||||
this.guadanorder.order_form.activityNum = res.data.activityNum;
|
||||
})
|
||||
}
|
||||
},
|
||||
getGuadanOrderGuestByOrderNo() {
|
||||
if (this.guadanorder.order_form.orderNo) {
|
||||
axios.get(HTTP_HOST + 'api/guadanorderguest/getbyorderno', {
|
||||
params: {
|
||||
orderNo: this.guadanorder.order_form.orderNo
|
||||
}
|
||||
}).then((res => {
|
||||
this.guadanguest.items = res.data;
|
||||
}))
|
||||
}
|
||||
},
|
||||
//掛單相關方法-------------------end
|
||||
},
|
||||
watch: {
|
||||
'guadanorder.order_form.orderNo'(newValue, oldValue) {
|
||||
if (newValue) {
|
||||
this.getGuadanOrderGuestByOrderNo();
|
||||
}
|
||||
},
|
||||
'selectGuestModal.options': {
|
||||
handler() {
|
||||
this.getGuadanFollowers();
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
// 分頁變化時自動刷新
|
||||
'automaticBedAllocation.followerModal.page': function () {
|
||||
this.getMultiSelectFollowers();
|
||||
},
|
||||
'automaticBedAllocation.followerModal.pageSize': function () {
|
||||
this.getMultiSelectFollowers();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.guadanorder.order_form.uuid) {
|
||||
this.getGuadanOrderById();
|
||||
this.getGuadanOrderGuestByOrderNo();
|
||||
}
|
||||
this.getActivityList();
|
||||
|
||||
},
|
||||
computed: {
|
||||
pageCount() {
|
||||
return Math.ceil(this.selectGuestModal.count / this.selectGuestModal.pageSize)
|
||||
},
|
||||
pageCount2: function () {
|
||||
var fm = this.automaticBedAllocation.followerModal;
|
||||
return Math.ceil(fm.totalCount / fm.pageSize) || 1;
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
</asp:Content>
|
||||
14
web/admin/guadan/view.aspx.cs
Normal file
14
web/admin/guadan/view.aspx.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using System.Web.UI.WebControls;
|
||||
|
||||
public partial class admin_guadan_view : MyWeb.config
|
||||
{
|
||||
protected void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
// 頁面初始化(暫無邏輯)
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@
|
||||
},
|
||||
methods: {
|
||||
getStatusList() {
|
||||
axios.get('/api/region/bed/status/list')
|
||||
axios.get(HTTP_HOST + 'api/region/bed/status/list')
|
||||
.then((res) => {
|
||||
this.items = res.data
|
||||
this.loading = false;
|
||||
@@ -73,7 +73,7 @@
|
||||
})
|
||||
},
|
||||
deleteStatus(item) {
|
||||
axios.post('/api/region/bed/status/delete', null, {
|
||||
axios.post(HTTP_HOST + 'api/region/bed/status/delete', null, {
|
||||
params: { code: item.code }
|
||||
})
|
||||
.then(() => {
|
||||
|
||||
@@ -316,7 +316,7 @@
|
||||
unoccupied: this.filter.unoccupied,
|
||||
gender: this.filter.Gender,
|
||||
};
|
||||
axios.post('/api/region/list', payload)
|
||||
axios.post(HTTP_HOST + 'api/region/list', payload)
|
||||
.then((res) => {
|
||||
this.regions = res.data.regions;
|
||||
this.summary = res.data.summary; // 保存後端統計
|
||||
@@ -347,7 +347,7 @@
|
||||
console.log(this.filter.Gender);
|
||||
},
|
||||
getRegionWithRoom() {
|
||||
axios.get('/api/region/regionwithroom')
|
||||
axios.get(HTTP_HOST + 'api/region/regionwithroom')
|
||||
.then((res) => {
|
||||
this.filter.areas = res.data;
|
||||
})
|
||||
|
||||
@@ -578,7 +578,7 @@
|
||||
this.expandAllFlag = false;
|
||||
},
|
||||
async loadRegions() {
|
||||
const res = await axios.post('/api/region/getRegionList');
|
||||
const res = await axios.post(HTTP_HOST + 'api/region/getRegionList');
|
||||
this.regions = res.data;
|
||||
this.flatRegions = this.flatten(res.data);
|
||||
if (this.currentSelectRoom) {
|
||||
@@ -586,7 +586,7 @@
|
||||
}
|
||||
},
|
||||
loadRegionType() {
|
||||
axios.post('/api/region/getRegionType')
|
||||
axios.post(HTTP_HOST + 'api/region/getRegionType')
|
||||
.then(res => {
|
||||
this.regionTypes = res.data
|
||||
});
|
||||
@@ -799,7 +799,7 @@
|
||||
});
|
||||
},
|
||||
confirmDeleteBed(bed) {
|
||||
axios.post('/api/region/bed/delete', null, {
|
||||
axios.post(HTTP_HOST + 'api/region/bed/delete', null, {
|
||||
params: { uuid: bed.uuid }
|
||||
}) // 假設後端吃的是 id
|
||||
.then(() => {
|
||||
@@ -840,7 +840,7 @@
|
||||
async saveEditBed() {
|
||||
|
||||
try {
|
||||
await axios.post('/api/region/bed/update', this.room_bed.newBedForm);
|
||||
await axios.post(HTTP_HOST + 'api/region/bed/update', this.room_bed.newBedForm);
|
||||
this.room_bed.showBedModal = false;
|
||||
|
||||
const updated = this.room_bed.newBedForm;
|
||||
@@ -882,7 +882,7 @@
|
||||
},
|
||||
getBedStatus() {
|
||||
//獲取床位狀態
|
||||
axios.get('/api/region/bed/status/list')
|
||||
axios.get(HTTP_HOST + 'api/region/bed/status/list')
|
||||
.then((res) => {
|
||||
this.room_bed.bed_status = res.data;
|
||||
})
|
||||
@@ -907,7 +907,7 @@
|
||||
});
|
||||
return;
|
||||
}
|
||||
axios.post('/api/region/room/create', this.room.room_form)
|
||||
axios.post(HTTP_HOST + 'api/region/room/create', this.room.room_form)
|
||||
.then((res) => {
|
||||
this.room.showCreateRoomDialog = false;
|
||||
this.currentSelectRegion.rooms.push(res.data);
|
||||
@@ -924,7 +924,7 @@
|
||||
},
|
||||
async roomUpdate() {
|
||||
try {
|
||||
const res = await axios.post('/api/region/room/update', this.room.room_form);
|
||||
const res = await axios.post(HTTP_HOST + 'api/region/room/update', this.room.room_form);
|
||||
this.$refs.messageModal.open({
|
||||
message: '客房資料更新成功'
|
||||
});
|
||||
@@ -950,7 +950,7 @@
|
||||
},
|
||||
|
||||
roomDelete() {
|
||||
axios.post('/api/region/room/delete', { uuid: this.currentSelectRoom.uuid })
|
||||
axios.post(HTTP_HOST + 'api/region/room/delete', { uuid: this.currentSelectRoom.uuid })
|
||||
.then((res) => {
|
||||
const region = this.findRegionById(this.regions, this.currentSelectRoom.regionUuid)//當前room所在的region
|
||||
if (region) {
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
},
|
||||
methods: {
|
||||
getRegionTypeList() {
|
||||
axios.post('/api/regiontype/getreiontypelist')
|
||||
axios.post(HTTP_HOST + 'api/regiontype/getreiontypelist')
|
||||
.then((res) => {
|
||||
this.items = res.data;
|
||||
})
|
||||
@@ -71,7 +71,7 @@
|
||||
'title': '刪除提示',
|
||||
'message': `確定要刪除 ${item.name} ?`,
|
||||
onConfirm: () => {
|
||||
axios.post('/api/regiontype/delete',null, {
|
||||
axios.post(HTTP_HOST + 'api/regiontype/delete',null, {
|
||||
params: { uuid: item.uuid }
|
||||
})
|
||||
.then(() => {
|
||||
|
||||
Reference in New Issue
Block a user